/* ============================================================
   v17 motion layer (v16's, plus v15's agent cards and step numerals).
   Only headings and a few special moments animate; body text is simply
   there. Without JS or with reduced motion the page is fully static.
   ============================================================ */
:root { --ease-out: cubic-bezier(0.2, 0.8, 0.2, 1); }

/* ---- Hero: the dawn sky drifts, very slowly ---- */
.hero { background-image: none; }
.hero-bg { position: absolute; inset: -6% -4%; z-index: 0; will-change: transform; }
.hero-bg i { position: absolute; inset: 0; background: url(art/dawn.jpg) center 64% / cover no-repeat; animation: drift 70s ease-in-out infinite alternate; }
@keyframes drift { from { transform: scale(1.02) translate3d(-1%, 0, 0); } to { transform: scale(1.08) translate3d(1.2%, -0.8%, 0); } }
.hero-bg::after { content: ""; position: absolute; left: 0; right: 0; top: 60%; height: 16%; background: radial-gradient(60% 50% at 50% 60%, rgba(255, 243, 230, 0.7), transparent 70%); animation: breathe 9s ease-in-out infinite; }
@keyframes breathe { 0%, 100% { opacity: 0.5; } 50% { opacity: 1; } }
.hero::after { z-index: 0; }
.hero-inner, .hero-logos { position: relative; z-index: 1; will-change: transform, opacity; }

/* Headline words rise out of a blur; subhead and buttons follow */
html.js .hero h1 .w { display: inline-block; opacity: 0; filter: blur(10px); transform: translateY(0.35em); transition: opacity 1s var(--ease-out), filter 1s var(--ease-out), transform 1s var(--ease-out); transition-delay: calc(var(--i) * 80ms + 150ms); }
html.js.is-in .hero h1 .w { opacity: 1; filter: blur(0); transform: none; }
html.js .hero .rv { opacity: 0; filter: blur(6px); transform: translateY(10px); transition: opacity 1s var(--ease-out), filter 1s var(--ease-out), transform 1s var(--ease-out); transition-delay: var(--d, 0ms); }
html.js.is-in .hero .rv { opacity: 1; filter: none; transform: none; }
html.js .hero-logos .row { opacity: 0; transform: translateY(8px); transition: opacity 0.9s ease 1.2s, transform 0.9s var(--ease-out) 1.2s; }
html.js.is-in .hero-logos .row { opacity: 1; transform: none; }

/* ---- Statement: words light up as you read ---- */
html.js .statement p .sw { color: var(--ink-300); transition: color 0.35s ease; }
html.js .statement p .sw.lit { color: var(--ink-900); }
html.js .statement p span.muted .sw.lit { color: var(--ink-900); }

/* ---- Product: tilts flat as it arrives ---- */
.art-plate { perspective: 1800px; }
.art-plate .app { transform-origin: 50% 0; will-change: transform; }

/* ---- Section headings ---- */
html.js [data-reveal] { opacity: 0; filter: blur(4px); transform: translateY(10px); transition: opacity 0.8s var(--ease-out), filter 0.8s var(--ease-out), transform 0.8s var(--ease-out); transition-delay: calc(var(--i, 0) * 110ms); }
html.js [data-reveal].is-shown { opacity: 1; filter: none; transform: none; }

/* ---- Systems: each big name rises as its rule draws in ---- */
html.js .problem { position: relative; border-bottom-color: transparent; }
html.js .problem::after { content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 1px; background: var(--line); transform: scaleX(0); transform-origin: 0 50%; transition: transform 1.1s var(--ease-out); }
html.js .problem h3 { opacity: 0; transform: translateY(0.3em); transition: opacity 0.8s var(--ease-out), transform 0.9s var(--ease-out), color 0.2s ease; }
html.js .problem.is-shown::after { transform: scaleX(1); }
html.js .problem.is-shown h3 { opacity: 1; transform: none; }
html.js .problem.is-shown:hover h3 { transform: translateX(6px); }

/* ---- Feature moments act out their job ----
   .is-shown brings the card in once, on scroll. .is-played runs what
   happens inside it, and is re-applied on hover so the moment replays. */
html.js .feature .card { opacity: 0; transform: translateY(24px) scale(0.98); transition: opacity 0.8s var(--ease-out), transform 0.8s var(--ease-out); }
html.js .feature.is-shown .card { opacity: 1; transform: none; }
/* Find: two records slide together, then the badges land */
html.js .feature .f-find .rec span { opacity: 0; transition: opacity 0.6s ease, transform 0.8s var(--ease-out); }
html.js .feature .f-find .rec span:nth-child(-n+2) { transform: translateX(-28px); }
html.js .feature .f-find .rec span:nth-child(n+3) { transform: translateX(28px); }
html.js .feature.is-played .f-find .rec span { opacity: 1; transform: none; transition-delay: 0.45s; }
html.js .feature .f-find .card-top .st { opacity: 0; transform: scale(0.7); transition: opacity 0.35s ease, transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1); }
html.js .feature.is-played .f-find .card-top .st { opacity: 1; transform: none; transition-delay: 1.1s; }
html.js .feature.is-played .f-find .card-top .st + .st { transition-delay: 1.25s; }
/* Fix: each empty value is struck, then the fix is written in */
html.js .feature .diff .old { text-decoration: none; background: linear-gradient(currentColor, currentColor) 0 55% / 0 1px no-repeat; transition: background-size 0.4s ease; }
html.js .feature .diff .new { opacity: 0; transform: translateX(-6px); transition: opacity 0.5s ease, transform 0.5s var(--ease-out); }
html.js .feature.is-played .diff tr:nth-child(1) .old { background-size: 100% 1px; transition-delay: 0.6s; }
html.js .feature.is-played .diff tr:nth-child(1) .new { opacity: 1; transform: none; transition-delay: 0.95s; }
html.js .feature.is-played .diff tr:nth-child(2) .old { background-size: 100% 1px; transition-delay: 1.2s; }
html.js .feature.is-played .diff tr:nth-child(2) .new { opacity: 1; transform: none; transition-delay: 1.55s; }
html.js .feature.is-played .diff tr:nth-child(3) .old { background-size: 100% 1px; transition-delay: 1.8s; }
html.js .feature.is-played .diff tr:nth-child(3) .new { opacity: 1; transform: none; transition-delay: 2.15s; }
html.js .feature .acts .mbtn--primary { transition: box-shadow 0.4s ease; }
html.js .feature.is-played .acts .mbtn--primary { animation: nudge 0.6s ease 2.6s both; }
@keyframes nudge { 0% { box-shadow: 0 0 0 0 rgba(135,118,207,0.5); } 100% { box-shadow: 0 0 0 10px rgba(135,118,207,0); } }
/* Keep: remembered rules drop onto the stack (the drop is the whole moment) */
html.js .feature .stack .card { opacity: 0; transform: translateY(-30px); }
html.js .feature.is-played .stack .card:nth-child(3) { opacity: 0.4; transform: scale(0.94); transition-delay: 0.1s; }
html.js .feature.is-played .stack .card:nth-child(2) { opacity: 0.7; transform: scale(0.97); transition-delay: 0.35s; }
html.js .feature.is-played .stack .card:nth-child(1) { opacity: 1; transform: none; transition-delay: 0.6s; }
/* Replay: snap back to the start instantly, then run again */
html.js .feature.is-rewinding *, html.js .feature.is-rewinding *::before, html.js .feature.is-rewinding *::after { transition: none !important; animation: none !important; }
.feature .moment { cursor: default; }

/* ---- Steps: numerals rise from a baseline ---- */
/* ---- Process: a lavender line draws across the steps, then the titles rise in ---- */
html.js .steps::before { transform: scaleX(0); transition: transform 1.4s cubic-bezier(0.65, 0, 0.35, 1) 0.1s; }
html.js .steps.is-shown::before { transform: none; }
html.js .steps h3, html.js .steps .step-n, html.js .steps p { opacity: 0; transform: translateY(12px); transition: opacity 0.8s var(--ease-out), transform 0.8s var(--ease-out); }
html.js .steps.is-shown h3, html.js .steps.is-shown .step-n, html.js .steps.is-shown p { opacity: 1; transform: none; }
html.js .steps > div:nth-child(1) > * { transition-delay: 0.35s; }
html.js .steps > div:nth-child(2) > * { transition-delay: 0.65s; }
html.js .steps > div:nth-child(3) > * { transition-delay: 0.95s; }

/* ---- Team portraits wipe up ---- */
html.js .person img { clip-path: inset(100% 0 0 0); transition: clip-path 1.2s cubic-bezier(0.65, 0, 0.35, 1); }
html.js .person.is-shown img { clip-path: inset(0 0 0 0); }

/* ---- Security: badges catch a light sweep (icons stay static) ---- */
.certs { position: relative; overflow: hidden; }
.certs::after { content: ""; position: absolute; top: 0; bottom: 0; width: 30%; left: -40%; background: linear-gradient(90deg, transparent, rgba(188, 178, 244, 0.16), transparent); pointer-events: none; }
html.js .certs.is-shown::after { animation: sweep 2.4s ease 0.4s; }
@keyframes sweep { to { left: 110%; } }

/* ---- Closing sky drifts too ---- */
.closing { overflow: hidden; background-image: none; }
.closing-bg { position: absolute; inset: -6% -4%; background: url(art/dusk.jpg) center 70% / cover no-repeat; animation: drift 80s ease-in-out infinite alternate-reverse; z-index: 0; }
.closing > .container { position: relative; z-index: 1; }

/* ---- Live console (ported from v8, in Ink styling) ---- */
.app { position: relative; }
.app-status.is-working::before { animation: pulse 1.2s ease-in-out infinite; background: var(--lavender-500); }
@keyframes pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.35; transform: scale(0.7); } }
.app-stat strong { transition: color 0.4s ease; }
.app-stat strong.bump { color: var(--lavender-600); }
.finding { transition: opacity 0.45s var(--ease-out), filter 0.45s var(--ease-out), transform 0.45s var(--ease-out); }
.finding.is-swapping { opacity: 0; filter: blur(4px); transform: translateY(6px); }
.finding dl > * { transition: opacity 0.4s ease; }
.finding dl > .is-pending { opacity: 0; }
.finding .fix-text { white-space: pre-wrap; }
.finding.is-done .finding-actions { display: none; }
.resolved { display: none; margin-top: 14px; padding: 12px 14px; border-radius: var(--r); background: #EEF8F4; color: var(--teal-700); font-size: 13px; }
.finding.is-done .resolved { display: block; animation: rise 0.5s var(--ease-out); }
@keyframes rise { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.quill-caret { display: inline-block; width: 14px; height: 14px; margin-left: 2px; vertical-align: -2px; animation: nib 0.5s ease-in-out infinite alternate; }
@keyframes nib { from { transform: rotate(-8deg); } to { transform: rotate(-2deg) translateY(-1px); } }
.reviewer { position: absolute; left: 0; top: 0; z-index: 5; pointer-events: none; opacity: 0; transition: transform 1s cubic-bezier(0.45, 0, 0.2, 1), opacity 0.3s ease; }
.reviewer svg { width: 16px; height: 16px; display: block; filter: drop-shadow(0 1px 1px rgba(0,0,0,0.2)); transition: transform 0.12s ease; }
.reviewer span { position: absolute; left: 12px; top: 14px; padding: 2px 6px; border-radius: 4px; background: var(--lavender-700); color: #fff; font-size: 11px; font-weight: 600; white-space: nowrap; }
.reviewer.is-on { opacity: 1; }
.reviewer.is-click svg { transform: scale(0.85); }
.app.is-reviewing, .app.is-reviewing * { cursor: none !important; }
.mbtn { transition: transform 0.12s ease, background-color 0.12s ease; }
.mbtn.is-pressed { transform: scale(0.95); background: var(--lavender-800); }
.app-table tr.is-new td { animation: rowIn 1.6s var(--ease-out); }
@keyframes rowIn { 0% { background: var(--lavender-100); opacity: 0; } 25% { opacity: 1; } 100% { background: transparent; } }

@media (prefers-reduced-motion: reduce) {
    .hero-bg i, .hero-bg::after, .closing-bg { animation: none; }
    html.js .hero h1 .w, html.js .hero .rv, html.js [data-reveal], html.js .problem h3 { opacity: 1 !important; filter: none !important; transform: none !important; transition: none !important; }
    html.js .hero-logos .row { opacity: 1 !important; transform: none !important; transition: none !important; }
    html.js .problem::after { transform: none !important; transition: none !important; }
    html.js .feature .card, html.js .feature .f-find .rec span, html.js .feature .f-find .card-top .st, html.js .feature .diff .new { opacity: 1 !important; transform: none !important; transition: none !important; }
    html.js .feature .diff .old { background-size: 100% 1px; }
    html.js .steps::before, html.js .steps h3, html.js .steps .step-n, html.js .steps p { opacity: 1 !important; transform: none !important; transition: none !important; }
    html.js .person img { clip-path: none !important; }
    html.js .statement p .sw { color: inherit !important; }
    .app-status.is-working::before, .quill-caret { animation: none; }
}
