/* src/styles/navbar.css */
/**
 * Header rules the design stylesheet cannot keep.
 *
 * Everything else about .navbar lives in the design system, where it belongs.
 * These three selectors were written there first and came back from
 * site_read_styles with "kind": "class" rather than "ambient" — Instatic 0.0.19
 * files a rule it cannot tie to a single element that way, and the publisher
 * drops it. Verified on 2026-09-13 against the summary, per rule 1 in
 * reference/instatic.md. A code stylesheet ships verbatim, so they live here.
 *
 * Scope is all-pages: the header is in the "Layout" template, which wraps every
 * page, and a page-scoped stylesheet is matched against the wrapping template
 * id and so would never link at all (rule 2).
 *
 * No `transition` is declared here on purpose. This file loads after
 * style-*.css, and a transition shorthand at this specificity would replace the
 * whole transition-property list of .navbar and kill the scheme fade (rule 12).
 */

/* Leistungen and FAQ are a desktop expansion of the four live links. The <a> is
   hidden as well as its <li>: a link inside a display:none parent still lays out
   as a zero-height box for anything walking the DOM. */
.navbar__item--wide .navbar__link {
  display: none;
}

@media (min-width: 992px) {
  .navbar__item--wide .navbar__link {
    display: inline-flex;
  }
}

/* The design system has no :focus-visible rule anywhere, so the header brings
   its own. Gold reads on mist and on the inverted forest bar alike. */
.navbar__logo:focus-visible,
.navbar__cta:focus-visible {
  outline: 2px solid var(--color-pizza);
  outline-offset: 3px;
}


/* src/styles/timeline.css */
/* Timeline (Ablauf) — the parts that depend on runtime state or on features the design
   stylesheet cannot carry.

   Scope is all-pages on purpose: Instatic matches a page scope against the id of the template that
   wraps the page, so a home-page scope on a template-wrapped page never links at all. The selectors
   below only exist on the home page, so an all-pages file costs nothing elsewhere. */

/* --- the rail fills with the scroll ------------------------------------------------------
   Where the browser has scroll-driven animations it does this itself, off the main thread. The
   49%/49% inset shrinks the scrollport to a thin band at the middle of the viewport — the line the
   rail fills to — so each segment runs from "my top is at the line" to "my bottom is at the line".
   Not 50%/50%: a zero-height scrollport is degenerate and freezes every animation at half progress.
   Browsers without it (Safari today) fall through to the script, which writes --timeline-seg. */
@supports (animation-timeline: view()) {
  .timeline__seg-fill {
    animation: timeline-rail linear both;
    animation-timeline: view(block 49% 49%);
  }
}

@keyframes timeline-rail {
  from { transform: scaleY(0); }
  to   { transform: scaleY(1); }
}

/* Only with JavaScript does the rail start empty. Without it every segment stands drawn and every
   step is in its reached state — the complete, readable picture, never a half-finished rail.
   The default belongs on the SEGMENT, not on the fill: the script writes --timeline-seg to the
   segment and the fill inherits it. Declared on the fill it would beat that inherited value and
   pin every segment at zero. */
.timeline[data-js="on"] .timeline__seg {
  --timeline-seg: 0;
}

/* --- a step the rail has reached ---------------------------------------------------------
   Plain colour and transform changes, so they reverse with the scroll direction on their own —
   no keyframes and no second animation for the way back. */
.timeline:not([data-js="on"]) .timeline__node,
.timeline__item.is-reached .timeline__node {
  border-color: var(--color-scheme-accent);
  background-color: color-mix(in srgb, var(--color-scheme-accent), transparent 88%);
  color: var(--color-scheme-accent);
}

.timeline:not([data-js="on"]) .timeline__card,
.timeline__item.is-reached .timeline__card {
  border-color: var(--timeline-reached);
}

.timeline:not([data-js="on"]) .timeline__link-fill,
.timeline__item.is-reached .timeline__link-fill {
  transform: scaleX(1);
}

@media (prefers-reduced-motion: no-preference) {
  /* armed one frame after the first pass, so steps already on screen open in their correct state
     instead of fading in from nothing. 0.35s is the value the old .timeline__dot-fill used. */
  .timeline[data-armed] .timeline__card {
    transition: border-color 0.35s ease;
  }
  .timeline[data-armed] .timeline__node {
    transition: border-color 0.35s ease, background-color 0.35s ease, color 0.35s ease;
  }
  .timeline[data-armed] .timeline__link-fill {
    transition: transform 0.35s ease;
  }
}


/* src/styles/hero-laptop.css */
/*
 * Hero laptop image sequence, driven by src/scripts/hero-laptop.js.
 *
 * Lives in a code stylesheet rather than the design stylesheet: these rules
 * react to state the script sets at runtime, and the publisher drops design
 * rules whose selector it cannot tie to an element on the page.
 *
 * Scoped to all pages on purpose. Instatic checks a stylesheet's page scope
 * against the layout template that wraps the page, so a home-page scope never
 * matches and the file is not linked. The selectors only exist on the home page.
 */

.hero__media img,
.hero__media canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

.hero__media canvas {
  opacity: 0;
  transition: opacity 0.3s ease;
}

/* Set on <html> before the first paint: the intro starts from an empty stage. */
[data-hero-intro] .hero__media img {
  opacity: 0;
}

/* The canvas has taken over from the hero image. */
.hero__media[data-sequence="ready"] canvas {
  opacity: 1;
}

.hero__media[data-sequence="ready"] img {
  opacity: 0;
}


/* src/styles/motion.css */
/**
 * Motion layer for the decoration kit (.deco*), the section rules and the signature.
 *
 * Lives in a code stylesheet (scope: all pages) because it holds @keyframes and the
 * styles for the state classes that src/scripts/motion.js sets at runtime — the design
 * stylesheet drops those. Everything degrades to a static, readable layout without JS.
 */

/* --- ambient motion of the decoration shapes --- */
.deco--dot {
  animation: deco-bob var(--deco-dur, 3s) ease-in-out var(--deco-delay, 0s) infinite;
}
.deco--orbit {
  animation: deco-spin var(--deco-dur, 40s) linear infinite;
}
.deco--reverse {
  animation-direction: reverse;
}
.deco--field {
  animation: deco-drift 12s ease-in-out infinite;
}
.deco--ring,
.about__frame {
  animation: deco-sway 9s ease-in-out infinite;
}
.about__fact:hover .about__fact-icon {
  animation: deco-wiggle 0.5s;
}

/* --- watermark stroke weight ---
   `stroke-width` is an SVG presentation property: the publisher strips it from the design
   stylesheet (instatic.md rule 10), so it has to be applied here. The VALUES live as tokens
   in the design system (`--wm-stroke`, `--wm-stroke-at`) — change them there, not here.
   Visible thickness = stroke ÷ viewBox width × rendered width.

   Both tokens are on the same (Lucide) scale, so they compare directly — 1.2 against 0.84
   reads as "Austria is 30 % finer", and equal values mean equal weight. Austria needs the
   factor because its box is 544 units wide instead of 24 and it renders at 15rem instead of
   --wm-width (11rem): 544 / 24 × 11 / 15 = 16.62. Recompute it if one of those widths moves. */
.icon--wm {
  stroke-width: var(--wm-stroke, 1.2);
}
.icon--wm-at {
  stroke-width: calc(var(--wm-stroke-at, 0.84) * 16.62);
}

/* --- fireflies in the benefit cards (src/scripts/fireflies.js) --- */
.firefly {
  position: absolute;
  border-radius: 50%;
  pointer-events: none;
  background-color: var(--color-scheme-accent);
  box-shadow: 0 0 var(--firefly-glow, 7px)
    color-mix(in srgb, var(--color-scheme-accent), transparent 35%);
  opacity: 0;
  animation: firefly var(--firefly-dur, 11s) ease-in-out var(--firefly-delay, 0s) infinite;
}
@keyframes firefly {
  0% { opacity: 0; translate: 0 0; }
  8% { opacity: 0; }
  18% { opacity: var(--firefly-peak, 0.35); }
  32% { opacity: calc(var(--firefly-peak, 0.35) * 0.35);
        translate: var(--firefly-x1, 4px) var(--firefly-y1, -5px); }
  46% { opacity: var(--firefly-peak, 0.35);
        translate: var(--firefly-x2, -3px) var(--firefly-y2, -9px); }
  62% { opacity: calc(var(--firefly-peak, 0.35) * 0.25);
        translate: var(--firefly-x3, 5px) var(--firefly-y3, -3px); }
  76% { opacity: var(--firefly-peak, 0.35);
        translate: var(--firefly-x4, -2px) var(--firefly-y4, -7px); }
  90% { opacity: 0; translate: var(--firefly-x4, -2px) var(--firefly-y4, -7px); }
  100% { opacity: 0; translate: 0 0; }
}
/* hovering a card freezes its own fireflies in place */
@media (hover: hover) and (pointer: fine) {
  .card--fireflies:hover .firefly {
    animation-play-state: paused;
  }
  /* the watermark drifts up-left on hover, so more of the icon slides into the card.
     Lives here because the design stylesheet files this selector as a CLASS rule with no
     node assigned, and the publisher then drops it (instatic.md rule 1). */
  .benefits__card:hover .icon--wm {
    translate: -6px -4px;
  }
}

@keyframes deco-bob {
  0%, 100% { transform: translateY(0); opacity: 0.55; }
  50% { transform: translateY(var(--deco-bob, -14px)); opacity: 1; }
}
@keyframes deco-spin {
  to { rotate: 360deg; }
}
@keyframes deco-drift {
  0%, 100% { translate: 0 0; }
  50% { translate: 8px 10px; }
}
@keyframes deco-sway {
  0%, 100% { translate: 0 0; rotate: 0deg; }
  50% { translate: 6px -6px; rotate: 1.5deg; }
}
@keyframes deco-wiggle {
  0% { rotate: 0deg; }
  25% { rotate: -10deg; }
  50% { rotate: 10deg; }
  75% { rotate: -5deg; }
  100% { rotate: 0deg; }
}

/* The self-drawing `.sign` monoline signature lived here until 2026-09-16.
   Removed with issue #10: the about section now carries the real signature
   (Amsterdam Four outlines, filled + mask-swept), whose rules live in
   src/styles/signature.css. `.sign` is used by nothing, and its `path` rule
   set fill:none + stroke + dash, which would fight a filled masked path. */

/* --- states set by src/scripts/motion.js --- */
.motion-js .section__rule {
  width: 0;
  transition: width 1s ease 0.3s;
}
.motion-js .section__rule.is-in {
  width: 6rem;
}
/* The reveal runs as an ANIMATION, not a transition: a `transition` shorthand here would
   replace the whole transition list of the element and kill the hover transitions of
   `.card--glow` (scale / border-color / box-shadow) — the card would snap instead of ease. */
.motion-js [data-reveal] {
  opacity: 0;
}
.motion-js [data-reveal].is-in {
  animation: reveal-rise 0.6s ease-out both;
}
@keyframes reveal-rise {
  from { opacity: 0; translate: 0 20px; }
  to { opacity: 1; translate: 0 0; }
}

/* --- the hero copy arrives in sequence ---
   Deliberately NOT the [data-reveal] path above. That one is a SCROLL reveal: its
   IntersectionObserver fires the moment an element enters the viewport, and the hero is
   already in the viewport at load — the observer fires on the first frame, the start state
   is never painted, and nothing visibly animates. An entrance belongs on a timeline, so
   this is a plain CSS animation with per-child delays and no JavaScript, which also means
   it still runs if a script fails. `backwards` holds the start state during the delay, so
   there is no flash of finished copy first. `.hero__body` exists only in the home hero.

   Gated on `.hero-ready`, which src/scripts/hero-laptop.js puts on <html>. That script is
   the only one placed in the HEAD with timing `immediate`, so the class is there before the
   first paint and the `backwards` start state applies to the very first frame.

   It was gated on `.motion-js` until 2026-09-13, and that was wrong: motion.js is
   placement `body-end`, timing `dom-ready`, so it lands AFTER the first paint. The copy
   painted, and ~20 ms later it was hidden and faded back in — the flash Adrian saw on every
   load, and the reason the comment that used to sit here ("motion.js adds .motion-js before
   the first paint") was simply false.

   Deliberately a class of its own rather than moving `.motion-js` earlier: `.motion-js`
   also drives the [data-reveal] rules above, which stay at opacity 0 until motion.js hands
   them `.is-in`. Arming that class from a different script would leave every revealed
   element hidden for good if motion.js ever failed to load. `.hero-ready` arms exactly one
   self-completing CSS animation and nothing else.

   The editor canvas is still safe: scripts have runInCanvas:false, so the class is never
   added there and the copy is simply visible — the same as with JavaScript switched off. */
@media (prefers-reduced-motion: no-preference) {
  .hero-ready .hero__body > * {
    animation: hero-enter 0.6s ease-out backwards;
  }
  .hero-ready .hero__body > :nth-child(1) { animation-delay: 0.05s; }
  .hero-ready .hero__body > :nth-child(2) { animation-delay: 0.13s; }
  .hero-ready .hero__body > :nth-child(3) { animation-delay: 0.21s; }
  .hero-ready .hero__body > :nth-child(4) { animation-delay: 0.29s; }
}
@keyframes hero-enter {
  from { opacity: 0; translate: 0 20px; }
}

@media (prefers-reduced-motion: reduce) {
  .deco--dot,
  .deco--orbit,
  .deco--field,
  .deco--ring,
  .about__frame,
  .about__fact:hover .about__fact-icon {
    animation: none;
  }
  .firefly {
    display: none;
  }
  .motion-js .section__rule {
    width: 6rem;
    transition: none;
  }
  .motion-js [data-reveal] {
    opacity: 1;
  }
  .motion-js [data-reveal].is-in {
    animation: none;
  }
}

/* large decorations are hidden on phones */
@media (max-width: 767px) {
  .deco--lg {
    display: none;
  }
}


/* src/styles/signature.css */
/* Animated signature - Amsterdam Four, letters AB, outlines from the font.
   The fill never moves; white brushes inside a mask uncover it, so the font's
   own edge is what you see at every moment. Each brush follows the centreline
   of its stroke and is clipped so it cannot uncover ink that is written later:
   where two strokes cross, the earlier one runs straight through. Generated by
   redesign/sign/v2 - see HANDOFF.md there. The keyframe stops carry the speed
   profile, so the interpolation between them must stay linear. */
.sign-ink {
  width: 9rem;
  height: auto;
  color: var(--color-scheme-accent);
  /* `.about__sign` is a flex row and an svg has no intrinsic width, so
     without this the signature is squeezed (measured 133px of 144). */
  flex: none;
}
.sign-ink__brush, .sign-ink__veil {
  animation-duration: 7s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}
.sign-ink__brush {
  stroke-dasharray: 1 2;
  /* Wherever the animation never runs: the FINISHED signature. */
  stroke-dashoffset: 0;
}
/* The fade: a black veil over the brushes inside the mask. */
.sign-ink__veil { animation-name: sign-veil; }
@keyframes sign-veil {
  0%, 88% { opacity: 0; }
  99%, 100% { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .sign-ink__brush, .sign-ink__veil { animation: none; }
  .sign-ink__brush { stroke-dashoffset: 0; }
}
@keyframes sign-w-a10 {
  0% { stroke-dashoffset: 0.99191; }
  0.5% { stroke-dashoffset: 0.98358; }
  1% { stroke-dashoffset: 0.97482; }
  1.5% { stroke-dashoffset: 0.96519; }
  2% { stroke-dashoffset: 0.95417; }
  2.5% { stroke-dashoffset: 0.94098; }
  3% { stroke-dashoffset: 0.92469; }
  3.5% { stroke-dashoffset: 0.90408; }
  4% { stroke-dashoffset: 0.87832; }
  4.5% { stroke-dashoffset: 0.84843; }
  5% { stroke-dashoffset: 0.81661; }
  5.5% { stroke-dashoffset: 0.78292; }
  6% { stroke-dashoffset: 0.74716; }
  6.5% { stroke-dashoffset: 0.70917; }
  7% { stroke-dashoffset: 0.66881; }
  7.5% { stroke-dashoffset: 0.62602; }
  8% { stroke-dashoffset: 0.58104; }
  8.5% { stroke-dashoffset: 0.53502; }
  9% { stroke-dashoffset: 0.49049; }
  9.5% { stroke-dashoffset: 0.44967; }
  10% { stroke-dashoffset: 0.41257; }
  10.5% { stroke-dashoffset: 0.37779; }
  11% { stroke-dashoffset: 0.3437; }
  11.5% { stroke-dashoffset: 0.30918; }
  12% { stroke-dashoffset: 0.27373; }
  12.5% { stroke-dashoffset: 0.23702; }
  13% { stroke-dashoffset: 0.19839; }
  13.5% { stroke-dashoffset: 0.15687; }
  14% { stroke-dashoffset: 0.11168; }
  14.5% { stroke-dashoffset: 0.06289; }
  15% { stroke-dashoffset: 0.01164; }
  15.112% { stroke-dashoffset: 0; }
  100% { stroke-dashoffset: 0; }
}
.sign-ink__ra10 { animation-name: sign-w-a10; }
@keyframes sign-w-a11 {
  0% { stroke-dashoffset: 1; }
  15.004% { stroke-dashoffset: 1; }
  16.5% { stroke-dashoffset: 0.52611; }
  17% { stroke-dashoffset: 0.36849; }
  17.5% { stroke-dashoffset: 0.23705; }
  18% { stroke-dashoffset: 0.14699; }
  18.5% { stroke-dashoffset: 0.0827; }
  19.059% { stroke-dashoffset: 0.024; }
  19.061%, 100% { stroke-dashoffset: 0; }
}
.sign-ink__ra11 { animation-name: sign-w-a11; }
@keyframes sign-w-a20 {
  0%, 19.407% { stroke-dashoffset: 1; }
  19.409% { stroke-dashoffset: 0.96936; }
  19.5% { stroke-dashoffset: 0.96167; }
  20% { stroke-dashoffset: 0.91747; }
  20.5% { stroke-dashoffset: 0.86279; }
  21% { stroke-dashoffset: 0.78564; }
  21.5% { stroke-dashoffset: 0.67364; }
  22.5% { stroke-dashoffset: 0.41263; }
  23% { stroke-dashoffset: 0.2844; }
  23.5% { stroke-dashoffset: 0.17026; }
  24% { stroke-dashoffset: 0.09072; }
  24.5% { stroke-dashoffset: 0.03179; }
  24.609% { stroke-dashoffset: 0.01995; }
  24.611%, 100% { stroke-dashoffset: 0; }
}
.sign-ink__ra20 { animation-name: sign-w-a20; }
@keyframes sign-w-b10 {
  0%, 26.607% { stroke-dashoffset: 1; }
  26.609% { stroke-dashoffset: 0.9652; }
  27% { stroke-dashoffset: 0.9064; }
  27.5% { stroke-dashoffset: 0.81966; }
  28% { stroke-dashoffset: 0.70226; }
  28.5% { stroke-dashoffset: 0.53304; }
  29% { stroke-dashoffset: 0.32972; }
  29.5% { stroke-dashoffset: 0.17362; }
  30% { stroke-dashoffset: 0.06497; }
  30.176% { stroke-dashoffset: 0.03145; }
  30.178%, 100% { stroke-dashoffset: 0; }
}
.sign-ink__rb10 { animation-name: sign-w-b10; }
@keyframes sign-w-b20 {
  0%, 32.174% { stroke-dashoffset: 1; }
  32.176% { stroke-dashoffset: 0.98817; }
  32.5% { stroke-dashoffset: 0.97114; }
  33% { stroke-dashoffset: 0.94147; }
  33.5% { stroke-dashoffset: 0.90205; }
  34% { stroke-dashoffset: 0.8452; }
  34.5% { stroke-dashoffset: 0.77283; }
  35% { stroke-dashoffset: 0.69935; }
  35.5% { stroke-dashoffset: 0.62814; }
  36% { stroke-dashoffset: 0.56234; }
  36.5% { stroke-dashoffset: 0.50286; }
  37% { stroke-dashoffset: 0.44583; }
  37.5% { stroke-dashoffset: 0.38539; }
  38% { stroke-dashoffset: 0.3182; }
  38.5% { stroke-dashoffset: 0.24608; }
  39% { stroke-dashoffset: 0.17318; }
  39.5% { stroke-dashoffset: 0.11284; }
  40% { stroke-dashoffset: 0.07156; }
  40.5% { stroke-dashoffset: 0.042; }
  41% { stroke-dashoffset: 0.01787; }
  41.121% { stroke-dashoffset: 0.01233; }
  41.123%, 100% { stroke-dashoffset: 0; }
}
.sign-ink__rb20 { animation-name: sign-w-b20; }
@keyframes sign-w-b30 {
  0%, 41.469% { stroke-dashoffset: 1; }
  41.471% { stroke-dashoffset: 0.97961; }
  42% { stroke-dashoffset: 0.94773; }
  42.5% { stroke-dashoffset: 0.91243; }
  43% { stroke-dashoffset: 0.86595; }
  43.5% { stroke-dashoffset: 0.80319; }
  44% { stroke-dashoffset: 0.72938; }
  44.5% { stroke-dashoffset: 0.65875; }
  45% { stroke-dashoffset: 0.58929; }
  45.5% { stroke-dashoffset: 0.51453; }
  46% { stroke-dashoffset: 0.43039; }
  46.5% { stroke-dashoffset: 0.33889; }
  47% { stroke-dashoffset: 0.2459; }
  47.5% { stroke-dashoffset: 0.16435; }
  48% { stroke-dashoffset: 0.10752; }
  48.5% { stroke-dashoffset: 0.06749; }
  49% { stroke-dashoffset: 0.03613; }
  49.388% { stroke-dashoffset: 0.01421; }
  49.39%, 100% { stroke-dashoffset: 0; }
}
.sign-ink__rb30 { animation-name: sign-w-b30; }
@keyframes sign-w-b40 {
  0%, 49.736% { stroke-dashoffset: 1; }
  49.738% { stroke-dashoffset: 0.98037; }
  50% { stroke-dashoffset: 0.96758; }
  50.5% { stroke-dashoffset: 0.94146; }
  51% { stroke-dashoffset: 0.90995; }
  51.5% { stroke-dashoffset: 0.86831; }
  52% { stroke-dashoffset: 0.81124; }
  52.5% { stroke-dashoffset: 0.74234; }
  53% { stroke-dashoffset: 0.67443; }
  53.5% { stroke-dashoffset: 0.60999; }
  54% { stroke-dashoffset: 0.54928; }
  54.5% { stroke-dashoffset: 0.49214; }
  55% { stroke-dashoffset: 0.43829; }
  55.5% { stroke-dashoffset: 0.38743; }
  56% { stroke-dashoffset: 0.33923; }
  56.5% { stroke-dashoffset: 0.29338; }
  57% { stroke-dashoffset: 0.24956; }
  57.5% { stroke-dashoffset: 0.20747; }
  58% { stroke-dashoffset: 0.16682; }
  58.5% { stroke-dashoffset: 0.1273; }
  59% { stroke-dashoffset: 0.08865; }
  60% { stroke-dashoffset: 0.01281; }
  60.002%, 100% { stroke-dashoffset: 0; }
}
.sign-ink__rb40 { animation-name: sign-w-b40; }
