/* ==========================================================================
   fx/scroll.css – scroll cinema (styles for fx/scroll.js)
   The page is complete without this file and without the script. Every
   pre-reveal or scroll-driven state below is scoped to html.js.fx-scroll
   (fx-scroll is set by the script) and to screen, in two tiers: the full
   tier under prefers-reduced-motion: no-preference, and a gentle tier under
   reduce (colour and opacity only, nothing travels through space). The
   script arms an element only while it is off-screen, so nothing that is on
   screen at load is hidden or changed. Square corners, flat fields, no
   shadows: the effects only draw rules, move type and fill colour.
   ========================================================================== */

/* Drives the IWI cut per section without restyling everything inside it. */
@property --cut-p {
  syntax: "<number>";
  inherits: false;
  initial-value: 1;
}

/* The programme line exists only with motion; its static state is no line at all. */
.fx-agenda__rail { display: none; }

@media screen {
  html.js.fx-scroll {
    --fx-ease: var(--ease, cubic-bezier(0.16, 1, 0.3, 1)); /* ease-out-expo, as everywhere on the site */
    --fx-soft: cubic-bezier(0.33, 1, 0.68, 1);              /* ease-out-cubic for colour and opacity */
  }

  /* 1. Statement: words fill from IWI grey (4.97:1, always legible) to ink in reading order. */
  html.js.fx-scroll .fx-fill .fx-w { color: var(--meta); transition: color 0.25s var(--fx-soft); }
  html.js.fx-scroll .fx-fill .fx-w.is-on { color: inherit; }

  /* 2. Section heads: the rule draws from the left, the heading rises out of a mask that
        stays at its own lower edge, the fact follows 120ms later. Transitions sit on the
        .is-in state only, so arming (off-screen) is instant and only the reveal animates. */
  html.js.fx-scroll .shead.fx-rv { position: relative; border-top-color: transparent; }
  html.js.fx-scroll .shead.fx-rv::before {
    content: ""; position: absolute; top: -1px; left: 0; right: 0;
    border-top: 1px solid; /* currentColor: ink on white and grey, white on the green fields */
    transform: scaleX(0); transform-origin: 0 0;
    pointer-events: none;
  }
  /* Translate and bottom inset run in step, so the visible edge stays put while the type rises. */
  html.js.fx-scroll .shead.fx-rv:not(.is-in) > h2 { clip-path: inset(0 0 100% 0); transform: translateY(100%); }
  html.js.fx-scroll .shead.fx-rv:not(.is-in) > .shead__fact { opacity: 0; transform: translateY(12px); }
  html.js.fx-scroll .shead.fx-rv.is-in::before {
    transform: none;
    transition: transform 1.2s var(--fx-ease);
  }
  html.js.fx-scroll .shead.fx-rv.is-in > h2 {
    clip-path: inset(-0.2em -0.1em -0.2em -0.1em);
    transition: transform 0.9s var(--fx-ease) 0.08s, clip-path 0.9s var(--fx-ease) 0.08s;
  }
  html.js.fx-scroll .shead.fx-rv.is-in > .shead__fact {
    transition: opacity 0.6s var(--fx-soft) 0.2s, transform 0.9s var(--fx-ease) 0.2s;
  }

  /* 3. Dates: the list rule draws, the rows rise 16px in turn (80ms apart), each hairline
        draws in after its row. --fx-i is the row index, set by the script. */
  html.js.fx-scroll .dates.fx-rv { position: relative; border-top-color: transparent; }
  html.js.fx-scroll .dates.fx-rv > li { position: relative; border-bottom-color: transparent; }
  html.js.fx-scroll .dates.fx-rv::before,
  html.js.fx-scroll .dates.fx-rv > li::after {
    content: ""; position: absolute; left: 0; right: 0;
    transform: scaleX(0); transform-origin: 0 0;
    pointer-events: none;
  }
  html.js.fx-scroll .dates.fx-rv::before { top: -1px; border-top: 1px solid var(--rule); }
  html.js.fx-scroll .dates.fx-rv > li::after { bottom: -1px; border-bottom: 1px solid var(--rule); }
  html.js.fx-scroll .dates.fx-rv:not(.is-in) > li { opacity: 0; transform: translateY(16px); }
  html.js.fx-scroll .dates.fx-rv.is-in::before,
  html.js.fx-scroll .dates.fx-rv.is-in > li::after {
    transform: none;
    transition: transform 1.1s var(--fx-ease);
  }
  html.js.fx-scroll .dates.fx-rv.is-in > li {
    transition: opacity 0.6s var(--fx-soft), transform 0.9s var(--fx-ease);
    transition-delay: calc(var(--fx-i, 0) * 80ms + 0.1s);
  }
  html.js.fx-scroll .dates.fx-rv.is-in > li::after { transition-delay: calc(var(--fx-i, 0) * 80ms + 0.22s); }

  /* 4. Green fields: the IWI diagonal draws in while the field scrolls up (--cut-p 0 → 1).
        While armed, the field's diagonal clip (site.css) gives way to a static box clip, and a
        triangle in the page colour covers the cut: scaleY(--cut-p) from the field's top edge
        takes it from flat to the full diagonal, (0,0)–(100%,0)–(0, cut-wide × p), the same shape
        the animated clip-path used to cut away. A scroll step now moves one small shape instead of
        re-clipping (and repainting) the whole field. The page behind both fields is --paper (white,
        and the sections above #faculty and #submit are white). The triangle starts 2px above the
        field, where the box clip cuts it off, so no half-covered pixel row is left on the top edge. */
  html.js.fx-scroll [data-cut].fx-cut {
    position: relative;
    isolation: isolate; /* the stacking context the clip-path gave */
    contain: paint;     /* clips to the field's box, as the clip-path did */
    clip-path: none;
  }
  html.js.fx-scroll [data-cut].fx-cut::after {
    --cut-p: inherit;   /* registered with inherits: false; only this triangle reads it */
    content: "";
    position: absolute; top: -2px; left: 0; right: 0; z-index: 1;
    height: calc(var(--cut-wide) + 2px);
    background: var(--paper, #fff);
    clip-path: polygon(0 0, 100% 0, 100% 2px, 0 100%);
    transform: scaleY(var(--cut-p, 1));
    transform-origin: 0 2px; /* the field's top edge */
    pointer-events: none;
  }

  /* 5. Programme: a 2px HSG-green line grows down the left gutter, a square marks its tip;
        rows it has passed set their time in ink. */
  html.js.fx-scroll .fx-agenda { position: relative; }
  html.js.fx-scroll .fx-agenda__rail {
    display: block; position: absolute; top: 0; bottom: 0; left: -24px; width: 2px;
    pointer-events: none;
  }
  .fx-agenda__line {
    position: absolute; inset: 0;
    background: var(--green);
    transform: scaleY(0); transform-origin: 50% 0;
    will-change: transform;
  }
  .fx-agenda__mark {
    position: absolute; top: -3px; left: -2px; width: 6px; height: 6px;
    background: var(--green);
    will-change: transform;
  }
  html.js.fx-scroll .agenda > li .agenda__time { transition: color 0.3s var(--fx-soft); }
  html.js.fx-scroll .agenda > li.is-past .agenda__time { color: var(--ink); }

  /* 6. Running band: the script runs it right to left on its own (scrolling adds speed) and
        shows the pause button (site.css); only its transform changes, on its own layer. */
  html.js.fx-scroll [data-ticker] .ticker__track { will-change: transform; }
}

/* Gentle tier for "reduce motion": fewer and gentler, not off. Colour and opacity only; nothing
   scales, translates or wipes, and every fade is short (0.5s) because it briefly lowers contrast.
   1. the statement fills as in the full tier; 2. the head's rule simply stands, heading and fact
   fade in; 3. the dates rows fade in turn with their hairlines, the list rule stands; 5. passed programme
   times turn ink, with no line (its rail keeps display: none). 4. the cut and 6. the band stay
   static as in site.css (the band without its pause button): the script does not arm them in this tier. */
@media not all { /* was: reduced motion (ignored by decision, see DESIGN.md) */
  html.js.fx-scroll { --fx-soft: cubic-bezier(0.33, 1, 0.68, 1); } /* ease-out-cubic */

  html.js.fx-scroll .fx-fill .fx-w { color: var(--meta); transition: color 0.25s var(--fx-soft); }
  html.js.fx-scroll .fx-fill .fx-w.is-on { color: inherit; }

  html.js.fx-scroll .shead.fx-rv:not(.is-in) > h2,
  html.js.fx-scroll .shead.fx-rv:not(.is-in) > .shead__fact { opacity: 0; }
  html.js.fx-scroll .shead.fx-rv.is-in > h2 { transition: opacity 0.5s var(--fx-soft); }
  html.js.fx-scroll .shead.fx-rv.is-in > .shead__fact { transition: opacity 0.5s var(--fx-soft) 0.1s; }

  html.js.fx-scroll .dates.fx-rv:not(.is-in) > li { opacity: 0; }
  html.js.fx-scroll .dates.fx-rv.is-in > li {
    transition: opacity 0.5s var(--fx-soft);
    transition-delay: calc(var(--fx-i, 0) * 80ms + 0.1s);
  }

  html.js.fx-scroll .agenda > li .agenda__time { transition: color 0.3s var(--fx-soft); }
  html.js.fx-scroll .agenda > li.is-past .agenda__time { color: var(--ink); }
}

/* Below 1024px the gutter is too narrow for the line next to the full-bleed break rows;
   the times turning ink (is-past) carry the progress on their own there. */
@media screen and (max-width: 1023px) {
  html.js.fx-scroll .fx-agenda__rail { display: none; }
}

/* Reduced motion: the band stands still even if a transform was left behind, and a still band
   has nothing to pause (the script hides the button too; this covers the moment of a switch). */
@media not all { /* was: reduced motion (ignored by decision, see DESIGN.md) */
  [data-ticker] .ticker__track { transform: none !important; }
  [data-ticker] .ticker__toggle { display: none; }
}

/* Forced colours would flatten the green line into the canvas; it is decorative, so it goes. */
@media (forced-colors: active) {
  html.js.fx-scroll .fx-agenda__rail { display: none; }
}
