/* ==========================================================================
   ALBI HOME — MOTION
   --------------------------------------------------------------------------
   One idea, applied three ways: light moving across glass.

   This is a glazing company, so the motion vocabulary is architectural —
   things settle into place and light travels over surfaces. Nothing bounces,
   nothing springs past its mark, nothing rotates. Those read as playful, and
   the brand is not.

   THE HIDDEN STATE IS OPT-IN, NOT DEFAULT.
   Every rule below is scoped to .reveal-ready, a class motion.js puts on
   <html> only after it has confirmed IntersectionObserver exists and that the
   visitor has not asked for reduced motion. If the script never runs, never
   loads, or bails, no element is ever hidden — the page is simply static.
   Hiding content by default and relying on JS to show it again is how a
   failed script turns into a blank page.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. SETTLE ON ENTER
   A 20px rise and a fade, ease-out, as a block enters the viewport. Transform
   and opacity only — both composited, so this never triggers layout.
   -------------------------------------------------------------------------- */
.reveal-ready [data-reveal] {
  opacity: 0;
  transform: translateY(20px);
}
.reveal-ready [data-reveal].is-revealed {
  opacity: 1;
  transform: none;
  transition:
    opacity var(--dur-reveal) var(--ease-out),
    transform var(--dur-reveal) var(--ease-out);
}

/* --- Staggered groups -----------------------------------------------------
   The container stays put; its children settle one after another. 60ms apart
   is enough to read as a sequence without the last card feeling late — and
   the index is capped in the JS so a long grid cannot run away with itself. */
.reveal-ready [data-reveal-stagger] > * {
  opacity: 0;
  transform: translateY(20px);
}
.reveal-ready [data-reveal-stagger].is-revealed > * {
  opacity: 1;
  transform: none;
  transition:
    opacity var(--dur-reveal) var(--ease-out),
    transform var(--dur-reveal) var(--ease-out);
  transition-delay: calc(var(--reveal-i, 0) * 60ms);
}

/* --------------------------------------------------------------------------
   2. LIGHT ON GLASS — the hero feature strip
   The strip is already frosted glass (backdrop-filter). A soft gold pool of
   light tracks the pointer across it, the way a highlight runs over real
   glazing. It is the one moment on the page that responds continuously to the
   visitor rather than to the scroll position.

   Pointer devices only. On a touchscreen there is no pointer to follow, and a
   hover state that latches on tap would just leave a smear behind the finger.
   -------------------------------------------------------------------------- */
@media (hover: hover) and (pointer: fine) {
  .hero__features {
    position: relative;
    overflow: hidden;
  }
  .hero__features::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 0;
    opacity: 0;
    pointer-events: none;
    background: radial-gradient(
      var(--glass-r, 260px) circle at var(--glass-x, 50%) var(--glass-y, 50%),
      var(--a-gold-24) 0%,
      rgba(226, 184, 92, .06) 42%,
      transparent 72%
    );
    transition: opacity var(--dur-slow) var(--ease-out);
  }
  .hero__features.is-lit::after { opacity: 1; }
  /* The features sit above the light, not in it. */
  .hero__feature { position: relative; z-index: 1; }
}

/* --------------------------------------------------------------------------
   3. LIFT ON HOVER — cards
   3px is deliberately small. These are product cards on an architectural
   site; the card should acknowledge the pointer, not jump at it. The gold
   edge does most of the work.

   Not applied to the gallery tiles: those already answer a hover with the
   photo zoom and the expand badge, and stacking a lift on top would be two
   responses to one gesture.
   -------------------------------------------------------------------------- */
@media (hover: hover) and (pointer: fine) {
  .benefit,
  .process-step {
    transition:
      transform var(--dur-base) var(--ease-out),
      border-color var(--dur-base) var(--ease-out),
      box-shadow var(--dur-base) var(--ease-out);
  }
  .benefit:hover,
  .process-step:hover {
    transform: translateY(-3px);
    border-color: var(--a-gold-24);
    box-shadow: var(--shadow-md);
  }
}

/* --------------------------------------------------------------------------
   4. REDUCED MOTION
   motion.js already refuses to add .reveal-ready when this is set, so nothing
   is hidden in the first place. These rules are the belt to that braces: they
   also cover the hover effects, which are pure CSS and would otherwise still
   move.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .reveal-ready [data-reveal],
  .reveal-ready [data-reveal-stagger] > * {
    opacity: 1 !important;
    transform: none !important;
  }
  .benefit:hover,
  .process-step:hover { transform: none; }
  .hero__features::after { display: none; }
}

/* --------------------------------------------------------------------------
   5. THE HERO BEACON
   The gold dot in the hero eyebrow sends out a slow halo. It is the only
   thing on the page that moves without being asked to, so it earns its place
   by being the first thing you see and by staying quiet: 2.6s per cycle, one
   ring, gone before it finishes crossing the pill.

   HERO ONLY, deliberately. There are six eyebrows down this page, and six
   dots pulsing forever would be exactly the "animate everything" noise that
   makes a site feel cheap — and would keep six paint loops alive on a phone
   battery. One beacon at the top reads as a signal; six read as decoration.

   box-shadow rather than a scaled pseudo-element: the halo has to grow from
   the dot's own edge, and a shadow already starts there. It repaints a 14px
   circle, which is nothing, and it cannot disturb the flex layout of the pill
   the way an extra positioned element could.

   Wrapped in no-preference rather than overridden afterwards, so a visitor
   who asks for reduced motion never starts the loop at all. */
@media (prefers-reduced-motion: no-preference) {
  .eyebrow::before {
    animation: eyebrow-beacon 2600ms var(--ease-out) infinite;
  }

  /* Phase-offset per section. Every dot on the same clock would blink in
     unison as you scroll, which reads as one mechanism rather than several
     independent markers. Negative delays start each mid-cycle, so they are
     already out of step on the first frame rather than drifting apart. */
  .projects-section  .eyebrow::before { animation-delay: -400ms; }
  .benefits-section  .eyebrow::before { animation-delay: -900ms; }
  .process-section   .eyebrow::before { animation-delay: -1300ms; }
  .services-section  .eyebrow::before { animation-delay: -1800ms; }
  .about-section     .eyebrow::before { animation-delay: -2200ms; }
  .area-section      .eyebrow::before { animation-delay: -600ms; }
}

@keyframes eyebrow-beacon {
  0%   { box-shadow: 0 0 0 0 var(--a-gold-40); }
  62%  { box-shadow: 0 0 0 10px var(--a-gold-00); }
  100% { box-shadow: 0 0 0 0 var(--a-gold-00); }
}

/* --- The response pledge — Kontakt ---------------------------------------
   Same beacon, green, on the "Antwort meist innerhalb von 24 Stunden" dot.
   It earns the exception to one-beacon-per-page because it is not a section
   marker: it is the only claim on the site about how fast a human answers,
   and a live signal is what that sentence is asserting.

   Slower than the gold beacon (3.2s against 2.6s) so the two never appear to
   share a clock — the KONTAKT eyebrow is pulsing a few hundred pixels away.

   Both keyframes restate the 4px resting ring from contact.css as their first
   shadow layer. A box-shadow animation replaces the whole list, so leaving it
   out would drop the ring for the duration of every cycle. */
@media (prefers-reduced-motion: no-preference) {
  .contact-pledge::before {
    animation: pledge-beacon 3200ms var(--ease-out) infinite;
  }
}

@keyframes pledge-beacon {
  0%   { box-shadow: 0 0 0 4px var(--a-success-18), 0 0 0 0 var(--a-success-45); }
  62%  { box-shadow: 0 0 0 4px var(--a-success-18), 0 0 0 12px var(--a-success-00); }
  100% { box-shadow: 0 0 0 4px var(--a-success-18), 0 0 0 0 var(--a-success-00); }
}

/* --------------------------------------------------------------------------
   6. THE FLOATING PLATE — Über uns
   The photograph and the gold plate behind it drift, slowly and out of sync.
   Two layers moving at different rates is what reads as depth: if they moved
   together they would just be one picture sliding around.

   It starts AFTER the reveal has finished (delayed by --dur-reveal) because
   both the settle and the float drive `transform`. Overlapping them would
   have the animation seize the property mid-transition and snap the element.
   The float's first keyframe is translateY(0), which is exactly where the
   settle leaves it, so the hand-over is invisible.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {
  .about__media.is-revealed {
    animation: plate-drift 6s var(--ease-in-out) var(--dur-reveal) infinite alternate;
  }
  /* The gold plate keeps its own offset — the keyframes rebuild it rather
     than replacing it, or the plate would snap back under the photograph on
     the first frame. Slower and shorter than the photo, so the gap between
     them opens and closes instead of holding steady. */
  .about__media.is-revealed::before {
    animation: gold-plate-drift 7.5s var(--ease-in-out) var(--dur-reveal) infinite alternate;
  }
}

@keyframes plate-drift {
  from { transform: translateY(0); }
  to   { transform: translateY(-10px); }
}

@keyframes gold-plate-drift {
  from { transform: translate(var(--about-plate-x), var(--about-plate-y)); }
  to   { transform: translate(var(--about-plate-x), calc(var(--about-plate-y) - 5px)); }
}

/* --------------------------------------------------------------------------
   7. DIRECTIONAL REVEAL — the two-column sections
   Über uns and Einsatzgebiet are the only places where content sits BESIDE
   something rather than under it, so their halves arrive from their own side
   instead of rising like everything else. The horizontal component is small
   (24px) — enough to say "these two belong to different columns", not enough
   to read as a slideshow.
   -------------------------------------------------------------------------- */
.reveal-ready .about__copy,
.reveal-ready .area__copy  { transform: translate(-24px, 14px); }
.reveal-ready .about__media { transform: translate(24px, 14px); }

/* Below 900 the columns stack, so there is no "own side" left to come from
   and the horizontal slide would just be sideways noise. */
@media (max-width: 899.98px) {
  .reveal-ready .about__copy,
  .reveal-ready .area__copy,
  .reveal-ready .about__media { transform: translateY(20px); }
}

@media (prefers-reduced-motion: reduce) {
  .about__media.is-revealed,
  .about__media.is-revealed::before { animation: none; }
}
