/* ===========================================================================
   SolutionsCoding -- HERO motion: copy entrance, first paint of the film,
   cross-fade between scenes, and what plays inside each scene while
   .is-live (coding-hero.js). All timing lives here; the driver only moves
   data-at when a step's progress line (cd-hero-grow, duration = the li's
   --dur) ends, so scene content and scene changes cannot drift.
   Transform / opacity only. Every animation uses fill "both" and ends on the
   final frame coding-hero*.css already draw, so pausing, reduced motion and
   no JS all show the same still frames.
   :is([data-at=N], [data-prev=N]) keeps an outgoing scene on its end frame
   while it fades out.
   =========================================================================== */

/* ---- copy column entrance (CSS only). The lead is the LCP text block: it
   only lifts, never fades, so it paints with the first frame. ---------------- */
@media (prefers-reduced-motion: no-preference) {
  .cd-hero-a { animation: cd-hero-copy-rise var(--dur-1) var(--ease-out) calc(var(--h, 0) * 70ms) both; }
  .cd-hero-a.cd-hero-lead { animation-name: cd-hero-copy-lift; }
}

/* ---- first paint (html.cd-hero-motion from the <head> script, before the
   driver runs): scene ① with an empty chat = frame 0 of the loop ---------- */
html.cd-hero-motion .cd-hero-film:not(.is-ready) .cd-hero-scene { opacity: 0; visibility: hidden; }
html.cd-hero-motion .cd-hero-film:not(.is-ready) .cd-hero-scene--0 { opacity: 1; visibility: visible; }
html.cd-hero-motion .cd-hero-film:not(.is-ready) .cd-hero-scene--0 .cd-hero-msg,
html.cd-hero-motion .cd-hero-film:not(.is-ready) [data-s] { opacity: 0; }
html.cd-hero-motion .cd-hero-film:not(.is-ready) [data-s="0"] { opacity: 1; }
html.cd-hero-motion .cd-hero-film:not(.is-ready) [data-say] { visibility: hidden; opacity: 0; }
html.cd-hero-motion .cd-hero-film:not(.is-ready) [data-say="0"] { visibility: visible; opacity: 1; }
html.cd-hero-motion .cd-hero-film:not(.is-ready) .cd-hero-rail [data-r] { background: none; font-weight: 400; color: inherit; box-shadow: none; }
html.cd-hero-motion .cd-hero-film:not(.is-ready) .cd-hero-rail [data-r="ai"] { background: var(--cd-chrome-hi); font-weight: 700; color: #FFF; box-shadow: inset 2px 0 0 var(--cd-mark); }

/* ---- cross-fade ------------------------------------------------------------ */
@media (prefers-reduced-motion: no-preference) {
  .cd-hero-film.is-ready .cd-hero-scene { transition: opacity 0.25s var(--ease-soft), visibility 0s linear 0.25s; }
  .cd-hero-film.is-ready[data-at="0"] .cd-hero-scene--0, .cd-hero-film.is-ready[data-at="1"] .cd-hero-scene--1,
  .cd-hero-film.is-ready[data-at="2"] .cd-hero-scene--2, .cd-hero-film.is-ready[data-at="3"] .cd-hero-scene--3 { transition: opacity 0.35s var(--ease-soft) 0.15s, visibility 0s; }
  .cd-hero-film.is-ready .cd-hero-status > .cd-hero-chip { transition: opacity 0.25s var(--ease-soft) 0.15s; }
  .cd-hero-film.is-ready .cd-hero-say > span { transition: opacity 0.25s var(--ease-soft), visibility 0s linear 0.25s; }
  .cd-hero-film.is-ready[data-at="0"] [data-say="0"], .cd-hero-film.is-ready[data-at="1"] [data-say="1"],
  .cd-hero-film.is-ready[data-at="2"] [data-say="2"], .cd-hero-film.is-ready[data-at="3"] [data-say="3"] { transition: opacity 0.35s var(--ease-soft) 0.15s, visibility 0s; }
  .cd-hero-film.is-ready .cd-hero-rail li { transition: background-color 0.25s var(--ease-soft), color 0.25s var(--ease-soft), box-shadow 0.25s var(--ease-soft); }
  .cd-hero-film.is-live[data-at="3"] .cd-hero-status > [data-s="3"] { transition-delay: 2s; }   /* 「レビュー完了」 when the verdict lands */
}
/* ④ until the verdict: 「レビュー中」 holds the status slot (live only; the still frame shows 完了) */
.cd-hero-film.is-live[data-at="3"] .cd-hero-status > [data-s="3w"] { animation: cd-hero-hold 2.05s linear both; }

/* ---- clock, status blink, freeze ------------------------------------------- */
.cd-hero-film.is-live .cd-hero-chip::before { animation: cd-hero-blink 1.4s ease-in-out infinite; }
.cd-hero-film.is-live[data-at="0"] [data-cd-step="0"] .cd-hero-prog, .cd-hero-film.is-live[data-at="1"] [data-cd-step="1"] .cd-hero-prog,
.cd-hero-film.is-live[data-at="2"] [data-cd-step="2"] .cd-hero-prog, .cd-hero-film.is-live[data-at="3"] [data-cd-step="3"] .cd-hero-prog { animation: cd-hero-grow var(--dur) linear both; }
.cd-hero-film.is-held, .cd-hero-film.is-held *, .cd-hero-film.is-held *::before, .cd-hero-film.is-held *::after { animation-play-state: paused !important; }
/* On loops (.is-loop: set as ④ wraps to ①, before ① starts) ① skips part of
   its lead-in: the visitor has already seen the empty chat once. */
.cd-hero-film.is-loop { --cd-lag: 0.6s; }
.cd-hero-film.is-live.is-loop[data-at="0"] [data-cd-step="0"] .cd-hero-prog { animation-duration: calc(var(--dur) - var(--cd-lag)); }

/* ---- ① 依頼 (4.8s): request, the AI thinks, the AI acknowledges ------------- */
.cd-hero-film.is-live:is([data-at="0"], [data-prev="0"]) .cd-hero-m-ask { animation: cd-hero-rise 0.4s var(--ease-out) calc(0.5s - var(--cd-lag, 0s)) both; }
.cd-hero-film.is-live:is([data-at="0"], [data-prev="0"]) .cd-hero-scene--0 .cd-hero-typing { animation: cd-hero-blip 1.2s linear calc(1.25s - var(--cd-lag, 0s)) both; }
.cd-hero-film.is-live:is([data-at="0"], [data-prev="0"]) .cd-hero-scene--0 .cd-hero-typing i { animation: cd-hero-dot 0.6s ease-in-out calc(1.25s + var(--k, 0) * 0.15s - var(--cd-lag, 0s)) 2; }
.cd-hero-film.is-live:is([data-at="0"], [data-prev="0"]) .cd-hero-m-ack { animation: cd-hero-rise 0.4s var(--ease-out) calc(2.45s - var(--cd-lag, 0s)) both; }

/* ---- ② ルール (5.6s): the card opens, the 4 rules check in one by one ----- */
.cd-hero-film.is-live:is([data-at="1"], [data-prev="1"]) .cd-hero-m-ctx { animation: cd-hero-rise 0.4s var(--ease-out) 0.3s both; }
.cd-hero-film.is-live:is([data-at="1"], [data-prev="1"]) .cd-hero-ctx li { animation: cd-hero-rise 0.35s var(--ease-out) calc(0.75s + var(--i, 0) * 0.45s) both; }
.cd-hero-film.is-live:is([data-at="1"], [data-prev="1"]) .cd-hero-ctx li::before { animation: cd-hero-scan 0.6s var(--ease-soft) calc(0.85s + var(--i, 0) * 0.45s) both; }   /* read, then tick */
.cd-hero-film.is-live:is([data-at="1"], [data-prev="1"]) .cd-hero-ctx .cd-hero-ck { animation: cd-hero-pop 0.35s var(--ease-out) calc(1.05s + var(--i, 0) * 0.45s) both; }
.cd-hero-film.is-live:is([data-at="1"], [data-prev="1"]) .cd-hero-ctx-wait { animation: cd-hero-hold 2.6s linear both; }
.cd-hero-film.is-live:is([data-at="1"], [data-prev="1"]) .cd-hero-ctx-n > :last-child { animation: cd-hero-pop 0.35s var(--ease-out) 2.6s both; }

/* ---- ③ 実装 (5.6s): new lines fill in, the count lands, the note slides in -- */
.cd-hero-film.is-live:is([data-at="2"], [data-prev="2"]) .cd-hero-ln--add::before { animation: cd-hero-band 0.3s var(--ease-out) calc(0.35s + var(--i, 0) * 0.3s) both; }
.cd-hero-film.is-live:is([data-at="2"], [data-prev="2"]) .cd-hero-ln--add > :not(:first-child) { animation: cd-hero-write 0.35s var(--ease-out) calc(0.45s + var(--i, 0) * 0.3s) both; }
/* caret blinks 3 times at the end of the line just written, then goes (forwards only: hidden before its time) */
.cd-hero-film.is-live:is([data-at="2"], [data-prev="2"]) .cd-hero-caret { animation: cd-hero-caret 0.9s linear 1.75s 3 forwards; }
.cd-hero-film.is-live:is([data-at="2"], [data-prev="2"]) .cd-hero-diffn { animation: cd-hero-pop 0.35s var(--ease-out) 1.75s both; }
.cd-hero-film.is-live:is([data-at="2"], [data-prev="2"]) .cd-hero-pane { animation: cd-hero-slide 0.45s var(--ease-out) 2.1s both; }
.cd-hero-film.is-live:is([data-at="2"], [data-prev="2"]) .cd-hero-why li { animation: cd-hero-rise 0.35s var(--ease-out) calc(2.55s + var(--i, 0) * 0.25s) both; }

/* ---- ④ レビュー (5.4s): 4 checks tick, verdict, then the knowledge toast ---- */
.cd-hero-film.is-live:is([data-at="3"], [data-prev="3"]) .cd-hero-checks .cd-hero-ck { animation: cd-hero-pop 0.35s var(--ease-out) calc(0.45s + var(--i, 0) * 0.35s) both; }
.cd-hero-film.is-live:is([data-at="3"], [data-prev="3"]) .cd-hero-checks li > span { animation: cd-hero-in 0.25s var(--ease-soft) calc(0.6s + var(--i, 0) * 0.35s) both; }
.cd-hero-film.is-live:is([data-at="3"], [data-prev="3"]) .cd-hero-verdict { animation: cd-hero-rise 0.4s var(--ease-out) 2s both; }
.cd-hero-film.is-live:is([data-at="3"], [data-prev="3"]) .cd-hero-toast { animation: cd-hero-toast 0.5s var(--ease-out) 2.7s both; }

/* the note pane slides from the side on wide screens, from below on phones */
.cd-hero-film { --cd-sx: 14px; --cd-sy: 0px; }
@media (max-width: 599.98px) { .cd-hero-film { --cd-sx: 0px; --cd-sy: 24px; } }

@keyframes cd-hero-copy-rise { from { opacity: 0; transform: translateY(12px); } }
@keyframes cd-hero-copy-lift { from { transform: translateY(12px); } }
@keyframes cd-hero-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes cd-hero-rise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@keyframes cd-hero-pop { 0% { opacity: 0; transform: scale(0.6); } 70% { opacity: 1; transform: scale(1.08); } 100% { opacity: 1; transform: none; } }
@keyframes cd-hero-blip { 0% { opacity: 0; } 12% { opacity: 1; } 88% { opacity: 1; } 100% { opacity: 0; } }
@keyframes cd-hero-dot { 0%, 100% { transform: none; } 50% { transform: translateY(-3px); } }
@keyframes cd-hero-write { from { opacity: 0; transform: translateX(-6px); } to { opacity: 1; transform: none; } }
@keyframes cd-hero-slide { from { opacity: 0; transform: translate(var(--cd-sx), var(--cd-sy)); } to { opacity: 1; transform: none; } }
@keyframes cd-hero-toast { 0% { opacity: 0; transform: translateY(14px) scale(0.96); } 60% { opacity: 1; transform: translateY(-2px); } 100% { opacity: 1; transform: none; } }
@keyframes cd-hero-grow { from { transform: scaleX(0); } to { transform: none; } }
@keyframes cd-hero-band { from { transform: scaleX(0); } to { transform: none; } }
@keyframes cd-hero-scan { 0% { opacity: 0; } 35% { opacity: 1; } 100% { opacity: 0; } }
@keyframes cd-hero-hold { 0%, 95% { opacity: 1; } 100% { opacity: 0; } }
@keyframes cd-hero-caret { 0%, 49.9% { opacity: 1; } 50%, 100% { opacity: 0; } }
@keyframes cd-hero-blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
