/* ============================================================
   IMAGINE — matte black edition
   Editorial agency · half-screen B&W · sentence nav
   ============================================================ */

:root {
  --ink:        #0A0A0A;     /* matte black base */
  --ink-2:      #131210;     /* slight warm */
  --ink-3:      #1B1A18;
  --paper:      #F4EFE9;     /* warm white */
  --paper-soft: #C9C2B9;
  --mute:       #807A73;
  --rule:       rgba(244,239,233,.18);
  --rule-soft:  rgba(244,239,233,.08);
  --accent:     #F4EFE9;

  --serif: 'Cormorant Garamond', 'Canela', 'Playfair Display', Georgia, serif;
  /* Headlines (h1-h4) ride on --display, which defaults to --serif so the two
     match. The Big Shoulders tweak overrides --display alone, giving a
     display-headline / Inter-body split. */
  --display: var(--serif);
  --sans:  'Inter', 'Lato', system-ui, sans-serif;
  --hand:  'Caveat', 'Permanent Marker', cursive;

  --shell: clamp(20px, 4vw, 64px);
  --maxw:  1480px;
}

/* Tweenable percentage for the splash-logo liquid-fill effect. @property lets
   CSS interpolate it as a real <percentage> instead of a string swap. */
@property --fill {
  syntax: '<percentage>';
  inherits: false;
  initial-value: 0%;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
html {
  scroll-behavior: smooth;
  /* Suppress the default translucent grey overlay that mobile browsers flash
     on any tapped element. Each interactive element handles its own feedback
     via :active / pressed states instead. */
  -webkit-tap-highlight-color: transparent;
}
body {
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.55;
  color: var(--paper);
  background: var(--ink);
  /* matte texture: very subtle grain + soft vignette to give the "matte" depth */
  background-image:
    radial-gradient(ellipse at 30% 20%, rgba(255,255,255,.025), transparent 55%),
    radial-gradient(ellipse at 80% 90%, rgba(255,255,255,.015), transparent 60%),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1  0 0 0 0 1  0 0 0 0 1  0 0 0 0.04 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
  background-size: auto, auto, 180px 180px;
  background-attachment: fixed, fixed, fixed;
  overflow-x: hidden;
  /* Default-arrow cursor everywhere — no I-beam over paragraphs/headings.
     Buttons/links still get pointer from their own rules; form fields
     reset to `text` below so they remain typeable. */
  cursor: default;
}
input[type="text"], input[type="email"], input[type="tel"],
input[type="url"], input[type="search"], input[type="password"],
input:not([type]), textarea { cursor: text; }

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; cursor: pointer; border: 0; background: transparent; }

.shell { max-width: var(--maxw); margin: 0 auto; padding: 0 var(--shell); }
::selection { background: var(--paper); color: var(--ink); }

/* ── Type ──────────────────────────────────────────────────── */
.serif { font-family: var(--serif); font-weight: 400; }
.hand  { font-family: var(--hand); font-weight: 500; }
.eyebrow {
  font-family: var(--sans); font-size: 11px; letter-spacing: .24em;
  text-transform: uppercase; color: var(--paper-soft); font-weight: 500;
}
/* Top-of-subpage eyebrows (Történetünk, Esettanulmányok, Együtt) read
   in the accent red instead of paper-soft. Per-section eyebrows on the
   about page keep their muted treatment via more specific rules. */
.about-hero > .eyebrow,
.work-intro .eyebrow,
.together .eyebrow,
.team-intro .eyebrow,
.legal .eyebrow,
.case-hero .eyebrow { color: #d4351c; }
.rule { display:inline-block; width: 56px; height: 1px; background: currentColor; opacity:.5; vertical-align: middle; margin: 0 14px 4px 0; }

h1,h2,h3,h4 { font-family: var(--display); font-weight: var(--display-weight, 400); letter-spacing: -.012em; line-height: 1; margin: 0; text-wrap: balance; }
.hed-xxl { font-size: clamp(64px, 12vw, 220px); line-height: .9;  letter-spacing: -.028em; }
.hed-xl  { font-size: clamp(48px, 8vw, 128px);  line-height: .94; letter-spacing: -.022em; }
.hed-l   { font-size: clamp(36px, 5.4vw, 80px); line-height: .98; }
.hed-m   { font-size: clamp(26px, 3.4vw, 48px); line-height: 1.05; }
.body-l  { font-size: clamp(17px, 1.4vw, 21px); line-height: 1.55; max-width: 62ch; text-wrap: pretty; }
.italic  { font-style: italic; }

/* ── Top bar — sentence nav (carusi-style: side rail) ──────── */
.topbar {
  position: fixed; inset: 0 0 auto 0; z-index: 110;
  display: flex; align-items: center; justify-content: space-between;
  padding: 28px clamp(28px, 4vw, 56px);
  pointer-events: none;
}
/* Centre the rail-group absolutely against the viewport so its position
   is independent of the brand/lang group widths on either side. */
.topbar > .top-rail-group {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}
.topbar.topbar--solid {
  background: transparent;
  border-bottom: none;
  /* On subpages an `.overlay` (z-index 80) is mounted underneath as a
     momentum-scrolling layer. The base topbar is `pointer-events: none` (so
     its empty areas pass taps/scroll through to Home), with only its children
     re-enabled — but iOS Safari mis-hit-tests a `pointer-events: none`,
     z-indexed fixed parent whose `auto` children sit over a scroll layer, so
     the hamburger stops responding until the overlay is closed. The topbar is
     opaque here with nothing interactive behind it, so just make the whole bar
     a normal interactive layer above the overlay — no pass-through needed. */
  pointer-events: auto;
}
.topbar.topbar--solid::before {
  content: '';
  position: absolute; inset: 0;
  background-color: var(--ink);
  background-image:
    radial-gradient(ellipse at 30% 20%, rgba(255,255,255,.025), transparent 55%),
    radial-gradient(ellipse at 80% 90%, rgba(255,255,255,.015), transparent 60%),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1  0 0 0 0 1  0 0 0 0 1  0 0 0 0.04 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
  background-size: auto, auto, 180px 180px;
  border-bottom: 1px solid rgba(255,255,255,.06);
  transform-origin: top;
  animation: topbar-roll .55s cubic-bezier(.2,.8,.2,1) both;
  z-index: -1;
}
@keyframes topbar-roll {
  from { transform: scaleY(0); }
  to   { transform: scaleY(1); }
}
@keyframes topbar-unroll {
  from { transform: scaleY(1); }
  to   { transform: scaleY(0); }
}
.topbar.topbar--closing::before {
  animation: topbar-unroll .35s cubic-bezier(.4,.2,.4,1) forwards;
}
.topbar > * { pointer-events: auto; }
.brand {
  font-family: var(--serif); font-size: 22px; letter-spacing: -.01em;
  display: flex; align-items: center; gap: 8px; color: var(--paper);
  /* Nudge the mark a touch closer to the viewport edge — the topbar's
     padding leaves the logo a little inset; this pulls it back left. */
  margin-left: -44px;
}
.brand-mark {
  display: inline-block;
  /* Logo aspect is ~3.06:1 (IMAGINE wordmark + "since 2004" subline). */
  width: 260px; height: 85px;
  background: var(--paper);
  -webkit-mask: url(brand/imagine-logo-white.png) left center / contain no-repeat;
          mask: url(brand/imagine-logo-white.png) left center / contain no-repeat;
  transition: background .25s ease;
}
@media (hover: hover) and (pointer: fine) {
  .brand:hover .brand-mark { background: #FF2233; }
}
.brand .dot-mark {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--paper); display: inline-block; transform: translateY(-2px);
}
.sentence {
  display: flex; align-items: center; gap: 22px;
  font-family: var(--serif); font-size: clamp(15px, 1.3vw, 19px);
  color: var(--paper);
}
.sentence button {
  position: relative; padding: 4px 0; opacity: .55;
  transition: opacity .35s;
  font-family: inherit; font-size: inherit; color: inherit;
}
.sentence button { transition: opacity .35s, color .25s; }
.sentence button:hover, .sentence button.is-active { opacity: 1; }
.sentence button:hover { color: #FF2233; }
.sentence button.is-active::after {
  content:''; position: absolute; left: 0; right: 0; bottom: -2px;
  height: 1px; background: currentColor;
}
.sentence .sep { opacity: .25; }

/* dot-rail nav living inside the topbar (replaces the floating bottom rail) */
.top-rail {
  display: flex; align-items: center; gap: 4px;
}
.top-rail button {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 14px; border-radius: 999px;
  font-family: var(--serif); font-style: normal;
  font-size: clamp(13px, 1vw, 15px);
  color: var(--paper); opacity: .55;
  transition: opacity .35s, background .35s;
}
.top-rail .dot {
  width: 5px; height: 5px; border-radius: 50%;
  background: currentColor;
}
.top-rail .lbl { white-space: nowrap; }
.top-rail button:hover { opacity: .9; }
.top-rail button.is-active {
  opacity: 1;
  color: #d4351c;
  background: rgba(244,239,233,.10);
}

/* ── Mobile: hamburger + drawer ───────────────────────────── */
.top-right { display: flex; align-items: center; gap: 12px; pointer-events: auto; }
.top-burger {
  display: none;
  width: 44px; height: 44px;
  align-items: center; justify-content: center;
  flex-direction: column; gap: 4px;
  background: transparent; border: 0; cursor: pointer;
  padding: 0;
}
.top-burger span {
  display: block;
  width: 22px; height: 1.5px;
  background: var(--paper);
  transition: transform .3s cubic-bezier(.2,.8,.2,1), opacity .2s ease;
}
.top-burger.is-open span:nth-child(1) { transform: translateY(5.5px) rotate(45deg); }
.top-burger.is-open span:nth-child(2) { opacity: 0; }
.top-burger.is-open span:nth-child(3) { transform: translateY(-5.5px) rotate(-45deg); }

.top-drawer {
  /* z-index 120 so it overlays both .case-layer (105) and .topbar (110).
     Tapping outside the nav (the backdrop) closes the drawer. */
  position: fixed; inset: 0; z-index: 120;
  background: var(--ink);
  display: flex; align-items: center; justify-content: center;
  opacity: 0; pointer-events: none;
  transform: translateY(-100%);
  transition: opacity .3s ease, transform .45s cubic-bezier(.2,.8,.2,1);
}
.top-drawer.is-open {
  opacity: 1; pointer-events: auto;
  transform: translateY(0);
}
.top-drawer-nav {
  display: flex; flex-direction: column; gap: 32px;
  text-align: center;
}
.top-drawer-item {
  background: transparent; border: 0; cursor: pointer;
  color: var(--paper);
  font-family: var(--serif); font-style: italic;
  /* Dynamic via clamp(): min sized so the longest label ("ahogy valóra
     váltjuk") fits on one line even at iPhone-SE width (~270px of
     available label space inside the flex row); preferred multiplier
     scales the font up smoothly on wider phones; max keeps the desktop
     drawer in its original 56px range. Iphone SE ~28px, Pixel 10 ~29px,
     wide phone ~35–42px, tablet+ ~56px. No wrapping, no auto-hyphenation. */
  font-size: clamp(28px, 7vw, 56px);
  display: flex; align-items: baseline; justify-content: center; gap: 18px;
  padding: 14px 24px;
  transition: color .25s ease;
  white-space: nowrap;
  hyphens: none;
  -webkit-hyphens: none;
}
.top-drawer-item .num {
  font-family: var(--sans); font-style: normal;
  font-size: 11px; letter-spacing: .22em;
  color: var(--paper-soft);
  text-transform: uppercase;
}
.top-drawer-item.is-active { color: var(--paper); }
.top-drawer-item.is-active .num { color: #FF2233; }
/* Brand mark pinned to the drawer's top-left while the drawer is open.
   Same mask trick as .brand-mark in the topbar — sized to match the mobile
   topbar logo so it reads as the same element behind the open drawer. */
.top-drawer-brand {
  /* Topbar's brand is wrapped in a native <button>, which adds a few px of
     vertical user-agent padding that nudges the visible mark down slightly.
     Adding ~4px to the top + a hair of extra height lines this drawer mark
     up with the topbar mark sitting behind it. */
  position: absolute;
  top: 18px; left: -42px;
  display: inline-block;
  width: 270px; height: 88px;
  background: var(--paper);
  -webkit-mask: url(brand/imagine-logo-white.png) left center / contain no-repeat;
          mask: url(brand/imagine-logo-white.png) left center / contain no-repeat;
  pointer-events: none;
}
/* Mail + phone icons pinned to the drawer's bottom-left, mirroring the
   place mark on the bottom-right. Each icon links via mailto: / tel:. */
.top-drawer-contact {
  position: absolute;
  bottom: 20px; left: clamp(16px, 4vw, 24px);
  display: flex; gap: 14px;
  pointer-events: auto;
}
.top-drawer-contact a {
  display: grid; place-items: center;
  width: 36px; height: 36px;
  border: 1px solid var(--rule);
  border-radius: 50%;
  color: var(--paper);
  background: transparent;
  transition: background .25s, color .25s, border-color .25s;
}
.top-drawer-contact a svg { width: 16px; height: 16px; display: block; }
.top-drawer-contact a:hover { background: rgba(244,239,233,.12); }
@media (hover: none) and (pointer: coarse) {
  .top-drawer-contact a:active { background: rgba(244,239,233,.12); }
}

/* Footer-style place mark pinned to the drawer's bottom-right. Matched to the
   contact icon's box (same bottom + 36px height, text vertically centred) so
   "Budapest 2026" lines up with the middle of the mail icon on the left. */
.top-drawer-place {
  position: absolute;
  bottom: 20px; right: var(--shell);
  height: 36px;
  display: flex; align-items: center;
  font-size: 11px; letter-spacing: .22em; text-transform: uppercase;
  color: var(--paper-soft);
  pointer-events: none;
}
/* Close X pinned to the drawer's top-right, mirroring the brand mark on the
   left. Tapping it closes the drawer (same as tapping the backdrop). Red
   circular fill so it reads as the primary action. */
.top-drawer-close {
  position: absolute;
  top: 14px; right: clamp(12px, 4vw, 20px);
  width: 40px; height: 40px;
  display: grid; place-items: center;
  border: 1px solid var(--rule);
  border-radius: 50%;
  background: rgba(10,10,10,.65);
  backdrop-filter: blur(8px);
  color: var(--paper);
  cursor: pointer;
  transition: background .25s, transform .35s cubic-bezier(.2,.8,.2,1);
}
.top-drawer-close svg { width: 14px; height: 14px; display: block; }
.top-drawer-close:hover { background: rgba(244,239,233,.12); transform: rotate(90deg); }

/* Mobile rail/burger toggle lives near end-of-file so it wins
   the cascade against the later `.top-rail-group { display: flex }` base rule. */

/* ── Opening splash ─────────────────────────────────────── */
.splash {
  position: fixed; inset: 0; z-index: 200;
  background: var(--ink);
  display: grid; place-items: center;
  transition: transform .9s cubic-bezier(.2,.8,.2,1), opacity .6s ease;
  transform: translateY(-100%);
  opacity: 0;
  pointer-events: none;
}
.splash.is-active {
  transform: translateY(0);
  opacity: 1;
  pointer-events: auto;
  cursor: pointer;
}
.splash-logo {
  display: block;
  /* Aspect ~3.06:1 — keep height proportional to width across the clamp range
     so the new wordmark + "since 2004" subline stay legible at every size. */
  width: clamp(360px, 50vw, 560px);
  height: clamp(118px, 16.3vw, 183px);
  /* Liquid-fill: the gradient's two stops sit at the same point (--fill),
     producing a hard horizontal line that rises from bottom (red below) to
     top (paper above) as --fill animates 0% → 100%. */
  background: linear-gradient(to top, #FF2233 var(--fill, 0%), var(--paper) var(--fill, 0%));
  -webkit-mask: url(brand/imagine-logo-white.png) center / contain no-repeat;
          mask: url(brand/imagine-logo-white.png) center / contain no-repeat;
  animation: splashLogoIn 1.8s cubic-bezier(.2,.8,.2,1) both;
  transition: --fill .6s cubic-bezier(.4,0,.2,1);
}
.splash.is-leaving .splash-logo {
  --fill: 100%;
  animation: splashLogoOut .9s cubic-bezier(.2,.8,.2,1) .65s both;
}
.splash.is-leaving .splash-hint {
  animation: splashHintOut .9s cubic-bezier(.2,.8,.2,1) .65s both;
}
.splash.is-leaving .splash-arrow { animation: none; }
@keyframes splashLogoIn {
  0%   { opacity: 0; transform: scale(.92) translateY(28px); filter: blur(6px); }
  55%  { opacity: 1; filter: blur(0); }
  100% { opacity: 1; transform: scale(1) translateY(0); filter: blur(0); }
}
@keyframes splashLogoOut {
  0%   { transform: translateY(0); }
  100% { transform: translateY(-72px); }
}
@keyframes splashHintOut {
  0%   { transform: translateY(0); }
  100% { transform: translateY(-44px); }
}
.splash-hint {
  position: absolute; bottom: 8vh;
  display: inline-flex; align-items: baseline; gap: 14px;
  font-family: var(--serif); font-style: italic;
  color: var(--paper-soft);
  font-size: 18px; letter-spacing: .02em;
  opacity: 0;
  animation: splashHintIn .45s ease .35s forwards;
  border: 0; background: transparent; cursor: pointer; padding: 8px 12px;
}
.splash-hint:hover { color: var(--paper); }
.splash-arrow {
  display: inline-block;
  animation: splashArrow 1.6s ease-in-out 1s infinite;
}
@keyframes splashHintIn { to { opacity: 1; } }
@keyframes splashArrow {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(8px); }
}

/* topbar edge arrows — flank the rail */
.top-rail-group {
  display: flex; align-items: center; gap: 14px;
}
.top-arrow {
  width: 44px; height: 28px;
  display: grid; place-items: center;
  color: var(--paper);
  border: none; background: transparent;
  opacity: .45;
  transition: opacity .25s, transform .35s cubic-bezier(.2,.8,.2,1);
  font-family: var(--serif); font-style: normal;
  font-size: 16px; line-height: 1; font-weight: 400;
  cursor: pointer;
}
.top-arrow span { display: block; }
.top-arrow svg { width: 36px; height: 12px; display: block; overflow: visible; }
.top-arrow--prev svg { transform: scaleX(-1); }
.top-arrow:not(:disabled):hover { opacity: 1; }
.top-rail-group:has(.top-arrow:first-child:not(:disabled):hover) .top-arrow:first-child { transform: translateX(-3px); }
.top-rail-group:has(.top-arrow:last-child:not(:disabled):hover) .top-arrow:last-child { transform: translateX(3px); }
.top-arrow:disabled { opacity: .18; cursor: default; transform: translateX(0) !important; }
/* Idle affordance: the two rail arrows continuously nudge outward and back,
   hinting they're clickable. Both animations are applied at mount and NEVER
   gated on :disabled, so they start together and stay perfectly in phase — on
   the middle 'work' panel (both enabled) prev/next mirror exactly. A disabled
   arrow (first/last panel) keeps its animation running but is pinned to centre
   via the !important above, so it doesn't visibly move yet stays in sync for
   when it's re-enabled (no restart = no drift). Reduced-motion users get none. */
@keyframes topArrowNudgePrev { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(-6px); } }
@keyframes topArrowNudgeNext { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(6px); } }
.top-arrow--prev { animation: topArrowNudgePrev 1.9s ease-in-out infinite; }
.top-arrow--next { animation: topArrowNudgeNext 1.9s ease-in-out infinite; }

.lang {
  display: flex; gap: 2px; font-size: 11px; letter-spacing: .2em;
  text-transform: uppercase; color: var(--paper);
}
.lang button { padding: 4px 6px; opacity: .45; color: inherit; }
.lang button.is-active { opacity: 1; }
.lang .pipe { opacity: .25; }

/* ── HOME — 3 horizontal panels (carusi pattern) ────────────── */
.home-h {
  position: fixed; inset: 0;
  overflow: hidden;
  background: #000;
}
.h-track {
  display: flex;
  /* `dvh` (dynamic viewport height) tracks the actual visible area on
     mobile — when Chrome's URL bar is shown/hidden, dvh shrinks/grows,
     so the panel content never gets clipped behind the URL bar.
     Falls back to vh on browsers without dvh support. */
  width: 100%; height: 100vh; height: 100dvh;
  overflow-x: auto; overflow-y: hidden;
  scroll-snap-type: none;
  scroll-behavior: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.h-track::-webkit-scrollbar { display: none; }
.h-panel {
  flex: 0 0 100vw;
  height: 100vh;
  height: 100dvh;
  position: relative;
  scroll-snap-align: start;
  scroll-snap-stop: always;
  overflow: hidden;
  background: #000;
}
.h-panel-inner {
  position: relative; z-index: 2;
  height: 100%;
  /* `auto 1fr auto auto` rows: h-center is content-sized (just title+line),
     h-teaser takes the 1fr stretch so its body floats to the visual midpoint
     between the line and the CTA regardless of viewport height. Marquee and
     CTA stay in their own auto rows below. */
  display: grid; grid-template-rows: auto 1fr auto auto;
  padding: 110px clamp(40px, 6vw, 96px) 80px;
  max-width: 1480px; margin: 0 auto;
}
/* align-self: start so the title is anchored to a fixed offset from the
   top of the grid row — otherwise centering would put the title at a
   different y on each panel because the teaser body lengths differ
   between panels (centered = (row - content) / 2, and content height
   varies). Padding-top here lands the title in the same place as the
   about panel's previous centred position with translateY(-6vh). */
.h-center {
  align-self: start;
  width: 100%;
  padding-top: clamp(0px, calc(18vh - 150px), 30px);
  transform: none;
  /* Flex column so the title and line stack with consistent alignment.
     h-teaser is now a SIBLING of .h-center (in its own 1fr grid row),
     so .h-center is purely the title-block container. */
  display: flex;
  flex-direction: column;
  /* Pin children to the left by default. `.opener-creed` carries
     `align-self: center` which would otherwise centre the <h1> horizontally
     as a flex item; explicit override below restores the left-edge align. */
  align-items: flex-start;
}
.h-center .h-word,
.h-center .opener-creed,
.h-center .h-line { align-self: flex-start; }
@keyframes hPagerNudgeR { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(5px); } }
@keyframes hPagerNudgeL { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(-5px); } }
@media (prefers-reduced-motion: reduce) {
  .h-pager-arrow--left, .h-pager-arrow--right { animation: none !important; }
}
.h-word {
  font-size: clamp(56px, 9vw, 160px);
  line-height: .92;
  letter-spacing: -.025em;
  margin: 0;
  /* Keep titles on a single line regardless of font-load state — otherwise
     "Ahogy valóra váltjuk…" wraps when Cormorant Garamond swaps in (its
     italic glyphs are wider than the fallback). */
  white-space: nowrap;
}
.h-word { transition: color .3s ease; color: var(--paper); }
.h-word em { font-style: italic; color: var(--paper); opacity: .92; transition: color .3s ease; }
.h-word:hover,
.h-word:hover em,
.h-center:hover .h-word,
.h-center:hover .h-word em,
.h-panel-inner:has(.h-teaser:hover) .h-word,
.h-panel-inner:has(.h-teaser:hover) .h-word em { color: #FF2233; }
/* On touch devices the hover state never fires — show the title in the
   activated red by default so it reads as the panel's accent the way it
   does on desktop when the user lands on the panel. */
@media (hover: none) and (pointer: coarse) {
  .h-word, .h-word em { color: #FF2233; }
}
.h-line {
  font-family: var(--serif); font-style: italic;
  font-size: clamp(20px, 1.8vw, 28px);
  color: var(--paper-soft);
  max-width: 30ch;
  margin: 24px 0 0;
  text-shadow: 0 2px 30px rgba(0,0,0,.4);
}

/* mini-about teaser shown under the headline. Now a top-level grid item
   in the 1fr row of .h-panel-inner — the row stretches between title
   block and marquee, and the body inside is centred via `justify-content:
   center`. This makes the body's position scale uniformly with the viewport
   (always at the visual midpoint of line and CTA) without per-viewport
   tuning. The divider rule (::before) is pinned to the top of this box. */
.h-teaser {
  margin: 40px auto 0;
  max-width: 820px;
  padding-top: 12px;
  text-align: center;
  position: relative;
  display: flex;
  flex-direction: column;
  /* Pin body to top of its 1fr row so the body's TOP is at the same Y on
     every panel. Centring inside the row puts the body MIDPOINT at the same
     Y, but each panel has a different-length copy so the top edge drifts —
     about's long body lands close to the divider, work's short body floats
     low. flex-start anchors the top edge instead so all three panels start
     reading at the same line. */
  justify-content: flex-start;
}
/* Dedicated divider — rendered INSIDE .h-center as the last child, right
   under the title. Margin-top is measured from the .h-word baseline so
   the line's Y is consistent across all three panels regardless of how
   much room the teaser/marquee/CTA below take. */
.h-divider {
  align-self: stretch;
  height: 1px;
  background: rgba(244,239,233,.18);
  margin-top: 28px;
  width: 100%;
  transform: scaleX(0);
  transform-origin: center;
  transition: transform .9s cubic-bezier(.2,.8,.2,1);
  position: relative;
}
/* Invisible hit area extending ~16px above and below the visible 1px line
   so hovering anywhere near the divider triggers the title-red effect via
   `.h-center:hover .h-word` (the divider lives inside .h-center). Without
   this, the 1px target is essentially impossible to land on with a mouse. */
.h-divider::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: -16px;
  bottom: -16px;
}
.h-panel.is-active .h-divider {
  transform: scaleX(1);
  transition-delay: 0s;
}

/* Parallax X — `--px` from the mouse handler, `--scroll-x` from the scroll
   handler (per-layer rate). They compose via calc so neither overrides the
   other. `--scroll-x` is 0 when the panel is snapped, so all three layers
   land in their natural position at rest. */
.h-shift,
.h-teaser-body,
.h-discover {
  transform: translate3d(calc(var(--px, 0px) + var(--scroll-x, 0px)), 0, 0);
  will-change: transform;
  /* No transition: the JS-driven --scroll-x already follows the goto scroll
     easing in real time, and a transform transition just lagged behind the
     scroll, producing a noticeable "stuck then snap" on topbar nav. */
}
/* Desktop teaser body is the full paragraph; mobile gets a shorter variant
   (see h-teaser-body--mobile). Both are rendered in the DOM so the text
   for the active viewport is always immediately available; the other is
   display:none-d in CSS. */
.h-teaser-body--desktop { display: block; }
.h-teaser-body--mobile  { display: none; }
@media (max-width: 600px) {
  .h-teaser-body--desktop { display: none; }
  .h-teaser-body--mobile  { display: block; }
}
.h-teaser-body {
  font-family: var(--serif);
  font-size: clamp(20px, 1.7vw, 26px);
  line-height: 1.45;
  color: var(--paper);
  /* Centring is now handled by .h-teaser's `justify-content: center` in its
     own 1fr grid row — no per-element auto margins needed here. */
  margin: 0;
  text-shadow: 0 2px 30px rgba(0,0,0,.4);
  text-wrap: pretty;
}
.h-discover {
  justify-self: center; align-self: end;
  display: inline-flex; align-items: baseline; gap: 16px;
  font-family: var(--serif); font-style: italic;
  font-size: clamp(18px, 1.6vw, 24px);
  color: var(--paper);
  padding: 10px 0 12px;
  transition: gap .3s, color .3s;
  text-align: left;
  line-height: 1;
  position: relative;
}
/* Animated underline that scales out from the centre, fired after the
   long-text reveal so the CTA's line is the last element to draw in. */
.h-discover::after {
  content: '';
  position: absolute;
  /* Slight right overhang so the line reaches the arrow's tip (the
     diamond head extends a few px past the SVG's right edge after
     overflow: visible). */
  left: 0; right: -10px; bottom: 0;
  height: 2px;
  background: rgba(244,239,233,.5);
  transform: scaleX(0);
  transform-origin: center;
  transition: transform .9s cubic-bezier(.2,.8,.2,1), background-color .3s ease, height .1s ease-out, bottom .1s ease-out;
}
.h-panel.is-active .h-discover::after {
  transform: scaleX(1);
  /* Delay only the reveal-transform so the hover-thickening on height/bottom
     isn't held back too. */
  transition-delay: .15s, 0s, 0s, 0s;
}
/* Hover styles gated to true pointer devices — on touchscreens, :hover sticks
   after a tap and the CTA appears permanently "activated" until the user
   taps elsewhere. */
@media (hover: hover) and (pointer: fine) {
  .h-discover:hover { gap: 22px; color: #FF2233; }
  /* Drop the bottom edge by the height gain so the line grows downward only —
     top stays anchored at its rest position. */
  .h-discover:hover::after { background-color: var(--paper); height: 5px; bottom: -3px; }
  .h-discover:hover .arr-down { transform: translate(4px, 2px); }
}
/* On touch devices there's no hover, so show the "activated" look by default
   so the CTA reads as tappable rather than dormant. */
@media (hover: none) and (pointer: coarse) {
  .h-discover { gap: 22px; color: #FF2233; font-weight: 700; }
  .h-discover::after { background-color: var(--paper); height: 5px; bottom: -3px; }
  .h-discover .arr-down { transform: translate(4px, 2px); }
}
.h-discover .arr-down {
  /* .h-discover is display:inline-flex with align-items:baseline, so
     vertical-align is ignored on this child. align-self centres the
     arrow against the text's vertical mid-line. */
  align-self: center;
  display: inline-block;
  transform: translateY(2px);
  transition: transform .3s;
}
.h-discover .arr-down svg {
  width: 1.1em; height: .9em;
  display: block;
  overflow: visible;
}

/* Default-hide the home-panel pager hint; only the mobile @media block
   below switches it on. */
.h-pager-hint { display: none; }


.h-hint {
  position: fixed; right: clamp(28px, 4vw, 56px); top: 50%;
  transform: translateY(-50%) rotate(90deg); transform-origin: right center;
  z-index: 30;
  font-size: 11px; letter-spacing: .26em; text-transform: uppercase;
  color: var(--paper); opacity: .55; white-space: nowrap;
  display: flex; align-items: center; gap: 14px;
  pointer-events: none;
}
.h-hint .ln { width: 28px; height: 1px; background: currentColor; display: inline-block; }

/* Overlay container — slide up from bottom over Home */
/* `.privacy-layer` shares the overlay's look + slide-up animation but sits at
   a higher z-index so it layers OVER the contact overlay (z 80) / case layer
   (z 105), like the case detail layers over Work. */
.overlay, .privacy-layer {
  position: fixed; inset: 0; z-index: 80;
  background: var(--ink);
  overflow-y: auto; overflow-x: hidden;
  animation: slideUp .55s cubic-bezier(.2,.8,.2,1) both;
  /* matte texture re-applied (fixed bg doesn't carry through) */
  background-image:
    radial-gradient(ellipse at 30% 20%, rgba(255,255,255,.025), transparent 55%),
    radial-gradient(ellipse at 80% 90%, rgba(255,255,255,.015), transparent 60%),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1  0 0 0 0 1  0 0 0 0 1  0 0 0 0.04 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
  background-size: auto, auto, 180px 180px;
}
@keyframes slideUp { from { transform: translateY(100%); } to { transform: none; } }
@keyframes slideDown { from { transform: none; } to { transform: translateY(100%); } }
/* Privacy layer rides above the overlay/case layers (z 80 / 105) but stays
   below the topbar (z 110), matching the case-detail layering. */
.privacy-layer { z-index: 106; }
/* Close mirrors the open: same duration, reversed easing curve
   (cubic-bezier(.8,0,.8,.2) is the inverse of (.2,.8,.2,1)) so the
   panel pulls down the same way it pulled up. */
.overlay.is-closing,
.privacy-layer.is-closing { animation: slideDown .55s cubic-bezier(.8,0,.8,.2) forwards; }

/* Case detail sits as its own layered overlay above the Work overlay so
   opening and closing match the subpage feel: slide up on mount, slide
   down on close revealing the case-study list underneath. */
.case-layer {
  position: fixed; inset: 0;
  z-index: 105;
  overflow-x: hidden;
  overflow-y: auto;
  background: var(--ink);
  animation: slideUp .4s cubic-bezier(.2,.8,.2,1);
}
.case-layer.is-closing { animation: slideDown .4s cubic-bezier(.8,0,.8,.2) forwards; }

/* During close: kill pointer events so :hover can't toggle mid-slide
   (cursor staying put while content translates would otherwise trip hover
   on/off and start the long filter/transform tweens on .case-row imagery,
   making the first row's image visibly desaturate/scale during the slide).
   JS at close-start also snapshots computed transform/filter on hover-
   sensitive imagery as inline styles, which override any rule changes
   triggered by the hover drop. */
.overlay.is-closing,
.case-layer.is-closing,
.privacy-layer.is-closing { pointer-events: none; }
.overlay-close {
  /* Lined up with the eyebrow row on each subpage (their hero containers
     all use padding-top: 160px), so the X sits on the same horizontal line
     as "Történetünk" / "Esettanulmányok" / "Együtt" instead of crowding the
     topbar (the desktop topbar is ~141px tall). Mobile keeps its own
     override below. */
  position: fixed; top: 160px; right: clamp(28px, 4vw, 56px);
  z-index: 130;
  width: 48px; height: 48px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: rgba(10,10,10,.65);
  border: 1px solid var(--rule);
  color: var(--paper);
  backdrop-filter: blur(8px);
  cursor: pointer;
  transition: background .25s, transform .35s cubic-bezier(.2,.8,.2,1);
  /* Ride up with the overlay on open, ride back down with it on close. Same
     duration + easing as .overlay so the button never lags or anticipates. */
  animation: overlayCloseUp .55s cubic-bezier(.2,.8,.2,1) both;
}
.overlay-close.is-closing {
  animation: overlayCloseDown .55s cubic-bezier(.8,0,.8,.2) forwards;
}
@keyframes overlayCloseUp {
  from { transform: translateY(120vh); }
  to   { transform: none; }
}
@keyframes overlayCloseDown {
  from { transform: none; }
  to   { transform: translateY(120vh); }
}
.overlay-close svg { width: 18px; height: 18px; display: block; }
.overlay-close:hover { background: rgba(244,239,233,.12); transform: rotate(90deg); }
/* Hide the subpage close X while the mobile drawer is open — otherwise the
   drawer's own close X (.top-drawer-close at z-index 120) and the overlay
   close (z-index 130) stack visibly on top of each other. */
body:has(.top-drawer.is-open) .overlay-close { display: none; }
/* Mobile: move the close button out of the top-right corner (where it
   collides with the burger) and align it on the same row as each subpage's
   eyebrow (e.g. "Történetünk"), but on the right side. */
@media (max-width: 600px) {
  .overlay-close {
    top: 84px;
    right: clamp(16px, 4vw, 24px);
    width: 40px; height: 40px;
  }
  .overlay-close svg { width: 16px; height: 16px; }
}
/* ── HOME — fullscreen B&W hero (legacy, kept for case detail bg) ── */
.opener {
  position: relative;
  min-height: 100vh;
  overflow: hidden;
  background: #000;
}
.opener-bg {
  position: absolute; inset: 0;
  background-size: cover; background-position: center;
  /* Inactive resting state — slight zoom (1.02), grayscale, dimmed. */
  filter: grayscale(1) contrast(1.05) brightness(.55);
  transform: scale(1.02);
  /* Mount fade-in only; no `both` fill so the transform isn't pinned by the
     animation after it ends and the .is-active transition can take over. */
  animation: heroIn 2.2s cubic-bezier(.2,.8,.2,1);
  /* Transition between inactive and active states so the panel never jumps
     — transform and filter tween from their current value to the target. */
  transition: transform 12s ease-out, filter 2.4s ease-in .4s;
}
.h-panel.is-active .opener-bg {
  filter: grayscale(0) contrast(1.02) brightness(.78);
  transform: scale(1.12);
}
/* Opacity-only fade-in. (Previously this animation also went scale(1.08)
   → scale(1.02), which fought the .is-active transition to scale(1.12)
   when the user dismissed the splash mid-animation — looking like a
   zoom direction reversal. Keeping it pure opacity lets the active-state
   transition run cleanly from 1.02 → 1.12.) */
@keyframes heroIn { from { opacity: 0; } to { opacity: 1; } }
.opener-veil {
  position: absolute; inset: 0;
  background:
    /* horizontal edge fade — each panel fades fully to black at its
       left and right edges so the picture blends seamlessly into the
       black gap during overscroll (no visible hard edge). */
    linear-gradient(90deg, rgba(0,0,0,1) 0%, rgba(0,0,0,.6) 6%, transparent 18%, transparent 82%, rgba(0,0,0,.6) 94%, rgba(0,0,0,1) 100%),
    linear-gradient(180deg, rgba(0,0,0,.55) 0%, rgba(0,0,0,.15) 30%, rgba(0,0,0,.45) 100%),
    radial-gradient(ellipse at 30% 60%, rgba(0,0,0,.45), transparent 60%);
}

/* Overscroll bleed — the `.h-track` has overflow-x:auto so it clips any
   bleed that would extend past the scroll boundary. Instead we render
   `.h-edge` siblings of the track, positioned to overlap the boundary
   panel (same image, same bg-size, scaled to match active state). They
   sit on top of the panel and during overscroll translate + scaleX
   outward, so the user sees the boundary panel's own image stretching.
   Opacity ramps with --over-frac (0→1 over the elastic range) for a
   soft fade. */
/* Overscroll bleed — solid black with a soft fade. Sits behind the
   track so the panel's text/CTA stay on top. As the track translates,
   a black wedge appears in the gap; opacity ramps with --over-frac. */
.home-h { --over-frac: 0; }
.h-edge {
  position: absolute;
  top: 0; bottom: 0;
  width: 50vw;
  pointer-events: none;
  z-index: 0;
  opacity: 0;
  will-change: opacity;
}
.h-edge--start {
  left: 0;
  /* fade from solid black at the outer edge to transparent toward the panel */
  background: linear-gradient(to right, #000 0%, transparent 100%);
  opacity: max(0, calc(-1 * var(--over-frac)));
}
.h-edge--end {
  right: 0;
  background: linear-gradient(to left, #000 0%, transparent 100%);
  opacity: max(0, var(--over-frac));
}
.h-track { position: relative; z-index: 1; }
.opener-words {
  position: relative; z-index: 2;
  min-height: 100vh;
  display: grid; grid-template-rows: auto 1fr auto;
  padding: 110px clamp(40px, 6vw, 96px) 48px;
}
.opener-eyebrow {
  font-size: 11px; letter-spacing: .26em; text-transform: uppercase;
  color: var(--paper);
  display: flex; align-items: center; gap: 14px;
  opacity: .9;
}
.opener-eyebrow .ln { width: 56px; height: 1px; background: var(--paper); display:inline-block; }
.opener-creed {
  align-self: center;
  font-family: var(--display); font-weight: var(--display-weight, 400);
  font-size: clamp(40px, 6.6vw, 110px); line-height: 1; letter-spacing: -.02em;
  max-width: 16ch;
  color: var(--paper);
  text-shadow: 0 2px 30px rgba(0,0,0,.35);
}
.opener-creed em { font-style: italic; color: var(--paper); opacity: .82; }
/* Touch-device default: hero titles read in the activated red, mirroring the
   .h-word rule above (.opener-creed shares the same element, so its later
   color: var(--paper) would otherwise win on the cascade). */
@media (hover: none) and (pointer: coarse) {
  .opener-creed, .opener-creed em { color: #FF2233; }
}
@keyframes rise { from { opacity: 0; transform: translateY(28px); } to { opacity: 1; transform: none; } }

.opener-bottom {
  display: flex; justify-content: space-between; align-items: end;
  font-size: 11px; letter-spacing: .22em; text-transform: uppercase;
  color: var(--paper); opacity: .85;
  gap: 24px;
}
.scroll-cue {
  display: flex; align-items: center; gap: 14px; cursor: pointer;
  font-family: var(--serif); font-style: italic; font-size: 18px;
  letter-spacing: 0; text-transform: none; color: var(--paper); opacity: 1;
}
.scroll-cue .arr { width: 32px; height: 1px; background: currentColor; position: relative; }
.scroll-cue .arr::after { content:''; position:absolute; right:0; top:-3px; width:7px; height:7px; border-right:1px solid currentColor; border-bottom:1px solid currentColor; transform: rotate(-45deg); animation: down 1.6s ease-in-out infinite; }
@keyframes down { 0%,100% { transform: rotate(-45deg) translateY(0); } 50% { transform: rotate(-45deg) translateY(4px); } }

/* Hero rotator dots in lower-right (carusi-style) */
.opener-rotator {
  position: absolute; right: clamp(28px, 4vw, 56px); bottom: 48px; z-index: 3;
  display: flex; flex-direction: column; gap: 10px; align-items: center;
}
.opener-rotator button {
  width: 8px; height: 8px; border-radius: 50%;
  background: rgba(244,239,233,.35);
  transition: background .4s, transform .4s;
}
.opener-rotator button.is-active { background: var(--paper); transform: scale(1.4); }

/* Vertical service tag in upper-right (carusi-style) */
.opener-vtag {
  position: absolute; right: clamp(28px, 4vw, 56px); top: 50%;
  transform: translateY(-50%) rotate(90deg); transform-origin: right center;
  z-index: 3;
  font-size: 11px; letter-spacing: .28em; text-transform: uppercase;
  color: var(--paper); opacity: .8; white-space: nowrap;
  cursor: pointer;
}
.opener-vtag::before { content: ''; display: inline-block; width: 24px; height: 1px; background: currentColor; vertical-align: middle; margin-right: 14px; }

/* The banner sentence revealed on scroll — carusi shifts to a quiet panel */
.banner {
  padding: 140px var(--shell) 120px;
  border-bottom: 1px solid var(--rule);
  text-align: left; max-width: var(--maxw); margin: 0 auto;
}
.banner .eyebrow { display: flex; align-items: center; margin-bottom: 36px; }
.banner .line { display: block; font-family: var(--serif); font-size: clamp(40px, 7vw, 110px); line-height: 1.02; letter-spacing: -.02em; max-width: 16ch; }
.banner .line em { font-style: italic; color: var(--paper-soft); }
.banner .line + .line { margin-top: 6px; }

/* ── Scenes — half-screen sticky split ──────────────────────── */
.scene {
  position: relative; min-height: 100vh;
  display: grid; grid-template-columns: 1fr 1fr;
  border-bottom: 1px solid var(--rule);
}
.scene:nth-child(even) { grid-template-columns: 1fr 1fr; direction: rtl; }
.scene:nth-child(even) > * { direction: ltr; }

.scene-img {
  position: relative; overflow: hidden;
  background: #000;
}
.scene-img .img {
  position: absolute; inset: 0; background-size: cover; background-position: center;
  filter: grayscale(1) contrast(1.05) brightness(.92);
  transition: filter 1.6s, transform 12s ease-out;
  transform: scale(1.04);
}
.scene:hover .scene-img .img,
.scene.is-in .scene-img .img { transform: scale(1); }
.scene-img .tag {
  position: absolute; left: 24px; bottom: 22px;
  font-family: var(--sans); font-size: 10px; letter-spacing: .24em;
  text-transform: uppercase; color: rgba(244,239,233,.8);
}
.scene-img .num {
  position: absolute; right: 24px; top: 22px;
  font-family: var(--serif); font-style: italic; font-size: 24px; color: rgba(244,239,233,.9);
}

.scene-words {
  display: flex; flex-direction: column; justify-content: space-between; gap: 14px;
  padding: 6vw clamp(28px, 5vw, 80px);
  background: var(--ink);
  position: relative;
}
.scene-words .who {
  font-family: var(--display); font-weight: var(--display-weight, 400); font-size: clamp(48px, 6.5vw, 96px);
  line-height: .96; letter-spacing: -.02em;
}
.scene-words .who em { font-style: italic; color: var(--paper-soft); }
.scene-words .where {
  margin-top: 14px;
  font-family: var(--serif); font-style: italic; font-size: clamp(18px, 1.6vw, 24px);
  color: var(--paper-soft);
}
.scene-words .motto {
  margin-top: 38px;
  font-family: var(--serif); font-style: italic; font-size: clamp(18px, 1.5vw, 22px);
  line-height: 1.45; max-width: 32ch; color: var(--paper);
}
.scene-words .meta {
  margin-top: 44px; padding-top: 22px; border-top: 1px solid var(--rule);
  display: flex; justify-content: space-between; gap: 14px;
  font-size: 11px; letter-spacing: .22em; text-transform: uppercase; color: var(--mute);
}
.scene-words .scene-eyebrow {
  font-size: 11px; letter-spacing: .24em; text-transform: uppercase;
  color: var(--paper-soft); margin-bottom: 32px;
  display: flex; align-items: center; gap: 14px;
}
.scene-words .scene-eyebrow .ln { width: 40px; height: 1px; background: var(--paper-soft); }

@media (max-width: 800px) {
  .scene, .scene:nth-child(even) { grid-template-columns: 1fr; min-height: auto; direction: ltr; }
  .scene-img { aspect-ratio: 4/5; }
  .scene-words { padding: 60px var(--shell); }
}

/* ── Képzelet (about) ────────────────────────────────────── */
.about-hero {
  padding: 160px var(--shell) 16px;
  margin-bottom: 0;
  position: relative;
}
/* Section divider drawn under the hero block, anchored to the hero's own
   left/right edges (`var(--shell)`). The first about-section had a
   `border-top` doing the same job, but it lived inside `.about-shell` whose
   1200px max-width made the line shorter than the hero text on wide screens
   ("cut off on the left/right"). This pseudo-element always tracks the hero,
   so the line and the lead text are flush. */
.about-hero::after {
  content: '';
  position: absolute;
  left: var(--shell); right: var(--shell);
  bottom: 0;
  height: 1px;
  background: var(--rule);
}
.about-hero .eyebrow,
.about-lead-shift {
  transform: translate3d(var(--ppx, 0px), 0, 0);
  will-change: transform;
}
.about-lead-shift { display: block; }
.about-shell { padding: 0 var(--shell) 100px; max-width: 1200px; margin: 0 auto; }
.about-creed {
  font-family: var(--display); font-weight: var(--display-weight, 400); font-size: clamp(40px, 6.2vw, 96px);
  line-height: 1.04; letter-spacing: -.022em;
  max-width: none;
  /* `.25em` margin-bottom scales with font-size, so descenders (g, y, p)
     have clearance to render below the line-box without colliding with
     the lead text below. At the max 96px font that's ~24px clearance. */
  margin: 0 0 .25em;
  padding-bottom: .1em;
}
.about-creed em { font-style: italic; color: var(--paper-soft); }
.about-creed .creed-line { display: block; white-space: nowrap; }
.about-lead {
  font-family: var(--serif); font-size: clamp(22px, 1.9vw, 28px);
  line-height: 1.55; color: var(--paper);
  max-width: none; margin: 0;
  text-align: justify; hyphens: auto;
}
.about-lead-old { display: none; }

/* Client-logo marquee — continuous right→left scroll. The track is
   duplicated and translated from 0% to -50% so the loop is seamless.
   On the home hero, it's positioned absolutely so the teaser/title above
   stay centred and aren't pushed sideways by the marquee's wide content. */
.logo-marquee {
  margin: 56px auto 0;
  overflow: hidden;
  width: 100%;
  max-width: 900px;
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, #000 8%, #000 92%, transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0%, #000 8%, #000 92%, transparent 100%);
}
/* On the home hero panel — sits in its own grid row between .h-center
   (the centred title/teaser) and the discover button. `margin: ... auto`
   centres it horizontally within the (wider) panel grid cell. */
.logo-marquee--hero {
  /* Shifted from `0 auto 80px` to `48px auto 32px` so the marquee sits a
     bit further down in its grid row — landing roughly between the bottom
     of the now-centred teaser body and the CTA, instead of flush against
     h-center's edge. Total vertical margin stays the same so the panel
     grid (and the title position) is unchanged. */
  margin: 48px auto 32px;
  align-self: end;
}
.logo-marquee-track {
  display: flex;
  /* NOTE: no `gap` — the gap doesn't apply between the two duplicated
     copies in a way that makes -50% a seamless wrap. Per-item margin
     ensures every item (including the seam) has identical trailing
     space, so translating by exactly -50% lands cleanly. */
  width: max-content;
  align-items: center;
  animation: logoMarquee 77s linear infinite;
}
.logo-item {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  /* Width sizes to the logo's natural aspect at the row height. Fixed
     widths plus object-fit: contain were causing the visual gap to vary
     by logo (narrow logos got more empty box padding around them than
     wide ones). Letting width follow the rendered image makes every gap
     exactly margin-right wide. */
  width: auto;
  height: 38px;
  margin-right: 56px;
  position: relative;
}
/* Logos render as <img> so multi-fill SVGs (BMW, teva) keep their
   interior detail. Two stacked <img>s per logo: the white one is
   always visible at low opacity (rest state); the red one fades in
   on hover. `.is-cursor` is set by a JS handler (in index.html) on
   whichever .logo-item is currently closest to the cursor while it
   sits inside any .logo-marquee — needed because the browser doesn't
   re-evaluate :hover when an animated element moves under a
   stationary cursor. */
.logo-shape {
  display: block;
  width: auto; height: 100%;
  object-fit: contain;
  object-position: center;
}
.logo-shape--white {
  filter: url(#logo-tint-white);
  opacity: .6;
  transition: opacity .9s ease;
}
/* "--red" name is historical — used to be a red tint, now renders the
   logo's native colors on hover so each brand reads in its own palette. */
.logo-shape--red {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  opacity: 0;
  transition: opacity .3s ease;
}
/* `.is-cursor` (set by JS) is the sole trigger — we don't also fire on
   :hover because the browser doesn't reliably update :hover when an
   animated element moves under a stationary cursor, leaving the
   previous logo flagged red while the new one (via .is-cursor) is
   already red. Two-red-at-once bug. */
.logo-item.is-cursor .logo-shape--red {
  opacity: 1;
  transition: opacity .9s ease;
}
.logo-marquee--hero .logo-item { height: 32px; margin-right: 48px; }
/* MOL + European Parliament + Posta Biztosító have squarer aspects and
   read small at the default row height. Bump just height — width follows
   the natural aspect, so each gets larger without disturbing the uniform
   inter-logo gap. */
.logo-item[data-alt="MOL"] { height: 58px; }
.logo-item[data-alt="European Parliament"] { height: 64px; }
.logo-item[data-alt="Posta Biztosító"] { height: 60px; }
.logo-marquee--hero .logo-item[data-alt="MOL"] { height: 50px; }
.logo-marquee--hero .logo-item[data-alt="European Parliament"] { height: 56px; }
.logo-marquee--hero .logo-item[data-alt="Posta Biztosító"] { height: 52px; }
.logo-marquee--hero .logo-shape--white { opacity: .55; }
/* `display: none` (not just `visibility: hidden`) so the marquee row in
   .h-panel-inner's grid collapses to 0 on about/contact panels. That lets
   the 1fr body row stretch all the way to the CTA, putting the centred body
   at the true midpoint of (line, CTA). Title row stays auto-sized so its
   position is unaffected. */
.logo-marquee.is-hidden { display: none; }

/* First-time elegant reveal of the hero panel after the splash slides
   away. The class flips on once `mounted` flips true and stays — so
   the animations play exactly once on initial load (they don't replay
   when the user returns to home from a subpage). */
.home-h.is-first-reveal .h-panel--about .h-word,
.home-h.is-first-reveal .h-panel--about .h-line,
.home-h.is-first-reveal .h-panel--about .h-teaser {
  animation: heroRevealIn 1.4s cubic-bezier(.2,.8,.2,1) both;
}
/* CTA fades in more slowly so it settles in at the same perceived pace
   as the bigger text elements above. */
.home-h.is-first-reveal .h-panel--about .h-discover {
  animation: heroRevealIn 3.2s cubic-bezier(.2,.8,.2,1) both;
}
.home-h.is-first-reveal .h-panel--about .h-word     { animation-delay: .20s; }
.home-h.is-first-reveal .h-panel--about .h-line     { animation-delay: .50s; }
.home-h.is-first-reveal .h-panel--about .h-teaser   { animation-delay: .80s; }
.home-h.is-first-reveal .h-panel--about .h-discover { animation-delay: 1.10s; }

@keyframes heroRevealIn {
  /* Opacity-only so we don't fight the parallax transforms already on
     .h-shift / .h-teaser-body / .h-discover. */
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes logoMarquee {
  /* Items move right → left as the track translates from 0 to -50%. The
     two duplicated copies make the wrap-around invisible. */
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

.about-section {
  display: grid; grid-template-columns: 1fr 1.6fr; gap: 6vw;
  align-items: center;
  padding: 48px 0;
  border-top: 1px solid var(--rule);
  transition: color .25s ease;
}
.about-section .eyebrow,
.about-section-title,
.about-section-title em { transition: color .25s ease; }
@media (hover: hover) and (pointer: fine) {
  .about-section:hover .eyebrow,
  .about-section:hover .about-section-title,
  .about-section:hover .about-section-title em { color: #FF2233; }
}
/* Touch devices: hover never fires, so the headline + kicker would stay
   muted as the user scrolls. The About component sets `.is-current` on the
   section whose middle is in the viewport — pick it up here to flip the
   colour the same way the desktop hover does. */
@media (hover: none) and (pointer: coarse) {
  .about-section.is-current .eyebrow,
  .about-section.is-current .about-section-title,
  .about-section.is-current .about-section-title em { color: #FF2233; }
}
.about-section:first-of-type { padding-top: 28px; border-top: 0; }
.about-section:last-of-type { border-bottom: 0; }
.about-section-head { margin-bottom: 28px; }
.about-section-head .eyebrow { margin-bottom: 18px; }
.about-section-title {
  font-family: var(--display); font-weight: var(--display-weight, 400);
  font-size: clamp(22px, 2.4vw, 34px);
  line-height: 1.05; letter-spacing: -.018em;
  margin: 0; color: var(--paper);
  white-space: nowrap;
}
@media (max-width: 900px) { .about-section-title { white-space: normal; } }
.about-section-title em { font-style: italic; color: var(--paper-soft); }
/* --ppx on each .about-section-content is driven by its own section's
   mouseenter/move/leave handler (set up in the About component) — local
   parallax that only reacts when the cursor is inside that row. */
.about-section-content {
  transform: translate3d(var(--ppx, 0px), 0, 0);
  will-change: transform;
}
.about-section-img {
  /* Matches the natural ratio of the source webps (~1600×1143) so the image
     displays at its real proportions — no stretch, no crop. */
  aspect-ratio: 7 / 5;
  overflow: hidden;
  align-self: center;
  /* Soft vignette mask so the photo's edges dissolve into the matte-black
     page bg instead of ending at a hard rectangle. `closest-side` ends the
     gradient AT the box edge (not far beyond it like `100% 100%` would),
     so the actual edge pixels reach full transparency. */
  -webkit-mask-image: radial-gradient(ellipse closest-side at center, #000 30%, transparent 100%);
          mask-image: radial-gradient(ellipse closest-side at center, #000 30%, transparent 100%);
}
.about-section-img .img {
  width: 100%; height: 100%;
  background-size: cover; background-position: center;
  filter: grayscale(.55);
  transition: filter .6s ease, transform 6s ease-out;
  transform: scale(1.02);
}
@media (hover: hover) and (pointer: fine) {
  .about-section:hover .about-section-img .img { filter: grayscale(0); transform: scale(1.06); }
}
@media (max-width: 900px) {
  .about-section-img { aspect-ratio: 16/10; margin-top: 32px; }
}
.about-section-body p {
  font-family: var(--serif); font-size: 19px; line-height: 1.7;
  color: var(--paper); margin: 0;
  text-align: justify; hyphens: auto;
  overflow-wrap: break-word;
}
/* Grid items default to min-width:auto, which makes long Hungarian words
   ("inspiráló környezetben…") force the column wider than the viewport on
   phones. Cap min-width and drop justify (looks bad in narrow columns). */
.about-section-content, .about-section-img { min-width: 0; }
.about-clients { list-style: none; padding: 0; margin: 36px 0 0; }
.about-clients li {
  display: grid; grid-template-columns: 220px 1fr auto;
  align-items: baseline; gap: 18px;
  padding: 14px 0;
  border-top: 1px solid var(--rule);
  font-family: var(--serif);
  cursor: default;
  transition: color .25s ease;
}
.about-clients li:hover .ac-name { color: #FF2233; }
.about-clients li:hover .ac-note { color: #FF2233; opacity: .85; }
.about-clients li:last-child { border-bottom: 1px solid var(--rule); }
.about-clients .ac-name { font-size: 22px; letter-spacing: -.01em; }
.about-clients .ac-rule { height: 1px; background: var(--rule); transform: translateY(-4px); }
.about-clients .ac-note { font-style: italic; color: var(--paper-soft); font-size: 16px; text-align: right; }

.about-kicker {
  font-family: var(--display); font-weight: var(--display-weight, 400); font-size: clamp(28px, 2.8vw, 40px);
  line-height: 1.3; color: var(--paper);
  margin: 140px auto 100px; max-width: 36ch;
  text-align: center;
  text-wrap: balance;
  cursor: pointer;
  transition: color .35s ease;
  display: block;
  background: transparent;
  border: 0;
  padding: 0;
  font-weight: inherit;
  letter-spacing: inherit;
}
.about-kicker em { font-style: italic; color: var(--paper-soft); transition: color .35s ease; }
.about-kicker:hover, .about-kicker:hover em,
.about-kicker.is-inview, .about-kicker.is-inview em {
  color: #FF2233;
}

@media (max-width: 800px) {
  .about-section { grid-template-columns: 1fr; gap: 28px; }
  .about-clients li { grid-template-columns: 1fr; gap: 4px; }
  .about-clients .ac-rule { display: none; }
  .about-clients .ac-note { text-align: left; }
}

.about-body-legacy {
  font-family: var(--serif); font-size: 21px; line-height: 1.65; color: var(--paper);
}
.about-figure { margin: 0; position: sticky; top: 110px; }
.about-img {
  aspect-ratio: 4/5;
  background-size: cover; background-position: center;
  filter: grayscale(1) contrast(1.05) brightness(.92);
}

/* About — staggered editorial gallery (writer · pianist · dancers · painter) */
.about-stage {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 22px;
  padding-top: 18px;
}
.about-stage-card { margin: 0; }
.about-stage-card .about-stage-img {
  width: 100%;
  background-size: cover; background-position: center;
  filter: grayscale(1) contrast(1.08) brightness(.92);
  border: 1px solid var(--rule);
  transition: filter .9s, transform .9s cubic-bezier(.2,.8,.2,1);
}
.about-stage-card:hover .about-stage-img { filter: grayscale(.75) contrast(1.05) brightness(1); transform: translateY(-2px); }
.about-stage-card figcaption {
  font-family: var(--serif); font-style: italic;
  font-size: 14px; color: var(--paper-soft);
  margin-top: 10px;
}
/* staggered, magazine-style placement: tall · short · short(offset) · tall */
.about-stage-card.pos-0 .about-stage-img { aspect-ratio: 3/4; }
.about-stage-card.pos-1 .about-stage-img { aspect-ratio: 4/5; margin-top: 56px; }
.about-stage-card.pos-2 .about-stage-img { aspect-ratio: 4/5; margin-top: -36px; }
.about-stage-card.pos-3 .about-stage-img { aspect-ratio: 3/4; margin-top: 20px; }
@media (max-width: 720px) {
  .about-stage { grid-template-columns: 1fr; }
  .about-stage-card .about-stage-img { margin-top: 0 !important; aspect-ratio: 4/5 !important; }
}
.about-figure figcaption {
  margin-top: 14px;
  font-family: var(--sans); font-size: 11px; letter-spacing: .22em;
  text-transform: uppercase; color: var(--paper-soft);
}
.about-aside { font-family: var(--sans); font-size: 13px; color: var(--paper-soft); }
.about-aside dl { display: grid; grid-template-columns: 140px 1fr; row-gap: 14px; margin: 32px 0 0; }
.about-aside dt { letter-spacing: .2em; text-transform: uppercase; font-size: 11px; }
.about-aside dd { margin: 0; font-family: var(--serif); font-size: 17px; color: var(--paper); font-style: italic; }

/* ── Work — vertical scenes list ──────────────────────────── */
.work-intro {
  padding: 160px var(--shell) 48px;
}
.work-intro h1 { max-width: 14ch; }
.work-intro .count { font-family: var(--serif); font-style: italic; color: var(--paper-soft); }

.case-row {
  display: grid; grid-template-columns: 1fr 1fr; min-height: 70vh;
  border-top: 1px solid var(--rule);
  cursor: pointer; transition: background .4s;
}
.case-row .case-img {
  position: relative; overflow: hidden; background: #000;
}
.case-row .case-img .img {
  position: absolute; inset: 0; background-size: cover; background-position: center;
  filter: grayscale(1) contrast(1.05); transition: filter 1.4s, transform 8s;
  transform: scale(1.03);
}
@media (hover: hover) and (pointer: fine) {
  .case-row:hover { background: var(--ink-2); }
  .case-row:hover .case-img .img { filter: grayscale(0) contrast(1.05); transform: scale(1); }
}
.case-row .case-words {
  display: flex; flex-direction: column; justify-content: space-between; gap: 14px;
  padding: 6vw clamp(28px,5vw,80px);
  transform: translate3d(var(--ppx, 0px), 0, 0);
  will-change: transform;
}
.case-row .case-words .eyebrow { transition: color .25s ease; }
.case-row .case-words .arrow { transition: color .25s ease, gap .3s; }
.case-row .case-words h2 {
  font-family: var(--display); font-size: clamp(34px,4.5vw,64px); line-height: 1.02;
}
.case-row .case-words h2 em { font-style: italic; color: var(--paper-soft); }
.case-row .case-words .meta { margin-top: 28px; font-size: 11px; letter-spacing: .22em; text-transform: uppercase; color: var(--mute); display: flex; gap: 18px; flex-wrap: wrap; }
.case-row .case-words .arrow { margin-top: 36px; font-family: var(--serif); font-style: italic; color: var(--paper-soft); border-bottom: 1px solid var(--rule); align-self: start; padding-bottom: 2px; }
.case-row:nth-child(even) { grid-template-columns: 1fr 1fr; direction: rtl; }
.case-row:nth-child(even) > * { direction: ltr; }
@media (max-width: 800px) {
  .case-row, .case-row:nth-child(even) { grid-template-columns: 1fr; direction: ltr; min-height: auto; }
  .case-row .case-img { aspect-ratio: 4/5; }
  .case-row .case-words { padding: 60px var(--shell); }
  /* Stack the meta items vertically, one per line, left-aligned. Hide the
     `·` separator spans (every even child in the alternating text/dot
     sequence) since each item now sits on its own row, and prefix each
     text span with a leading dot bullet. */
  .case-row .case-words .meta {
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
  }
  .case-row .case-words .meta > span:nth-child(2n) { display: none; }
  .case-row .case-words .meta > span:nth-child(2n+1)::before {
    content: '·';
    display: inline-block;
    margin-right: 10px;
    color: var(--paper-soft);
  }
}

/* ── Case detail ─────────────────────────────────────────── */
.case-hero {
  padding: 160px 0 24px var(--shell);
  display: grid; grid-template-columns: 1.1fr 1fr; gap: 5vw; align-items: end;
  /* leave room below for the case-strip to sit within the same viewport */
  min-height: calc(100vh - 180px);
}
/* Left-side text column: eyebrow pinned to the top (just under the topbar
   line) and h1 floated to the bottom of the cell (preserving the original
   bottom-aligned title alongside the cover image on the right). Flex
   column + margin-top: auto on the heading. */
.case-hero > div:not(.case-cover) {
  display: flex;
  flex-direction: column;
  align-self: stretch;
}
.case-hero > div:not(.case-cover) > h1 { margin-top: auto; }
.case-hero h1 em { font-style: italic; color: var(--paper-soft); }
.case-cover {
  align-self: stretch;
  /* pull up past hero's top padding so the cover reaches the topbar bottom
     (topbar is ~80px tall, hero top padding is 110px → -30px overlap). */
  margin-top: -30px;
  /* bleed past hero's bottom padding so the cover bottom is flush with the
     case-strip's top border line. */
  margin-bottom: -24px;
  overflow: hidden; background: #000;
}
.case-cover .img {
  width:100%; height:100%;
  background-size: cover; background-position: center;
  filter: grayscale(.65) contrast(1.04);
  transform: scale(1.04);
  transition: filter .6s, transform 1.2s;
}
.case-hero:hover .case-cover .img { filter: grayscale(0) contrast(1.05); transform: scale(1); }
@media (max-width: 900px) {
  .case-hero { grid-template-columns: 1fr; padding: 110px var(--shell) 32px; min-height: 0; }
  .case-cover { aspect-ratio: 4/5; max-height: 60vh; margin-top: 0; align-self: auto; }
  /* Single-column: the text cell is now only as tall as its content, so the
     desktop `margin-top: auto` (which floats the title to the bottom of a tall
     cell) collapses to 0 and the eyebrow ends up flush against the title. With
     the title's tight `line-height: .94`, its capital ascenders overflow up
     into the eyebrow line and the two read as bleeding together. Give the
     title an explicit gap below the eyebrow instead. */
  .case-hero > div:not(.case-cover) > h1 { margin-top: 18px; }
}

.case-strip {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 14px 22px;
  padding: 24px 0;
  border-bottom: 2px solid var(--rule);
  margin: 0 0 56px;
  position: relative;
  font-size: 12px; letter-spacing: .22em; text-transform: uppercase;
  color: var(--paper-soft);
}
/* full-bleed top rule that spans past the shell padding to viewport edges,
   so the line still reads under the right-side cover that bleeds to the
   viewport edge. */
.case-strip::before {
  content: '';
  position: absolute;
  top: 0;
  left: calc(-1 * var(--shell));
  right: calc(-1 * var(--shell));
  height: 2px;
  background: var(--rule);
}
.case-strip-item { color: var(--paper); }
.case-strip-sep  { color: var(--paper-soft); opacity: .7; }

.case-section {
  padding: 44px var(--shell);
  display: grid; grid-template-columns: 1fr;
  justify-items: center; gap: 16px;
  text-align: center;
}
.case-section-body { width: 100%; }
@media (max-width: 800px) { .case-section { gap: 12px; } }
.case-section .lab { font-size: 11px; letter-spacing: .22em; text-transform: uppercase; color: var(--paper-soft); padding-top: 10px; transition: color .35s ease; }
.case-section .lab em { font-family: var(--serif); font-style: italic; font-size: 22px; color: var(--paper); display:block; text-transform: none; letter-spacing: 0; margin-bottom: 8px; transition: color .35s ease; }
/* Label flips to red only while its section sits in the middle "reading
   band" of the viewport — driven by an IntersectionObserver in the Section
   component that toggles `.is-current` as you scroll between sections, so
   only the one you're actively reading is highlighted. Hover (on pointer
   devices) is an additional manual trigger. */
.case-section.is-current .lab,
.case-section.is-current .lab em { color: #FF2233; }
@media (hover: hover) and (pointer: fine) {
  .case-section:hover .lab,
  .case-section:hover .lab em { color: #FF2233; }
}
.case-section .copy { font-family: var(--serif); font-size: clamp(22px, 2.4vw, 34px); line-height: 1.3; max-width: 32ch; color: var(--paper); margin: 0 auto; }
/* Wider variant for the intro paragraph — the body is a longer multi-clause
   sentence so 32ch felt cramped. Tuned around 60ch for comfortable reading. */
.case-section .copy.copy--wide { max-width: 60ch; }
/* Posta's challenge / idea / process / aftermath paragraphs are noticeably
   longer than Teva's, so the 32ch measure makes them stack as tall blocks.
   Bumping to 48ch for this case only — the article carries a `case--posta`
   class set on the wrapper. */
.case--posta .case-section .copy { max-width: 48ch; }
/* EU's challenge / idea / process / aftermath paragraphs run long for the
   same reason as Posta's; widen to match. */
.case--eu .case-section .copy { max-width: 48ch; }

.toolkit { display: grid; grid-template-columns: 1fr auto 1fr; gap: 40px; max-width: 1200px; margin: 0 auto; align-items: start; justify-items: center; text-align: center; }
@media (max-width: 800px) { .toolkit { grid-template-columns: 1fr; gap: 56px; } }
.toolkit-col { text-align: center; }
.toolkit h4 { font-size: 11px; letter-spacing: .22em; text-transform: uppercase; color: var(--paper-soft); margin-bottom: 28px; font-family: var(--sans); }
/* 3-col grid so 4–6 swatches wrap to two rows (e.g. Posta has 6 brand
   colours). With 3 or fewer swatches it still reads as a single row. */
.swatch-row { display: grid; grid-template-columns: repeat(3, auto); gap: 22px; justify-content: center; padding: 4px 0 8px; }
.swatch-item { display: flex; flex-direction: column; align-items: center; min-width: 64px; }
.swatch {
  width: 64px; height: 64px; border-radius: 50%;
  position: relative;
  /* Subtle highlight upper-left → shadow lower-right gives each circle a
     soft "sphere" feel without overpowering the base hue. Inline
     `backgroundColor` from JSX sits underneath this overlay. */
  background-image: radial-gradient(circle at 30% 28%,
    rgba(255,255,255,.22) 0%,
    rgba(255,255,255,0) 45%,
    rgba(0,0,0,.18) 100%);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.08);
}
.swatch-name { margin-top: 14px; font-family: var(--sans); font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase; color: var(--paper); text-align: center; }
.swatch-hex { margin-top: 4px; font-family: var(--sans); font-size: 10.5px; letter-spacing: .04em; color: var(--paper-soft); }
/* Label sits below the circle without being clipped by the 56px width —
   absolute-position with translateX so longer names ("Float Yellow") stay
   on one line. */
.type-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; justify-items: center; }
.type-card { display: flex; flex-direction: column; align-items: center; gap: 14px; }
.type-name { font-family: var(--sans); font-size: 10.5px; letter-spacing: .22em; text-transform: uppercase; color: var(--paper); }
.type-sample { font-size: 14px; line-height: 1.5; color: var(--paper-soft); letter-spacing: .04em; word-break: break-all; }
.type-sample--serif { font-family: var(--serif); font-size: 16px; }
.type-sample--sans { font-family: var(--sans); }
.type-big { font-size: 56px; line-height: 1; color: var(--paper); margin-top: 4px; }
.type-big--serif { font-family: var(--serif); font-style: italic; }
.type-big--sans { font-family: var(--sans); font-weight: 600; }
.materials { font-family: var(--serif); font-size: 17px; line-height: 1.9; font-style: italic; color: var(--paper); padding: 0; margin: 0; }
.materials li { list-style: none; padding-left: 0; }

/* Materials: each item shows a square texture swatch + name. The
   textures are pure CSS so no images are needed. */
.materials-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, max-content));
  grid-auto-flow: row;
  gap: 22px 28px;
  justify-content: center;
  max-width: 240px;
  margin: 0 auto;
}
.material-item { display: flex; flex-direction: column; align-items: center; gap: 12px; }
.material-tex {
  width: 72px; height: 72px;
  border-radius: 4px;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.08), 0 6px 18px rgba(0,0,0,.35);
}
.material-name { font-family: var(--serif); font-style: italic; font-size: 15px; color: var(--paper); }

/* Uncoated paper — warm cream with subtle fibre speckle */
.tex--paper {
  background-color: #ece3cf;
  background-image:
    radial-gradient(rgba(120,90,40,.18) 1px, transparent 1.2px),
    radial-gradient(rgba(60,40,20,.12) 1px, transparent 1.2px),
    linear-gradient(180deg, rgba(0,0,0,.04), rgba(255,255,255,.04));
  background-size: 7px 7px, 11px 11px, 100% 100%;
  background-position: 0 0, 3px 5px, 0 0;
}
/* Linen / cloth weave — crossed fine threads */
.tex--linen {
  background-color: #c9bda5;
  background-image:
    repeating-linear-gradient( 90deg, rgba(60,40,20,.18) 0 1px, transparent 1px 4px),
    repeating-linear-gradient(  0deg, rgba(60,40,20,.18) 0 1px, transparent 1px 4px),
    linear-gradient(135deg, rgba(255,255,255,.08), rgba(0,0,0,.08));
}
/* Stone — mottled cream + grey clumps */
.tex--stone {
  background-color: #b7ad97;
  background-image:
    radial-gradient(ellipse 14px 10px at 22% 30%, rgba(0,0,0,.20), transparent 70%),
    radial-gradient(ellipse 12px 9px  at 70% 22%, rgba(255,255,255,.18), transparent 70%),
    radial-gradient(ellipse 18px 11px at 40% 70%, rgba(0,0,0,.16), transparent 70%),
    radial-gradient(ellipse 10px 8px  at 80% 75%, rgba(255,255,255,.16), transparent 70%),
    radial-gradient(ellipse 13px 9px  at 15% 85%, rgba(0,0,0,.14), transparent 70%);
}
/* Blind deboss — soft circular impression with highlight + shadow */
.tex--emboss {
  background-color: #e8dcc4;
  background-image:
    radial-gradient(circle at 50% 50%, transparent 0 32%, rgba(0,0,0,.18) 33%, transparent 38%),
    radial-gradient(circle at 50% 50%, rgba(255,255,255,.35) 0 22%, transparent 32%),
    radial-gradient(circle at 50% 50%, rgba(0,0,0,.10) 0 30%, transparent 40%);
}
/* Handwriting facsimile — ink-stroke suggestions */
.tex--script {
  background-color: #f1ead9;
  background-image:
    linear-gradient(20deg, transparent 30%, rgba(20,20,40,.55) 31%, rgba(20,20,40,.55) 33%, transparent 34%),
    linear-gradient(15deg, transparent 50%, rgba(20,20,40,.45) 51%, rgba(20,20,40,.45) 52%, transparent 53%),
    linear-gradient(25deg, transparent 65%, rgba(20,20,40,.50) 66%, rgba(20,20,40,.50) 67%, transparent 68%);
}
/* Foil / metallic — angled gradient highlight */
.tex--foil {
  background:
    linear-gradient(135deg, #b8a877 0%, #f4e7a7 35%, #c8b06a 60%, #f1e3a0 85%, #9f8a4f 100%);
}
/* Glossy magazine stock — bright reflective sweep with diagonal highlight,
   suggesting a coated cover catching the light. */
.tex--glossy {
  background:
    linear-gradient(135deg,
      #d8dde4 0%,
      #ffffff 28%,
      #eef1f5 42%,
      #c4cad3 55%,
      #ffffff 72%,
      #d2d8e0 100%);
}
/* Saddle stitch — warm paper base with two stitch marks running down the
   centre fold, mimicking a stapled magazine spine. */
.tex--stitch {
  background-color: #ece3cf;
  background-image:
    /* paper speckle */
    radial-gradient(rgba(120,90,40,.15) 1px, transparent 1.2px),
    /* fold line down the middle */
    linear-gradient(rgba(60,40,20,.18) 0 100%);
  background-size: 7px 7px, 1px 100%;
  background-position: 0 0, center;
  background-repeat: repeat, no-repeat;
  position: relative;
}
.tex--stitch::before,
.tex--stitch::after {
  content: '';
  position: absolute;
  left: 50%; transform: translateX(-50%);
  width: 14px; height: 2px;
  background: rgba(60,40,20,.55);
  border-radius: 1px;
}
.tex--stitch::before { top: 24px; }
.tex--stitch::after  { bottom: 24px; }
/* A4 format — a small portrait page silhouette centred on a darker ground,
   reading as a document spec. */
.tex--format {
  background:
    linear-gradient(#ece3cf 0 0) center / 38% 64% no-repeat,
    linear-gradient(rgba(255,255,255,.06), rgba(255,255,255,.02)),
    #2a2825;
  position: relative;
}
.tex--format::after {
  content: '';
  position: absolute;
  left: 50%; top: 50%;
  width: 38%; height: 64%;
  transform: translate(-50%, -50%);
  box-shadow: 0 4px 10px rgba(0,0,0,.4);
  pointer-events: none;
}
@media (max-width: 600px) {
  .type-big { font-size: 44px; }
  .swatch { width: 56px; height: 56px; }
}

/* Three-column custom layout for the Kiemelt megvalósítások section.
   Flexbox row with the columns themselves as flex columns — this lets
   each column's h4 title and content row be individually horizontally
   centred via `align-items: center`, so the title always sits exactly
   above the centre of its content regardless of case-specific mix. */
.case-highlights {
  /* Grid with explicit fixed-width side tracks (300 / auto / 300). The
     side tracks being identical guarantees the middle column (results
     on EU, film on Teva/Posta) lands at the geometric centre of the
     row — same x as the "Kiemelt megvalósítások" section title above.
     Each side column's own contents (themes' 300 / projects' 188 /
     publishing's 240) is then centred inside its 300-wide track via
     `justify-self: center`. */
  display: grid;
  column-gap: 60px;
  justify-content: center;
  margin: 0 auto;
  align-items: start;
}
.case-highlights > .hl-col { min-width: 0; }
/* Anchor each side column to the edge of its track facing the middle
   column so the visual gap from themes-content to middle-col and from
   middle-col to projects/publishing-content is always exactly the
   column-gap, regardless of how narrow the side content is. */
.case-highlights > .hl-col--themes                       { justify-self: end; }
.case-highlights > .hl-col--projects,
.case-highlights > .hl-col--publishing                   { justify-self: start; }

/* Case-specific column tracks — each case sizes to ITS OWN content so
   EU isn't padded out to fit Teva/Posta's wider film embed, and Posta
   gets the extra side-col width it needs for its long Hungarian labels
   ("BELSŐ KOMMUNIKÁCIÓ" / "KÜLSŐ KOMMUNIKÁCIÓ"). Side tracks always
   identical so the middle column lands centred under the section title. */
.case--eu .case-highlights {
  grid-template-columns: 300px auto 300px;
  max-width: 1200px;
}
/* EU projects column: keep the small 80×80 thumbnails and centre the
   188px grid inside the 300px projects track. That gives a moderate
   shift right from the original left-flush position (56px each side)
   without going all the way to the right edge. */
.case--eu .hl-col--projects { justify-self: center; }
.case--teva .case-highlights {
  grid-template-columns: 300px auto 300px;
  max-width: 1280px;
}
/* Teva publishing: anchored toward the right of the 300px track but
   pulled back 20px from the right edge so it doesn't sit flush against
   it — a tad less shift than `justify-self: end` alone. */
.case--teva .hl-col--publishing {
  justify-self: end;
  margin-right: 20px;
}
.case--posta .case-highlights {
  /* Posta side track must fit the longest label ("BELSŐ KOMMUNIKÁCIÓ")
     on one line AND the row must fit the 13" MacBook M1 content area
     (~1312px after section padding). Side col 340, middle 500, gap 60
     → row 1300 ≈ fits. */
  grid-template-columns: 340px auto 340px;
  max-width: 1320px;
}
/* Posta publishing: centre the 240px covers grid inside the 340px
   publishing track — a moderate shift right from flush-left without
   going all the way to the track right edge. */
.case--posta .hl-col--publishing { justify-self: center; }

/* Posta theme cells are wide enough for the long Hungarian category
   labels on one line. Cat font dropped to 9px / 0 letter-spacing so
   "BELSŐ KOMMUNIKÁCIÓ" (~99px text width at 9px) fits inside the
   100px cell. */
.case--posta .hl-theme {
  flex: 0 0 100px;
  width: 100px;
}
.case--posta .hl-theme-row { gap: 20px; }
.case--posta .hl-theme-cat {
  font-size: 9px;
  letter-spacing: 0;
}

/* Shared "studio light" backdrop for the whole Kiemelt megvalósítások
   block — one single warm-grey radial glow that spans BOTH the highlights
   columns AND the viewer mounted directly beneath them, instead of two
   separate pseudo-elements stacked vertically. The `closest-side` mask
   wipes the box edges to absolute transparency so no rectangle line ever
   shows regardless of how tall the block grows. */
.featured-block {
  position: relative;
  isolation: isolate;
}
/* Tighten the gap between the viewer inside .featured-block and the next
   case section (Aftermath) — the default viewer margin (48px) plus the
   case-section's default top padding (44px) added up to ~92px of dead
   space below the studio-lit area. Bring "A projekt utóélete" close. */
.featured-block .case-book,
.featured-block .panel-strip { margin-bottom: 12px; }
.featured-block + .case-section { padding-top: 12px; }
.featured-block::before {
  content: '';
  position: absolute;
  inset: 0 -10% 0 -10%;
  z-index: -1;
  background: radial-gradient(ellipse 60% 85% at 50% 50%,
    rgba(244,239,233,.48) 0%,
    rgba(244,239,233,.34) 25%,
    rgba(244,239,233,.20) 50%,
    rgba(244,239,233,.08) 75%);
  -webkit-mask-image: radial-gradient(ellipse closest-side at 50% 50%, #000 35%, transparent 100%);
          mask-image: radial-gradient(ellipse closest-side at 50% 50%, #000 35%, transparent 100%);
  pointer-events: none;
}
.case-highlights > .hl-col--themes     { width: 330px; }
.case-highlights > .hl-col--results    { width: 380px; }
.case-highlights > .hl-col--projects   { width: 188px; }
.case-highlights > .hl-col--film       { width: 500px; }
.case-highlights > .hl-col--publishing { width: 240px; }
.case-highlights h4 {
  font-size: 11px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--paper-soft);
  margin: 0 0 36px;
  font-family: var(--sans);
  text-align: center;
}

.hl-theme-row {
  display: flex;
  justify-content: center;
  gap: 30px;
  width: 100%;
}
.hl-theme {
  flex: 0 0 80px;
  width: 80px;
  /* Override flex's default `min-width: auto` so the cell can't grow past
     80px when its category label (e.g. "TÁRSADALOM", "KOMMUNIKÁCIÓ") is
     wider than the cell — without this, one cell expands, the row goes
     asymmetric, and the column title no longer sits above the middle
     icon. The label's wrap is handled by `.hl-theme-cat { width: 100% }`. */
  min-width: 0;
}
.hl-theme {
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.hl-theme-icon {
  width: 72px; height: 72px;
  margin: 0 auto 16px;
  /* Icon shape comes from the per-icon `--icon-url` CSS var set inline.
     Fill colour comes from background-color — tinted green/blue/yellow
     per position (first/second/third) by the rules below. */
  background-color: var(--paper-soft);
  -webkit-mask: var(--icon-url) center / contain no-repeat;
          mask: var(--icon-url) center / contain no-repeat;
  transition: transform .35s cubic-bezier(.2,.8,.2,1), background-color .25s ease;
}
/* The three icons in each case row tinted in order: green, blue, yellow. */
.hl-theme:nth-child(1) .hl-theme-icon { background-color: #5BA968; } /* green */
.hl-theme:nth-child(2) .hl-theme-icon { background-color: #4A8FBF; } /* blue */
.hl-theme:nth-child(3) .hl-theme-icon { background-color: #D4B845; } /* yellow */
@media (hover: hover) and (pointer: fine) {
  .hl-theme:hover .hl-theme-icon { transform: scale(1.08); }
}
.hl-theme-cat {
  font-size: 10px;
  letter-spacing: .18em;
  color: var(--paper);
  font-family: var(--sans);
  margin-bottom: 14px;
  /* Reserve room for the typical 2-line category label so 1-line entries
     (e.g. "B2B") don't drag the project list below them up to a higher
     y than the 2-line neighbours. */
  min-height: 2.4em;
  width: 100%;
  text-align: center;
  /* Keep the label on a single line — no wrapping (so "BELSŐ
     KOMMUNIKÁCIÓ" / "KÜLSŐ KOMMUNIKÁCIÓ" stay together). With
     text-align: center the overflow extends symmetrically into the
     gaps around the cell, which sit inside the wider themes column. */
  white-space: nowrap;
}
.hl-theme-list { width: 100%; }
.hl-theme-list {
  list-style: none;
  margin: 0;
  padding: 0;
  font-family: var(--serif);
  font-size: 13px;
  line-height: 1.45;
  color: var(--paper-soft);
}
.hl-theme-list li + li { margin-top: 4px; }

.hl-result-row {
  display: flex;
  justify-content: center;
  gap: 24px;
  width: 100%;
}
.hl-result {
  flex: 0 0 178px;
  width: 178px;
  min-width: 0;
}
.hl-result { text-align: center; display: flex; flex-direction: column; }
.hl-result-img {
  width: 100%;
  aspect-ratio: 4 / 3;
  background-size: cover;
  background-position: center;
  border-radius: 2px;
  margin-bottom: 18px;
}
.hl-result-cat {
  font-size: 10px;
  letter-spacing: .22em;
  color: var(--paper);
  font-family: var(--sans);
  margin-bottom: 12px;
}
.hl-result-body {
  font-family: var(--serif);
  font-size: 14px;
  line-height: 1.5;
  color: var(--paper-soft);
  margin: 0;
}

.hl-project-grid {
  display: grid;
  grid-template-columns: repeat(2, 80px);
  gap: 22px 28px;
  /* Flush LEFT inside .hl-col--projects (margin 0 not auto) so the
     visual gap between the middle col and the first thumbnail equals
     the highlights column-gap. Leaving margin auto centred the grid in
     the col and gave a big empty space between EREDMÉNYEK and the
     first thumb that the user flagged. */
  margin: 0;
}
.hl-project {
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  background: transparent;
  border: 0;
  cursor: pointer;
  color: var(--paper-soft);
  -webkit-tap-highlight-color: transparent;
  transition: color .25s ease;
}
.hl-project-img {
  display: block;
  width: 80px; height: 80px;
  background-size: cover;
  background-position: center;
  border-radius: 4px;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.08), 0 6px 18px rgba(0,0,0,.35);
  outline: 2px solid transparent;
  outline-offset: 3px;
  transition: outline-color .25s ease, transform .35s ease, filter .25s ease;
}
.hl-project-title {
  display: block;
  margin-top: 10px;
  font-family: var(--serif);
  font-style: italic;
  font-size: 13px;
  line-height: 1.25;
  text-align: center;
  /* Constrain to the thumb width so long titles like "The Poisoned River"
     wrap inside the 80px cell instead of overflowing left/right, which
     was widening the column's visual extent and making the PROJEKTEK
     title look left of its content centre. */
  width: 80px;
}
.hl-project.is-active { color: var(--paper); }
.hl-project.is-active .hl-project-img { outline-color: #FF2233; }
.hl-project.is-empty { cursor: default; }
.hl-project.is-empty .hl-project-img { filter: grayscale(1) brightness(.55); }
.hl-project.is-empty .hl-project-title { opacity: .55; }
@media (hover: hover) and (pointer: fine) {
  .hl-project:not(.is-empty):hover { color: #FF2233; }
  .hl-project:not(.is-empty):hover .hl-project-img { transform: translateY(-2px); }
}
.hl-project:focus-visible { outline: none; }
.hl-project:focus-visible .hl-project-img { outline-color: #FF2233; }
@media (hover: hover) and (pointer: fine) {
  .hl-project:hover .hl-project-img { transform: scale(1.02); }
}

/* Film column (Teva): embed sits in a 16:9 frame; caption beneath. */
.hl-film-embed {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: 2px;
  overflow: hidden;
  box-shadow: 0 14px 36px rgba(0,0,0,.45);
}
.hl-film-embed iframe {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  border: 0; display: block;
}
.hl-film-caption {
  margin-top: 14px;
  text-align: center;
  font-family: var(--serif);
  font-style: italic;
  font-size: 13px;
  color: var(--paper-soft);
}

/* Publishing column (Teva): 2 grouped rows of 3 clickable magazine covers.
   Active cover gets a red outline matching the books picker. */
.hl-pub-group + .hl-pub-group { margin-top: 26px; }
.hl-pub-covers {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
}
.hl-pub-cover {
  width: 100%;
  aspect-ratio: 3 / 4;
  background-size: cover;
  background-position: center;
  border: 0;
  padding: 0;
  border-radius: 2px;
  box-shadow: 0 4px 12px rgba(0,0,0,.4);
  cursor: pointer;
  outline: 2px solid transparent;
  outline-offset: 3px;
  -webkit-tap-highlight-color: transparent;
  transition: outline-color .25s ease, transform .25s ease;
}
.hl-pub-cover.is-active { outline-color: #FF2233; }
@media (hover: hover) and (pointer: fine) {
  .hl-pub-cover:hover { transform: translateY(-2px); }
}
.hl-pub-cover:focus-visible { outline-color: #FF2233; }
.hl-pub-caption {
  margin-top: 10px;
  text-align: center;
  font-family: var(--serif);
  font-size: 12px;
  line-height: 1.35;
  color: var(--paper-soft);
}

@media (max-width: 980px) {
  .case--eu .case-highlights,
  .case--teva .case-highlights,
  .case--posta .case-highlights {
    grid-template-columns: 1fr;
    row-gap: 48px;
    justify-items: center;
  }
  .case-highlights > .hl-col--film       { width: 100%; max-width: 600px; }
  .case-highlights > .hl-col--publishing { width: 100%; max-width: 360px; }
  /* Desktop fixed widths (themes 330 / results 380 / projects 188) overflow
     a 360–390px viewport once the grid collapses. Unlock to viewport-fit. */
  .case-highlights > .hl-col--themes   { width: 100%; max-width: 360px; }
  .case-highlights > .hl-col--results  { width: 100%; max-width: 360px; }
  .case-highlights > .hl-col--projects { width: 100%; max-width: 360px; }
  /* EU Projektek: switch from desktop's 2-col 80×80 grid to a single
     horizontal row of 4 thumbs that flex to the column width. */
  .hl-project-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 14px 10px;
    width: 100%;
  }
  .hl-project-img {
    width: 100%;
    height: auto;
    aspect-ratio: 1 / 1;
  }
  .hl-project-title { width: 100%; font-size: 11px; }
  /* Desktop side-track anchoring uses justify-self + margin offsets so
     side columns balance against the centred middle column. On the
     single-column stacked layout those offsets push the column past
     its track edge and clip the leftmost cover/thumb. Reset them. */
  .case--teva  .hl-col--publishing,
  .case--posta .hl-col--publishing,
  .case--eu    .hl-col--projects { justify-self: center; margin-right: 0; }
}
@media (max-width: 600px) {
  /* Tighter section labels: 36px below the h4 is desktop-air; on a single
     stacked column it disconnects the title from its content. */
  .case-highlights h4 { margin-bottom: 18px; }
  .case--eu .case-highlights,
  .case--teva .case-highlights,
  .case--posta .case-highlights { row-gap: 32px; }
  /* Themes: keep the desktop horizontal icon strip (3 cells side-by-side
     with icon-above-text), just shrink to fit a 360–390px viewport. */
  .hl-theme-row {
    flex-direction: row;
    gap: 14px;
    justify-content: center;
    align-items: flex-start;
  }
  .hl-theme {
    flex: 1 1 0;
    min-width: 0;
    width: auto;
  }
  .hl-theme-icon {
    width: 56px;
    height: 56px;
    margin: 0 auto 12px;
  }
  .hl-theme-cat {
    /* Allow wrap on the narrower mobile cells so long Hungarian labels
       (BELSŐ KOMMUNIKÁCIÓ) break naturally instead of overflowing. Keep
       the desktop's 2-line min-height so a 1-line label (e.g. "B2B")
       doesn't pull its project list — "Éves jelentések" — up to a higher
       y than the 2-line neighbours' lists. */
    white-space: normal;
    min-height: 2.4em;
    margin-bottom: 10px;
    letter-spacing: .14em;
  }
  .hl-theme-list {
    font-size: 12px;
    line-height: 1.4;
  }
  /* Posta's desktop override clamps cells to 100px with a 9px nowrap
     font — relax both so cells share the row evenly with the rest. */
  .case--posta .hl-theme { flex: 1 1 0; width: auto; }
  .case--posta .hl-theme-row { gap: 14px; }
  .case--posta .hl-theme-cat {
    font-size: 10px;
    letter-spacing: .14em;
    white-space: normal;
  }
  /* Results (EU only): same wide-stack treatment so the result photo +
     copy doesn't sit in a 178px island in the middle of the viewport. */
  .hl-result-row {
    flex-direction: column;
    gap: 32px;
    align-items: stretch;
    max-width: 320px;
    margin: 0 auto;
  }
  .hl-result { flex: 0 0 auto; width: 100%; }
  .hl-result-img { aspect-ratio: 16 / 10; }
}

/* Page-flip book viewer (StPageFlip). Sits below Kiemelt megvalósítások on
   the EU case. Library injects its own DOM into .case-book-flip — only
   set positioning + sizing here. */
.case-book {
  max-width: 1100px;
  margin: 8px auto 48px;
  padding: 24px var(--shell) 32px;
  text-align: center;
}
.case-book-title {
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--paper-soft);
  margin: 0 0 28px;
}
.case-book-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
  max-width: 840px;
  margin: 0 auto;
}
.case-book-flip {
  flex: 1 1 auto;
  min-width: 0;
  max-width: 720px;
}
.case-book-flip canvas,
.case-book-flip .stf__parent { margin: 0 auto; }
/* StPageFlip injects .stf__block / .stf__item with a default white
   page-background. Override to the matte dark page bg so any unrendered
   area reads as blank, not as a bright white slab. Images sit on top. */
.case-book-flip .stf__parent,
.case-book-flip .stf__block,
.case-book-flip .stf__item { background: #0a0a0a; }
/* Each rendered page is an <img> inside a page-container. StPageFlip
   defaults to stretching the image to fill the container, which distorts
   pages whose natural aspect doesn't match the widget. object-fit: contain
   preserves native aspect and lets the page bg (#0a0a0a) show through as
   a clean letterbox. */
.case-book-flip .stf__item img,
.case-book-flip .stf__parent img {
  object-fit: contain !important;
  background: #0a0a0a;
}

/* Fullscreen toggle — small pill below the flipbook, same typographic
   treatment as the page counter. */
.case-book-fs {
  margin: 14px auto 0;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 16px;
  border: 1px solid var(--rule);
  border-radius: 999px;
  background: transparent;
  color: var(--paper-soft);
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: .22em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color .25s ease, border-color .25s ease, background .25s ease;
}
.case-book-fs svg { width: 14px; height: 14px; }
@media (hover: hover) and (pointer: fine) {
  .case-book-fs:hover { color: var(--paper); border-color: var(--paper); }
}

/* Fullscreen overlay — portalled into document.body so its z-index isn't
   trapped under the case-layer's stacking context. Backdrop blurs the page
   behind; the book centres in the stage and renders at high pixel density. */
.case-book-overlay {
  position: fixed;
  inset: 0;
  z-index: 220;
  background: rgba(5,5,5,.92);
  -webkit-backdrop-filter: blur(8px);
          backdrop-filter: blur(8px);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 80px 4vw 60px;
  /* Opacity-only animation. Animating backdrop-filter forces the GPU to
     re-rasterize the blur each frame which fights with the canvas repaint
     inside, producing edge jitter on the flipbook during open. Keep the
     blur as a static property and just fade the whole overlay in. */
  animation: caseBookOvBgIn .42s cubic-bezier(.2,.8,.2,1) both;
}
@keyframes caseBookOvBgIn {
  0%   { opacity: 0; }
  100% { opacity: 1; }
}
.case-book-overlay-stage {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 28px;
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  max-width: 100%;
  animation: caseBookOvStageIn .5s cubic-bezier(.2,.8,.2,1) .08s both;
}
/* Slide + fade only — no scale. Scaling the stage subpixel-rasterizes the
   StPageFlip canvas at sub-1.0 sizes, which causes a thin white sliver of
   the canvas's hard-coded "paper" to flicker outside our masking bars
   during the open animation. Translation + opacity have no such artefact. */
@keyframes caseBookOvStageIn {
  0%   { opacity: 0; transform: translateY(32px); }
  100% { opacity: 1; transform: translateY(0); }
}
/* Close — reverse of the open. Backdrop fades + unblurs over 0.36s; the
   stage shrinks/sinks slightly while fading on the same timeline so the
   widget feels like it's being put away, not yanked. */
.case-book-overlay.is-closing {
  animation: caseBookOvBgOut .36s cubic-bezier(.6,.04,.7,.2) forwards;
  pointer-events: none;
}
.case-book-overlay.is-closing .case-book-overlay-stage {
  animation: caseBookOvStageOut .32s cubic-bezier(.6,.04,.7,.2) forwards;
}
@keyframes caseBookOvBgOut {
  0%   { opacity: 1; }
  100% { opacity: 0; }
}
@keyframes caseBookOvStageOut {
  0%   { opacity: 1; transform: translateY(0); }
  100% { opacity: 0; transform: translateY(24px); }
}
/* Spread layout — two plain <img> tags side-by-side, used both inline
   and in fullscreen. The browser scales each img at native quality so
   text stays sharp regardless of zoom level. */
.case-book-overlay-stage--imgs {
  align-items: center;
}
.case-book-spread {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  /* 1-cell grid so the leaving and entering spread layers can stack and
     crossfade in place. Each `.case-book-spread-layer` is the real flex
     row holding the two pages — flex centring + 4px gap lives there now. */
  display: grid;
  grid-template-areas: "stack";
  place-items: stretch;
  height: 100%;
}
.case-book-spread > .case-book-spread-layer {
  grid-area: stack;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-width: 0;
  min-height: 0;
  animation: spreadFadeIn .55s ease both;
  will-change: opacity;
}
.case-book-spread-layer--leaving {
  animation: spreadFadeOut .55s ease both !important;
  pointer-events: none;
}
/* Strip the page background + drop-shadow from the leaving layer — both
   layers having `background: #0a0a0a` darkens the spread at the mid-point
   of the crossfade (same flicker pattern PanelStrip had), and a shadow on a
   fading element creates a visible ghost halo. */
.case-book-spread-layer--leaving .case-book-spread-page {
  background: transparent;
  box-shadow: none;
}
@keyframes spreadFadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes spreadFadeOut {
  from { opacity: 1; }
  to   { opacity: 0; }
}
/* Inline mode — capped narrower so it doesn't dominate the case-section,
   uses object-driven heights via the page aspect. */
.case-book-spread--inline {
  max-width: 720px;
  height: auto;
  align-self: center;
}
.case-book-spread--inline .case-book-spread-page {
  max-height: 460px;
}
.case-book-spread--single { max-width: 360px; }
.case-book-spread-page {
  flex: 0 1 auto;
  max-width: 50%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  background: #0a0a0a;
  box-shadow: 0 12px 36px rgba(0,0,0,.55);
  user-select: none;
}
.case-book-spread--single .case-book-spread-page { max-width: 100%; }
.case-book-spread-page.is-blank {
  background: transparent;
  box-shadow: none;
  opacity: 0;
  min-width: 1px;
}
/* Fullscreen nav arrows — pinned to the viewport vertical centre so they
   always sit at the page's mid-height regardless of how tall the spread
   renders. Reads like a standard image-viewer layout (Lightbox, etc.). */
.case-book-overlay .case-book-nav {
  position: fixed;
  top: 50%;
  transform: translateY(-50%);
  width: 52px;
  height: 52px;
  background: rgba(244,239,233,.06);
  border: 1px solid rgba(244,239,233,.18);
  border-radius: 999px;
  color: var(--paper);
  z-index: 5;
}
.case-book-overlay .case-book-nav:disabled {
  cursor: default;
  /* Fade the SVG arrow (via currentColor) only — leave the circle frame at
     full opacity so the disabled button still reads as a button. Previously
     `opacity: .25` faded the whole element, which collapsed the already-
     subtle 6% background to ~1.5% alpha and made the circle disappear on
     a black backdrop. */
  color: rgba(244,239,233,.25);
}
.case-book-overlay .case-book-nav--prev { left: 28px; }
.case-book-overlay .case-book-nav--next { right: 28px; }
@media (hover: hover) and (pointer: fine) {
  .case-book-overlay .case-book-nav:not(:disabled):hover {
    background: rgba(244,239,233,.16);
    color: var(--paper);
  }
  .case-book-overlay .case-book-nav--prev:not(:disabled):hover { transform: translateY(-50%) translateX(-3px); }
  .case-book-overlay .case-book-nav--next:not(:disabled):hover { transform: translateY(-50%) translateX(3px); }
}
.case-book-overlay-stage .case-book-nav { flex: 0 0 auto; }
.case-book-overlay-close {
  position: absolute;
  top: 24px;
  right: 28px;
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  background: rgba(244,239,233,.06);
  border: 1px solid rgba(244,239,233,.18);
  border-radius: 999px;
  color: var(--paper);
  cursor: pointer;
  transition: background .25s ease, transform .25s ease;
}
.case-book-overlay-close:hover { background: rgba(244,239,233,.16); transform: rotate(90deg); }
.case-book-overlay-close svg { width: 16px; height: 16px; display: block; }
.case-book-overlay .case-book-count { margin-top: 20px; color: var(--paper-soft); }
/* Fullscreen panel image (PanelStrip in overlay mode) — sized to fit the
   stage box while preserving aspect ratio. No clip needed; pure img tags
   don't have StPageFlip's canvas paper bleed. */
.panel-strip-overlay-stage {
  gap: 28px;
}
.panel-strip-panel--fs {
  max-width: 60vw;
  max-height: 70vh;
  width: auto;
  height: auto;
  object-fit: contain;
  flex: 0 1 auto;
  min-width: 0;
  background: transparent;
  box-shadow: 0 12px 40px rgba(0,0,0,.5);
}
@media (max-width: 600px) {
  .panel-strip-panel--fs { max-width: 100%; max-height: 100%; }
}

/* One-panel-at-a-time exhibition viewer (Poisoned River). A single panel
   is shown per slide at its natural aspect ratio, capped by a max display
   height; prev/next buttons sit either side and a counter sits below.
   NOTE: class prefix is `.panel-strip` (not `.case-strip`) to avoid a
   collision with the case-detail metadata row which also uses `.case-strip`
   but as a grid layout — the two would override each other. */
.panel-strip {
  max-width: 1100px;
  margin: 8px auto 48px;
  padding: 24px var(--shell) 32px;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.panel-strip-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
  width: 100%;
  max-width: 840px;
}
.panel-strip-track {
  flex: 1 1 auto;
  min-width: 0;
  /* Grid (not flex) so leaving + entering panels can share a single cell
     and crossfade in place. `place-items: center` matches the prior flex
     centering. Explicit `grid-template-rows: 100%` is required — without
     it the implicit row sizes to content (the img's natural height), which
     for tall panels (eu-poisoned-river, eu-bridges) blows past the 420px
     track and overflows over the page below. With a concrete row height,
     the img's `max-height: 100%` resolves properly and stays inside. */
  display: grid;
  grid-template-rows: 100%;
  grid-template-columns: 100%;
  place-items: center;
  /* Fixed height (not min-height) so the row stays a stable size regardless
     of which panel is loaded — otherwise tall panels grow the track and the
     prev/next arrows jump vertically when the user steps through slides. */
  height: 420px;
}
.panel-strip-panel {
  max-height: 100%;
  max-width: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  user-select: none;
  /* No background fill on the panel itself — both leaving + entering imgs
     would otherwise paint a black box during the crossfade, producing a
     mid-transition darkening that reads as a flicker. The track/stage bg
     shows through pixels of either image that are 0%-opacity. */
  border-radius: 2px;
  box-shadow: 0 8px 24px rgba(0,0,0,.35);
  animation: stripFadeIn .55s ease both;
  /* Promote each img to its own compositor layer so the crossfade is purely
     a GPU opacity blend — no repaint of underlying pixels mid-animation. */
  will-change: opacity;
  backface-visibility: hidden;
}
@keyframes stripFadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes stripFadeOut {
  from { opacity: 1; }
  to   { opacity: 0; }
}
/* Outgoing panel layered on top of the incoming one — same grid cell, so
   the two crossfade in place rather than the new one popping in over a
   blank stage. Drop the box-shadow during fade-out — shadows + opacity
   compositing on top of another image causes a visible ghost halo. */
.panel-strip-panel--leaving {
  animation: stripFadeOut .55s ease both;
  pointer-events: none;
  box-shadow: none;
}
/* Stack the inline track imgs in one grid cell so leaving + entering panels
   overlap during the crossfade. */
.panel-strip-track {
  grid-template-areas: "stack";
}
.panel-strip-track > .panel-strip-panel {
  grid-area: stack;
  /* Override grid items' default min-height/min-width: auto, which forces
     them to be at least the size of their content (the img's natural
     dimensions). Without this, tall panels ignore the track's 420px cap
     and overflow into the page below. */
  min-height: 0;
  min-width: 0;
}
/* Fullscreen stacking wrapper — same single-cell grid trick so the leaving
   image overlays the incoming one. Takes the place of the previous bare
   <img> as a flex child of .case-book-overlay-stage. */
.panel-strip-fs-stack {
  display: grid;
  place-items: center;
  grid-template-areas: "stack";
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
}
.panel-strip-fs-stack > .panel-strip-panel--fs {
  grid-area: stack;
  /* Same min-height/min-width: 0 override as the inline track so tall
     panels don't blow past the stage in fullscreen either. */
  min-height: 0;
  min-width: 0;
  /* Hard caps live here (not on .panel-strip-panel--fs alone) because
     .panel-strip-panel { max-height: 100% } is declared later in the file
     and would override an equal-specificity rule on --fs by source order. */
  max-width: 60vw;
  max-height: 70vh;
}
@media (max-width: 600px) {
  .panel-strip-fs-stack > .panel-strip-panel--fs { max-width: 100%; max-height: 100%; }
}
/* Allow vertical scroll through the panel, capture horizontal motion for
   the swipe handler (touchmove preventDefault then fires the flip). */
.panel-strip-track { touch-action: pan-y; }
/* Desktop: hide the bottom-bar arrow buttons — the stage holds the side
   arrows. Bar arrows only appear in the mobile @media block below. */
.panel-strip-fs-bar .case-book-nav { display: none; }
.panel-strip-count,
.case-book-count {
  margin-top: 18px;
  font-family: var(--serif);
  font-style: italic;
  font-size: 13px;
  color: var(--paper-soft);
  letter-spacing: .04em;
  text-align: center;
}
@media (max-width: 600px) {
  /* Drop the shell-padding + top margin on mobile and tighten the arrow
     gap so the viewer gets the full width minus the 44px arrow boxes.
     Track must keep a FIXED height (not auto) — otherwise stepping
     through slides of different aspect ratios resizes the track and
     the section below (e.g. "A projekt utóélete") jumps up and down.
     70vh capped at 540px scales to the phone but never exceeds the
     desktop value. */
  .panel-strip { padding: 0 8px 12px; margin-top: 0; }
  .panel-strip-row { gap: 8px; }
  /* Mobile fullscreen: arrows in the bottom counter row, hidden in stage. */
  .case-book-overlay .panel-strip-overlay-stage > .case-book-nav { display: none !important; }
  .case-book-overlay .panel-strip-fs-bar {
    display: flex !important;
    align-items: center;
    justify-content: center;
    gap: 18px !important;
  }
  .case-book-overlay .panel-strip-fs-bar .case-book-nav {
    display: inline-flex !important;
    position: static !important;
    top: auto !important;
    left: auto !important;
    right: auto !important;
    transform: none !important;
    width: 40px !important;
    height: 40px !important;
    background: rgba(244,239,233,.08) !important;
    border: 1px solid rgba(244,239,233,.2) !important;
    border-radius: 999px !important;
    color: var(--paper) !important;
    align-items: center;
    justify-content: center;
  }
  .case-book-overlay .panel-strip-fs-bar .case-book-nav svg { width: 22px; height: 22px; display: block; }
  /* Aspect-sized track per case — height computed from width so the
     image fills the track end-to-end. Stable across slides (same
     aspect each time) and zero dead space above/below, so the
     counter sits right under the image and the content above hugs
     the image top.
     Teva  → 3:4 magazine covers
     Posta → 3:4 product / 1:1 annual mix (pick the taller portrait
             aspect so termék fills; square éves leaves a small gap)
     EU    → 1:1 Poisoned River pages */
  .panel-strip-track { height: auto; align-items: flex-end; }
  .case--teva  .panel-strip-track { aspect-ratio: 800 / 1039; }
  .case--posta .panel-strip-track { aspect-ratio: 800 / 1102; }
  .case--eu    .panel-strip-track { aspect-ratio: 1 / 1; align-items: center; }
  /* EU's book pages (Step in and Help! / Well-known Hungarians) are
     600×1053 — much taller than the square Poisoned River panels that
     share the same strip viewer. Override the track aspect when the
     PanelStrip is rendering book pages so pages don't shrink to fit
     a square slot. */
  /* Track aspect slightly taller than the page (1053) so flex-end leaves
     a small natural gap above the image — matches the breathing room
     Teva/Posta covers get from their own aspect mismatch. */
  .case--eu .panel-strip--tall .panel-strip-track { aspect-ratio: 600 / 1200; }
  .panel-strip-count { margin-top: 10px; }
  /* Pull the viewer up close to the publishing/projects strip — desktop
     padding (44px section + 8px strip-margin + 24px strip-padding) adds
     up to ~76px of dead air on mobile. */
  .featured-block .case-section { padding-bottom: 16px; }
  /* Teva's track aspect (800/1039) matches its image exactly so there's
     zero in-track dead space — looks tighter than Posta where square
     éves covers leave a natural gap above. Stretch Teva's track to a
     taller aspect so a similar breathing room appears above the cover. */
  .case--teva .panel-strip-track { aspect-ratio: 800 / 1200; }
  /* BookViewer arrows go missing because the StPageFlip widget's
     minWidth (220) is wider than the flex item left over after 44px
     arrows + 18px gaps + shell padding on a 360–390px viewport — the
     widget overflows and shoves the next arrow off-screen. Shrink the
     ornamentation so the widget and both arrows fit on the row. */
  .case-book { padding: 12px 4px 16px; margin-bottom: 12px; }
  .case-book-row { gap: 6px; }
  .case-book-title { margin-bottom: 14px; }
  .case-book-nav { width: 32px; height: 32px; }
  .case-book-nav svg { width: 22px; height: 22px; }
}

/* Project picker shown under the book — 4 thumbnails that swap the active
   PDF in the page-flip widget. Disabled items (no `pages` yet) dim out. */
.case-book-picker {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  gap: 28px;
  margin: 0 auto 36px;
  flex-wrap: wrap;
}
.case-book-thumb {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  width: 88px;
  padding: 0;
  background: transparent;
  border: 0;
  cursor: pointer;
  color: var(--paper-soft);
  -webkit-tap-highlight-color: transparent;
  transition: color .25s ease, transform .25s ease;
}
.case-book-thumb-img {
  display: block;
  width: 80px; height: 80px;
  background-size: cover;
  background-position: center;
  border-radius: 4px;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.08), 0 6px 18px rgba(0,0,0,.35);
  outline: 2px solid transparent;
  outline-offset: 3px;
  transition: outline-color .25s ease, transform .25s ease, filter .25s ease;
}
.case-book-thumb-title {
  font-family: var(--serif);
  font-style: italic;
  font-size: 12px;
  line-height: 1.2;
  text-align: center;
}
.case-book-thumb.is-active { color: var(--paper); }
.case-book-thumb.is-active .case-book-thumb-img { outline-color: #FF2233; }
.case-book-thumb.is-empty { cursor: default; }
.case-book-thumb.is-empty .case-book-thumb-img { filter: grayscale(1) brightness(.55); }
.case-book-thumb.is-empty .case-book-thumb-title { opacity: .55; }
@media (hover: hover) and (pointer: fine) {
  .case-book-thumb:not(.is-empty):hover { color: #FF2233; }
  .case-book-thumb:not(.is-empty):hover .case-book-thumb-img { transform: translateY(-2px); }
}
.case-book-thumb:focus-visible { outline: none; }
.case-book-thumb:focus-visible .case-book-thumb-img { outline-color: #FF2233; }
.case-book-nav {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  background: transparent;
  border: 0;
  color: var(--paper-soft);
  cursor: pointer;
  transition: color .25s ease, transform .25s ease;
  -webkit-tap-highlight-color: transparent;
}
.case-book-nav svg { width: 26px; height: 26px; display: block; }
@media (hover: hover) and (pointer: fine) {
  /* `:not(:disabled)` is required: without it, a disabled prev/next button
     still receives the hover transform on mouseover, which wipes out the
     overlay buttons' `translateY(-50%)` centering and drops the button by
     half its height. Same exclusion on the colour flip — disabled buttons
     should stay dim, not turn red on hover. */
  .case-book-nav:not(:disabled):hover { color: #FF2233; }
  .case-book-nav--prev:not(:disabled):hover { transform: translateX(-3px); }
  .case-book-nav--next:not(:disabled):hover { transform: translateX(3px); }
}
@media (hover: none) and (pointer: coarse) {
  .case-book-nav { color: var(--paper); }
}
.case-book-nav:focus-visible { outline: 1px solid #FF2233; outline-offset: 4px; }

.case-bottom {
  display: grid; grid-template-columns: 1fr 1fr; gap: 48px;
  padding: 48px var(--shell) 32px;
  align-items: stretch;
}
@media (max-width: 800px) { .case-bottom { grid-template-columns: 1fr; gap: 32px; align-items: stretch; } }

/* Deliverables gallery shown inside "A megvalósítás" — magazine covers +
   a YouTube embed for the brand film. Two-col on desktop (covers side-by-
   side, film spans full width below), single column on phones. */
.case-deliverables {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 32px;
  margin: 12px auto 24px;
  max-width: 1200px;
  padding: 24px var(--shell) 20px;
  position: relative;
  isolation: isolate;
}
/* One shared studio-light backdrop sitting behind BOTH magazine covers AND
   the brand film below. Pseudo's box is pulled well outside the gallery's
   edges (negative insets on all sides) so the radial gradient's transparent
   stop lands far outside the visible area — no hard rectangle edges show
   through. The ellipse is now taller (55% × 80%) so the glow covers the
   whole gallery vertically. */
.case-deliverables::before {
  content: '';
  position: absolute;
  inset: -25% -25% -25% -25%;
  z-index: -1;
  /* Bright "lit" gradient covering most of the pseudo box… */
  background: radial-gradient(ellipse 80% 85% at 50% 50%,
    rgba(244,239,233,.48) 0%,
    rgba(244,239,233,.34) 25%,
    rgba(244,239,233,.20) 50%,
    rgba(244,239,233,.08) 75%);
  /* …then a mask wipes the edges to absolute transparency via
     `closest-side` so the 100% stop lands AT the pseudo's box edge,
     guaranteeing no visible rectangle/clip line regardless of where the
     gradient happens to be at that point. */
  -webkit-mask-image: radial-gradient(ellipse closest-side at 50% 50%, #000 35%, transparent 100%);
          mask-image: radial-gradient(ellipse closest-side at 50% 50%, #000 35%, transparent 100%);
  pointer-events: none;
}
.case-deliverable {
  margin: 0;
  display: flex; flex-direction: column;
  gap: 14px;
  position: relative;
}
.case-deliverable--film { grid-column: 1 / -1; }
.case-deliverable img {
  width: 100%; height: auto; display: block;
  /* Heavy drop shadow + a soft warm halo above so the covers read as
     floating off the shared studio-light ellipse behind them. */
  box-shadow:
    0 30px 80px -20px rgba(0,0,0,.7),
    0 -10px 40px -10px rgba(244,239,233,.15);
}
/* Magazine covers (one per side of the 2-up grid) must render at the same
   visible height regardless of native aspect ratio. Aspect-ratio + contain
   gives every img a fixed-shape box and scales the actual image inside
   without stretching. `box-shadow` is dropped because the shadow would
   trace the empty letterbox box; `filter: drop-shadow` traces the visible
   pixels instead. */
.case-deliverable--magazine img {
  aspect-ratio: 4 / 5;
  object-fit: contain;
  background: transparent;
  box-shadow: none;
  filter: drop-shadow(0 24px 40px rgba(0,0,0,.6));
}
.case-deliverable figcaption {
  font-family: var(--sans); font-size: 11px;
  letter-spacing: .22em; text-transform: uppercase;
  color: var(--paper-soft);
  text-align: center;
}
.film-embed { position: relative; width: 100%; aspect-ratio: 16 / 9; background: #000; }
.film-embed iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
/* Lightweight YouTube facade: the thumbnail fills the .film-embed box, the
   red play button sits centred on top. Clicking swaps to the iframe with
   autoplay=1 (handled in FilmEmbed). */
.film-thumb {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  border: 0; padding: 0; margin: 0;
  background-color: #000;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: filter .35s ease;
  overflow: hidden;
}
.film-thumb-img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}
.film-thumb:hover { filter: brightness(1.05); }
.film-play {
  display: block;
  width: clamp(64px, 8vw, 96px);
  height: clamp(64px, 8vw, 96px);
  filter: drop-shadow(0 6px 20px rgba(0,0,0,.55));
  transition: transform .25s cubic-bezier(.2,.8,.2,1);
}
.film-thumb:hover .film-play { transform: scale(1.08); }
.film-play svg { width: 100%; height: 100%; display: block; }
@media (max-width: 700px) {
  .case-deliverables { grid-template-columns: 1fr; gap: 24px; }
  .case-deliverable--film { grid-column: auto; }
}

.case-quote {
  margin: 0 auto; padding: 24px 0;
  border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule);
  font-family: var(--serif); font-style: italic; font-size: clamp(22px, 2.4vw, 34px);
  line-height: 1.25; max-width: 28ch; color: var(--paper);
  text-align: center;
  display: flex; flex-direction: column; justify-content: space-between; gap: 14px;
  transition: transform .35s cubic-bezier(.2,.8,.2,1);
}
.case-quote cite { display: block; margin-top: 16px; font-style: normal; font-size: 13px; letter-spacing: .18em; text-transform: uppercase; color: var(--paper-soft); white-space: pre-line; }

.case-memory {
  margin: 0 auto; padding: 24px 0;
  border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule);
  font-family: var(--serif); font-style: italic; font-size: clamp(22px, 2.4vw, 34px);
  line-height: 1.25; max-width: 28ch; color: var(--paper);
  text-align: center;
  display: flex; flex-direction: column; justify-content: space-between; gap: 14px;
  transition: transform .35s cubic-bezier(.2,.8,.2,1);
}
.case-memory cite { display: block; margin-top: 16px; font-style: normal; font-size: 13px; letter-spacing: .18em; text-transform: uppercase; color: var(--paper-soft); white-space: pre-line; }
/* Eyebrow transitions smoothly between muted and red — driven only by
   hover (rule below). The scroll-band IntersectionObserver was removed:
   quote + memory live side-by-side, so the observer ended up locking one
   block as "current" and leaving the other permanently muted. Hover-only
   is simpler and reads correctly on desktop; touch devices fall through
   to the static eyebrow colour. */
.case-quote .eyebrow,
.case-memory .eyebrow { transition: color .35s ease; }
/* Hover (pointer devices only) scales the whole block up slightly so it
   reads as interactive. Touch-gated to avoid sticky-tap on phones. The
   `.reveal-block` chain bumps specificity past the later-defined
   `.reveal-block[data-revealed="true"] { transform: none }` which would
   otherwise overwrite the hover transform. */
@media (hover: hover) and (pointer: fine) {
  .case-quote.reveal-block:hover,
  .case-memory.reveal-block:hover { transform: scale(1.05); }
  .case-quote.reveal-block:hover .eyebrow,
  .case-memory.reveal-block:hover .eyebrow { color: #FF2233; }
  .case-back a:hover { color: #FF2233; }
}

.case-back { padding: 0 var(--shell) 40px; }
.case-back a { font-family: var(--serif); font-style: italic; color: var(--paper-soft); border-bottom: 1px solid var(--rule); cursor: pointer; }

/* ── Together (contact) + team ──────────────────────────── */
.together { padding: 160px var(--shell) 48px; }
.together h1 { max-width: none; white-space: nowrap; margin-bottom: 32px; }
.together h1 em { font-style: italic; color: var(--paper-soft); }
.together-grid { display: grid; grid-template-columns: 1.1fr 1.3fr 1fr; column-gap: 0; row-gap: 4vw; align-items: start; }
.together-grid > .contact-map { margin-left: 6vw; margin-right: 1.5vw; }
@media (max-width: 900px) {
  .together-grid { grid-template-columns: 1fr; row-gap: 56px; }
  /* Title nowrap clips off-screen on phones since "Kezdjük egy beszélgetéssel."
     is too long for a single line at narrow widths. Let it wrap. */
  .together h1 { white-space: normal; }
  /* On desktop the map's height is driven by `align-self: stretch` against
     the aside row. With a single column there's nothing to stretch against,
     so the map collapses to 0 and disappears — give it an explicit height. */
  .together-grid > .contact-map { margin-left: 0; margin-right: 0; height: 280px; }
}
.together-form { display: grid; gap: 18px; }
.field { display: grid; gap: 6px; }
.field label { font-size: 11px; letter-spacing: .22em; text-transform: uppercase; color: var(--paper-soft); }
.field input, .field textarea, .field select {
  font-family: var(--serif); font-size: 22px; padding: 10px 0;
  border: 0; border-bottom: 1px solid var(--rule); background: transparent; color: var(--paper);
  outline: none;
}
.field input::placeholder { color: var(--mute); }
.field input:focus, .field textarea:focus { border-bottom-color: var(--paper); }
.field textarea { resize: vertical; min-height: 88px; line-height: 1.4; }
/* Custom dropdown — replaces native <select> so the open menu inherits
   the form's serif font instead of OS chrome. */
.field-select { position: relative; }
.field-select-toggle {
  width: 100%; text-align: left;
  font-family: var(--serif); font-size: 22px; line-height: 1.2;
  padding: 10px 0; border: 0; border-bottom: 1px solid var(--rule);
  background: transparent; color: var(--paper);
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  cursor: pointer; outline: none;
}
.field-select-toggle:not(.has-value) { color: var(--mute); }
.field-select-toggle:focus { border-bottom-color: var(--paper); }
.field-select-toggle svg {
  width: 12px; height: 8px;
  transition: transform .25s ease;
  flex-shrink: 0;
}
.field-select.is-open .field-select-toggle svg { transform: rotate(180deg); }
.field-select-menu {
  position: absolute; left: 0; right: 0; top: calc(100% + 6px);
  margin: 0; padding: 6px 0;
  list-style: none;
  /* Lifted off the matte-black page (--ink is the same #0A0A0A) so the menu
     reads as a solid raised panel, not a transparent overlay. Capped to ~5
     options tall; the rest scroll. */
  background: #18181a; border: 1px solid rgba(244,239,233,.3);
  box-shadow: 0 18px 44px rgba(0,0,0,.6);
  /* overflow-y: scroll (not auto) + a custom ::-webkit-scrollbar keep the bar
     permanently visible, overriding macOS's auto-hiding overlay bars. NOTE: do
     NOT set scrollbar-width/scrollbar-color here — when those standard props
     are present, Chrome ignores ::-webkit-scrollbar and falls back to the
     auto-hiding overlay bar (the bug that made this invisible). */
  max-height: 248px; overflow-y: scroll;
  z-index: 50;
}
.field-select-menu::-webkit-scrollbar { width: 14px; -webkit-appearance: none; }
.field-select-menu::-webkit-scrollbar-track { background: rgba(244,239,233,.1); }
/* Transparent border + background-clip: padding-box insets the thumb inside the
   track, so the track (and its left divider line) stays visible on both sides
   of the slider instead of being covered. Hover uses background-color (not the
   `background` shorthand) so it doesn't reset background-clip back to border-box. */
.field-select-menu::-webkit-scrollbar-thumb { background: rgba(244,239,233,.5); border-radius: 7px; border: 3px solid transparent; background-clip: padding-box; }
.field-select-menu::-webkit-scrollbar-thumb:hover { background-color: rgba(244,239,233,.7); }
.field-select-option {
  display: block; width: 100%;
  font-family: var(--serif); font-size: 18px; line-height: 1.3;
  padding: 10px 18px;
  border: 0; background: transparent; color: var(--paper);
  text-align: left; cursor: pointer;
}
.field-select-option:hover,
.field-select-option:focus {
  background: rgba(244,239,233,.06);
  outline: none;
}
.field-select-option.is-selected { color: var(--paper); font-style: italic; }
.btn-send {
  justify-self: start; margin-top: -8px; padding: 14px 28px; border-radius: 999px;
  background: var(--paper); color: var(--ink); font-family: var(--serif);
  font-size: 18px; letter-spacing: 0; transition: background .3s, color .3s;
}
.btn-send:hover { background: #FF2233; color: var(--paper); }
/* Consent line above the send button — small, muted, with an underlined
   link to the privacy notice (opens in a new tab so the form isn't lost). */
.form-consent {
  margin: -8px 0 0; max-width: 52ch;
  font-family: var(--serif); font-size: 15px; line-height: 1.5; color: var(--paper-soft);
}
.form-consent a { color: var(--paper); text-decoration: underline; text-underline-offset: 3px; white-space: nowrap; transition: color .25s ease; }
@media (hover: hover) and (pointer: fine) { .form-consent a:hover { color: #FF2233; } }
@media (hover: none) and (pointer: coarse) { .form-consent a { color: #FF2233; } }
/* Submit failure notice under the send button (Worker/Brevo error). */
.form-error {
  margin: 12px 0 0; max-width: 52ch;
  font-family: var(--serif); font-size: 15px; line-height: 1.5; color: #FF6B6B;
}
.form-error a { color: inherit; border-bottom: 1px solid currentColor; }
.contact-aside { font-family: var(--serif); font-size: 19px; line-height: 1.55; color: var(--paper); justify-self: end; max-width: 320px; }

/* ── Adatkezelési tájékoztató (privacy notice) page ─────────────────
   Standalone legal page reached at /adatkezeles. Reuses the subpage
   top-padding (160px) so the eyebrow clears the topbar like the others. */
.legal { padding: 160px var(--shell) 80px; }
.legal-shell { max-width: 760px; margin: 0 auto; }
.legal-title { margin-bottom: 28px; }
.legal-intro {
  font-family: var(--serif); font-size: clamp(19px, 1.9vw, 23px); line-height: 1.6;
  color: var(--paper); margin: 0 0 8px;
  /* No max-width: fills the shell so it lines up with the title above.
     Justify + Hungarian hyphenation: the page sets <html lang="hu">, so the
     browser breaks long compound words (Marketingkommunikációs…) at correct
     Hungarian points, giving a clean block instead of ragged gaps. */
  text-align: justify;
  -webkit-hyphens: auto; hyphens: auto;
}
.legal-section { padding-top: 36px; margin-top: 36px; border-top: 1px solid var(--rule); }
.legal-h {
  font-family: var(--display); font-weight: var(--display-weight, 400);
  font-size: clamp(22px, 2.4vw, 30px); line-height: 1.15; color: var(--paper);
  margin: 0 0 16px;
}
.legal-p {
  font-family: var(--serif); font-size: 18px; line-height: 1.6;
  color: var(--paper-soft); margin: 0 0 14px;
  text-align: justify;
  -webkit-hyphens: auto; hyphens: auto;
}
.legal-p:last-child { margin-bottom: 0; }
.legal-list {
  list-style: none; margin: 0; padding: 0;
  font-family: var(--serif); font-size: 18px; line-height: 1.6; color: var(--paper-soft);
}
.legal-list li { position: relative; padding-left: 22px; margin-bottom: 8px; }
.legal-list li::before {
  content: ''; position: absolute; left: 2px; top: .62em;
  width: 5px; height: 5px; border-radius: 50%; background: #FF2233;
}
.legal-defs { margin: 0; }
.legal-def { display: grid; grid-template-columns: 200px 1fr; gap: 8px 24px; padding: 8px 0; }
.legal-def + .legal-def { border-top: 1px solid var(--rule-soft); }
.legal-def dt {
  font-family: var(--sans); font-size: 11px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--mute); padding-top: 5px;
}
.legal-def dd {
  margin: 0; font-family: var(--serif); font-size: 18px; line-height: 1.5; color: var(--paper);
}
@media (max-width: 640px) {
  .legal { padding: 96px var(--shell) 56px; }
  .legal-def { grid-template-columns: 1fr; gap: 2px; }
  .legal-def dt { padding-top: 0; }
}

/* Footer privacy link */
.foot-legal { color: var(--paper-soft); text-decoration: none; transition: color .25s ease; }
@media (hover: hover) and (pointer: fine) { .foot-legal:hover { color: #FF2233; } }
.contact-map {
  position: relative;
  width: 100%;
  /* Stretch to match the aside's full height so the map's bottom edge
     lines up with the last contact line. */
  align-self: stretch;
  overflow: hidden;
  border-radius: 2px;
  background: #1a1a1a;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.08);
}
.contact-map-leaflet { width: 100%; height: 100%; background: #1a1a1a; }
/* Apply the high-contrast B&W only to the tile pane so the red marker
   (in the overlay pane) keeps its colour. */
.contact-map-leaflet .leaflet-tile-pane {
  filter: grayscale(1) invert(1) contrast(1.7) brightness(1.05);
}
.contact-map-leaflet .leaflet-control-attribution {
  background: rgba(0,0,0,.4); color: var(--paper-soft);
  font-size: 9px;
}
.contact-map-leaflet .leaflet-control-attribution a { color: var(--paper); }
.contact-map-leaflet .leaflet-control-zoom a {
  background: #1a1a1a; color: var(--paper);
  border-color: rgba(255,255,255,.15);
}
.contact-map-leaflet .leaflet-control-zoom a:hover { background: #2a2a2a; }
/* Touch-only tap-to-activate gate: a full-cover button that absorbs
   touches so a finger landing on the map while scrolling doesn't get
   hijacked into a map pan. Goes away on tap; window pointerdown re-arms
   it on the next tap-outside (see ContactMap useEffect). */
.contact-map-gate {
  position: absolute; inset: 0;
  z-index: 5;
  display: flex; align-items: center; justify-content: center;
  background: rgba(10,10,10,.32);
  color: var(--paper);
  font-family: var(--sans);
  font-size: 12px;
  letter-spacing: .22em;
  text-transform: uppercase;
  cursor: pointer;
  border: 0;
  padding: 0;
  -webkit-tap-highlight-color: transparent;
}
.contact-map-gate span {
  padding: 10px 18px;
  border: 1px solid rgba(244,239,233,.6);
  border-radius: 999px;
  background: rgba(0,0,0,.45);
  backdrop-filter: blur(2px);
}
.contact-aside h3 { font-size: 11px; letter-spacing: .22em; text-transform: uppercase; color: var(--paper-soft); margin: 0 0 12px; font-family: var(--sans); font-weight: 500; }
.contact-aside section { margin-bottom: 36px; }
.contact-aside a { border-bottom: 1px solid var(--rule); }
.aside-social-row {
  display: flex;
  align-items: center;
  gap: 10px;
}
.aside-social-row > span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px; height: 32px;
  color: var(--paper-soft);
  cursor: pointer;
  transition: color .25s ease, transform .25s ease;
}
.aside-social-row > span:hover { color: #FF2233; transform: translateY(-1px); }
.aside-social-row svg { width: 20px; height: 20px; display: block; }

/* Temporary: hide the social-media blocks (Együtt aside + footer) until
   the real account links are ready. JSX is kept intact so removing this
   rule brings everything back. The .foot scope on .foot-social bumps
   specificity over the later display: inline-flex on .foot-social
   further down the file. */
.aside-social,
.foot .foot-social { display: none; }

/* Team */
.team {
  padding: 60px var(--shell);
  border-top: 1px solid var(--rule);
  /* Cap on very wide screens so the leads don't blow up and the heading
     on the left doesn't drift far from the lead cards on the right. */
  max-width: 1400px;
  margin: 0 auto;
}
.team h2 { margin-bottom: 60px; }
/* Vertically centre the heading with the lead cards on the right, and cap
   the heading size so "Az Imagine alkotói közössége." stays at two lines
   even on wide screens (instead of wrapping to three). */
.team-intro .asym-left { align-self: center; padding-top: 0; }
.team-intro .asym-left .hed-l { font-size: clamp(42px, 6.2vw, 92px); text-wrap: balance; }
.leads { display: grid; grid-template-columns: 1fr 1fr; gap: 28px; max-width: 720px; margin-bottom: 0; }
.lead-card { padding: 14px 14px 18px; border: 1px solid var(--rule); }
.lead-card .ph { aspect-ratio: 1/1; background-size: cover; background-position: center; filter: grayscale(.25); transition: filter .6s ease; }
@media (hover: hover) and (pointer: fine) {
  .lead-card:hover .ph { filter: grayscale(0); }
}
.lead-card .nm {
  position: relative;
  font-family: var(--serif); font-size: 19px; margin-top: 14px; color: var(--paper);
  padding-left: 14px;
}
.lead-card .nm::before {
  content: '';
  position: absolute;
  left: 0;
  top: 4px; bottom: 4px;
  width: 2px;
  background: #d4351c;
}
.lead-card .rl { font-size: 11px; letter-spacing: .18em; text-transform: uppercase; color: var(--paper-soft); margin-top: 4px; }

/* Wrap the crew in an .asym-grid so its left/right edges align with the
   team-intro's content area (heading on left edge of col 2, leads' right
   edge on col 11). Crew-grid itself then spans cols 2-11. */
.crew-wrap.asym-grid { padding: 0; }
.team-intro.asym-grid { padding-bottom: 0; }
.team-intro h2 { margin-bottom: 0; }
.crew-label { grid-column: 2 / span 10; margin-top: 24px; margin-bottom: 28px; color: #d4351c; }
.crew-grid {
  grid-column: 2 / span 10;
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 28px;
}
@media (max-width: 900px) {
  .crew-wrap.asym-grid > .crew-grid,
  .crew-wrap.asym-grid > .crew-label { grid-column: 1 / -1; }
  .crew-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 500px) {
  .crew-grid { grid-template-columns: 1fr; }
  /* Match the leads to the crew layout — both 1-col on small phones so
     Gyarmati Krisztina / László's cards aren't half the size of the rest. */
  .leads { grid-template-columns: 1fr; }
}

/* ── Footer ─────────────────────────────────────────────── */
.foot {
  padding: 4px var(--shell);
  display: flex; justify-content: space-between; align-items: center;
  font-size: 12px; letter-spacing: .18em; text-transform: uppercase; color: var(--paper-soft);
  border-top: 1px solid var(--rule);
}
.foot .mark { font-family: var(--display); font-weight: var(--display-weight, 400); font-size: 80px; line-height: .9; letter-spacing: -.02em; color: var(--paper); text-transform: none; }
.foot .mark em { font-style: italic; color: var(--paper-soft); }
.foot .foot-mark {
  display: inline-block;
  width: 360px; height: 118px;
  background: var(--paper);
  -webkit-mask: url(brand/imagine-logo-white.png) left center / contain no-repeat;
          mask: url(brand/imagine-logo-white.png) left center / contain no-repeat;
  transition: background .25s ease;
  cursor: pointer;
}
.foot .foot-mark:hover { background: #FF2233; }
/* Social icon row — sits between the logo (left) and the copyright block
   (right). Three flex items in the .foot now distribute across the row. */
.foot-social {
  display: inline-flex;
  align-items: center;
  gap: 18px;
}
.foot-social > * {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px; height: 32px;
  color: var(--paper-soft);
  cursor: pointer;
  transition: color .25s ease, transform .25s ease;
}
.foot-social > *:hover { color: #FF2233; transform: translateY(-1px); }
.foot-social svg { width: 18px; height: 18px; display: block; }
/* Mobile footer: stack vertically and centre everything — logo on top, then
   social row, copyright line, services line. Inline `text-align: right` on
   the copyright div is overridden with !important since the JSX sets it
   inline. */
@media (max-width: 600px) {
  .foot {
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 0;
    padding: 0 var(--shell) 24px;
    line-height: 1;
  }
  .foot .foot-mark {
    display: block;
    -webkit-mask-position: center;
            mask-position: center;
    width: 340px; height: 112px;
    margin: -8px 0;
  }
  .foot > div { text-align: center !important; }
  .foot-social { gap: 22px; }
  .foot-social a { width: 36px; height: 36px; }
  .foot-social svg { width: 20px; height: 20px; }
}

.work-intro-body {
  font-family: var(--serif); font-size: clamp(20px, 1.7vw, 26px);
  line-height: 1.55; color: var(--paper);
  margin: 36px 0 0; max-width: none;
  text-align: justify; hyphens: auto;
}

/* page transitions */
.page { animation: pageIn .6s cubic-bezier(.2,.8,.2,1) both; }
@keyframes pageIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

/* ============================================================
   Asymmetric 12-col layout (CarusiHR-style alternating sections)
   ============================================================ */
.asym-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: 24px;
  row-gap: 0;
  padding: 96px var(--shell);
  align-items: start;
}
.asym-grid > .asym-left  { grid-column: 2 / span 5; }
.asym-grid > .asym-right { grid-column: 7 / span 5; }
@media (max-width: 900px) {
  .asym-grid { padding: 64px var(--shell); }
  .asym-grid > .asym-left,
  .asym-grid > .asym-right { grid-column: 1 / -1; }
}

/* Override the original two-column layout on About sections (Contact team
   uses .asym-grid wrapped explicitly, case-detail keeps its original grid). */
.about-section.asym-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  padding: 96px 0;
  /* `dense` allows the image (when its explicit grid-column is to the LEFT
     of the content's column) to back-fill row 1 instead of being pushed to
     row 2 by the default forward-only placement. */
  grid-auto-flow: dense;
  /* Smaller gutter between photo and text so the two columns read as a pair. */
  column-gap: 24px;
  /* Image aligned with the vertical middle of the text column instead of
     pinned to the top (overrides the base `.asym-grid { align-items: start }`). */
  align-items: center;
}
/* Widen the photo to 7 of 12 cols (was 5), running it to the page edge on
   its side so it reads bigger. Content keeps its 5-col span so the text
   stays readable. The aspect-ratio + soft mask above scale with the new
   width automatically. */
.about-section.asym-grid > .about-section-img.asym-right { grid-column: 7 / span 6; }
.about-section.asym-grid > .about-section-img.asym-left  { grid-column: 1 / span 6; }
.team .asym-grid { padding: 0 0 32px 0; }
@media (max-width: 900px) {
  .about-section.asym-grid { padding: 56px 0; }
  .team .asym-grid         { padding: 0 0 48px 0; }
  /* Single-column: the heading stacks directly above the lead cards (asym-grid
     row-gap is 0), so give it a little breathing room underneath. */
  .team-intro .asym-left { margin-bottom: 28px; }
  /* The leads (asym-right) now flow straight into the crew grid below — with
     the "Vezető munkatársak" label removed they read as one list. Match the
     gap under the last lead to the inter-card rhythm instead of the 48px
     section padding, which left an oversized hole under Gyarmati Krisztina. */
  .team-intro.asym-grid { padding-bottom: 18px; }
}

/* Subpage hero parallax — same pattern as .h-shift but subtler (±10px). */
.hp-shift {
  display: inline-block;
  transform: translate3d(var(--ppx, 0px), 0, 0);
  will-change: transform;
}

/* ============================================================
   Line / row split reveal (used on big italic headings).
   Each child of .reveal-rows is wrapped in a clipped row;
   the inner span starts below and slides up with stagger.
   ============================================================ */
.reveal-rows .reveal-row {
  display: block;
  /* `overflow: clip` + `overflow-clip-margin` lets descenders (g, y, p) extend
     past the tight line-height without being cut, while still hiding the inner
     span's pre-reveal translateY offset. */
  overflow: clip;
  overflow-clip-margin: 0.22em;
  line-height: inherit;
}
/* Larger headings (`.hed-xl` reaches 128px on wide screens, with line-height
   .94) have descenders that overshoot the default 0.22em clip-margin. Bump
   it so "gy", "g", "y" don't get sliced. */
.hed-xl .reveal-row { overflow-clip-margin: 0.55em; padding-bottom: .15em; }
.reveal-rows .reveal-row > .reveal-row-inner {
  display: inline-block;
  transform: translateY(40px);
  opacity: 0;
  transition: transform .9s cubic-bezier(.25,.1,.25,1),
              opacity .9s ease;
  transition-delay: calc(var(--i, 0) * 100ms);
  will-change: transform, opacity;
}
.reveal-rows[data-revealed="true"] .reveal-row > .reveal-row-inner {
  will-change: auto;
  transform: none;
  opacity: 1;
}

/* ============================================================
   Scroll-triggered reveals, hero parallax, center-out underlines
   Layered behaviors only — no layout changes.
   ============================================================ */

/* Inline split-line reveal: <span class="reveal"><span class="reveal-inner">…</span></span>
   The outer span clips, the inner slides up. Stagger via --i on the outer. */
.reveal {
  display: inline-block;
  overflow: clip;
  overflow-clip-margin: 0.22em;
  vertical-align: bottom;
  line-height: inherit;
}
.reveal > .reveal-inner {
  display: inline-block;
  transform: translateY(110%);
  opacity: 0;
  transition: transform .9s cubic-bezier(.2,.8,.2,1), opacity .9s ease;
  transition-delay: calc(var(--i, 0) * 90ms);
  will-change: transform;
}
.reveal[data-revealed="true"] > .reveal-inner {
  will-change: auto;
  transform: none;
  opacity: 1;
}

/* Block-level reveal — for whole sections, rows, paragraphs. */
.reveal-block {
  opacity: 0;
  transform: translateY(28px);
  transition: transform .9s cubic-bezier(.2,.8,.2,1), opacity .9s ease;
  transition-delay: calc(var(--i, 0) * 70ms);
  will-change: transform, opacity;
}
.reveal-block[data-revealed="true"] {
  will-change: auto;
  opacity: 1;
  transform: none;
}

/* Eyebrow reveal — same pattern as .reveal-block but subtler (smaller
   translate, faster) to match the eyebrow's small typographic weight. */
.eyebrow.reveal-block {
  transform: translateY(14px);
  transition: transform .7s cubic-bezier(.25,.1,.25,1), opacity .7s ease;
}

/* Rule / line decorations inside any revealed block scale from 0 → full
   width once their parent intersects. transform-origin: left so they
   draw out from the start. */
.reveal-block .rule,
.reveal-block .ln,
.reveal-rows .rule,
.reveal-rows .ln {
  display: inline-block;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .9s cubic-bezier(.25,.1,.25,1) .15s;
}
.reveal-block[data-revealed="true"] .rule,
.reveal-block[data-revealed="true"] .ln,
.reveal-rows[data-revealed="true"] .rule,
.reveal-rows[data-revealed="true"] .ln {
  transform: scaleX(1);
}


/* Mouse-follow parallax on the home hero italic word.
   The <h1> keeps its `rise` mount animation. A dedicated <span class="h-shift">
   wraps the text inside the <em> so its transform doesn't fight the parent
   animation (which holds `transform: none` via fill-mode: both). */
.h-shift {
  display: inline-block;
  /* Composes mouse-parallax X (--px) + scroll-parallax X (--scroll-x). The
   earlier .h-shift rule sets the same transform but this later definition
   would otherwise override and drop --scroll-x. */
  transform: translate3d(calc(var(--px, 0px) + var(--scroll-x, 0px)), 0, 0);
  will-change: transform;
}

/* Center-out underlines — replace the static border-bottom rules above
   on case-row arrow, case-back link, and contact-aside links. */
.case-row .case-words .arrow,
.case-back a,
.contact-aside a {
  border-bottom: 0;
  position: relative;
  display: inline-block;
  padding-bottom: 2px;
}
.case-row .case-words .arrow::after,
.case-back a::after,
.contact-aside a::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: currentColor;
  opacity: .55;
  transform: scaleX(0);
  transform-origin: center;
  transition: transform .55s cubic-bezier(.2,.8,.2,1), opacity .35s ease;
}
.case-back a:hover::after,
.contact-aside a:hover::after {
  transform: none;
  opacity: 1;
}
@media (hover: hover) and (pointer: fine) {
  .case-row:hover .case-words .arrow::after { transform: none; opacity: 1; }
  /* "Teljes esettanulmány →" text + "01/03 - Teva" eyebrow both flip red
     on hover in sync with the center-out underline animation. */
  .case-row:hover .case-words .arrow,
  .case-row:hover .case-words .eyebrow { color: #FF2233; }
}
/* On touch devices (no hover state) the eyebrow ("01/03 - Teva", etc.) and
   the arrow ("Teljes esettanulmány →") start in the default muted tone and
   animate to red — and the underline draws itself in center-out — when the
   row crosses Reveal's threshold and `data-revealed` flips. Explicit
   keyframe animations (not transitions) so they fire even though the flag
   change can collide with the overlay's slide-up paint frame. The .4s
   delay lets the row settle into place before the line and red appear. */
@media (hover: none) and (pointer: coarse) {
  .case-row .case-words .eyebrow.is-in-view,
  .case-row .case-words .arrow.is-in-view {
    animation: caseRowRedIn .7s ease both;
  }
  .case-row .case-words .arrow.is-in-view::after {
    animation: caseRowUnderlineIn .9s cubic-bezier(.2,.8,.2,1) both;
  }
}
/* Hard-coded colours (no var()) — some Safari builds skip the from-keyframe
   colour entirely when it resolves via a CSS custom property, which yields
   the perceived "instantly red" bug. #C9C2B9 = var(--paper-soft). */
@keyframes caseRowRedIn {
  from { color: #C9C2B9; }
  to   { color: #FF2233; }
}
@keyframes caseRowUnderlineIn {
  from { transform: scaleX(0); opacity: .55; }
  to   { transform: none;      opacity: 1; }
}
/* Email + phone anchors: also flip to red on hover (the underline animation
   already fires from the rule above). */
.contact-aside a {
  transition: color .25s ease;
}
.contact-aside a:hover { color: #FF2233; }
/* Address blocks (the plain <div>s without anchors inside) also become
   interactive on hover — same animated centre-out underline as the email +
   phone anchors above. `:not(:has(a))` excludes the email/phone div so it
   keeps its per-anchor underline behaviour. */
.contact-aside section > div:not(:has(a)):not(.aside-social-row) {
  position: relative;
  padding-bottom: 2px;
  cursor: pointer;
  transition: color .25s ease;
}
.contact-aside section > div:not(:has(a)):not(.aside-social-row)::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: currentColor;
  opacity: .55;
  transform: scaleX(0);
  transform-origin: center;
  transition: transform .55s cubic-bezier(.2,.8,.2,1), opacity .35s ease;
}
.contact-aside section > div:not(:has(a)):not(.aside-social-row):hover { color: #FF2233; }
.contact-aside section > div:not(:has(a)):not(.aside-social-row):hover::after { transform: none; opacity: 1; }

/* ============================================================
   MOBILE RULES (≤ 900px and below)
   Tighten paddings, scale small text, ensure tap-friendly sizes,
   and image-above-text ordering on the about section.
   ============================================================ */

/* About section image goes above content on stacked layout. */
@media (max-width: 900px) {
  .about-section.asym-grid > .about-section-img { order: -1; }
  /* Reset the explicit `grid-column: 7 / span 6` on asym-right (and the
     mirror on asym-left) — with the grid collapsed to a single column those
     line numbers create empty implicit columns and the image renders 0px
     wide. Span the full row instead so sections 1 & 3 (asym-right images)
     stay visible alongside section 2 (asym-left). */
  .about-section.asym-grid > .about-section-img.asym-right,
  .about-section.asym-grid > .about-section-img.asym-left { grid-column: 1 / -1; }
  .contact-aside { justify-self: start; max-width: none; }
  /* Collapse the 12-col grid to a single column on mobile. The desktop
     column-gap: 64px × 11 gaps adds 704px of intrinsic width that overflows
     a phone viewport — the image was pushing past the right edge. With one
     column, gaps don't matter and the image neatly fills the available width. */
  .about-section.asym-grid {
    grid-template-columns: 1fr;
    column-gap: 0;
    row-gap: 28px;
  }
  /* Narrow columns + justify produces ugly wide gaps. Switch to left-align. */
  .about-section-body p { text-align: left; }
}

/* Phone tier — paddings, font-sizes, touch targets. */
@media (max-width: 600px) {
  /* Topbar — keep brand + lang + burger compact. */
  .topbar { padding: 18px clamp(16px, 4vw, 24px); }
  .brand-mark { width: 270px; height: 88px; }
  /* Position the brand absolutely so its width doesn't push the lang
     switcher + burger to the right (or pull them left when the brand is
     the only flex item). Right group stays pinned to the right edge. */
  .brand {
    position: absolute;
    left: -42px;
    top: 50%;
    transform: translateY(-50%);
    margin: 0;
    pointer-events: auto;
    z-index: 2;
  }
  .top-right { margin-left: auto; }
  .lang { font-size: 10px; }

  /* Splash — never under the home indicator. */
  .splash-hint { font-size: clamp(14px, 3.5vw, 18px); bottom: max(8vh, 56px); }
  .splash { padding-bottom: env(safe-area-inset-bottom); }

  /* Home hero — fluid top/bottom padding scaling with viewport HEIGHT (not
     width). Means short phones (iPhone SE, 13 mini) and tall phones (Pro
     Max) get proportional breathing room around the panel content without
     a separate breakpoint each. Same grid: title pinned to row 1, body
     centred in the 1fr row, marquee + CTA in their own auto rows. */
  .h-panel-inner { padding: clamp(56px, 9vh, 110px) clamp(20px, 6vw, 40px) clamp(20px, 5vh, 80px); }
  .h-teaser { max-width: 100%; margin-top: 22px; padding-top: 16px; }
  /* Tighten the gap between the main title and the italic line under it. */
  .h-line { margin-top: 12px; }
  /* Long Hungarian titles (e.g. "Ahogy valóra váltjuk…") can't fit on one
     line at phone widths. Let them wrap and shrink — otherwise nowrap pushes
     the right half past the panel's overflow:hidden boundary, and a swipe
     shears the title visibly. The 2-line min-height keeps the visual block
     the same regardless of whether the title actually wraps, so "Együtt"
     (1 line) and "Ahogy valóra váltjuk…" (2 lines) start at the same Y. */
  .h-word {
    /* Sized so the longest panel title — "ahogy valóra váltjuk…" — fits on
       one line at 360px+ viewport. Single-line keeps all three titles at the
       same Y and right above the teaser divider line. min(7vw, 4.5vh) caps
       title growth by whichever axis is tighter — keeps short-phone titles
       from eating the body's vertical budget. */
    white-space: nowrap;
    font-size: clamp(24px, min(7vw, 4.5vh), 48px);
    font-weight: 700;
  }
  .h-word em { font-weight: 700; }
  /* Anchor the title block to the top of its grid row. With `align-self: center`
     the title's Y depends on the total content height (title + teaser), and
     since each panel's teaser body has a different length, centring puts the
     titles at different Ys. Top-anchoring fixes the title at the same offset
     regardless of teaser length. */
  /* Title + line stay pinned at their original offset (padding-top: 4vh)
     so all 3 panels share the same title Y. The teaser body is the only
     thing that floats — `margin: auto 0` on the flex column pushes it into
     the middle of the remaining space below the title/line. */
  .h-center {
    align-self: stretch;
    align-items: flex-start;
    transform: none;
    padding-top: 4vh;
    display: flex;
    flex-direction: column;
    text-align: left;
  }
  /* `.opener-creed` carries `align-self: center` for desktop's grid layout;
     in this flex column it would centre the <h1> horizontally as a flex
     item. Pin it back to the left so the title sits at the panel's edge. */
  .h-center .h-word,
  .h-center .opener-creed,
  .h-center .h-line { align-self: flex-start; }
  /* h-teaser is now a sibling of .h-center in panel-inner's 1fr grid row;
     the body inside is centred via the parent's `justify-content: center`,
     so no per-element auto-margin tricks needed here on mobile either. */
  /* Pin body to top of its 1fr row so the body's Y is consistent across panels
     — without this, work centres in a shorter row (marquee taking grid space)
     and lands higher than about/contact, which centre in a tall row. */
  .h-teaser { margin: 22px auto 0; min-height: 0; padding-bottom: 8px; justify-content: center; }
  /* Work panel has a visible logo marquee that takes grid space, which
     makes the 1fr row holding the body shorter than on about/contact
     (where the marquee row collapses via display:none). With justify-
     content: center inside the shorter row, the body ends up higher on
     work than the other two panels. Adding a top margin pushes it back
     down to roughly match. */
  /* No work-specific teaser tweaks needed — the divider is in its own
     grid row now, so it sits at the same Y across all three panels
     regardless of teaser margins. */
  /* One shared body size for all three hero panels — sized for Contact (the
     longest mobile copy, ~85 words) so every panel fits even on the shortest
     phone with the URL bar visible. Dual-axis min(clamp-vw, clamp-vh) keeps
     overflow bounded on both axes; iPhone SE (667dvh) lands ~19px, Pixel 8
     ~21px, Pro Max hits the 21px height-ceiling.

     hyphens: auto lets long Hungarian compounds (együttműködésünk,
     energiaforrást) break at proper syllable boundaries.

     max-width in `ch` (not px) ties the wrap to the current font — every
     panel reads as a unified ~30-character-wide column regardless of which
     viewport's clamp value is in effect. */
  .h-teaser-body {
    font-size: min(clamp(19px, 6vw, 26px), clamp(18px, 3.4vh, 25px));
    line-height: 1.4;
    hyphens: auto;
    -webkit-hyphens: auto;
    max-width: 30ch;
    margin-left: auto;
    margin-right: auto;
  }
  /* Slightly thicker divider line on top of the teaser body — 1px is too
     fine on phone DPI; bump to 2px with a touch more opacity. */
  /* Thicker divider line on mobile (1px is too fine on phone DPI). Margin
     above the divider scales with viewport height so short phones don't
     waste budget on a fat title→divider gap. */
  .h-divider { height: 2px; background: rgba(244,239,233,.3); margin-top: clamp(10px, 2.4vh, 22px); }
  /* Disable the GPU compositing on hero text. The parallax is off on touch,
     so the translate3d + will-change just promote each text node to its own
     layer — and Android Chrome fails to repaint those layers correctly during
     native scroll-snap, producing the "half the box vanishes" glitch. */
  .h-shift, .h-teaser-body, .h-discover {
    transform: none;
    will-change: auto;
  }
  /* Drop expensive text-shadow on the teaser body — mobile Chrome clips the
     30px blur incorrectly when the panel is mid-snap, which can read as the
     text box shearing. */
  .h-teaser-body { text-shadow: none; }
  /* Centre the CTA under the teaser body on phones (desktop left-aligns it
     with the rest of the panel content). Hide the long down-arrow SVG so
     the button collapses to text width — the centring then lands cleanly
     under the body. `.h-discover::after` underline is centre-origin so it
     grows symmetrically from the new position. */
  .h-discover { justify-self: center; text-align: center; }
  .h-discover .arr-down { display: none; }
  /* Pager hint below the CTA — mobile-only. Subtle text + arrow row that
     cues the user to swipe horizontally between hero panels. Arrows use
     the same topbar SVG; the left one is mirrored via scaleX. */
  .h-pager-hint {
    display: inline-flex !important;
    justify-self: center;
    margin-top: 14px;
    align-items: center;
    gap: 14px;
    font-family: var(--sans);
    font-size: 11px;
    letter-spacing: .26em;
    text-transform: uppercase;
    color: var(--paper);
    opacity: .8;
    pointer-events: none;
    white-space: nowrap;
  }
  .h-pager-arrow {
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
  /* Gentle outward nudge so the swipe affordance reads as live, not static. */
  .h-pager-arrow--right { animation: hPagerNudgeR 1.8s ease-in-out infinite; }
  .h-pager-arrow--left  { animation: hPagerNudgeL 1.8s ease-in-out infinite; }
  .h-pager-arrow svg { width: 48px; height: 10px; display: block; overflow: visible; }
  .h-pager-arrow--left svg { transform: scaleX(-1); }
  /* Hero logo marquee on phones — kept visible per design. All sizes are
     fluid against viewport height so short phones get a compact marquee
     and tall phones get a roomier one — no separate breakpoint needed.
     The brand-specific overrides (MOL, EP, Posta Biztosító) inherit the
     same fluid pattern, capped well under their desktop ceilings. */
  .logo-marquee--hero {
    margin: clamp(8px, 1.6vh, 32px) auto clamp(8px, 1.2vh, 24px);
    transform: none;
  }
  .logo-marquee--hero .logo-item {
    height: clamp(25px, 3.7vh, 40px);
    margin-right: clamp(30px, 6vw, 56px);
  }
  .logo-marquee--hero .logo-item[data-alt="MOL"]                  { height: clamp(37px, 5.5vh, 62px); }
  .logo-marquee--hero .logo-item[data-alt="European Parliament"]  { height: clamp(42px, 6.2vh, 70px); }
  .logo-marquee--hero .logo-item[data-alt="Posta Biztosító"]      { height: clamp(40px, 5.8vh, 64px); }
  /* On the non-work panels the marquee is invisible but on desktop still
     occupies 98px of space (visibility:hidden) to keep titles aligned across
     panels. On mobile that empty band shoves the visible content off-centre,
     so collapse the row entirely — the about/contact stack can now actually
     vertically centre via align-content. */
  .logo-marquee--hero.is-hidden { display: none; }
  /* Opener-bg on mobile: keep the recolor+zoom but shorten the transitions.
     The desktop's 12s scale + 2.4s filter tween was still mid-animation when
     the next swipe started, and that overlapping transition during native
     scroll-snap is what triggered the half-text-box repaint glitch. With a
     ~400ms tween, the previous panel has fully settled before the next swipe
     begins, so no transition is running while scroll is in motion. */
  .opener-bg { transition: transform .45s ease-out, filter .35s ease-out; }
  /* Work hero on mobile: dancer occupies the right 30% of the source. 100%
     (right edge) anchors her body off-screen left; 75% puts her on the
     right of the viewport with the motion trails crossing centre. */
  .h-panel--work .opener-bg { background-position: 75% 70% !important; }
  /* Same treatment for the about hero — pull the focal subject (typewriter)
     toward the left side of the visible frame on a phone-width viewport. */
  .h-panel--about .opener-bg { background-position: 62% 50% !important; }
  /* Contact hero on mobile uses the people-at-a-table photo (about-hero-2):
     the 3 people sit right-of-centre, so pull the frame right so they're in
     view on a portrait phone instead of the empty wall on the left. */
  .h-panel--contact .opener-bg { background-position: 70% 50% !important; }

  /* Work hero on mobile: distribute title → body → logo roll → CTA down the
     panel with weighted flexible spacers. The larger first spacer (1.2fr) drops
     the body near vertical centre to match about/contact; the two 0.8fr spacers
     sit the logo roll between the body and the bottom-pinned CTA. Only the work
     panel shows the marquee, so about/contact are untouched. */
  .h-panel--work .h-panel-inner { grid-template-rows: auto 1.2fr auto 0.8fr auto 0.8fr auto auto; }
  .h-panel--work .h-teaser { grid-row: 3; }
  .h-panel--work .logo-marquee--hero { grid-row: 5; }
  .h-panel--work .h-discover { grid-row: 7; }
  .h-panel--work .h-pager-hint { grid-row: 8; }

  /* About hero — fit phone. */
  .about-hero { padding: 84px var(--shell) 8px; }
  /* Tighten creed → divider → first picture so the gap doesn't read too big. */
  .about-creed { margin-bottom: 8px; }
  .about-section:first-of-type { padding-top: 12px; }
  /* Hungarian compound words can exceed phone column widths. Use hyphens:
     auto (lang-aware via document.documentElement.lang = 'hu') so the
     browser inserts hyphens at proper syllable boundaries instead of the
     previous word-break: break-word which forced character-level splits. */
  .about-creed { hyphens: auto; -webkit-hyphens: auto; overflow-wrap: normal; }
  .about-kicker { margin: 80px auto 64px; }

  /* Work hero — fit phone. */
  .work-intro { padding: 84px var(--shell) 32px; }
  /* Tighten the gap between the title and the logo marquee inside the
     work-intro — the default 56px top margin reads too airy on mobile. */
  .work-intro .logo-marquee { margin-top: 24px; }

  /* Case detail hero. */
  .case-hero { padding: 84px var(--shell) 0; min-height: auto; }
  /* Cover bleeds out to the viewport edges AND sits flush against the
     case-strip below — no gap. */
  .case-cover {
    aspect-ratio: 4/5;
    max-height: 56vh;
    margin: 0 calc(-1 * var(--shell));
    align-self: auto;
  }

  /* Case strip — tighter padding on phones. */
  /* Mobile: stack each meta item on its own line with a horizontal divider
     between them — matches the original deployed treatment. */
  .case-strip {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 0;
    margin-bottom: 24px;
    font-size: 11px;
    text-align: center;
  }
  .case-strip-item {
    padding: 14px 0;
    border-bottom: 1px solid var(--rule);
  }
  .case-strip-item:last-of-type { border-bottom: 0; }
  .case-strip-sep { display: none; }

  /* Sections: 44px desktop top/bottom padding adds up to ~88px of dead
     air between adjacent sections on a phone. Halve it. */
  .case-section { padding: 24px var(--shell); }

  /* Contact form — bigger tap targets, smaller fonts. */
  .together { padding: 84px var(--shell) 16px; }
  .field input, .field textarea, .field-select-toggle {
    font-size: clamp(18px, 4.4vw, 22px);
    min-height: 44px;
    padding: 12px 0;
  }
  .field-select-option { padding: 14px 18px; }
  .field-select-toggle { padding: 12px 24px 12px 0; }

  /* Team — match new mobile rhythm. Smaller top so it sits closer to the
     contact phone number above it (was 84px, the gap read too large). */
  .team { padding: 24px var(--shell) 0; }
  .leads { gap: 14px; }
  .crew-grid { gap: 18px; }

  /* Eyebrows — tiny but legible. */
  .eyebrow { font-size: clamp(11px, 2.6vw, 12px); }
  .rule { width: 36px; margin-right: 10px; }
}

/* Small phone (~320–480px) — final tightening for case-strip. */
@media (max-width: 480px) {
  .case-strip-item { padding: 12px 0; }
}

/* Hide the Tweaks panel on phones — desktop-only convenience. */
@media (max-width: 768px) {
  .tweaks-panel, .twk { display: none !important; }
  .top-rail-group { display: none !important; }
  .top-burger { display: flex !important; }
  /* Native horizontal snap on touch — the desktop wheel handler does its own
     scrollTo on wheel/key, so on mobile we hand control back to the browser. */
  .h-track { scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch; }

  /* Touch-mode photo treatments. On a phone there is no hover, so the
     case-row covers, case-detail hero, and about-section photos would
     otherwise stay permanently in their grayscale `scale(1.03)` resting
     state. Land them on the hover/active visuals instead, and drop the
     transitions so a fast scroll doesn't run filter+transform tweens. */
  .case-row .case-img .img,
  .case-cover .img,
  .about-section-img .img {
    filter: none;
    transform: scale(1);
    transition: none;
  }
  /* Case-row covers were 4/5 (portrait-tall) on phones — each row consumed
     nearly a full screen of vertical space. Landscape 3/2 keeps the cover
     prominent without dominating the list. */
  .case-row .case-img { aspect-ratio: 3/2; }
  /* Case-detail hero cover: cap height tighter on phones so the title +
     eyebrow above remain readable without scrolling. */
  .case-cover { aspect-ratio: 3/2; max-height: 50vh; }
  /* About-section images: 16/10 was fine, but center the body underneath
     them with consistent top breathing room. */
  .about-section-img { aspect-ratio: 16/10; margin-top: 20px; }
}

/* Big Shoulders Display has no italic face loaded, so emphasised words inside
   titles — the hero word is wrapped in <em> — would otherwise get a synthetic
   (faked) slant. The font effect marks the root with data-display-noitalic for
   that option; keep title emphasis upright. Body italics use Work Sans / Inter
   (real italics), so they are left alone. Placed last so it wins the
   equal-specificity tie with .case-row .case-words h2 em. */
:root[data-display-noitalic] h1 em,
:root[data-display-noitalic] h2 em,
:root[data-display-noitalic] h3 em,
:root[data-display-noitalic] h4 em,
:root[data-display-noitalic] .opener-creed em,
:root[data-display-noitalic] .about-creed em,
:root[data-display-noitalic] .about-section-title em,
:root[data-display-noitalic] .about-kicker em,
:root[data-display-noitalic] .scene-words .who em,
:root[data-display-noitalic] .foot .mark em {
  font-style: normal;
}

