/* -------------------------------------------------------------------------- */

:root {
    /* ============================================================
       Palette (Tweaks panel can override via inline style)
       ============================================================ */
    --ink: #efece6;
    --ink-soft: #8b8680;
    --line: #2a2826;
    --bg: #0e0d0c;
    --card: #161513;

    /* ============================================================
       Phase progress vars — all written from JS, all 0..1.
       p1, p2:       A↔B split + side text
       pBC/pCD/pDE:  segment progress for B→C, C→D, D→E
       pLift/pShift: D→E sub-phases (lift, then shift-left-for-wordmark)
       pShrink:      D→E scale-down to the state-E small-logo size
       p3:           final reveal (wordmark + Kontaktuje nás)
       ============================================================ */
    --p1: 0;
    --p2: 0;
    --pBC: 0;
    --pCD: 0;
    --pDE: 0;
    --pLift: 0;
    --pShift: 0;
    --pShrink: 0;
    --p3: 0;

    /* ============================================================
       Per-element channels for the two enlarged halves
       side : 0 at rest, 1 fully off the relevant viewport edge
       pull : 0 at rest, 1 fully translated to the assembled-logo offset
       ============================================================ */
    --bigR-side: 1; --bigR-pull: 0;
    --bigL-side: 1; --bigL-pull: 0;

    /* ============================================================
       Tuning knobs — edit these to retune the whole choreography
       without hunting through transform calcs.
       ============================================================ */
    /* Vertical lift applied to the state-E cluster (logo + wordmark
       + Kontaktuje nás). Single knob for the "rise into final pose". */
    --e-lift: 12vh;
    /* Horizontal shift applied to the assembled logo when the wordmark
       reveals to its right. Capped in px on wide screens. */
    --e-shift-x: min(12vw, 180px);
    /* Vertical anchor (as % of viewport height) for the "Kontakt + email"
       block in state E (wide mode only — narrow mode positions this
       relative to the wordmark via a max() formula). Decrease to bring
       the Kontakt block closer to the wordmark; increase to push it
       further down. Effective center sits at (--e-contact-y − --e-lift). */
    --e-contact-y: 80%;
    /* Horizontal anchor (left%) for the wordmark in state E (wide mode
       only). The wordmark element's `left:` reads this; narrow mode
       centres the wordmark and ignores this token.
       The wordmark SVG has a large left margin inside its viewBox
       (viewBox starts at x=1601, content starts ~x=2010), so the
       element edge sits well to the left of the visible "N" — values
       in the low-50s look fine in practice. Reduce to bring the
       wordmark closer to the logo (smaller gap); increase to push it
       further right. At 50.5% the "N" sits a hair off the logo's
       right rim on a wide viewport. */
    --e-wordmark-x: 50.5%;

    /* ===========================================================
       Big halves coordinate space — derived from state A
       ===========================================================
       Both state A (small assembled logo, .logo-wrap + .part-* with
       percentages inside a square box) and states C–E (big halves
       sliding in from viewport edges, vh-based) share ONE conceptual
       100% × 100% logo box. State A uses the box directly via CSS
       percentages on .part-*; states C–E project the same box into vh
       via --logo-box-h so the halves can also be addressed in vw/vh
       for the slide-in physics.
       Every offset, height and shrink-correction below is derived
       from the EXACT percentages used by .part-* in styles/hero.css.
       Change --big-half-h to scale the whole composition; the
       proportions stay locked to state A automatically.
       ----------------------------------------------------------- */

    /* Big-half natural height in landscape side-by-side mode. This is
       the user-facing scale knob — everything else cascades. */
    --big-half-h: 80vh;
    /* Conceptual 100% × 100% logo box, in vh. Equals --big-half-h ÷
       part-left's height fraction (91.59%) so the big halves match the
       state-A box exactly. */
    --logo-box-h: calc(var(--big-half-h) / 0.9159);   /* ≈ 87.35vh @ 80vh */

    /* How far each big half is inset from its viewport edge at rest in
       states C / E (so the smiley/clock breathe instead of bleeding off
       the rim). Increase to tighten the layout; decrease for drama. */
    --big-half-inset: 3vw;
    /* Slide-in pull (viewport-anchored, not box-anchored — the halves
       come from viewport edges in states C/D, so this can't live in
       logo-box space). */
    --big-pull-r: calc(50vw - 40vh - var(--big-half-inset));
    --big-pull-l: calc(50vw - 40vh - var(--big-half-inset));
    /* Final scale the big halves reach at state E (= small-logo size /
       big-half-h). 0.32 ≈ 26vh / 80vh, matching the small logo at its
       state-E scale of 0.82. */
    --big-final-scale: 0.32;

    /* --- Geometry-pure tokens (everything derives from state-A %s) ---
       Each percentage below matches .part-* in hero.css verbatim:
         clock  (.part-left)   centre x: (3.81 + 43.46/2)% = 25.54%
         mast   (.part-middle) centre x: (17.83 + 36.44/2)% = 36.05%
                               centre y: (24.32 + 45.90/2)% = 47.27%
         smiley (.part-right)  centre x: (17.83 + 77.71/2)% = 56.69%
       Offsets-from-logo-centre = (centre% − 50%) × --logo-box-h.
       Shrink corrections = offset × (1 − final-scale), since each
       element scales around its own centre. */
    --big-middle-h:           calc(var(--logo-box-h) *  0.4590);          /* mast height fraction */
    --big-middle-dx:          calc(var(--logo-box-h) * -0.1395);          /* 36.05% − 50% */
    --big-middle-dy:          calc(var(--logo-box-h) * -0.0273);          /* 47.27% − 50% */
    --big-shrink-dx-mid-pure: calc(var(--logo-box-h) *  0.0949);          /* 0.1395 × (1 − 0.32) */
    --big-shrink-dy-mid:      calc(var(--logo-box-h) *  0.01856);         /* 0.0273 × (1 − 0.32) */
    --big-shrink-dx-l:        calc(var(--logo-box-h) *  0.1663);          /* 0.2446 × (1 − 0.32), clock centre at 25.54% */
    --big-shrink-dx-r-pure:   calc(var(--logo-box-h) *  0.04549);         /* 0.0669 × (1 − 0.32), smiley centre at 56.69% */

    /* --- Perceptual mast-gap nudge (state-E only) ---
       The visible bar inside part-middle's SVG sits at viewBox x =
       442.98 → 512.38 of a 546.53-wide box — that is 81% → 94% across,
       not centred. With pure geometry the bar's left edge lands ON
       the clock arc's right ink and the bar's right edge lands INSIDE
       the smiley arc's left ink. At state A's scale the resulting
       hairline overlaps are sub-pixel and read as "touching"; at
       state E's smaller scale the same proportional overlap visually
       merges the bar into both arcs, killing the gap that should be
       visible. Push the mast a hair right and the smiley a hair
       further right so a clear gap appears on both sides at state E
       without affecting state A. Set --mast-shift / --smiley-shift to
       0 to fall back to pure geometry. */
    --mast-shift:   1.31vh;   /* mast bar nudged right at state E (clock↔mast gap ≈ 1.0vh) */
    --smiley-shift: 2.03vh;   /* smiley arc nudged right at state E (mast↔smiley gap ≈ 1.0vh) */

    /* State-A counterparts. Same perceptual fix applied to the small
       .part-* elements in their own logo-wrap coordinate system — the
       SVG bar in part-middle sits at 81–94% across its box, so the
       hairline clock↔mast and mast↔smiley gaps are sub-pixel at
       --logo-w sizes too. Expressed in % of logo-wrap (which is
       sized by --logo-w). Tuned so the ABSOLUTE pixel gap matches
       state E (~1vh ≈ 10px at typical desktop, where --logo-w lands
       near 50vh ≈ 540px → 2% of logo-wrap ≈ 10.8px). Set both to 0
       for the original SVG-pinned layout. */
    --mast-shift-a:   1.0%;
    --smiley-shift-a: 2.0%;

    --big-shrink-dx-mid: calc(var(--big-shrink-dx-mid-pure) + var(--mast-shift));
    --big-shrink-dx-r:   calc(var(--big-shrink-dx-r-pure)   - var(--smiley-shift));

    /* Background-mode opacity for narrow / portrait viewports. The big
       half drops to this when at rest in state C/D (10% backdrop), then
       ramps back to 1.0 across D→E. */
    --bg-half-opacity: 0.1;

    /* ============================================================
       Mobile-tunable tokens (wide-mode defaults; overridden in
       styles/narrow.css under the @media blocks).

       Edit narrow.css to retune the mobile presentation. The phone
       breakpoint is `(max-width: 760px)` — keep it consistent with
       MOBILE_QUERY in scripts/hero-scroll.js.
       ============================================================ */
    /* Assembled-logo width (state A/B). Mobile bumps this up so the
       logo doesn't disappear into a phone viewport.
       50vh makes the state-A mark commanding on desktop and shrinks
       the visual jump into the state-C big halves — see the margin
       math in hero.css (K = 0.50, V = 0.18 → ~9.4% edge-to-half
       margin, still positive so the halves never crash the nav/hint). */
    --logo-w: clamp(160px, min(50vw, 50vh), 640px);
    /* Side text typography (state B). Mobile sizes are smaller. */
    --story-fs-h2: clamp(18px, min(2.7vw, 4vh), 36px);
    --story-fs-p:  clamp(11px, min(0.95vw, 1.7vh), 15px);
    /* "Kontakt" heading under the wordmark (state E). */
    --below-h3-fs: clamp(28px, 2.6vw, 44px);
  }

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

  html, body {
    background: var(--bg);
    color: var(--ink);
    font-family: "Barlow", system-ui, sans-serif;
    font-weight: 400;
    -webkit-font-smoothing: antialiased;
    line-height: 1.4;
  }

  /* ---- global page chrome ---- */
  .nav {
    position: fixed;
    top: 0; left: 0; right: 0;
    z-index: 50;
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 28px 48px;
    pointer-events: none;
    mix-blend-mode: difference;
    color: #fff;
  }
  .nav .word {
    font-size: 18px;
    font-weight: 500;
    letter-spacing: 0.28em;
    text-transform: uppercase;
  }

  /* ---- page reveal cover: solid bg colour over everything, faded out
         by scripts/hero-scroll.js once fonts + load have settled. Sits
         above the vignette (z 9999) so the page stays uniformly dark
         during load instead of showing the vignette gradient first. */
  .page-cover {
    position: fixed;
    inset: 0;
    z-index: 10000;
    background: var(--bg);
    pointer-events: none;
    transition: opacity 600ms ease;
  }
  .page-cover.is-hidden { opacity: 0; }

  /* ---- always-on vignette (cinematic edge darkening) ----
         The radial gradient interpolates alpha over ~200 8-bit steps
         across a huge viewport, which produces visible concentric
         rings (gradient banding) on calibrated screens. Two
         non-destructive fixes layered together:
         (1) `in oklab` requests perceptual-space interpolation (CSS
             Color L4; ~93% browser support) so steps land more
             evenly than in default sRGB.
         (2) `filter: blur(2px)` smears the hard step boundaries
             into sub-pixel ramps — directly attacks the rings
             without painting any noise on top of the page. Increase
             the radius if rings still show on your display; the
             vignette is broad enough that even 4–6px stays crisp.
             Cost is one cheap GPU pass on a static layer. */
  body::after {
    content: "";
    position: fixed;
    inset: 0;
    pointer-events: none;
    z-index: 9999;
    background: radial-gradient(ellipse 85% 75% at 50% 50% in oklab, rgba(0,0,0,0) 35%, rgba(0,0,0,0.78) 100%);
    filter: blur(2px);
  }

  /* ---- always-on dissolve grain (inspired by codepen vYxYomx) ----
         Noise is generated in-browser via inline SVG feTurbulence — no
         network round-trip and ~400 bytes vs. a multi-MB PNG, so the
         grain is present the instant the page-cover fades. The 200px
         tile repeats across the oversized container; the dissolve
         animation keeps shifting the tile grid so the texture still
         feels alive. baseFrequency tunes grain coarseness (higher =
         finer); numOctaves tunes complexity (higher = costlier). */
  .bg-dissolve {
    position: fixed;
    top: -100%; left: -100%;
    width: 300%; height: 300%;
    /* Background-layer grain only — sits behind all content. The
       vignette de-bands itself via oklab interpolation + sub-pixel
       blur on body::after, so this layer is purely decorative film
       texture and shouldn't overlay readable text. */
    z-index: 0;
    pointer-events: none;
    background-image: url("../assets/images/noise.svg");
    background-repeat: repeat;
    opacity: 0.15;
    animation: dissolveGrain 24s steps(10) infinite;
    will-change: transform;
  }
  @keyframes dissolveGrain {
    0%,100% { transform: translate(0, 0); }
    10% { transform: translate(-3%, -6%); }
    20% { transform: translate(-9%, -12%); }
    30% { transform: translate(-3%, -6%); }
    40% { transform: translate(-9%, -12%); }
    50% { transform: translate(-3%, -6%); }
    60% { transform: translate(-9%, -12%); }
    70% { transform: translate(-3%, -6%); }
    80% { transform: translate(-9%, -12%); }
    90% { transform: translate(-3%, -6%); }
  }

