@import url('/css/tokens.css');

/* ===========================================================================
   INERA CONNECTION — site.css
   The shared stylesheet. Every page of the site loads this file and nothing
   else, except the four "offer" sub-routes, which add /css/pages/offer.css.

   It grew out of prototype C, "AZ ÖSVÉNY" (The Path). The home page's system
   is described below; the page components that come after it are built from
   the same parts, so an interior page cannot drift away from the arrival.

   THE DISCIPLINE RULE
   JavaScript writes exactly one quantity: --p (a unitless 0..100 scroll
   position) and its second face --y (the same scroll offset in px). The drop
   swell, the trunk draw, the sideways daughter and the photo resolve are all
   pure CSS functions of that one number. The only motion NOT driven by it is
   the station-mark reveal, a declarative CSS view() timeline — no script, no
   observer, and it degrades to "always visible" where unsupported.

   THE END-STATE IS THE DEFAULT
   --p defaults to 100 (lit) and --y to a number larger than any document, so
   no JS, blocked script, or reduced motion all render the FINISHED page. The
   script only ever takes those values down to the live scroll position, and
   only after it has confirmed the document actually scrolls.

   STROKE WIDTHS
   Exactly four widths exist (Murray's law, ratio 0.7937): --stroke-d0 .16rem /
   --stroke-d1 .127rem / --stroke-d2 .101rem / --stroke-d3 .080rem. No other
   rule, border, outline or underline width appears anywhere below, and none
   may be introduced by a page.

   GROUNDS
   Nothing in this file hard-codes a colour for text. A block declares its
   ground (Forest / Paper / Sand) by re-pointing --ink, --ink-muted and --line;
   everything inside it then reads correctly without knowing where it sits.
   =========================================================================== */

@property --p {
  syntax: '<number>';
  inherits: true;
  initial-value: 100;
}

/* Scroll offset in pixels, from the same single callback as --p. The trunk's
   tip and the drop are anchored to a fixed line in the viewport (--tip-line),
   so the station marks — which are revealed by their own position in the
   viewport — arrive exactly as the line reaches them. */
@property --y {
  syntax: '<length>';
  inherits: true;
  initial-value: 1000000px;
}

:root {
  /* The one animated quantity, unitless so it can drive both lengths and
     opacities. Default is the LIT END-STATE: no JS, blocked script or reduced
     motion all render the finished page. */
  --p: 100;
  --y: 1000000px;
  --drop-y: calc(var(--p) * 1%);
  /* where the growing tip sits in the viewport — unused now that --tip reads
     --p directly (below), kept defined in case a future ground needs a fixed
     viewport line again. */
  --tip-line: 62svh;
  /* The tip tracks scroll PROGRESS, not a fixed line in the viewport: at
     --p:0 the line has ~zero length at the very top of `.page`, and at
     --p:100 it is the page's full height — top to bottom, on every viewport
     width, desktop and mobile alike. `--y` is still written by site.js and
     still the reduced-motion end-state's second face below, but nothing in
     this file reads it any more; it stays defined rather than removed, since
     the discipline rule (top of file) treats it as the driver's public
     contract, not dead weight. */
  --tip: calc(var(--p) * 1%);

  /* Murray's law strokes — the only widths in this stylesheet. */
  --stroke-d0: .16rem;
  --stroke-d1: .127rem;
  --stroke-d2: .101rem;
  --stroke-d3: .080rem;

  /* Layout: a left gutter the trunk lives in; text never enters it. */
  --gutter: clamp(2rem, 7vw, 5.5rem);
  --pad-start: calc(var(--gutter) + clamp(0.75rem, 3.4vw, 2.5rem));
  --pad-end: clamp(1rem, 5vw, 5rem);

  /* The drop rides the trunk. --drop-x is a constant, not an animation. */
  --drop-x: calc(var(--gutter) / 2);

  /* Ink on the dark ground. */
  --ink: var(--paper);
  --ink-muted: color-mix(in oklab, var(--paper), var(--sage) 22%);
  --rail-ink: color-mix(in oklab, var(--sand), transparent 58%);
  --line: color-mix(in oklab, var(--sand), transparent 34%);
}

/* (reduced-motion --p override removed 2026-08 — the scroll driver always runs
   and animates --p; see tokens.css for the client decision.) */

html { background: var(--forest); }

body {
  background: transparent;
  color: var(--ink);
}

/* Light blocks re-point the ink tokens; nothing below needs to know which
   ground it sits on. .page--paper is the same switch at page level — it is
   what every interior page uses. */
.on-light,
.page--paper,
.section--paper,
.section--sand {
  --ink: var(--forest);
  /* 22%, not 30%. Forest was lightened to #35432E (client, 2026-08), and every
     ink mixed FROM Forest toward Sand therefore lands lighter at the same
     percentage. The whole muted family is pulled back by 8 points so each ink
     renders where the design put it: 30->22 here, 34->26 on `.tukor`,
     26->18 and 22->14 in the Esély panel, 22->14 on the tooth band. Measured on
     the rendered page, this ink is 5.21:1 on the legal pages' linen (its
     tightest ground) and 5.80:1 on flat Paper. At the old 30% it measured
     4.32:1 on linen — below AA. */
  --ink-muted: color-mix(in oklab, var(--forest), var(--sand) 22%);
  --rail-ink: color-mix(in oklab, var(--moss), transparent 58%);
  --line: color-mix(in oklab, var(--moss), transparent 34%);
  color: var(--ink);
}

.shapes { position: absolute; width: 0; height: 0; overflow: hidden; }

/* ---------------------------------------------------------------- the ground */
/* The arrival is FLAT Forest — no wash, no bloom, no halo behind the headline.
   There is no light layer on this page at all; `--p` / `--y` now drive only the
   trunk, the drop and the sideways daughter in the Esély panel. */

.grain::before { z-index: 0; }

/* The drop itself: the brand mark, pointed at the top and full at the bottom.
   It swells 7 -> 14px and darkens Sage -> Moss -> Forest with --p, and its
   POINT is anchored to the trunk's growing tip, where the line stops — line and
   drop are one gesture, and nothing runs through or past the drop.

   It is hidden until the script confirms the page scrolls and takes over --y
   (the `js-drop` class on <html>). Without that, --y is a number larger than
   any document and a visible drop would push the document a million pixels
   tall; the finished page simply carries a whole trunk and no travelling drop,
   which is exactly what reduced motion renders too. */
.drip {
  display: none;
  position: absolute;
  z-index: 4;
  left: var(--drop-x);
  top: var(--tip);
  width: calc(11px + var(--p) * 0.10px);
  translate: -50% 0;
  pointer-events: none;
  color: color-mix(in oklab,
    color-mix(in oklab, var(--sage), var(--moss) calc(var(--p) * 1%)),
    var(--forest) calc(var(--p) * 1%));
}

.js-drop .drip { display: block; }

.drip__core {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 9 / 15;
  overflow: visible;
}

/* (reduced-motion drip-hide removed 2026-08 — the travelling drop always shows
   once the page scrolls; see tokens.css for the client decision.) */

/* Desktop is scroll-driven too, exactly like mobile: --tip reads --p directly
   (see :root above) and site.js's single ScrollTrigger runs on every viewport
   width, so there is no separate desktop end-state to pin here any more. The
   CANONICAL BREAKPOINT — 48rem (768px), mobile its complement at
   `(max-width: 47.99rem)` — still governs the mobile nav below; it just no
   longer governs the line. */

/* ---------------------------------------------------------------- the trunk */
/* One line for the whole page, thinning by Murray's law as it descends, and
   drawn only as far as the drop has travelled. Everything above the tip
   exists; everything below it has not happened yet. */

.trunk {
  position: absolute;
  /* above every section ground, including the Esély panel — the line crosses
     the stone surface rather than disappearing behind it */
  z-index: 3;
  inset: 0 auto 0 0;
  width: var(--gutter);
  height: 100%;
  overflow: visible;
  pointer-events: none;
  /* A hard stop, not a fade: the line ends exactly where the drop's point
     begins, so the drop is the end of the gesture and not a bead on a wire. */
  -webkit-mask-image: linear-gradient(to bottom,
    #000 var(--tip), transparent calc(var(--tip) + 0.5px));
          mask-image: linear-gradient(to bottom,
    #000 var(--tip), transparent calc(var(--tip) + 0.5px));
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  -webkit-mask-size: 100% 100%;
          mask-size: 100% 100%;
}

/* Sage is the one ink that reads on both grounds — but not equally well since
   Forest was lightened to #35432E. Measured on rendered pixels, the trunk went
   from 2.68:1 against the old Forest to 2.15:1 against the new one, while on
   Paper it is unchanged. It is decoration rather than text, so it fails no AA
   rule, but it is visibly weaker, and one stroke colour cannot serve both.
   So the ink is a token the PAGE'S GROUND re-points — the trunk is a child of
   `.page`, so this needs no restructuring and no second element.
     · the default is the Forest-ground ink: Sage carried 22% toward Warm Sand,
       which measures 2.72:1 on #35432E — the reading the line had before the
       palette moved. `.page--field` (the 404) is the page that takes it.
     · `.page--paper` — the home page and every interior page — keeps the
       original Sage, which is what reads on Paper (3.16:1 measured). */
:root { --trunk-ink: color-mix(in oklab,
          color-mix(in oklab, var(--sage), var(--sand) 22%), transparent 24%); }

.page--paper { --trunk-ink: color-mix(in oklab, var(--sage), transparent 24%); }

.trunk path {
  fill: none;
  stroke: var(--trunk-ink);
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

/* ---------------------------------------------------------------- page */

.page {
  position: relative;
  overflow-x: clip;
}

/* Every page that is not the arrival stands on Paper. The rows keep the footer
   at the bottom of the viewport on a page shorter than the screen, so a short
   page ends deliberately instead of leaving a strip of ground under the foot.
   (.trunk and .drip are absolutely positioned and are not grid items.) */
.page--paper {
  display: grid;
  grid-template-rows: auto 1fr auto;
  min-block-size: 100svh;
  background: var(--paper);
  /* The ground layer below is a `z-index: -1` pseudo-element, and `.page` is
     only `position: relative` — without a stacking context of its own the
     layer would paint UNDER this background instead of on it, and the texture
     would be invisible. `.section--sand` isolates for the same reason. */
  isolation: isolate;
}

/* --- the paper ground's own warmth ------------------------------------- */
/* The interior pages' Paper is not a blank sheet: it carries the same ceramic
   tooth the sand bands do, a tenth of the way. `ai-keramia` is the only grain
   here — the cracks are the Esély band's alone, and a page that whispers them
   everywhere has nothing left to say when the band arrives.
   THE SAND BANDS MUST STAY THE WARMER SURFACE. Measured on the built pages:
   the paper ground renders rgb(241,239,233), a tooth or pebble band 220-224,
   and the Esély band — whose plaster is a soft-light blend and therefore barely
   moves the value — rgb(234,229,218). Even the lightest of them is a clear step
   below the paper, and the tint moves the paper toward the sand's hue rather
   than its value, so the step reads as warmth and not as dirt.
   The sand mixed into the layer is what makes it warmth rather than grey:
   multiplying paper by a neutral grain only dulls it.
   The home page has no `.page--paper`, so none of this reaches it.
   Absolutely positioned, so it is NOT a grid item of the page's three rows. */
.page--paper::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-color: var(--sand);
  background-image:
    url('/images/tex/ai-keramia.webp'),
    url('/images/tex/ai-keramia.webp'),
    url('/images/tex/ai-keramia.webp');
  background-size: 420px;
  /* the same three offset copies the tooth-only sand bands use, and for the
     same reason — over a whole page of unbroken Paper a single tile's residual
     seam draws a 420px grid that is impossible to unsee once noticed */
  background-position: 0 0, 140px 233px, 280px 91px;
  background-repeat: repeat;
  background-blend-mode: multiply, multiply, multiply;
  mix-blend-mode: multiply;
  /* Judged at 0 / 0.05 / 0.07 / 0.09 / 0.12 against a sand band in the same
     frame. At 0.12 the Paper has gone grey and the step into a band is nearly
     gone (paper:sand 1.14:1); at 0 the Paper is a cool near-white that does not
     belong to the same material as the sand. 0.06 lands the Paper on
     #F1EEE7 with a 0.56-level tooth — warm enough to read as the same family,
     and the step into a band stays at 1.21:1 against 1.28:1 with no layer at
     all. That 0.07 of contrast is what the warmth costs, and it is worth it:
     the bands are still unmistakably the warmer surface. */
  opacity: 0.06;
}

/* --- the legal pages' ground -------------------------------------------- */
/* Long statutory text needs calm, so neither the sand nor the ceramic tooth
   goes here: the two legal pages stand on linen instead. `vaszon` is a woven
   ground with no landmark in it — nothing to look at, which is the point —
   and it is the only place on the site that texture appears.
   The file is a tileable Poly Haven scan, so it repeats at a fixed size rather
   than covering: a page of statutes can be six screens tall and a `cover`
   instance would stretch the weave into stripes.
   `brightness` lifts the flattened scan (mean 153) to a multiplier map near
   white, exactly as the sand layer's own grains were re-derived to be — this
   is a white-point correction, not a new colour. */
.page--linen::before {
  background-color: transparent;
  background-image: url('/images/tex/vaszon.webp');
  background-size: 340px;
  background-position: 0 0;
  background-blend-mode: normal;
  filter: brightness(1.56);
  opacity: 0.5;
}

/* --- the 404's field ----------------------------------------------------- */
/* Not a page with an error band on it: the whole page is one Forest field, the
   site's other deliberate pause. It takes the arrival's ground and the
   arrival's ink, so the reader who lands on a dead link lands somewhere that
   was built rather than somewhere that broke. */
.page--field {
  display: grid;
  grid-template-rows: auto 1fr auto;
  min-block-size: 100svh;
  background: var(--forest);
  isolation: isolate;
}

/* One section, and it takes the whole height the page has — otherwise a short
   404 leaves a strip of ground below the field. */
.page--field > main { display: grid; }

/* The foot is Forest on every page, and here it would repaint its own flat
   Forest over the field's grain — a visible horizontal seam across a page whose
   whole point is that it is one surface. It keeps its ink tokens (they are on
   `.foot` itself) and lets the field show through. */
.page--field > .foot { background: transparent; }

/* Bark, and only here. On a ground this dark `multiply` has nowhere to go (the
   Forest moves two levels out of 255 and the grain is invisible), so the field
   uses `overlay`: it darkens under the ridges and lightens over them, and —
   because the map is centred on mid-grey — it leaves the Forest's own value
   exactly where the palette put it. `brightness` recentres the flattened scan
   (mean 83) on 128, `contrast` gives it the travel the flatten pass took away.
   Re-measured on the rendered page after Forest was lightened to #35432E: the
   field ranges 63-74 in the green channel (1st to 99th percentile) around a
   mean of 67 — and #35432E's own green channel is 67, so the grain still
   leaves the Forest exactly where the palette put it, which is the whole point
   of `overlay` here. In luminance the field spans L=0.044 to L=0.061 about a
   median of L=0.050 (flat Forest is L=0.0497); Paper ink on its lightest
   pixel measures 8.70:1. */
.page--field::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image: url('/images/tex/kereg.webp');
  background-size: 820px;
  background-repeat: repeat;
  filter: brightness(1.54) contrast(2.4);
  mix-blend-mode: overlay;
  /* Judged at 0.50 / 0.34 / 0.22: at 0.50 the willow's diagonal ridges become a
     photograph of bark and the page reads as wallpapered; at 0.22 the grain is
     something you feel in the ground rather than something you look at, which
     is what a pause needs. The tile runs at its own 820px so the ridges stay
     the size of ridges. */
  opacity: 0.22;
}

.head,
.arrival,
.esely,
.section,
.foot {
  margin: 0;
  padding-inline: var(--pad-start) var(--pad-end);
}

/* The foot is Forest on every ground, but the trunk's ink is the ground the
   PAGE stands on (see `--trunk-ink`), so on a light page a Paper-ground line
   would cross a Forest strip at 2.15:1. The foot simply stands in front of the
   line instead — which is already what a scrolled page renders, because the
   growing tip never reaches the footer. The 404's field is one surface from top
   to bottom and keeps the line running through it. */
.page--paper > .foot { z-index: 4; }

/* ---------------------------------------------------------------- header */
/* Logo left, navigation right, on one line while there is room for one line.
   Baseline alignment does two things at once: the wordmark's foot and the menu
   labels sit on the same line, and — because the row's height is measured from
   the first baseline down — opening the Kapcsolódj disclosure grows the header
   DOWNWARD without moving the logo a pixel. */

.head {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  column-gap: clamp(1.5rem, 4vw, 3rem);
  row-gap: var(--space-s);
  padding-block: var(--space-xl) var(--space-l);
}

/* A block around the link, not the link itself: it keeps the wordmark's line
   box (and therefore the header's exact height) identical to the arrival's
   original header. */
.head__brand { flex: 0 0 auto; }

/* The wordmark is drawn outlines, not type: the CONNECTION line is the same
   width as `inera` by construction, and no font has to load for it. */
.site-logo-link {
  display: inline-flex;
  color: var(--ink);
  text-decoration: none;
}

.site-logo {
  display: block;
  height: 2.4rem;
  width: auto;
  fill: currentColor;
}

@media (max-width: 40rem) {
  .site-logo { height: 1.9rem; }
}

/* ---------------------------------------------------------------- nav */
/* Zero JavaScript, on desktop and on a phone alike. Five labels, one of them a
   native <details> disclosure — unchanged above 48rem, where the labels still
   sit in one horizontal row and nothing about the pre-existing behaviour below
   moved. Below 48rem the row is replaced by a hamburger: the same checkbox
   trick `.filter__input` already uses elsewhere on this site (see FILTER
   below), not a script. The checkbox is visually hidden but stays in
   the tab order and toggles on Space, which is its native behaviour; the
   label (`.nav__burger`) is what the reader sees and taps; the list becomes a
   Paper dropdown anchored under the header when the checkbox is checked.
   Nothing is ever hidden for good — with CSS off the list is simply static
   and always visible, exactly as it always was.

   MARKUP (copy verbatim from docs/page-skeleton.html)
     <nav class="nav" aria-label="Fő navigáció">
       <input type="checkbox" id="nav-toggle" class="nav__toggle" hidden>
       <label for="nav-toggle" class="nav__burger" aria-label="Menü">
         <span class="nav__burger-bar"></span>
         <span class="nav__burger-bar"></span>
         <span class="nav__burger-bar"></span>
       </label>
       <ul class="nav__list">
         <li class="nav__item"><a class="nav__link" href="/ismerj-meg.html">…</a></li>
         …
         <li class="nav__item">
           <details class="nav__more">
             <summary class="nav__summary">
               <span class="nav__label">Kapcsolódj</span>
             </summary>
             <ul class="nav__sub"> five <a class="nav__sublink"> — the hub
                 link (Kapcsolódj) first, then the four forms … </ul>
           </details>
         </li>
         …
       </ul>
     </nav>

   CURRENT PAGE
     top-level page   → aria-current="page" on that .nav__link
     Kapcsolódj page  → aria-current="true" on the .nav__summary,
                        aria-current="page" on the hub .nav__sublink
                        (the one pointing at /kapcsolodj.html)
     a sub-route      → aria-current="true" on the .nav__summary,
                        aria-current="page" on that .nav__sublink,
                        and `open` on the <details> so the reader lands with
                        the branch they are standing on already unfolded. */

.nav {
  flex: 0 1 auto;
  color: var(--ink);
  font-size: var(--step--1);
  letter-spacing: 0.05em;
}

.nav__list {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: flex-start;
  gap: var(--space-2xs) clamp(0.9rem, 2.2vw, 1.6rem);
  list-style: none;
  margin: 0;
  padding: 0;
}

.nav__item { margin: 0; }

/* One underline treatment for every clickable word in the menu: absent at
   rest, drawn on hover, focus, and for the page you are on. */
.nav__link,
.nav__label,
.nav__sublink {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: transparent;
  text-decoration-thickness: var(--stroke-d3);
  text-underline-offset: 0.34em;
  transition: text-decoration-color 240ms ease;
}

.nav__link:hover,
.nav__link:focus-visible,
.nav__sublink:hover,
.nav__sublink:focus-visible,
.nav__summary:hover .nav__label,
.nav__summary:focus-visible .nav__label {
  text-decoration-color: var(--line);
}

.nav__link[aria-current],
.nav__sublink[aria-current],
.nav__summary[aria-current] .nav__label {
  text-decoration-color: var(--line);
}

/* The disclosure. The default triangle is removed in every engine; disclosure
   state is carried natively by the <details> element — no visual marker
   replaces it, the submenu simply appears in place. */
.nav__more { margin: 0; }

.nav__summary {
  display: flex;
  align-items: center;
  cursor: pointer;
  list-style: none;
}

.nav__summary::-webkit-details-marker { display: none; }
.nav__summary::marker { content: ''; }

.nav__sub {
  display: grid;
  gap: var(--space-3xs);
  list-style: none;
  margin: var(--space-2xs) 0 0;
  padding: var(--space-3xs) 0 var(--space-3xs) var(--space-xs);
  border-inline-start: var(--stroke-d3) solid var(--line);
}

.nav__sublink { color: var(--ink-muted); }
.nav__sublink:hover,
.nav__sublink:focus-visible,
.nav__sublink[aria-current] { color: var(--ink); }

/* --- the burger: hidden above 48rem, the only entry below it ------------ */
/* Visually hidden the same way `.filter__input` is (see FILTER below) — NOT
   `display: none`, which is what the `hidden` attribute alone would apply,
   because that also drops the control out of the tab order. Kept focusable
   and full-size here, at every width, so a keyboard user can always reach it
   when it is the visible control; the >=48rem rule below removes it (and the
   list toggle it drives) from the page entirely once the row above it is
   what's on screen. */
.nav__toggle {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  display: block;
}

.nav__burger {
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.34rem;
  cursor: pointer;
}

.nav__burger-bar {
  display: block;
  inline-size: 1.5rem;
  block-size: var(--stroke-d3);
  background: currentColor;
  border-radius: var(--stroke-d3);
  transition: translate 240ms ease, rotate 240ms ease, opacity 240ms ease;
}

.nav__toggle:focus-visible ~ .nav__burger {
  outline: 2px solid currentColor;
  outline-offset: 4px;
}

@media (min-width: 48rem) {
  .nav__toggle,
  .nav__burger { display: none; }

  /* The submenu becomes a floating panel instead of expanding the row
     in place — opening "Kapcsolódj" no longer pushes the page content
     down. `.nav__more` is the positioning context and `.nav__sub` lifts
     out of flow onto it, so the row above it never changes height.

     It carries its own ground, exactly like the <48rem panel below does
     (see `.nav__list` under 47.99rem) — Paper background, Forest ink,
     re-pointed regardless of what the header itself is standing on.
     Two of the pages this nav ships on (`404.html`, `catalog.html`) are
     Forest-ground pages where the ambient ink is pale; without this the
     panel's text would be pale-on-Paper and unreadable. */
  .nav__more { position: relative; }

  .nav__sub {
    position: absolute;
    inset-inline-start: 0;
    inset-block-start: 100%;
    z-index: 30;
    min-width: max-content;
    margin-block: var(--space-3xs) 0;
    padding: var(--space-2xs) var(--space-s);
    border: var(--stroke-d3) solid var(--line);
    background: var(--paper);
    --ink: var(--forest);
    --ink-muted: color-mix(in oklab, var(--forest), var(--sand) 22%);
    --line: color-mix(in oklab, var(--moss), transparent 34%);

    /* Smooth, no-JS reveal: fades and eases in from a hair above its
       resting position. `@starting-style` gives the transition a "from"
       frame to animate out of even though the panel has no box at all
       the instant before `[open]` lands — without it the panel would
       simply snap to visible on the first frame. Degrades gracefully:
       a browser without `@starting-style` support just shows/hides the
       panel instantly, still as an overlay, so there is no layout jump
       either way. */
    opacity: 0;
    transform: translateY(-0.35rem);
    transition: opacity .2s ease, transform .2s ease, display .2s allow-discrete;
  }

  .nav__more[open] .nav__sub {
    opacity: 1;
    transform: none;

    @starting-style {
      opacity: 0;
      transform: translateY(-0.35rem);
    }
  }
}

@media (max-width: 47.99rem) {
  /* A real target: 2.75rem (44px) square, the accessibility floor, even
     though the three bars it draws are narrower. */
  .nav__burger {
    display: flex;
    inline-size: 2.75rem;
    block-size: 2.75rem;
    margin-inline-end: calc((2.75rem - 1.5rem) / -2);
    color: var(--ink);
  }

  /* Hidden by default; the checkbox is the only thing that reveals it, so the
     panel needs no script and no `open`/`closed` state of its own. Anchored
     to `.head` (the nearest positioned ancestor — `.nav` itself stays static)
     so `inset-inline: 0` runs the panel the full width of the header, bleeding
     past the page's own side padding rather than sitting as an inset card. */
  .nav__list {
    display: none;
    position: absolute;
    inset-inline: 0;
    inset-block-start: 100%;
    z-index: 5;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: var(--space-s) var(--pad-start) var(--space-l);
    /* A dropdown is its own ground — Paper, Forest ink — regardless of
       whether it opens over the dark arrival or an already-Paper interior
       header, so it re-points --ink/--ink-muted/--line exactly as `.on-light`
       does (see GROUNDS at the top of this file) rather than inheriting
       whatever the header behind it happens to be standing on. No shadow: the
       site draws separation with a hairline everywhere else (see `.card`,
       `.facts`), never a blur — the border above is that same drawn edge. */
    --ink: var(--forest);
    --ink-muted: color-mix(in oklab, var(--forest), var(--sand) 22%);
    --line: color-mix(in oklab, var(--moss), transparent 34%);
    color: var(--ink);
    background: var(--paper);
    border-block-start: var(--stroke-d3) solid var(--line);
  }

  .nav__toggle:checked ~ .nav__list { display: flex; }

  .nav__item {
    padding-block: var(--space-3xs);
    border-block-end: var(--stroke-d3) solid var(--line);
  }
  .nav__item:last-child { border-block-end: 0; }

  .nav__link,
  .nav__summary { padding-block: var(--space-xs); }
  .nav__link { display: block; }

  .nav__sub {
    padding-block-end: var(--space-2xs);
    padding-inline-start: var(--space-m);
  }
  .nav__sublink { display: block; padding-block: var(--space-3xs); }

  /* The three bars fold into an X — an optional nicety, not the toggle's
     mechanism (the checkbox's `:checked` state already is). */
  /* 0.42rem = the gap (0.34rem) plus one bar's own height (--stroke-d3), the
     centre-to-centre distance from the outer bars to the middle one — so
     folding them lands exactly on the middle bar's position, not past it. */
  .nav__toggle:checked ~ .nav__burger .nav__burger-bar:nth-child(1) {
    translate: 0 0.42rem;
    rotate: 45deg;
  }
  .nav__toggle:checked ~ .nav__burger .nav__burger-bar:nth-child(2) {
    opacity: 0;
  }
  .nav__toggle:checked ~ .nav__burger .nav__burger-bar:nth-child(3) {
    translate: 0 -0.42rem;
    rotate: -45deg;
  }
}

/* ---------------------------------------------------------------- arrival */

.arrival { padding-block: 0 var(--space-2xl); }

/* Words left, place right — one screen, two halves, and the picture is now the
   larger half. The photograph carries the arrival; the words keep a light
   ground of their own beside it. Nothing is laid over the picture: a scrim
   would rebuild the green field the client asked us to take away. */
.arrival__first {
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1fr);
  align-items: center;
  gap: var(--space-xl) clamp(1.25rem, 3vw, 2.75rem);
  margin-block-end: var(--space-3xl);
}

.arrival__screen {
  display: flex;
  flex-direction: column;
  min-height: min(44rem, calc(100svh - 9rem));
  padding-block: var(--space-xl) var(--space-l);
}

.whisper {
  font-size: var(--step--1);
  letter-spacing: 0.06em;
  color: var(--ink-muted);
  max-width: var(--measure-narrow);
  margin-bottom: var(--space-l);
}

/* The page title. The arrival takes the largest step on the scale and a
   tighter measure; every other page uses the step below it. */
h1 {
  font-size: var(--step-4);
  font-weight: 300;
  color: var(--ink);
  max-width: 22ch;
  margin-bottom: var(--space-m);
}

.arrival h1 {
  font-size: var(--step-5);
  max-width: 17ch;
}

.subtitle {
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-style: italic;
  color: var(--ink-muted);
  max-width: var(--measure-narrow);
  margin: 0;
}

.fold {
  margin: auto 0 0;
  padding-top: var(--space-2xl);
  font-size: var(--step--1);
  letter-spacing: 0.07em;
  color: var(--ink-muted);
  max-width: var(--measure-narrow);
}

/* The path photograph shares the first screen with the headline and runs off
   the right edge of the page. Its natural colours, at full strength. */
.ground--path {
  width: calc(100% + var(--pad-end));
  margin-inline-start: auto;
  margin-inline-end: calc(var(--pad-end) * -1);
  align-self: stretch;
  --lit-floor: 100;
  --lit-gain: 0;
}

.stance {
  display: grid;
  grid-template-columns: minmax(0, 27rem) minmax(0, 1fr);
  align-items: center;
  gap: var(--space-xl) clamp(2rem, 6vw, 5rem);
}

.stance__text { max-width: var(--measure-narrow); }

/* Home-page only. An interior page's opening paragraph is .lede. */
.lead {
  font-family: var(--font-display);
  font-size: var(--step-3);
  line-height: 1.32;
  color: var(--ink);
  max-width: 26ch;
  margin-bottom: var(--space-l);
}

.stance__line {
  font-size: var(--step-1);
  color: var(--ink);
  margin-bottom: var(--space-m);
}

.sig {
  font-size: var(--step--1);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin: 0;
}

/* ---------------------------------------------------------------- grounds */
/* Photographs are cut by flowing outlines, never boxed. On the dark ground
   they resolve as the drop passes; on the light ground they are simply lit. */

.ground { margin: 0; --lit-floor: 62; --lit-gain: 0.38; }

.ground img {
  width: 100%;
  height: auto;
  opacity: calc((var(--lit-floor) + var(--p) * var(--lit-gain)) * 1%);
}

/* Whole, uncut — the arrival's first image renders as the client's photograph,
   not a silhouette. Beside the headline it still takes the whole height of the
   screen it shares. (`#shape-sweep` stays defined below: `.ground--tukor img`
   and `ismerj-meg.css` still cut on it.) */
.ground--path img {
  height: 100%;
  min-height: 26rem;
  object-fit: cover;
  /* hold the path's mouth in the lower half of the frame and the mist above it */
  object-position: 52% 58%;
}

.ground--portrait {
  width: min(100%, 27rem);
  --lit-floor: 92;
  --lit-gain: 0.08;
}
.ground--portrait img { clip-path: url(#shape-seed); }

/* The mirror photograph carries the invitation. It sits in the right-hand
   column of `.tukor__open`, which runs to the page edge, so the picture bleeds
   off the page and only its left edge is drawn — the same lobe the arrival's
   neighbour used to carry, on the same side of the same beat. */
.ground--tukor {
  --lit-floor: 92;
  --lit-gain: 0.08;
}
/* The long S, the same hand that cuts the arrival — and for the same reason:
   it is the one cut that reads as an EDGE on a picture whose other three sides
   run off the page. (The lobe was tried here first; on a wide frame its three
   waves bite a third of the way in and eat the head out of the photograph.) */
.ground--tukor img {
  clip-path: url(#shape-sweep);
  aspect-ratio: 100 / 84;
  object-fit: cover;
  /* hold the mirror, and the reflected face in it, clear of the cut */
  object-position: 58% 46%;
}

/* --- the broken bowl, cut by hand ---------------------------------------- */
/* ONE polygon is both the clip and the shape-outside, declared once as a custom
   property so the two can never drift apart. That is the whole point: the old
   cut was a symmetrical three-lobe wave down the right side of a rectangle, and
   the text stood beside it in a rectangle of its own, so nothing about the pair
   read as hand-made. The silhouette now has no axis of symmetry at all — it
   closes to nothing over the wall at the top, opens widest at the bowl's rim
   and draws back in around its foot — and the paragraphs follow that edge and
   close underneath it.
   IT FLOATS RIGHT, not left: the left of the reading column belongs to the line
   and to the mark's twig, which points at the first words of the block. A float
   there would stand exactly where the twig lands, and it would put a moving
   left margin on running text.
   `border-box` is stated on the shape so the polygon resolves against the same
   box `clip-path` uses; left to its default the shape would resolve against the
   margin box and sit a few pixels off the picture it is supposed to trace. */
/* The source file is very tall and mostly wall; the frame closes on the ceramic
   so the float is a bowl and not a column of shadow. */

/* The Esély photograph: two hands and a mirror. The cut is the boulder — the
   fullest of the outlines, and the only one that does not take the mirror's own
   rim off at the shoulders (the arch was tried first and did exactly that).
   `multiply` marries the studio white into the plaster, so the picture stands ON
   the band rather than as a card laid over it — the treatment the stone it
   replaced carried in the same place. */
.ground--hands {
  width: min(100%, 28rem);
  --lit-floor: 100;
  --lit-gain: 0;
}
.ground--hands img {
  clip-path: url(#shape-boulder);
  mix-blend-mode: multiply;
}

/* ---------------------------------------------------------------- tükör */
/* The home page's second beat. It used to be an enumerated list of the five
   stations plus its own introduction; the client pointed out that the main menu
   already lists exactly those five pages, so the section said the same thing
   twice. It is now an invitation carried by a photograph — and the line, the
   drop and the ring-and-twig marks stay, because they were never the list's:
   they are the page's rhythm, and each mark still has words to point at.
   The ink tokens are the ones this band always carried; only the ground has
   gone, since the whole page now stands on Paper. */

.tukor {
  position: relative;
  --ink: var(--forest);
  /* 26%, not 34% — the same 8-point pull-back as every other Forest-derived
     muted ink after Forest was lightened to #35432E. Measured 5.28:1 on flat
     Paper; at 34% it measured 4.41:1, below AA. */
  --ink-muted: color-mix(in oklab, var(--forest), var(--sand) 26%);
  --rail-ink: color-mix(in oklab, var(--moss), transparent 62%);
  --line: color-mix(in oklab, var(--moss), transparent 30%);
  color: var(--ink);
}

/* --- a beat on the line -------------------------------------------------- */
/* The two-column geometry the station rows had: the first column IS the trunk's
   gutter, so the ring's gaps at 12 and 6 o'clock are where the line passes
   through the mark and the twig reaches toward the words. The block runs to the
   page edges and re-applies the end padding itself, exactly as `.station` does —
   that is what puts a mark ON the line rather than beside it.
   NOT A LIST ROW: one beat carries one block of reading, and a page carries a
   few of them, far apart. */
.beat {
  display: grid;
  grid-template-columns: var(--gutter) minmax(0, 1fr);
  align-items: start;
}

/* The mark holds the first line of its block rather than the middle of it: a
   ring floating halfway down a long paragraph points at nothing in particular. */
.beat > .mark {
  align-self: start;
  margin-block-start: 0.5rem;
}

.beat__body {
  grid-column: 2;
  padding-inline-start: clamp(0.75rem, 3.4vw, 2.5rem);
}

/* The opening: words left, the photograph right and running off the page. */
.tukor__open {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1fr);
  align-items: center;
  gap: var(--space-xl) clamp(1.5rem, 4vw, 3rem);
  padding-block: var(--space-2xl);
}

.tukor h2 {
  font-size: var(--step-4);
  color: var(--ink);
  max-width: 15ch;
  margin: 0;
}

.tukor__body,
.tukor__tail { padding-inline-end: var(--pad-end); }

/* The reading measure is the container's, not each paragraph's: a `max-width`
   on the paragraph would leave the float standing inside its box and squeeze
   the wrapped lines to nothing. */
.tukor__text { max-width: 41rem; }
.tukor__text p { max-width: none; }
.tukor__text > :last-child { margin-bottom: 0; }

.tukor__tail { padding-block: var(--space-2xl) var(--space-3xl); }

.stations__nav { position: relative; }

/* /kapcsolodj.html renders its four doors with these same classes — the hub's
   doors ARE stations on the same line — but from inside a `.section`, which
   carries the page's side padding. A station's first grid column IS the trunk's
   gutter: the ring's gaps at 12 and 6 o'clock are where the line passes through
   the mark. Left inside that padding, the marks stood clear of the line with
   nothing running through them and the door text indented a whole gutter past
   every other paragraph on the page. Pull the list back to the page edges;
   `.station` re-applies the end padding itself, exactly as on the home page. */
.section > .stations__nav {
  margin-inline: calc(var(--pad-start) * -1) calc(var(--pad-end) * -1);
}

.stations__list {
  position: relative;
  display: grid;
  grid-auto-rows: 1fr;   /* five equal rows => the trunk's splits land exactly */
  list-style: none;
  margin: 0;
  padding: 0;
}

.away path,
.mark path {
  fill: none;
  stroke: var(--line);
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

.s-d0 { stroke-width: var(--stroke-d0); }
.s-d1 { stroke-width: var(--stroke-d1); }
.s-d2 { stroke-width: var(--stroke-d2); }
.s-d3 { stroke-width: var(--stroke-d3); }

.station {
  display: grid;
  grid-template-columns: var(--gutter) minmax(0, 1fr);
  align-items: center;
  padding-inline-end: var(--pad-end);
}

/* The station mark: an open circle (two arcs, gaps at 12 and 6 where the trunk
   passes) plus the twig that reaches toward the words. Both ARRIVE as the line
   grows past this station — see the reveal block below. */
.mark {
  grid-column: 1;
  grid-row: 1;
  justify-self: center;
  align-self: center;
  width: 3.4rem;
  height: 2.1rem;
  overflow: visible;
  color: var(--line);
}

.mark__ring { transform-box: fill-box; transform-origin: center; }

.station__link {
  grid-column: 2;
  grid-row: 1;
  display: block;
  text-decoration: none;
  padding-inline-start: clamp(0.75rem, 3.4vw, 2.5rem);
  padding-block: var(--space-l);
  color: var(--ink);
}

.station__no {
  display: block;
  font-size: var(--step--1);
  letter-spacing: 0.34em;
  color: var(--ink-muted);
  margin-bottom: var(--space-2xs);
}

.station__name {
  font-size: var(--step-3);
  color: var(--ink);
  margin-bottom: var(--space-2xs);
  text-decoration: underline;
  text-decoration-color: transparent;
  text-decoration-thickness: var(--stroke-d3);
  text-underline-offset: 0.22em;
  transition: text-decoration-color 240ms ease;
}

.station__link:hover .station__name,
.station__link:focus-visible .station__name {
  text-decoration-color: var(--line);
}

.station__motto {
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-style: italic;
  line-height: 1.36;
  color: var(--ink);
  max-width: 34ch;
  margin-bottom: var(--space-s);
}

.station__desc {
  font-size: var(--step--1);
  color: var(--ink-muted);
  max-width: var(--measure-narrow);
  margin: 0;
}

/* --- the marks arrive one by one ---------------------------------------- */
/* Declarative and element-local: each mark is bound to its own position in the
   viewport, so it appears exactly as the growing line reaches it. Where
   scroll-driven animations are unsupported, or motion is reduced, the marks
   are simply there from the start — nothing is ever hidden for good. */

@keyframes ring-in {
  from { opacity: 0; scale: 0.72; }
  to   { opacity: 1; scale: 1; }
}

@keyframes twig-draw {
  from { opacity: 0; stroke-dashoffset: 42; }
  20%  { opacity: 1; }
  to   { opacity: 1; stroke-dashoffset: 0; }
}

@supports (animation-timeline: view()) {
  /* client 2026-08: the no-preference wrapper was removed so the station marks
     animate regardless of the OS reduce-motion setting. */
  .mark__ring {
    opacity: 0;
    animation: ring-in linear both;
    animation-timeline: view();
    animation-range: cover 33% cover 39%;
  }
  .mark__twig {
    opacity: 0;
    stroke-dasharray: 42;
    animation: twig-draw linear both;
    animation-timeline: view();
    animation-range: cover 36% cover 45%;
  }
}

/* --- the closing question: highlighted, and the ceramic grain is its ground */

.tukor__close {
  position: relative;
  isolation: isolate;
  font-family: var(--font-display);
  font-size: var(--step-3);
  line-height: 1.34;
  color: var(--forest);
  max-width: 40rem;
  margin: 0;
  padding: var(--space-xl) clamp(1.5rem, 4vw, 2.75rem);
  background-color: var(--sand);
  /* THE APPROVED RECIPE, RESTORED. `ai-keramia-v1` is the grain this panel was
     signed off on — the file that later became `ai-keramia.webp` was re-derived
     for the tooth-only bands' seam fix, so the original is kept here under its
     own name rather than the two surfaces sharing one file that can only serve
     one of them. Same bytes, same 420px, same blend: this panel renders exactly
     as it did. */
  background-image: url('/images/tex/ai-keramia-v1.webp');
  background-size: 420px;
  /* soft-light keeps Warm Sand warm and light while the grain still reads;
     multiply would drag the whole panel down into taupe */
  background-blend-mode: soft-light;
}

/* ---------------------------------------------------------------- esély */
/* The highlighted block. The cracked-plaster texture is its ground — visible,
   not a whisper under a gradient. The trunk disappears behind it; one daughter
   leaves sideways and never rejoins. */

.esely {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 28rem);
  align-items: center;
  gap: var(--space-xl) clamp(2rem, 6vw, 5rem);
  padding-block: var(--space-3xl);
  color: var(--forest);
  /* THE APPROVED RECIPE, RESTORED. The cracked plaster: ONE soft-light pass —
     noticeable at a scroll, never a decoration. (Two passes read as too strong;
     `multiply` drags the panel into taupe.) A single soft-light pass lifts the
     ground slightly, so the base is dropped 3% toward Forest to land the panel
     back on Warm Sand.
     One cover-sized instance, never tiled: a repeat shows its own seams and the
     plaster stops reading as a surface.
     NO SECOND MATERIAL UNDER IT. The ceramic tooth belongs to the bands that
     carry no landmark; stacked under the cracks it read as marble with paper
     laid over it — two surfaces where the panel is one. */
  background-color: color-mix(in oklab, var(--sand), var(--forest) 3%);
  background-image: url('/images/tex/ai-repedes.webp');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  background-blend-mode: soft-light;
}

/* Raised above the trunk (z-index:3) and the `.away` daughter it sits beside
   (position:absolute, z-index:auto, inside the same `.esely` stacking
   context) so the vertical/sideways line no longer crosses the writing on
   desktop. `.away` still reads: its path runs wider than `.esely__text`'s
   measure and travels above/beside the copy, not only underneath it. */
.esely__text { position: relative; z-index: 4; max-width: var(--measure); }

.away {
  position: absolute;
  left: var(--drop-x);
  top: clamp(3rem, 7vw, 6rem);
  width: min(76%, 34rem);
  height: clamp(3.5rem, 9vw, 7rem);
  pointer-events: none;
  -webkit-mask-image: linear-gradient(to right,
    #000 calc((var(--drop-y) - 58%) * 2.9),
    transparent calc((var(--drop-y) - 58%) * 2.9 + 10%));
          mask-image: linear-gradient(to right,
    #000 calc((var(--drop-y) - 58%) * 2.9),
    transparent calc((var(--drop-y) - 58%) * 2.9 + 10%));
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  -webkit-mask-size: 100% 100%;
          mask-size: 100% 100%;
}

.away path { stroke: color-mix(in oklab, var(--moss), var(--sand) 22%); }

.esely__eyebrow {
  font-size: var(--step--1);
  letter-spacing: 0.3em;
  text-transform: uppercase;
  /* 18%, not 26% — 8-point pull-back after Forest was lightened to #35432E.
     Measured 5.17:1 on the interior pages' Esély plaster (its darkest ground);
     at 26% it measured 4.28:1, below AA. */
  color: color-mix(in oklab, var(--forest), var(--sand) 18%);
  margin: 0 0 var(--space-m);
}

.esely h2 {
  font-size: var(--step-4);
  color: var(--forest);
  max-width: 18ch;
  margin-bottom: var(--space-l);
}

.esely__body {
  color: var(--forest);
  max-width: var(--measure-narrow);
}

.esely__act { margin: var(--space-l) 0 var(--space-m); }

/* The branch button: the frame is a drawn stem, stroked in the same widths as
   everything else on the page. It never closes — the gap at the lower left is
   the same "process, not closure" motif as the rings on the line. */
.branch-btn {
  position: relative;
  display: inline-block;
  padding: 0.95rem 2.4rem;
  font-size: var(--step-1);
  color: var(--forest);
  text-decoration: none;
  isolation: isolate;
}

.branch-btn__frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  z-index: -1;
  pointer-events: none;
}

.branch-btn__frame path {
  fill: none;
  stroke: color-mix(in oklab, var(--moss), transparent 28%);
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
  transition: stroke 240ms ease;
}

/* THE FRAME HAS NO TWIGS (client, 2026-08). The three small offshoot strokes
   that grew off the drawn border are switched off here, in the shared
   stylesheet, rather than page by page: the same SVG is copied into every page
   that ends on this button, and one rule is the only way all of them change
   together. The frame, the gap where it never quite closes, and the hover /
   focus behaviour are untouched. New markup should simply leave the three
   `.s-d3` paths out — see docs/component-catalogue.md. */
.branch-btn__frame .s-d3 { display: none; }

.branch-btn__label { display: block; }

.branch-btn:hover .branch-btn__frame path,
.branch-btn:focus-visible .branch-btn__frame path { stroke: var(--moss); }

.esely__quiet,
.esely__safety {
  font-size: var(--step--1);
  /* 14%, not 22% — 8-point pull-back after Forest was lightened to #35432E. */
  color: color-mix(in oklab, var(--forest), var(--sand) 14%);
  max-width: var(--measure-narrow);
  margin: 0 0 var(--space-2xs);
}

.esely__safety { letter-spacing: 0.05em; margin: 0; }

/* ---------------------------------------------------------------- footer */
/* The foot is Forest on every page, so it carries the dark-ground ink tokens
   itself rather than inheriting whatever ground it happens to follow. */

.foot {
  position: relative;
  padding-block: var(--space-2xl) var(--space-xl);
  background: var(--forest);
  --ink: var(--paper);
  --ink-muted: color-mix(in oklab, var(--paper), var(--sage) 22%);
  --rail-ink: color-mix(in oklab, var(--sand), transparent 58%);
  --line: color-mix(in oklab, var(--sand), transparent 34%);
  color: var(--ink-muted);
  font-size: var(--step--1);
}

.foot__nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-m);
  margin-bottom: var(--space-m);
}

.foot__nav a {
  color: var(--paper);
  text-decoration: underline;
  /* 50%, not 62%. This underline is Sand held at low alpha over the Forest
     foot, so lightening Forest closed the gap between them: at 62% it measures
     2.54:1, and it measured 2.87:1 before Forest moved — under 3:1 in both
     cases, so this was already failing and the colour change made it worse.
     50% measures 3.31:1. The link text itself is Paper at 9.66:1 either way;
     this only makes the underline that marks it as a link actually visible. */
  text-decoration-color: color-mix(in oklab, var(--sand), transparent 50%);
  text-decoration-thickness: var(--stroke-d3);
  text-underline-offset: 0.28em;
  transition: text-decoration-color 240ms ease;
}
.foot__nav a:hover,
.foot__nav a:focus-visible { text-decoration-color: var(--sand); }

.foot__copy {
  color: color-mix(in oklab, var(--paper), var(--sage) 22%);
  margin-bottom: var(--space-2xs);
  max-width: none;
}
.foot__legal {
  color: color-mix(in oklab, var(--paper), var(--sage) 22%);
  margin: 0;
  max-width: none;
  letter-spacing: 0.02em;
}

/* ---------------------------------------------------------------- narrow */

@media (max-width: 58rem) {
  .arrival__first,
  .stance,
  .tukor__open,
  .esely { grid-template-columns: minmax(0, 1fr); }

  .arrival__first { gap: var(--space-l); }
  /* Stacked, the words come first and the photograph follows — so the block of
     type has to END inside the first screen, or the arrival is type only and
     the picture that now carries it is a scroll away. Measured at 390x800 with
     the header wrapped to two rows: the photograph opens about 200px above the
     fold. The fold line keeps its air, just less of it. */
  .arrival__screen {
    min-height: min(24rem, calc(100svh - 24rem));
    padding-block: var(--space-l) var(--space-s);
  }
  .fold { padding-top: var(--space-xl); }
  /* Stacked, the photograph is simply itself again — no stretch, no crop. */
  .ground--path img { height: auto; min-height: 0; object-fit: fill; }
  .stance { align-items: start; }
  .ground--portrait { width: min(84%, 24rem); }
  .ground--hands { width: min(80%, 22rem); margin-inline-start: auto; }
  .tukor__open { padding-block: var(--space-2xl); }
}

/* Phones: a photograph is the width of the screen. Every picture bleeds
   through the page's side padding rather than sitting as a small inset.
   (`.ground--tukor` is not in the list: its column already runs to both page
   edges, so a negative margin would push it off the screen.) */
@media (max-width: 40rem) {
  .ground--path,
  .ground--portrait,
  .ground--hands {
    width: calc(100% + var(--pad-start) + var(--pad-end));
    margin-inline-start: calc(var(--pad-start) * -1);
    margin-inline-end: calc(var(--pad-end) * -1);
  }
  /* No float on a phone: a 320px column has no room to wrap around anything,
     and a text that wrapped there would be four words wide. The bowl becomes a
     full-width picture, still cut by the same hand. */
  .mark { width: 2.4rem; }
  /* The middle beat loses its mark here, and only here. A mark is only a mark
     if it has words beside it. Above 40rem the bowl is floated, so that beat
     opens with `Gyerekkorodban tele voltál kérdésekkel.` and the ring points at
     it. At 40rem and below the float is off (see `.ground--bowl` above), the
     picture becomes a full-bleed block at the top of the beat, and the first
     line of reading drops roughly a screen further down — leaving the ring and
     its twig pointing into blank paper beside the bowl's cut-away silhouette.
     Measured at 390 and 320: the twig ended ~470px above the first word.
     The other two marks are untouched; the trunk still runs past this one. */
  .tukor__body > .mark { display: none; }
  .station__link { padding-block: var(--space-m); }
}

@media (max-width: 24rem) {
  .arrival h1 { max-width: none; }
  .station__no { letter-spacing: 0.22em; }
}

/* ===========================================================================
   PAGE COMPONENTS
   Everything below is for the pages that are not the arrival. They are built
   from the same four stroke widths, the same two typefaces and the same three
   grounds, so an interior page cannot drift away from the home page.
   =========================================================================== */

/* ---------------------------------------------------------------- sections */
/* A band of the page. It carries the side padding that keeps text out of the
   trunk's gutter, and — in its ground modifiers — re-points the ink tokens the
   way .tukor and .esely do for the arrival. */

.section { position: relative; padding-block: var(--space-3xl); }

.section--tight { padding-block: var(--space-2xl); }

.section--paper { background: var(--paper); }

.section--sand {
  /* Warm Sand. What lies on it depends on the band — the ceramic tooth for a
     band with no landmark, the cracked plaster for `#inera-esely`. Both need a
     stacking context of their own so a `z-index: -1` layer lands on this
     background instead of under it. */
  isolation: isolate;
  background-color: var(--sand);
  /* The textured band's field is a few percent darker than flat Warm Sand, so
     the muted ink the light grounds share does not clear AA against it and this
     band always needs its own, darker one. Re-measured on the rendered page
     after Forest was lightened to #35432E: the tooth band's ground reads
     L=0.703 at the median and L=0.676 at the 1st percentile (inside a crack),
     against L=0.765 for flat Warm Sand — so the band is the darkest light
     ground on the site and sets the floor for the whole muted family.
     14% is what clears it: 5.28:1 measured against that 1st-percentile ground.
     The old 22% now measures 4.37:1 there — below AA — which is why this value
     drops by the same 8 points as every other Forest-derived muted ink. It is
     still the same ink the Esély panel uses for its quiet lines, so the sand
     grounds all agree, exactly as before. */
  --ink-muted: color-mix(in oklab, var(--forest), var(--sand) 14%);
}

/* ------------------------------------------------------- the sand ground */
/* Warm Sand carries two different jobs, and they are NOT the same recipe.

   · The INERA Esély surfaces — `.tukor__close` and `.esely` on the home
     page, `#inera-esely` on the two interior pages that tell that story — wear
     the approved plaster: ONE image, `background-blend-mode: soft-light`, on
     the element's own background. Nothing lies under it. That look was signed
     off by the client and is not a dial to turn.
   · Every OTHER sand band is a quiet ground with no landmark on it, and takes
     the ceramic tooth as a `::after` layer (below).

   The two must not be merged. Stacking the tooth under the cracks was tried
   and rejected: the speckle reads through the crack network as a second
   material, so the panel looks like marble with paper laid over it instead of
   one plastered wall.

   ONE GRAIN, ONE JOB.
   · ai-keramia — the tooth. Uniform speckle with no landmark in it, made
     seamless and its own slow density drift divided out, so it TILES at a
     fixed 420px. That is the point: the grain is the same size on a 300px band
     as on a 900px one, which `cover` could never promise. Every sand band gets
     the tooth, and a much fainter mix of it is the warmth on the interior
     pages' paper ground (see `.page--paper::before`).
   · a landmark lies where the tooth is NOT, one `cover`-sized instance, never
     tiled, because a landmark that repeats reads as wallpaper. Two exist, and
     each belongs to exactly one place:
       · ai-repedes, the cracked plaster — the INERA Esély surfaces ONLY (the
         home page's two, and `#inera-esely` on the two interior pages that tell
         that story). It is the signature; if it turned up on every band it
         would stop meaning anything. It is the whole material there: no tooth
         under it.
       · kavics, the pebbles — the four service pages' WhatsApp band, the
         ground underfoot at the point where contact is decided. It lies on the
         tooth, on its own layer, because a soft `cover` stone cannot camouflage
         a tile seam the way a crack network can. */

/* Everything a tooth-bearing sand band shares: where the layer sits and how it
   meets the ground. What goes IN it is the rule after this one. */
.section--sand::after {
  content: '';
  position: absolute;
  inset: 0;
  /* behind the copy, in front of the ground — so it multiplies the sand and
     nothing else. The hosts all open a stacking context of their own. */
  z-index: -1;
  pointer-events: none;
  background-repeat: repeat;
  mix-blend-mode: multiply;
}

/* --- a band with no landmark: the tooth alone ---------------------------- */
/* THREE OFFSET COPIES OF THE SAME TILE, NOT ONE, and this is a fix rather than
   an effect. `ai-keramia` tiles almost seamlessly — its edge means match to
   0.05 of a level — but "almost" is measured against a band that has cracks
   lying across it. With the tooth alone the ground is otherwise perfectly
   uniform, and the eye locks onto the residual: the rendered band stepped 4-5
   levels at every tile edge, a visible 420px grid across ismerj-meg, kapcsolodj
   and utravalo (measured: worst row-range 5.87 levels, worst edge jump 5.17).
   Three copies at incommensurate offsets, each a third of the weight, put every
   copy's seam inside another copy's interior: worst row-range 2.17, worst edge
   jump 1.53 — under the speckle's own noise floor, so there is no grid left to
   see. The mean depth is unchanged (217.9 against the single layer's 217.8), so
   these bands sit exactly where they sat; what the averaging costs is grain,
   which drops to 0.53 of the single layer's. That is the right way round: the
   INERA Esély band stays the most textured surface on the site, and a band with
   nothing lying on it is quieter than the one that carries the signature.
   `#inera-esely` cancels this layer outright — see below. */
.section--sand::after {
  background-image:
    url('/images/tex/ai-keramia.webp'),
    url('/images/tex/ai-keramia.webp'),
    url('/images/tex/ai-keramia.webp');
  background-size: 420px;
  background-position: 0 0, 140px 233px, 280px 91px;
  background-blend-mode: multiply, multiply, normal;
  opacity: 0.104;
}

/* --- the interior pages' INERA Esély band: the home panel's plaster ------- */
/* `amiben-melletted-allok` and `egyesulet` carry the same story as the home
   page's Esély panel, so they stand on the same material and take it the same
   way: the crack network on the element's own background, one cover-sized
   instance, `soft-light`, the 3% drop toward Forest that lands the panel back
   on Warm Sand. Identical to `.esely` above, character for character.
   The tooth is cancelled, not overridden — these bands carry a landmark, and
   the speckle beneath it turned one surface into two. */
#inera-esely.section--sand {
  background-color: color-mix(in oklab, var(--sand), var(--forest) 3%);
  background-image: url('/images/tex/ai-repedes.webp');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  background-blend-mode: soft-light;
}

/* THE ONE PLACE THIS BAND IS ALLOWED TO DIFFER FROM THE HOME PANEL, and only
   in how hard the cracks are pressed — never in what the material is.
   On the home page the panel is read between two Forest sections: the eye
   arrives having just left near-black, and the sand alone announces the
   surface. Here the band sits in a run of Paper, a 1.11:1 step, and the crack
   network measures 5.2 levels of travel below its own field. At 1280 that just
   reads; at 390, where `cover` crops the network to a single column of it,
   it does not — the band goes back to being a slightly warmer rectangle, which
   is the complaint this band started with.
   SAME FILE, PRESSED HARDER. The layer is the crack image blended with ITSELF
   (`multiply`), which is the same picture at higher contrast — no second
   material, no filter, no new colour — and that is soft-lit onto the band.
   Squaring lands the layer's field near soft-light's own neutral point, so the
   band's VALUE barely moves while the crack cores dig: measured on the rendered
   band, field 228.1 -> 228.8 (the home panel is at 228.0) and crack travel
   5.2 -> 9.7 levels.
   Judged against the home panel side by side at 0 / 0.45 / 0.70 / 1.00, at both
   widths: 1.00 (travel 15.1) and 0.70 (12.2) read as a more weathered wall than
   the home panel, which is exactly what must not happen; 0 does not read at
   390. 0.45 is the smallest setting where the plaster reads as plaster on a
   phone, and it holds the band within a level of the home surface. */
#inera-esely.section--sand::after {
  background-image:
    url('/images/tex/ai-repedes.webp'),
    url('/images/tex/ai-repedes.webp');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  background-blend-mode: multiply;
  mix-blend-mode: soft-light;
  opacity: 0.45;
}

/* --- the four service pages' contact band: pebbles ----------------------- */
/* The pebbles are a SECOND layer, on their own `::before`, rather than a second
   image inside the tooth's `::after`. Two reasons, both measured. The band then
   keeps the three-copy tooth above, so it has no tile grid in it — the pebbles
   are far too soft at `cover` scale to camouflage a seam the way the Esély
   band's cracks do, and on a single-copy tooth the 420px grid was plainly
   visible across the band. And `kavics` needs a filter that the tooth must not
   get: it is the flattened Poly Haven scan at mean 134 against the tooth's 221,
   so multiplied raw it would drop the band 13 % below the Esély panel and read
   as a darker beige rather than as stone. `brightness` is the white-point
   correction the file never got, and on its own element it reaches only the
   pebbles.
   The two layers together put the band at 0.949 of the Warm Sand. The Esély
   panel takes its plaster as a soft-light BLEND rather than a multiply layer,
   so it sits at 0.998 of Warm Sand — the blend redistributes the channels
   (blue +5 levels) instead of dropping the value. The two grounds are not the
   same effect at two strengths: this one is stone pressed into the sand, that
   one is plaster the light has been worked across.
   No colour is introduced: the scan is greyscale. */
.section--pebble::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image: url('/images/tex/kavics.webp');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  filter: brightness(1.81);
  mix-blend-mode: multiply;
  opacity: 0.28;
}

/* The band opens on the button, so the button's own step down from the text
   above it is the band's padding and not an extra one. (A page whose copy puts
   a sentence before the button keeps that step — there the gap is between the
   sentence and the button, which is where it belongs.) */
.section--sand > .bough + .act { margin-block-start: 0; }

.section--forest {
  background: var(--forest);
  --ink: var(--paper);
  --ink-muted: color-mix(in oklab, var(--paper), var(--sage) 22%);
  --rail-ink: color-mix(in oklab, var(--sand), transparent 58%);
  --line: color-mix(in oklab, var(--sand), transparent 34%);
  color: var(--ink);
}

/* A heading that stands on its own in a .section, outside .prose. These rules
   set nothing the arrival's own headings do not already set for themselves —
   in particular no margin-top — so the home page is untouched by them. */
h2 {
  font-size: var(--step-3);
  color: var(--ink);
  margin-bottom: var(--space-m);
}

h3 {
  font-size: var(--step-1);
  color: var(--ink);
  margin-bottom: var(--space-s);
}

.section > h2 { max-width: 22ch; }

/* ---------------------------------------------------------------- pageintro */
/* The standard opening of every page that is not the arrival:
     .whisper (the station motto) → optional eyebrow → <h1> → .lede */

.pageintro { margin-block-end: var(--space-2xl); }

.pageintro .whisper { margin-bottom: var(--space-m); }

.pageintro__eyebrow {
  font-size: var(--step--1);
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin: 0 0 var(--space-m);
}

.pageintro h1 { margin-bottom: var(--space-m); }

/* The Cormorant opening paragraph. Valid inside .pageintro and inside .prose.
   (.lead is the arrival's; do not use it on an interior page.) */
.lede {
  font-family: var(--font-display);
  font-size: var(--step-2);
  line-height: 1.4;
  color: var(--ink);
  max-width: 34ch;
  margin: 0 0 var(--space-m);
}

/* ---------------------------------------------------------------- prose */
/* Long-form body. Poppins at the reading measure, Cormorant for the headings
   and the lede, generous leading, and no rule anywhere that is not one of the
   four stroke widths. */

.prose {
  max-width: var(--measure);
  color: var(--ink);
}

.prose p {
  max-width: var(--measure);
  margin: 0 0 var(--space-m);
}

.prose > :last-child { margin-bottom: 0; }

.prose h2 {
  font-size: var(--step-2);
  color: var(--ink);
  max-width: 26ch;
  margin: var(--space-xl) 0 var(--space-s);
}

.prose h3 {
  font-size: var(--step-1);
  color: var(--ink);
  max-width: 30ch;
  margin: var(--space-l) 0 var(--space-2xs);
}

.prose > :is(h2, h3):first-child { margin-block-start: 0; }

.prose ul,
.prose ol {
  list-style: none;
  max-width: var(--measure);
  margin: 0 0 var(--space-m);
  padding-inline-start: var(--space-m);
}

.prose li {
  position: relative;
  margin-bottom: var(--space-2xs);
}

/* The list marker is a drawn hairline, not a bullet — the same gesture as the
   station twig, at word scale. */
.prose ul > li::before {
  content: '';
  position: absolute;
  inset-inline-start: calc(var(--space-m) * -1);
  inset-block-start: 0.82em;
  inline-size: 0.62em;
  border-block-start: var(--stroke-d2) solid var(--line);
}

/* The ordered list needs a wider rail than the drawn dash: the number is set
   in the station's tracking and must not crowd the first word. */
.prose ol {
  counter-reset: prose-count;
  padding-inline-start: var(--space-l);
}
.prose ol > li { counter-increment: prose-count; }
.prose ol > li::before {
  content: counter(prose-count, decimal-leading-zero);
  position: absolute;
  inset-inline-start: calc(var(--space-l) * -1);
  font-size: var(--step--1);
  letter-spacing: 0.18em;
  color: var(--ink-muted);
}

.prose blockquote {
  margin: var(--space-l) 0;
  padding-inline-start: var(--space-m);
  border-inline-start: var(--stroke-d2) solid var(--line);
  font-family: var(--font-display);
  font-style: italic;
  font-size: var(--step-1);
  line-height: 1.42;
  color: var(--ink);
}

.prose blockquote p { margin-bottom: var(--space-2xs); }
.prose blockquote > :last-child { margin-bottom: 0; }

.prose a {
  text-decoration: underline;
  text-decoration-color: var(--line);
  text-decoration-thickness: var(--stroke-d3);
  text-underline-offset: 0.22em;
  transition: text-decoration-color 240ms ease;
}
.prose a:hover,
.prose a:focus-visible { text-decoration-color: currentColor; }

.prose strong { font-weight: 400; }

/* ---------------------------------------------------------------- pull */
/* A Cormorant italic pull-quote, set wider than the reading measure so it
   breaks the column deliberately. No quotation marks: the type is the mark. */

.pull {
  font-family: var(--font-display);
  font-style: italic;
  font-size: var(--step-3);
  line-height: 1.34;
  color: var(--ink);
  max-width: min(100%, 34ch);
  margin: var(--space-xl) 0;
  padding: 0;
  border: 0;
}

.pull p {
  font: inherit;
  max-width: none;
  margin: 0 0 var(--space-2xs);
}

.pull > :last-child { margin-bottom: 0; }

.pull cite {
  display: block;
  font-family: var(--font-body);
  font-style: normal;
  font-size: var(--step--1);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin-block-start: var(--space-s);
}

/* ---------------------------------------------------------------- facts */
/* Short factual rows — forma / kinek szól / hogyan indul. Hairline separators
   only, drawn in --stroke-d3. There is no price row in this design. */

.facts {
  display: grid;
  grid-template-columns: minmax(7rem, 13rem) minmax(0, 1fr);
  max-width: var(--measure);
  margin: var(--space-l) 0;
  border-block-end: var(--stroke-d3) solid var(--line);
}

.facts dt {
  grid-column: 1;
  padding-block: var(--space-s);
  border-block-start: var(--stroke-d3) solid var(--line);
  font-size: var(--step--1);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.facts dd {
  grid-column: 2;
  margin: 0;
  padding-block: var(--space-s);
  padding-inline-start: var(--space-m);
  border-block-start: var(--stroke-d3) solid var(--line);
  color: var(--ink);
}

@media (max-width: 40rem) {
  .facts { grid-template-columns: minmax(0, 1fr); }
  .facts dt {
    grid-column: 1;
    padding-block: var(--space-s) 0;
  }
  .facts dd {
    grid-column: 1;
    padding-block: var(--space-2xs) var(--space-s);
    padding-inline-start: 0;
    border-block-start: 0;
  }
}

/* ---------------------------------------------------------------- cards */
/* The Útravaló index. No box, no shadow, no filled button: a card is an icon,
   a kind + date line, a title that is the link, and two or three sentences —
   held together by one drawn hairline above it. */

.card-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-l) clamp(1.5rem, 4vw, 3rem);
  list-style: none;
  margin: 0;
  padding: 0;
}

@media (min-width: 40rem) {
  .card-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 68rem) {
  .card-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding-block-start: var(--space-m);
  border-block-start: var(--stroke-d2) solid var(--line);
}

/* Monoline, one width per icon, in the same drawing system as the spine.
   stroke and stroke-width are inherited properties, so they reach into the
   <use> shadow tree — which is why the icons carry no classes of their own. */
.card__icon {
  inline-size: 1.75rem;
  block-size: 1.75rem;
  overflow: visible;
  color: var(--line);
  fill: none;
  stroke: currentColor;
  stroke-width: var(--stroke-d2);
  stroke-linecap: round;
  stroke-linejoin: round;
  margin-block-end: var(--space-s);
}

.card__icon--fine { stroke-width: var(--stroke-d3); }

.card__meta {
  font-size: var(--step--1);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin: 0 0 var(--space-2xs);
  max-width: none;
}

.card__title {
  font-size: var(--step-1);
  color: var(--ink);
  margin: 0 0 var(--space-2xs);
}

.card__link {
  text-decoration: underline;
  text-decoration-color: transparent;
  text-decoration-thickness: var(--stroke-d3);
  text-underline-offset: 0.22em;
  transition: text-decoration-color 240ms ease;
}

/* The whole card is the target; there is exactly one link inside it. */
.card__link::after {
  content: '';
  position: absolute;
  inset: 0;
}

.card__link:hover,
.card__link:focus-visible { text-decoration-color: var(--line); }

.card:hover .card__icon,
.card:focus-within .card__icon { color: var(--ink-muted); }

.card__excerpt {
  font-size: var(--step--1);
  color: var(--ink-muted);
  margin: 0;
  max-width: 42ch;
}

/* ---------------------------------------------------------------- filter */
/* A category filter with no JavaScript: radio inputs, sibling combinators, and
   nothing hidden that a reader could not reach. With CSS off, every card is
   visible and the labels are plain text. */

.filter {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2xs) var(--space-m);
  border: 0;
  margin: 0 0 var(--space-l);
  padding: 0;
  min-inline-size: 0;
}

.filter__input {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.filter__label {
  cursor: pointer;
  font-size: var(--step--1);
  letter-spacing: 0.08em;
  color: var(--ink-muted);
  text-decoration: underline;
  text-decoration-color: transparent;
  text-decoration-thickness: var(--stroke-d3);
  text-underline-offset: 0.34em;
  transition: text-decoration-color 240ms ease, color 240ms ease;
}

.filter__label:hover { text-decoration-color: var(--line); }

.filter__input:checked + .filter__label {
  color: var(--ink);
  text-decoration-color: var(--line);
}

/* The visually-hidden input keeps its focus ring by lending it to its label. */
.filter__input:focus-visible + .filter__label {
  outline: 2px solid currentColor;
  outline-offset: 4px;
}

.filter .card-grid,
.filter__empty { flex: 1 0 100%; }

.filter .card-grid { margin-block-start: var(--space-m); }

/* Hide what the chosen category is not. No :has(), no script. */
#f-iras:checked ~ .card-grid .card:not([data-kind="iras"]),
#f-video:checked ~ .card-grid .card:not([data-kind="video"]),
#f-podcast:checked ~ .card-grid .card:not([data-kind="podcast"]) {
  display: none;
}

/* The empty-category line. CSS cannot count cards, so put this element in the
   markup ONLY for a category that genuinely has none; it then appears exactly
   when that category is chosen. */
.filter__empty {
  display: none;
  font-size: var(--step--1);
  color: var(--ink-muted);
  margin: var(--space-m) 0 0;
}

#f-iras:checked ~ .filter__empty[data-kind="iras"],
#f-video:checked ~ .filter__empty[data-kind="video"],
#f-podcast:checked ~ .filter__empty[data-kind="podcast"],
#f-mind:checked ~ .filter__empty[data-kind="mind"] {
  display: block;
}

/* ---------------------------------------------------------------- the close */
/* Every page that ends on the WhatsApp button ends the same way: the button's
   own row, then one or two quiet lines, the last of which is the 112 safety
   line. This used to be four near-identical copies — .journey-act/.journey-note
   in journey.css, .offer__act/.offer__note in offer.css, .probono-*, and
   .egyesulet__* — one per page stylesheet, because a page loads only its own.
   They are one component and now live here.

   MARKUP
     <p class="act">…<a class="branch-btn">…</a></p>
     <p class="quiet">Jelenleg online dolgozom, így nem számít, hol élsz.</p>
     <p class="quiet quiet--safety" role="group"
        aria-label="Vészhelyzeti tájékoztatás">… hívd a <a href="tel:112">112</a>-t.</p>

   The safety line ALWAYS carries role="group" with that aria-label: aria-label
   is ignored on a bare <p>, so without the role the label never surfaces.

   (.esely__act / .esely__quiet / .esely__safety above are the home page's own
   copy of this block. index.html is client-approved and frozen, so they stay
   where they are; the values here are theirs.) */

.act { margin: var(--space-xl) 0 0; }

/* The button reads the ground it stands on rather than assuming Forest ink. */
.act .branch-btn { color: var(--ink); }

.quiet {
  font-size: var(--step--1);
  color: var(--ink-muted);
  max-width: var(--measure-narrow);
  margin: var(--space-m) 0 0;
}

/* The 112 line takes the same faint tracking everywhere on the site. */
.quiet--safety { letter-spacing: 0.05em; }

/* A quiet line that hands back to running text keeps its own breathing room:
   .prose carries no top margin of its own, so without this the paragraph
   after it would butt straight against it. */
.quiet + .prose { margin-block-start: var(--space-2xs); }

/* Inside the INERA Esély band the two lines stack tight, exactly as they do in
   the home page's own Esély panel — the band has to read identically on all
   three pages that carry it (index, /amiben-melletted-allok, /egyesulet). */
#inera-esely .quiet { margin-block: 0 var(--space-2xs); }
#inera-esely .quiet--safety { margin-block-end: 0; }

/* On /egyesulet.html the band has no button between the prose and the quiet
   line, so the gap the button's row would have opened is restored here. */
#inera-esely .prose + .quiet { margin-block-start: var(--space-l); }

/* ---------------------------------------------------------------- crumb */
/* The quiet way back from a sub-route. */

.crumb {
  font-size: var(--step--1);
  letter-spacing: 0.06em;
  color: var(--ink-muted);
  margin: 0 0 var(--space-m);
  max-width: none;
}

.crumb a {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: transparent;
  text-decoration-thickness: var(--stroke-d3);
  text-underline-offset: 0.3em;
  transition: text-decoration-color 240ms ease, color 240ms ease;
}

.crumb a:hover,
.crumb a:focus-visible {
  color: var(--ink);
  text-decoration-color: var(--line);
}

/* ---------------------------------------------------------------- subbrand */
/* Live text, never the drawn logo: the wordmark SVG stays the master lockup.
   The tracking is the lockup's — inera +250, the word +420. */

.subbrand {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.55em;
  font-size: var(--step--1);
  color: var(--ink-muted);
  margin: 0 0 var(--space-s);
  max-width: none;
}

.subbrand__mark {
  font-weight: 200;
  text-transform: lowercase;
  letter-spacing: 0.25em;
}

.subbrand__word {
  text-transform: uppercase;
  letter-spacing: 0.42em;
}

/* ---------------------------------------------------------------- bough */
/* THE DRAWN BRANCH, as a component.
   The home page's `.away` — the line that leaves the trunk at the top of the
   Esély panel and sweeps sideways with one offshoot — generalised so any band
   on any page can carry it. `.away` itself is untouched above: that one is the
   arrival's, index.html is client-approved, and it stays exactly as it is.

   WHERE IT STARTS
   The left edge is `--drop-x`, the exact x of the trunk's hairline, and every
   path begins at x=0 of its viewBox — so the branch GROWS OUT of the spine
   rather than floating next to it. That is the whole motif; do not move it
   inboard, and do not put it on a block that is not full-page-width.

   HOW IT SITS
   Absolutely positioned inside the band (`.section` is already `position:
   relative`), and small enough to live inside the band's top padding — its top
   offset plus its height stays under `--space-2xl`, the smallest block padding
   a band can have (`.section--tight`). So it never displaces, overlaps or
   crowds text, in a 200px band or a 900px one. `pointer-events: none` keeps it
   out of every hit area and out of text selection; `aria-hidden` on the element
   keeps it out of the accessibility tree and the tab order (an <svg> is not
   focusable anyway, and `focusable="false"` covers old Edge).

   HOW IT ARRIVES
   The same left-to-right mask `.away` uses, driven by the same single scroll
   variable — nothing new is animated and no script of its own exists. The
   mapping is deliberately generous (drawn by roughly half the page): a
   component that may sit anywhere cannot know where on the page it will land,
   and a branch drawn a little early is a decoration, while a branch that never
   draws is a bug. With `--p` at its default 100 — no JS, blocked script, a page
   too short to scroll, or reduced motion — the mask sits far past the right
   edge and the branch renders whole.

   COLOUR
   One declaration for all three grounds: `--ink` is re-pointed by whichever
   ground the band declares, so the stroke lands as moss-on-sand / moss-on-paper
   on a light band and as a warm off-white on a Forest one, without the
   component knowing where it sits. No new colour: both ends of the mix are
   locked palette tokens.

   MARKUP (copy verbatim, first child of the band)
     <svg class="bough bough--sweep" viewBox="0 0 400 64" preserveAspectRatio="none"
          aria-hidden="true" focusable="false">
       <path class="s-d1" d="M0 5C46 7 92 15 140 26C186 36 236 46 292 50C330 53 364 54 396 53"/>
       <path class="s-d3" d="M140 26C168 34 190 44 214 60"/>
     </svg>

     <svg class="bough bough--rise" viewBox="0 0 260 64" preserveAspectRatio="none"
          aria-hidden="true" focusable="false">
       <path class="s-d2" d="M0 59C22 57 46 49 80 40C114 31 166 21 254 15"/>
       <path class="s-d3" d="M80 40C93 45 103 52 111 62"/>
     </svg>

   One bough per band, and not on two consecutive bands. */

.bough {
  position: absolute;
  left: var(--drop-x);
  top: clamp(1rem, 2.2vw, 1.6rem);
  pointer-events: none;
  /* drawn left to right by the one scroll number, exactly as `.away` is */
  -webkit-mask-image: linear-gradient(to right,
    #000 var(--bough-draw),
    transparent calc(var(--bough-draw) + 9%));
          mask-image: linear-gradient(to right,
    #000 var(--bough-draw),
    transparent calc(var(--bough-draw) + 9%));
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  -webkit-mask-size: 100% 100%;
          mask-size: 100% 100%;
  /* A floor of 26% is deliberate: at the very top of a page `--p` is still ~0,
     and a band there would otherwise carry nothing at all. The stem always
     leaves the trunk and fades out into the ground; scrolling extends it. */
  --bough-draw: max(26%, (var(--drop-y) - 6%) * 2.1);
}

.bough path {
  fill: none;
  /* 34%, not 42% — the same 8-point pull-back. On a light ground `--ink` IS
     Forest, so this stroke lightened with it: at 42% it measured 2.75:1 on the
     tooth band, under the 3:1 a non-text stroke needs. 34% measures 3.32:1
     there and 3.69:1 on the Esély plaster, and renders the same grey-green the
     stroke had before Forest moved. */
  stroke: color-mix(in oklab, var(--ink), var(--sand) 34%);
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

/* The long one: leaves the trunk high, falls across the band and settles almost
   flat, with one offshoot that drops away and never rejoins — the home page's
   gesture, at band scale. `.bough` is never used without one of the two
   variants: the variant carries the size. */
.bough--sweep {
  width: min(70%, 30rem);
  height: clamp(2.5rem, 4.8vw, 3.5rem);
}

/* The short one: the same hand, the other way round — it lifts as it goes and
   the offshoot drops. Half the reach, and a later draw, so two bands in a row
   never read as one stamp. */
.bough--rise {
  width: min(38%, 13rem);
  height: clamp(2.5rem, 4.8vw, 3.5rem);
  --bough-draw: max(22%, (var(--drop-y) - 14%) * 1.9);
}

/* Phones: the band's own padding is smaller, and so is the reach. The branch
   stays inside the top padding and well clear of the right edge. */
@media (max-width: 34rem) {
  .bough { top: 0.85rem; }
  .bough--sweep { width: min(74%, 15rem); height: 2.25rem; }
  .bough--rise { width: min(50%, 9.5rem); height: 2.25rem; }
}
