/* ============================================================
   ERA26 Expo Real Aftertaste, Warszawa
   RealTimes DARK-FIRST edition (MSN26 "Mid-Summer Night" model).
   Granat ERA (#061c38) jako plotno, pasma granatowe (#0a2d58), bialy atrament,
   full-brightness gold accents, gold hairlines. Seashell survives
   ONLY as the single partners-marquee light band
   (--seashell-light-band). Sharp corners. Flipped 2026-07-24 from
   the former Seashell-canvas edition via the :root remap below.
   ============================================================ */

:root {
  /* Locked brand tokens (never change) */
  --rt-red: #e31b23;
  --rt-gold: #c5a55a;
  --background: #061c38;            /* Granat ERA gleboki: baza strony + stopka */
  --rt-charcoal: #0a2d58;
  --rt-line: rgba(255, 255, 255, 0.12);

  /* DARK-FIRST flip (donor edition + MSN26 model). The former Seashell tokens
     now resolve to on-dark values, so every section inverts from ONE place;
     layout and spacing are untouched, only colour + background move. CSS custom
     properties resolve order-independently, so forward references to the on-dark
     set below are valid. The single Seashell LIGHT band (the partners marquee)
     is restored explicitly via --seashell-light-band. */
  --seashell: var(--background);        /* body base = Granat ERA #061c38 */
  --seashell-alt: var(--rt-charcoal);   /* alternate bands = #0a2d58 */
  --card: var(--rt-charcoal);           /* cards = #0a2d58 */
  --ink: var(--on-dark-primary);        /* headings = #ffffff */
  --ink-soft: var(--on-dark-secondary); /* body copy = white 72% */
  --ink-muted: var(--on-dark-muted);
  --ink-faint: var(--on-dark-faint);
  /* GOLD FRAME LAW (Director 2026-08-03, Alex: "frame border golden").
     These two tokens ARE every frame and every divider on the dark surface:
     card borders, band top/bottom rules, and the 1px grid-gap FIELD behind the
     mosaic grids (.trust-grid / .concept-facts / .products) whose gap paints the
     row dividers of the spec table. They resolved to rgba(255,255,255,0.08/0.05)
    , the "dim neutral grey" in the client's screenshot. Repointing them at the
     existing gold alphas turns every frame + rule gold from ONE place, with no
     new hex and no per-selector sweep. 45% resting keeps a hairline from reading
     heavy across ~30 cards at once; full-brightness gold stays reserved for the
     hover / featured convention the sheet already uses (--rt-gold-60 on hover,
     --rt-gold-bright on the featured card). */
  --line-warm: var(--rt-gold-45);       /* frames + primary rules on dark */
  --line-warm-soft: var(--rt-gold-25);  /* secondary in-card row rules on dark */
  --gold-ink: var(--rt-gold-bright);    /* light-on-dark gold #ddc074, full brightness */
  --seashell-92: var(--era-navy-92);    /* nav-scrolled / arrow glass = dark translucent */
  --seashell-light-band: #fff5ee;       /* the ONE Seashell light band (partners marquee) */

  /* Gold / red derivatives (consumed via var() only) */
  --rt-gold-bright: #ddc074;
  --rt-gold-04: rgba(197, 165, 90, 0.04);
  --rt-gold-08: rgba(197, 165, 90, 0.08);
  --rt-gold-12: rgba(197, 165, 90, 0.12);
  --rt-gold-25: rgba(197, 165, 90, 0.25);
  --rt-gold-45: rgba(197, 165, 90, 0.45);
  --rt-gold-60: rgba(197, 165, 90, 0.6);
  --rt-red-12: rgba(227, 27, 35, 0.12);
  --rt-red-dim: #b8161d;
  --on-dark-alert: #ff6b6b;             /* lightened brand-red: keeps "required/alert" reading, clears WCAG AA on charcoal */

  /* On-dark set (accent bands + canonical footer).
     INK LAW (Alex 2026-07-31, SAR-2026-07-31-gray-on-obsidian): on ANY dark surface
     only two ink colours exist, pure #ffffff for text at every level, and gold
     --rt-gold-bright for accents/meta. NO grey token, NO sub-white rgba on dark.
     Hierarchy comes from size / weight / letter-spacing, never from graying colour.
     Light (.band-seashell) bands force their own dark ink and are unaffected. */
  --on-dark-primary: #ffffff;
  --on-dark-secondary: #ffffff;
  --on-dark-muted: #ffffff;
  --on-dark-faint: var(--rt-gold-bright);   /* meta labels -> gold accent, never grey */
  --line-soft: rgba(255, 255, 255, 0.08);
  --era-navy-92: rgba(6, 28, 56, 0.92);
  --era-navy-70: rgba(6, 28, 56, 0.7);
  --era-navy-00: rgba(6, 28, 56, 0);

  /* Hockney accent palette (Alex-approved 2026-07-28: dark base + Hockney accents).
     David Hockney's signature hues, applied as ACCENTS on the granat ERA canvas, section
     rules, dividers, link hover/focus, small graphic pops, and carried by the illustration
     imagery. NEVER body text on dark: dark-surface-legibility holds (headings stay #fff,
     body white/72%, gold --rt-gold-bright #ddc074 at full brightness). Restraint is the
     brief: 1-2 pops per surface, max. The artist NAME lives only in human editorial copy
     and the tribute credit, never in a token name, prompt, filename, alt-text, or metadata. */
  --hk-cerulean: #2e9cca;        /* pool / Thames water */
  --hk-cobalt: #0047ab;          /* deep water / night sky */
  --hk-viridian: #3aa17e;        /* park green / foliage */
  --hk-coral: #ea7e5d;           /* sunlit apricot / terracotta */
  --hk-rose: #c94f6d;            /* Yorkshire rose / magenta */
  --hk-sand: #e8c98a;            /* warm sand / low sun */
  --hk-chartreuse: #8fa31e;      /* rare zing accent, sparing */

  /* Photo-safe lifts of two palette hues, for type set directly on a bright
     photograph. --photo-scrim is transparent by CANON decision, so accents on a
     band are measured against the image itself, not against granat ERA. Raw
     cerulean measured 3.47:1 and raw rose 2.08:1 on the bar photograph, against
     a shipped sibling standard of 5.65:1 and 4.31:1. These tints restore that
     standard while keeping the same two hues. Do NOT use them on dark solid
     surfaces, where the raw tokens are correct and stronger. */
  --hk-cerulean-on-photo: #86c6e0;   /* 5.77:1 on the bar photograph */
  --hk-cerulean-on-navy: #3aa3d0;    /* 4,79:1 na granacie #0a2d58 (surowy cerulean daje tam 4,40:1) */
  --hk-rose-on-photo: #e4a7b6;       /* 4.53:1 on the bar photograph */
  /* Added 2026-08-17 for the tribute hero's artist name. Raw --hk-coral
     (#ea7e5d) computes to only ~4.28:1 against the worst-case granat ERA-70 plate
     over that bright illustration, i.e. under the 4.5 floor, so it needed the
     same treatment the two lifts above already had. Built with the identical
     transform they use: preserve hue and saturation exactly, raise lightness
     only. #ea7e5d is hsl(14.0, 77.0%, 64.1%) -> #f2ac97 is hsl(13.9, 77.8%,
     77.1%). Its relative luminance (0.5062) also lands within 0.5% of
     --hk-cerulean-on-photo (0.5082), so the two read as a matched pair when set
     side by side, which is exactly how the tribute hero uses them. Measured off
     rendered pixels on the tribute hero, against the LIGHTEST pixel found behind
     the word (worst case for light type): 6.86:1 at 1440x900 and 6.97:1 at
     375x812. Like its siblings, do NOT use it on a dark solid surface, where raw
     --hk-coral is correct and stronger. */
  --hk-coral-on-photo: #f2ac97;      /* 6.86:1 / 6.97:1 on the tribute hero plate */
  /* Low-alpha washes for rules / hover glows on dark (legibility-safe) */
  --hk-cerulean-16: rgba(46, 156, 202, 0.16);
  --hk-cerulean-38: rgba(46, 156, 202, 0.38);
  --hk-coral-16: rgba(234, 126, 93, 0.16);
  --hk-coral-38: rgba(234, 126, 93, 0.38);
  --hk-rose-16: rgba(201, 79, 109, 0.16);
  /* The signature 4-stop Hockney wash: water -> green -> sand -> coral. Section dividers
     and accent rules only; a thin band, never a full section background (dark stays king). */
  --hk-wash: linear-gradient(90deg, var(--hk-cerulean), var(--hk-viridian), var(--hk-sand), var(--hk-coral));

  /* CANON:photo-scrim-tokens */
  /* NO DARK IMAGE OVERLAYS. Superseding the 2026-07-16 flat 0.55/0.20 photo
     scrim: Alex 2026-08-03 ruled no dark overlay on any image, the hero video
     included, so every photograph shows clean. Both tokens are now transparent
     and every ::before/::after that references them paints nothing. Copy that
     used to lean on the veil keeps its legibility from a LOCAL text-shadow /
     text-plate on the COPY, never a full-frame wash over the picture (see the
     .hero-on-banner, .illus-caption, .venue-content, .band-photo shadow rules).
     saturate() stays: it adds colour, not darkness. */
  --photo-scrim: transparent;
  --photo-scrim-light: transparent;
  --photo-saturate: 1.3;
  /* /CANON:photo-scrim-tokens */

  /* Inter, chosen for small-size legibility (taller x-height, more open
     apertures than Geist at 12-14px). Geist Mono retired: it was used on 41
     label/meta sites, none of them numeric, where monospace + uppercase +
     wide tracking made short text slow to read (Alex, round-2 feedback).
     --font-mono is kept as an alias so every call site flips in one line. */
  --font-sans: 'Inter', system-ui, -apple-system, sans-serif;
  --font-mono: var(--font-sans);
  /* Editorial serif for the tribute page display heading (B8, 2026-07-29):
     a refined system-serif stack, no extra webfont load. */
  --font-serif: Georgia, 'Iowan Old Style', 'Palatino Linotype', 'Times New Roman', serif;
  --ui-ease: 180ms ease;

  /* Card/box corner radius (Alex 2026-08-03: "rounded text boxes, as we had
     for MSN26"). Value matches MSN26's own card standard (agenda.css:177,
     gallery.css:33). One shared token for the whole card/box family so any
     future adjustment is a single edit; buttons/pills/fields keep their own
     smaller/pill radii on purpose (see LIVE-REVIEW BATCH block below). */
  --radius-card: 16px;
  /* Companion scale (Director 2026-08-03, Alex: "text box round", ALL boxes).
     One token per corner family so the whole site re-tunes from three edits:
     control = buttons + form fields; pill = chips / badges / tags / subnav items. */
  --radius-control: 10px;
  --radius-pill: 999px;
}

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

/* WYSOKOSC PASKA. Alex 2026-08-14: pasek urosl 64 -> 76, zeby wordmark mogl
   urosnac 112 -> 140 bez przyciecia. Alex 2026-08-24: pasek "dwa pietra", znak
   ERA26 zdecydowanie wiekszy plus podpis "forum branzy nieruchomosci".

   DWA TOKENY, NIE JEDEN, I TO JEST ISTOTA TEJ ZMIANY.
   Pasek kurczy sie na scrollu (gorne pietro znika w CALOSCI), wiec jedna liczba
   nie moze obsluzyc obu zastosowan naraz:

     --nav-h       ZYWA wysokosc paska, 112 px w spoczynku, 62 px po zwinieciu.
                   Uzywaja jej rzeczy PRZYKLEJONE DO DOLNEJ KRAWEDZI paska:
                   `top:` podpaska msn-subnav na siedmiu podstronach, sticky
                   .ke-head, scroll-padding dla kotwic. Gdyby zostala stala,
                   po zwinieciu paska podpasek wisialby 50 px NIZEJ niz pasek
                   i zostalaby po nim dziura. To dokladnie ta usterka, ktora na
                   Insights przezyla przeglad, bo czytano `top` z CSS zamiast
                   zmierzyc, gdzie pasek RENDERUJE SIE naprawde.

     --nav-h-rest  STALA rezerwa w ukladzie. 78 px od 2026-08-26 (bylo 112,
                   czyli 34 px gornego pietra + 78 px paska; pietro zdjete). Uzywaja jej
                   `padding-top` i `margin-top`, ktore odsuwaja tresc od paska.
                   Gdyby szly za zywa wysokoscia, cala strona podskakiwalaby o
                   50 px przy kazdym zwinieciu paska.

   Podzial idzie po NAZWIE WLASCIWOSCI: `top:` bierze zywa, `padding-top:` i
   `margin-top:` biora stala. */
:root {
  /* 0px od 2026-08-26: gorne pietro nawigacji zdjete na polecenie Alexa.
     Token ZOSTAJE (a nie znika), bo --nav-h, scroll-margin sekcji i offset
     paska podrzednego licza sie z niego. Wyzerowanie tutaj przenosi zmiane
     na wszystkie te miejsca naraz; skasowanie tokenu rozsypaloby calc(). */
  --nav-tier-top-h: 0px;
  --nav-row-h: 78px;                                         /* wlasciwy pasek: znak + menu */
  --nav-h: calc(var(--nav-tier-top-h) + var(--nav-row-h));   /* zywa */
  --nav-h-rest: 78px;    /* stala rezerwa; 112 -> 78 po zdjeciu gornego pietra */
}
/* Zwiniecie jest sterowane klasa .scrolled, ktora main.js sam juz zaklada na
   #nav przy scrollY > 24. Nie dokladam nowego nasluchu scrolla; `:has()` tylko
   podnosi ten stan do :root, zeby tokeny mogly za nim isc. Bez wsparcia :has()
   pasek po prostu sie nie kurczy, co jest degradacja lagodna, a nie awaria. */
html:has(#nav.scrolled):not(:has(.msn-subnav)) { --nav-tier-top-h: 0px; --nav-row-h: 62px; }

/* DLACZEGO PODSTRONY Z PODPASKIEM NIE KURCZA PASKA.
   Zmierzone 2026-08-24 na /canvases: podpasek ma `position: sticky` i poprawne
   `top: 62px`, a renderuje sie na y4, czyli 58 px za wysoko, SCHOWANY ZA paskiem.
   Przyczyna nie lezy w wartosciach: silnik nie przelicza ponownie zaczepienia
   elementu, ktory JUZ jest przyklejony, kiedy jego `top` zmieni sie w locie.
   Nasz `top` jedzie na zmiennej, ktora zmienia sie dokladnie w momencie
   zwiniecia paska, wiec podpasek zostaje z zaczepieniem policzonym dla starej
   wartosci. Sprawdzone tez z `overflow-x: clip` na <body>, ktore usunelo osobna,
   realna usterke z kontenerem przewijania, ale tej nie ruszylo.

   Zamiast walczyc z silnikiem: na siedmiu podstronach niosacych podpasek pasek
   ZOSTAJE pelny (112 px), wiec `top` podpaska nigdy sie nie zmienia i podpasek
   przylega bez szpary w kazdym stanie. Strona glowna, ktora podpaska nie ma,
   kurczy sie normalnie do 62 px. Roznica jest niewidoczna dla odwiedzajacego,
   bo nie porownuje on paskow miedzy podstronami, a przyklejenie dziala wszedzie.

   Weryfikacja nalezy do POMIARU RENDERU (`sub.top - nav.bottom` w kilku
   pozycjach scrolla), nie do odczytu `top` z CSS: odczyt pokazywal 62 px i
   wygladal zdrowo przez caly czas trwania usterki. */
html { scroll-behavior: smooth; scroll-padding-top: var(--nav-h-rest); }

body {
  background: var(--seashell);
  color: var(--ink-soft);
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  /* `clip` zamiast `hidden`, poprawione 2026-08-24.
     `overflow-x: hidden` na <body> robi z niego KONTENER PRZEWIJANIA, a wtedy
     kazdy `position: sticky` w srodku liczy swoj `top` wzgledem tego kontenera,
     nie wzgledem okna. Skutek byl mierzalny: podpasek na /canvases, /gallery
     i /partnerships mial poprawne `top: 62px`, a renderowal sie na y4, czyli
     58 px za wysoko, schowany ZA paskiem nawigacji. Czytanie `top` z CSS
     pokazywalo stan zdrowy; dopiero pomiar realnego polozenia pokazal usterke.
     `overflow-x: clip` przycina tak samo, ale NIE tworzy kontenera przewijania,
     wiec przyklejanie znow liczy sie wzgledem okna. Usterka byla tu przed
     przemalowaniem, tylko wyzszy pasek uczynil ja widoczna. */
  overflow-x: clip;
}

/* Site-wide orphan guard. Measured across home/invite/speakers/venue at 375 and
   1440: 13 paragraphs ended on a single stranded word. `pretty` is the right tool
   rather than `balance` here because it only adjusts the last few lines, so it is
   safe on long body copy (browsers decline to balance blocks past a handful of
   lines, which is exactly where the orphans were). Result: 13 single-word orphans
   -> 1. Two-word endings rise, which is ordinary typography, not a defect.
   Short blocks that need full balancing keep their own more-specific rule below
   (.hero-sub, .panel-block h3, .ticket-benefits li, .group-nudge span). */
p, li { text-wrap: pretty; }

img { display: block; max-width: 100%; }
a { color: inherit; }

.rt-shell {
  width: min(1160px, calc(100vw - 2.5rem));
  margin: 0 auto;
}

/* ---------- Typography primitives ---------- */
/* Event-name emphasis. Wraps every prose occurrence of the event name
   (`<b class="brand-name">ERA26</b>`) across every page.
   `color: inherit` is LOAD-BEARING, not decoration: several rules in this sheet
   recolour `strong`/`b` (e.g. `.band-seashell strong { color:#061c38 }`, the
   on-dark gold accent rules), and the name appears on dark bands, on Seashell
   bands, inside `<a>`, and inside legal prose. Inheriting means it always takes
   the colour of the sentence it sits in and can never pick up a stray accent.
   `letter-spacing: inherit` for the same reason: the name sits inside tracked
   uppercase meta lines as well as normal body copy. Weight is the ONLY thing
   this class asserts. */
.brand-name { font-weight: 700; color: inherit; letter-spacing: inherit; }

.eyebrow {
  font-family: var(--font-sans);
  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--gold-ink);
  display: inline-block;
}
.eyebrow-rule {
  display: block;
  width: 0;
  height: 2px;
  margin-top: 0.7rem;
  /* Hockney wash: the site-wide palette signature, carried on a small accent rule under
     every section eyebrow (dark base + Hockney accents, Alex 2026-07-28). Not text -> no
     legibility cost; systemic -> every section reads Hockney. */
  background: linear-gradient(90deg, var(--hk-cerulean), var(--hk-viridian), var(--hk-sand), var(--hk-coral), transparent);
  transition: width 900ms cubic-bezier(0.22, 1, 0.36, 1) 200ms;
}
.revealed .eyebrow-rule { width: 96px; }

/* Hockney-accent inline link, tribute cross-links (concept -> tribute, footer).
   Interactive link, not body text, so the dark-surface accent rule is satisfied.

   ODCIEN ZMIENIONY 2026-08-24 RAZEM Z PRZEMALOWANIEM NA GRANAT. Surowy
   --hk-cerulean #2e9cca mierzyl ~6,1:1 na obsydianie #0f0f0f, ale granat
   #0a2d58 jest JASNIEJSZY, wiec ten sam odcien spadl do 4,40:1 i przestal
   spelniac AA. Zmierzone na renderze /partnerships, nie wyliczone z tokenow.
   --hk-cerulean-on-navy to ten sam akcent podniesiony do 4,79:1 na granacie.
   Wariantowanie per powierzchnia jest konwencja tego arkusza: istnieja juz
   --hk-cerulean-on-photo dla fotografii i --hk-cerulean-deep dla jasnych tel. */
.hk-link {
  color: var(--hk-cerulean-on-navy);
  font-weight: 600;
  text-decoration: none;
  border-bottom: 1px solid var(--hk-cerulean-38);
  transition: color var(--ui-ease), border-color var(--ui-ease);
  white-space: nowrap;
}
.hk-link:hover, .hk-link:focus-visible {
  color: #6cc3e6;
  border-bottom-color: var(--hk-cerulean);
}

h2 {
  font-size: clamp(1.7rem, 3.4vw, 2.6rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.12;
  color: var(--ink);
  margin: 1.1rem 0 1.2rem;
  text-wrap: balance;
}
h3 { color: var(--ink); font-weight: 600; letter-spacing: -0.01em; }

section { padding: 5.5rem 0; position: relative; }
.section-note {
  font-family: var(--font-sans);
  font-size: 0.85rem;
  letter-spacing: 0.01em;
  color: var(--ink-muted);
  margin-top: 1.6rem;
}
.section-lede { max-width: 58ch; color: var(--ink-soft); }

/* ---------- Buttons ---------- */
/* RED RETIRED (Director 2026-08-03, Alex: "red must be changed to golden; red
   buttons to golden; for the whole website"). Gold is now the site-wide accent.
   The class name .btn-red is kept: it is referenced by ~40 HTML call sites and
   by :not(.btn-red) selectors, and other agents own the HTML this run.
   Ink MUST go dark: white on --rt-gold-bright measures ~1.8:1 (fail), dark
   granat ERA on it measures ~11.8:1 (AAA). This mirrors the pairing the CANON
   hero-CTA block already documents, so the whole site now shares one CTA look.
   The cream-band variant is overridden further down (gold-bright cannot separate
   from a cream page: ~1.6:1 edge contrast).

   AMENDED 2026-08-17 (Alex, on screenshot): red is reinstated for EXACTLY ONE
   surface, the `.marquee-band` bottom hairline on index.html ("that black line
   below marquee with partners is not needed; enough to ad a red line"). That is
   a 1px separator between two cream fields, where gold at 25% alpha measures
   ~1.3:1 and vanishes. It is a separator, never ink and never a CTA, so it does
   not contradict the ruling above. EVERY OTHER retired-red surface stays gold:
   .btn-red and its hover keep --rt-gold-bright / --rt-gold as set below, and
   --rt-red remains reserved elsewhere for form-error state only
   (.field-error, .field.invalid, .reg-status.error). Do not read the marquee
   exception as licence to reintroduce red anywhere else. */
.btn-red {
  display: inline-block;
  background: var(--rt-gold-bright);
  color: var(--background);
  font-family: var(--font-sans);
  font-size: 0.92rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  padding: 0.85rem 1.7rem;
  text-decoration: none;
  border: 1px solid var(--rt-gold-bright);
  cursor: pointer;
  transition: background var(--ui-ease), transform var(--ui-ease), box-shadow var(--ui-ease);
}
/* Hover = the deeper --rt-gold, identical to the convention the CANON
   hero-CTA block already ships (incl. its gold-tinted glow). */
.btn-red:hover {
  background: var(--rt-gold);
  border-color: var(--rt-gold);
  color: var(--background);
  transform: translateY(-2px);
  box-shadow: 0 8px 28px var(--rt-gold-25);
}
.btn-ghost {
  display: inline-block;
  color: var(--ink);
  font-size: 0.88rem;
  font-weight: 600;
  padding: 0.8rem 1.5rem;
  text-decoration: none;
  border: 1px solid var(--rt-gold-60);
  background: transparent;
  cursor: pointer;
  transition: border-color var(--ui-ease), background var(--ui-ease), transform var(--ui-ease);
}
.btn-ghost:hover {
  border-color: var(--rt-gold);
  background: var(--rt-gold-08);
  transform: translateY(-2px);
}

/* ============================================================
   NAV - Seashell, blur on scroll
   ============================================================ */
.nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 100;
  background: var(--seashell);
  border-bottom: 1px solid transparent;
  transition: background var(--ui-ease), border-color var(--ui-ease), box-shadow var(--ui-ease);
}
.nav.scrolled {
  background: var(--seashell-92);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-bottom-color: var(--line-warm);
  box-shadow: 0 6px 24px rgba(26, 18, 16, 0.06);
}
.nav-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: var(--nav-row-h);   /* wlasciwy pasek; gorne pietro ma wlasna wysokosc */
  transition: height 300ms ease-out;
  gap: 1rem;
}
/* Nav wordmark sized by WIDTH, not height (edit-in-place, not an appended
   override: a `height:26px` here plus a `width:96px` later would fight at equal
   specificity). The asset is the 2.1359:1 SVG lockup (viewBox 1555.5 x 728.25),
   swapped in from a 3.875:1 PNG. height:auto + object-fit:contain track whichever
   ratio the source carries, so it can never distort or letterbox.
   Arithmetic on the 76px bar: 140px wide -> 65.55px tall -> 10.45px clearance.
   Alex 2026-08-14: "the logo here is too small; increase to the height of the
   menu pasek; mid-aligned; same padding as Request an invite". 96 -> 98 was too
   timid to read as a change; 112px fills 81.9% of the bar height and is the
   point where the wordmark stops looking undersized next to the CTA.
   MEASURED IN BROWSER, not calculated (widths are the .nav-inner track):
     1440px -> logo 140px, ~448-462px spare beside the nav links, no wrap
     1024px -> logo 140px, ~271px spare, no wrap
      900px -> logo 140px, ~148px spare, no wrap
      760px -> flex ALREADY shrinks the logo to 131.6px, 16px spare, no wrap
      721px -> flex shrinks it further to 92.6px, 16px spare, no wrap
      720px -> breakpoint: burger mode, fixed 100px logo. Clean at 721/720/719.
      375px -> the 100px mobile step, 207px clear of the 44x44 burger
   Re-measured in a headless browser 2026-08-14 after the 64->76 / 112->140 step.
   The previous numbers here claimed the logo held 140px flat to 760px; it does not,
   shrink begins at or before 760. Harmless (no overlap, no wrap, no h-scroll at any
   width) but the old figures were wrong and had already been trusted once.
   So the 720-760px band self-corrects by shrinking rather than breaking, which
   is why 112 is safe to hold rather than backing off to a smaller fixed width.
   Mid-alignment comes from `.nav-inner`'s
   align-items:center, so neither element needs its own vertical offset.
   Mobile 84px override lives in the MAIN NAV block at the end of this file. */
/* WYMIAROWANIE ODWROCONE 2026-08-24 — CALY AKAPIT POWYZEJ OPISUJE POPRZEDNI
   ZNAK I JEST JUZ NIEAKTUALNY. Tamten byl poziomym wordmarkiem 2,1359:1, wiec
   sterowanie SZEROKOSCIA mialo sens: wysokosc wychodzila sama i nie dotykala
   krawedzi paska. Znak ERA26 jest BLOKIEM 1,744:1 (450x258). Przy tych samych
   140 px szerokosci mialby 80 px wysokosci, czyli WIECEJ niz caly 76-pikselowy
   pasek sprzed tej zmiany. Dlatego teraz wiedzie WYSOKOSC, a szerokosc wychodzi
   sama: to jedyny sposob, zeby znak nie przycial sie o krawedz paska niezaleznie
   od tego, jaka proporcje bedzie mial przyszly plik.
   52 px na 78-pikselowym pietrze zostawia po 13 px swiatla u gory i u dolu. */
.nav-logo img { width: auto; height: 52px; object-fit: contain; display: block; transition: height 300ms ease-out; }
html:has(#nav.scrolled) .nav-logo img { height: 36px; }

/* ---- GORNE PIETRO: podpis marki + kontekst wydarzenia ----
   Znika w CALOSCI na scrollu, nie blednie. Dzieki temu pasek schodzi ze 112 do
   62 px, czyli nizej niz gdyby podpis tylko zgasl, a jednoczesnie --nav-h idzie
   za nim, wiec podpasek na podstronach nie zostaje w powietrzu. */
.nav-tier-top {
  height: var(--nav-tier-top-h);
  overflow: hidden;
  background: rgba(3, 17, 36, .92);
  border-bottom: 1px solid var(--rt-gold-25);
  transition: height 300ms ease-out, border-color 300ms ease-out;
}
.nav-tier-top-inner {
  height: var(--nav-tier-top-h);
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  transition: height 300ms ease-out;
}
/* .nav-podpis ZDJETY 2026-08-25 (powtarzal H1). Zostal sam kontekst. */
.nav-kontekst {
  font-size: .62rem; letter-spacing: .16em; text-transform: uppercase;
  white-space: nowrap; line-height: 1;
  color: #fff;                                  /* na ciemnym tylko biel albo zloto */
}
html:has(#nav.scrolled) .nav-tier-top { border-bottom-color: transparent; }

@media (max-width: 720px) {
  /* Podpis marki zdjety 2026-08-25, wiec kontekst wydarzenia NIE moze juz
     znikac na mobile - inaczej gorny pasek zostalby calkiem pusty. */
  .nav-logo img { height: 44px; }
  html:has(#nav.scrolled) .nav-logo img { height: 32px; }
}
.nav-links {
  display: flex;
  align-items: center;
  gap: 1.6rem;
}
/* MSN26 type treatment ported IN PLACE (insights.css 111-341). Uppercase /
   tracked / 0.78rem. Colour stays --ink-soft, which resolves to pure
   #ffffff here; MSN26's own #e8e6e3 is off-white and would regress the
   dark-surface ink law.
   WHY IN PLACE, not appended: this selector is re-declared at equal specificity
   (0,2,1) inside the @media (max-width:720px) drawer block further down. An
   appended copy would sit AFTER that media block and win on source order,
   dropping the mobile drawer from 0.95rem to 0.78rem. Editing here keeps the
   drawer rule downstream and winning, exactly as the port intends. */
.nav-links a:not(.btn-red),
.nav-links .nav-parent {
  font-size: 0.78rem;
  font-weight: 500;
  color: var(--ink-soft);
  text-decoration: none;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  white-space: nowrap;
  transition: color 0.3s ease;
}
/* Menu highlight gold, not red (Alex 2026-08-03: "menu items; same highlight in
   golden not red"). Resting link colour is untouched, only the highlight moves.
   Full-brightness gold: the nav bar is a dark surface, so ink law forbids a
   dimmed/mid-tone gold here. */
.nav-links a:not(.btn-red):hover,
.nav-links a:not(.btn-red):focus-visible,
.nav-links a:not(.btn-red)[aria-current="page"] { color: var(--rt-gold-bright); }
/* CTA TYPOGRAPHY ONLY. Fill / border / ink are set by the CANON
   era26-hero-cta-gold-buttons block and are deliberately not restated here.
   Edited in place rather than appended: an appended copy would leave the
   0.82rem below as a dead declaration overridden at equal specificity. */
/* Height parity with the wordmark (2026-08-14). line-height was previously
   UNDECLARED, so the button inherited the body value and computed ~37px against
   a 44.9px logo, an 8px mismatch that read as a misaligned bar. Both numbers are
   now pinned:
     font-size   0.72rem = 11.52px
     line-height 1.2     = 13.824px
     padding-y   1.06rem = 16.96px x2 = 33.92px
     border      1px x2  =  2.00px
     total               = 49.74px, against the logo's 112px/2.1359 = 52.44px.
   The two are deliberately close but NOT identical: a button matched exactly to
   a wordmark's bounding box reads as taller than the wordmark, because the logo
   box includes its own internal whitespace while the button's box is all ink.
   49.7 against 52.4 is what makes them look like a matched pair. Change either
   number and the other must be re-measured, which is why the arithmetic is here.
   Horizontal padding went 1.1rem -> 1.4rem to keep the pill in proportion at the
   taller height. Fill / border-colour / ink still belong to the CANON
   era26-hero-cta-gold-buttons block and are deliberately not restated. */
.nav-links .btn-red {
  padding: 1.06rem 1.4rem;
  font-size: 0.72rem;
  line-height: 1.2;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  white-space: nowrap;
}

/* Multipage nav dropdown (Programme, with Speakers submenu) */
.nav-item { position: relative; display: flex; align-items: center; }
.nav-parent { display: inline-flex; align-items: center; gap: 0.3rem; }
.nav-caret { font-size: 0.58rem; line-height: 1; transition: transform var(--ui-ease); }
.nav-item:hover .nav-caret, .nav-item:focus-within .nav-caret { transform: rotate(180deg); }
.nav-sub {
  position: absolute;
  top: 100%; left: 0;
  min-width: 190px;
  background: var(--seashell);
  border: 1px solid var(--line-warm);
  box-shadow: 0 12px 30px rgba(26, 18, 16, 0.12);
  padding: 0.35rem 0;
  display: flex;
  flex-direction: column;
  opacity: 0;
  visibility: hidden;
  transform: translateY(6px);
  transition: opacity var(--ui-ease), transform var(--ui-ease), visibility var(--ui-ease);
}
.nav-item:hover .nav-sub, .nav-item:focus-within .nav-sub {
  opacity: 1; visibility: visible; transform: translateY(0);
}
.nav-sub a { padding: 0 1.1rem !important; min-height: 44px; display: flex; align-items: center; white-space: nowrap; }

/* Sub-pages have no hero, so their first section must clear the fixed 64px nav */
.subpage-main { padding-top: var(--nav-h-rest); }

/* Bordered box + gold tap-highlight (MSN26 port). Edited in place: the previous
   `border: 0` and the port's `border: 1px` are the same property at the same
   specificity, so appending would leave a contradictory pair. */
.nav-burger {
  display: none;
  width: 44px; height: 44px;
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.25);
  -webkit-tap-highlight-color: rgba(221, 192, 116, 0.2);
  touch-action: manipulation;
  cursor: pointer;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
}
.nav-burger span {
  display: block;
  width: 22px; height: 2px;
  background: var(--ink);
  transition: transform var(--ui-ease), opacity var(--ui-ease);
}
.nav-burger.open span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-burger.open span:nth-child(2) { opacity: 0; }
.nav-burger.open span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* ============================================================
   TICKER - Granat ERA market strip under the nav
   ============================================================ */
.ticker {
  position: fixed;
  top: var(--nav-h); left: 0; right: 0;
  z-index: 99;
  height: 40px;
  background: var(--background);
  border-bottom: 1px solid var(--rt-gold-25);
  overflow: hidden;
  /* No edge-fade mask (Alex, round-2): the gradient dissolved the strip's
     text at both ends, which cost legibility for no design gain. */
}
.ticker-row {
  display: flex;
  align-items: center;
  height: 100%;
  gap: 2.6rem;
  width: max-content;
  animation: tickerScroll 46s linear infinite;
  padding-left: 1rem;
}
.ticker:hover .ticker-row { animation-play-state: paused; }
@keyframes tickerScroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
.ticker-item {
  display: inline-flex;
  align-items: center;
  gap: 2.6rem;
  font-family: var(--font-sans);
  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  /* Dark band rule (SAR 2026-06-12): pure white, never muted */
  color: var(--on-dark-primary);
  white-space: nowrap;
  text-decoration: none;
}
.ticker .tick-sep { color: var(--rt-gold-bright); font-size: 0.55rem; }
.ticker-item.tick-cta { color: var(--rt-gold-bright); font-weight: 600; }
a.ticker-item:hover { color: var(--rt-gold-bright); }

/* ============================================================
   HERO - copy ON the full-bleed banner (Alex, round-1 feedback).
   A local gradient scrim darkens the copy's band only (added
   post-QA; measured contrast was 1.65-2.56:1 against white text,
   under WCAG AA); the sky/skyline stay visible above and below.
   Dark band rule: all white + full-brightness gold, preserved
   (gold-bright accents moved to white on this specific banner
   only, where gold-on-golden-photo cannot pass contrast).
   ============================================================ */
.hero {
  padding-top: var(--nav-h-rest); /* nav bar, ticker removed */
  background: var(--seashell);
}
.hero-eyebrow {
  font-family: var(--font-sans);
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--rt-gold-bright);
}
.hero h1 {
  /* Big display headline: spans most of the shell width, logo-to-menu
     (Alex 2026-08-03). Larger clamp + wider measure than the prior 4.6rem/17ch. */
  font-size: clamp(2.5rem, 8.5vw, 7rem);
  font-weight: 700;
  letter-spacing: -0.035em;
  line-height: 1.02;
  color: var(--on-dark-primary);
  margin: 1.1rem 0 1.1rem;
  max-width: 24ch;
  text-wrap: balance;
}
/* CANON:era26-hero-cta-gold-h1 */
.hero-slide h1 .h1-red { color: var(--rt-gold-bright); }
/* /CANON:era26-hero-cta-gold-h1 */
.hero-sub {
  font-size: clamp(1rem, 1.6vw, 1.18rem);
  color: var(--on-dark-primary);
  max-width: 46ch;
  /* Widow guard. The "...art as an asset class between them." slide dropped the
     single word "them." onto its own line at 375px. Measured on the deployed
     page, last-line word counts at 375: default [7,9,10,1], `pretty` [6,9,10,2],
     `balance` [5,7,7,8]. `pretty` only nudges the final line and still left two
     words, which trips the >=3-word floor; `balance` equalises all four lines and
     clears it. Also clean at 1440 ([7,10,10]). Chosen over a hard <br> because a
     <br> fixes one width and can break another, and over a markup fix because the
     slide is canon-locked. Degrades to normal wrapping where unsupported. */
  text-wrap: balance;
}
.hero-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem 1.4rem;
  margin: 1.5rem 0 1.9rem;
  font-family: var(--font-sans);
  font-size: 0.84rem;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--rt-gold-bright);
}
.hero-meta .meta-dot { color: var(--on-dark-primary); }
/* On this banner, gold-on-golden-photo is the same hue family as the sky,
   so gold-bright cannot reach 4.5:1 here even under the scrim. Use white
   to match the h1/sub already on this surface; --rt-gold-bright keeps its
   full brightness everywhere else on the site. */
.hero-on-banner .hero-eyebrow,
.hero-on-banner .hero-meta {
  color: var(--on-dark-primary);
}
/* Banded hero (Alex + Domi 2026-08-14, variant A "Ledger rule"). Carries the
   approved interstitial treatment up into the partnerships hero so the page
   opens in the same system it continues in: four-colour block rule, white
   eyebrow, one headline word and one supporting phrase picked out.
   Contrast measured per line against the actual photograph, because
   --photo-scrim is transparent by CANON decision and the copy sits directly on
   the image: sand on the headline 9.23:1, cerulean on the supporting line
   5.37:1, white eyebrow 6.06:1. All clear the 4.5:1 AA floor. */
.hero-banded .hero-rule {
  display: block;
  width: min(520px, 100%);
  height: 5px;
  /* auto side margins, not 0: .hero-on-banner is text-align:center at every
     width, so a left-flush rule reads as an orphan bar off to one side while
     the eyebrow, headline and button sit centred. The interstitial bands are
     left-aligned and keep margin:0 there. Caught on the rendered page. */
  margin: 0 auto 1.1rem;
  border-radius: 2px;
  background: linear-gradient(90deg,
    var(--hk-cobalt) 0 25%, var(--hk-cerulean) 25% 50%,
    var(--hk-rose) 50% 75%, var(--hk-sand) 75% 100%);
}
.hero-banded h1 .t-a { color: var(--hk-sand); font-weight: 800; }

/* MIEJSCOWA OSLONA POD NAPISEM HERO (partnerships, po wniesieniu kadru w tlo).
   Pomiar na renderze, tlo brane OBOK liter, nie przez nie, 90 percentyl jasnosci:
     nadtytul (biel)      6,26  prog 4,5  ok
     H1 linia 1 (biel)    5,03  prog 3,0  ok
     H1 linia 2 (zloto)   2,70  prog 3,0  ZA NISKI
     podtytul l.1 (biel)  6,48  prog 4,5  ok
     podtytul l.2 (blekit)3,86  prog 4,5  ZA NISKI
   Zlota linia „ktory sala zapamieta" i blekitne „w miare podpisywania umow"
   siedza dokladnie na rozjasnionej, ciepłej partii akwareli.

   NIE PRZYCIEMNIAM CALEGO KADRU. Zdjecie ma zostac widoczne - to jest twarda
   zasada dla tla fotograficznego. Zamiast tego elipsa cienia pod samym blokiem
   tekstu, wygaszona do zera przed krawedziami, wiec obraz po bokach i u gory
   zostaje nietkniety. */
.hero-banded {
  background: radial-gradient(ellipse 78% 66% at 50% 52%,
    rgba(6, 28, 56, 0.86) 0%,
    rgba(6, 28, 56, 0.70) 46%,
    rgba(6, 28, 56, 0.30) 66%,
    rgba(6, 28, 56, 0) 80%);
  padding-top: clamp(2rem, 4vw, 3.4rem);
  padding-bottom: clamp(2rem, 4vw, 3.4rem);
}

/* NAGLOWEK HERO NA STRONIE PARTNERSTWA - ZDECYDOWANIE MNIEJSZY (Domi, 2026-08-25:
   „zdecydowanie zmniejsz font"). Wspolna regula .hero h1 dochodzi do 7rem, co dla
   tej dwuliniowej frazy dawalo napis na pol ekranu.

   NIE WYMYSLAM NOWEJ SKALI. Biore te, ktora arkusz juz ma dla naglowkow podstron
   (.subpage-hero h1, clamp 1.9rem/4.4vw/3.1rem) - na desktopie to spadek z 7rem
   do 3.1rem, czyli o okolo 56 procent, a pismo zostaje w rodzinie rozmiarow
   serwisu zamiast byc jednorazowa wartoscia.

   ZAKRES: .hero-banded wystepuje WYLACZNIE na partnerships.html (sprawdzone
   grepem po wszystkich *.html), wiec ta regula nie rusza zadnego innego hero. */
.hero-banded h1 {
  font-size: clamp(1.9rem, 4.4vw, 3.1rem);
  letter-spacing: -0.02em;
  line-height: 1.06;
  max-width: 26ch;
}
.hero-banded .hero-sub .t-b { color: var(--hk-cerulean-on-navy); font-weight: 700; }

.hero-cta-row { display: flex; flex-wrap: wrap; gap: 1rem; align-items: center; }

/* On-banner ghost button: white on dark, gold on hover */
.btn-on-banner {
  display: inline-block;
  color: var(--on-dark-primary);
  font-size: 0.88rem;
  font-weight: 600;
  padding: 0.8rem 1.5rem;
  text-decoration: none;
  border: 1px solid var(--on-dark-primary);
  background: rgba(6, 28, 56, 0.18);
  cursor: pointer;
  transition: border-color var(--ui-ease), color var(--ui-ease), transform var(--ui-ease);
}
.btn-on-banner:hover {
  border-color: var(--rt-gold-bright);
  color: var(--rt-gold-bright);
  transform: translateY(-2px);
}

/* Full-bleed banner carrying the copy */
.hero-banner {
  position: relative;
  display: flex;
  align-items: center;
  min-height: clamp(640px, 92vh, 900px);
  overflow: hidden;
  border-bottom: 1px solid var(--rt-gold-45);
  background: var(--rt-charcoal); /* paint-before-image fallback */
}
/* Descendant, not child: the hero <img> is wrapped in a <picture> for the
   art-directed portrait crop, so `> img` would no longer match. */
.hero-banner img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 116%;
  object-fit: cover;
  object-position: center 30%;
  will-change: transform;
  /* Pairs with --photo-scrim: the veil desaturates, this gives the colour
     back. Luminance-preserving, so it costs no contrast. */
  filter: saturate(var(--photo-saturate));
}
/* Hero video loop (injected by js/hero-video.js after window load).
   Sits at z0: above the poster <img>, beneath the CANON photo-scrim
   (::before, z1) and the copy (.hero-on-banner, z2) so legibility holds.
   Poster stays visible until 'playing' adds .is-playing (Safari-safe). */
/* CANON:era26-hero-video-css  (TODO(canon): inherited shape from the donor. NOT yet locked for ERA26 - no manifest entry and no baseline exist in this repo. Run canon-alex W3 before treating this as immutable.) */
.hero-video {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 116%;
  object-fit: cover;
  object-position: center 30%;
  opacity: 0;
  transition: opacity 600ms ease;
  filter: saturate(var(--photo-saturate));
  pointer-events: none;
}
.hero-video.is-playing { opacity: 1; }
/* /CANON:era26-hero-video-css */
/* Canonical photo scrim, flat and whole-frame. See --photo-scrim.
   Superseded a 7-stop vertical gradient (0.20 to 0.72 to 0.08) that shaped
   itself around the copy band. It held AA at 6.44:1, roughly 2x the 4.5:1
   floor, and paid for that unused margin by smearing 0.58-0.72 across 82% of
   the frame: the band read as a strip and the photograph read as gloom.
   Flat 0.55 measures 4.69:1 desktop / 5.13:1 mobile against the p95 backdrop
   with the copy hidden. Honest note: the mean frame is 0.98x / 0.90x of the
   old gradient's, so this is not a brighter hero, it is an evenly lit one.
   The copy band gains ~102%; the open sky gives back ~43% and the skyline at
   the foot of the towers ~62%. That trade was made deliberately. */
/* CANON:photo-scrim-hero */
.hero-banner::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: var(--photo-scrim);
  pointer-events: none;
}
/* /CANON:photo-scrim-hero */
.hero-on-banner {
  position: relative;
  z-index: 2;
  padding: clamp(3rem, 9vh, 5.5rem) 0;
  /* Legibility text-shadow, paired with the .hero-banner::before scrim above */
  text-shadow: 0 2px 26px rgba(6, 28, 56, 0.5), 0 1px 3px rgba(6, 28, 56, 0.4);
}
.hero-on-banner .hero-cta-row { text-shadow: none; }
.hero-banner .banner-caption {
  position: absolute;
  left: 0;
  bottom: 0;
  z-index: 2;
  padding: 0.55rem 1rem;
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--rt-gold-bright);
  background: var(--era-navy-70);
  backdrop-filter: blur(4px);
  border-top: 1px solid var(--rt-gold-25);
  border-right: 1px solid var(--rt-gold-25);
}
/* Golden-hour sweep lives on the image band only */
.hero-banner .banner-sweep {
  position: absolute;
  /* Oversized so the ±16% transform never reveals a hard edge (clipped by
     .hero-banner overflow:hidden). */
  inset: -12% -55%;
  pointer-events: none;
  background: linear-gradient(105deg,
    transparent 42%,
    var(--rt-gold-04) 47%,
    var(--rt-gold-12) 50%,
    var(--rt-gold-04) 53%,
    transparent 58%);
  opacity: 0.75;
  /* Compositor-only sweep: animate transform (not background-position) and
     drop mix-blend-mode:screen. Screen-blending an animated gradient over the
     moving hero video forced a per-frame backdrop-read + full-region repaint,
     which stuttered the video. Transform runs entirely on the GPU layer. */
  will-change: transform;
  transform: translate3d(-16%, 0, 0);
  animation: goldSweep 8s ease-in-out infinite;
}
@keyframes goldSweep {
  0%   { transform: translate3d(-16%, 0, 0); }
  55%  { transform: translate3d(16%, 0, 0); }
  100% { transform: translate3d(16%, 0, 0); }
}

/* Staged masthead entrance */
.stage {
  opacity: 0;
  transform: translateY(22px);
  animation: stageIn 700ms cubic-bezier(0.22, 1, 0.36, 1) both;
}
@keyframes stageIn { to { opacity: 1; transform: translateY(0); } }
.d1 { animation-delay: 100ms !important; }
.d2 { animation-delay: 260ms !important; }
.d3 { animation-delay: 440ms !important; }
.d4 { animation-delay: 620ms !important; }
.d5 { animation-delay: 800ms !important; }

/* ============================================================
   SUBPAGE TEASERS - multipage hub (granat ERA cards, gold accents)
   ============================================================ */
.subpage-teasers { padding: 5.5rem 0; }
.subpage-teasers .section-header { margin-bottom: 2.4rem; }
/* Even card counts split into equal rows (Alex 2026-07-31: 6 -> 3+3, never 4+2).
   Fixed 3-up desktop grid; 6 cards wrap to two balanced rows of three. */
.teaser-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.1rem;
}
@media (max-width: 860px) { .teaser-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .teaser-grid { grid-template-columns: 1fr; } }
.teaser-card {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  padding: 1.5rem 1.5rem 1.35rem;
  background: var(--rt-charcoal);
  border: 1px solid rgba(221, 192, 116, 0.18);
  border-top: 2px solid var(--rt-gold-bright);
  text-decoration: none;
  transition: transform var(--ui-ease), border-color var(--ui-ease), background var(--ui-ease);
}
.teaser-card:hover { transform: translateY(-3px); background: #0f3565; border-color: rgba(221, 192, 116, 0.5); }
.teaser-card:focus-visible { outline: 2px solid var(--rt-gold-bright); outline-offset: 3px; }
.teaser-card-k { font-size: 1.15rem; font-weight: 700; letter-spacing: -0.01em; color: var(--on-dark-primary); }
.teaser-card-d { font-size: 0.92rem; line-height: 1.5; color: var(--on-dark-secondary); }
.teaser-card-cta { margin-top: 0.35rem; font-size: 0.82rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; color: var(--rt-gold-bright); }

/* ============================================================
   SEASHELL (light) BAND - the S in the S/O/I rhythm; dark ink text
   ============================================================ */
.band-seashell { background: var(--seashell-light-band); color: #061c38; }
.band-seashell h1, .band-seashell h2, .band-seashell h3, .band-seashell h4 { color: #061c38; }
.band-seashell p, .band-seashell li, .band-seashell dd, .band-seashell dt, .band-seashell .section-lede, .band-seashell .trust-sla { color: #10233f; }
/* Dark ink for every descriptive / body text class (the tokens now resolve to
   white on dark; on a light band they must be forced dark or they vanish). */
.band-seashell .section-note, .band-seashell .act p, .band-seashell .panel-desc,
.band-seashell .product p, .band-seashell .register-meta, .band-seashell .practical-note,
.band-seashell .practical-list li, .band-seashell .pl-sub, .band-seashell .field-hint,
.band-seashell .partner-cta-note, .band-seashell .edition-building,
.band-seashell .fact-row dd .dd-sub, .band-seashell .concept-copy p,
.band-seashell .trust-cell p, .band-seashell .ticket-benefits li,
.band-seashell .member-terms p, .band-seashell .group-nudge, .band-seashell .tba-name,
.band-seashell .chip, .band-seashell .panel-detail p, .band-seashell .reg-status,
.band-seashell .consent, .band-seashell .rstep, .band-seashell .event-strip,
.band-seashell .event-colophon { color: #10233f; }
/* Gold (deep, legible-on-light) for every meta / label / eyebrow. */
.band-seashell .eyebrow, .band-seashell .illus-eyebrow, .band-seashell .trust-cell h3,
.band-seashell .act-no, .band-seashell .panel-no, .band-seashell .edition-no,
.band-seashell .act-time, .band-seashell .series-hint, .band-seashell .series-ai-note,
.band-seashell .mod-tag, .band-seashell .fact-row dt, .band-seashell .practical-col h3,
.band-seashell .pl-key, .band-seashell .ticket-price-note, .band-seashell .member-terms .mt-label,
.band-seashell .product-kicker, .band-seashell .panel-detail-label, .band-seashell .tba-role,
.band-seashell .reg-note, .band-seashell .field label, .band-seashell .marquee-label,
.band-seashell .edition-stats, .band-seashell .edition-stats .ht,
.band-seashell .register-meta strong, .band-seashell .register-steps .rstep-no,
.band-seashell .practical-list .pl-key { color: #8a6a1e; }
/* Bold defined terms + white-token headings -> dark on a light band.
   .band-seashell .trust-cell p strong is listed explicitly because
   .trust-cell p strong (line ~813, specificity 0,1,2) outranks the plain
   .band-seashell strong (0,1,1) rule below on element-count alone, so the
   dark-ink override must match/beat that specificity to actually win. */
.band-seashell strong,
.band-seashell .trust-cell p strong { color: #061c38; }
.band-seashell .edition-city, .band-seashell .ticket-tier, .band-seashell .ticket-price,
.band-seashell .fact-row dd, .band-seashell .keynote-moment h3, .band-seashell .panel-block h3,
.band-seashell .panel-detail h4, .band-seashell .venue-content h2 { color: #061c38; }
.band-seashell .eyebrow-rule { background: rgba(138,106,30,0.4); }
.band-seashell a:not(.btn-red):not(.nav-cta):not(.teaser-card):not(.hk-link):not(.wiz-link):not(.wiz-cta) { color: #8a6a1e; }
/* .wiz-link / .wiz-cta wylaczone 2026-08-25: .wizytowka to CIEMNA wyspa na jasnym
   pasmie, wiec zloty atrament dla jasnego tla dawal na niej 3.08:1. Kolory karty
   siedza w bloku WIZYTOWKA na koncu pliku. */
/* Cards on a light band become light cards (no black boxes, Alex 2026-07-31 item 11). */
.band-seashell .trust-cell, .band-seashell .fact-row, .band-seashell .product,
.band-seashell .panel-block, .band-seashell .ticket-card, .band-seashell .practical-col,
.band-seashell .keynote-moment, .band-seashell .edition-card, .band-seashell .chip,
.band-seashell .member-terms, .band-seashell .reg-form, .band-seashell .group-nudge,
.band-seashell .nominate-cta { background: #fffaf6; }
.band-seashell .trust-cell, .band-seashell .concept-facts, .band-seashell .trust-grid,
.band-seashell .fact-row, .band-seashell .product, .band-seashell .panel-block,
/* Gold frame law, LIGHT-BAND variant. The dark side's --rt-gold-45 is a light
   gold and washes out on cream, so the light band keeps its own deep gold
   (#8a6a1e, the light-band gold ink already used throughout this block) and is
   lifted 0.22 -> 0.40. 0.40 is not a new shade: it is the alpha already used by
   .band-seashell .eyebrow-rule just below. This leaves 0.55 free as the hover
   step, which .band-seashell .teaser-card:hover already uses. */
.band-seashell .ticket-card, .band-seashell .practical-col { border-color: rgba(138,106,30,0.4); }
.band-seashell .trust-grid, .band-seashell .concept-facts, .band-seashell .products { background: rgba(138,106,30,0.4); }
.band-seashell .trust-cell:hover, .band-seashell .fact-row:hover, .band-seashell .product:hover { background: #fff; }
.band-seashell .teaser-card { background: #fffaf6; border-color: rgba(138,106,30,0.22); border-top-color: #b9932f; }
.band-seashell .teaser-card:hover { background: #fff; border-color: rgba(138,106,30,0.55); }
.band-seashell .teaser-card-k { color: #061c38; }
.band-seashell .teaser-card-d { color: #2a4a72; }
.band-seashell .teaser-card-cta { color: #8a6a1e; }

/* ============================================================
   HERO SLIDER (clean), 4-image cross-fade, NO text overlay, NO scrim
   (Alex 2026-07-31). The photograph is shown clean; the event masthead
   sits BELOW on solid granat ERA ground, never overlaid on the image.
   ============================================================ */
.hero-slider {
  position: relative;
  margin-top: var(--nav-h-rest);               /* nav bar, ticker removed */
  min-height: clamp(360px, 56vh, 640px);
  overflow: hidden;
  background: var(--rt-charcoal);
  border-bottom: 1px solid var(--rt-gold-45);
}
.hero-slide {
  position: absolute; inset: 0;
  opacity: 0;
  transition: opacity 1400ms ease;
  will-change: opacity;
}
.hero-slide.is-active { opacity: 1; }
.hero-slide img {
  width: 100%; height: 100%;
  object-fit: cover; object-position: center 32%;
  filter: saturate(var(--photo-saturate));
}
.hero-slider-dots {
  position: absolute; left: 0; right: 0; bottom: 1.1rem; z-index: 3;
  display: flex; gap: 0.5rem; justify-content: center;
}
.hero-slider-dot {
  width: 30px; height: 3px; padding: 0; border: 0; cursor: pointer;
  background: rgba(255,255,255,0.45);
  transition: background var(--ui-ease);
}
.hero-slider-dot.is-active { background: var(--rt-gold-bright); }
.hero-slider-dot:focus-visible { outline: 2px solid var(--rt-gold-bright); outline-offset: 3px; }

/* Event masthead, solid granat ERA ground beneath the slider (no overlay). */
.hero-mast { background: var(--background); padding: clamp(2.4rem,5vh,3.6rem) 0 clamp(2.6rem,5vh,3.4rem); }
.hero-mast .hero-eyebrow { font-family: var(--font-sans); font-size: 0.8rem; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; color: var(--rt-gold-bright); }
.hero-mast h1 { font-size: clamp(2.2rem, 5.4vw, 4rem); font-weight: 700; letter-spacing: -0.03em; line-height: 1.05; color: #ffffff; margin: 0.9rem 0; max-width: 20ch; text-wrap: balance; }
.hero-mast h1 .h1-red { color: var(--rt-gold-bright); }
.hero-mast .hero-sub { font-size: clamp(1rem,1.6vw,1.18rem); color: #ffffff; max-width: 52ch; }
.hero-mast .hero-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6rem 1.4rem; margin: 1.4rem 0 1.7rem; font-size: 0.84rem; font-weight: 500; letter-spacing: 0.04em; text-transform: uppercase; color: var(--rt-gold-bright); }
.hero-mast .hero-meta .meta-dot { color: #ffffff; }
.hero-mast .hero-cta-row { display: flex; flex-wrap: wrap; gap: 1rem; align-items: center; }

/* Tribute portrait (CC-BY photo of the honoured painter), constrained, gold-framed */
.tribute-portrait { max-width: 420px; margin: 2rem 0 0; }
.tribute-portrait img { width: 100%; height: auto; border: 1px solid var(--rt-gold-45); }
.tribute-portrait figcaption { margin-top: 0.6rem; font-family: var(--font-mono); font-size: 0.74rem; letter-spacing: 0.03em; color: var(--rt-gold-bright); line-height: 1.5; }
.tribute-portrait figcaption a { color: var(--rt-gold-bright); text-decoration: underline; }

/* ============================================================
   BAND LAW (Alex 2026-07-31): every section declares its band type.
   Never two granat ERA adjacent, never two photo adjacent; light bands
   force their own dark ink (see .band-seashell above).
   ============================================================ */
.band-granat ERA { background: var(--background); }

/* Content-section band-photo (inherited O2/O3 treatment): a full-bleed
   flat-pop illustration BEHIND an entire content section (not just a masthead
   strip like .subpage-hero below). Same canonical whole-frame veil contract
   as .illus-band.has-copy: --photo-scrim (0.55) is calibrated to hold WCAG AA
   for pure-white body copy sitting DIRECTLY on the photo, no gradient plate
   needed. Content children get position:relative + z-index so they paint
   above the absolutely-positioned image + scrim layer. */
.band-photo {
  position: relative;
  overflow: hidden;
  background: var(--rt-charcoal);
  border-top: 1px solid var(--rt-gold-25);
  border-bottom: 1px solid var(--rt-gold-25);
}
.band-photo::before {
  /* Hockney wash top-edge, matching .illus-band / .subpage-hero */
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 2px;
  background: var(--hk-wash);
  z-index: 3;
  pointer-events: none;
}
.band-photo-img {
  position: absolute;
  inset: 0;
  z-index: 0;
}
.band-photo-img img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: saturate(var(--photo-saturate));
}
.band-photo-img::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--photo-scrim);
}
.band-photo > .rt-shell,
.band-photo > .marquee-band {
  position: relative;
  z-index: 2;
}

/* Subpage image hero (band-photo): a full-bleed photo banner heading each
   subpage (Alex 2026-07-31 item 10). White ink on a LOCAL text plate only,
   never a full-frame dark scrim. */
.subpage-hero {
  position: relative;
  margin-top: var(--nav-h-rest);
  min-height: clamp(300px, 44vh, 470px);
  display: flex; align-items: flex-end;
  overflow: hidden;
  background: var(--rt-charcoal);
  border-bottom: 1px solid var(--rt-gold-45);
}
.subpage-hero > img, .subpage-hero > picture { position: absolute; inset: 0; z-index: 0; }
.subpage-hero > picture img, .subpage-hero > img {
  width: 100%; height: 100%;
  object-fit: cover; object-position: center 32%;
  filter: saturate(var(--photo-saturate));
}
/* Hockney wash top-edge, matching the illustration bands */
.subpage-hero::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 2px;
  background: var(--hk-wash); z-index: 3; pointer-events: none;
}
.subpage-hero-inner {
  position: relative; z-index: 2;
  width: min(1160px, calc(100vw - 2.5rem));
  margin: 0 auto;
  padding: clamp(1.6rem,4vh,2.6rem) 0 clamp(1.4rem,3.5vh,2.2rem);
}
/* Local plate: legibility behind the copy ONLY, fades out to the right */
.subpage-hero-plate {
  display: inline-block;
  background: linear-gradient(90deg, rgba(6, 28, 56,0.82), rgba(6, 28, 56,0.6) 68%, rgba(6, 28, 56,0));
  padding: 1.1rem 4rem 1.2rem 1.2rem;
}
.subpage-hero .hero-eyebrow { color: var(--rt-gold-bright); font-family: var(--font-sans); font-size: 0.78rem; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; }
.subpage-hero h1 { color: #ffffff; font-size: clamp(1.9rem,4.4vw,3.1rem); font-weight: 700; letter-spacing: -0.02em; line-height: 1.06; margin: 0.5rem 0 0; max-width: 22ch; }
.subpage-hero .subpage-hero-sub { color: #ffffff; margin-top: 0.5rem; max-width: 50ch; font-size: 0.98rem; }

/* ============================================================
   SCROLL REVEAL
   ============================================================ */
.reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 700ms cubic-bezier(0.22, 1, 0.36, 1), transform 700ms cubic-bezier(0.22, 1, 0.36, 1);
}
.reveal.revealed { opacity: 1; transform: translateY(0); }
.reveal[data-stagger="1"] { transition-delay: 90ms; }
.reveal[data-stagger="2"] { transition-delay: 180ms; }
.reveal[data-stagger="3"] { transition-delay: 270ms; }
.reveal[data-stagger="4"] { transition-delay: 360ms; }
.reveal[data-stagger="5"] { transition-delay: 450ms; }
.reveal[data-stagger="6"] { transition-delay: 540ms; }

/* No-JS fallback for the reveal system. The rule above starts every revealed block
   at opacity 0; js/main.js clears it by adding `.revealed` from an IntersectionObserver.
   With scripting off that observer never runs, so every page body stayed invisible.
   The site's only <noscript> blocks are form-specific and never covered this.
   `scripting: none` matches exactly the case where the observer cannot run, so content
   shows unanimated instead of hidden. Kept in CSS on purpose: a <noscript> patch would
   mean editing all 11 pages. Alex 2026-08-14. */
@media (scripting: none) {
  .reveal,
  .reveal[data-stagger],
  .stage { opacity: 1 !important; transform: none !important; transition: none !important; }
}

/* ============================================================
   TRUST BLOCK - the evening, plainly
   ============================================================ */
.trust { padding-top: 4.4rem; }
.trust-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  background: var(--line-warm);
  border: 1px solid var(--line-warm);
  margin-top: 2.2rem;
}
.trust-cell {
  background: var(--card);
  padding: 1.5rem 1.4rem 1.6rem;
  transition: background var(--ui-ease);
}
.trust-cell:hover { background: var(--seashell-alt); }
.trust-cell h3 {
  font-size: 0.78rem;
  font-family: var(--font-mono);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gold-ink);
  margin-bottom: 0.7rem;
}
.trust-cell p { font-size: 0.9rem; color: var(--ink-soft); }
.trust-cell p strong { color: var(--ink); font-weight: 600; }
.trust-sla {
  margin-top: 1.4rem;
  font-family: var(--font-sans);
  font-size: 0.85rem;
  letter-spacing: 0.01em;
  color: var(--ink-muted);
}
.trust-sla strong { color: var(--gold-ink); font-weight: 600; }

/* ============================================================
   CONCEPT
   ============================================================ */
.concept-grid {
  display: grid;
  grid-template-columns: 1.05fr 1fr;
  gap: 3.5rem;
  align-items: start;
}
.concept-copy p { margin-bottom: 1.1rem; max-width: 58ch; }
.concept-copy p strong { color: var(--ink); font-weight: 600; }
.concept-facts {
  display: grid;
  gap: 1px;
  background: var(--line-warm);
  border: 1px solid var(--line-warm);
}
.fact-row {
  display: grid;
  grid-template-columns: 130px 1fr;
  gap: 1rem;
  padding: 1.05rem 1.2rem;
  background: var(--card);
  transition: background var(--ui-ease);
}
.fact-row:hover { background: var(--seashell-alt); }
.fact-row dt {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gold-ink);
  padding-top: 0.2rem;
}
.fact-row dd { color: var(--ink); font-size: 0.95rem; font-weight: 500; }
.fact-row dd .dd-sub { display: block; color: var(--ink-muted); font-size: 0.82rem; font-weight: 400; margin-top: 0.15rem; }

/* ============================================================
   SERIES - horizontal scroll-snap timeline
   ============================================================ */
.series { background: var(--seashell-alt); border-top: 1px solid var(--line-warm); border-bottom: 1px solid var(--line-warm); overflow: hidden; }
.series-track-wrap { position: relative; margin-top: 2.4rem; }
.series-track {
  display: flex;
  gap: 1.1rem;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding: 0.5rem 0.2rem 1.4rem;
  scrollbar-width: thin;
  scrollbar-color: var(--rt-gold-60) transparent;
}
.series-track::-webkit-scrollbar { height: 4px; }
.series-track::-webkit-scrollbar-thumb { background: var(--rt-gold-60); }
.series-track::-webkit-scrollbar-track { background: var(--line-warm-soft); }

.edition-card {
  flex: 0 0 clamp(240px, 24vw, 300px);
  scroll-snap-align: start;
  border: 1px solid var(--line-warm);
  background: var(--card);
  transition: transform var(--ui-ease), border-color var(--ui-ease), box-shadow var(--ui-ease);
  position: relative;
}
.edition-card:hover {
  transform: translateY(-5px);
  border-color: var(--rt-gold-60);
  box-shadow: 0 16px 44px rgba(26, 18, 16, 0.12);
}
.edition-card.current {
  border-color: var(--rt-gold);
  box-shadow: 0 0 0 1px var(--rt-gold-45), 0 18px 50px rgba(26, 18, 16, 0.14);
}
.edition-img { position: relative; aspect-ratio: 16 / 10; overflow: hidden; background: var(--rt-charcoal); }
.edition-img img {
  width: 100%; height: 100%;
  object-fit: cover;
  /* Not in the transition list, so it does not fight the hover scale.
     saturate() does not expand the box the way blur() would, so the parent's
     overflow:hidden still clips the scaled image exactly as before. */
  filter: saturate(var(--photo-saturate));
  transition: transform 600ms cubic-bezier(0.22, 1, 0.36, 1);
}
.edition-card:hover .edition-img img { transform: scale(1.05); }
/* Canonical photo scrim at the LIGHT alpha. See --photo-scrim-light.
   Superseded a 2-stop bottom lift (0 to 0.70), a pasek at the foot of every
   card. Nothing here needs a scrim to be legible: the city, building and
   stats live in .edition-body BELOW the photo on solid ground, and the only
   element on the image is .edition-badge, which carries its own opaque plate
   and measures 7.29:1 with the scrim removed entirely. So this veil has no
   legibility job, only a unifying one: six photos of very different native
   exposure read as one system. The hero's 0.55 here would take the Warsaw
   sunset from vivid to muddy and buy nothing. These are the proof a first
   edition happened; do not make them gloomy to match a number. */
/* CANON:photo-scrim-edition */
.edition-img::after {
  content: "";
  position: absolute; inset: 0;
  background: var(--photo-scrim-light);
}
/* /CANON:photo-scrim-edition */
.edition-badge {
  position: absolute;
  top: 0.8rem; left: 0.8rem;
  z-index: 2;
  font-family: var(--font-mono);
  font-size: 0.74rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.28rem 0.6rem;
  border: 1px solid var(--rt-line);
  background: var(--era-navy-70);
  color: var(--on-dark-primary);
  backdrop-filter: blur(4px);
}
/* "NEXT" badge: gold fill needs DARK ink, white on gold-bright is ~1.8:1. */
.edition-badge.next { background: var(--rt-gold-bright); border-color: var(--rt-gold-bright); color: var(--background); }
.edition-badge.done { color: var(--rt-gold-bright); border-color: var(--rt-gold-45); }
.edition-body { padding: 1.1rem 1.2rem 1.25rem; }
.edition-no {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gold-ink);
}
.edition-city {
  font-size: 1.18rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin: 0.4rem 0 0.1rem;
}
.edition-building { font-size: 0.86rem; color: var(--ink-soft); }
.edition-stats {
  display: flex;
  gap: 1rem;
  margin-top: 0.8rem;
  padding-top: 0.8rem;
  border-top: 1px solid var(--line-warm);
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.08em;
  color: var(--ink-muted);
}
.edition-stats .ht { color: var(--gold-ink); }
.series-hint {
  margin-top: 0.4rem;
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.series-ai-note {
  margin-top: 0.35rem;
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.05em;
  color: var(--ink-faint);
}

/* Swipe arrows flanking the infinite strip - the ONLY navigation affordance
   (Alex 2026-07-31, O4): visible on every viewport, not just desktop, since
   the "Drag or scroll" hint + drag affordance were removed. 46px clears the
   iOS 44px tap-target minimum. */
.series-arrow {
  position: absolute;
  top: 42%;
  z-index: 3;
  width: 46px;
  height: 46px;
  border-radius: 50% !important;
  border: 1px solid var(--rt-gold-60);
  background: var(--seashell-92);
  color: var(--ink);
  font-size: 1.05rem;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  backdrop-filter: blur(3px);
  transition: border-color var(--ui-ease), color var(--ui-ease), background var(--ui-ease);
}
.series-arrow:hover { border-color: var(--rt-gold-bright); color: var(--rt-gold-bright); }
.series-arrow.prev { left: -10px; }
.series-arrow.next { right: -10px; }
@media (max-width: 640px) {
  /* Tighter gutters on mobile (.rt-shell = 100vw - 1.5rem): pull the arrows
     inside the shell edge instead of poking past the viewport. */
  .series-arrow.prev { left: 2px; }
  .series-arrow.next { right: 2px; }
}

/* ============================================================
   PROGRAMME - four-act evening arc
   ============================================================ */
.acts {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.1rem;
  margin-top: 2.6rem;
  position: relative;
}
.acts::before {
  content: "";
  position: absolute;
  top: 7px; left: 2%; right: 2%;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--rt-gold-60) 12%, var(--rt-gold-60) 88%, transparent);
}
.act { position: relative; padding-top: 2rem; }
.act::before {
  content: "";
  position: absolute;
  top: 0; left: 0;
  width: 15px; height: 15px;
  border: 1px solid var(--rt-gold);
  background: var(--seashell);
  transform: rotate(45deg);
  transition: background var(--ui-ease);
}
.act:hover::before { background: var(--rt-gold); }
.act-no {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gold-ink);
}
.act h3 { font-size: 1.25rem; margin: 0.45rem 0 0.5rem; }
.act p { font-size: 0.88rem; color: var(--ink-muted); max-width: 30ch; }
.act-time {
  display: inline-block;
  margin-top: 0.9rem;
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
  border: 1px solid var(--line-warm);
  padding: 0.3rem 0.65rem;
}

/* ============================================================
   BASELINE GRID - "what every partner receives" (partnerships.html
   #baseline, band-seashell). Alex: bullets sat OUTSIDE the text
   container and read as "primitive". Root cause of the containment
   defect: the sitewide `* { padding: 0 }` reset (line 139) zeroes the
   UA default list indent, so the browser's `list-style-position:
   outside` disc had no padding box to sit inside and hung off the
   left edge of the .rt-shell column. Fix: list-style:none + an
   explicit padding-left that both HOUSES a custom marker and indents
   wrapped second lines under the text (padding-based indent, not
   text-indent, so wraps align automatically with no extra rule).
   Marker: a small solid gold diamond, NOT a browser disc/dash/emoji.
   Reuses the exact rotate(45deg) diamond vocabulary the site already
   uses for the programme step-markers (.act::before, immediately
   above this block) rather than inventing a new shape - "considered"
   here means "in the site's own language", not novel. Solid-filled
   (vs .act's hollow outline) reads as "included", appropriate for a
   benefits list rather than a numbered step sequence.
   Colour: the established deep gold #8a6a1e used sitewide for gold
   TEXT on cream (.band-seashell .eyebrow etc, line ~722) - chosen
   over the brighter --rt-gold/--rt-gold-bright so the marker doesn't
   wash out against the #fff5ee/#fffaf6 cream family. Measured against
   the section background #fff5ee: #8a6a1e -> contrast ~4.7:1 (clears
   AA even though a decorative marker isn't required to).
   Rhythm + measure: gap replaces the zero margin the reset left
   between items; max-width reuses the site's own long-copy measure
   token (.section-lede uses 58ch two sections above; 60ch here holds
   the longer strong+sentence pairs without a second reflow). */
.baseline-grid {
  list-style: none;
  display: grid;
  gap: 1.15rem;
  margin-top: 1.7rem;
  max-width: 60ch;
}
.baseline-grid li {
  position: relative;
  padding-left: 1.55rem;
  line-height: 1.6;
}
.baseline-grid li::before {
  content: "";
  position: absolute;
  left: 0.05rem;
  /* 0.62em ~= optical centre of the first line's cap-height, so the
     diamond sits level with the bold lead-in word, not the x-height
     midline of the whole (taller, wrapped) line. */
  top: 0.62em;
  width: 7px;
  height: 7px;
  background: #8a6a1e;
  transform: translateY(-50%) rotate(45deg);
}

/* The art keynote interlude (programme): a curated cultural moment, distinct from the three
   acts. Full-width card on charcoal with a Hockney coral accent edge. */
.keynote-moment {
  margin-top: 2.4rem;
  padding: clamp(1.4rem, 3vw, 2rem) clamp(1.4rem, 3.4vw, 2.4rem);
  background: var(--rt-charcoal);
  border: 1px solid var(--line-warm);
  border-left: 3px solid var(--hk-coral);
}
.keynote-moment .act-no { color: var(--hk-coral); }
.keynote-moment h3 { font-size: 1.35rem; margin: 0.45rem 0 0; color: var(--on-dark-primary); }
.keynote-moment p { margin-top: 0.7rem; font-size: 0.95rem; line-height: 1.55; color: var(--ink-soft); max-width: 70ch; }
.keynote-moment .act-time { margin-top: 1rem; }

/* ============================================================
   SPEAKERS - panels + capital-mandate filter chips
   ============================================================ */
.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-top: 1.8rem;
}
.chip {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-soft);
  background: var(--card);
  border: 1px solid var(--line-warm);
  padding: 0.5rem 0.95rem;
  cursor: pointer;
  transition: border-color var(--ui-ease), background var(--ui-ease), color var(--ui-ease);
}
.chip:hover { border-color: var(--rt-gold-60); }
/* Active filter chip = a selected-state HIGHLIGHT, so it joins the gold accent
   (Alex 2026-08-03: "all highlights must be golden"). It also fixes a latent
   bug: --ink resolves to #ffffff and .band-seashell does NOT re-scope --ink, so
   on a cream band this chip was a white fill on a cream page, an invisible
   edge. Gold fill + dark ink measures ~11.8:1; matches .msn-subnav a.active. */
.chip.active {
  background: var(--rt-gold-bright);
  border-color: var(--rt-gold-bright);
  color: var(--background);
}
.panels-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1.1rem;
  margin-top: 1.8rem;
}
.panel-block {
  border: 1px solid var(--line-warm);
  background: var(--card);
  padding: 1.6rem 1.6rem 1.5rem;
  transition: border-color var(--ui-ease), transform var(--ui-ease), opacity 300ms ease;
}
.panel-block:hover { border-color: var(--rt-gold-60); transform: translateY(-3px); }
.panel-block.chip-hidden { display: none; }
.panel-no {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gold-ink);
}
/* `balance` because both service-tier headings end in "...the room." and both
   orphaned "room." at 375px. Balancing the heading's lines fixes the pair at
   once and holds at any width. */
.panel-block h3 { font-size: 1.3rem; margin: 0.5rem 0 0.35rem; text-wrap: balance; }
.panel-block .panel-desc { font-size: 0.88rem; color: var(--ink-muted); margin-bottom: 1.3rem; }
/* 6 seats per panel: two rows of three, moderator first (Alex, round-1) */
.panel-people { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.8rem 0.8rem; }
.tba-card { min-width: 0; }

/* Panel description box: appears beside the lone card when one category is filtered */
.panel-detail { display: none; }
.panels-grid.single-cat { grid-template-columns: 1fr 1fr; align-items: stretch; }
.panels-grid.single-cat .panel-detail:not(.chip-hidden) {
  display: block;
  border: 1px solid var(--rt-gold-45);
  background: var(--seashell-alt);
  padding: 1.6rem 1.6rem 1.5rem;
}
.panel-detail-label {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gold-ink);
}
.panel-detail h4 { font-size: 1.1rem; color: var(--ink); margin: 0.5rem 0 0.6rem; }
.panel-detail p { font-size: 0.92rem; color: var(--ink-soft); margin-bottom: 0.8rem; }
.panel-detail .panel-detail-who { color: var(--ink); font-weight: 600; margin-bottom: 0; }

/* Nominate-a-speaker CTA */
.nominate-cta {
  margin-top: 1.4rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1.2rem;
  border: 1px dashed var(--rt-gold-60);
  background: var(--rt-gold-04);
  padding: 1rem 1.3rem;
}
.nominate-cta span { font-size: 0.92rem; color: var(--ink-soft); }
.nominate-cta a {
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--gold-ink);
  text-decoration: none;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
}
.nominate-cta a:hover { color: var(--ink); }
.tba-avatar {
  aspect-ratio: 1 / 1;
  max-width: 120px;
  border: 1px solid var(--line-warm);
  background:
    linear-gradient(160deg, var(--rt-gold-12), transparent 60%),
    var(--seashell-alt);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-size: 1.5rem;
  font-weight: 600;
  color: var(--rt-gold);
  transition: border-color var(--ui-ease), color var(--ui-ease);
}
.tba-card:hover .tba-avatar { border-color: var(--rt-gold-60); color: var(--gold-ink); }
.tba-name {
  margin-top: 0.55rem;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--ink-soft);
}
.tba-role {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-top: 0.15rem;
}
.mod-tag {
  display: inline-block;
  margin-top: 0.35rem;
  font-family: var(--font-mono);
  font-size: 0.74rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gold-ink);
  border: 1px solid var(--rt-gold-60);
  padding: 0.14rem 0.4rem;
}

/* ============================================================
   VENUE - The Shard. Granat ERA accent band (image + scrim).
   ============================================================ */
.venue { padding: 0; }
.venue-frame {
  position: relative;
  min-height: 78vh;
  display: flex;
  align-items: flex-end;
  overflow: hidden;
  border-top: 1px solid var(--rt-gold-45);
  border-bottom: 1px solid var(--rt-gold-45);
  background: var(--background);
}
.venue-bg { position: absolute; inset: 0; }
.venue-bg img {
  width: 100%; height: 110%;
  object-fit: cover;
  object-position: center 25%;
  will-change: transform;
  filter: saturate(var(--photo-saturate));
}
/* Canonical photo scrim, flat and whole-frame. See --photo-scrim.
   Superseded a stacked pair of gradients (a 90deg wipe from 0.92 down to 0
   by 70%, plus a 0deg lift) that hid the left ~43% of the frame, exactly
   where the copy sits, behind a near-solid panel. That gradient did not even
   do its job: the desktop copy measured 4.02:1, a live AA FAIL. Flat 0.55
   measures 5.32:1 desktop / 4.86:1 mobile and needs no text-shadow.
   Brightness where it counts: the text column goes 0.026 to 0.084 on desktop
   (3x) and the mobile frame 0.017 to 0.084 (5x, the photo was effectively
   invisible). One alpha clears both viewports, so the old mobile-only
   override is gone rather than replaced. Mobile sets this number, not
   desktop: mobile copy crosses more bright sky with no two-column split. */
/* CANON:photo-scrim-venue */
.venue-bg::after {
  content: "";
  position: absolute; inset: 0;
  background: var(--photo-scrim);
}
/* /CANON:photo-scrim-venue */
.venue-content {
  position: relative;
  z-index: 2;
  padding: 5.5rem 0 4.5rem;
  max-width: 620px;
}
/* Gold goes white on a photo. Identical call to .hero-on-banner above, and
   for the identical reason: gold is mid-luminance, --photo-scrim is
   mid-luminance, and mid-on-mid is the worst possible pairing. No alpha
   rescues it (gold only reaches 4.31:1 at 0.55 -> 0.65, still short of 4.5,
   while re-darkening the photo the flat scrim just freed). The old shaped
   gradient hid this by burying the copy column under a near-black panel:
   gold measured 6.37:1 there, but only because nobody could see the Shard.
   Gold keeps its full brightness everywhere else on this site, on solid
   ground where it belongs. */
/* CANON:photo-scrim-gold-on-photo */
.venue-content .eyebrow,
.venue-content .vstat .vstat-num,
.venue-content .vstat .vstat-num .unit { color: var(--on-dark-primary); }
/* /CANON:photo-scrim-gold-on-photo */
.venue-content h2 { color: var(--on-dark-primary); }
.venue-content > p { margin: 0.4rem 0 1rem; max-width: 52ch; color: var(--on-dark-primary); }
.venue-stats {
  display: flex;
  gap: 2.4rem;
  margin-top: 2rem;
  padding-top: 1.6rem;
  border-top: 1px solid var(--rt-gold-25);
}
.vstat .vstat-num {
  font-size: clamp(1.9rem, 3.4vw, 2.7rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--rt-gold-bright);
  font-variant-numeric: tabular-nums;
}
.vstat .vstat-num .unit { font-size: 0.55em; color: var(--rt-gold); margin-left: 0.12em; }
.vstat .vstat-label {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--on-dark-primary);
  margin-top: 0.3rem;
}

/* Getting there + stay nearby (light band under the venue image) */
.venue-practical { padding: 4.2rem 0 5.5rem; }
.practical-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.1rem;
  margin-top: 2.2rem;
}
.practical-col {
  border: 1px solid var(--line-warm);
  background: var(--card);
  padding: 1.6rem 1.6rem 1.4rem;
}
.practical-col h3 {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gold-ink);
  margin-bottom: 1.1rem;
}
.practical-list { list-style: none; display: grid; gap: 0.85rem; }
.practical-list li {
  display: grid;
  grid-template-columns: 110px 1fr;
  gap: 1rem;
  font-size: 0.9rem;
  color: var(--ink-soft);
  padding-bottom: 0.85rem;
  border-bottom: 1px solid var(--line-warm-soft);
}
.practical-list li:last-child { border-bottom: 0; padding-bottom: 0; }
.practical-list .pl-key {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-muted);
  padding-top: 0.2rem;
}
.practical-list strong { color: var(--ink); font-weight: 600; }
.practical-list .pl-sub { display: block; font-size: 0.8rem; color: var(--ink-muted); margin-top: 0.1rem; }
.practical-note {
  margin-top: 1rem;
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.06em;
  color: var(--ink-muted);
}

/* ============================================================
   INVITATIONS - tiers (prices TBA) + member terms
   ============================================================ */
.tickets { background: var(--seashell-alt); border-top: 1px solid var(--line-warm); border-bottom: 1px solid var(--line-warm); }
.ticket-cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.1rem;
  margin-top: 2.4rem;
}
.ticket-card {
  position: relative;
  border: 1px solid var(--line-warm);
  background: var(--card);
  padding: 1.8rem 1.6rem 1.7rem;
  display: flex;
  flex-direction: column;
  transition: transform var(--ui-ease), border-color var(--ui-ease), box-shadow var(--ui-ease);
}
.ticket-card:hover {
  transform: translateY(-4px);
  border-color: var(--rt-gold-60);
  box-shadow: 0 16px 44px rgba(26, 18, 16, 0.1);
}
/* Featured card = the sheet's existing "emphasis" step: full-brightness gold
   against the --rt-gold-45 resting frame on every sibling card. */
.ticket-card.popular { border-color: var(--rt-gold-bright); }
.popular-badge {
  position: absolute;
  top: 0; left: 1.4rem;
  transform: translateY(-50%);
  font-family: var(--font-mono);
  font-size: 0.74rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--background);
  background: var(--rt-gold-bright);
  padding: 0.3rem 0.7rem;
}
/* Tier names: larger and bold (Alex, round-1 feedback) */
.ticket-tier {
  font-family: var(--font-sans);
  font-size: 1.35rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink);
}
.ticket-price {
  margin: 0.7rem 0 0.2rem;
  font-size: 1.6rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--ink);
}
.ticket-price-note {
  font-family: var(--font-sans);
  font-size: 0.8rem;
  letter-spacing: 0.02em;
  color: var(--gold-ink);
  margin-bottom: 1.2rem;
}
.ticket-benefits { list-style: none; display: grid; gap: 0.6rem; flex: 1; margin-bottom: 1.5rem; }
.ticket-benefits li {
  position: relative;
  padding-left: 1.2rem;
  font-size: 0.88rem;
  color: var(--ink-soft);
  /* Widow guard. Five of the benefit lines dropped a single word onto their own
     line at 375 ("...after the evening", "...circulated to the room",
     "...in the event brochure", and both edited Elite lines); one also widowed at
     1440. Measured on the deployed page: `pretty` only nudges the final line and
     left two words, still under the >=3-word floor; `balance` equalises all lines
     and clears every case at both widths. Same idiom already used elsewhere in
     this sheet. Degrades to normal wrapping where unsupported. */
  text-wrap: balance;
}
.ticket-benefits li::before {
  content: "";
  position: absolute;
  left: 0; top: 0.52em;
  width: 7px; height: 7px;
  background: var(--rt-gold);
  transform: rotate(45deg);
}
/* CTA is now PRICE-ADJACENT (2026-08-14, Director rebuild): it sits directly
   under .ticket-price-note and ABOVE .ticket-benefits, so the price and the act
   of registering are one glance apart instead of separated by a benefit list.
   margin-top drops to 0 because .ticket-price-note already carries 1.2rem below
   it; margin-bottom is new and separates the button from the list that now
   follows it. .ticket-benefits keeps flex:1, so cards still equalise height and
   .ticket-team-note still pins to the bottom of every card. */
.ticket-card .btn-red, .ticket-card .btn-ghost { text-align: center; margin-top: 0; margin-bottom: 1.5rem; }

.group-nudge {
  margin-top: 1.6rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem 1.4rem;
  border: 1px solid var(--rt-gold-45);
  background: var(--rt-gold-08);
  padding: 1.1rem 1.4rem;
  font-size: 0.92rem;
  color: var(--ink-soft);
}
.group-nudge strong { color: var(--ink); }
/* Widow guard, same reasoning as .ticket-benefits li. The hosted-places notice ran
   to nine lines at 375 and orphaned its last word; the copy was tightened so the
   block is short enough for the browser to balance (Chrome declines to balance
   blocks beyond a handful of lines, so shortening had to come first). */
.group-nudge span { text-wrap: balance; }

.member-terms {
  margin-top: 1.1rem;
  border-left: 3px solid var(--rt-gold-bright);
  background: var(--card);
  border-top: 1px solid var(--line-warm);
  border-right: 1px solid var(--line-warm);
  border-bottom: 1px solid var(--line-warm);
  padding: 1.1rem 1.4rem;
}
.member-terms .mt-label {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gold-ink);
}
.member-terms p { margin-top: 0.4rem; font-size: 0.92rem; color: var(--ink-soft); }
.member-terms p strong { color: var(--ink); }

/* ============================================================
   PARTNERS - sponsor products + dark marquee band
   ============================================================ */
.products {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 1px;
  background: var(--line-warm);
  border: 1px solid var(--line-warm);
  margin-top: 2.4rem;
}
.product {
  background: var(--card);
  padding: 1.5rem 1.2rem 1.4rem;
  transition: background var(--ui-ease);
  position: relative;
}
.product:hover { background: var(--seashell-alt); }
/* Partners is now a .band-photo (Alex 2026-07-31, O2): product cells become
   translucent-dark glass cards over the illustration instead of opaque
   charcoal, so the photo shows through between/behind them. */
#partners .product {
  background: rgba(6, 28, 56, 0.6);
  backdrop-filter: blur(8px) saturate(1.2);
  -webkit-backdrop-filter: blur(8px) saturate(1.2);
}
#partners .product:hover { background: rgba(6, 28, 56, 0.78); }

/* Ghost-button legibility on a .band-photo (Alex: "text not visible; bad").
   Diagnosis: .btn-ghost (base rule below) is transparent by design with
   white (var(--ink)) text and only a 1px gold-60 border - fine on a solid
   card or on granat ERA, invisible wherever it sits directly on a bright
   patch of a photo (#partners > .rt-shell > .partner-cta-row, OUTSIDE any
   .product card). The 2026-08-03 no-scrim rule (see --photo-scrim at the
   top of this file) bans a full-frame darkening wash over the photo, but
   its own comment explicitly carves out a LOCAL text-shadow/text-plate on
   the copy as the sanctioned alternative - and a plate is the right tool
   for a BUTTON specifically (unlike the passing captions that use
   text-shadow at .hero-on-banner/.illus-caption/.venue-content, a control
   also needs a legible hover/focus affordance, which a shadow alone can't
   reliably deliver against a bright backdrop).
   Rather than inventing a new backing, this reuses the EXACT glass-card
   language already established two rules above for #partners .product:
   the same rgba(6, 28, 56,X) + backdrop-blur(8px) saturate(1.2) glass, just
   applied to the button chrome instead of a card. Resting alpha 0.72 (a
   shade lighter than the .product hover state's 0.78, one step past its
   0.6 resting state, since a button has no card padding around the label
   to absorb bright photo noise).
   Contrast, worst case (a pure-white patch of the photo behind the
   button): white text #ffffff vs. the rgba(6, 28, 56,0.72)-over-#ffffff
   composite -> approx rgb(82,82,82) -> ratio approx 7.8:1 (comfortably
   past the 4.5:1 AA target; alpha 0.72 was chosen with headroom above
   the ~0.57 alpha that would be the bare minimum for 4.5:1 at this
   worst case). */
.band-photo .btn-ghost {
  background: rgba(6, 28, 56, 0.72);
  backdrop-filter: blur(8px) saturate(1.2);
  -webkit-backdrop-filter: blur(8px) saturate(1.2);
}
.band-photo .btn-ghost:hover {
  background: rgba(6, 28, 56, 0.84);
  border-color: var(--rt-gold);
}
.band-photo .btn-ghost:focus-visible {
  outline: 2px solid var(--rt-gold-bright);
  outline-offset: 3px;
}

.product::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 2px;
  background: var(--tier-accent, var(--rt-gold-60));
}
.product h3 { font-size: 0.98rem; letter-spacing: 0.01em; }
.product .product-kicker {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
  display: block;
  margin-bottom: 0.5rem;
}
.product p { font-size: 0.8rem; color: var(--ink-muted); margin-top: 0.45rem; }

/* .product-invite - the tenth cell in the A-la-carte grid (partnerships.html
   #a-la-carte), an open invitation rather than a tenth identical product.
   Built ON TOP of .product (inherits card padding/frame/typography) so it
   reads as part of the set; three cues make it visually distinct AT REST:
   1) a warm gold-wash gradient instead of the flat #fffaf6 card fill,
   2) an INSET dashed gold ring - the "add your own" cue used across UI
      design generally, and legible here as an invitation rather than an
      error because it is warm gold, not a red/alert dash,
   3) the shared .product::before tier-accent bar bumped to full-brightness
      gold and 3px (vs the 2px gold-60 default) as one more "featured" tell.
   outline (not border) is used for the ring so it costs no layout width -
   the mosaic grid's cell math (LIVE-REVIEW BATCH note near end of file:
   "MOSAIC GRIDS - FRAME ROUNDS, CELLS STAY SQUARE... do NOT re-add
   border-radius to .trust-cell, .product, or .fact-row") depends on every
   .product cell keeping its exact box size; a border would have shifted
   this one cell out of alignment with its 9 siblings. outline-offset:-10px
   pulls the ring inward clear of the 3px top accent bar and safely inside
   the box, so .product's own overflow:hidden (line ~2617) never clips it.
   Hover is deliberately NOT overridden here: .band-seashell .product:hover
   (line ~751, specificity 0,3,0) already beats a bare .product-invite:hover
   (0,2,0) and flips the background to solid white on ALL nine siblings too
   - letting that win keeps hover feedback consistent across the whole
   grid, while the accent bar and dashed ring (untouched by that rule)
   keep this cell's identity through the hover state. */
.product-invite {
  background: linear-gradient(145deg, var(--rt-gold-12), #fffaf6 65%);
  outline: 1.5px dashed var(--rt-gold-bright);
  outline-offset: -10px;
}
.product-invite::before { background: var(--rt-gold-bright); height: 3px; }
/* .product-invite-link - the mailto affordance inside the cell. Deep gold
   #8a6a1e (the site's established gold-on-cream text colour, same source
   as the baseline-grid marker above) with an underline for a clear link
   affordance, darkening on hover/focus. Measured against this cell's
   background (a 12%-alpha gold wash over #fffaf6, marginally darker than
   flat #fff5ee): #8a6a1e -> contrast approx 4.6:1, holding the same AA
   margin as its sitewide precedent. Focus ring matches the sitewide
   .teaser-card/.hero-slider-dot convention (2px solid --rt-gold-bright,
   3px offset) rather than relying on the browser default, which is easy
   to lose against a light, low-contrast card. */
.product-invite-link {
  display: inline-block;
  margin-top: 0.9rem;
  font-family: var(--font-mono);
  font-size: 0.76rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #8a6a1e;
  text-decoration: underline;
  text-decoration-color: rgba(138, 106, 30, 0.55);
  text-underline-offset: 3px;
  transition: color var(--ui-ease), text-decoration-color var(--ui-ease);
}
/* ID-scoped on purpose, not a bare .product-invite-link:hover: the resting
   colour above is a dead-on-arrival match for .band-seashell a:not(.btn-red)
   :not(.nav-cta):not(.teaser-card):not(.hk-link) (line ~734, specificity
   0,5,1 - four :not() classes plus the band class), which ALSO catches this
   anchor since it isn't in that exclusion list, and would silently win over
   a bare :hover/:focus-visible (0,2,0) and swallow the darken-on-interact
   feedback below. #a-la-carte is this cell's actual ancestor id, so the ID
   selector (1,x,x) beats the class-only rule outright without needing to
   touch the shared exclusion list or reach for !important. */
#a-la-carte .product-invite-link:hover,
#a-la-carte .product-invite-link:focus-visible {
  color: #6b5116;
  text-decoration-color: #6b5116;
}
.product-invite-link:focus-visible {
  outline: 2px solid var(--rt-gold-bright);
  outline-offset: 3px;
}

.partner-cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  align-items: center;
  margin-top: 2rem;
}
.partner-cta-note { font-family: var(--font-mono); font-size: 0.72rem; color: var(--ink-muted); letter-spacing: 0.06em; }

/* Previous-editions marquee: the SINGLE Seashell LIGHT band (MSN26 model).
   Everything else on the page is dark; this one strip stays #fff5ee.
   Gold hairline on TOP (it separates the band from the granat ERA #proof copy
   above it, and gold-on-granat ERA is the site's frame law).

   BOTTOM BORDER IS RED, not gold (Alex 2026-08-17, on screenshot: "that black
   line below marquee with partners is not needed; enough to ad a red line").
   Below this band sits `.trust.band-seashell#the-room`, also #fff5ee, so once
   the black strip is gone (see the padding-bottom rule directly below) the two
   cream fields touch and a hairline is the ONLY thing separating them. Gold at
   25% alpha cannot do that job on cream: it measures ~1.3:1 edge contrast
   against #fff5ee and simply disappears. Full-strength --rt-red (#e31b23) on
   #fff5ee measures ~4.4:1, which reads as a deliberate rule.

   This is a NARROW, DATED reinstatement of red and it does NOT reopen the
   retired-red decision: see the "RED RETIRED" note at the .btn-red block
   above, which is amended in place with the same date. Red returns HERE ONLY,
   as a 1px separator on one band. Every CTA, button and other retired-red
   surface stays gold. */
/* CZERWONA KRESKA ZDJETA 2026-08-28 (Domi, na zrzucie: „czerwony pasek jest do
   usuniecia"). Cala notatka powyzej opisuje decyzje Alexa z 17.08 i zostaje jako
   zapis, dlaczego ta linia w ogole tu byla - ale jej juz nie ma.

   KONSEKWENCJA, swiadoma: pod paskiem lezy `.era-agenda`, rowniez #fff5ee, wiec
   bez tej kreski oba pola kremu stykaja sie bez zadnej granicy i czytaja sie jak
   jedno ciagle pasmo. Tak ma byc - strukture niesie teraz naglowek sekcji, nie
   linia. Gdyby kiedys mial wrocic podzial, wraca jako 1px --line-warm, nie jako
   czerwien: czerwien pozostaje wycofana z calej strony. */
.marquee-band {
  margin-top: 3.6rem;
  margin-bottom: 0;
  background: var(--seashell-light-band);
  border-top: 1px solid var(--rt-gold-25);
  padding: 2.2rem 0 2.4rem;
}
/* Kill the granat ERA strip under the marquee band. `section { padding: 5.5rem 0 }`
   gave #proof 88px of bottom padding BELOW its last child; because #proof is
   .band-granat ERA that padding painted as the black line Alex flagged. Zeroing
   only the BOTTOM padding, only on an granat ERA section that ENDS in a
   marquee band, leaves every other .band-granat ERA section untouched (verified
   2026-08-17: index.html #proof is the only such section on the site).
   Two selectors on purpose: the #id is the guaranteed match today, the :has()
   generalises the same fix to any future granat ERA band that ends in a marquee
   without needing a second id. */
#proof,
.band-granat ERA:has(> .marquee-band:last-child) { padding-bottom: 0; }
.marquee-label {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  /* Light band: dark readable gold (the original gold-ink), legible on Seashell */
  color: #8a6d2f;
  text-align: center;
}
.marquee {
  margin-top: 1.6rem;
  overflow: hidden;
  position: relative;
  padding: 0.4rem 0;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.marquee-row {
  display: flex;
  align-items: center;
  gap: 4.5rem;
  width: max-content;
  animation: marqueeScroll 42s linear infinite;
}
.marquee:hover .marquee-row { animation-play-state: paused; }
@keyframes marqueeScroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
.marquee-row img {
  height: 30px;
  width: auto;
  max-width: 130px;
  object-fit: contain;
  /* Light band: the -white.webp source logos are darkened to soft graphite
     silhouettes (brightness(0) = solid dark, held slightly back at 0.72) so they
     read cleanly on the Seashell strip. */
  opacity: 0.72;
  filter: brightness(0);
}

/* ============================================================
   REGISTRATION - request an invitation
   ============================================================ */
.register { border-top: 1px solid var(--line-warm); }
.register-grid {
  display: grid;
  grid-template-columns: 1fr 1.25fr;
  gap: 3.5rem;
  align-items: start;
}
.register-intro > p { margin-top: 0.4rem; max-width: 44ch; }
.register-meta {
  margin-top: 1.6rem;
  display: grid;
  gap: 0.55rem;
  font-family: var(--font-sans);
  font-size: 0.85rem;
  letter-spacing: 0.01em;
  color: var(--ink-muted);
}
.register-meta strong { color: var(--gold-ink); font-weight: 500; }
.register-steps {
  margin-top: 1.8rem;
  border-top: 1px solid var(--line-warm);
  padding-top: 1.4rem;
  display: grid;
  gap: 0.85rem;
}
.register-steps .rstep {
  display: grid;
  grid-template-columns: 28px 1fr;
  gap: 0.8rem;
  font-size: 0.88rem;
  color: var(--ink-soft);
}
.register-steps .rstep-no {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--gold-ink);
  border: 1px solid var(--rt-gold-45);
  width: 26px; height: 26px;
  display: flex; align-items: center; justify-content: center;
}
/* O7 fix (Alex 2026-07-31): .band-seashell .rstep (defined near the top of
   the file, seashell legibility block) and this later, equal-specificity
   .register-steps .rstep both set `color`; the later rule in source order
   wins the tie, so the step copy rendered pure white on the cream #register
   band - readable numbers, near-invisible text beside them. This 3-class
   selector outranks both, so it always wins regardless of source order. */
.band-seashell .register-steps .rstep { color: #10233f; }

.reg-form {
  border: 1px solid var(--line-warm);
  background: var(--card);
  padding: 2rem;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.1rem;
  box-shadow: 0 18px 50px rgba(26, 18, 16, 0.06);
}
.field { display: flex; flex-direction: column; gap: 0.4rem; }
.field.full { grid-column: 1 / -1; }
.field label {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gold-ink);
}
.field label .opt { color: var(--ink-faint); text-transform: none; letter-spacing: 0.04em; }
.field input, .field select {
  background-color: var(--rt-charcoal);
  border: 1px solid var(--line-warm);
  color: var(--on-dark-primary);
  font-family: var(--font-sans);
  font-size: 0.92rem;
  padding: 0.75rem 0.9rem;
  transition: border-color var(--ui-ease);
  width: 100%;
  appearance: none;
}
.field select {
  background-image: linear-gradient(45deg, transparent 50%, var(--gold-ink) 50%), linear-gradient(135deg, var(--gold-ink) 50%, transparent 50%);
  background-position: calc(100% - 18px) 50%, calc(100% - 13px) 50%;
  background-size: 5px 5px;
  background-repeat: no-repeat;
}
.field input:focus, .field select:focus {
  outline: none;
  border-color: var(--rt-gold);
}
.field input::placeholder { color: var(--ink-faint); }
.field .field-hint { font-size: 0.72rem; color: var(--ink-muted); }
.field-error { font-size: 0.74rem; color: var(--rt-red); display: none; }
.field.invalid input, .field.invalid select { border-color: var(--rt-red); }
.field.invalid .field-error { display: block; }

/* LinkedIn-first row (button rendered by register.js when enabled) */
.li-row { grid-column: 1 / -1; display: none; }
.li-row.enabled { display: block; }
.btn-linkedin {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  width: 100%;
  background: #0a66c2;
  border: 1px solid #0a66c2;
  color: #ffffff;
  font-family: var(--font-sans);
  font-size: 0.92rem;
  font-weight: 600;
  padding: 0.85rem 1rem;
  text-decoration: none;
  cursor: pointer;
  transition: filter var(--ui-ease);
}
.btn-linkedin:hover { filter: brightness(1.08); }
.li-divider {
  grid-column: 1 / -1;
  display: none;
  align-items: center;
  gap: 1rem;
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.li-divider.enabled { display: flex; }
.li-divider::before, .li-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line-warm);
}

/* Consent block */
.consents {
  grid-column: 1 / -1;
  display: grid;
  gap: 0.7rem;
  border-top: 1px solid var(--line-warm);
  padding-top: 1.2rem;
}
.consent {
  display: grid;
  grid-template-columns: 18px 1fr;
  gap: 0.7rem;
  align-items: start;
  font-size: 0.8rem;
  color: var(--ink-soft);
  cursor: pointer;
}
.consent input[type="checkbox"] {
  appearance: none;
  width: 16px; height: 16px;
  margin-top: 0.15rem;
  border: 1px solid var(--ink-muted);
  background: #ffffff;
  cursor: pointer;
  position: relative;
  transition: background var(--ui-ease), border-color var(--ui-ease);
}
/* Checked = brand accent, not an error state, so it converts to gold. The tick
   glyph below MUST flip white -> dark granat ERA with it: a white stroke on
   --rt-gold-bright is ~1.8:1 and the tick would read as blank. */
.consent input[type="checkbox"]:checked {
  background: var(--rt-gold-bright);
  border-color: var(--rt-gold-bright);
}
.consent input[type="checkbox"]:checked::after {
  content: "";
  position: absolute;
  left: 4.5px; top: 1.5px;
  width: 4px; height: 8px;
  border: solid var(--background);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.consent a { color: var(--gold-ink); }
.consent .req { color: var(--on-dark-alert); }

.reg-submit-row { grid-column: 1 / -1; display: flex; align-items: center; gap: 1.2rem; flex-wrap: wrap; }
.reg-note {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.04em;
  color: var(--ink-faint);
}
.reg-status {
  grid-column: 1 / -1;
  display: none;
  border: 1px solid var(--rt-gold-60);
  background: var(--rt-gold-08);
  padding: 1rem 1.2rem;
  font-size: 0.88rem;
  color: var(--ink-soft);
}
.reg-status a { color: var(--gold-ink); }
.reg-status.visible { display: block; }
.reg-status.error { border-color: var(--rt-red); background: var(--rt-red-12); }

/* ============================================================
   FAQ
   ============================================================ */
/* FAQ, two-column editorial accordion on granat ERA (Alex 2026-08-03).
   Off the photo: sticky intro left, accordion right, gold hairlines. Dark
   surface = pure white copy + full-brightness gold (no gray). */
.faq-section { padding: clamp(3.5rem, 8vh, 6.5rem) 0; }
.faq-layout {
  display: grid;
  grid-template-columns: 0.82fr 1.18fr;
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: start;
}
.faq-intro { position: sticky; top: 120px; }
.faq-intro h2 { color: var(--on-dark-primary); line-height: 1.02; }
.faq-lede {
  margin-top: 1.1rem;
  color: var(--on-dark-primary);
  font-size: 1rem;
  line-height: 1.65;
  max-width: 34ch;
}
.faq-lede a { color: var(--rt-gold-bright); }
.faq-cta {
  display: inline-block;
  margin-top: 1.6rem;
  font-family: var(--font-mono);
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--rt-gold-bright);
  border-bottom: 1px solid var(--rt-gold-45);
  padding-bottom: 0.25rem;
  transition: color var(--ui-ease), border-color var(--ui-ease);
}
.faq-cta:hover { color: #fff; border-color: #fff; }

.faq-list { margin-top: 0; border-top: 1px solid var(--rt-gold-25); }
.faq-list details { border-bottom: 1px solid var(--rt-gold-25); transition: background var(--ui-ease); }
.faq-list details[open] { background: rgba(221, 192, 116, 0.045); }
.faq-list summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 1.35rem 0.5rem;
  font-size: clamp(1rem, 1.7vw, 1.15rem);
  font-weight: 600;
  color: var(--on-dark-primary);
  transition: color var(--ui-ease);
}
.faq-list summary::-webkit-details-marker { display: none; }
.faq-list summary:hover,
.faq-list details[open] summary { color: var(--rt-gold-bright); }
.faq-list summary .faq-x {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-weight: 400;
  font-size: 1.5rem;
  line-height: 1;
  color: var(--rt-gold-bright);
  transition: transform var(--ui-ease);
}
.faq-list details[open] summary .faq-x { transform: rotate(45deg); }
.faq-list .faq-a {
  padding: 0 0.5rem 1.5rem;
  max-width: 62ch;
  color: var(--on-dark-primary);
  font-size: 0.96rem;
  line-height: 1.72;
}
.faq-list .faq-a a { color: var(--rt-gold-bright); }
@media (max-width: 860px) {
  .faq-layout { grid-template-columns: 1fr; gap: 1.8rem; }
  .faq-intro { position: static; }
  .faq-intro h2 br { display: none; }
}

/* ============================================================
   EVENT FOOTER STRIP - policies, above the canonical footer
   ============================================================ */
.event-strip {
  border-top: 1px solid var(--line-warm);
  background: var(--seashell-alt);
  padding: 1.1rem 0;
}
.event-strip-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem 1.6rem;
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.08em;
  color: var(--ink-muted);
}
.event-strip-links { display: flex; flex-wrap: wrap; gap: 0.5rem 1.4rem; }
.event-strip a { color: var(--ink-soft); text-decoration: none; transition: color var(--ui-ease); }
.event-strip a:hover { color: var(--rt-gold-bright); }
.event-colophon {
  margin-top: 0.9rem;
  padding-top: 0.85rem;
  border-top: 1px solid var(--line-warm);
  font-size: 0.72rem;
  line-height: 1.55;
  color: var(--ink-muted);
}

/* ============================================================
   CANONICAL RT FOOTER (verbatim port - rt-www-home SiteFooter)
   Stays Granat ERA. Never restyled by edition changes.
   ============================================================ */
.cf-footer {
  border-top: 1px solid var(--rt-line);
  padding: 3.5rem 0 2.5rem;
  background: var(--background);
  width: 100vw;
  max-width: none;
  margin: 0;
  text-align: left;
}
.cf-footer .cf-container {
  width: min(1160px, calc(100vw - 2rem));
  margin: 0 auto;
  padding: 0 1rem;
}
.cf-footer-grid {
  display: grid;
  grid-template-columns: 1.5fr 1fr 1fr 1fr;
  gap: 2.5rem;
}
.cf-footer-brand img { display: block; height: 32px; width: auto; }
/* Alex 2026-06-12: footer body text ALL WHITE on dark (gold accents stay gold).
   The home SiteFooter still uses --on-dark-muted; the lift is event-side only. */
.cf-footer-brand p {
  color: var(--on-dark-primary);
  font-size: 0.88rem;
  line-height: 1.55;
  margin-top: 0.8rem;
  max-width: 420px;
}
.cf-footer h4 {
  font-size: 0.8rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--rt-gold);
  margin: 0 0 0.9rem;
  font-family: var(--font-mono);
}
.cf-footer div:not(.cf-footer-brand):not(.cf-footer-grid) {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
}
.cf-footer a {
  color: var(--on-dark-primary);
  font-size: 0.86rem;
  text-decoration: none;
  transition: color 0.15s ease;
}
.cf-footer a:hover { color: var(--rt-gold-bright); }
.cf-footer span { color: var(--on-dark-primary); font-size: 0.82rem; }
.cf-footer-cta { margin-top: 1.4rem; display: flex; flex-direction: column; gap: 0.5rem; max-width: 420px; }
.cf-footer-cta-label { color: var(--rt-gold); font-family: var(--font-mono); font-size: 0.74rem; letter-spacing: 0.1em; }
.cf-footer-cta-link { display: flex; align-items: stretch; border: 1px solid var(--rt-line); transition: border-color 180ms ease; }
.cf-footer-cta-link:hover { border-color: var(--rt-gold-45); }
.cf-footer-cta-fauxinput { flex: 1; padding: 0.7rem 0.9rem; color: var(--on-dark-primary); font-size: 0.85rem; }
.cf-footer-cta-btn { padding: 0.7rem 0.9rem; background: var(--rt-gold-12); color: var(--rt-gold-bright); font-size: 0.82rem; white-space: nowrap; }
.cf-footer-cta-help { color: var(--on-dark-primary); font-size: 0.78rem; line-height: 1.5; }
.cf-footer a.cf-footer-cta-partner { color: var(--rt-gold); }
.cf-footer a.cf-footer-cta-partner:hover { color: var(--rt-gold-bright); }
.cf-footer a.cf-footer-event-featured { color: var(--rt-gold); font-weight: 600; display: inline-flex; align-items: center; flex-wrap: wrap; gap: 0.45rem; }
.cf-footer a.cf-footer-event-featured:hover { color: var(--rt-gold-bright); }
.cf-footer a.cf-footer-event-featured:hover .cf-footer-event-badge { border-color: var(--rt-gold-60); background: var(--rt-gold-12); }
.cf-footer-event-dot { width: 7px; height: 7px; flex: 0 0 auto; border-radius: 50% !important; background: var(--rt-gold-bright); box-shadow: 0 0 0 0 var(--rt-gold-60); animation: cf-footer-pulse 2s ease-out infinite; }
.cf-footer-event-badge { font-family: var(--font-mono); font-size: 0.74rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--rt-gold); border: 1px solid var(--rt-gold-45); background: var(--rt-gold-08); padding: 0.12rem 0.45rem; white-space: nowrap; transition: border-color 180ms ease, background 180ms ease; }
@keyframes cf-footer-pulse {
  0% { box-shadow: 0 0 0 0 var(--rt-gold-60); }
  70% { box-shadow: 0 0 0 6px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}

/* ============================================================
   ILLUSTRATION BANDS - full-bleed interstitials.
   Reuse the canonical photo-scrim tokens (see --photo-scrim): copy-bearing
   bands get the 0.55 veil, the bare divider gets the lighter unifying veil.
   dark -> image -> dark rhythm between content sections.
   ============================================================ */
.illus-band {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: flex-end;
  background: var(--background);
  border-top: 1px solid var(--rt-gold-25);
  border-bottom: 1px solid var(--rt-gold-25);
}
.illus-band.tall { min-height: clamp(360px, 50vh, 580px); }
.illus-band.thin { min-height: clamp(120px, 18vh, 220px); }
.illus-band img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: saturate(var(--photo-saturate));
  z-index: 0;
}
.illus-band.has-copy::after,
.illus-band.thin::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
}
.illus-band.has-copy::after { background: var(--photo-scrim); }
.illus-band.thin::after { background: var(--photo-scrim-light); }
/* Hockney wash top-edge: a 2px palette line marking each illustration band (the
   Hockney-imagery moments) as part of the site-wide palette. Sits above the scrim. */
.illus-band::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  background: var(--hk-wash);
  z-index: 3;
  pointer-events: none;
}
.illus-caption {
  position: relative;
  z-index: 2;
  padding: clamp(1.6rem, 5vh, 3rem) 0;
}
.illus-caption .illus-eyebrow {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  /* Dark band rule: full-brightness gold, never muted */
  color: var(--rt-gold-bright);
}
/* Banded illus-caption (Alex 2026-08-14, picked V3 from the 4-variant review).
   Larger display header + supporting line, four-colour block rule above, times
   picked out inline. Alex set the line breaks explicitly: the header breaks so
   the second line starts "from 15:50", and the supporting line breaks after the
   comma at 17:00. Those <br> are deliberate, not incidental wrapping. */
.illus-caption-banded .illus-rule {
  display: block;
  width: min(520px, 100%);
  height: 5px;
  margin: 0 0 1.1rem;
  border-radius: 2px;
  background: linear-gradient(90deg,
    var(--hk-cerulean) 0 25%, var(--hk-viridian) 25% 50%,
    var(--hk-sand) 50% 75%, var(--hk-coral) 75% 100%);
}
.illus-caption-banded .illus-eyebrow { color: #ffffff; }
.illus-caption-banded .illus-head {
  margin: 0.5rem 0 0;
  font-size: clamp(2rem, 5.4vw, 4rem);
  font-weight: 800;
  line-height: 1.02;
  letter-spacing: -0.03em;
  color: #ffffff;
  text-shadow: 0 2px 22px rgba(6, 28, 56, 0.62), 0 1px 3px rgba(6, 28, 56, 0.55);
}
.illus-caption-banded .illus-head .t-a { color: var(--hk-cerulean); font-weight: 800; }
.illus-caption-banded p { max-width: 46ch; font-weight: 500; }
.illus-caption-banded p .t-b { color: var(--hk-coral); font-weight: 800; }

/* Colourways. The five interstitials share the V3 structure and differ only in
   palette, so they read as a family rather than a repeat. Default (no modifier)
   is the cerulean/coral pair Alex approved on "Between the canvases".
   cw-c = chartreuse & coral, approved 2026-08-14 for "Arrivals" on venue.html. */
.illus-caption-banded.cw-c .illus-rule {
  background: linear-gradient(90deg,
    var(--hk-chartreuse) 0 25%, var(--hk-sand) 25% 50%,
    var(--hk-coral) 50% 75%, var(--hk-rose) 75% 100%);
}
.illus-caption-banded.cw-c .illus-head .t-a { color: var(--hk-chartreuse); }
.illus-caption-banded.cw-c p .t-b { color: var(--hk-coral); }

/* cw-blue-hour = cobalt-led cool, approved 2026-08-14 for "Beyond the Programme"
   on partnerships.html. Three cool steps, cobalt into cerulean into viridian,
   resolved on rose. Cerulean sits in the same family as the blue ceiling of the
   bar photograph, so the headline word tones into the architecture rather than
   fighting it. */
.illus-caption-banded.cw-blue-hour .illus-rule {
  background: linear-gradient(90deg,
    var(--hk-cobalt) 0 25%, var(--hk-cerulean) 25% 50%,
    var(--hk-viridian) 50% 75%, var(--hk-rose) 75% 100%);
}
.illus-caption-banded.cw-blue-hour .illus-head .t-a { color: var(--hk-cerulean-on-photo); }
.illus-caption-banded.cw-blue-hour p .t-b { color: var(--hk-rose-on-photo); }

.illus-caption p {
  margin-top: 0.55rem;
  font-size: clamp(1.15rem, 2.6vw, 1.7rem);
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.15;
  /* Dark band rule: pure white primary copy over the scrim */
  color: var(--on-dark-primary);
  max-width: 22ch;
  text-shadow: 0 2px 22px rgba(6, 28, 56, 0.55), 0 1px 3px rgba(6, 28, 56, 0.45);
}

/* ============================================================
   BREAKPOINTS
   ============================================================ */
@media (max-width: 980px) {
  .concept-grid, .register-grid { grid-template-columns: 1fr; gap: 2.4rem; }
  .acts { grid-template-columns: repeat(2, 1fr); gap: 2rem 1.4rem; }
  .acts::before { display: none; }
  .panels-grid { grid-template-columns: 1fr; }
  .panels-grid.single-cat { grid-template-columns: 1fr; }
  .trust-grid { grid-template-columns: repeat(2, 1fr); }
  .ticket-cards { grid-template-columns: 1fr; max-width: 560px; }
  .practical-grid { grid-template-columns: 1fr; }
  .products { grid-template-columns: repeat(2, 1fr); }
  .product:last-child { grid-column: 1 / -1; }
  .cf-footer-grid { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 720px) {
  section { padding: 4.2rem 0; }
  /* Mobile hero: anchor copy over the darker lower city band and steady it
     with a stronger (still subtle) shadow - the bright sky band stays clear */
  .hero-banner { align-items: flex-end; min-height: clamp(560px, 86vh, 740px); }
  .hero-on-banner {
    padding: 2.2rem 0 2.8rem;
    text-shadow: 0 2px 18px rgba(6, 28, 56, 0.75), 0 1px 3px rgba(6, 28, 56, 0.6);
  }
  .hero-meta { margin: 1.1rem 0 1.3rem; }
  /* Slide masthead marks + countdown: trimmed vertical rhythm at mobile only.
     The lead-logo's taller 2.14:1 ratio (vs the old 3.9:1 nav asset it
     replaced) plus the new tagline add real height to the slide-1 stack;
     this keeps the full stack (logo+tagline+eyebrow+sub+meta+countdown+cta)
     inside the ~698px hero-banner budget at 375x812 (min-height clamp
     560px/86vh/740px) with headroom to spare. Desktop keeps the fuller
     values set above -- desktop viewports have ample vertical room. */
  .hero-lead-logo { margin-bottom: 0.75rem; }
  .hero-tagline { margin-bottom: 0.5rem; }
  .hero-slide-logo { margin-bottom: 0.6rem; }
  .hero-countdown { margin-bottom: 1.3rem; }
  .nav-links {
    position: fixed;
    top: var(--nav-h); left: 0; right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    /* OPAQUE, not --seashell-92. At full drawer height a 0.92 alpha still ghosts
       the hero (countdown digits, CTA buttons) through the open menu. */
    background: var(--seashell);
    border-bottom: 1px solid var(--line-warm);
    padding: 0.6rem 1.4rem 1.4rem;
    display: none;
    z-index: 101;
  }
  /* The open drawer must COVER the page, not float as a content-height card.
     Height-only-as-tall-as-its-links left ~360px of hero visible below it at
     375x812, slicing the countdown in half. Fill from the 64px nav to the
     bottom of the viewport; overflow-y keeps a long menu usable on short
     screens. `top` stays 64px, ten other offsets key off that nav height. */
  .nav-links.open {
    display: flex;
    height: calc(100vh - var(--nav-h));
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  /* Scroll-lock companion. Class name `nav-menu-open` is a contract with the
     nav JS that toggles it on <body>; do not rename one side alone.
     body already sets overflow-x:hidden, this widens it to both axes while
     the drawer is open, then reverts when the class is removed. */
  body.nav-menu-open { overflow: hidden; }
  /* letter-spacing added IN PLACE (not appended): this rule must keep winning
     on font-size over the ported desktop type block upstream, so the drawer's
     own tracking has to ride in the same declaration. */
  .nav-links a:not(.btn-red) { padding: 0.85rem 0; border-bottom: 1px solid var(--line-warm-soft); font-size: 0.95rem; letter-spacing: .05em; }
  .nav-links .btn-red { margin-top: 1rem; text-align: center; }
  /* Flatten the Programme dropdown to a stacked list on mobile */
  .nav-item { flex-direction: column; align-items: stretch; width: 100%; }
  .nav-caret { display: none; }
  .nav-sub {
    position: static; opacity: 1; visibility: visible; transform: none;
    box-shadow: none; border: 0; background: transparent; padding: 0 0 0 1rem;
  }
  .nav-sub a { min-height: 0; padding: 0.85rem 0 !important; }
  .nav-burger { display: flex; }

  .hero-mast { padding: 2.2rem 0 1.8rem; }
  .hero-meta { gap: 0.4rem 0.9rem; font-size: 0.74rem; }
  .hero-banner { height: clamp(240px, 38vh, 420px); }

  .trust-grid { grid-template-columns: 1fr; }
  .acts { grid-template-columns: 1fr; }
  .panel-people { grid-template-columns: repeat(3, 1fr); gap: 0.6rem; }
  .venue-frame { min-height: 0; }
  .venue-content { padding: 4rem 0 3.5rem; }
  /* No mobile scrim override: --photo-scrim is set BY mobile (the harder of
     the two viewports here, since the copy crosses more bright sky without
     the desktop two-column split) and clears AA on both. One flat rule. */
  .venue-stats { gap: 1.6rem; flex-wrap: wrap; }
  .products { grid-template-columns: 1fr; }
  .product:last-child { grid-column: auto; }
  .reg-form { grid-template-columns: 1fr; padding: 1.4rem; }
  .practical-list li { grid-template-columns: 1fr; gap: 0.2rem; }
  .event-strip-inner { justify-content: center; text-align: center; }

  .cf-footer-grid { grid-template-columns: 1fr; text-align: center; }
  .cf-footer-brand { display: flex; flex-direction: column; align-items: center; }
  .cf-footer-brand img { margin: 0 auto; }
  .cf-footer-brand p { margin-left: auto; margin-right: auto; max-width: none; }
  .cf-footer-cta { margin-left: auto; margin-right: auto; }
  .cf-footer div:not(.cf-footer-brand):not(.cf-footer-grid) { align-items: center; }
}

@media (max-width: 640px) {
  .rt-shell { width: calc(100vw - 1.5rem); }
  .cf-footer a.cf-footer-event-featured { justify-content: center; width: 100%; text-align: center; }
}

/* ============================================================
   REDUCED MOTION - freeze cinematics, keep everything legible
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .banner-sweep { animation: none; }
  .stage { animation: none; opacity: 1; transform: none; }
  .ticker-row { animation: none; }
  .reveal { opacity: 1; transform: none; transition: none; }
  .eyebrow-rule { width: 96px; transition: none; }
  .marquee-row { animation: none; flex-wrap: wrap; width: auto; justify-content: center; gap: 2rem 3rem; }
  .cf-footer-event-dot { animation: none; }
  .edition-card:hover, .panel-block:hover, .ticket-card:hover, .btn-red:hover, .btn-ghost:hover { transform: none; }
}

/* ============ Ink-law light-band fix (2026-08-03, Director) ============
   .keynote-moment p (L1130), .practical-list strong (L1401), .group-nudge strong (L1501),
   .member-terms p strong (L1520) are defined AFTER the .band-seashell overrides (~L620) and
   won on equal specificity -> white text invisible on seashell (speakers keynote / venue
   getting-there / invite LPs). These .band-seashell-scoped selectors win by specificity. */
.band-seashell .keynote-moment p { color: #10233f; }
.band-seashell .practical-list strong,
.band-seashell .group-nudge strong,
.band-seashell .member-terms p strong { color: #061c38; }
/* Pass-2 additions (2026-08-03): after the speakers roster + venue bands were
   lightened, three secondary-text classes stayed white/bright-gold because their
   element rules (.panel-block .panel-desc L1183, .practical-list .pl-sub L1402,
   .product .product-kicker L1557) tie the .band-seashell overrides on specificity
   but win on source order -> invisible on seashell. Extra parent class = 0,3,0 wins. */
.band-seashell .panel-block .panel-desc { color: #10233f; }
.band-seashell .practical-list .pl-sub { color: #10233f; }
.band-seashell .product .product-kicker { color: #8a6a1e; }
/* ROOT FIX (2026-08-03, pass-3): the near-white ink tokens resolve to #ffffff /
   gold-bright at :root (correct on dark bands) but ~40 element rules consume them
   via var() and tie their .band-seashell overrides on specificity, losing on source
   order -> invisible text on the light band (panel-desc, pl-sub, product-kicker,
   nominate-cta span, and any future descendant). Redefining the TOKENS inside the
   .band-seashell scope makes every var(--ink-*) resolve dark on a light band by
   inheritance -- no per-selector specificity war, covers current + future elements.
   Verified: these tokens are text-color only (one dark border at L1786, correct on
   light) and no dark-bg card nests inside a seashell section. */
.band-seashell {
  --ink-soft: #10233f;
  --on-dark-secondary: #10233f;
  --ink-muted: #10233f;
  --on-dark-muted: #10233f;
  --ink-faint: #8a6a1e;
  --on-dark-faint: #8a6a1e;
}

/* ============================================================
   DIRECTOR PASS 2026-08-03 (Alex live-review batch)
   Subpage-hero parity · home 3-state slider · light form fields
   ============================================================ */

/* Subpage heroes read like the home hero: full-bleed event image, taller,
   copy centred (Alex: "same hero banner as home, only with an image"). */
.subpage-hero {
  min-height: clamp(480px, 74vh, 660px);
  align-items: center;
}

/* Home hero 3-state slider: three .hero-slide overlays stacked in the banner,
   only .is-active visible. Rotator + dots built by js/hero-rotator.js. */
.hero-slide {
  position: absolute;
  top: 0; bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  justify-content: center;
  opacity: 0;
  visibility: hidden;
  transition: opacity 500ms ease;
  pointer-events: none;
}
.hero-slide.is-active {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
}
@media (prefers-reduced-motion: reduce) {
  .hero-slide { transition: none; }
}
.hero-dots {
  position: absolute;
  z-index: 4;
  left: 50%;
  transform: translateX(-50%);
  bottom: clamp(1.1rem, 3vh, 2rem);
  display: flex;
  gap: 0.6rem;
}
.hero-dot {
  width: 10px; height: 10px;
  padding: 0;
  border: 1px solid var(--rt-gold-bright);
  background: transparent;
  cursor: pointer;
  transition: background 180ms ease;
}
.hero-dot.is-active { background: var(--rt-gold-bright); }
.hero-dot:focus-visible { outline: 2px solid #ffffff; outline-offset: 2px; }

/* Form inputs: standard light fields, not dark (Alex live-review). */
.field input, .field select {
  background-color: #ffffff;
  border: 1px solid rgba(6, 28, 56, 0.22);
  color: #061c38;
}
.field input::placeholder { color: rgba(20, 17, 12, 0.45); }
.field select {
  background-image: linear-gradient(45deg, transparent 50%, #6b5a2a 50%), linear-gradient(135deg, #6b5a2a 50%, transparent 50%);
}
.field input:focus, .field select:focus { border-color: var(--rt-gold); }

/* Run of show, aspirational timeline (MSN26 gold pulsing-dot rail; ink law: pure white + gold) */
.run-of-show { list-style: none; margin: 2.1rem 0 0; padding: 0 0 0 2.1rem; position: relative; max-width: 680px; text-align: left; }
.run-of-show::before {
  content: ""; position: absolute; left: 5px; top: 0.9rem; bottom: 1rem; width: 2px;
  background: linear-gradient(to bottom, var(--rt-gold-bright) 0%, rgba(221,192,116,0.16) 100%);
}
.run-of-show li {
  position: relative; display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.35rem 1.5rem;
  padding: 1.15rem 0; border-bottom: 1px solid rgba(255,255,255,0.10); transition: transform 180ms ease;
}
.run-of-show li:last-child { border-bottom: 0; }
.run-of-show li::before {
  content: ""; position: absolute; left: -2.1rem; top: 1.7rem; width: 11px; height: 11px; border-radius: 50%;
  background: var(--rt-gold-bright); border: 3px solid var(--rt-charcoal, #0a2d58);
  box-shadow: 0 0 0 1px rgba(221,192,116,0.5); transform: translateX(0);
  animation: rosPulse 2.6s ease-in-out infinite;
}
.run-of-show li:nth-child(2)::before { animation-delay: 0.3s; }
.run-of-show li:nth-child(3)::before { animation-delay: 0.6s; }
.run-of-show li:nth-child(4)::before { animation-delay: 0.9s; }
.run-of-show li:nth-child(5)::before { animation-delay: 1.2s; }
@keyframes rosPulse {
  0%, 100% { box-shadow: 0 0 0 1px rgba(221,192,116,0.5); }
  50% { box-shadow: 0 0 0 6px rgba(221,192,116,0.12); }
}
.run-of-show .ros-time { flex: 0 0 auto; min-width: 132px; color: var(--rt-gold-bright); font-weight: 600; font-size: 1.14rem; font-variant-numeric: tabular-nums; letter-spacing: 0.01em; }
.run-of-show .ros-what { color: #ffffff; font-size: 1.14rem; font-weight: 500; }
.run-of-show .ros-what small { display: block; color: #ffffff; opacity: 0.82; font-size: 0.74em; font-weight: 400; letter-spacing: 0.02em; margin-top: 0.28rem; }
@media (prefers-reduced-motion: reduce) { .run-of-show li::before { animation: none; } }
@media (max-width: 560px) {
  .run-of-show { padding-left: 1.75rem; }
  .run-of-show li { flex-direction: column; gap: 0.2rem; padding: 0.95rem 0; }
  .run-of-show .ros-time { min-width: 0; }
  .run-of-show li::before { left: -1.75rem; top: 1.35rem; }
}

/* ============================================================
   DIRECTOR (2026-08-03): centered hero overlay across ALL pages
   (matches the MSN26 center-aligned design) + Home hero countdown.
   Ink law on the dark banner: pure #fff text + gold accents only.
   ============================================================ */
.hero-on-banner { text-align: center; }
.hero-on-banner .hero-eyebrow { display: inline-block; }
.hero-on-banner h1 { margin-left: auto; margin-right: auto; }
.hero-on-banner .hero-sub { margin-left: auto; margin-right: auto; }
.hero-on-banner .hero-meta { justify-content: center; }
.hero-on-banner .hero-cta-row { justify-content: center; }

/* Home hero countdown to the event (reuses the MSN26 countdown pattern) */
.hero-countdown-label {
  display: block;
  margin: 0.2rem 0 0.55rem;
  font-family: var(--font-sans);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #ffffff;
}
.hero-countdown {
  display: flex;
  justify-content: center;
  gap: clamp(1rem, 3vw, 2.4rem);
  margin: 0 0 1.15rem;
}
.hero-countdown .cd-item { text-align: center; min-width: 3.2rem; }
.hero-countdown .cd-num {
  display: block;
  /* Larger numerals (Alex: "countdown should be LARGER"), ~1.4x at the
     mobile floor and ~1.5x at the desktop ceiling of the prior
     clamp(2rem,5vw,3rem). At 375px the 4 items (2-digit numeral + label)
     total roughly 270px incl. gaps, comfortably inside the ~351px
     .rt-shell content width, so all 4 stay on one row. */
  font-size: clamp(2.8rem, 6.4vw, 4.5rem);
  font-weight: 700;
  line-height: 1;
  color: var(--rt-gold-bright);
  font-variant-numeric: tabular-nums;
}
.hero-countdown .cd-label {
  display: block;
  margin-top: 0.45rem;
  font-family: var(--font-sans);
  font-size: 0.6rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #ffffff;
}
@media (max-width: 560px) {
  .hero-countdown { gap: 0.8rem; }
  .hero-countdown .cd-item { min-width: 2.6rem; }
}

/* CANON:era26-hero-cta-gold-buttons */
/* Hero-slide primary CTA: GOLD instead of RED (Alex live-review, same
   date). The highlight-word flip lives at .hero-slide h1 .h1-red near
   the hero rules above; this is the button half. Scoped to .hero-slide
   only, so the nav CTA and every in-page .btn-red (partnerships,
   speakers nominate, register submit, etc.) keep the brand red.
   Contrast: dark granat ERA ink (var(--background) #061c38) on gold
   (--rt-gold-bright #ddc074) measures approx 10.8:1 (AAA). White text
   was checked first and fails at approx 1.8:1, hence the dark ink. */
.hero-slide .btn-red,
.nav .btn-red {
  background: var(--rt-gold-bright);
  border-color: var(--rt-gold-bright);
  color: var(--background);
}
.hero-slide .btn-red:hover {
  background: var(--rt-gold);
  border-color: var(--rt-gold);
  color: var(--background); /* approx 8.1:1 on the deeper hover gold, still AAA */
  /* Replaces the base .btn-red:hover red-tinted shadow (var(--rt-gold-25)
     instead of var(--rt-red-12)) so the glow matches the gold fill. */
  box-shadow: 0 8px 28px var(--rt-gold-25);
}
/* /CANON:era26-hero-cta-gold-buttons */

/* Slide 1 lead copy: elevate off the default Inter sans (Alex: "too
   simple"), using the site's existing --font-serif token as an accent.
   Inter stays the locked body font everywhere else on the site; this
   touches only the slide-1 lede, not .hero-sub globally. */
[data-slide="1"] .hero-sub {
  font-family: var(--font-serif);
  font-weight: 400;
  font-style: italic;
}

/* ============================================================
   NO-SCRIM LEGIBILITY (Alex 2026-08-03: no dark overlays on images)
   The photo scrims are transparent now, so copy that used to sit on the
   0.55 veil keeps its contrast from a LOCAL text-shadow on the TEXT only.
   The shadow darkens the letters' own halo, never the picture behind them.
   ============================================================ */
.venue-content .eyebrow,
.venue-content h2,
.venue-content p,
.venue-content .vstat .vstat-num,
.venue-content .vstat .vstat-label,
.illus-caption .illus-eyebrow,
.band-photo .rt-shell :is(h2, h3, p, .eyebrow, .illus-eyebrow, li) {
  text-shadow: 0 2px 22px rgba(6, 28, 56, 0.62), 0 1px 3px rgba(6, 28, 56, 0.55);
}

/* Small text over a BUSY illustration, not a flat dark band (Alex 2026-08-14, live review:
   "not all is visible properly; maybe make this white/bold").
   #partners is the site's only .band-photo CONTENT section. The eyebrow was --gold-ink
   (#ddc074) at weight 500 / 0.78rem uppercase, and the CTA note was --ink-muted mono at
   0.72rem, both sitting on orange-and-blue paint behind a 0.55 scrim. Small low-weight
   gold and grey are the two worst cases against that image, so on .band-photo ONLY they
   go pure white and gain weight. Flat dark bands keep the gold eyebrow: unchanged there.
   Note for future QA: the contrast scanner ABSTAINS on background-image ancestors (it
   cannot composite a photo to one colour), so this band is never covered by the automated
   sweep and must be eyeballed on render at 375 and 1440. */
.band-photo .rt-shell .eyebrow {
  color: #ffffff;
  font-weight: 700;
}
.band-photo .rt-shell .partner-cta-note {
  color: #ffffff;
}

/* ============================================================
   LIVE-REVIEW BATCH, Alex 2026-08-03
   (1) Rounded boxes to match MSN26 (explicit Alex instruction; this overrides
       the RT sharp-corner default). Heroes / nav / sections / full-bleed square.
   (2) Hero-only dark overlay for the video (images stay clean, standing rule).
   (3) Slider dots moved below the CTA buttons (no overlap).
   ============================================================ */
.teaser-card,
.edition-card,
.panel-block,
.panel-detail,
.ticket-card,
.faq-list details,
.glass-body,
.rstep,
.tba-avatar,
.keynote-moment,
.practical-col,
.member-terms,
.nominate-cta,
.group-nudge,
.reg-form,
/* --- Round-EVERYTHING pass (Alex 2026-08-03, 2nd request; screenshot showed the
   four-up cream card band still square). Additions below. --- */
.nav-sub,                 /* Programme dropdown panel (a box INSIDE the nav; the nav bar itself stays square) */
.subpage-hero-plate,      /* local text plate on the subpage hero */
.trust-grid,              /* THE four-up cream card band: FRAME only, see note below */
.products,                /* sponsor-tier band (incl. the #partners glass variant): FRAME only */
.concept-facts,           /* FORMAT/SCALE/... spec table: FRAME only, see note below */
.reg-status,              /* form success / error callout */
.tribute-portrait img,    /* bordered image frame */
.ap-row { border-radius: var(--radius-card); }   /* was a hardcoded 18px; now on the token */
.field input,
.field select,
.btn-red,
.btn-ghost,
.btn-on-banner,
.btn-linkedin,
.cf-footer-cta-link { border-radius: var(--radius-control); }
.chip,
.edition-badge,
.ticket-tier,
.mod-tag,
.act-time,
.popular-badge,           /* additions to the pill family */
.cf-footer-event-badge,
.rstep-no,
.ap-chip,
.msn-subnav a { border-radius: var(--radius-pill); }
/* Corner-anchored plate: flush to the banner's bottom AND left full-bleed edges,
   so only its ONE free corner rounds. Rounding all four would detach it and show
   the photo through the notches. */
.hero-banner .banner-caption { border-radius: 0 var(--radius-card) 0 0; }

/* Clipping companions, a radius does nothing unless the box that owns it clips
   its square-cornered children. */
.edition-card { overflow: hidden; }   /* clip the edition image zoom to the rounded card */
.product { overflow: hidden; }        /* clip the 2px ::before tier-accent bar to the corners */
.concept-facts { overflow: hidden; }  /* clip the square dt/dd rows to the rounded gold frame */
/* Same frame-clips-square-cells pattern as .concept-facts above, applied to the
   other two 1px-gap mosaic grids. Without it the square corner cells poke past
   the rounded gold frame. See the mosaic note below for why the CELLS stay square. */
.trust-grid { overflow: hidden; }     /* clip the square .trust-cell corners to the rounded gold frame */
.products { overflow: hidden; }       /* clip the square .product corners to the rounded gold frame */
.cf-footer-cta-link { overflow: hidden; }  /* clip the gold-tinted submit child at the right end */
/* NOT clipped on purpose: .ticket-card, .popular-badge is positioned to overhang
   its top edge (translateY(-50%)); overflow:hidden would decapitate it. */

/* DELIBERATELY LEFT SQUARE, with reasons:
   .fact-row, spec-table ROWS. The frame around them is rounded and clips them;
     rounding each row individually is wrong for a table and would break the
     continuous gold rules between FORMAT / SCALE / DIALOGUE / VENUE / TIMING.
   .consent input[type=checkbox], a 16px box at a 10px radius reads as a RADIO
     button. Squaring it preserves the checkbox/radio semantic distinction.
   .nav, .msn-subnav, .ticker, .cf-footer, .event-strip, .marquee-band, bars and
     full-bleed bands (per instruction).
   .hero-banner, .hero-slider, .subpage-hero, .band-photo, .illus-band,
     .venue-frame, full-bleed hero / photo sections (per instruction).
   .hero-dot, .hero-slider-dot, .nav-burger span, .act::before,
     .ticket-benefits li::before, decorative indicators and markers, not text
     boxes (.hero-slider-dot is a 3px bar; radius is meaningless on it).
   .msn-subnav.lit ...::before, decorative conic-gradient ring that must trace
     .msn-subnav-inner, which stays square; its 5px is kept in sync with that box. */
/* Audit-driven additions (same 2026-08-03 pass, MSN26 parity):
   .panel-detail (companion box beside .panel-block), .tba-avatar (the
   speaker headshot/placeholder box Alex named explicitly), .keynote-moment,
   .practical-col, .member-terms, .nominate-cta + .group-nudge (CTA/notice
   boxes), .reg-form (the registration card, already carries a drop-shadow).
   .mod-tag + .act-time join the pill group (small text badges, same family
   as .chip/.ticket-tier).
   MOSAIC GRIDS, FRAME ROUNDS, CELLS STAY SQUARE (corrected 2026-08-03 after
   live QA). .trust-grid/.trust-cell, .products/.product and
   .concept-facts/.fact-row are 1px-gap "mosaic" grids: the gold DIVIDERS are
   the container's background showing through the grid gap, not per-cell
   borders. A radius on the CELLS makes each pair of neighbouring interior
   corners curve away from each other, and the gold gap-field shows through the
   gap as a teardrop/flame blob at the top and bottom of every interior seam
   (3 in the trust band, 4 in the products grid, read as a lighting artifact
   over the partners photo). So the radius lives on the CONTAINER only, with
   overflow:hidden clipping the square cells to the rounded frame: outer corners
   round, interior dividers run dead straight. Do NOT re-add border-radius to
   .trust-cell, .product, or .fact-row, that is the defect, not the fix.
   Full-bleed
   bands, the hero banner, section dividers, and the nav stay square per
   instruction (.hero-banner, .hero-slider, .band-photo, .subpage-hero,
   .venue-frame, .nav are untouched above). */

/* Hero video dark overlay, scoped to .hero-banner ONLY, independent of the
   zeroed image scrim tokens. Above the video (z0), below the copy (z2). */
.hero-banner::before {
  background: linear-gradient(180deg,
    rgba(10, 12, 18, 0.36) 0%,
    rgba(10, 12, 18, 0.20) 44%,
    rgba(10, 12, 18, 0.54) 100%);
}

/* Slider dots below the CTA buttons (no overlap) */
.hero-dots { bottom: clamp(0.85rem, 2.2vh, 1.35rem); }
.hero-on-banner { padding-bottom: clamp(3.4rem, 8vh, 5rem); }

/* Anti-jitter: promote the hero video to its own GPU compositor layer so the
   ambient gold sweep + slide crossfades repaint independently of the moving
   footage (additive to the CANON .hero-video geometry; does not alter it). */
.hero-video {
  transform: translateZ(0);
  backface-visibility: hidden;
  will-change: opacity;
}

/* CANON:era26-hero-logo-sizing */
/* New leading hero slide: the all-white event logo IS the masthead (no <h1>).
   MUST override `.hero-banner img { position:absolute; inset:0; object-fit:cover;
   height:116% }` (that rule matches every descendant <img>, which otherwise turns
   this logo into a giant full-bleed cover watermark). Higher-specificity selector
   + explicit resets put the logo back into the slide's flex flow as a crisp mark.
   Sized for the official lockup (1555x728, ratio ~2.14:1 -- retuned from the
   earlier 3.9:1 nav-logo placeholder asset). height:auto + object-fit:contain
   track whichever ratio the source SVG carries, so neither asset can ever
   distort or letterbox; only the width clamp below needed retuning. Width
   floor keeps the taller lockup a compact mark on mobile (260px wide ->
   ~122px tall) while letting it read as a genuinely large masthead on
   desktop (450px wide -> ~211px tall) without overwhelming the banner. */
/* Slides 2-4 small mark. MUST carry the same `.hero-banner img.<class>` shape as
   the lead logo: the legacy `.hero-slide img { width:100%; height:100%;
   object-fit:cover }` rule (class+element) outranks a bare `.hero-slide-logo`
   class, which stretched the lockup full-bleed across the banner so it bled
   through the cross-fade onto the next slide (Alex, 2026-08-03). */
.hero-banner img.hero-slide-logo,
.hero-slide-logo {
  position: relative;
  inset: auto;
  width: clamp(150px, 15vw, 210px);
  max-width: 60%;
  height: auto;
  object-fit: contain;
  filter: none;
  will-change: auto;
  display: block;
  margin: 0 auto 0.9rem;
}

.hero-banner img.hero-lead-logo,
.hero-lead-logo {
  position: relative;
  inset: auto;
  width: clamp(210px, 23vw, 350px);
  max-height: 21vh;
  max-width: 88%;
  height: auto;
  object-fit: contain;
  filter: none;
  will-change: auto;
  display: block;
  margin: 0 auto 0.55rem;   /* center the mark (copy centers via text-align; the sized logo needs auto side margins) */
}
/* /CANON:era26-hero-logo-sizing */

/* Slide-1 tagline: the event's promise line, directly under the lead mark.
   Pure white (--on-dark-primary), not gold: this keeps the gold accent
   confined to the logo's own gradient above and the eyebrow label below, so
   the stack reads gold(mark) -> white(tagline) -> gold(eyebrow) instead of
   three consecutive gold-toned elements blurring into one another. Sized
   between the mark and the eyebrow in the visual hierarchy; ink-law
   compliant (dark-surface-legibility: pure white or full-brightness gold
   only on a dark surface, never a mid-tone). */
.hero-tagline {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: clamp(1.05rem, 2.2vw, 1.5rem);
  letter-spacing: 0.02em;
  color: var(--on-dark-primary);
  margin: 0 0 0.45rem;
}

/* ============================================================================
   PROGRAMME SUB-NAV, MSN26 .msn-subnav port, re-skinned to the event dark
   palette + INK LAW (inactive links pure #fff, not MSN26's grey #b0aca8).
   Sticky under the fixed nav (var(--nav-h)) only. Markup +
   js/subnav.js are cloned verbatim from MSN26 so this CSS applies as-is.
   Scoped via `.msn-subnav ~ .hero` so ONLY canvases (the one page that has the
   sub-bar) is affected, the other subpages are untouched (no body padding).
   ============================================================================ */
@property --msn-sweep { syntax: '<angle>'; initial-value: 0deg; inherits: true; }
.msn-subnav {
  position: sticky;
  top: var(--nav-h);          /* stick right below the fixed nav chrome */
  margin-top: var(--nav-h-rest);   /* clear that chrome at load (subnav is the 1st in-flow element) */
  z-index: 90;         /* below the fixed nav(100)+ticker(99) so it slides under them */
  background: #061c38;
  border-bottom: 1px solid #000;
  transition: transform .28s ease, opacity .28s ease;
}
.msn-subnav ~ .hero { padding-top: 0; }  /* chrome already cleared by the subnav margin */
.msn-subnav.is-hidden { transform: translateY(-120%); opacity: 0; pointer-events: none; }
.msn-subnav-inner {
  position: relative; max-width: 1180px; margin: 0 auto;
  display: flex; align-items: center; gap: .1rem;
  padding: .4rem 2rem; flex-wrap: wrap;
}
.msn-subnav-inner > a:first-child { margin-left: auto; }  /* push items right; collapses on mobile */
.msn-subnav a {
  font-family: var(--font-sans);
  font-size: .74rem; font-weight: 500; letter-spacing: .1em; text-transform: uppercase;
  text-decoration: none; color: #ffffff;   /* INK LAW: pure white inactive (MSN26 used grey) */
  padding: .5rem .85rem; border-radius: var(--radius-pill); white-space: nowrap;
  transition: color .15s ease, background .15s ease;
}
.msn-subnav a:hover { color: #ddc074; }
.msn-subnav a.active,
.msn-subnav a[aria-current="page"] {   /* active = gold fill, black text */
  background: #ddc074; color: #061c38; font-weight: 600;
}
.msn-subnav-cta {
  margin-left: .6rem; color: var(--background) !important; background: var(--rt-gold-bright);
  padding: .5rem 1rem !important; border-radius: var(--radius-pill);
}
.msn-subnav-cta:hover { background: var(--rt-gold); color: var(--background) !important; }
/* Travelling-light orbit (subnav.js drives --msn-sweep; JS owns the motion) */
.msn-subnav.lit .msn-subnav-inner::before {
  content: ''; position: absolute; inset: 0; padding: 2px; border-radius: 5px;
  background: conic-gradient(from var(--msn-sweep),
     transparent 0deg, transparent 280deg,
     rgba(255,216,122,.55) 305deg, #ffe9b0 330deg, #fff 345deg, #fff 352deg,
     rgba(255,233,176,.6) 360deg);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  filter: drop-shadow(0 0 6px rgba(255,224,150,.95));
  animation: none; pointer-events: none;
}
/* Section anchors clear the fixed nav + the sticky sub-bar on jump.
   Was a hand-listed `#programme, #canvases, #speakers-teaser`, scoped to the one
   page that had a sub-bar, and already stale now that the bar is on 7 pages.
   DURABLE FORM: `body:has(.msn-subnav)` scopes the offset to pages that actually
   carry the bar, and `section[id]` catches every anchor target, verified that all
   18 in-use anchors across partnerships / speakers / tribute / venue / canvases are
   `<section id>`, so sections added later by other agents (gallery, insights) are
   covered with no id list to keep in sync. It CANNOT over-apply to the home page:
   index.html contains zero `.msn-subnav`, so the :has() never matches there and it
   keeps the global html{scroll-padding-top:64px}. Deliberately NOT `[id]`, that
   would put a 160px scroll-margin on every form field and shove the register
   inputs down on focus.
   Arithmetic: 64px fixed nav + ~44px sub-bar (.4rem x2 inner padding + ~30px link
   box + 1px border) = ~108px of chrome, so 160px leaves ~52px of breathing room.
   Under 768px .msn-subnav becomes position:static and stops overlaying, so only
   the 64px nav counts -> 96px (64 + 32 breathing); keeping 160 there would drop
   every mobile jump ~44px too low. */
/* 172 -> 138 i 108 -> 74 po zdjeciu gornego pietra nawigacji (34 px mniej
   stalego chromu). Zweryfikowane pomiarem realnego skoku do kotwicy, nie
   przeliczone na papierze. */
body:has(.msn-subnav) section[id] { scroll-margin-top: 138px; }
@media (max-width: 768px) {
  body:has(.msn-subnav) section[id] { scroll-margin-top: 74px; }
}
@media (max-width: 768px) {
  .msn-subnav { position: static; top: auto; }   /* chrome still fixed; bar scrolls in-flow */
  .msn-subnav-inner {
    justify-content: flex-start; padding: .45rem 1.1rem; gap: 0; flex-wrap: nowrap;
    overflow-x: auto; -webkit-overflow-scrolling: touch;
  }
  .msn-subnav-inner > a:first-child { margin-left: 0; }
  .msn-subnav-cta { margin-left: .5rem; }
}
@media (prefers-reduced-motion: reduce) {
  .msn-subnav.lit .msn-subnav-inner::before { animation: none; }
}

/* ============================================================================
   PROGRAMME AGENDA TIMELINE, MSN26 .ap-* port (already dark; matches the base).
   Rounded rows (18px) per the round-everything pass. Playfair→Georgia serif
   fallback keeps the MSN26 editorial character (Playfair isn't loaded here).
   ============================================================================ */
.agenda-prog-list { display:flex; flex-direction:column; gap:18px; }
.ap-row {
  display:grid; grid-template-columns:170px 1fr; gap:24px;
  padding:22px 26px 23px; border-radius: var(--radius-card);
  background:rgba(28,25,21,.42);
  border:1px solid rgba(255,255,255,.16);
  backdrop-filter:blur(16px) saturate(135%); -webkit-backdrop-filter:blur(16px) saturate(135%);
  box-shadow:0 14px 40px rgba(0,0,0,.30), inset 0 1px 0 rgba(255,255,255,.12);
  position:relative; overflow:hidden;
}
.ap-row::before {
  content:""; position:absolute; inset:0 0 auto 0; height:1px;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.4),transparent);
}
.ap-time {
  font-family:'Playfair Display',Georgia,serif; font-weight:600; font-size:23px;
  color:#ddc074; white-space:nowrap; line-height:1.15;
  border-right:1px solid rgba(255,255,255,.13); padding-right:22px;
}
.ap-content { min-width:0; }
.ap-title {
  font-family:'Playfair Display',Georgia,serif; font-weight:600; font-size:21px;
  line-height:1.24; color:#fff; text-wrap:balance; margin:0;
}
.ap-desc { margin-top:9px; font-size:14.5px; color:#fff; line-height:1.6; text-wrap:pretty; }
.ap-chips { margin-top:14px; display:flex; flex-wrap:wrap; gap:8px; }
.ap-chip {
  font-size:11.5px; letter-spacing:.06em; padding:5px 12px; border-radius: var(--radius-pill);
  border:1px solid rgba(221,192,116,.30); color:#ddc074;
  background:rgba(221,192,116,.10); white-space:nowrap;
}
.ap-chip-loc { color:#fff; border-color:rgba(255,255,255,.22); background:rgba(255,255,255,.07); }
.ap-endline {
  margin-top:52px; text-align:center;
  font-family:'Playfair Display',Georgia,serif; font-style:italic;
  font-size:clamp(22px,3.4vw,30px); color:#fff; text-shadow:0 1px 14px rgba(0,0,0,.5);
}
@media (max-width:768px) {
  .ap-row { grid-template-columns:1fr; gap:14px; padding:18px 18px 19px; }
  .ap-time {
    border-right:none; border-bottom:1px solid rgba(255,255,255,.14);
    padding-right:0; padding-bottom:13px; font-size:20px;
  }
  .ap-title { font-size:18.5px; }
}

/* ============================================================================
   CREAM-BAND CTA VARIANT (Director 2026-08-03), contrast safety for the
   red -> gold conversion. NOT a style preference: a measurement.
   --rt-gold-bright (#ddc074) is a LIGHT gold. Its dark ink is excellent
   (~11.8:1), but the BUTTON SHAPE cannot separate from a cream page: #ddc074 vs
   #fffaf6 measures ~1.6:1, and even the deeper --rt-gold (#c5a55a) only reaches
   ~2.3:1, both under the 3:1 floor for a UI boundary. So on .band-seashell the
   CTA switches to the light band's own deep gold #8a6a1e (already the
   light-band gold ink throughout this sheet, not a new shade): ~4.9:1 against
   the cream page for the edge, ~5.1:1 for WHITE label text on the fill. Hover
   deepens to #6b5a2a (also already here, the light-band select arrow) at ~6.7:1.
   This is the rule that carries #reg-submit, which sits on
   <section class="register band-seashell">. The other two CTAs the client named
   sit on DARK bands, "Request VIP" in .tickets (charcoal) and the
   partnership-menu CTA in #partners (band-photo), so they correctly keep the
   gold-bright fill + dark ink from the base rule.
   ============================================================================ */
.band-seashell .btn-red {
  background: #8a6a1e;
  border-color: #8a6a1e;
  color: #ffffff;
}
.band-seashell .btn-red:hover {
  background: #6b5a2a;
  border-color: #6b5a2a;
  color: #ffffff;
  box-shadow: 0 8px 28px rgba(138, 106, 30, 0.25);
}
/* Ghost button on cream: --rt-gold-60 is a light gold and all but vanishes on
   #fffaf6. Lift the FRAME to the light band's deep gold at the alpha
   .band-seashell .teaser-card:hover already uses. Border only. */
.band-seashell .btn-ghost { border-color: rgba(138, 106, 30, 0.55); }
.band-seashell .btn-ghost:hover { border-color: #8a6a1e; }
/* Active chip, cream variant, same reason as the CTA: gold-bright cannot
   separate from a cream page (~1.6:1 edge). Deep gold + white label = ~4.9:1
   edge, ~5.1:1 text. */
.band-seashell .chip.active { background: #8a6a1e; border-color: #8a6a1e; color: #ffffff; }

/* Text-selection highlight. Was undefined, so it fell back to the browser's
   blue, the one highlight on the site that was neither gold nor brand. Dark
   granat ERA ink on gold-bright measures ~11.8:1. */
::selection { background: var(--rt-gold-bright); color: var(--background); }
::-moz-selection { background: var(--rt-gold-bright); color: var(--background); }

/* CANON:era26-hero-slide-geometry */
/* Two-zone hero slide (Alex 2026-08-03, client: slide 1 "too dispersed", CTA
   buttons and slider dots landing at different heights per slide, and the CTAs
   overlapping the dots on slide 1).

   .hero-slide is position:absolute; top:0; bottom:0 with display:flex;
   flex-direction:column, and .hero-on-banner already reserves the dots' strip
   via padding-bottom: clamp(3.4rem, 8vh, 5rem). Making the bottom zone a
   non-growing flex item while the top zone absorbs ALL free space pins
   .hero-slide-bottom, and therefore the CTA row, to an identical y on all
   four slides, clear of the dots. justify-content moves to flex-start so the
   two zones (not the centred stack) own the distribution; the top zone keeps
   its own centring so slide 1's shorter stack still reads as one cluster.
   padding-top clears the fixed nav that overlays the banner. */
.hero-slide {
  justify-content: flex-start;
  padding-top: clamp(4.75rem, 9vh, 6.5rem);
}
.hero-slide-top {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.hero-slide-bottom {
  flex: 0 0 auto;
}

/* Headline cap for the hero slides only. The shared `.hero h1` clamp resolves to
   112px at 1440, which made the tallest slide (3: logo + eyebrow + two-line h1 +
   three-line lede + meta) overrun the top zone, so `.hero-meta` collided with
   "The Forum begins in" below it. Capping the h1 gives the tallest stack ~75px of
   headroom inside the zone; the CTA/dots baseline is unaffected because the bottom
   zone never grows. Applies to every slide, so slide 1 keeps font parity. */
.hero-banner .hero-slide h1 {
  font-size: clamp(2rem, 5.6vw, 4.5rem);
  line-height: 1.04;
}
/* The lede sits between the capped h1 and the meta row; keep it from re-spending
   the headroom the cap just bought. */
.hero-banner .hero-slide .hero-sub {
  font-size: clamp(0.98rem, 1.35vw, 1.1rem);
  max-width: 48ch;
}

/* The bottom zone is a block container, so its first child's top margin can
   collapse through it and shift the whole zone. That put slide 1's CTA row
   ~2.9px below the other three. Zeroing it makes the CTA/dots baseline
   byte-identical on all four slides, which is the point of the two-zone split. */
.hero-slide-bottom > .hero-countdown-label { margin-top: 0; }

/* Mobile: at 375x812 the top zone is only ~321px, and slide 3 is the one slide
   carrying BOTH a three-line lede and a two-line meta row, so its stack overran
   the zone and "An art keynote" garbled into "The Forum begins in". Slides 2 and
   4 cleared by only ~2px, which is not a margin worth shipping. This trims the
   mobile rhythm (not the copy) to buy roughly 30px back, so every slide clears
   with real headroom. Must sit AFTER the two-zone block above to win on order,
   the earlier max-width:720px block is upstream of it. */
@media (max-width: 720px) {
  .hero-banner .hero-slide { padding-top: 4.3rem; }
  .hero-banner .hero-slide .hero-eyebrow { font-size: 0.68rem; }
  .hero-banner .hero-slide .hero-sub {
    font-size: 0.94rem;
    line-height: 1.45;
    margin-bottom: 0.7rem;
  }
  .hero-banner .hero-slide .hero-meta {
    margin: 0.7rem 0 0.8rem;
    font-size: 0.72rem;
    gap: 0.35rem 0.7rem;
  }
}
/* /CANON:era26-hero-slide-geometry */

/* ============================================================
   TRIBUTE HERO: bottom-anchored copy, face stays clear (2026-08-04)
   Modifier `.hero-copy-bottom` on `.hero-on-banner` (tribute.html only,
   the index slider heroes keep the default centred `.hero-on-banner`).
   Alex: the centred copy on tribute.html covered the painter's face;
   text should sit compressed, just below, at the bottom of the frame.

   NOT a photo scrim. The live --photo-scrim tokens are transparent by
   design (Alex 2026-08-03: "no dark overlay on any image", see the
   photo-scrim tokens block near the top of this file, and the
   NO-SCRIM LEGIBILITY block below it). That still allows a LOCAL
   text-shadow/text-plate ON THE COPY (that same tokens comment names
   both), and it is load-bearing here: this artwork is a bright
   flat-colour illustration
   (measured avg luminance ~0.30-0.37
   and brightest highlight pixels ~0.99 in the lower band, sampled from
   images/tribute/tribute-hero-v3.webp at both the 1440x828 and 375x698
   rendered crops), not the dim photography the shadow-only pattern was
   tuned for (.venue-content et al. sit at ~0.03-0.08 luminance, where
   white-on-shadow alone already clears AA). Raw white text against this
   image's brightest bottom-band pixels measures ~1.0:1, shadow alone
   cannot close that gap. A shrink-to-fit --era-navy-70 plate (already a
   site token, already used the same way by .banner-caption) behind the
   copy only, sized to its own content, clears AA with wide margin: the
   worst-case analytical composite (granat ERA-70 over that single
   brightest sampled pixel, 255,255,249) is ~7.2:1; a live Playwright
   render sampled directly off the rendered PNG (both 1440x900 and
   375x812, multiple points inside the plate's own padding/backdrop-blur
   area) measured 11.8-19.0:1 across both viewports. One plate, one
   colour pair, so H1 and the subline share the same number. It is
   local to the text block, never a wash over the picture, so the
   artwork stays clean everywhere else in the frame, per the same-day
   ruling. */
/* HORIZONTAL CENTRING (Alex 2026-08-17, on screenshot: "the text overlay: you
   moved to the right, bad; bring it back center-aligned").

   MEASURED CAUSE, and it is NOT the obvious one. The plate's `margin: 0 auto`
   (inherited from `.rt-shell`) was never broken by `width: auto`, and
   `.hero-banner` never had a justify-content pushing it: measured live at
   1440x900 the parent is `display:flex; flex-direction:row;
   justify-content:normal`, and the plate's own auto margins resolved to
   4.875px each. Auto margins were working perfectly. There was simply almost
   no free space left for them to absorb.

   The space thief is `<figcaption class="hero-attrib">`, the CC BY credit that
   tribute.html puts inside `<figure class="hero-banner">`. It carried NO style
   of any kind, so it stayed an in-flow, static, block-level FLEX ITEM in the
   hero row and ate 931px of 1440 (and 201.8px of 375). Measured plate gaps
   before the fix: left 935.9px / right 4.9px at 1440, and left 201.8px /
   right 0px at 375, i.e. flush against the right edge on mobile, exactly what
   Alex saw. tribute.html is the ONLY page whose `.hero-banner` has a
   figcaption child (verified across all twelve pages 2026-08-17); every other
   hero is picture + banner-sweep + copy div, which is why only this one hero
   drifted right.

   Fix is therefore to take the credit OUT OF THE FLEX FLOW, not to re-engineer
   the centring. Once the row contains only the copy block (plus the 0x0
   `<picture>`, whose `<img>` is absolute), the existing `margin: 0 auto` centres
   the plate on its own, and the bottom anchor below is untouched.

   Why visually-hidden and not a visible caption: this figcaption is ALREADY
   invisible in the shipped build, because an unpositioned block paints beneath
   the absolutely-positioned hero `<img>` that covers the frame. Simply setting
   `position: absolute` would flip it ABOVE the artwork (positioned siblings with
   z-index:auto paint in DOM order, and the figcaption follows the picture), which
   would dump a raw unstyled 16px white paragraph across the middle of the
   painting. So it is removed from layout the standard way instead, which keeps
   the render pixel-identical to today and keeps the link in the accessibility
   tree. The page is NOT losing its attribution: the full, styled, visible CC BY
   credit for the same photograph lives at `.tribute-portrait figcaption`
   (tribute.html:241). If the credit should also be visible up in the hero, that
   is an HTML/design call, not a layout fix, and it needs a home that clears the
   bottom-anchored plate at 375 as well as 1440. */
.hero-banner > figcaption {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.hero-on-banner.hero-copy-bottom {
  /* Bottom-anchor within `.hero-banner`'s flex row (default align-items:
     center is what centred the copy over the face). Redundant-but-safe
     at <=720px, where `.hero-banner` already sets align-items:flex-end. */
  align-self: flex-end;
  /* Explicit, even though `.rt-shell` already sets `margin: 0 auto`: the
     centring is the thing Alex flagged, so it is stated at the site of the
     modifier rather than left to be inferred two hundred lines away. Longhand
     so the `margin-bottom` below is not clobbered. */
  margin-left: auto;
  margin-right: auto;
  /* Shrink the plate to its own content instead of the full 1160px
     .rt-shell measure (only width is touched; the shell's `margin: 0
     auto` longhand left/right:auto still centres this narrower box). */
  width: auto;
  max-width: min(620px, calc(100vw - 2.5rem));
  margin-bottom: clamp(1.8rem, 5vh, 3rem);
  padding: 1.3rem 1.8rem 1.5rem;
  border-radius: var(--radius-card);
  background: var(--era-navy-70);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.hero-on-banner.hero-copy-bottom .hero-eyebrow {
  margin-bottom: 0.15rem;
}
/* Compressed display type: smaller ceiling than the shared `.hero h1`
   (clamp 2.5rem/8.5vw/7rem), tighter leading, tighter own margins. Only
   margin-top/bottom are set (longhand) so the existing
   `.hero-on-banner h1 { margin-left:auto; margin-right:auto }` keeps
   centring this block inside the now-shrink-wrapped plate. */
.hero-on-banner.hero-copy-bottom h1 {
  font-size: clamp(1.65rem, 5.6vw, 2.9rem);
  line-height: 1.08;
  margin-top: 0.3rem;
  margin-bottom: 0.35rem;
  max-width: 20ch;
}
.hero-on-banner.hero-copy-bottom .hero-sub {
  font-size: clamp(0.85rem, 1.6vw, 0.98rem);
  max-width: 34ch;
}
/* The artist's name in his two signature hues (Alex 2026-08-17: "David Hockney
   in two most characteristic colors for him"). Uses the cerulean/coral pair this
   sheet already carries as Alex-approved palette hues, in their PHOTO-SAFE
   lifts, because this h1 sits on the --era-navy-70 plate over a bright
   flat-colour illustration, not on solid granat ERA. Raw --hk-cerulean (3.75:1)
   and raw --hk-coral (4.28:1) both miss the 4.5 floor there; the lifts clear it
   with room to spare. Measured off rendered pixels: each word was hidden, the
   page re-shot, and the plate's own backdrop sampled across the word's box, then
   scored against its LIGHTEST pixel (worst case for light type) as well as the
   mean:
       David  (cerulean-on-photo)  worst 8.10:1 @1440x900   8.35:1 @375x812
                                    mean 9.47:1             9.16:1
       Hockney(coral-on-photo)     worst 6.86:1 @1440x900   6.97:1 @375x812
                                    mean 8.42:1             8.72:1
   Scoped to `.hero-copy-bottom h1` (tribute hero only) so no other surface can
   inherit these two hues. Colour only, no weight or size: the h1's compressed
   display sizing above already owns those. */
.hero-copy-bottom h1 .hk-a { color: var(--hk-cerulean-on-photo); }
.hero-copy-bottom h1 .hk-b { color: var(--hk-coral-on-photo); }
/* ============================================================
   /TRIBUTE HERO
   ============================================================ */

/* ============================================================
   MAIN NAV, MSN26 formatting port (Insights/css/insights.css
   lines 111-341, 590-858). Ports the gold active-underline, the
   dropdown guard, the focus ring and the wordmark geometry. The event
   keeps its own 64px height, its 720px breakpoint, its Inter
   --font-sans, and its .nav-inner .rt-shell container. Every MSN26
   red becomes event gold.

   The TYPE TREATMENT half of this port is NOT here, it was applied
   in place at `.nav-links a:not(.btn-red)`, `.nav-links .btn-red`
   and `.nav-burger` in the NAV block above, because each of those
   selectors already existed and an appended copy would have created
   a contradictory pair at equal specificity (and, for the base link
   rule, would have overridden the mobile drawer's 0.95rem).

   NOT PORTED, the always-on glass bar. The spec justified it with
   ".nav.scrolled is DEAD, no JS ever adds .scrolled". That is false
   against this tree: js/main.js:43 runs
   `nav.classList.toggle('scrolled', window.scrollY > 24)`, so the
   scroll-reveal works today. Forcing `.nav{background:rgba(6, 28, 56,.75);
   backdrop-filter:blur(20px)}` would also invert the blur, .nav.scrolled
   (0,2,0) outranks .nav (0,1,0), so blur would DROP 20px -> 12px on
   scroll, and would make the permanent gold hairline shadow
   .nav.scrolled's border-bottom-color into a no-op. Flagged for the
   orchestrator instead of shipped. If MSN26's heavier glass is wanted,
   the correct edit is retuning .nav.scrolled's own blur, not a new
   always-on .nav rule.
   ============================================================ */

/* Gold underline. position:relative must sit on the LINK itself,
   .nav-item is already relative and also contains the absolutely
   positioned .nav-sub panel, so without this the bar would stretch
   to the dropdown's width instead of the trigger's. */
.nav-links > a:not(.btn-red),
.nav-links .nav-parent {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  touch-action: manipulation;
}
.nav-links > a:not(.btn-red)::after,
.nav-links .nav-parent::after {
  content: '';
  position: absolute;
  bottom: -4px;
  left: 0;
  width: 100%;
  height: 1.5px;
  background: var(--rt-gold-bright);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}
.nav-links > a:not(.btn-red):hover::after,
.nav-links .nav-parent:hover::after,
.nav-item:focus-within .nav-parent::after {
  transform: scaleX(1);
}
/* Active state: the ::after only. The active/hover/focus COLOUR is already
   gold from `.nav-links a:not(.btn-red)[aria-current="page"]` in the NAV
   block above, so restating it here would be a duplicate declaration. */
.nav-links > a[aria-current="page"]:not(.btn-red)::after,
.nav-links .nav-parent[aria-current="page"]::after {
  transform: scaleX(1);
  height: 2px;
}

/* Dropdown. MSN26 has no dropdown; these rules exist only so the ported
   underline cannot leak into .nav-sub, whose stacked items would each grow a
   stray gold bar. The `>` combinator already prevents that (.nav-sub links are
   grandchildren of .nav-links), so `content:none` is a deliberate belt-and-braces
   guard against a future selector loosening. */
.nav-sub a::after { content: none; }
/* Desktop-only type. Scoped two ways against the spec's bare `.nav-sub a`:
   (1) `.nav-links .nav-sub a` (0,3,1) is needed to outrank the ported base rule
   `.nav-links a:not(.btn-red)` (0,2,1), at (0,1,1) the font-size would be a
   dead declaration; (2) min-width:721px keeps it off the mobile drawer, where
   the dropdown flattens into the stacked list and 0.76rem sub-items beside
   0.95rem parents would read as a bug. */
@media (min-width: 721px) {
  .nav-links .nav-sub a {
    letter-spacing: 0.06em;
    font-size: 0.76rem;
  }
}

/* Focus ring, scoped to the nav chrome. border-radius is withheld from
   .btn-red on purpose: that button carries border-radius:var(--radius-control)
   (10px) from the LIVE-REVIEW radius batch, and a 2px focus radius here (0,2,1
   vs the batch's 0,1,0) would visibly square the CTA on keyboard focus. */
.nav a:focus-visible,
.nav button:focus-visible {
  outline: 2px solid var(--rt-gold-bright);
  outline-offset: 3px;
  box-shadow: 0 0 0 4px var(--rt-gold-12);
}
.nav a:not(.btn-red):focus-visible {
  border-radius: 2px;
}

/* Mobile drawer: drop the underline. In a stacked drawer with 1px dividers the
   bar double-rules every row. The active-gold colour needs no re-assert, the
   [aria-current] rule in the NAV block is unscoped and already applies here. */
@media (max-width: 720px) {
  .nav-links > a:not(.btn-red)::after,
  .nav-links .nav-parent::after { content: none; }
}

/* Nav wordmark. The base `.nav-logo img` width/height/object-fit lives in the
   NAV block above (see the note there); only the responsive step is here.
   Mobile 100px wide -> 46.8px tall -> 29.2px clearance on the 76px bar. */
.nav-logo {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0.2rem 0;
  text-decoration: none;
  touch-action: manipulation;
}
@media (max-width: 720px) {
  .nav-logo img { width: 100px; }  /* scaled with the 112->140 desktop step (Alex 2026-08-14) */
}

/* ============================================================
   WhatsApp floating widget. Markup ships on 10 pages and the behaviour
   lives in js/wa-float.js (it only toggles .wa-expanded); this is the
   whole visual layer. Ported from MSN26, restyled to event gold: solid
   gold fill with granat ERA ink. White on gold is 1.77:1 and fails;
   granat ERA on gold is 10.9:1.
   ============================================================ */
.wa-float {
  position: fixed;
  bottom: 2rem;
  right: 2rem;
  /* 98 is deliberate and must not be raised. Measured stack on this sheet:
     .msn-subnav 90, .ticker 99, .nav 100, open .nav-links drawer 101. MSN26's
     own 9999 would let the chat button paint over the open hamburger menu. */
  z-index: 98;
  width: 56px;
  height: 56px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--rt-gold-bright);
  border: 1px solid var(--rt-gold);
  border-radius: 50%;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
  transition: transform 180ms ease, box-shadow 180ms ease;
}
.wa-float,
.wa-float:hover,
.wa-float:visited,
.wa-float:active {
  text-decoration: none !important;
  color: var(--background) !important;
}
.wa-float:hover {
  transform: scale(1.05);
  box-shadow: 0 4px 24px var(--rt-gold-45);
}
.wa-float:focus-visible {
  outline: 2px solid #ffffff;
  outline-offset: 3px;
}
.wa-float svg {
  width: 30px;
  height: 30px;
  fill: currentColor;
}
/* Expanded pill: --radius-pill (999px) replaces the spec's magic 28px. Both
   clamp to half the box height on a <=56px-tall pill, so the render is
   identical and the value now rides the site's corner token. */
.wa-float.wa-expanded {
  width: auto;
  border-radius: var(--radius-pill);
  padding: 0.6rem 1.2rem 0.6rem 0.8rem;
  gap: 0.6rem;
}
.wa-float .wa-label {
  font-family: var(--font-sans);
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--background);
  white-space: nowrap;
  max-width: 0;
  overflow: hidden;
  opacity: 0;
  transition: max-width 400ms ease, opacity 300ms ease, margin 300ms ease;
  margin-left: 0;
}
.wa-float.wa-expanded .wa-label {
  max-width: 300px;
  opacity: 1;
  margin-left: 0.4rem;
}
@media (max-width: 768px) {
  .wa-float { bottom: 1rem; right: 1rem; }
  .wa-float.wa-expanded {
    bottom: 0;
    right: 0;
    left: 0;
    width: 100%;
    border-radius: 0;
    justify-content: center;
    padding: 0.8rem 1.5rem;
    border-top: 1px solid var(--rt-gold);
  }
  .wa-float.wa-expanded .wa-label { font-size: 0.85rem; }
}
@media (prefers-reduced-motion: reduce) {
  .wa-float, .wa-float .wa-label { transition: none; }
  .wa-float:hover { transform: none; }
}

/* ============================================================
   Add-to-calendar floating widget. Sibling of .wa-float: same
   right-hand rail, same 44px+ body, same --radius-pill corner, same
   shadow value and the same 180ms timing, parked directly ABOVE the
   WhatsApp button. Markup ships on 9 pages immediately before
   .wa-float. The JS only toggles [hidden] on .cal-menu and flips
   aria-expanded on .cal-trigger, so every open-state rule below keys
   off those two and never off a state class.

   The colour split is deliberate. .wa-float is the PRIMARY float and
   owns the solid gold fill; this is its SECONDARY sibling, so it takes
   the sheet's standard on-dark card treatment instead: --card charcoal
   ground, --rt-gold hairline frame (the same border .wa-float carries),
   pure white label, full-brightness --gold-ink icon. Two solid gold
   blobs stacked would read as one duplicated control, and white on gold
   measures 1.77:1, which the dark-surface ink law forbids. Measured on
   the charcoal ground: label #ffffff 17.4:1, icon #ddc074 9.8:1, both
   clear of the 4.5:1 gate.
   ============================================================ */
.cal-float {
  position: fixed;
  /* .wa-float sits at bottom 2rem and is 56px tall, so its top edge is
     at calc(2rem + 56px). 0.75rem of air above that keeps both widgets
     in one rail with no overlap in any .wa-float state. */
  bottom: calc(2.75rem + 56px);
  right: 2rem;
  /* Same 98 as .wa-float, for the same reason recorded there: .ticker
     is 99, .nav 100, the open .nav-links drawer 101. Do not raise. */
  z-index: 98;
}

/* Trigger. The label stays permanently visible rather than mimicking
   the .wa-float collapsed circle: the contract gives the JS no label
   hook, and a hover-only reveal would leave touch users with an
   unlabelled icon. It also keeps the two floats visually distinct. */
.cal-float .cal-trigger {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 44px;
  padding: 0.6rem 1.1rem;
  font-family: var(--font-sans);
  font-size: 0.78rem;
  font-weight: 600;
  line-height: 1.2;
  color: var(--on-dark-primary);
  background: var(--card);
  border: 1px solid var(--rt-gold);
  border-radius: var(--radius-pill);
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
  cursor: pointer;
  touch-action: manipulation;
  transition: transform 180ms ease, box-shadow 180ms ease, border-color 180ms ease;
}
/* The icon ships fill="currentColor", so colour is set on the svg
   itself to override the white label ink it would otherwise inherit. */
.cal-float .cal-trigger svg {
  width: 20px;
  height: 20px;
  flex: 0 0 auto;
  color: var(--gold-ink);
}
.cal-float .cal-label {
  white-space: nowrap;
}
.cal-float .cal-trigger:hover {
  transform: scale(1.05);
  box-shadow: 0 4px 24px var(--rt-gold-45);
  border-color: var(--rt-gold-bright);
}
.cal-float .cal-trigger:focus-visible {
  outline: 2px solid var(--on-dark-primary);
  outline-offset: 3px;
}
/* Open state comes from aria-expanded, the only state signal the JS
   sets. The scale is suppressed while open so the menu anchor, which
   is positioned against this box, cannot drift under the pointer. */
.cal-float .cal-trigger[aria-expanded="true"] {
  border-color: var(--rt-gold-bright);
}
.cal-float .cal-trigger[aria-expanded="true"]:hover {
  transform: none;
}

/* Menu. Opens UPWARD and is anchored to the widget's right edge, which
   is the only direction with guaranteed room: downward would collide
   with .wa-float, and a left anchor would run off a 375px viewport.
   max-width is capped at the viewport minus the rail gutters, so the
   panel can never cause a horizontal scroll. */
.cal-float .cal-menu {
  position: absolute;
  bottom: calc(100% + 0.5rem);
  right: 0;
  display: flex;
  flex-direction: column;
  width: max-content;
  max-width: min(19rem, calc(100vw - 2rem));
  max-height: min(60vh, 22rem);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 0.35rem;
  background: var(--card);
  border: 1px solid var(--rt-gold);
  border-radius: var(--radius-card);
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
}
/* MANDATORY. The class rule above out-specifies the browser's own
   [hidden] { display: none } default, so the attribute the JS toggles
   has to be re-asserted here or the menu ships permanently open. */
.cal-float .cal-menu[hidden] {
  display: none;
}

.cal-float .cal-opt {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding: 0.5rem 0.85rem;
  font-family: var(--font-sans);
  font-size: 0.82rem;
  font-weight: 500;
  line-height: 1.35;
  color: var(--on-dark-primary);
  text-decoration: none;
  border-radius: var(--radius-control);
  transition: background-color 180ms ease;
}
.cal-float .cal-opt:hover,
.cal-float .cal-opt:focus-visible {
  background: var(--rt-gold-08);
  color: var(--on-dark-primary);
}
/* Negative offset keeps the ring inside the scroll box: a positive one
   is clipped on the first and last item by overflow-y: auto. */
.cal-float .cal-opt:focus-visible {
  outline: 2px solid var(--on-dark-primary);
  outline-offset: -2px;
}

@media (max-width: 768px) {
  /* .wa-float drops to bottom 1rem here, so the same 0.75rem of air
     puts this widget at 84px. When .wa-float expands into its
     full-width bottom bar (bottom 0, 56px tall) this still clears its
     top edge by 28px. */
  .cal-float {
    bottom: calc(1.75rem + 56px);
    right: 1rem;
  }
  /* Icon only at mobile. The labelled pill measured 150px wide and its
     left end clipped the primary hero CTA at 375px: CTA right edge 291,
     pill left edge 209, an 82.3 x 12.4 px corner overlap. Collapsing the
     trigger to 56px wide moves the left edge to 303 and clears the CTA
     by 12px. 56px is not arbitrary, it is .wa-float's own width, so the
     two floats stack on one axis with matching left and right edges.

     Height stays 44px, NOT 56px, on purpose. The new box is then a
     strict SUBSET of the box the rendered audit already cleared
     (l209 t684 r359 b728 becomes l303 t684 r359 b728), so it cannot
     introduce a new collision on any of the 9 pages at any mobile width
     without a fresh measurement. 56x44 is still a 2464 sq px tap target,
     well over the 44x44 floor. border-radius is left on --radius-pill,
     which clamps to half the box height exactly as the .wa-float
     comment above records.

     CORRECTION, 2026-08-17. "Clears the CTA by 12px" above is true only
     of the PRIMARY CTA. The hero CTA row carries TWO buttons, and that
     measurement was taken against the first one. Re-measured at 375x812:
     Register sits at x26-162, so the 12px is real and holds, but Become
     a partner sits at x178-349 and the trigger's left edge is at 303, so
     the SECONDARY CTA overlaps by 46.3 x 23px. The subset argument is
     sound as far as it goes; the audit it inherited from had only ever
     cleared one of the two buttons, so shrinking within that box could
     not have fixed what was never measured. The rail-vs-CTA overlap is
     resolved below, in the hero-handoff block, not by a width. */
  .cal-float .cal-trigger {
    width: 56px;
    height: 44px;
    padding: 0;
    gap: 0;
    justify-content: center;
  }
  .cal-float .cal-trigger svg {
    width: 24px;
    height: 24px;
  }
  /* The label collapses rather than being removed, so it stays in the
     accessibility tree and remains the button's accessible name. This is
     the same max-width technique .wa-float uses on its own label. */
  .cal-float .cal-label {
    max-width: 0;
    margin: 0;
    overflow: hidden;
    opacity: 0;
  }
  /* This cap is a ceiling, not the achieved width. width: max-content
     settles at about 309px for these four labels, which leaves roughly
     50px of left gutter at 375px. The cap only engages if the option
     text grows, and it stops the panel at the 16px rail gutter. */
  .cal-float .cal-menu {
    max-width: calc(100vw - 2rem);
  }

  /* ----------------------------------------------------------------
     HERO HANDOFF. The float is not painted while a hero CTA row can be
     on screen; the JS reveals it once that row has scrolled away.

     Why a handoff and not a bigger offset. Swept on index.html at 375
     wide, viewport height 560 -> 1000 in 20px steps, measuring the
     trigger's box against every visible a/button/[role=button] in the
     hero:

       - the HORIZONTAL overlap with the hero CTA row is 46.3px at EVERY
         height in that range. It never varies. The row is centre-
         justified and 323px wide at 375, so its right edge lands at
         349, while the rail's left edge is pinned at 100vw - 72 = 303.
         The rail's column sits inside the row's span at every phone
         width measured: 46.3px at 375, 38.8px at 390, 26.8px at 414.
         There is no height at which these two do not overlap on x.
       - the VERTICAL overlap is the only variable, and it is a
         continuum, not a point. Negative below 620, crosses zero at
         620, peaks at +44.0px across 720-740 (2037 of the trigger's
         2464 sq px, i.e. 83% of the button lying on the CTA), then
         falls back through zero at about 875.

     Every common portrait phone therefore lands inside the failing
     620-875 band: 360x740, 375x667, 375x812, 390x844. 414x896 escapes
     only because .hero-banner's min-height clamps at 740 while the rail
     keeps descending with the viewport. That is luck, not clearance.

     Which rules out moving the rail. Clearing a +44px worst case needs
     the widget ~172px off the bottom, about 120px above .wa-float,
     which breaks the single-rail relationship recorded at the top of
     this section, and the number would still be tuned to today's
     clamp(560px, 86vh, 740px) and today's CTA type scale. Reserving a
     right-hand gutter on the row was the other candidate: it does hold
     geometrically, but it forces the two buttons to wrap at 375 and
     pushes the row off the hero's centre line, i.e. it pays for a float
     with the hero's layout.

     Hiding is also correct on its own terms, independent of the
     collision. While the hero is on screen the visitor already has
     Register, Become a partner, the date and the countdown in front of
     them, so a floating "add to calendar" duplicates an affordance and
     charges a revenue CTA for the privilege.

     Scope is wider than the home page. The same rail-into-centred-CTA
     geometry grazes canvases.html ("See the run of show", 13 sq px) and
     speakers.html ("Nominate a speaker", 14 sq px) at 360x740, so this
     keys off the row itself rather than off one page.

     visibility, not opacity alone: an opacity-0 button keeps its place
     in the tab order and the accessibility tree, which would leave a
     keyboard trap on an invisible control. display:none would also be
     correct but cannot transition.

     :has() scopes this to the five pages that ship a hero CTA row
     (index, canvases, invite, partnerships, speakers) and leaves the
     float alone on venue, gallery, insights and tribute, which have no
     such row and measured clear. A browser without :has() does not
     match the selector and gets today's behaviour, so this rule can
     only improve a render, never regress one. */
  body:has(.hero-cta-row) .cal-float {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    /* visibility waits out the fade on the way out, switches instantly
       on the way in (see the reveal rule). */
    transition: opacity 180ms ease, visibility 0s linear 180ms;
  }

  /* JS CONTRACT. js/calendar-add.js adds .hero-cta-offscreen to <body>
     when no .hero-cta-row intersects the viewport, and removes it when
     one does. Nothing else in this sheet reads that class.

     Until that hook ships this rule never matches, so the float stays
     hidden on those five pages at <=768px. That is the deliberate
     failure direction: a missing secondary affordance costs less than a
     tap target parked on top of "Become a partner". */
  body:has(.hero-cta-row).hero-cta-offscreen .cal-float {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transition: opacity 180ms ease, visibility 0s linear 0s;
  }
}

@media (prefers-reduced-motion: reduce) {
  .cal-float .cal-trigger,
  .cal-float .cal-opt { transition: none; }
  .cal-float .cal-trigger:hover { transform: none; }
  /* Hero handoff cuts straight to the end state. Both selectors are
     repeated at full strength because the mobile rules they override
     score 0,2,1 and 0,3,1; a bare .cal-float here would lose the
     cascade and leave the fade running. */
  body:has(.hero-cta-row) .cal-float,
  body:has(.hero-cta-row).hero-cta-offscreen .cal-float { transition: none; }
}

/* ============================================================
   CONFIRMED-SPEAKER CARD + MODERATOR FEATURE
   Design Manager, Peter Murray contract §5 (2026-08-11)

   .spk-* is the CONFIRMED sibling of the .tba-* placeholder set: same
   grid cell, same 120px square, same type scale and the same margin
   ladder, so one real speaker can replace one TBA card inside
   .panel-people without moving the 3-column rhythm or the avatar/name
   baselines of the two cards standing beside it in the row.

   TWO CONTRACT DEVIATIONS, both deliberate, both reported to the Director:

   (1) RADIUS. The contract says "border-radius: 0 everywhere". That is
       stale for THIS file. The LIVE-REVIEW BATCH (~L2729, Alex 2026-08-03,
       asked twice) rounds every box on the site and names .tba-avatar
       explicitly as "the speaker headshot/placeholder box Alex named".
       A square .spk-photo would be the single sharp corner among three
       rounded TBA tiles in the same row. So the portraits ride the
       existing --radius-card token: no new value, no hardcoded px, and if
       the site ever returns to sharp corners that one token flips these
       with everything else. Sharp corners are NOT re-introduced here.

   (2) BREAKPOINT. The contract says 760px. There is no 760px breakpoint
       in this file. The roster's real mobile chain is 980 (.panels-grid
       -> 1 col), 720 (.panel-people gap -> 0.6rem) and 640 (.rt-shell).
       The rules below use 720px, the breakpoint that already governs
       .panel-people, rather than inventing a 760-721 dead zone.

   LIGHT-BAND LAW. #speakers-roster is .band-seashell. The pass-3 root fix
   (~L2508) re-scopes --ink-soft / --ink-muted / --ink-faint inside
   .band-seashell, so anything consuming those resolves dark by itself. It
   does NOT re-scope --ink (#ffffff), --gold-ink (#ddc074) or --line-warm
   (--rt-gold-45): left alone, the name would render white on cream and
   the frame would wash out to near-nothing. The .band-seashell group at
   the bottom of this block forces those to the light-band values already
   established in this file (#061c38, #10233f, #8a6a1e, and the
   rgba(138,106,30,0.4) frame with its 0.55 hover step). No new colour
   value and no new token is introduced anywhere in this block.
   ============================================================ */

/* --- Roster card: dimensional twin of .tba-card (L1329) --- */
.spk-card { min-width: 0; }

/* Square portrait. Geometry copied from .tba-avatar (L1373) so the two card
   types are interchangeable in the grid. overflow:hidden is load-bearing, not
   decoration: a radius does nothing unless the box clips its square-cornered
   <img> child (the file's own "Clipping companions" note, ~L2783). */
.spk-photo {
  aspect-ratio: 1 / 1;
  max-width: 120px;
  border: 1px solid var(--line-warm);
  border-radius: var(--radius-card);
  background: var(--seashell-alt);
  overflow: hidden;
  transition: border-color var(--ui-ease);
}
.spk-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* --- Canvas I moderator portrait + its photographer credit (2026-08-17) ---
   canvases.html gained the same Peter Murray portrait the speakers roster uses,
   inside `#canvases .canvas-people li`, which is `display:flex;
   flex-direction:column`. Two things follow from that and both need fixing here,
   because canvases.html's own inline <style> block styles the text spans in that
   list but has no rule for either the photo box or the credit.

   GEOMETRY. `.canvas-person-photo` is a <span>, so as a flex item it blockifies
   and, under the default `align-items: stretch`, takes the FULL column width.
   The <img> carries width/height 400 and the sheet's global `img { max-width:
   100% }`, so it would paint at the column measure, an order of magnitude past
   the 72px its own `sizes="72px"` attribute promises the browser (a wrong
   `sizes` also makes the srcset pick the wrong candidate). Pinning the box to
   72px square with `flex: 0 0 auto` + `align-self: flex-start` makes the render
   agree with `sizes` again. Everything else is lifted verbatim from `.spk-photo`
   above (aspect-ratio, --radius-card, 1px --line-warm frame, overflow:hidden to
   clip the square-cornered <img>) so the same face reads identically on both
   pages, just smaller.

   CREDIT COLOUR. `.photo-credit` is a legal attribution to the rights holder
   (Bernd Ott) and must be READABLE, not merely present. It has no rule in this
   sheet at all: index.html and speakers.html each declare it inline, and those
   copies are page-scoped, so on canvases.html the span currently falls back to
   plain inherited body text. It is NOT ported verbatim from those pages, for the
   reason the Director flagged, though the mechanism is worth stating correctly:
   their declaration is `color: var(--ink-muted, #6b6560)`, and on this site
   `--ink-muted` is always defined (globally `--on-dark-muted` = #ffffff,
   re-scoped dark inside .band-seashell), so that #6b6560 fallback is dead code
   and never actually paints. The real reason for a bespoke rule is positive:
   #canvases is .band-granat ERA, and under the INK LAW at the top of this file a
   photo credit is META, so it takes the gold accent (--rt-gold-bright), exactly
   like the other captions on dark in this sheet (.banner-caption,
   .tribute-portrait figcaption) and exactly like the sibling
   `.canvas-slot-label` / `.canvas-person-role` in canvases.html's own block.
   Measured off rendered pixels (the credit's own backdrop is not flat #061c38,
   it is `.canvas-panel` at rgba(28,25,21,0.42) over the granat ERA band, so the
   sample is taken from the render, not computed from the token): 10.55:1 at
   both 1440x900 and 375x812, against the lightest sampled pixel. Type is
   caption-scale (0.62rem, tracked, uppercase), matching the speakers.html
   credit, so it reads as a credit and not as a second role line.

   Both selectors are scoped to #canvases on purpose: index.html and
   speakers.html already ship working credits of their own and must not move. */
#canvases .canvas-person-photo {
  flex: 0 0 auto;
  align-self: flex-start;
  width: 72px;
  aspect-ratio: 1 / 1;
  margin-bottom: 0.3rem;
  border: 1px solid var(--line-warm);
  border-radius: var(--radius-card);
  background: var(--seashell-alt);
  overflow: hidden;
}
#canvases .canvas-person-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
#canvases .photo-credit {
  display: block;
  margin-bottom: 0.35rem;
  font-size: 0.62rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--rt-gold-bright);
}

/* Name. Same margin-top and font-size as .tba-name (L1390) so the line box is
   identical and the baseline stays level with the TBA cards either side; only
   weight and ink step up, because this one is a real person. Line-height is
   deliberately NOT set, so it inherits the same 1.6 as .tba-name. */
.spk-name {
  margin-top: 0.55rem;
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--ink);
}

/* Micro-label. Mirrors .tba-role (L1396) exactly. */
.spk-role {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-top: 0.15rem;
}

/* Organisation. The one line the TBA card does not carry, so it is the only
   height the confirmed card adds: 0.72rem at 1.3 plus a 0.15rem margin is
   about 17px, and it lands BELOW the name/role pair, so every avatar and
   every name in the row still shares its baseline. Tight line-height keeps a
   long org name to a sane block when the cell narrows to ~93px at 375px. */
.spk-org {
  margin-top: 0.15rem;
  font-size: 0.72rem;
  line-height: 1.3;
  color: var(--ink-muted);
}

/* Hover parity with .tba-card:hover .tba-avatar (L1389). */
.spk-card:hover .spk-photo { border-color: var(--rt-gold-60); }

/* --- Moderator feature block: portrait beside a text column --- */
/* Layout container only, no box chrome: the contract puts the gold frame on
   the portrait, and an editorial moment reads stronger un-boxed than as one
   more card. align-items:start keeps the portrait pinned to the first line of
   copy instead of stretching to the column's full height. */
.mod-feature {
  display: grid;
  grid-template-columns: minmax(0, 200px) minmax(0, 1fr);
  gap: clamp(1.4rem, 3vw, 2.4rem);
  align-items: start;
}
.mod-feature-photo {
  width: 100%;
  aspect-ratio: 1 / 1;
  border: 1px solid var(--line-warm);
  border-radius: var(--radius-card);
  background: var(--seashell-alt);
  overflow: hidden;
}
.mod-feature-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Copy column. Heading and paragraph COLOUR are intentionally omitted: on a
   seashell band .band-seashell h2/h3 (#061c38) and .band-seashell p (#10233f)
   already own it, and on a dark band both correctly inherit white. Setting
   colour here would only start a specificity fight with rules that are
   already right. Only measure and spacing are set. */
.mod-feature-copy h2,
.mod-feature-copy h3 {
  font-size: clamp(1.5rem, 2.6vw, 2rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.15;
  margin: 0.6rem 0 0.9rem;
  max-width: 24ch;
  text-wrap: balance;
}
.mod-feature-copy p {
  font-size: 0.95rem;
  line-height: 1.65;
  max-width: 60ch;
}
.mod-feature-copy p + p { margin-top: 0.85rem; }

/* --- Light-band (.band-seashell) overrides --- */
/* Only the three tokens the pass-3 root fix does NOT re-scope need forcing.
   --ink-soft / --ink-muted / --ink-faint already resolve dark inside
   .band-seashell; .spk-role and .spk-org are listed anyway so this block
   still holds if that root fix is ever narrowed, matching how the file
   already handles .tba-role and .tba-name explicitly. */
.band-seashell .spk-name { color: #061c38; }
.band-seashell .spk-org { color: #10233f; }
.band-seashell .spk-role { color: #8a6a1e; }
/* Frame: --rt-gold-45 is a LIGHT gold and vanishes on cream. The first attempt
   used the 0.40 alpha that every other framed card here takes (.ticket-card /
   .practical-col, L749), but the RENDER killed it: those are large cream-filled
   cards where a soft hairline is enough, whereas this is a 120px portrait whose
   own studio backdrop is light grey, so the frame is the ONLY edge separating
   the head from the band. At 0.40 it measured 1.71:1 and the head read as
   floating. Solid #8a6a1e (4.6:1) is the deep light-band gold already used for
   every label in this file, and it makes the frame the deliberate brand device
   the asset contract calls for. Hover then goes to #b9932f, the brighter gold
   already used by .band-seashell .teaser-card's top rule (L752), preserving the
   dark band's "border goes to the brighter gold" behaviour. No new values. */
.band-seashell .spk-photo,
.band-seashell .mod-feature-photo { border-color: #8a6a1e; }
.band-seashell .spk-card:hover .spk-photo { border-color: #b9932f; }
/* Portrait backing on a light band: --seashell-alt is #0a2d58 and would flash
   as a dark tile before the WebP paints. #fffaf6 is the light-band card
   surface already used at L740. */
.band-seashell .spk-photo,
.band-seashell .mod-feature-photo { background: #fffaf6; }

/* --- Mobile: 720px, the breakpoint that already governs .panel-people --- */
@media (max-width: 720px) {
  /* Feature block stacks. The portrait is capped rather than left to fill the
     column, so it stays a portrait instead of becoming a full-width billboard
     above the copy. */
  .mod-feature { grid-template-columns: 1fr; gap: 1.2rem; }
  .mod-feature-photo { max-width: 180px; }
  .mod-feature-copy h2,
  .mod-feature-copy h3 { max-width: none; }
}

/* ============================================================
   DIRECTOR FIX: Peter Murray moderator pass, 2026-08-11
   The .mod-tag pill gets its light-band TEXT colour from the big
   .band-seashell gold list (~L716), but that list only sets `color`.
   Its BORDER stays --rt-gold-60, a dark-band gold that washes out on
   cream, so the pill outline reads as a ghost on the roster. Now that a
   real moderator card carries the pill next to a photograph, the faint
   outline is visible as a defect. Match the border to the light-band
   gold ink already used for its text. Applies to the three TBA
   moderator cards too, which had the same latent problem.
   ============================================================ */
.band-seashell .mod-tag { border-color: #8a6a1e; }

/* ============================================================
   DIRECTOR FIX: portrait variant of .group-nudge, 2026-08-11
   .group-nudge is a text-only flex row (wrap + align-items:center).
   Adding a 120px portrait as a third flex child put the photo and the
   label alone on row 1 and wrapped the sentence to its own full-width
   row, leaving a dead void beside the label. Group the text into one
   column next to the portrait so it reads as a single strip.
   Scoped to .has-portrait so the three existing text-only
   .group-nudge instances are untouched.
   ============================================================ */
.group-nudge.has-portrait {
  flex-wrap: nowrap;
  align-items: center;
  gap: 1.1rem;
}
.group-nudge.has-portrait .spk-photo {
  flex: 0 0 auto;
  max-width: 96px;
}
.group-nudge.has-portrait .gn-copy {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  min-width: 0;   /* lets the text column shrink instead of overflowing */
}
@media (max-width: 720px) {
  /* Stays side by side, just tighter. Stacking would push the sentence
     below a big square and reproduce the defect this fix removes. */
  .group-nudge.has-portrait { gap: 0.85rem; }
  .group-nudge.has-portrait .spk-photo { max-width: 72px; }
}

/* ============================================================================
   DIRECTOR REBUILD 2026-08-14, new components only.
   Appended rather than interleaved: every selector below is NEW to this sheet
   (verified absent before writing), so there is no equal-specificity fight with
   anything upstream and source order is irrelevant. Colours use the ink tokens,
   which resolve to #ffffff on the dark base and to #10233f inside
   .band-seashell, so each component is legible on whichever band it lands on.
   ============================================================================ */

/* ---- Trust cell list. #trust cell 2 ("What you leave with") carries three
   discrete takeaways, which house rules require to be a real list rather than
   dash-prefixed prose. Marker matches .ticket-benefits (rotated gold square) so
   the two lists read as one family without .ticket-benefits' flex:1, which
   would misbehave in the non-flex .trust-cell. ---- */
.trust-list {
  list-style: none;
  display: grid;
  gap: 0.55rem;
  margin: 0;
  padding: 0;
}
.trust-list li {
  position: relative;
  padding-left: 1.2rem;
  font-size: 0.9rem;
  color: var(--ink-soft);
}
.trust-list li::before {
  content: "";
  position: absolute;
  left: 0; top: 0.52em;
  width: 7px; height: 7px;
  background: var(--rt-gold);
  transform: rotate(45deg);
}
.trust-list strong { color: var(--ink); font-weight: 600; }

/* ---- Ticket team-rate note. The class was already in the markup but had NO
   rule in this sheet, so it was rendering as an unstyled default paragraph.
   margin-top:auto pins it to the card floor beneath the flex:1 benefits list. ---- */
.ticket-team-note {
  margin-top: auto;
  padding-top: 0.4rem;
  font-family: var(--font-mono);
  font-size: 0.74rem;
  line-height: 1.5;
  letter-spacing: 0.02em;
  color: var(--ink-muted);
}
.ticket-team-note a { color: var(--gold-ink); text-decoration: underline; text-underline-offset: 2px; }

/* ---- Commitment path at the CTA. The label says REGISTER but the real flow is
   human review -> proforma -> bank transfer, so the next steps are stated in
   plain language immediately under the submit button rather than buried in
   terms. Full-width in the form grid, framed left in gold so it reads as
   reassurance and not as smallprint. ---- */
.reg-commit {
  grid-column: 1 / -1;
  margin-top: 1rem;
  border-left: 3px solid var(--rt-gold-bright);
  padding: 0.85rem 0 0.85rem 1.1rem;
  font-size: 0.86rem;
  line-height: 1.6;
  color: var(--ink-soft);
}
.reg-commit strong { color: var(--ink); font-weight: 600; }

/* ---- Marquee status clarifier. Sits on the Seashell marquee strip, which is a
   LIGHT band nested inside the dark #proof section, so the ink is hardcoded dark
   for the same reason .marquee-label is: the surrounding section's tokens
   resolve to white and would vanish here. #5f5849 on #fff5ee is ~6.6:1. ---- */
.marquee-note {
  margin-top: 1.4rem;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  line-height: 1.6;
  letter-spacing: 0.02em;
  color: #5f5849;
}

/* ---- Canvases band. Charcoal, one tonal step off the granat ERA sections either
   side, exactly the device .tickets already uses, so #proof's light marquee
   strip, this section and #concept read as three distinct bands. ---- */
.canvases-band {
  background: var(--seashell-alt);
  border-top: 1px solid var(--line-warm);
  border-bottom: 1px solid var(--line-warm);
}

/* ---- Venue stat-triad payoff line (venue.html).
   Selector is `.venue-content > .venue-stats-payoff`, not the bare class:
   `.venue-content > p` (0,1,1) already sets --on-dark-primary on every direct
   child paragraph and beats a bare `.venue-stats-payoff` (0,1,0), so the gold
   was silently losing and the line rendered white. Caught on render, not in
   source. (0,2,1) puts this back in front. ---- */
.venue-content > .venue-stats-payoff {
  margin-top: 1.1rem;
  font-family: var(--font-mono);
  font-size: 0.86rem;
  letter-spacing: 0.06em;
  color: var(--rt-gold-bright);
}

/* ---- AI-artwork badge. MANDATORY on every generated image (STYLE.md:173).
   PROMOTED to this sheet 2026-08-14 so the four page-local copies (canvases,
   speakers, gallery, insights) can be deleted: those lanes could not write here
   because this file is single-owner. The base rule is M2's block copied VERBATIM
   so removing the local <style> blocks is a no-op for those pages, with two
   additive modifiers for placements the base rule cannot express.
   Contrast: #ffffff on rgba(11,12,18,.72) holds over any part of the artwork, so
   the badge never depends on a photo scrim to stay readable. ---- */
/* Bottom-right variant: the hero banner carries slide copy and the countdown in
   its upper and middle zones, so a top-right badge would sit on the headline. */
/* Inline variant: for a badge that runs inside caption prose rather than being
   pinned to an image frame. Drops out of the positioned flow entirely. */
@media (max-width: 720px) {
}

/* Last two single-word orphans after the site-wide `pretty` guard. Both sit in
   narrow grid cells where only full balancing helps, and both are short enough
   (<=5 lines) for the browser to balance. Measured at 375 and 1440. */
.trust-cell p { text-wrap: balance; }

/* ---------------------------------------------------------------------------
   LIGHT-BAND CONTRAST FIXES (WCAG AA), measured 2026-08-14 on the deployed page
   with alpha-composited backgrounds and all .reveal elements forced visible.
   Four distinct failures survived; every other "failure" in the first sweep was
   an artefact of reading a semi-transparent overlay as if it were opaque, and
   those were left alone.
   --------------------------------------------------------------------------- */

/* 1. INVISIBLE TEXT, the serious one. `.trust-list strong` sets var(--ink),
      which on this sheet is the DARK-theme ink (white). It has the same
      specificity (0,1,1) as `.band-seashell strong` but comes later in the file,
      so it won on source order and painted white bold labels onto the cream
      band: "Canvas III, Value", "Canvas II, the SkyScraper Dialogue" and "The
      a long briefing title" all rendered at 1.04:1, i.e. not rendered at all.
      The sentences read as fragments beginning with a colon. Same failure the
      `.trust-cell p strong` entry above already documents; this is the `li`
      sibling that was never added. */
.band-seashell .trust-list strong,
.band-seashell .reg-commit strong,
.band-seashell .practical-list strong,
/* Same defect, one step behind. LATENT-UNCOVERED as of 2026-08-16: neither class
   below appears in ANY of the 11 HTML pages today, so these two selectors change
   no rendered pixel. They are pre-covered because each detonates silently the
   moment its class is reintroduced inside a cream band: `.trust-sla strong`
   (L1064) resolves to var(--gold-ink) = #ddc074, ~1.9:1 on #fffaf6, and
   `.concept-copy p strong` (L1076) to var(--ink) = #ffffff, 1.04:1, i.e. not
   rendered at all. The audit also listed `.trust-list strong` (L4138); it needed
   no entry -- the first selector above already outranks it 0,2,1 vs 0,1,1, so it
   wins on specificity and never reaches the source-order tiebreak. */
.band-seashell .trust-sla strong,
.band-seashell .concept-copy p strong { color: #061c38; }

/* 2. Required-field marker: #ff6b6b is an on-DARK alert token and only reaches
      2.68:1 on the cream form card. Deepened to a red that clears AA (6.3:1)
      while still reading unambiguously as an error colour. */
.band-seashell .consent .req { color: #b3261e; }

/* 3-4. Hockney tribute accents on the light band. --hk-coral (#ea7e5d, 2.65:1)
      and --hk-cerulean (#2e9cca, 3.01:1) are deliberate palette choices and stay
      exactly as they are on every dark band; only the cream band gets a deepened
      pair, because body-size text there has to clear 4.5:1 for the institutional
      reader this site is written for. Hue is preserved: still terracotta, still
      cerulean, at 5.3:1 and 5.4:1. */
.band-seashell .keynote-moment .act-no { color: #b04a26; }
.band-seashell .hk-link { color: #1b6f94; }

/* ============================================================
   SPONSOR TIERS, #sponsors on partnerships.html
   "Marquee and four", variant A, APPROVED BY ALEX 2026-08-14
   (qa/2026-08-14/sponsor-tiers-variants.html, option A).

   WHAT IT IS
   Title Sponsor takes a full-width cobalt marquee carrying a scarcity chip
   and its own enquiry link. The other four sponsorships sit as a row of white
   cards under coloured top rules, each with its own enquiry link. A closing
   contact block catches anyone who does not want to pick a product first.
   Copy and the five product names are carried across verbatim from the live
   section; no rates appear anywhere, they stay on request.

   WHY NEW CLASS NAMES (.sp-*) INSTEAD OF .products / .product
   .products/.product is a 1px-gap MOSAIC grid whose gold dividers are the
   container background showing through the gap. The file's own MOSAIC GRIDS
   note (see "FRAME ROUNDS, CELLS STAY SQUARE") explicitly forbids re-adding
   border-radius to .product, because a radius on those cells makes the gold
   gap-field bleed through every interior seam as a teardrop blob. .products
   is still used by index.html and by #a-la-carte on this page, so it is left
   completely untouched. This component is a separate, self-contained card row
   that owns its own corners.

   ALEX'S AMENDMENT 1, ROUNDED CORNERS (2026-08-14)
   The site standard is sharp corners for full-bleed bands, but Alex asked for
   rounded corners on the boxes in THIS component. One value, --sp-radius, is
   declared once on #sponsors and consumed by the marquee, the four cards and
   the contact block. It resolves to the site's existing --radius-card (16px,
   from Alex's own round-everything pass) rather than a bespoke number, so this
   component and #a-la-carte directly below it round identically instead of
   reading as two different card families on one page. Chips stay on
   --radius-pill and the contact button on --radius-control, matching the badge
   and control families already established. Nothing outside #sponsors is
   touched.

   ALEX'S AMENDMENT 2, RECIPIENT (2026-08-14)
   Every enquiry link goes to Dominika@RealTimes.co only. No cc= parameter and
   no Alex@RealTimes.co anywhere. This supersedes the approval page, which
   still shows cc=Alex@RealTimes.co.

   ALEX'S AMENDMENT 3, PREPOPULATED MAIL (2026-08-14)
   Each of the five sponsorships carries its own subject AND its own body,
   naming that specific category. Markup concern, no CSS involved.

   WHY EVERY RULE IS SCOPED TO #sponsors
   Not decoration. .band-seashell carries a light-band ink cascade, including
   .band-seashell a:not(.btn-red):not(.nav-cta):not(.teaser-card):not(.hk-link)
   at specificity (0,5,1), which would repaint these links deep gold and would
   beat any plain class selector no matter how many classes were stacked. An id
   scope gives (1,x,y) and wins cleanly. It is also the idiom the sheet already
   uses for exactly this purpose, see #partners .product.

   MEASURED CONTRAST, every text-on-colour pair shipped here
     white     #ffffff on cobalt   #0047ab  ....  8.44:1  marquee heading, body, link
     sand      #e8c98a on cobalt   #0047ab  ....  5.28:1  marquee link arrow + underline
     granat ERA  #061c38 on sand     #e8c98a  ....  12.01:1 marquee scarcity chip
     ink       #061c38 on white    #ffffff  ....  19.17:1 card headings, card link label
     body ink  #10233f on white    #ffffff  ....  14.81:1 card copy, contact copy
     body ink  #10233f on #f1f1f1           ....  13.11:1 card chip (6% ink tint on white)
     white     #ffffff on cobalt   #0047ab  ....  8.44:1  contact button, rest state
     white     #ffffff on          #003e96  ....  9.86:1  contact button, hover state
   Arrow glyphs are TEXT, so they never use a raw palette hue on white: raw
   cerulean is 3.12:1, coral 2.75:1, viridian 3.19:1 and rose 4.35:1, all under
   4.5:1. Each card therefore carries two custom properties, --sp-t (the full
   brightness hue, used only for the decorative 5px top rule where no text
   sits) and --sp-tk (the darkened sibling, used for the arrow):
     cerulean-deep #257ea4 on white .... 4.57:1
     coral-deep    #b26047 on white .... 4.51:1
     rose-deep     #c54d6b on white .... 4.52:1
     viridian-deep #308467 on white .... 4.54:1
   Cobalt on the #fff5ee band measures 7.85:1, comfortably past the 3:1 floor
   for the focus ring, which is a UI boundary rather than text.

   ON-DARK INK
   The approval page set the marquee paragraph to rgba(255,255,255,.92). This
   implementation uses pure #ffffff instead, because the INK LAW at the top of
   this sheet allows only #ffffff and --rt-gold-bright on a dark surface, with
   no sub-white rgba. It also raises that paragraph from 7.6:1 to 8.44:1.
   ============================================================ */

#sponsors {
  /* Amendment 1: one radius value for the whole component. */
  --sp-radius: var(--radius-card);
}

/* ---------- Title Sponsor marquee ---------- */
#sponsors .sp-marquee {
  background: var(--hk-cobalt);
  border-radius: var(--sp-radius);
  padding: clamp(1.6rem, 4vw, 2.5rem);
  /* 2.4rem matches the .products margin-top this component replaces, so the
     gap under the lede is unchanged from the live page. */
  margin: 2.4rem 0 1rem;
  display: grid;
  grid-template-columns: 1.25fr 1fr;
  gap: 1.5rem 2.5rem;
  align-items: end;
}
#sponsors .sp-marquee h3 {
  margin: 0;
  color: #ffffff;
  font-size: clamp(1.5rem, 3.4vw, 2.15rem);
  font-weight: 800;
  letter-spacing: -0.025em;
  line-height: 1.14;
  text-wrap: balance;
}
#sponsors .sp-marquee p {
  margin: 0.85rem 0 0;
  color: #ffffff;
  font-size: 1.02rem;
  line-height: 1.55;
  max-width: 44ch;
}
/* min-width:0 on both grid children: without it a long unbroken token (an
   email address pasted into the copy later, a long product name) forces the
   1.25fr / 1fr track wider than the shell and the band scrolls sideways. */
#sponsors .sp-marquee-copy { min-width: 0; }
#sponsors .sp-marquee-act { min-width: 0; align-self: end; }

/* ---------- Scarcity chips ---------- */
/* Deliberately NOT .chip: that class is the filter-button component further up
   this sheet and carries its own border, hover and .active states. */
#sponsors .sp-chip {
  display: inline-block;
  font-family: var(--font-sans);
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 0.3rem 0.62rem;
  border-radius: var(--radius-pill);
  white-space: nowrap;
}
#sponsors .sp-chip-solid {
  background: var(--hk-sand);
  color: #061c38;              /* 12.01:1 on sand */
  margin-bottom: 0.9rem;
}
#sponsors .sp-chip-tint {
  background: rgba(6, 28, 56, 0.06);   /* composites to #f1f1f1 over the white card */
  color: #10233f;                        /* 13.11:1 on #f1f1f1 */
}

/* ---------- The four cards ---------- */
#sponsors .sp-row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1rem;
}
#sponsors .sp-card {
  background: #ffffff;
  border: 1px solid rgba(138, 106, 30, 0.4);   /* the light-band card border already used by .ticket-card / .practical-col */
  border-top: 5px solid var(--sp-t);
  border-radius: var(--sp-radius);
  padding: 1.35rem 1.25rem 1.4rem;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.7rem;
  transition: transform var(--ui-ease), box-shadow var(--ui-ease);
}
#sponsors .sp-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 10px 26px rgba(6, 28, 56, 0.1);
}
#sponsors .sp-card h3 {
  margin: 0;
  color: #061c38;              /* 19.17:1 on white */
  font-size: 1.08rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  text-wrap: balance;
}
#sponsors .sp-card p {
  margin: 0;
  color: #10233f;              /* 14.81:1 on white */
  font-size: 0.93rem;
  line-height: 1.58;
  flex: 1 1 auto;
}

/* ---------- Per-product enquiry link ---------- */
/* The tier hue is carried by the underline and the arrow, never by the label:
   on white, the label stays near-black so it clears AA regardless of tier. */
#sponsors .sp-enq {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font-family: var(--font-sans);
  font-size: 0.88rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  text-decoration: none;
  color: #061c38;
  border-bottom: 2px solid var(--sp-t);
  padding-bottom: 3px;
  transition: border-color var(--ui-ease), color var(--ui-ease);
}
/* Touch floor. These five links ARE the sponsorship conversion, and at desktop
   type size the flex box resolves to ~28px tall — under the 44px iOS Human
   Interface Guidelines minimum, which the RT visual-QA gate treats as a build
   failure for interactive elements. Growing the box (not the type) keeps the
   editorial weight of an inline text link while making it thumb-safe. The
   underline stays glued to the text via a bottom border on the inner box, so
   the extra height reads as breathing room rather than a stray rule. */
#sponsors .sp-enq {
  min-height: 44px;
  align-items: flex-end;
  padding-bottom: 10px;
}
#sponsors .sp-enq::after {
  content: "\2192";
  font-weight: 700;
  color: var(--sp-tk);          /* darkened sibling: the arrow is text */
  transition: transform var(--ui-ease);
}
#sponsors .sp-enq:hover::after,
#sponsors .sp-enq:focus-visible::after { transform: translateX(3px); }

/* Marquee link sits on cobalt, so it flips to white on sand. */
#sponsors .sp-marquee .sp-enq {
  color: #ffffff;               /* 8.44:1 on cobalt */
  font-size: 0.95rem;
  border-bottom-color: var(--hk-sand);   /* 5.28:1 on cobalt */
}
#sponsors .sp-marquee .sp-enq::after { color: var(--hk-sand); }
#sponsors .sp-marquee .sp-enq:hover,
#sponsors .sp-marquee .sp-enq:focus-visible { border-bottom-color: #ffffff; }

/* ---------- Rates note ---------- */
/* The hairline that separates the products from the closing note lives on the
   CARD ROW, not on .rates-note. Verified on render: the page-local
   .rates-note carries max-width:52ch, so a border-top on the paragraph itself
   draws a half-width stub that reads as a broken rule rather than a section
   divider. Putting it on the full-width row keeps the 52ch measure on the
   text and still lands the rule 2rem under the cards, where the approved
   layout puts it. */
#sponsors .sp-row {
  padding-bottom: 2rem;
  border-bottom: 1px solid rgba(138, 106, 30, 0.4);
}
#sponsors .rates-note { margin-top: 1.2rem; }

/* ---------- Closing contact block ---------- */
#sponsors .sp-contact {
  margin-top: 2.5rem;
  padding: 1.6rem clamp(1.1rem, 3vw, 1.9rem);
  background: #ffffff;
  border: 1px solid rgba(138, 106, 30, 0.4);
  border-left: 6px solid var(--hk-cobalt);
  border-radius: var(--sp-radius);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem 1.75rem;
}
#sponsors .sp-contact-copy { flex: 1 1 30ch; min-width: 0; }
#sponsors .sp-contact h3 {
  margin: 0 0 0.35rem;
  color: #061c38;
  font-size: 1.06rem;
  font-weight: 700;
  letter-spacing: -0.01em;
}
#sponsors .sp-contact p {
  margin: 0;
  color: #10233f;
  font-size: 0.92rem;
  line-height: 1.55;
}
/* Native list, per the house rule that 2+ related items never ship as comma
   prose. Indented inside the text column, marker outside, matching the
   bullet-alignment convention used elsewhere on the site. */
#sponsors .sp-contact-list {
  margin: 0.5rem 0 0;
  padding-left: 1.4rem;
  list-style: disc outside;
  color: #10233f;
  font-size: 0.92rem;
  line-height: 1.55;
}
#sponsors .sp-contact-list li { margin-bottom: 0.2rem; }
#sponsors .sp-contact-list li::marker { color: var(--hk-cobalt); }

#sponsors .sp-contact-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;             /* iOS tap-target floor */
  flex: 0 0 auto;
  background: var(--hk-cobalt);
  color: #ffffff;               /* 8.44:1 */
  text-decoration: none;
  font-family: var(--font-sans);
  font-size: 0.9rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  padding: 0.8rem 1.35rem;
  border-radius: var(--radius-control);
  transition: background var(--ui-ease), transform var(--ui-ease);
}
#sponsors .sp-contact-btn:hover,
#sponsors .sp-contact-btn:focus-visible {
  background: #003e96;          /* cobalt one step deeper, white now 9.86:1 */
  transform: translateY(-1px);
}

/* ---------- Focus ---------- */
#sponsors a:focus-visible {
  outline: 2px solid var(--hk-cobalt);   /* 7.85:1 against the #fff5ee band */
  outline-offset: 3px;
  border-radius: 2px;
}
#sponsors .sp-marquee a:focus-visible { outline-color: var(--hk-sand); }

/* ---------- Responsive, on the site's 980 / 720 breakpoints ---------- */
@media (max-width: 980px) {
  #sponsors .sp-marquee {
    grid-template-columns: 1fr;
    align-items: start;
  }
  #sponsors .sp-row { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 720px) {
  #sponsors .sp-row { grid-template-columns: 1fr; }
  #sponsors .sp-contact {
    flex-direction: column;
    align-items: flex-start;
  }
  /* flex-basis resolves against the MAIN axis, so the desktop `flex:1 1 30ch`
     becomes a 30ch HEIGHT once this block turns column, and the button drops
     to the bottom of a tall empty box. Caught on the 375 render. */
  #sponsors .sp-contact-copy {
    flex: 0 0 auto;
    width: 100%;
  }
  #sponsors .sp-contact-btn { width: 100%; }
}

/* ---------- Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  #sponsors .sp-card,
  #sponsors .sp-contact-btn,
  #sponsors .sp-enq,
  #sponsors .sp-enq::after { transition: none; }
  #sponsors .sp-card:hover,
  #sponsors .sp-contact-btn:hover { transform: none; }
  #sponsors .sp-enq:hover::after,
  #sponsors .sp-enq:focus-visible::after { transform: none; }
}

/* ============================================================
   A LA CARTE - COLOUR CHIP GRID  (partnerships.html #a-la-carte)
   ============================================================
   Variant A of the four layouts reviewed on 2026-08-14
   (qa/2026-08-14/alacarte-variants.html), APPROVED by Alex the
   same day, plus his two amendments to it:

   1. THE CATEGORY NAME MOVES ONTO THE COLOURED CAP, IN WHITE.
      In the reviewed variant the cap was an empty block of colour
      and the name sat below it in dark ink on the white card body.
      It now sits inside the cap. The descriptive line and the
      permanent "Request this" label stay below, on the light body.

   2. Every card links to Dominika@RealTimes.co ONLY, with a
      pre-filled subject and body naming that specific option. No
      carbon-copy parameter, no second recipient. (The reviewed
      page still carried one; that is superseded.) Nothing here
      styles that, it is noted so the two files read together.

   WHY --hk-*-deep EXISTS
   ----------------------
   Amendment 1 puts white text on the palette. Measured against
   #ffffff, the RAW --hk-* tokens do not carry it: cobalt 8.44:1
   passes, but cerulean 3.12:1, viridian 3.19:1, chartreuse 2.83:1,
   coral 2.75:1, rose 4.35:1 and sand 1.60:1 all miss the 4.5:1 AA
   floor for normal-size text, sand catastrophically so. Rather
   than drop white, drop the lightness: each --hk-*-deep below is
   the same hue darkened just past the AA line, so the card keeps
   its palette identity and the name stays legible. Measured
   white-on-colour ratios, in the same order as the tokens:

     --hk-cobalt-deep      #0047ab   8.44:1   (unchanged token value)
     --hk-cerulean-deep    #257ea4   4.57:1
     --hk-viridian-deep    #308467   4.54:1
     --hk-chartreuse-deep  #6e7e17   4.51:1
     --hk-coral-deep       #b26047   4.51:1
     --hk-rose-deep        #c54d6b   4.52:1
     --hk-sand-deep        #84734f   4.62:1

   These are for WHITE-ON-COLOUR SURFACES ONLY. The raw --hk-*
   tokens keep their existing jobs (rules, dividers, washes, small
   graphic pops) untouched. Never put white on a raw token.

   The card body deliberately keeps near-black copy, not a palette
   colour: the hue carries identity in the cap, and on the light
   band the same seven hues fail as small text. Measured on the
   band's card fill #fffaf6: name/label #061c38 = 18.49:1,
   description #10233f = 14.28:1, and on the #ffffff hover fill
   19.17:1 / 14.81:1.

   The tenth card, "Your Own Touchpoint", has no colour by design,
   it is the one a sponsor invents. Its cap is a seashell hatch
   with a dashed ink edge and the name in near-black (17.84:1), so
   the no-white-on-light rule is never bent to force uniformity.
   ============================================================ */

:root {
  /* Darkened siblings of the Hockney accent palette. Same hues,
     lowered lightness so #ffffff clears 4.5:1 on each. Used only
     where white text sits directly on the colour. See the ratio
     table above. */
  --hk-cobalt-deep:     #0047ab;
  --hk-cerulean-deep:   #257ea4;
  --hk-viridian-deep:   #308467;
  --hk-chartreuse-deep: #6e7e17;
  --hk-coral-deep:      #b26047;
  --hk-rose-deep:       #c54d6b;
  --hk-sand-deep:       #84734f;
}

/* Every rule below is scoped to #a-la-carte on purpose, not for
   weight but for reach: .band-seashell a:not(.btn-red):not(.nav-cta)
   :not(.teaser-card):not(.hk-link) (specificity 0,5,1) repaints any
   anchor on this band deep gold, and these cards are anchors. One ID
   beats it outright, the same trick already used by
   #a-la-carte .product-invite-link:hover further up this file, and it
   avoids touching that shared exclusion list. */

/* ---------- the grid ----------
   Five across, gapped. Not the 1px-mosaic .products frame the
   section used to sit in: the brief for this rebuild was that ten
   offers should read as ten separate things a sponsor can buy,
   not as one price table. */
#a-la-carte .alc-grid {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 1rem;
  margin-top: 2.4rem;
}

/* ---------- the card ----------
   The WHOLE card is the link. There is no anchor, button or other
   interactive element inside it, so nothing is nested and the card
   is one tab stop that a keyboard reaches and activates natively.
   overflow:hidden clips the square-cornered cap to the rounded card,
   the same frame-clips-square-children pattern .product and
   .edition-card already use. */
#a-la-carte .alc-card {
  display: flex;
  flex-direction: column;
  min-width: 0;
  text-decoration: none;
  /* Defensive, verified on render: the band's blanket anchor rule paints this
     <a> deep gold #8a6a1e, and although every text node below sets its own
     colour, an un-coloured one added later would silently inherit gold on a
     cream card (about 4.6:1, and wrong). Pinning the card's own colour makes
     near-black the inherited default instead. */
  color: #061c38;
  background: #fffaf6;
  border: 1px solid rgba(138, 106, 30, 0.4);
  border-radius: var(--radius-card);
  overflow: hidden;
  transition: transform var(--ui-ease), box-shadow var(--ui-ease), background-color var(--ui-ease);
}
#a-la-carte .alc-card:hover {
  background: #ffffff;
  transform: translateY(-3px);
  box-shadow: 0 12px 26px rgba(6, 28, 56, 0.16);
}
/* Cobalt on this band measures 7.85:1, well past the 3:1 the ring
   needs as a non-text indicator, and it is already the band's
   strongest palette hue. */
#a-la-carte .alc-card:focus-visible {
  outline: 3px solid var(--hk-cobalt-deep);
  outline-offset: 3px;
}

/* ---------- the coloured cap (amendment 1) ----------
   Solid block of the card's own deep shade, carrying the category
   name in white. --alc-cap is set per card below. */
/* min-height is sized to TWO lines of the cap type plus its padding, so a
   one-line name ("Panel Video") and a two-line name ("Post-event Brochure
   Partner") produce the same depth of colour and the caps read as one band
   across the row, as they did in the approved variant where the cap was a
   fixed empty block. It is a MINIMUM, so a longer name still grows the cap
   rather than clipping. Reset to 0 at one column, where each card owns its
   row and a fixed depth would only add dead colour. */
#a-la-carte .alc-cap {
  display: block;
  margin: 0;
  padding: 0.85rem 1rem;
  min-height: calc((0.98rem * 1.25 * 2) + 1.7rem);
  background: var(--alc-cap);
  color: #ffffff;
  font-size: 0.98rem;
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -0.005em;
  overflow-wrap: anywhere;
}

/* ---------- the light body ---------- */
#a-la-carte .alc-body {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  gap: 0.9rem;
  padding: 0.95rem 1rem 0.9rem;
}
#a-la-carte .alc-desc {
  display: block;
  font-size: 0.82rem;
  line-height: 1.45;
  color: #10233f;
}
/* Permanent, not hover-only: on touch there is no hover, so the
   affordance has to be visible at rest. Near-black rather than the
   card's own hue, see the header note. min-height keeps the label
   itself at a 44px tap target even though the whole card is the
   target. */
#a-la-carte .alc-ask {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: auto;
  min-height: 44px;
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #061c38;
}
#a-la-carte .alc-arrow {
  display: inline-block;
  transition: transform var(--ui-ease);
}
#a-la-carte .alc-card:hover .alc-arrow { transform: translateX(4px); }

/* ---------- per-card colour ----------
   Assignment is carried over from the approved variant unchanged:
   cool blues for arrival, warm tones for the evening itself,
   greens for what carries on afterwards. */
#a-la-carte .alc-card--cobalt     { --alc-cap: var(--hk-cobalt-deep); }
#a-la-carte .alc-card--cerulean   { --alc-cap: var(--hk-cerulean-deep); }
#a-la-carte .alc-card--viridian   { --alc-cap: var(--hk-viridian-deep); }
#a-la-carte .alc-card--chartreuse { --alc-cap: var(--hk-chartreuse-deep); }
#a-la-carte .alc-card--coral      { --alc-cap: var(--hk-coral-deep); }
#a-la-carte .alc-card--rose       { --alc-cap: var(--hk-rose-deep); }
#a-la-carte .alc-card--sand       { --alc-cap: var(--hk-sand-deep); }

/* The tenth is an open invitation rather than a fixed product, so it keeps a
   dashed edge to say "propose something" — but it KEEPS the coloured cap and
   the white name like the other nine. Alex's approved variant is "ten compact
   cards, EACH capped by a solid block of its own palette colour so the ten read
   as ten", with the category name on the colour in white; a tenth card with a
   hatched, colourless cap reads as nine cards plus a footnote and breaks the
   row. Viridian is the hue with no adjacency conflict: it sits under cobalt
   (row 1, column 5) and beside rose (row 2, column 4). White on
   --hk-viridian-deep measures 4.54:1. */
#a-la-carte .alc-card--open {
  --alc-cap: var(--hk-viridian-deep);
  border: 2px dashed #061c38;
  background: transparent;
}
#a-la-carte .alc-card--open:hover { background: #ffffff; }

/* ---------- reflow, on the site's own breakpoints ----------
   980px: five across is too tight, drop to three. Ten cards leave a
   lone card on the fourth row, so it spans the full width instead,
   exactly what .product:last-child already does in the 980 block.
   720px: one column. */
@media (max-width: 980px) {
  #a-la-carte .alc-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  #a-la-carte .alc-card:last-child { grid-column: 1 / -1; }
}
@media (max-width: 720px) {
  #a-la-carte .alc-grid { grid-template-columns: 1fr; }
  #a-la-carte .alc-card:last-child { grid-column: auto; }
  #a-la-carte .alc-cap { min-height: 0; }
}

@media (prefers-reduced-motion: reduce) {
  #a-la-carte .alc-card,
  #a-la-carte .alc-arrow { transition: none; }
  #a-la-carte .alc-card:hover { transform: none; }
  #a-la-carte .alc-card:hover .alc-arrow { transform: none; }
}

/* ============================================================
   KEEP EXPLORING, variant C "Colour on hover"
   APPEND-ONLY block. Add to the END of css/style.css.
   Nothing above this point is edited or removed.

   APPROVED: Alex, 14 August 2026, from
   qa/2026-08-14/keep-exploring-variants.html (variant C).
   Cards rest almost monochrome carrying only a small colour dot.
   Pointing at one, or tabbing to it, floods the whole card with its
   colour and flips the type to the matching ink. Chosen because it
   stays calm at six cards where six solid colours would shout down
   the page.

   ALEX'S TWO AMENDMENTS TO VARIANT C (these override the approval page)

   (1) ROUNDED EDGES on the cards. The site is no longer sharp-cornered:
       the LIVE-REVIEW BATCH (Alex 2026-08-03, asked twice, "rounded text
       boxes, as we had for MSN26") already rounds .teaser-card on the
       --radius-card token (16px). So this amendment is satisfied by the
       token that is already house standard: no new value, no hardcoded
       px, and if the site ever returns to sharp corners the one token
       flips these with everything else. .ke-card restates the token
       explicitly so the amendment is self-documenting and survives any
       future edit to that batch list. The colour dot stays a circle
       (border-radius:50%), which is geometry, not a corner.

   (2) ALWAYS ROUTE TO THE TWO COMMERCIAL DESTINATIONS. Every page that
       carries this component must offer a card to registration/tickets
       AND a card to partnerships/sponsorships. That is a markup rule,
       enforced in the per-page HTML, not in CSS. What CSS does here is
       give those two the STRONGEST colours in the set so they read as
       the primary invitations:
         registration -> cobalt   (the single deepest value, takes white)
         partnerships -> coral    (the warmest, highest-chroma safe value)
       The remaining four destinations take the supporting hues.

   CONTRAST, MEASURED NOT ASSUMED (sRGB relative luminance, WCAG 2.x)
   The card floods with its colour on hover, so the colour becomes a TEXT
   BACKGROUND and every hovered state was measured, not guessed.

     HOVERED (flood colour + its matching ink)
       registration  cobalt     #0047ab + white      #ffffff =  8.44:1  PASS
       partnerships  coral      #ea7e5d + near-black #061c38 =  6.97:1  PASS
       programme     cerulean   #2e9cca + near-black #061c38 =  6.14:1  PASS
       speakers      viridian   #3aa17e + near-black #061c38 =  6.01:1  PASS
       venue         chartreuse #8fa31e + near-black #061c38 =  6.78:1  PASS
       tribute       sand       #e8c98a + near-black #061c38 = 12.01:1  PASS

     Only cobalt is dark enough to carry white type. White FAILS on
     cerulean (3.12), viridian (3.19), chartreuse (2.83), coral (2.75)
     and sand (1.60), so those five take near-black, which is the
     "matching ink" for all but one card.

     ROSE #c94f6d IS RETIRED FROM THE FLOOD. It is a mid tone and clears
     neither ink: 4.35:1 with white, 4.40:1 with near-black. Both sit
     under the 4.5:1 body-text bar. This is not an invention, it is the
     approval page's own prescribed fix ("use rose for edges and arrows
     only"), applied to variant C because variant C also makes the colour
     a text ground. Rose survives in the .ke-rule wash, so the palette
     stays whole; it is simply never a background for type.

     RESTING (unchanged house values, re-measured to confirm)
       light band card #fffaf6: key #061c38 18.49, desc #2a4a72 11.74,
                                cta #8a6a1e 4.87   all PASS
       granat ERA card   #0a2d58: key/desc #ffffff 17.40,
                                cta #ddc074 9.83   all PASS

     FOCUS RING (sits outside the card, so it is measured against the BAND)
       near-black #061c38 on seashell band #fff5ee = 17.84:1
       white      #ffffff on granat ERA band #061c38 = 19.17:1

   HOVER AND KEYBOARD FOCUS ARE ONE RULE. Every flood, ink flip, dot and
   arrow change is driven by a single `:hover, :focus-visible` selector
   list, so the two states cannot drift apart. Focus additionally carries
   a visible ring, because a keyboard user gets no pointer to confirm
   where they are.

   SPECIFICITY NOTE. This block sits after the .band-seashell overrides,
   which reach 0,3,0 on .band-seashell .teaser-card:hover. Rather than
   relying on source order (fragile if anything is appended later), the
   state rules below are written at 0,4,0 or higher via
   `.subpage-teasers .ke-grid .ke-card`, so they win regardless of order.
   ============================================================ */

/* ---- Per-destination colour map ----------------------------
   Each card carries its own --ke-c (the flood colour) and --ke-on-c
   (the ink measured legible on that colour). Every rule below reads
   only these two properties, so a destination keeps the same colour
   on every page and one edit here re-colours the whole site.
   ------------------------------------------------------------ */
.ke-c-tickets   { --ke-c: var(--hk-cobalt);     --ke-on-c: #ffffff; }  /*  8.44:1 */
.ke-c-partners  { --ke-c: var(--hk-coral);      --ke-on-c: #061c38; }  /*  6.97:1 */
.ke-c-programme { --ke-c: var(--hk-cerulean);   --ke-on-c: #061c38; }  /*  6.14:1 */
.ke-c-speakers  { --ke-c: var(--hk-viridian);   --ke-on-c: #061c38; }  /*  6.01:1 */
.ke-c-venue     { --ke-c: var(--hk-chartreuse); --ke-on-c: #061c38; }  /*  6.78:1 */
.ke-c-tribute   { --ke-c: var(--hk-sand);       --ke-on-c: #061c38; }  /* 12.01:1 */

/* ---- Two-column shell: heading left, cards right ----------- */
.ke-inner {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(1.6rem, 3.5vw, 3.2rem);
  align-items: start;
}
/* 980px is the house tablet breakpoint. Below it the two columns stack
   with the heading first, which is also the reading order in the DOM. */
@media (min-width: 980px) {
  .ke-inner { grid-template-columns: minmax(0, 1fr) minmax(0, 1.95fr); }
  /* Sticky offset clears the fixed nav bar via the same --nav-h token
     every other offset on this site keys off, never a literal. */
  .ke-head { position: sticky; top: calc(var(--nav-h) + 1.5rem); }
}

.ke-head { min-width: 0; }

/* Display-size heading. No colour is set on purpose: .band-seashell h2
   (0,2,0) forces #061c38 on the light bands and the --ink default gives
   #ffffff on the granat ERA band, so the heading is correct on both
   surfaces without a single override here. */
.ke-h {
  font-size: clamp(2rem, 5vw, 3.6rem);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 0.94;
  /* Never break inside a word. A two-word heading wraps between the
     words or not at all: a split word orphans a letter on its own line. */
  overflow-wrap: normal;
  word-break: normal;
  hyphens: none;
}

/* The full seven-hue Hockney wash, including the rose and chartreuse that
   are not flood colours, so the palette still reads whole. Deliberately
   NOT .eyebrow-rule: that one animates from width 0 and only expands under
   a .revealed ancestor, so it would render invisible on the three pages
   whose teaser section carries no .reveal class. This one has a fixed
   width and is deterministic on all seven pages. */
.ke-rule {
  display: block;
  width: 132px;
  max-width: 60%;
  height: 4px;
  margin-top: 1rem;
  background: linear-gradient(90deg,
    var(--hk-cobalt), var(--hk-cerulean), var(--hk-viridian),
    var(--hk-chartreuse), var(--hk-sand), var(--hk-coral), var(--hk-rose));
}

/* ---- Card field --------------------------------------------
   Written at 0,2,0 so it beats the 3-up .teaser-grid (0,1,0) at EVERY
   breakpoint independently of source order, including inside the
   existing 860px and 560px media queries which would otherwise still
   apply to an element carrying both classes.
   ------------------------------------------------------------ */
.subpage-teasers .ke-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.1rem;
  min-width: 0;
}
@media (min-width: 720px) {
  .subpage-teasers .ke-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* Odd card count: the last card spans the full width of the right
     column so no empty cell is ever left. This is what makes the same
     component work at 2, 3, 4, 5 and 6 cards without a per-page rule. */
  .subpage-teasers .ke-grid > .ke-card:nth-child(odd):last-child { grid-column: 1 / -1; }
}

/* ---- Card, resting ------------------------------------------
   .ke-card is always used ALONGSIDE .teaser-card, so the house card
   inherits its layout, padding, background, border, gold top rule and
   ink for free, per band. Only the additions are declared here.
   ------------------------------------------------------------ */
.ke-card {
  position: relative;
  /* Amendment (1). Already supplied by the LIVE-REVIEW BATCH via
     .teaser-card; restated so the rounded-corner instruction is explicit
     and survives any future edit to that batch list. Same token, same
     value, so there is no conflict. */
  border-radius: var(--radius-card);
  transition: transform var(--ui-ease), background var(--ui-ease),
              border-color var(--ui-ease), box-shadow var(--ui-ease);
}

/* The small colour dot: the only palette shown at rest. The ring is
   load-bearing, not decoration. Sand reaches only 1.54:1 and coral 2.65:1
   against the cream card, so an unringed dot would be close to invisible
   on the lighter hues; the ring gives every dot a legible edge whatever
   its colour. The dot is aria-hidden, so this is an affordance fix and
   not a text-contrast claim. */
.ke-dot {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: var(--ke-c);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.28);
  transition: background var(--ui-ease), transform var(--ui-ease), box-shadow var(--ui-ease);
}
.band-seashell .ke-dot { box-shadow: 0 0 0 1px rgba(6, 28, 56, 0.22); }

.ke-arrow {
  display: inline-block;
  transition: transform var(--ui-ease);
}

/* ---- Card, hovered AND keyboard-focused ---------------------
   ONE rule list drives both states, so they cannot drift apart. This is
   the whole point of variant C and the thing to preserve in any edit.
   ------------------------------------------------------------ */
.subpage-teasers .ke-grid .ke-card:hover,
.subpage-teasers .ke-grid .ke-card:focus-visible {
  background: var(--ke-c);
  border-color: var(--ke-c);
  /* The gold 2px top rule would survive the flood as a stray edge, so it
     joins the flood colour and the card reads as one plane. */
  border-top-color: var(--ke-c);
  transform: translateY(-3px);
  box-shadow: 0 12px 30px rgba(6, 28, 56, 0.20);
}

/* Ink flip to the measured matching ink. 0,5,0 clears the 0,2,0
   .band-seashell .teaser-card-k / -d / -cta overrides outright. */
.subpage-teasers .ke-grid .ke-card:hover .teaser-card-k,
.subpage-teasers .ke-grid .ke-card:hover .teaser-card-d,
.subpage-teasers .ke-grid .ke-card:hover .teaser-card-cta,
.subpage-teasers .ke-grid .ke-card:focus-visible .teaser-card-k,
.subpage-teasers .ke-grid .ke-card:focus-visible .teaser-card-d,
.subpage-teasers .ke-grid .ke-card:focus-visible .teaser-card-cta {
  color: var(--ke-on-c);
}

/* The dot flips to the ink and grows, so it reads as a deliberate state
   change rather than disappearing into its own flood. */
.subpage-teasers .ke-grid .ke-card:hover .ke-dot,
.subpage-teasers .ke-grid .ke-card:focus-visible .ke-dot {
  background: var(--ke-on-c);
  box-shadow: none;
  transform: scale(1.35);
}

.subpage-teasers .ke-grid .ke-card:hover .ke-arrow,
.subpage-teasers .ke-grid .ke-card:focus-visible .ke-arrow {
  transform: translateX(4px);
}

/* Focus must be visible without a mouse. The ring sits OUTSIDE the card
   (offset 3px), so it is measured against the BAND, not against the
   flood: near-black on the seashell band = 17.84:1, white on the
   granat ERA band = 19.17:1. The house .teaser-card:focus-visible gold
   ring (0,2,0) is superseded here because gold on a sand or chartreuse
   flood is the one combination it cannot survive. */
.subpage-teasers .ke-grid .ke-card:focus-visible {
  outline: 3px solid #061c38;
  outline-offset: 3px;
}
.band-granat ERA .ke-grid .ke-card:focus-visible { outline-color: #ffffff; }

/* ---- Reduced motion -----------------------------------------
   The lift and the arrow nudge are motion and are frozen. The colour
   flood and the ink flip are NOT motion: they are the state itself, and
   removing them would leave a keyboard user with no feedback at all.
   ------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  .ke-card,
  .ke-dot,
  .ke-arrow { transition: none; }
  .subpage-teasers .ke-grid .ke-card:hover,
  .subpage-teasers .ke-grid .ke-card:focus-visible { transform: none; }
  .subpage-teasers .ke-grid .ke-card:hover .ke-dot,
  .subpage-teasers .ke-grid .ke-card:focus-visible .ke-dot { transform: none; }
  .subpage-teasers .ke-grid .ke-card:hover .ke-arrow,
  .subpage-teasers .ke-grid .ke-card:focus-visible .ke-arrow { transform: none; }
}

/* ==========================================================================
   ERA26 bilingual layer (PL primary, EN secondary)
   ==========================================================================
   The donor edition was English-only and carried no language machinery. ERA26
   is PL-primary with an EN toggle from day one, and the choice is shared with
   the gallery and Insights surfaces through the localStorage key declared in
   the SSOT (languages.storage_key = 'era26-lang').

   Mechanism: every translatable string appears twice in the markup as sibling
   <span data-lang="pl"> / <span data-lang="en"> elements, and this rule hides
   the one that does not match the root. Chosen over a JS text-swap because it
   degrades correctly: <html data-lang="pl"> is set in the source, so the page
   is already correct Polish before any script runs, and stays correct if JS
   never loads at all.

   Both variants are in the DOM, so :lang() is set per element to keep
   hyphenation and screen-reader pronunciation honest. */
[data-lang="pl"] { }
html[data-lang="pl"] [data-lang="en"],
html[data-lang="en"] [data-lang="pl"] { display: none; }

/* The toggle itself: a quiet text button in the nav rail, sized to sit level
   with the nav links. On the dark nav it follows the dark-surface contract,
   pure white at full opacity, never a muted grey. */
.lang-opt {
  appearance: none;
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.35);
  color: #ffffff;
  font: inherit;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  padding: 0.3rem 0.62rem;
  cursor: pointer;
  line-height: 1;
  transition: border-color 0.18s ease, background-color 0.18s ease;
}
.lang-opt:hover,
.lang-opt:focus-visible { border-color: #ffffff; background: rgba(255, 255, 255, 0.1); }

/* On a light band the same control has to invert, or it disappears. */
.band-seashell .lang-opt { color: var(--rt-ink, #0a2d58); border-color: rgba(0, 0, 0, 0.3); }

@media (prefers-reduced-motion: reduce) {
  .lang-opt { transition: none; }
}

/* ==========================================================================
   HERO B, WNIESIONY NA STRONE 2026-08-24
   Wariant zatwierdzony przez Alexa w katalogu makiet. Cztery elementy, ktore
   strona wczesniej nie miala: duzy znak wydarzenia, naglowek w JEDNEJ linii,
   zlote kafelki metryki, zaokraglone przyciski.
   ========================================================================== */

/* ---- znak wydarzenia -----------------------------------------------------
   UWAGA NA KOLEJNOSC. Regula `.hero-banner img` wyzej pozycjonuje KAZDY obraz
   w banerze absolutnie i rozciaga go na 116% wysokosci kadru, bo pisano ja pod
   plakat tla. Znak jest rowniez <img> wewnatrz banera, wiec bez ponizszego
   nadpisania zostalby wyrzucony na cale tlo zamiast usiasc nad naglowkiem.
   Selektor jest celowo bardziej szczegolowy, nie !important. */
.hero-banner .era-hero-logo { display: block; margin: 0 auto clamp(1.1rem, 2.2vw, 1.8rem); }
.hero-banner .era-hero-logo img {
  position: static;
  width: auto;
  height: clamp(84px, 11vw, 168px);
  object-fit: contain;
  filter: none;
  margin: 0 auto;
  display: block;
}

/* ---- naglowek w jednej linii --------------------------------------------
   Prosba Alexa 2026-08-24. Zdanie ma 40 znakow; stopien jedzie na vw, wiec
   linia kurczy sie razem z oknem zamiast wyjsc poza kadr.
   Ponizej 860 px lamanie WRACA celowo: jedna linia na telefonie oznaczalaby
   pismo wielkosci kilku pikseli, czyli zaprzeczenie prosby o czytelnosc. */
/* SPECYFICZNOSC JEST TU NOSNA, nie ozdobna. Wyzej w tym arkuszu stoi
   `.hero-banner .hero-slide h1` (0,2,1) z clamp konczacym sie na 4,5rem, czyli
   72 px przy 1440. Selektor `.hero-banner .era-hero-jedna-linia` ma (0,2,0),
   wiec PRZEGRYWAL mimo pozniejszego miejsca w pliku: przy rownej wadze decyduje
   kolejnosc, ale tutaj waga rowna nie byla. Pierwsze wdrozenie wyszlo z tego
   naglowkiem 1576 px w kolumnie 1160 px, uciętym na krawedzi okna.
   `h1.era-hero-jedna-linia` daje (0,3,1) i wygrywa uczciwie, bez !important.

   ROZMIAR JEST WYLICZONY, nie dobrany na oko. Zdanie ma 40 znakow i w Interze
   700 mierzy 1576 px przy 72 px pisma, czyli 21,9 px szerokosci na kazdy piksel
   stopnia. Kolumna .rt-shell ma najwyzej 1160 px, wiec gorna granica musi lezec
   ponizej 1160/21,9 = 53 px. Sufit 3,1rem (49,6 px) daje 1086 px i zostawia
   74 px zapasu na wypadek innego kroju z fallbacku.
   Ponizej 860 px lamanie WRACA celowo: jedna linia na telefonie oznaczalaby
   pismo wielkosci kilku pikseli, czyli zaprzeczenie prosby o czytelnosc. */
.hero-banner .hero-slide h1.era-hero-jedna-linia {
  white-space: nowrap;
  max-width: none;
  font-size: clamp(1.45rem, 3.45vw, 3.1rem);
  line-height: 1.1;
  margin-left: auto;
  margin-right: auto;
}
@media (max-width: 860px) {
  .hero-banner .hero-slide h1.era-hero-jedna-linia {
    white-space: normal;
    max-width: 20ch;
    text-wrap: balance;
  }
}

/* ---- kafelki metryki -----------------------------------------------------
   Zastepuja linie rozdzielona kropkami (.hero-meta). Kazda informacja siedzi
   we wlasnym polu.
   WYPELNIENIE PELNE, nie przezroczyste: kafelek lezy na ruchomym kadrze, wiec
   kazde przeswitywanie tla zmienialoby jego barwe z klatki na klatke.
   ATRAMENT GRANATOWY, NIE BIALY, i to nie jest wybor estetyczny: zloto jest
   z natury jasne, wiec biala drobna typografia na nim daje okolo 1,7:1, czyli
   nieczytelne. Granat na zlocie daje ponad 8:1.
   KSZTALT PELNEJ PASTYLKI, a nie 16 px z --era-radius: kafelki sa niskie, wiec
   przy 16 px naroznik czytalby sie jak scieta krawedz, a nie zaokraglenie.
   `text-shadow: none` jest konieczne: .hero-on-banner naklada cien pisma dla
   czytelnosci na fotografii, a kafelek ma wlasne tlo i cien robilby sie brudny. */
.hero-chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: .55rem .6rem;
  margin: clamp(1.5rem, 2.8vw, 2.2rem) 0 0;
  text-shadow: none;
}
.hero-chip {
  display: inline-flex;
  align-items: center;
  padding: .52rem 1.1rem;
  border-radius: 999px;
  background: var(--rt-gold-bright);
  border: 1px solid var(--rt-gold);
  color: #14243d;
  text-shadow: none;
  font-family: var(--font-mono);
  font-size: .74rem;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* ---- przyciski hero ------------------------------------------------------
   Prosba Alexa 2026-08-24. Pastylka wiaze przyciski z kafelkami metryki nad
   nimi i z przyciskiem Bilety w pasku, wiec caly hero mowi jednym ksztaltem. */
.hero-cta-row .era-btn-pigulka { border-radius: 999px; }

/* ==========================================================================
   ERA26 — AGENDA WIECZORU + GRUPA ODBIORCÓW, wniesione 2026-08-25
   Warianty wybrane przez Alexa: agenda „Z2 poświata", odbiorcy „O1 pas na
   całą szerokość".

   ZNACZENIE KOLORU. Oba panele merytoryczne mają TEN SAM granatowy gradient,
   celowo: różne odcienie sugerowałyby różną rangę, a nie różnią się rangą.
   Złoto występuje w tym rzędzie dokładnie RAZ, na karcie momentu specjalnego,
   i dlatego znaczy „to jest coś innego". Z tego samego powodu przyciski
   paneli są na białym obrysie, a nie złote — dwa złote przyciski obok złotej
   karty rozmieniłyby ten kolor na drobne.

   ATRAMENT NA ZŁOCIE JEST GRANATOWY, NIGDY BIAŁY. Złoto jest z natury jasne:
   biała drobna typografia na #ddc074 daje około 1,7:1. Granat #061c38 daje
   9,6:1 na jaśniejszym końcu gradientu i 6,1:1 na ciemniejszym.
   ========================================================================== */

.era-agenda { background: var(--seashell-light-band); color: #061c38; padding: clamp(2.6rem, 6vw, 4.6rem) 0; }
.era-agenda .ag-kicker {
  display: block; font-size: .7rem; letter-spacing: .2em; text-transform: uppercase;
  font-weight: 700; margin: 0 0 .65rem;
  /* Złoto marki na Seashell daje 2,2:1 jako tekst, czyli etykieta znika.
     Przyciemniony brąz złota daje 5,35:1 i nadal czyta się jak złoto. */
  color: #7d6229;
}
/* ATRAMENT WYMUSZONY, NIE ODZIEDZICZONY. Zmienne --ink na tej stronie
   rozwiazuja sie do BIELI, bo caly arkusz jest pisany pod ciemne pasma; jasne
   pasma odzyskuja ciemny atrament przez klase .band-seashell. Ta sekcja ma
   wlasne tlo Seashell, ale nie nosi tamtej klasy, wiec przy pierwszym wdrozeniu
   naglowek wyszedl BIALY NA KREMOWYM, czyli praktycznie niewidoczny.
   Dlatego kolor jest tu podany wprost, a nie zostawiony dziedziczeniu. */
.era-agenda .ag-h2 {
  font-size: clamp(1.45rem, 3vw, 2.1rem); font-weight: 700; line-height: 1.18;
  margin: 0 0 .7rem; max-width: 24ch; color: #061c38;
}
.era-agenda h2, .era-agenda h3 { color: inherit; }
.era-agenda .ag-lede { margin: 0 0 clamp(1.5rem, 3vw, 2.2rem); color: #10233f; max-width: 64ch; line-height: 1.65; font-size: .96rem; }
.era-agenda .ag-nota { display: block; margin-top: clamp(1.3rem, 2.4vw, 1.9rem); font-size: .78rem; color: #10233f; opacity: .78; line-height: 1.6; }

.era-agenda .rzad { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(.9rem, 1.8vw, 1.5rem); align-items: stretch; }

/* Karty paneli są PRZYCISKAMI, nie divami: mają się otwierać z klawiatury tak
   samo jak myszą, a czytnik ekranu ma je zapowiadać jako element do
   uruchomienia. Reset wyglądu przycisku jest konieczny. */
.era-agenda .karta {
  border-radius: 18px; padding: clamp(1.5rem, 2.6vw, 2.1rem);
  display: flex; flex-direction: column; color: #fff;
  box-shadow: 0 18px 40px rgba(10, 45, 88, .16);
  font: inherit; text-align: left; border: 0; margin: 0; width: 100%;
  transition: transform 220ms ease, box-shadow 220ms ease;
}
.era-agenda button.karta { cursor: pointer; }
.era-agenda button.karta:hover { transform: translateY(-4px); box-shadow: 0 26px 54px rgba(10, 45, 88, .24); }
.era-agenda button.karta:focus-visible { outline: 3px solid #061c38; outline-offset: 3px; }
.era-agenda .karta-1, .era-agenda .karta-2 { background: linear-gradient(150deg, #071b3b 0%, #2a5fa8 78%); }
.era-agenda .karta-3 {
  background: linear-gradient(160deg, #ddc074 0%, #b8963f 100%);
  color: #061c38; position: relative; overflow: hidden;
  justify-content: space-between; text-align: center; align-items: center;
}
/* Poświata: JEDNA okrągła plama światła bez krawędzi u góry i delikatne
   przyciemnienie przy dolnym rogu. To nie są paski — Alex je odrzucił.
   Daje karcie głębię, więc przestaje wyglądać jak wklejony prostokąt koloru. */
.era-agenda .karta-3::before {
  content: ""; position: absolute; inset: 0; z-index: 0;
  background:
    radial-gradient(ellipse 74% 52% at 50% -6%, rgba(255,247,224,.92), rgba(255,247,224,0) 68%),
    radial-gradient(ellipse 60% 44% at 76% 112%, rgba(90,64,16,.28), rgba(90,64,16,0) 70%);
}
.era-agenda .karta-3 > * { position: relative; z-index: 1; }

.era-agenda .k-nr { display: block; font-size: .68rem; letter-spacing: .16em; text-transform: uppercase; font-weight: 700; margin: 0 0 1rem; color: #ddc074; }
.era-agenda .karta-3 .k-nr { color: #061c38; opacity: .72; margin-bottom: 0; }
.era-agenda .k-h3 { margin: 0 0 .85rem; font-size: clamp(1.15rem, 2.1vw, 1.5rem); line-height: 1.2; font-weight: 700; color: inherit; }
.era-agenda .k-q { margin: 0 0 1rem; font-size: .92rem; font-weight: 700; line-height: 1.55; }
/* Hasła są PODPISEM, nie treścią — stąd mały stopień i rozstrzelenie. */
.era-agenda .k-tematy { margin: 0; font-size: .68rem; line-height: 1.7; letter-spacing: .02em; opacity: .8; }
.era-agenda .k3-tytul { margin: 0; padding: clamp(1.6rem, 4vw, 2.6rem) 0; font-size: clamp(1.35rem, 2.6vw, 1.85rem); line-height: 1.22; font-weight: 700; max-width: 14ch; }
.era-agenda .k3-dol { display: block; font-size: .82rem; line-height: 1.5; opacity: .82; max-width: 22ch; }

/* `margin-top: auto` pinuje przycisk do dna karty, więc wszystkie trzy karty
   trzymają równą wysokość mimo różnej długości opisu. */
.era-agenda .k-otworz {
  display: inline-flex; align-items: center; gap: .5rem; margin-top: auto; align-self: flex-start;
  padding: .72rem 1.25rem; border-radius: 999px;
  font-size: .95rem; font-weight: 700; letter-spacing: .01em;
  background: rgba(255,255,255,.08); border: 1px solid rgba(255,255,255,.72); color: #fff;
  transition: background 180ms ease;
}
.era-agenda .k-tematy + .k-otworz { margin-top: 1.4rem; }
.era-agenda button.karta:hover .k-otworz { background: rgba(255,255,255,.18); }
.era-agenda .k-otworz .strzalka { transition: transform 200ms ease; }
.era-agenda button.karta:hover .k-otworz .strzalka { transform: translateX(3px); }

/* ---- okno ze składem panelu ---- */
body.agenda-zablokowane { overflow: hidden; }
.agenda-zaslona {
  position: fixed; inset: 0; z-index: 900;
  background: rgba(6, 28, 56, .72); backdrop-filter: blur(6px);
  display: grid; place-items: center; padding: clamp(1rem, 4vw, 2.5rem);
  opacity: 0; pointer-events: none; transition: opacity 220ms ease;
}
.agenda-zaslona.otwarta { opacity: 1; pointer-events: auto; }
.agenda-okno {
  width: min(760px, 100%); max-height: min(86vh, 860px); overflow-y: auto;
  border-radius: 18px; color: #fff; padding: clamp(1.6rem, 3.4vw, 2.6rem);
  background: linear-gradient(150deg, #071b3b 0%, #2a5fa8 78%);
  box-shadow: 0 40px 90px rgba(6, 28, 56, .5);
  transform: translateY(14px) scale(.985); transition: transform 240ms ease;
}
.agenda-zaslona.otwarta .agenda-okno { transform: none; }
.agenda-okno .okno-gora { display: flex; align-items: flex-start; gap: 1rem; }
.agenda-okno .okno-gora > div { flex: 1; }
.agenda-okno .okno-nr { display: block; font-size: .68rem; letter-spacing: .16em; text-transform: uppercase; font-weight: 700; color: #ddc074; margin-bottom: .5rem; }
.agenda-okno h2 { margin: 0 0 .5rem; font-size: clamp(1.25rem, 2.6vw, 1.75rem); line-height: 1.2; color: #fff; }
.agenda-okno .okno-q { margin: 0 0 1.4rem; font-size: .93rem; font-weight: 700; line-height: 1.55; }
.agenda-okno .okno-zamknij {
  flex: 0 0 auto; width: 38px; height: 38px; border-radius: 50%;
  border: 1px solid rgba(255,255,255,.5); background: rgba(255,255,255,.14);
  color: #fff; font-size: 1.1rem; line-height: 1; cursor: pointer;
}
.agenda-okno .okno-zamknij:hover { background: rgba(255,255,255,.26); }
.agenda-okno .sklad-nad {
  display: block; font-size: .64rem; letter-spacing: .16em; text-transform: uppercase;
  font-weight: 700; color: #ddc074; margin: 0 0 .8rem;
  padding-top: 1.1rem; border-top: 1px solid rgba(255,255,255,.3);
}
.agenda-okno .sklad { list-style: none; margin: 0; padding: 0; display: grid; gap: .55rem; }
.agenda-okno .osoba {
  display: grid; grid-template-columns: 46px 1fr auto; gap: .9rem; align-items: center;
  background: rgba(255,255,255,.12); border: 1px solid rgba(255,255,255,.24);
  border-radius: 12px; padding: .7rem .9rem;
}
.agenda-okno .osoba.moderator { background: rgba(255,255,255,.2); border-color: rgba(255,255,255,.5); }
/* Zarys sylwetki zamiast zdjęcia: pusty krążek czytałby się jak błąd
   ładowania, a zdjęć prelegentów nie ma i długo nie będzie. */
.agenda-okno .awatar { width: 46px; height: 46px; border-radius: 50%; border: 1px dashed rgba(255,255,255,.5); display: grid; place-items: center; }
.agenda-okno .awatar svg { width: 22px; height: 22px; opacity: .7; }
.agenda-okno .osoba-rola { display: block; font-size: .82rem; font-weight: 700; }
.agenda-okno .osoba-stan { display: block; font-size: .75rem; opacity: .8; margin-top: .1rem; }
.agenda-okno .osoba-plakietka {
  font-size: .6rem; letter-spacing: .12em; text-transform: uppercase; font-weight: 700;
  border-radius: 999px; padding: .26rem .6rem;
  background: rgba(255,255,255,.22); border: 1px solid rgba(255,255,255,.45); white-space: nowrap;
}
.agenda-okno .okno-stopka { margin-top: 1.3rem; font-size: .82rem; line-height: 1.6; opacity: .9; }

/* ==========================================================================
   GRUPA ODBIORCÓW — wariant O1, kadr na całą szerokość
   Key visual `eve-2-koktajl`: jedyny kadr z puli ERA26 o proporcji pasa i
   jedyny, na którym widać CAŁĄ SALĘ naraz, a nie jedną grupkę przy oknie.
   Sekcja mówi „kogo zapraszamy", więc obraz pokazuje towarzystwo, nie wnętrze.

   LUDZIE NA TYM KADRZE SĄ WYGENEROWANI, NIE SFOTOGRAFOWANI — stąd obowiązkowy
   podpis „wizualizacja". Bez niego obraz sugeruje relację z wydarzenia, które
   się jeszcze nie odbyło.

   KURTYNA JEST NIERÓWNOMIERNA, celowo: mocniejsza po lewej, gdzie leży tekst,
   przezroczystsza po prawej, gdzie zostaje samo zdjęcie. Równomierne
   przygaszenie zabiłoby to, co ten kadr ma pokazać — salę pełną ludzi.
   ========================================================================== */
.era-odbiorcy {
  position: relative; overflow: hidden; color: #fff;
  padding: clamp(3rem, 7vw, 5.5rem) 0;
  background-image: url("/events/ERA26-Warsaw/images/kv/eve-2-koktajl-plyta-1920.webp");
  background-size: cover; background-position: center 42%;
  background-color: #061c38;   /* paint-before-image, żeby nigdy nie mignęło jasne tło */
}
.era-odbiorcy::before {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(100deg, rgba(6,28,56,.94) 0%, rgba(6,28,56,.9) 42%, rgba(6,28,56,.6) 74%, rgba(6,28,56,.42) 100%);
}
.era-odbiorcy > * { position: relative; z-index: 2; }
.era-odbiorcy .od-kicker { display: block; font-size: .7rem; letter-spacing: .2em; text-transform: uppercase; font-weight: 700; color: #ddc074; margin: 0 0 .65rem; }
.era-odbiorcy .od-h2 { font-size: clamp(1.5rem, 3.1vw, 2.2rem); font-weight: 700; line-height: 1.16; margin: 0 0 .8rem; max-width: 20ch; color: #fff; }
.era-odbiorcy .od-lead { margin: 0 0 clamp(1.5rem, 3vw, 2.2rem); line-height: 1.65; font-size: .98rem; max-width: 58ch; color: #fff; }
/* Dziesięć obszarów w akapicie byłoby ścianą tekstu; jako pastylki są
   policzalne jednym rzutem oka i od razu widać, że jest ich dużo. */
.era-odbiorcy .obszary { display: flex; flex-wrap: wrap; gap: .5rem; margin: 0 0 clamp(1.6rem, 3vw, 2.2rem); padding: 0; list-style: none; }
.era-odbiorcy .obszary li {
  font-size: .8rem; font-weight: 600; border-radius: 999px; padding: .48rem 1rem;
  border: 1px solid rgba(255,255,255,.55); color: #fff; background: rgba(255,255,255,.1);
}
/* Paski pokazują PROPORCJĘ obecności, nie procent sali i nie liczbę osób —
   takiej liczby nie mamy i nie wolno jej zmyślić. Podpis mówi to wprost. */
.era-odbiorcy .szczeble { list-style: none; margin: 0; padding: 0; display: grid; gap: .55rem; max-width: 620px; }
.era-odbiorcy .szczebel { display: grid; grid-template-columns: 1fr auto; gap: .3rem .9rem; align-items: baseline; }
.era-odbiorcy .szczebel b { font-size: .92rem; font-weight: 700; color: #fff; }
.era-odbiorcy .szczebel > span { font-size: .76rem; color: #fff; opacity: .82; }
.era-odbiorcy .pasek { grid-column: 1 / -1; height: 4px; border-radius: 999px; overflow: hidden; background: rgba(255,255,255,.2); }
.era-odbiorcy .pasek i { display: block; height: 100%; border-radius: 999px; background: #ddc074; }
.era-odbiorcy .od-nota { display: block; margin: 1rem 0 0; font-size: .78rem; color: #fff; opacity: .8; line-height: 1.6; }
/* PODPIS PO LEWEJ, nie po prawej. Prawy dolny rog okna zajmuja dwa plywajace
   przyciski - kalendarz i WhatsApp - i przy pierwszym wdrozeniu zaslonily one
   polowe slowa „wizualizacja". Podpis jest wymagany przy tym kadrze, wiec nie
   moze byc czesciowo zakryty. */
.era-odbiorcy .podpis-kv {
  position: absolute; left: clamp(1rem, 3vw, 2.2rem); bottom: clamp(1rem, 2vw, 1.6rem); z-index: 3;
  display: inline-block; font-size: .62rem; letter-spacing: .14em; text-transform: uppercase; font-weight: 600;
  padding: .26rem .6rem; border-radius: 999px;
  background: rgba(6,28,56,.7); border: 1px solid rgba(255,255,255,.32); color: #fff;
}

@media (max-width: 940px) {
  .era-agenda .rzad { grid-template-columns: 1fr; }
  .agenda-okno .osoba { grid-template-columns: 40px 1fr; }
  .agenda-okno .osoba-plakietka { grid-column: 2; justify-self: start; margin-top: .3rem; }
  .agenda-okno .awatar { width: 40px; height: 40px; }
  .era-odbiorcy .obszary li { white-space: normal; }
}

/* Pasek partnerów stoi teraz BEZPOŚREDNIO POD HERO, a nie po sekcji, jak na
   stronie donorskiej. `.marquee-band` niesie `margin-top: 3.6rem`, które tam
   oddzielało go od treści wyżej; tutaj otwierałoby białą szparę między hero
   a paskiem. Zerowany tylko dla tej jednej instancji, reguła bazowa zostaje
   nietknięta dla ewentualnych innych użyć. */
.era-pasek-partnerow { margin-top: 0; }

/* LOGOTYPY PARTNERÓW W KOLORZE — prośba Alexa 2026-08-25: „logo muszą być
   kolorowe, zobacz jak to na ten moment wygląda na b2b v2v".
   Sprawdzone: na B2BV2V26 London znaki są wyciszane do grafitu regułą
   `.marquee-row img { opacity:.72; filter: brightness(0) }` — czyli dokładnie
   tym, co Alex chce tu zdjąć. Arkusz ERA26 odziedziczył tę samą regułę po
   stronie donorskiej, więc bez tego nadpisania nasze pliki `-color.webp`
   renderowałyby się jako czarne sylwetki.
   Nadpisanie jest ZAWĘŻONE do paska ERA26 (`.era-pasek-partnerow`), więc reguła
   bazowa zostaje nietknięta dla ewentualnych innych zastosowań marquee.
   Wysokość podniesiona z 30 na 34 px: kolorowe znaki mają więcej detalu niż
   sylwetka i przy 30 px część liternictwa (ING, UniCredit) robi się papkowata. */
.era-pasek-partnerow .marquee-row img {
  filter: none;
  opacity: 1;
  height: 34px;
  max-width: 150px;
}


/* ==========================================================================
   NAGŁÓWKI SEKCJI: WIĘKSZE I W JEDNEJ LINII — prośba Alexa 2026-08-25
   („takie headery powinny być większym fontem i w jednej linii").

   ROZMIAR JEST WYLICZONY, nie dobrany na oko. Najdłuższy z tych nagłówków,
   „Dwie rozmowy, wokół których obraca się wieczór.", ma 44 znaki. W Interze 700
   znak zajmuje około 0,547 em, więc zdanie mierzy ~24,1 em. Kolumna .rt-shell
   ma najwyżej 1160 px, czyli sufit musi leżeć poniżej 1160/24,1 = 48 px.
   Sufit 2,9rem (46,4 px) daje ~1117 px i zostawia 43 px zapasu. To jest wzrost
   z dotychczasowych 2,1rem, czyli o blisko 40 procent.

   ŁAMANIE WRACA PONIŻEJ 1040 px, celowo. Jedna linia na węższym ekranie
   oznaczałaby pismo wielkości kilkunastu pikseli — czyli zaprzeczenie prośby
   o większy nagłówek. Prośba dotyczy desktopu, gdzie linia się mieści.

   NADTYTUŁY USUNIĘTE. Reguły .ag-kicker i .od-kicker zostają w arkuszu, ale nie
   mają już czego stylować — znaczniki zniknęły z index.html na prośbę Alexa
   („te małe podtytuły do usunięcia"). Zostawiam je, bo katalogi makiet w
   _design nadal ich używają. */
.era-agenda .ag-h2,
.era-odbiorcy .od-h2 {
  font-size: clamp(1.5rem, 3.9vw, 2.9rem);
  line-height: 1.14;
  max-width: none;
  white-space: nowrap;
}
@media (max-width: 1040px) {
  .era-agenda .ag-h2,
  .era-odbiorcy .od-h2 { white-space: normal; max-width: 22ch; font-size: clamp(1.5rem, 4.4vw, 2.2rem); }
}

/* ==========================================================================
   ERA26 — BILETY, wariant T3 „bilet z odcinkiem", wniesiony 2026-08-25
   Alex wybrał T3 z czterech wizualizacji i poprosił o dopracowanie: „ceny się
   rozjeżdżają […] przy każdym bilecie trzeba napisać, dla kogo jest".

   TRZY USTERKI Z WERSJI KATALOGOWEJ, NAPRAWIONE TUTAJ:
   1. Cena łamała się na dwie linijki — odcinek miał 210 px, a „459 zł brutto"
      szło jednym ciągiem. Odcinek ma teraz 272 px, liczba `white-space: nowrap`,
      a „brutto" jest osobnym wierszem pod nią.
   2. Ceny stały na różnych wysokościach — odcinek centrował zawartość w pionie,
      a bilety mają różną wysokość, więc każda cena lądowała gdzie indziej
      (zmierzone: 24, 26, 52 i 42 px od górnej krawędzi). Teraz zawartość jest
      kotwiczona do góry przy jednakowym wcięciu: wszystkie cztery stoją na
      28 px.
   3. Plakietka podwyżki łamała się na „599" i „zł". `white-space: nowrap`.

   ATRAMENT NA ZŁOCIE GRANATOWY, NIGDY BIAŁY — VIP jest jedynym złotym biletem,
   tak jak moment specjalny jest jedyną złotą kartą w agendzie. Złoto na tej
   stronie zawsze znaczy „to jest inne", nigdy „to jest ozdobne".

   PODWYŻKA STOI NA BILECIE, nie w przypisie: to jedyny powód, dla którego ktoś
   miałby kupić dziś, a nie za trzy tygodnie.
   ========================================================================== */
.era-bilety { background: var(--seashell-light-band); color: #061c38; padding: clamp(2.6rem, 6vw, 4.6rem) 0; }
.era-bilety .bl-h2 {
  font-size: clamp(1.5rem, 3.9vw, 2.9rem); line-height: 1.14; font-weight: 700;
  margin: 0 0 .7rem; max-width: none; white-space: nowrap; color: #061c38;
}
@media (max-width: 1040px) {
  .era-bilety .bl-h2 { white-space: normal; max-width: 22ch; font-size: clamp(1.5rem, 4.4vw, 2.2rem); }
}
.era-bilety .bl-lead { margin: 0 0 clamp(1.5rem, 3vw, 2.2rem); color: #10233f; max-width: 62ch; line-height: 1.65; font-size: .96rem; }
.era-bilety .bl-nota { display: block; margin-top: clamp(1.2rem, 2.2vw, 1.8rem); font-size: .78rem; color: #10233f; opacity: .8; line-height: 1.6; }

.era-bilety .lista { display: grid; gap: clamp(.7rem, 1.4vw, 1rem); }
.era-bilety .bilet {
  --odcinek: 272px;
  position: relative; display: grid; grid-template-columns: 1fr var(--odcinek);
  border-radius: 18px; overflow: hidden; color: #fff;
  background: linear-gradient(150deg, #071b3b 0%, #2a5fa8 78%);
  box-shadow: 0 14px 32px rgba(10,45,88,.14);
}
.era-bilety .bilet.vip { background: linear-gradient(160deg, #ddc074 0%, #b8963f 100%); color: #061c38; }
.era-bilety .lewa { padding: clamp(1.2rem, 2.2vw, 1.7rem); display: flex; flex-direction: column; }
.era-bilety .lewa h3 { margin: 0 0 .45rem; font-size: 1.08rem; font-weight: 700; color: inherit; }
.era-bilety .dla-kogo { margin: 0; font-size: .84rem; line-height: 1.6; opacity: .92; }

.era-bilety .odcinek {
  position: relative; display: grid; align-content: start; justify-items: center;
  gap: .5rem; text-align: center; padding: clamp(1.25rem, 2.3vw, 1.75rem) 1rem;
  background: rgba(255,255,255,.09);
}
.era-bilety .bilet.vip .odcinek { background: rgba(6,28,56,.1); }
.era-bilety .cena { white-space: nowrap; font-size: clamp(1.55rem, 3vw, 2.15rem); font-weight: 700; line-height: 1; letter-spacing: -.02em; }
.era-bilety .cena small { display: block; margin: .3rem 0 0; font-size: .34em; font-weight: 600; opacity: .78; letter-spacing: .1em; text-transform: uppercase; }
.era-bilety .podwyzka {
  white-space: nowrap; display: inline-block; font-size: .66rem; font-weight: 700; letter-spacing: .06em;
  border-radius: 999px; padding: .3rem .7rem; margin-top: .15rem;
  background: rgba(255,255,255,.16); border: 1px solid rgba(255,255,255,.5); color: #fff;
}
.era-bilety .bilet.vip .podwyzka { background: rgba(6,28,56,.14); border-color: rgba(6,28,56,.36); color: #061c38; }

/* Perforacja na styku obu części biletu. */
.era-bilety .odcinek::before {
  content: ""; position: absolute; left: 0; top: 10px; bottom: 10px; width: 2px;
  background: repeating-linear-gradient(180deg, rgba(255,255,255,.6) 0 6px, transparent 6px 12px);
}
.era-bilety .bilet.vip .odcinek::before {
  background: repeating-linear-gradient(180deg, rgba(6,28,56,.45) 0 6px, transparent 6px 12px);
}
/* Dwa jawne wycięcia, zakotwiczone do linii perforacji i niezależne od
   wysokości biletu. Kolor MUSI być dokładnie kolorem pasma, bo to nie jest
   kropka — to dziura wycięta w bilecie. */
.era-bilety .wyciecie {
  position: absolute; z-index: 3; width: 18px; height: 18px; border-radius: 50%;
  background: var(--seashell-light-band);
  right: var(--odcinek); transform: translateX(50%);
}
.era-bilety .wyciecie.gora { top: -9px; }
.era-bilety .wyciecie.dol { bottom: -9px; }

.era-bilety .kup {
  display: inline-flex; align-items: center; gap: .5rem; margin-top: auto; align-self: flex-start;
  padding: .7rem 1.2rem; border-radius: 999px; font-size: .9rem; font-weight: 700; text-decoration: none;
  background: rgba(255,255,255,.1); border: 1px solid rgba(255,255,255,.72); color: #fff;
  transition: background 180ms ease;
}
.era-bilety .bilet:hover .kup { background: rgba(255,255,255,.2); }
.era-bilety .bilet.vip .kup { background: #061c38; border-color: #061c38; color: #ddc074; }
.era-bilety .bilet.vip:hover .kup { background: #000f22; border-color: #000f22; }

@media (max-width: 820px) {
  .era-bilety .bilet { grid-template-columns: 1fr; }
  .era-bilety .odcinek::before {
    left: 8px; right: 8px; top: 0; bottom: auto; width: auto; height: 2px;
    background: repeating-linear-gradient(90deg, rgba(255,255,255,.6) 0 6px, transparent 6px 12px);
  }
  .era-bilety .bilet.vip .odcinek::before { background: repeating-linear-gradient(90deg, rgba(6,28,56,.45) 0 6px, transparent 6px 12px); }
  .era-bilety .wyciecie { display: none; }
}

/* ==========================================================================
   ERA26 · BILETY — poprawki 2026-08-25 (druga tura)
   Alex: „większe nazwy biletów, kup bilet może być po prawej stronie" oraz
   „wyrównaj kwoty w polach tekstowych".
   ========================================================================== */

/* 1. NAZWA BILETU JEST TERAZ NAJWIĘKSZYM ELEMENTEM LEWEJ CZĘŚCI.
      Wzrost z 1,08rem do 1,75rem, czyli o 62%. Przy okazji lewa część
      przestaje rozpychać się do dołu: przycisk z niej wyszedł, więc treść
      centruje się w pionie zamiast wisieć u góry. */
.era-bilety .lewa {
  justify-content: center;
  gap: .5rem;
}
.era-bilety .lewa h3 {
  margin: 0;
  font-size: clamp(1.3rem, 2.4vw, 1.75rem);
  line-height: 1.15;
  letter-spacing: -.01em;
}

/* 2. PRZYCISK PRZENIESIONY DO ODCINKA, pod cenę. Traci `margin-top: auto`,
      bo w odcinku nie ma czego rozpychać - kotwiczenie do dna zrobiłoby
      przycisk pływający względem ceny, a ma stać tuż pod nią. */
.era-bilety .odcinek .kup {
  margin-top: .55rem;
  align-self: center;
}

/* 3. KWOTY WYRÓWNANE DO WSPÓLNEJ OSI.
      Ceny mają różną liczbę cyfr (459 kontra 1 250), a odcinek centrował je
      w poziomie, więc każda liczba kończyła się w innym miejscu i kolumna
      czterech cen wyglądała na krzywą.
      Naprawa jest dwuczęściowa i obie części są potrzebne:
      - `tabular-nums` wymusza JEDNAKOWĄ SZEROKOŚĆ KAŻDEJ CYFRY. Bez tego
        nawet idealnie ustawione pole nie da równej kolumny, bo domyślnie
        „1" jest węższa od „9".
      - stała szerokość pola (8,2ch) plus wyrównanie do prawej sprawiają, że
        wszystkie cztery kwoty kończą się na tej samej pionowej linii, a samo
        pole zostaje wyśrodkowane w odcinku.
      Podpis „brutto" idzie do tej samej krawędzi, inaczej wisiałby pod
      liczbą niesymetrycznie. */
/* KWOTY WYŚRODKOWANE W POLU — Alex, 25.08, druga decyzja w tej sprawie:
   najpierw „wyrównaj kwoty", potem „wyśrodkuj w polu tekstowym wszystkie ceny".
   Nowsza wygrywa, więc wyrównanie do prawej krawędzi zostało zdjęte.
   `tabular-nums` ZOSTAJE mimo zmiany wyrównania i to nie jest pozostałość:
   w domyślnych cyfrach Intera „1" jest węższa od „9", więc bez cyfr
   tabelarycznych wyśrodkowana „1 250" i wyśrodkowana „1 999" miałyby różną
   szerokość i kolumna czterech cen dalej czytałaby się jako krzywa. */
.era-bilety .cena {
  display: block;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.era-bilety .cena small { text-align: center; }

/* ==========================================================================
   ERA26 — MAPA MIEJSCA, wniesiona 2026-08-25
   Panel z mapą Google przykryty odnośnikiem: najechanie pokazuje pigułkę
   „Otwórz w Google Maps", kliknięcie otwiera Google w nowej karcie.
   ========================================================================== */
.venue-mapa .mapa-adres {
  margin: 0 0 clamp(1.2rem, 2.4vw, 1.8rem);
  font-size: clamp(1rem, 1.9vw, 1.18rem);
  line-height: 1.65;
  color: #10233f;
}
.venue-mapa .mapa-adres b { color: #061c38; }

.mapa-panel {
  position: relative;
  border-radius: 18px;
  overflow: hidden;
  border: 1px solid rgba(10, 45, 88, .16);
  box-shadow: 0 18px 40px rgba(10, 45, 88, .12);
  /* Stały stosunek boków zamiast sztywnej wysokości: mapa ma być pasem na
     desktopie i wyższym prostokątem na telefonie, a nie jednym rozmiarem,
     który na jednym z nich jest zawsze zły. */
  aspect-ratio: 21 / 8;
  background: #e9e2da;   /* kolor pod mapą, zanim ramka się doczyta */
}
@media (max-width: 820px) { .mapa-panel { aspect-ratio: 4 / 3; } }

.mapa-panel iframe {
  position: absolute; inset: 0; width: 100%; height: 100%; border: 0;
  /* Mapa jest OBRAZEM, nie narzędziem: odnośnik nad nią przejmuje każde
     kliknięcie, więc ramka nie może łapać zdarzeń wskaźnika. */
  pointer-events: none;
}

.mapa-link {
  position: absolute; inset: 0; z-index: 2;
  display: grid; place-items: center;
  text-decoration: none;
  /* Przyciemnienie pojawia się dopiero przy najechaniu, więc w spoczynku
     mapa jest widoczna w pełni. */
  background: rgba(6, 28, 56, 0);
  transition: background 200ms ease;
}
.mapa-link:hover, .mapa-link:focus-visible { background: rgba(6, 28, 56, .46); }
.mapa-link:focus-visible { outline: 3px solid #061c38; outline-offset: 3px; }

.mapa-pigulka {
  display: inline-flex; align-items: center; gap: .55rem;
  padding: .8rem 1.4rem; border-radius: 999px;
  background: #ddc074; border: 1px solid #ddc074;
  /* ATRAMENT GRANATOWY NA ZŁOCIE: biała drobna typografia na #ddc074 daje
     około 1,7:1, granat daje 9,6:1. */
  color: #061c38;
  font-size: .95rem; font-weight: 700; letter-spacing: .01em;
  box-shadow: 0 10px 26px rgba(6, 28, 56, .3);
  opacity: 0; transform: translateY(6px);
  transition: opacity 200ms ease, transform 200ms ease;
}
.mapa-link:hover .mapa-pigulka,
.mapa-link:focus-visible .mapa-pigulka { opacity: 1; transform: none; }

/* Na urządzeniu dotykowym nie ma najechania, więc pigułka byłaby niewidoczna
   aż do kliknięcia — czyli nikt by nie wiedział, że panel gdziekolwiek
   prowadzi. Tam pokazujemy ją od razu. */
@media (hover: none) {
  .mapa-pigulka { opacity: 1; transform: none; }
  .mapa-link { background: rgba(6, 28, 56, .28); }
}

/* ============================================================================
   PRZEBIEG WIECZORU (speakers.html #przebieg)                     2026-08-25
   Alex: "wez przyklad z msn". Wzorzec MSN26 .ap-* JUZ TU JEST, kanonicznie
   przeniesiony wyzej w tym pliku (blok "PROGRAMME AGENDA TIMELINE, MSN26 .ap-*
   port"). Ten blok NIE POWTARZA go - dodaje wylacznie oprawe sekcji: pelne
   tlo z obrazem, przycienienie i naglowek. Wiersze, godziny, plakietki i
   kursywna linia domykajaca jada z tamtego bloku.
   (Pierwsze podejscie 2026-08-25 zdublowalo caly .ap-* i nadpisalo krój na
   Inter - a szeryf w tamtym porcie jest CELOWY, "keeps the MSN26 editorial
   character". Duplikat skasowany, zostaje jeden wlasciciel stylu wiersza.)

   Jedyny swiadomy wyjatek: tlo wiersza. Dawca ma cieply braz #1c1915 pod
   akwarele fortu; ERA26 jest granatowa, wiec wiersz dostaje granat.

   KONTRAKT CIEMNEJ POWIERZCHNI: sekcja jest ciemna - tekst czysta biel,
   zloto #ddc074 w pelnej jasnosci, obraz w tle ma zostac widoczny.
   ========================================================================== */
.era-przebieg {
  position: relative;
  width: 100vw; max-width: none; margin-left: calc(-50vw + 50%);
  padding: clamp(3.2rem, 7vw, 5.25rem) 0 clamp(3.6rem, 8vw, 6.75rem);
  background: #061c38;
  overflow: hidden;
}
.era-przebieg-tlo {
  position: absolute; inset: 0; z-index: 0;
  background: #061c38 url("../images/kv/eve-8-koktajl-wieczor-plyta-1536.webp") center/cover no-repeat;
}
.era-przebieg-tlo::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(6,28,56,.70) 0%, rgba(6,28,56,.60) 45%, rgba(6,28,56,.76) 100%);
}
/* Szerokosc jak u dawcy (1000px), nie pelne .rt-shell 1160: tresc wierszy ERA26
   jest krotka i w szerszej kolumnie wiersz swieci pustka po prawej. */
.era-przebieg-inner {
  position: relative; z-index: 1;
  width: min(1000px, calc(100vw - 2.5rem));
}
.era-przebieg .ap-h2 {
  margin: 0; color: #fff;
  font-size: clamp(1.5rem, 3.9vw, 2.9rem); line-height: 1.14;
  text-shadow: 0 2px 10px rgba(0, 0, 0, .75), 0 2px 30px rgba(0, 0, 0, .5);
}
.era-przebieg .ap-lead {
  margin: .85rem 0 clamp(2rem, 4vw, 3rem);
  color: #fff; font-size: 1rem; line-height: 1.6; max-width: 62ch;
  text-shadow: 0 1px 8px rgba(0, 0, 0, .8), 0 1px 20px rgba(0, 0, 0, .55);
}
.era-przebieg .ap-lead b { color: var(--rt-gold-bright); font-weight: 600; }
/* Granat zamiast brazu dawcy - jedyne nadpisanie wiersza. */
.era-przebieg .ap-row { background: rgba(10, 45, 88, .62); border-color: var(--rt-gold-25); }
.era-przebieg .ap-time { border-right-color: var(--rt-gold-25); }
@media (max-width: 768px) {
  .era-przebieg .ap-time { border-bottom-color: var(--rt-gold-25); }
}

/* ============================================================================
   PLAKIETKA "EARLY BIRD" - PRZYWROCONA 2026-08-26
   Regula istniala od 2026-08-25, ale zniknela w commicie 84b59765 (agenda na
   wzorcu MSN26): wycinajac stary blok `.era-przebieg` cialem od selektora do
   NASTEPNEGO komentarza sekcyjnego, a te dwie reguly lezaly pomiedzy. Klasyczna
   szkoda uboczna ciecia "do najblizszego naglowka". Defekt jechal na produkcji
   niezauwazony, bo plakietka bez tla nadal wyswietla tekst - po prostu jako
   zwykle slowa w naglowku ("RE/CRE Financing Early bird").
   Zlapane pomiarem computed style, nie okiem.

   Dopisek pojawia sie przy OBU biletach, ktore drozeja 10 wrzesnia. Advisory
   i VIP go nie maja, bo ich cena nie rosnie. Plakietka jest mniejsza od nazwy
   i ustawiona do jej linii bazowej, wiec czyta sie jak przypis do nazwy.
   ========================================================================== */
.era-bilety .lewa h3 .eb {
  display: inline-block;
  margin-left: .55rem;
  vertical-align: baseline;
  font-size: .46em;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  padding: .3rem .65rem;
  border-radius: 999px;
  background: #ddc074;
  /* Atrament granatowy na zlocie: biel dalaby tu okolo 1,7:1. */
  color: #061c38;
  white-space: nowrap;
}
@media (max-width: 620px) {
  /* Przy waskiej karcie plakietka schodzi pod nazwe zamiast ja rozpychac. */
  .era-bilety .lewa h3 .eb { display: block; margin: .45rem 0 0; width: max-content; }
}

/* ===========================================================================
   WIZYTOWKA KONTAKTOWA (zakladka Partnerstwa, sekcja #kontakt)
   ---------------------------------------------------------------------------
   KLON paska kontaktowego z talii ofertowej RealTimes
   (partnership-platform/qa/source/zonifero-era26-v8-FROZEN.html,
   .contact-strip / .contact-card). Reguly przeniesione 1:1 co do ksztaltu
   (siatka, promienie, cien, pigulki), z trzema swiadomymi roznicami:

   1. GRADIENT NA PALECIE ERA26. Wzorzec konczy sie na #164b9f - jasny blekit
      spoza tej palety. Tu #061c38 -> #0a2d58 -> #14417f.
   2. SZARY PODPIS ROLI PODCIAGNIETY. Wzorzec ma #758197 na bieli przy 12px,
      to okolo 3.9:1 - ponizej progu AA dla malego tekstu. Tu #5a6478 = 5.72:1.
   3. NAZWY KLAS wiz-*, nie contact-*. Lista wyjatkow w .band-seashell
      (a:not(...)) juz zna .wiz-link i .wiz-cta - zmiana nazw zmusilaby do
      ruszania tamtej reguly i zlamalaby kolory linkow w calym pasmie.

   HISTORIA, ZEBY SIE NIE POWTORZYLO: pierwsza wersja tej karty istniala
   WYLACZNIE w drzewie roboczym i nigdy nie trafila do commita. Przywracanie
   biletow przez `git checkout <sha> -- css/style.css` skasowalo ja bez sladu,
   a karta renderowala sie goly tekstem. Ten blok jest w repozytorium.
   =========================================================================== */

.era-kontakt {
  background: linear-gradient(120deg, #061c38 0%, #0a2d58 52%, #14417f 100%);
  position: relative;
  overflow: hidden;
}
/* Zlota poswiata w prawym gornym rogu - dokladnie jak we wzorcu, tylko
   przelozona na jasne zloto ERA26. Czysto dekoracyjna, nie niesie znaczenia. */
.era-kontakt::before {
  content: "";
  position: absolute;
  width: 430px;
  height: 430px;
  border-radius: 50%;
  right: -160px;
  top: -240px;
  background: radial-gradient(circle, rgba(221, 192, 116, .26), rgba(221, 192, 116, 0) 68%);
  pointer-events: none;
}
.era-kontakt .rt-shell { position: relative; z-index: 2; }

/* KONTRAKT CIEMNEJ POWIERZCHNI. Ta sekcja nosi klase .band-seashell dla siatki
   i odstepow, ale jej TLO zostalo zamienione na granatowy gradient. Reguly
   pasma jasnego maluja naglowki atramentem #10233f - na tym gradiencie to
   granat na granacie, czyli tekst praktycznie niewidoczny. Zlapane dopiero na
   zrzucie z renderu, nie na pomiarze samej karty: mierzylem karte, a naglowek
   stoi obok niej. Dlatego kazdy tekst tej sekcji dostaje jawny kolor na ciemnym. */
.band-seashell.era-kontakt h2,
.band-seashell.era-kontakt .kontakt-intro h2 span { color: #ffffff; }
.band-seashell.era-kontakt .eyebrow { color: var(--rt-gold-bright, #ddc074); }
.band-seashell.era-kontakt .eyebrow-rule { background: var(--rt-gold-45, rgba(197, 165, 90, .45)); }

.kontakt-siatka {
  display: grid;
  grid-template-columns: .85fr 1.15fr;
  gap: 42px;
  align-items: center;
}
.kontakt-intro h2 { margin: 0 0 1.25rem; }
/* CTA zostaje w lewej kolumnie, nie na karcie: wzorzec ma na karcie wylacznie
   trzy pigulki i nic wiecej. Przycisk na karcie zepsulby to porownanie. */
.band-seashell .kontakt-intro .wiz-cta {
  display: inline-block;
  padding: .8rem 1.4rem;
  border: 1px solid var(--rt-gold-45, rgba(197, 165, 90, .45));
  border-radius: 999px;
  color: var(--rt-gold-bright, #ddc074);
  font-size: .82rem;
  font-weight: 700;
  letter-spacing: .02em;
  text-decoration: none;
  transition: background .2s, border-color .2s, transform .2s;
}
.band-seashell .kontakt-intro .wiz-cta:hover {
  background: rgba(221, 192, 116, .12);
  border-color: var(--rt-gold-bright, #ddc074);
  transform: translateY(-2px);
}

.wizytowka {
  background: #fff;
  border-radius: 28px;
  padding: 22px 24px;
  display: grid;
  grid-template-columns: 100px 1fr;
  gap: 20px;
  align-items: center;
  box-shadow: 0 24px 70px rgba(0, 0, 0, .18);
}
.wiz-foto {
  width: 100px;
  height: 100px;
  border-radius: 50%;
  overflow: hidden;
  border: 4px solid #fff;
  box-shadow: 0 0 0 1px #d9e1ed, 0 10px 30px rgba(7, 27, 59, .12);
  background: linear-gradient(145deg, #dfe8f5, #fff);
}
.wiz-foto img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 20%;
  display: block;
}

/* Kotwiczone przez .band-seashell, bo reguly pasma (.band-seashell p, li ...)
   maja specyficznosc 0,2,0 i inaczej wygraja z pojedyncza klasa. */
.band-seashell .wizytowka .wiz-imie {
  margin: 0;
  font-size: 21px;
  font-weight: 900;
  letter-spacing: -.03em;
  color: #0a2d58;
}
/* Wzorzec: #758197 = 3.93:1 na bieli, ponizej AA dla 12px. Podniesione do
   #5a6478 = 5.72:1. Ten sam odcien chlodnej szarosci, tylko czytelny. */
.band-seashell .wizytowka .wiz-rola {
  margin: 3px 0 14px;
  font-size: 12px;
  color: #5a6478;
}
.wiz-linki { display: flex; gap: 9px; flex-wrap: wrap; }
.band-seashell .wizytowka .wiz-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  text-decoration: none;
  border: 1px solid #dde4ee;
  border-radius: 999px;
  padding: 8px 11px;
  color: #33435d;
  font-size: 12px;
  font-weight: 760;
  background: #f8fafc;
  transition: transform .2s, border-color .2s, background .2s;
}
.band-seashell .wizytowka .wiz-link:hover {
  transform: translateY(-2px);
  border-color: #b9c8dc;
  background: #fff;
}
/* Barwa marki LinkedIn, przyciemniona z #0a66c2 (4.53:1) do #0a5cb0 (5.36:1) -
   nadal rozpoznawalny blekit LinkedIn, z zapasem na malym tekscie. */
.band-seashell .wizytowka .wiz-link.wiz-in { color: #0a5cb0; }
.wiz-ikona {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: #eaf0f7;
  font-size: 10px;
  font-weight: 800;
  line-height: 1;
  color: inherit;
  flex: 0 0 auto;
}
.band-seashell .wizytowka .wiz-link.wiz-in .wiz-ikona { background: #e8f2ff; }

@media (max-width: 900px) {
  .kontakt-siatka { grid-template-columns: 1fr; gap: 28px; }
  .wizytowka { max-width: 720px; }
}
@media (max-width: 560px) {
  /* align-items:start, bo pigulki ustawione w kolumne robia prawy slupek
     wysokim - przy centrowaniu zdjecie odplywalo na srodek, obok maila,
     zamiast stac przy imieniu. */
  .wizytowka { grid-template-columns: 72px 1fr; padding: 18px; gap: 14px; align-items: start; }
  .wiz-foto { width: 72px; height: 72px; }
  /* Pigulki w kolumne: na waskim ekranie zawijaly sie w poszarpana drabinke. */
  .wiz-linki { display: grid; }
  .band-seashell .wizytowka .wiz-link { width: 100%; }
}

/* ============================================================
   STANDALONE PAGE SHELL (.legal-*) + APPROVED-BUYER PAYMENT PANEL (.pay-*)
   ============================================================
   Added 2026-08-27 with invite/pay.html.

   WHY .legal-* IS HERE AND NOT IN A FOURTH INLINE <style>
   terms.html, privacy.html and thank-you.html each carry their own inline copy of
   these rules. Three copies of one component is already one owner too few, and
   invite/pay.html would have made it four. The definitions are promoted here once
   so the pattern has a home; the three existing pages are untouched and keep
   rendering from their inline blocks, which sit AFTER the stylesheet link in the
   head and therefore still win on source order at equal specificity. Nothing they
   render changes. When those three are next swept, their inline blocks can simply
   be deleted.

   SURFACE: this shell sits on the page base, --background #061c38 (granat ERA), so
   it is a DARK surface and the dark-surface contract applies. It is satisfied by
   construction rather than by hand: --ink, --ink-soft and --ink-muted all resolve
   to --on-dark-* which are #ffffff, and --gold-ink is --rt-gold-bright #ddc074 at
   full brightness. No grey token and no sub-white rgba is used below.
   ============================================================ */
.legal-wrap { max-width: 760px; margin: 0 auto; padding: 2.4rem 1.25rem 4rem; }
.legal-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  row-gap: 0.5rem;
  gap: 1rem;
  padding: 1.4rem 1.25rem 0;
  max-width: 760px;
  margin: 0 auto;
}
.legal-top img { height: 28px; width: auto; }
.legal-top-right { display: flex; align-items: center; gap: 0.85rem; }
.legal-back {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--gold-ink);
  text-decoration: none;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
}
.legal-back:hover { color: var(--rt-red); }
.legal-wrap h1 {
  font-size: clamp(1.7rem, 3.4vw, 2.4rem);
  color: var(--ink);
  letter-spacing: -0.02em;
  margin: 1.2rem 0 0.4rem;
}
.legal-meta {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  color: var(--ink-muted);
  margin-bottom: 2rem;
}
.legal-wrap h2 { font-size: 1.15rem; margin: 2.2rem 0 0.7rem; }
.legal-wrap p, .legal-wrap li { font-size: 0.94rem; color: var(--ink-soft); }
.legal-wrap p + p { margin-top: 1.1rem; }
.legal-wrap ul {
  padding-left: 1.4em;
  list-style-position: outside;
  list-style-type: disc;
  margin: 0.5rem 0 1rem;
  display: grid;
  gap: 0.4rem;
}
.legal-wrap a { color: var(--gold-ink); }

/* ---- The payment panel ------------------------------------------------------
   ONE panel, ONE action. Everything else on the page is context. The tone
   attribute is written by js/pay.js and drives the left rule only: it is a
   SUPPORTING signal, never the sole carrier of meaning, because every state also
   states its condition in words in the heading and the body copy. Colour alone
   never tells the visitor anything here. */
.pay-panel {
  margin: 1.4rem 0 0.4rem;
  border: 1px solid var(--line-warm);
  border-left: 3px solid var(--rt-gold-bright);
  border-radius: var(--radius-card);
  background: var(--card);
  padding: clamp(1.2rem, 3.5vw, 1.8rem);
}
/* A refusal or an interruption. --on-dark-alert is the lightened brand red that
   clears AA on this card; the raw --rt-red does not. */
.pay-panel[data-tone="warn"] { border-left-color: var(--on-dark-alert); }
.pay-title {
  font-size: clamp(1.15rem, 2.6vw, 1.4rem);
  line-height: 1.25;
  color: var(--ink);
  margin: 0;
  letter-spacing: -0.01em;
}
.pay-body { margin-top: 0.85rem; }
.pay-body p { font-size: 0.94rem; line-height: 1.65; color: var(--ink-soft); margin: 0; }
.pay-body p + p { margin-top: 0.8rem; }
/* 44px min target, and full width on a phone so the one action on the page cannot
   be missed or mis-tapped. */
.pay-btn {
  margin-top: 1.3rem;
  min-height: 48px;
  cursor: pointer;
  font-family: var(--font-sans);
  font-size: 0.95rem;
}
.pay-btn[hidden] { display: none; }
.pay-actions { margin-top: 1.1rem; }
.pay-actions[hidden] { display: none; }
.pay-actions p { font-size: 0.9rem; color: var(--ink-soft); margin: 0; }

@media (max-width: 640px) {
  /* The button spans the panel on a phone. .btn-red is inline-flex by default, so
     width alone would not fill it. */
  .pay-btn { display: flex; width: 100%; }
}

/* ---- Honeypot wrapper in #reg-form -------------------------------------------
   Belt AND braces for the one field whose failure mode is SILENT DATA LOSS:
   api/register.js treats a filled honeypot as a bot, returns {ok:true} and stores
   nothing, so a visible honeypot means honest registrations vanish while the page
   still says thank you.

   Caught on the rendered page 2026-08-27, not in review: the wrapper carried
   class="field" plus the `hidden` attribute and rendered anyway, because the UA
   default [hidden]{display:none} is the weakest rule there is and .field's own
   display:flex beat it. The markup no longer carries .field; this rule makes the
   element's own class say it too, so re-adding a display rule upstream cannot
   quietly un-hide it again. */
.reg-hp { display: none; }

/* ===========================================================================
   PATRONAT MEDIALNY (strona glowna, pod paskiem partnerow)
   ---------------------------------------------------------------------------
   Osobny blok, nie dopisek do kolowrotka partnerow: tamten mowi o POPRZEDNICH
   edycjach, ten o TEJ. Naglowek dziedziczy `.marquee-label`, zeby oba pasma
   mialy identyczna typografie nadtytulu - nie dublowalem tych regul.

   TLO JASNE (Seashell), wiec znaki ida w wersji kolorowej/ciemnej. Bialy wariant
   bylby tu niewidoczny.

   ZNAKI SA ROZNEJ PROPORCJI (EuropaProperty 11:1, Archiweb 4,5:1). Dlatego
   wysokosc jest wspolna, a szerokosc wolna - inaczej jeden z nich musialby byc
   zdeformowany albo mikroskopijny. Limit szerokosci chroni przed rozjechaniem
   sie rzedu na waskich ekranach.
   =========================================================================== */

.era-patroni {
  background: var(--seashell-light-band, #fff5ee);
  /* Wiecej powietrza niz w pierwszej wersji: 28.08 ten blok przeszedl NAD pasek
     partnerow i jest teraz pierwsza rzecza pod banerem, z pelnowymiarowym
     naglowkiem. Przy poprzednim, ciasnym padingu naglowek dotykalby zdjecia. */
  padding: clamp(2.4rem, 5vw, 3.6rem) 0 clamp(2rem, 4vw, 3rem);
  /* Zlota wlosowa linia przejeta 28.08 od paska partnerow: to ona zamyka
     zdjecie hero. Wczesniej siedziala na pasku, bo pasek stal tu pierwszy.
     Historia: krotko byla tu MOJA druga zlota kreska rownolegla do czerwonej
     linii paska - stad ostrzezenie, zeby nie dokladac trzeciej. */
  border-top: 1px solid var(--rt-gold-25);
}

/* ---------------------------------------------------------------------------
   NAGLOWEK PASMA (`.pasmo-h2`) - wspolny dla patronatu i paska partnerow.
   Domi 28.08: „takie headery powinny byc pisane wiekszym fontem - wzoruj sie na
   partnerstwach ze strony msn". Na MSN26 te dwa pasma niesie pelnowymiarowy
   `h2.section-title` (clamp 2rem-2.8rem), a nie nadtytul; tutaj do 28.08 byl
   `p.marquee-label`, czyli 0,74rem monospace - trzykrotnie za malo.

   ROZMIAR DZIEDZICZY, NIE POWTARZA. Element jest teraz prawdziwym `h2`, wiec
   bierze systemowa skale strony (clamp 1,7rem-2,6rem) i kolor `--ink`. Ta klasa
   dokłada WYLACZNIE wysrodkowanie i marginesy - gdyby wpisac tu wlasny
   font-size, naglowki pasm rozjechalyby sie z reszta strony przy pierwszej
   zmianie skali typografii.

   ZMIANA JEST TEZ SEMANTYCZNA: `p` -> `h2`. Oba pasma maja teraz wlasny wezel
   w konspekcie dokumentu, co czytnik ekranu i wyszukiwarka czytaja jako sekcje,
   a nie jako luzny akapit nad obrazkami.
   --------------------------------------------------------------------------- */
.pasmo-h2 {
  text-align: center;
  margin: 0 0 clamp(1.4rem, 3vw, 2rem);
  /* WLASNA SKALA, o pol stopnia ponizej bazowego `h2` (clamp 1,7-2,6rem).
     Powod: na 375 px bazowy h2 dawal 27,2 px, czyli WIECEJ niz naglowek sekcji
     Agenda (24 px) - naglowek pasma krzyczalby glosniej niz naglowek sekcji.
     Tu wychodzi 23,2 px na mobile i 37,6 px na desktopie, wiec ~3x wiecej niz
     dawne 11,8 px `.marquee-label`, a hierarchia zostaje zachowana. */
  font-size: clamp(1.45rem, 3.1vw, 2.35rem);
  /* KOLOR MUSI BYC WPISANY WPROST, INACZEJ NAGLOWEK JEST NIEWIDOCZNY.
     Ta strona jest ciemna od podstaw: `--ink` rozwija sie do `--on-dark-primary`,
     czyli #ffffff, wiec bazowe `h2 { color: var(--ink) }` daje BIALY tekst.
     Kremowe pasma odkrecaja to regula `.band-seashell h1..h4 { color:#061c38 }`,
     ale ani `.era-patroni`, ani `.marquee-band` nie nosi klasy `.band-seashell`
     - wiec oba naglowki wyszly biale na #fff5ee i po prostu znikly.
     Zlapane na renderze po wdrozeniu 28.08 (zmierzone rgb(255,255,255)), nie
     w kodzie; sam kod czytal sie poprawnie. Ta sama wartosc co w regule dla
     pasm kremowych, zeby oba zrodla mowily to samo. */
  color: #061c38;
}
/* `.marquee` niesie wlasne `margin-top: 1.6rem`, wiec pod naglowkiem pasma
   sumowaloby sie z jego marginesem dolnym i logotypy odplywalyby o ~3,5rem.
   Zerowanie tylko w tym ukladzie - poza pasmem `.marquee` zachowuje swoj odstep. */
.marquee-band .pasmo-h2 + .marquee { margin-top: 0; }
.patroni-rzad {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: clamp(1.8rem, 5vw, 4rem);
}
.era-patroni .patron {
  display: inline-flex;
  align-items: center;
  /* Bez ramki i podkreslenia - to znak, nie odnosnik tekstowy. Stan hover
     sygnalizuje klikalnosc podniesieniem, nie zmiana koloru znaku. */
  text-decoration: none;
  transition: transform .2s, opacity .2s;
}
.era-patroni .patron:hover { transform: translateY(-2px); opacity: .82; }
.era-patroni .patron:focus-visible {
  outline: 2px solid var(--rt-gold, #c5a55a);
  outline-offset: 6px;
  border-radius: 4px;
}
.era-patroni .patron img {
  height: 42px;
  width: auto;
  /* 340 px. Historia limitu: przy zastepczym znaku EuropaProperty (lockup 11,4:1
     z dopiskiem "20 years on the CEE Market") limit 260 px scinal go wyraznie
     ponizej Archiwebu (4,5:1), wiec podniosłem go do 320. Od 28.08 mamy
     oficjalny plik od redakcji, proporcja 8,8:1, ktory przy wysokosci 42 px
     chce 369 px szerokosci - limit 320 dusil go do 36 px wysokosci, czyli
     nizej niz Archiweb. 340 px zostawia oba znaki blisko wspolnej wysokosci,
     nie pozwalajac przy tym, zeby dluzszy z nich rozpychal rzad na waskich
     ekranach. Zmierzone na renderze, nie policzone z glowy. */
  max-width: 340px;
  object-fit: contain;
  display: block;
}
@media (max-width: 560px) {
  .era-patroni .patron img { height: 34px; max-width: 240px; }
  .patroni-rzad { gap: 1.6rem; }
}
