/* REGISTER (direction atelier) for sc08: palette ink-champagne, type frank-ruhl-libre over assistant, labels assistant.
   Written by engine/directions.py; never edited by hand. */
:root {
  --ink: #0b1015;
  --ink-2: #111921;
  --ink-deep: #010408;
  --paper: #faf6ee;
  --accent: #d6b98a;
  --accent-deep: #0d1721;
  --line: #989285;
  --shadow: #000000;
  --gr-light: #f5f1e9;
  --gr-light-fg: #0b1015;
  --gr-light-accent: #0d1721;
  --gr-light-pop: #0d1721;
  --gr-light-on: #faf6ee;
  --gr-dark: #0d1721;
  --gr-dark-fg: #faf6ee;
  --gr-dark-accent: #d6b98a;
  --gr-dark-pop: #d6b98a;
  --gr-dark-on: #0b1015;
  --gr-vivid: #d6b98a;
  --gr-vivid-fg: #0b1015;
  --gr-vivid-accent: #0d1721;
  --gr-vivid-pop: #0d1721;
  --gr-vivid-on: #faf6ee;
  --gr-pale: #d2e0ee;
  --gr-pale-fg: #0b1015;
  --gr-pale-accent: #0d1721;
  --gr-pale-pop: #0d1721;
  --gr-pale-on: #faf6ee;
  --font-display: "Frank Ruhl Libre", serif;
  --font-mark: "Frank Ruhl Libre", serif;
  --font-body: "Assistant", Arial, sans-serif;
  --font-label: "Assistant", sans-serif;
  --ground: var(--gr-light);
  --ground-2: color-mix(in srgb, var(--gr-light) 94%, var(--gr-light-fg));
  --ground-deep: var(--ink-deep);
  --fg: var(--gr-light-fg);
  --fg-72: color-mix(in srgb, var(--gr-light-fg) 72%, transparent);
  --fg-45: color-mix(in srgb, var(--gr-light-fg) 45%, transparent);
  --alt: var(--gr-dark);
  --alt-fg: var(--gr-dark-fg);
  --brand: var(--gr-light-accent);
  --brand-alt: var(--gr-dark-accent);
  --on-brand: var(--gr-light-on);
  --pop: var(--gr-light-pop);
  --edge: var(--line);
  --on-media: var(--paper);
  --on-media-72: color-mix(in srgb, var(--paper) 72%, transparent);
  --brand-media: var(--gr-dark-accent);
  --grain: 0.035;
  --head-relief: 0;
  --head-measure: none;
  --head-size-max: 14rem;
  --head-stagger: 0;
  --head-weight: 300;
  --head-track: -0.02em;
  --key-weight: 900;
  --mark-weight: 300;
  --kicker-track: 0.02em;
  --label-weight: 700;
  --body-weight: 400;
  --brand-weight: 700;
  --kicker-weight: 700;
  --kicker-gap: 1.4rem;
  --manifest-weight: 300;
  --manifest-size: clamp(2.4rem, 7vw, 6rem);
  --manifest-measure: none;
  --section-pad-block: clamp(5.5rem, 16svh, 9rem);
  --cta-size: clamp(3.4rem, 12vw, 11rem);
  --btn-weight: 700;
  --radius-pill: 100px;
  --radius-mark: 0;
  --motion-ease: cubic-bezier(0.22, 1, 0.36, 1);
  --motion-dur: 1.3s;
  --motion-settle: 1.6s;
}
/* each section wears its own ground; the kit's roles follow it inside */
[data-ground="light"] {
  --ground: var(--gr-light); --ground-2: color-mix(in srgb, var(--gr-light) 94%, var(--gr-light-fg));
  --fg: var(--gr-light-fg); --fg-72: color-mix(in srgb, var(--gr-light-fg) 72%, transparent);
  --fg-45: color-mix(in srgb, var(--gr-light-fg) 45%, transparent);
  --alt: var(--gr-light); --alt-fg: var(--gr-light-fg);
  --brand: var(--gr-light-accent); --brand-alt: var(--gr-light-accent); --on-brand: var(--gr-light-on);
  --pop: var(--gr-light-pop); --edge: color-mix(in srgb, var(--gr-light-fg) 26%, var(--gr-light));
}

[data-ground="dark"] {
  --ground: var(--gr-dark); --ground-2: color-mix(in srgb, var(--gr-dark) 94%, var(--gr-dark-fg));
  --fg: var(--gr-dark-fg); --fg-72: color-mix(in srgb, var(--gr-dark-fg) 72%, transparent);
  --fg-45: color-mix(in srgb, var(--gr-dark-fg) 45%, transparent);
  --alt: var(--gr-dark); --alt-fg: var(--gr-dark-fg);
  --brand: var(--gr-dark-accent); --brand-alt: var(--gr-dark-accent); --on-brand: var(--gr-dark-on);
  --pop: var(--gr-dark-pop); --edge: color-mix(in srgb, var(--gr-dark-fg) 26%, var(--gr-dark));
}

[data-ground="vivid"] {
  --ground: var(--gr-vivid); --ground-2: color-mix(in srgb, var(--gr-vivid) 94%, var(--gr-vivid-fg));
  --fg: var(--gr-vivid-fg); --fg-72: color-mix(in srgb, var(--gr-vivid-fg) 72%, transparent);
  --fg-45: color-mix(in srgb, var(--gr-vivid-fg) 45%, transparent);
  --alt: var(--gr-vivid); --alt-fg: var(--gr-vivid-fg);
  --brand: var(--gr-vivid-accent); --brand-alt: var(--gr-vivid-accent); --on-brand: var(--gr-vivid-on);
  --pop: var(--gr-vivid-pop); --edge: color-mix(in srgb, var(--gr-vivid-fg) 26%, var(--gr-vivid));
}

[data-ground="pale"] {
  --ground: var(--gr-pale); --ground-2: color-mix(in srgb, var(--gr-pale) 94%, var(--gr-pale-fg));
  --fg: var(--gr-pale-fg); --fg-72: color-mix(in srgb, var(--gr-pale-fg) 72%, transparent);
  --fg-45: color-mix(in srgb, var(--gr-pale-fg) 45%, transparent);
  --alt: var(--gr-pale); --alt-fg: var(--gr-pale-fg);
  --brand: var(--gr-pale-accent); --brand-alt: var(--gr-pale-accent); --on-brand: var(--gr-pale-on);
  --pop: var(--gr-pale-pop); --edge: color-mix(in srgb, var(--gr-pale-fg) 26%, var(--gr-pale));
}

section[data-ground] { background-color: var(--ground); color: var(--fg); }

/* THE KIT — the chrome every wow-demo shares: grain, progress, header, brand,
   buttons, the manifest and CTA sections, the footer, the scroll hint.

   ~60% of each original template was exactly this, copy-pasted, which is why a
   third vertical used to mean a third copy.

   IT NAMES NO PALETTE TOKEN. Not one rule here mentions --ink or --paper. It
   speaks only in SEMANTIC roles — --ground, --fg, --alt, --brand — and the
   register decides which palette colour plays each part. That indirection is
   the whole reason a light register is possible at all: on a dark register
   --ground is the ink and --alt is the paper; on a light one they swap, and not
   a line of this file changes. Registers own the mapping; the kit owns the page.

   Final states are the CSS defaults: with no JS the page is complete. */

/* ── MOTION TOKENS ──
   The kit owns these, not a register. A register holds colour, typography and
   rhythm (_ROLES.md); how fast a thing answers a finger is neither — it is the
   same everywhere, because the hand is the same everywhere. Two durations,
   because a touch layer has exactly two speeds: the ACKNOWLEDGEMENT, which has
   to land inside the ~100ms a person reads as "it heard me", and the SETTLE,
   the long ease back to rest that is what separates a control from a toy.
   The JS pointer layer reads these off :root rather than carrying its own
   numbers, so the two halves of one gesture can never drift apart. */
:root {
  --dur-touch: 0.18s;
  --dur-settle: 1.1s;
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --page-p: 0;        /* page progress 0..1, written by runtime.js on every scroll */
  --drift: 2.2rem;    /* how far a data-drift element travels across the screen */
}

/* --mesh is set only by a generated register in the mesh-gradient world. The
   default lives in :where(:root) - zero specificity - so the register's own
   :root wins wherever the two sheets sit in the assembled file. */
:where(:root) { --mesh: none; }
/* THE MARK. A generated register splits type in two (engine/resolve.py): the dealt
   face, when it is a costume (the Rubik display cuts, a handwriting), sets only the
   business name and single words at poster size - --font-mark - and every headline
   and sentence is set in its readable pair, --font-display. A v1 register has one
   display face, so its mark IS its display face and nothing it renders changes.
   Same for the kicker's tracking: v1 keeps its 0.33em, a generated register sets
   its own (Hebrew has no small caps to track). */
:where(:root) {
  --font-mark: var(--font-display);
  --mark-weight: var(--head-weight);
  --kicker-track: 0.33em;
}

* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: auto; }

body {
  font-family: var(--font-body);
  font-weight: var(--body-weight);
  background: var(--ground);
  color: var(--fg);
  overflow-x: hidden;
}

::selection { background: var(--brand); color: var(--on-brand); }
:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; }

img { display: block; max-width: 100%; }

h1, h2, h3, h4 { font-family: var(--font-display); letter-spacing: var(--head-track); }

/* ── film grain ── */
.grain {
  position: fixed; inset: -50%; z-index: 70; pointer-events: none;
  width: 200%; height: 200%;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
  opacity: var(--grain); mix-blend-mode: overlay;
}

/* ── scroll progress ── */
.progress {
  position: fixed; top: 0; inset-inline: 0; z-index: 80;
  height: 2px; background: var(--brand);
  transform: scaleX(0); transform-origin: 100% 50%;
}
html.reduced .progress { display: none; }

/* ── header and footer: primitives/frames/<id>/frame.css (dealt since v2) ── */
.btn {
  text-decoration: none; border-radius: var(--radius-pill); font-weight: 500;
  transition: background 0.25s ease, color 0.25s ease, border-color 0.25s ease,
              transform var(--dur-touch) var(--ease-out);
}
/* THE PRESS. A phone has no hover, so until this rule a tap on either button was
   a link that did nothing for 300ms and then navigated — the one moment on the
   page where the machine looked broken on the device it is actually opened on.
   :active fires on touch and on mouse alike, so this needs no query. .98 is
   deliberately small: the button must dip, not bounce, or the page starts
   arguing with the restraint the register is selling. */
.btn:active { transform: scale(0.98); }
@media (prefers-reduced-motion: reduce) { .btn { transition: none; } .btn:active { transform: none; } }

.btn-ghost {
  color: inherit; border: 1px solid color-mix(in srgb, currentColor 45%, transparent);
  padding: 0.5rem 1.15rem; font-size: 0.9rem;
}

/* ── split-text line masks ──
   RTL: split by WORD only. Letters break niqqud, and the overflow:hidden mask
   clips HORIZONTALLY too, so a narrow container guillotines words silently. */
/* The mask also has to leave room for a RELIEF. A headline extruded with
   text-shadow paints copies of the glyph up to ~0.05em toward +x and +y, and
   in RTL the first letter of a line sits flush against the mask's start edge —
   so the +x copies fell outside the box and the leading glyph lost its depth
   while every other letter kept it. The bleed is padding pulled back by the
   same margin: the line's width and every indent measured from its content
   edge are unchanged; only the clipping edge moves out.
   The block-end bleed is widened for the same reason: 0.09em covered a
   descender, not a descender plus its extrusion. */
.sl-line {
  overflow: hidden;
  padding-inline-start: 0.1em; margin-inline-start: -0.1em;
  padding-block-end: 0.16em; margin-block-end: -0.16em;
}

/* ── scroll hint (lives inside whatever hero moment is mounted) ── */
.scroll-hint {
  position: absolute; z-index: 6; bottom: 3.4svh; left: 50%;
  transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 0.6rem;
}
.hint-line {
  display: block; inline-size: 1px; block-size: 44px;
  background: linear-gradient(to bottom, transparent, var(--brand));
  animation: hint 2.2s ease-in-out infinite;
  transform-origin: top;
}
.hint-word { font-size: 0.67rem; letter-spacing: 0.4em; color: var(--fg-45); }
@keyframes hint { 0%, 100% { transform: scaleY(0.35); opacity: 0.4; } 55% { transform: scaleY(1); opacity: 1; } }
html.reduced .hint-line, html.reduced .scroll-hint { animation: none; }
@media (prefers-reduced-motion: reduce) { .hint-line { animation: none; } }

/* ── the kicker appears in TWO worlds ──
   Moments put it on the ground; the manifest puts it on the alt surface. On a
   dark register those are dark and light; on a light register they are light and
   dark. One colour cannot serve both, and getting it wrong is silent: pale gold
   on pale paper still renders, it just cannot be read. So it is scoped. */
.kicker {
  font-size: 0.77rem; letter-spacing: var(--kicker-track); font-weight: var(--kicker-weight);
  color: var(--brand); margin-block-end: var(--kicker-gap);
}
.manifest .kicker { color: var(--brand-alt); }

/* ── manifest ──
   Three layers: a rule along the top, a ghost word behind, the copy in front.
   The section clips its own overflow because the ghost is deliberately wider
   than the page on a phone and parallaxes past the section's edges — without
   the clip it would widen the document and break mobile. */
.manifest {
  --manifest-pad-inline: clamp(1.4rem, 8vw, 7rem);
  position: relative; overflow: hidden;
  background: var(--alt); color: var(--alt-fg);
  padding: var(--section-pad-block) var(--manifest-pad-inline);
}
.manifest .kicker, .manifest-line { position: relative; z-index: 1; }
.manifest-line {
  font-family: var(--font-display); font-weight: var(--manifest-weight);
  font-size: var(--manifest-size);
  line-height: 1.31; max-inline-size: var(--manifest-measure);
}
/* the rule draws right-to-left as the section enters (JS scrubs scaleX from 0);
   drawn is the resting state. It is --brand-alt, not --brand: it lies on the
   alt surface, and --brand is the accent as read on the GROUND — in a light
   register that is the deep tone, invisible on ink. Same scoping as the kicker. */
.manifest-rule {
  position: absolute; top: 0; inset-inline: var(--manifest-pad-inline);
  block-size: 2px; background: var(--brand-alt);
  transform-origin: 100% 50%;
}
/* the ghost: one huge display word in the edge colour, faint enough to read as
   texture. Sized in vw so it stays proportional to the page, not to the copy;
   nowrap because it is one word and must never break (a break would be a
   letter split by another name). It is positioned, so it needs an explicit
   inline-size — an absolutely positioned box shrink-wraps under any
   max-inline-size the register sets on text. */
.manifest-ghost {
  position: absolute; z-index: 0; inset-inline-start: -0.06em; top: 50%;
  inline-size: max-content; max-inline-size: none;
  transform: translateY(-50%);
  font-family: var(--font-display); font-weight: 900;
  font-size: clamp(7rem, 26vw, 24rem); line-height: 1; letter-spacing: -0.03em;
  white-space: nowrap; color: var(--edge); opacity: 0.08;
  pointer-events: none; user-select: none;
}

/* ── CTA ── */
/* THE OUTLINE WORD BELONGS TO EVERY HERO, not to one moment.
   config.json marks a word in hero.h1 with <em> and it is drawn as a brass stroke
   around an empty fill. The rule lived only in the scroll-world sheet, scoped to
   .hero-world, and a cold lead walked straight into the gap: the machine dealt it
   a line-draw hero, whose section is .hero, so the <em> got no rule at all and the
   browser did what it does with an unstyled <em> - synthesised italic. Hebrew has
   no italic; the browser SLANTS the glyphs, and a slanted Hebrew word in a 128px
   headline reads as a rendering fault, on the first screen.
   Only the base treatment moves here. Lighting the word under a finger stays in
   scroll-world, because that is the only moment with a pointer layer to light it.
   text-shadow is restated as none for the documented reason: it paints the glyph
   SHAPE whatever the fill is, so a relief stack reaching an empty letter turns the
   well into a solid dark ghost of the word. */
.hero .hero-head h1 em {
  font-style: normal;
  color: transparent;
  /* em with a 1px floor: at phone sizes 0.014em is under a pixel and the word
     would simply vanish. */
  -webkit-text-stroke: max(1px, 0.014em) var(--brand);
  text-shadow: none;
}

.cta {
  background: var(--alt); color: var(--alt-fg); text-align: center;
  padding: var(--section-pad-block) clamp(1.4rem, 6vw, 4rem);
}
.cta h2 { font-weight: var(--head-weight); font-size: var(--cta-size); line-height: 1.03; }
.cta-sub { margin-top: 1.55rem; font-size: clamp(1rem, 1.5vw, 1.15rem); color: color-mix(in srgb, var(--alt-fg) 62%, transparent); }
.cta-actions {
  margin-top: 2.7rem; display: flex; align-items: center; justify-content: center;
  gap: clamp(1.1rem, 3vw, 2rem); flex-wrap: wrap;
}
/* the solid button is the alt surface inverted — register-agnostic by construction */
.btn-solid {
  display: inline-flex; align-items: center; gap: 0.6rem;
  background: var(--alt-fg); color: var(--alt);
  padding: 1.05rem 1.9rem; font-weight: var(--btn-weight); font-size: 1.02rem;
}
/* HOVER LIVES BEHIND (hover: hover), ALWAYS.
   A touch browser keeps :hover latched on the last thing tapped until something
   else is tapped, so an ungated hover rule leaves a phone with one permanently
   inverted button and no way to clear it. Both of the kit's hovers are gated
   here, in one block, so the next one added has an obvious place to go.
   The inversion itself is unchanged: --brand-alt is by construction readable
   against --alt, which makes --alt readable on it. --on-brand here would put
   ink on accent_deep in a dark register. */
@media (hover: hover) {
  .btn-ghost:hover { background: var(--brand); border-color: var(--brand); color: var(--on-brand); }
  .btn-solid:hover { background: var(--brand-alt); color: var(--alt); }
}
.cta-phone {
  color: var(--alt-fg); font-weight: var(--btn-weight); letter-spacing: 0.055em;
  text-decoration: underline; text-underline-offset: 6px;
  text-decoration-color: var(--brand-alt);
}
.contact-note { margin-top: 1.6rem; font-size: 0.85rem; color: color-mix(in srgb, var(--alt-fg) 62%, transparent); }

/* ── v2: the phone layer ──
   The tilt chip exists only on iOS, which grants DeviceOrientation from a tap
   and never otherwise. It sits above the fold's lower edge, out of the hero's
   way, and removes itself after one answer either way. */
.tilt-chip {
  position: fixed; z-index: 75; inset-block-end: 5.2rem; inset-inline-start: 50%;
  transform: translateX(50%);
  padding: 0.55rem 1.1rem; border: 1px solid color-mix(in srgb, var(--on-media) 45%, transparent);
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--ground-deep) 72%, transparent);
  color: var(--on-media); font: inherit; font-size: 0.85rem;
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
}
/* Secondary motion that runs off the main thread: anything marked data-drift
   slides a little as it crosses the screen. Vertical pages only - a track moves
   by transform, and view() timelines only follow real scrolling. */
@supports (animation-timeline: view()) {
  html[data-chassis="vertical"] [data-drift] {
    animation: wow-drift linear both;
    animation-timeline: view();
    animation-range: entry 0% exit 100%;
  }
}
@keyframes wow-drift {
  from { transform: translateY(var(--drift)); }
  to { transform: translateY(calc(-1 * var(--drift))); }
}
@media (prefers-reduced-motion: reduce) { [data-drift] { animation: none; } }

/* ── v2 kit sections ──
   Entrances without ScrollTrigger: runtime.js writes --p (the section's own
   progress from the chassis, 0..1) on every .kit-sec, and each [data-enter]
   derives its opacity and lift from it, staggered by --i. --p defaults to 1 here,
   so with no JS or under reduced motion everything simply stands in place. */
.kit-sec {
  --p: 1;
  position: relative;
  padding: var(--section-pad-block) clamp(1.4rem, 7vw, 6rem);
  background: var(--ground); color: var(--fg);
  background-image: var(--mesh);
}
.kit-sec .sec-title {
  font-weight: var(--head-weight); line-height: 1.02; letter-spacing: var(--head-track);
  font-size: clamp(2.2rem, 5.6vw, 4.6rem); max-inline-size: 18ch;
  /* no one-word last line: "מה נכנס לזר בכל / עונה" on a phone (sc02 rehearsal) */
  text-wrap: balance;
}
.kit-sec [data-enter] {
  --i: 0;
  --e: clamp(0, (var(--p) - 0.04 - var(--i) * 0.035) * 6, 1);
  opacity: var(--e);
  transform: translateY(calc((1 - var(--e)) * 1.8rem));
}
.chassis-h.is-h .kit-sec { padding-block: 5.5rem 2.5rem; }

/* ── v2: a STAGE behind the page ──
   A stage engine (engine.json slot "stage") draws every section's ground itself,
   on one canvas fixed behind the page, and plays its pieces across all of them.
   So once it is live (html.stage-live, set by the engine after it has READ each
   section's ground) the sections stop painting their own and become glass over
   the stage. Each section keeps its own text colours: the stage paints that
   section's ground under it, so a dark manifest is still light words on dark.
   Without JS, under reduced motion or on tier none, the class never lands and the
   page is exactly the page it was. --sec-ground is the ground a section's words
   were written for; the halo on small text uses it, because a piece can drift
   behind a sentence mid-flight. */
html.stage-live #top, html.stage-live .site-footer { position: relative; z-index: 1; }
html.stage-live #top section, html.stage-live #top .eng-stage, html.stage-live .site-footer {
  background-color: transparent; background-image: none;
}
html.stage-live #top section { --sec-ground: var(--ground); }
html.stage-live #top section[data-alt], html.stage-live #top .manifest, html.stage-live #top .cta {
  --sec-ground: var(--alt);
}
/* LEGIBILITY OVER A LIVE STAGE (reworked 28.09.2026).
   Between 28.09 and 29.09 five site builds each met eye.py's LEGIBILITY gate by
   thickening a -webkit-text-stroke around the words, in a contrasting colour
   (--on-brand), 0.16em to 0.34em wide. Every number passed and every page got
   worse: the headlines read as stickers with a white outline, the small text
   sat in a blurred blob - exactly the trap the taste ledger names ("the number
   went up and the page got worse"). The rule now:
   - small text keeps a KNOCKOUT in its own section's ground (--sec-ground). On
     gather's flat fog that halo is invisible - it only shows when a piece
     drifts behind a sentence, which is when it is needed;
   - headlines never get a stroke. They carry a soft shadow in the same ground,
     invisible on a flat ground, and are made legible by the STAGE instead:
     gather leaves the words room, and day calms the photograph under the words
     (engines/day: a neutral darken or lighten plus a light blur, only where
     text sits - the photo stays a photo, never a colour field);
   - on the day stage the photo IS the ground, so small text drops the stroke
     too (a stroke on a photograph is a visible blob) and leans on the same
     calm patch plus a tighter shadow. */
html.stage-live #top .kicker, html.stage-live #top section p,
html.stage-live #top .tset .tl.is-small .tl-in, html.stage-live #top figcaption {
  -webkit-text-stroke: 0.22em var(--sec-ground); paint-order: stroke fill;
  text-shadow: 0 0 1px var(--sec-ground), 0 1px 3px var(--sec-ground),
    0 0 16px color-mix(in srgb, var(--sec-ground) 85%, transparent);
}
html.stage-live #top .tset .tl-in, html.stage-live #top .tset .kw {
  -webkit-text-stroke: 0; paint-order: normal;
  text-shadow: 0 0.02em 0.5em color-mix(in srgb, var(--sec-ground) 55%, transparent);
}
html.stage-live.stage-is-day #top .kicker, html.stage-live.stage-is-day #top section p,
html.stage-live.stage-is-day #top .tset .tl.is-small .tl-in, html.stage-live.stage-is-day #top figcaption {
  -webkit-text-stroke: 0; paint-order: normal;
  text-shadow: 0 0 2px color-mix(in srgb, var(--sec-ground) 80%, transparent),
    0 1px 10px color-mix(in srgb, var(--sec-ground) 60%, transparent);
}
/* No glow on a split headline over the day stage: each line is its own mask box
   (overflow clipped for the rise-in), so the 0.5em ground-coloured glow was cut
   at the line's edges into a hard tinted RECTANGLE behind every big word - pink
   behind sc04's "נתכנן", the box behind sc03's "פינה" (29.09.2026 review). The
   stage's own calm tone, feathered wide, does this job without an edge. */
html.stage-live.stage-is-day #top .tset .tl-in, html.stage-live.stage-is-day #top .tset .kw { text-shadow: none; }
html.stage-live #top .sec-gallery figcaption { --sec-ground: var(--ground-deep); }
html.stage-live .manifest-ghost { opacity: 0.05; }
/* On the day stage the ground under a small accent word is a photograph, and an
   accent colour sits mid-luminance - no calm patch brings a photo far enough from
   it for 4.5:1 without turning the photo into a sheet. So small accent text there
   (kickers, prices) takes the section's own ink; the accent stays on the big words. */
html.stage-live.stage-is-day #top .kicker, html.stage-live.stage-is-day #top .svc-price,
html.stage-live.stage-is-day #top .kicker * { color: var(--fg); }

/* FRAME: rail - the header turned on its side. A narrow column on the page's
   start edge (the right, in Hebrew) carries the mark, the name set vertically
   and a meter that fills with the page; the way to talk is a pill that floats at
   the end edge and never scrolls away. On a phone a column would take a fifth of
   the screen, so it folds to the mark at the top and the pill at the bottom. */
html[data-frame="rail"] .progress { display: none; }
.site-header.frame-rail {
  position: fixed; z-index: 60; inset-block: 0; inset-inline-start: 0;
  inline-size: 4.2rem; padding-block: 1.2rem;
  display: flex; flex-direction: column; align-items: center; justify-content: space-between;
  color: var(--fg); pointer-events: none;
}
.frame-rail > * { pointer-events: auto; }
.rail-mark {
  display: grid; place-items: center; inline-size: 2.4rem; block-size: 2.4rem;
  border-radius: 50%; background: var(--brand); color: var(--on-brand); text-decoration: none;
  font-family: var(--font-mark); font-weight: var(--mark-weight); font-size: 1.1rem;
}
.rail-name {
  writing-mode: vertical-rl; font-family: var(--font-mark); font-weight: var(--mark-weight);
  font-size: 0.95rem; letter-spacing: 0.12em; opacity: 0.82;
}
.rail-meter {
  position: relative; inline-size: 2px; block-size: 18vh;
  background: color-mix(in srgb, currentColor 22%, transparent);
}
.rail-meter > span {
  position: absolute; inset: 0; background: var(--brand);
  transform-origin: 50% 0; transform: scaleY(var(--page-p));
}
.rail-cta {
  position: fixed; inset-block-end: 1.1rem; inset-inline-end: 1.1rem;
  padding: 0.75rem 1.3rem; background: var(--brand); color: var(--on-brand);
  font-weight: var(--btn-weight); font-size: 0.92rem;
  box-shadow: 0 10px 30px -12px color-mix(in srgb, var(--shadow) 70%, transparent);
}
html.js .site-header.frame-rail.over-alt { color: var(--alt-fg); }
html.js .site-header.frame-rail.over-media { color: var(--on-media); }

.site-footer.frame-rail-foot {
  display: flex; flex-direction: column; align-items: flex-start; gap: 0.8rem;
  padding: 3.2rem clamp(1.4rem, 6vw, 4rem) 5.5rem;
  background: var(--ground); color: var(--fg-45); font-size: 0.8rem; letter-spacing: 0.075em;
}
.frame-rail-foot .foot-name {
  font-family: var(--font-mark); font-weight: var(--mark-weight);
  font-size: clamp(1.8rem, 6vw, 3.4rem); letter-spacing: var(--head-track); color: var(--fg);
}
@media (max-width: 767px) {
  .site-header.frame-rail {
    inset-block-end: auto; inline-size: auto; padding: 0.9rem;
    flex-direction: row;
  }
  .rail-name, .rail-meter { display: none; }
}

/* CHASSIS: vertical. v1 pages have no [data-span] and no .eng-stage, so nothing
   here reaches them. An engine section is --span screens tall and its stage
   sticks while the section scrolls past: the pin, done by CSS, so an engine never
   needs a ScrollTrigger of its own. --span is declared here as a default because
   tokens.lint_roles fails any var() the sheet never declares; the fragment's
   inline style="--span: N" wins over it. */
[data-span] { --span: 1; }
html[data-chassis="vertical"] [data-span] {
  position: relative;
  height: calc(var(--span) * 100svh);
}
html[data-chassis="vertical"] .eng-stage {
  position: sticky; top: 0;
  height: 100svh; overflow: hidden;
}


/* ── section: hero-stage ── */
/* SECTION: hero-stage - the opening's words over the stage. A screen of room for
   the stage and one block of words where it leaves space: low on a phone (the
   stage plays in the top of the screen), at the start edge on a wide screen.
   The words arrive after the stage's opening burst has begun (0.9s), so the
   first thing the eye gets is motion, then the sentence. */
.sec-hero-stage {
  min-height: 100svh;
  display: flex; flex-direction: column; justify-content: flex-end;
  padding-block: 7rem clamp(4.5rem, 13svh, 7.5rem);
}
.hs-head { position: relative; max-inline-size: 34rem; }
.hs-title {
  font-weight: var(--head-weight); line-height: 0.98; letter-spacing: var(--head-track);
  font-size: clamp(2.6rem, 7.6vw, 6.6rem); text-wrap: balance;
}
.hs-sub {
  margin-top: 1.1rem; max-inline-size: 38ch;
  font-size: clamp(1.02rem, 1.6vw, 1.25rem); color: var(--fg-72);
}
html.js:not(.reduced) .hs-head > * { animation: hs-in 1.1s var(--ease-out) both; }
html.js:not(.reduced) .hs-head > :nth-child(1) { animation-delay: 0.9s; }
html.js:not(.reduced) .hs-head > :nth-child(2) { animation-delay: 1.02s; }
html.js:not(.reduced) .hs-head > :nth-child(3) { animation-delay: 1.18s; }
@keyframes hs-in { from { opacity: 0; transform: translateY(1.4rem); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .hs-head > * { animation: none; } }
@media (min-width: 900px) {
  .sec-hero-stage { justify-content: center; }
  .hs-head { max-inline-size: min(40vw, 36rem); }
}
.chassis-h.is-h .h-track > section.sec-hero-stage { justify-content: flex-end; }
@media (min-width: 900px) { .chassis-h.is-h .h-track > section.sec-hero-stage { justify-content: center; } }


/* ── section: act-stage ── */
/* SECTION: act-stage - the words beside the stage's climax. Two screens long;
   on a vertical page the block pins for the second one, on a track the chassis
   holds (data-span). The block sits where hero-stage's did, so the stage keeps
   the same room to play in. */
.sec-act-stage { padding: 0; }
.as-pin {
  min-height: 100svh;
  display: flex; flex-direction: column; justify-content: flex-end;
  padding: 7rem clamp(1.4rem, 7vw, 6rem) clamp(4.5rem, 13svh, 7.5rem);
}
html[data-chassis="vertical"] .sec-act-stage .as-pin { position: sticky; top: 0; height: 100svh; }
.as-head { max-inline-size: 34rem; }
.as-title { font-size: clamp(2.4rem, 7vw, 6rem); }
.as-sub { margin-top: 1rem; max-inline-size: 36ch; font-size: clamp(1rem, 1.5vw, 1.2rem); color: var(--fg-72); }
@media (min-width: 900px) {
  .as-pin { justify-content: center; }
  .as-head { max-inline-size: min(40vw, 36rem); }
}
.chassis-h.is-h .h-track > section.sec-act-stage { display: block; }
.chassis-h.is-h .sec-act-stage .as-pin { height: 100%; }


/* ── section: gallery ── */
/* SECTION: gallery - the deep ground, so any photograph sits on dark and the
   captions use the media roles the register already proved against it. Three
   columns with the middle one dropped: a grid, but not a spreadsheet. On a track
   it becomes a filmstrip. No width/height attributes on the <img>: they would
   turn into a presentational height and check.py's aspect-ratio rule would fail. */
.sec-gallery { background: var(--ground-deep); color: var(--on-media); }
.sec-gallery .kicker { color: var(--brand-media); }
.gal-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(0.6rem, 1.4vw, 1.2rem); margin-top: 3rem; }
.gal-item { position: relative; overflow: hidden; }
.gal-item:nth-child(3n+2) { margin-top: 3.5rem; }
.gal-item img { inline-size: 100%; aspect-ratio: 4 / 5; object-fit: cover; }
.gal-item figcaption { margin-top: 0.6rem; font-size: 0.82rem; color: var(--on-media-72); }
@media (max-width: 767px) {
  .gal-grid { grid-template-columns: repeat(2, 1fr); }
  .gal-item:nth-child(3n+2) { margin-top: 0; }
  .gal-item:nth-child(2n) { margin-top: 2.4rem; }
}
/* ".h-track > section." - the chassis's own "every section is a centred column"
   rule (.h-track > section:not(.eng)) outranked a plain .sec-gallery, so on a
   desk the strip fell UNDER the heading and off the bottom of the screen (sc05,
   29.09.2026). */
.chassis-h.is-h .h-track > section.sec-gallery { display: flex; flex-direction: row; align-items: center; gap: 3vw; padding-inline: 6vw; }
.chassis-h.is-h .sec-gallery .sec-head { flex: 0 0 min(26rem, 30vw); }
.chassis-h.is-h .gal-grid { display: flex; gap: 1.2rem; margin: 0; }
.chassis-h.is-h .gal-item { margin: 0; }
/* On the track each photograph keeps its OWN shape (auto, with 4/5 only until it
   loads). 29.09.2026 (review: "zoom and image faults", sc04/sc05): a 16:9 photo
   forced into a 4:5 tile 52svh tall showed 45% of its width at 2.3x its own
   pixels on a phone - a nail macro became a smear of lacquer, a model house a
   corner of a wall. */
.chassis-h.is-h .gal-item img { block-size: calc(66svh - 2.2rem); inline-size: auto; aspect-ratio: auto 4 / 5; max-inline-size: 62vw; object-fit: cover; }
@media (max-width: 767px) {
  .chassis-h.is-h .h-track > section.sec-gallery { flex-direction: column; align-items: flex-start; justify-content: center; }
  .chassis-h.is-h .sec-gallery .sec-head { flex: 0 0 auto; }
  .chassis-h.is-h .gal-item img { block-size: auto; inline-size: 84vw; max-inline-size: none; max-block-size: 52svh; }
}


/* ── section: faq ── */
/* SECTION: faq - the secondary surface, two columns of questions with a plus
   that turns to a cross. Native <details>: accessible and complete without JS. */
.sec-faq { background: var(--ground-2); }
.faq-list { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0 clamp(1.6rem, 4vw, 3.4rem); margin-top: 2.6rem; max-inline-size: 72rem; }
.faq-item { padding-block: 1.2rem; border-top: 1px solid color-mix(in srgb, var(--edge) 70%, transparent); }
.faq-item summary {
  display: flex; justify-content: space-between; gap: 1rem; cursor: pointer; list-style: none;
  font-family: var(--font-display); font-weight: var(--head-weight); font-size: clamp(1.1rem, 2vw, 1.45rem);
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after { content: "+"; color: var(--brand); font-family: var(--font-body); transition: transform var(--dur-touch) var(--ease-out); }
.faq-item[open] summary::after { transform: rotate(45deg); }
.faq-item p { margin-top: 0.8rem; color: var(--fg-72); max-inline-size: 48ch; }
@media (max-width: 767px) { .faq-list { grid-template-columns: 1fr; } }
.chassis-h.is-h .sec-faq { display: flex; flex-direction: column; justify-content: center; padding-inline: 6vw; }


/* ── stage: sketch ── */
/* STAGE: sketch - one canvas behind the whole page: drafting paper, a building
   drawn on it line by line as the visitor scrolls, and the photograph of that
   building rising out of the drawing. This file is SERVED - no operator names
   in its comments (check.py). */
.stage-sketch { position: fixed; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; }
.sketch-canvas {
  position: absolute; inset: 0; inline-size: 100%; block-size: 100%; display: block;
  opacity: 0; transition: opacity 0.5s ease;
}
.stage-sketch.is-drawn .sketch-canvas { opacity: 1; }

/* the plate's caption: which project is on the sheet, docked under the header
   like the day stage's hour chip, and just as quiet */
.sketch-label {
  position: fixed; z-index: 1; top: clamp(3.6rem, 10vh, 4.6rem); left: clamp(1rem, 3vw, 2rem);
  margin: 0; padding: 0.4em 0.9em; border-radius: 999px; font: 600 0.76rem/1 var(--font-body);
  letter-spacing: 0.06em; color: var(--on-media);
  background: color-mix(in srgb, var(--ground-deep) 62%, transparent);
  opacity: 0; transition: opacity 0.5s ease; pointer-events: none;
}
.sketch-label.on { opacity: 0.92; }
/* the footer keeps its own ground over the sheet, as on the day stage */
html.stage-live.stage-is-sketch .site-footer { background-color: var(--ground); }
@media (prefers-reduced-motion: reduce) { .sketch-label { display: none; } }


/* ── direction layer ── */
/* THE DIRECTION LAYER - shared by every direction (directions/<id>.css adds the
   direction's own grammar on top). Loaded only on pages dealt a direction, so the
   v1 leads and the milestone-1 pages never see a line of it.
   Every colour is a role: inside a section the roles are that section's ground. */

/* a register from before the key weight existed sets its key in the head weight */
:where(:root) { --key-weight: var(--head-weight); --pop: var(--brand); --label-weight: 700; --font-label: var(--font-body); }

/* ── headlines set as type (direction.js composes them) ──
   Each line is its own mask: overflow hidden, with room below for the Hebrew
   descenders (ק ך ן ף ץ) pulled back by the same margin so the rhythm holds. */
.typeset .tset { max-inline-size: none; font-size: 1rem; line-height: 1; text-wrap: nowrap; }
.tset .tl {
  display: block; overflow: hidden;
  padding-block: 0.02em 0.14em; margin-block-end: -0.1em;
  padding-inline: 0.06em; margin-inline: -0.06em;
}
.tset .tl-in {
  --dx: 0px;
  display: inline-block; white-space: nowrap; line-height: 0.9;
  font-family: var(--font-display); font-weight: var(--head-weight); letter-spacing: var(--head-track);
  translate: var(--dx) 0;
  transform: translateY(0);
}
.tset .tl.is-small .tl-in {
  font-family: var(--font-body); font-weight: 700; letter-spacing: 0; line-height: 1.25;
  color: var(--fg-72);
}
.tset .tl.is-key .tl-in { color: var(--pop); font-weight: var(--key-weight); }
.tset .kw { color: var(--pop); font-weight: var(--key-weight); }
.tset em { font-style: normal; }
html.js:not(.reduced) .tset .tl-in {
  transform: translateY(108%);
  transition: transform calc(var(--motion-dur) * 1.25) var(--motion-ease) calc(var(--i) * 85ms);
}
html.js:not(.reduced) .tset.is-shown .tl-in { transform: translateY(0); }
@media (prefers-reduced-motion: reduce) { .tset .tl-in { transform: none; transition: none; translate: none; } }

/* A headline set over a moving picture carries a well of the deep ground in its
   own letters' shadow, wide enough to hold 3:1 where the picture is brightest (the
   pale window frame of a loop measured 1.72:1 without it, sc02s). The mask gets
   room above and below so the well is not cut off by it. */
.eng-loop .tset .tl { padding-block: 0.1em 0.18em; margin-block: -0.08em -0.14em; }
.eng-loop .tset .tl-in {
  text-shadow:
    0 0 0.05em color-mix(in srgb, var(--ground-deep) 72%, transparent),
    0 0.02em 0.2em color-mix(in srgb, var(--ground-deep) 62%, transparent),
    0 0 0.5em color-mix(in srgb, var(--ground-deep) 40%, transparent);
}

/* ── the preloader ──
   On the page from the first paint (so nothing is seen before it), gone without
   JS (<noscript> in page.html) and under reduced motion. */
.preloader { display: none; }
html[data-preloader] .preloader {
  position: fixed; inset: 0; z-index: 95;
  display: grid; place-items: center;
  background: var(--gr-dark); color: var(--gr-dark-fg);
  clip-path: inset(0 0 0 0);
  transition: clip-path 0.85s var(--motion-ease);
}
html[data-preloader] .preloader.pl-out { clip-path: inset(0 0 100% 0); }
.pl-in { display: grid; justify-items: center; gap: 1.2rem; }
.pl-name {
  font-family: var(--font-mark); font-weight: var(--mark-weight);
  font-size: clamp(3rem, 16vw, 11rem); line-height: 0.9; white-space: nowrap;
}
.pl-count {
  font-family: var(--font-label); font-weight: var(--label-weight); font-size: 0.9rem;
  letter-spacing: 0.08em; color: var(--gr-dark-accent); direction: ltr;
}
@media (prefers-reduced-motion: reduce) { html[data-preloader] .preloader { display: none; } }

/* ── a button leans toward the cursor (direction.js sets --mx/--my) ── */
.is-magnetic {
  --mx: 0px; --my: 0px;
  translate: var(--mx) var(--my);
  transition: translate 0.35s var(--ease-out), background 0.25s ease, color 0.25s ease;
}

/* ── labels: a direction's kickers are set in its label face ── */
html[data-direction] .kicker {
  font-family: var(--font-label); font-weight: var(--label-weight);
  font-size: 0.8rem; letter-spacing: var(--kicker-track);
}

/* The kit's gallery assumes the deep ground and colours its kicker and captions with the
   media roles (proved against dark). A direction gives the gallery a ground of its own, so
   on light or pale those roles read as nothing: hasson (30.09.2026, gallery on pale) had a
   champagne kicker at 1.4:1 and paper-white captions. The ground's own roles instead. */
html[data-direction] section[data-ground].sec-gallery .kicker { color: var(--brand); }
html[data-direction] section[data-ground].sec-gallery .gal-item figcaption { color: color-mix(in srgb, var(--fg) 78%, transparent); }
/* ...and kit.css knocks a gallery caption out in --ground-deep over a live stage: a 0.22em
   near-black stroke around dark words on pale, which read as a blot (1.08:1). */
html.stage-live[data-direction] #top section[data-ground].sec-gallery figcaption { --sec-ground: var(--ground); }


/* ── direction: atelier ── */
/* DIRECTION: atelier - quiet luxury.
   Loaded only on pages dealt this direction; roles only, every role is the
   section's ground inside it. Its grammar against the template habits:
   - a kicker over every heading   -> a short rule and a label, nothing louder
   - headlines as paragraphs        -> a light serif set to the width, one word
                                       in its black weight (direction.js, key)
   - four season cards              -> an editorial list: the season's name at
                                       poster size in the light cut, a hairline
   - three service cards            -> three arches, the price in the serif
   - motion                         -> slow; nothing arrives faster than a breath */

html[data-direction="atelier"] #top .kicker {
  display: flex; align-items: center; gap: 0.9em;
  font-family: var(--font-label); font-weight: var(--label-weight); font-size: 0.82rem; letter-spacing: 0.02em;
}
html[data-direction="atelier"] #top .kicker::before {
  content: ""; flex: 0 0 2.4em; block-size: 1px; background: currentColor; opacity: 0.8;
}
html[data-direction="atelier"] .tset .tl-in { line-height: 0.96; }

/* the opening: the arch holds the loop, the words sit under its sill */
html[data-direction="atelier"] .eng-loop .loop-head { max-inline-size: none; inset-inline: clamp(1.4rem, 7vw, 6rem); }
html[data-direction="atelier"] .eng-loop .loop-title { inline-size: min(100%, 60rem); }
html[data-direction="atelier"] .eng-loop .loop-sub { max-inline-size: 36ch; }
/* over the moving picture the key word keeps the light ink and differs by weight
   alone: a rose word on rose petals disappeared (sc02s hero) */
html[data-direction="atelier"] .eng-loop .tset .kw { color: inherit; }
/* PAST THE HERO: kit.css's own .kw halo (--on-brand glow behind --pop fill)
   is tuned for gather's flat fog and, on sc07 (day stage, lilac-dusk
   palette), still read 1.52-1.92:1 on manifest/act - short of the 3:1 its own
   size-aware floor asks for. A first attempt here forced color: inherit on
   TOP of that halo instead of replacing it - fill went to ink while the glow
   stayed tuned for --pop, and the two together rendered .kw as a solid dark
   blob (measured ~1.05:1, ink-on-ink). This is the hero's own fix (line 27),
   properly this time: ink fill AND no halo, so there is only one mechanism
   in play, the one already proven clean on this palette (sc02s, sc07's own
   check-_uw_vxf0 before kit.css grew a .kw rule of its own). */
html.stage-live[data-direction="atelier"] #top .tset .kw {
  color: inherit; -webkit-text-stroke-width: 0; text-shadow: none;
}
/* where the picture opens to the full width, the words' side of it dims - a veil
   from the start edge, not a glow around each letter: the pale curtain behind the
   first word read 1.7:1 with only the glow (sc02s, desktop) */
@media (min-width: 900px) {
  html[data-direction="atelier"] .eng-loop .loop-grade {
    background:
      linear-gradient(to left, color-mix(in srgb, var(--ground-deep) 86%, transparent) 0%,
        color-mix(in srgb, var(--ground-deep) 64%, transparent) 46%, transparent 86%),
      linear-gradient(to top, color-mix(in srgb, var(--ground-deep) 70%, transparent) 0%, transparent 48%);
  }
}

/* seasons: an editorial list, not cards; on a wide screen it keeps to the start
   two thirds and the stage lays its herbarium plate in the rest */
@media (min-width: 900px) {
  html[data-direction="atelier"] #top .sec-seasons .sec-head,
  html[data-direction="atelier"] #top .season-grid { inline-size: 62vw; }
}
html[data-direction="atelier"] #top .season-grid {
  display: grid; grid-template-columns: 1fr; gap: 0; margin-top: 2.6rem;
}
html[data-direction="atelier"] #top .season {
  display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); grid-template-areas: "name flowers" "name line";
  align-items: end; column-gap: clamp(1.4rem, 4vw, 4rem); row-gap: 0.6rem;
  min-block-size: 0; padding: clamp(1.2rem, 3vw, 2rem) 0;
  background: none; box-shadow: none; border-top: 1px solid var(--edge);
}
html[data-direction="atelier"] #top .season:last-child { border-bottom: 1px solid var(--edge); }
html[data-direction="atelier"] #top .season-name {
  grid-area: name; font-weight: var(--head-weight); letter-spacing: var(--head-track);
  font-size: clamp(3.4rem, 10vw, 8.5rem); line-height: 0.9;
}
html[data-direction="atelier"] #top .season-flowers {
  grid-area: flowers; font-family: var(--font-label); font-weight: var(--label-weight);
  font-size: 0.85rem; letter-spacing: 0.02em; color: var(--brand);
}
html[data-direction="atelier"] #top .season-line { grid-area: line; max-inline-size: 34ch; }
@media (max-width: 767px) {
  html[data-direction="atelier"] #top .season { grid-template-columns: 1fr; grid-template-areas: "name" "flowers" "line"; }
  html[data-direction="atelier"] #top .season-name { font-size: 3.6rem; }
}

/* services: three arches */
html[data-direction="atelier"] #top .svc-grid { gap: clamp(1rem, 2.4vw, 2rem); margin-top: 2.8rem; }
html[data-direction="atelier"] #top .svc {
  justify-items: center; text-align: center; align-content: start;
  padding: clamp(3rem, 6vw, 4.6rem) 1.6rem 2rem;
  border: 1px solid color-mix(in srgb, var(--fg) 40%, transparent);
  border-radius: 999px 999px 0 0;
  background: color-mix(in srgb, var(--ground) 70%, transparent);
}
html[data-direction="atelier"] #top .svc-price {
  font-family: var(--font-display); font-weight: var(--key-weight); letter-spacing: var(--head-track);
  font-size: clamp(1.8rem, 11cqi, 3.2rem); color: var(--fg);
}
html[data-direction="atelier"] #top .svc-name {
  font-family: var(--font-label); font-weight: var(--label-weight); font-size: 0.95rem; color: var(--brand);
}
html[data-direction="atelier"] #top .svc-line { max-inline-size: 26ch; color: var(--fg-72); }

/* the contact: centred, the light serif at the width, a long quiet button */
html[data-direction="atelier"] .cta { text-align: center; }
html[data-direction="atelier"] .cta .tset .tl { text-align: center; }
html[data-direction="atelier"] .contact .btn-solid {
  padding: 1.15rem 2.6rem; font-family: var(--font-display); font-weight: var(--key-weight);
  font-size: 1.15rem; letter-spacing: var(--head-track);
}
html[data-direction="atelier"] .contact-note { font-size: 0.8rem; }

/* the preloader: the name in the light serif and a hairline that draws */
html[data-direction="atelier"] .pl-count { display: none; }
html[data-direction="atelier"] .pl-name { font-weight: var(--head-weight); letter-spacing: var(--head-track); }
html[data-direction="atelier"] .pl-in::after {
  content: ""; display: block; inline-size: min(40vw, 18rem); block-size: 1px; justify-self: center;
  background: currentColor; transform-origin: 100% 50%; animation: at-line 1.1s var(--motion-ease) both;
}
@keyframes at-line { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@media (prefers-reduced-motion: reduce) { html[data-direction="atelier"] .pl-in::after { animation: none; } }
