/* ─────────────────────────────────────────────────────────────
   IVG — Motion System
   Loaded LAST in <head> on every page so it wins the cascade
   over per-page inline styles. Pairs with scripts/motion.js.

   Principles:
   - Motion serves the argument, never decoration.
   - Everything degrades: no JS → content visible, reduced
     motion → finished states, no transforms, no blur.
   - Hidden initial states are gated on html.motion-ok, which
     only motion.js sets (and only when motion is allowed).
   ───────────────────────────────────────────────────────────── */

/* ── 1. CROSS-DOCUMENT VIEW TRANSITIONS ──
   Quiet cross-fade between pages; the wordmark stays planted. */
@view-transition { navigation: auto; }
::view-transition-old(root) { animation-duration: 200ms; }
::view-transition-new(root) { animation-duration: 260ms; }
.ivg-nav-logo, .hero-logo { view-transition-name: ivg-wordmark; }

@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) { animation: none !important; }
}

/* ── 2. ACCENT VEIL (profile pages, landing through-the-door) ──
   CSS-only: plays on load, never blocks without JS. */
.ivg-veil {
  position: fixed; inset: 0; z-index: 2000;
  background: var(--ivg-accent, #3A4A22);
  pointer-events: none;
  animation: ivgVeilOut 360ms var(--ivg-ease-out, ease) 60ms both;
}
@keyframes ivgVeilOut { from { opacity: 1; } to { opacity: 0; visibility: hidden; } }
@media (prefers-reduced-motion: reduce) { .ivg-veil { display: none; } }

/* ── 3. UNIFIED REVEAL GROUPS ──
   Add data-reveal-group to a container; motion.js staggers its
   children 70ms apart when the container enters the viewport. */
html.motion-ok [data-reveal-group] > * {
  opacity: 0;
  transform: translateY(14px);
  transition:
    opacity 640ms var(--ivg-ease-out, ease) calc(var(--reveal-i, 0) * 70ms),
    transform 640ms var(--ivg-ease-out, ease) calc(var(--reveal-i, 0) * 70ms);
}
html.motion-ok [data-reveal-group].group-in > * {
  opacity: 1;
  transform: translateY(0);
}

/* ── 4. HERO LINE-RISE ──
   Wrap each visual h1 line in .hl > .hl-inner and set --hl-i.
   Padding trick keeps Cormorant italic descenders unclipped. */
html.motion-ok .hl {
  display: block;
  overflow: hidden;
  padding-bottom: 0.14em;
  margin-bottom: -0.14em;
}
html.motion-ok .hl-inner {
  display: block;
  transform: translateY(112%);
  animation: ivgHlRise 760ms var(--ivg-ease-out, cubic-bezier(.22,1,.36,1))
             calc(180ms + var(--hl-i, 0) * 130ms) both;
}
@keyframes ivgHlRise { to { transform: translateY(0); } }

/* ── 5. RADAR BLOOM ──
   motion.js adds .vg-bloom at init and .is-live on first view,
   then removes both after the bloom so select-and-compare
   returns to its base.css behaviour untouched.
   Polygon coordinates are centered on the chart origin, so a
   plain scale() blooms from the middle. */
.vg-radar-wrap.vg-bloom polygon:not([data-pg]) {
  transition:
    transform 900ms var(--ivg-ease-out, ease) calc(var(--ring-i, 0) * 90ms),
    opacity 700ms ease calc(var(--ring-i, 0) * 90ms);
}
.vg-radar-wrap.vg-bloom polygon[data-pg] {
  transition:
    transform 820ms var(--ivg-ease-spring, cubic-bezier(.16,1,.3,1)) calc(380ms + var(--pg-i, 0) * 180ms),
    opacity 700ms ease calc(380ms + var(--pg-i, 0) * 180ms),
    stroke-width .25s ease;
}
.vg-radar-wrap.vg-bloom .vg-legend-item {
  transition:
    opacity 560ms ease calc(480ms + var(--pg-i, 0) * 180ms),
    transform 560ms var(--ivg-ease-out, ease) calc(480ms + var(--pg-i, 0) * 180ms),
    background-color .2s ease;
}
.vg-radar-wrap.vg-bloom:not(.is-live) polygon:not([data-pg]) { transform: scale(.55); opacity: 0; }
.vg-radar-wrap.vg-bloom:not(.is-live) polygon[data-pg]       { transform: scale(.4);  opacity: 0; }
.vg-radar-wrap.vg-bloom:not(.is-live) .vg-legend-item        { opacity: 0; transform: translateY(10px); }

/* ── 6. FULLBLEED MOMENT DEVELOPS LIKE A PHOTOGRAPH ──
   Keyed on the .visible class the page reveal observer already
   adds; motion.js also observes these sections as a fallback. */
html.motion-ok .fullbleed-moment .fullbleed-moment-bg img {
  transition: transform 1600ms var(--ivg-ease-settle, ease-out);
}
html.motion-ok .fullbleed-moment .fullbleed-label {
  transition: opacity 600ms ease, transform 600ms var(--ivg-ease-out, ease);
}
html.motion-ok .fullbleed-moment .fullbleed-quote {
  transition: opacity 900ms ease 250ms, transform 900ms var(--ivg-ease-out, ease) 250ms;
}
html.motion-ok .fullbleed-moment .fullbleed-attribution {
  transition: opacity 600ms ease 850ms;
}
html.motion-ok .fullbleed-moment:not(.visible) .fullbleed-moment-bg img { transform: scale(1.03); }
html.motion-ok .fullbleed-moment:not(.visible) .fullbleed-label        { opacity: 0; transform: translateX(-12px); }
html.motion-ok .fullbleed-moment:not(.visible) .fullbleed-quote        { opacity: 0; transform: translateY(18px); }
html.motion-ok .fullbleed-moment:not(.visible) .fullbleed-attribution  { opacity: 0; }

/* ── 7. CONCEPT ACCORDION: PRINCIPLE FIRST, CONSEQUENCE SECOND ── */
html.motion-ok .concept-item .concept-desc {
  opacity: 0; transform: translateY(10px);
  transition: opacity 380ms ease, transform 380ms var(--ivg-ease-out, ease);
}
html.motion-ok .concept-item .concept-example {
  opacity: 0; transform: translateY(10px);
  position: relative;
  transition: opacity 380ms ease, transform 380ms var(--ivg-ease-out, ease);
}
html.motion-ok .concept-item.open .concept-desc {
  opacity: 1; transform: none;
  transition-delay: 160ms;
}
html.motion-ok .concept-item.open .concept-example {
  opacity: 1; transform: none;
  transition-delay: 300ms;
}
/* accent left border draws top-to-bottom as the example lands */
html.motion-ok .concept-item .concept-example::before {
  content: '';
  position: absolute; left: 0; top: 0; bottom: 0;
  width: 2px;
  background: var(--accent-light, var(--ivg-accent-light, #7A8A4A));
  transform: scaleY(0); transform-origin: top;
  transition: transform 420ms var(--ivg-ease-out, ease) 360ms;
}
html.motion-ok .concept-item.open .concept-example::before { transform: scaleY(1); }

/* jump-to-concept feedback pulse (motion.js adds/removes .cflash) */
.concept-item.cflash {
  animation: ivgConceptFlash 900ms ease both;
}
@keyframes ivgConceptFlash {
  0%   { background-color: transparent; }
  25%  { background-color: var(--accent-pale, var(--ivg-accent-pale, #E8EDD8)); }
  100% { background-color: transparent; }
}

/* ── 8. FOCUS SNAP ──
   For the one line that earns it. Blur exists only when motion
   is allowed; reduced-motion users never see a filter. */
html.motion-ok .focus-reveal {
  transition: filter 900ms var(--ivg-ease-settle, ease), opacity 900ms ease;
}
html.motion-ok .focus-reveal:not(.is-focused) {
  filter: blur(2.5px);
  opacity: .55;
}

/* ── 9. FOOTER: INSTITUTE GREEN, SPROUT COLOPHON ──
   Overrides both base.css and per-page inline footer blocks
   (this file loads last). */
.ivg-footer {
  background: var(--ivg-green-deep, #2F3D1B);
  position: relative;
}
.ivg-footer::before {
  content: '';
  position: absolute; inset: 0; z-index: 0;
  pointer-events: none;
  opacity: 0.05;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='256' height='256'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.78' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='256' height='256' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 220px;
}
.ivg-footer > * { position: relative; z-index: 1; }
.ivg-footer-logo span { background: var(--ivg-green, #3A4A22); }
/* sprout colophon, quiet, cream-gold line-art */
.ivg-footer::after {
  content: '';
  position: relative; z-index: 1;
  display: block;
  width: 30px; height: 30px;
  margin: 2.2rem auto 0;
  opacity: 0.55;
  background-repeat: no-repeat;
  background-size: contain;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32' fill='none' stroke='%23F1E4B8' stroke-width='1.3' stroke-linecap='round'%3E%3Cpath d='M16 28 V13'/%3E%3Cpath d='M16 19 C16 13.5, 11.5 10.5, 5.5 10.5 C5.5 16.5, 10.5 19.5, 16 19'/%3E%3Cpath d='M16 13 C16 7.5, 20.5 4.5, 26.5 4.5 C26.5 10.5, 21.5 13.5, 16 13'/%3E%3C/svg%3E");
}

/* ── 10. NAV PILL SPRING ── */
.ivg-routes.open .ivg-routes-menu {
  transform-origin: top right;
  animation: ivgRoutesIn 280ms var(--ivg-ease-spring, cubic-bezier(.16,1,.3,1)) both;
}
@keyframes ivgRoutesIn {
  from { opacity: 0; transform: scale(.96) translateY(-4px); }
  to   { opacity: 1; transform: scale(1) translateY(0); }
}
.ivg-routes-item .ivg-route-dot { transition: opacity 200ms ease, transform 200ms ease; }
.ivg-routes-item:hover .ivg-route-dot { opacity: 1; transform: scale(1.25); }
@media (prefers-reduced-motion: reduce) {
  .ivg-routes.open .ivg-routes-menu { animation: none; }
}

/* ── 11. GLOBAL FOCUS VISIBILITY ── */
:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 3px;
  border-radius: 2px;
}

/* ── 12. REDUCED MOTION: finished states, no movement ──
   html.motion-ok is never set when reduced motion is on, so the
   hidden initial states above simply don't apply. This block
   additionally stills anything that animates by itself. */
@media (prefers-reduced-motion: reduce) {
  .hl-inner { animation: none; transform: none; }
  .concept-item.cflash { animation: none; }
}
