/* Jusa scenes: power and current, drawn in hairlines (README.md here).
 *
 * The default style of every part is its FINAL frame: that is what shows
 * without JavaScript and under prefers-reduced-motion. scenes.js adds
 * .is-armed to a scene it will play; only then do the "off" states below
 * apply, and each [data-at] step turns on as the clock passes it.
 * Current is clay. Green (--sc-live) only ever paints .is-live or
 * .is-delivered; developers/tests/test_scenes.py holds that line. */

.scene, .sc-power, .sc-board, .sc-divider {
  --sc-ink: var(--ink-2, #2A323B);
  --sc-soft: rgba(42, 50, 59, .38);   /* hairlines only: never text */
  --sc-note: #5A6560;                 /* a note's text: 6.1:1 on the plate */
  --sc-faint: rgba(42, 50, 59, .13);
  --sc-paper: var(--surface, #FFFFFF);
  --sc-well: var(--ground-2, #E8EAE5);
  --sc-lcd: #2A323B;
  --sc-current: var(--accent, #B4431F);
  --sc-glow: var(--accent-bright, #F0805A);
  --sc-warm: rgba(180, 67, 31, .16);
  --sc-on-current: #FFFFFF;
  --sc-text: var(--ink, #171C1A);
  --sc-live: #37AC34;
  --sc-ease: cubic-bezier(.2, .7, .3, 1);
}
/* A scene on a night band. Plates stay paper in dark mode: only code goes dark (README.md). */
.scene.is-night {
  --sc-ink: #B7BFC2; --sc-soft: rgba(183, 191, 194, .42); --sc-faint: rgba(183, 191, 194, .14); --sc-note: #9AA3A8;
  --sc-paper: #1E252B; --sc-well: #2A323B; --sc-lcd: #0F1316;
  --sc-current: #F0805A; --sc-glow: #F79274; --sc-warm: rgba(240, 128, 90, .18);
  --sc-on-current: #161B20; --sc-text: #F2F3F0;
}

/* Arming jumps to the first frame (scenes.js); no fade out of the final one. */
.is-arming * { transition: none !important; }

/* ---- the frame: a fixed aspect box, so nothing shifts when it plays ---- */
.scene { margin: 0; min-width: 0; }
/* Never smaller than legible: at least --sc-floor tall (165px: the 120-unit
   height at 1.375, so 8-unit labels are 11px). Narrower columns scroll the
   plate sideways (portal.css). */
.scene.is-plate { background: var(--surface-2, #FAFBF9); border: 1px solid var(--line, #E0E2DC);
                  border-radius: var(--r-card, 14px); padding: var(--s-4, 16px) var(--s-4, 16px) var(--s-3, 12px); }
.scene > svg, .sc-stage { display: block; width: 100%; height: auto; aspect-ratio: var(--sc-ar, 2 / 1);
                          overflow: visible; min-width: calc(var(--sc-floor, 165px) * var(--sc-ar, 2)); }
.scene figcaption { margin-top: var(--s-3, 12px); font-size: .9rem; line-height: 1.5; color: var(--ink-soft, #47514E); }
.scene figcaption strong { display: block; color: var(--ink, #171C1A); font-weight: 600; margin-bottom: 2px; }

/* ---- drawing vocabulary ---- */
.scene svg *, .sc-power svg *, .sc-board svg *, .sc-divider svg * { vector-effect: non-scaling-stroke; }
/* Not the current: a dash measured in pathLength units needs the path's own scale. */
.scene svg .sc-run, .sc-power svg .sc-run, .sc-board svg .sc-run, .sc-divider svg .sc-run,
.scene svg :is(.sc-tick, .sc-mark), .sc-power svg .sc-hot { vector-effect: none; }
.sc-s, .sc-s * { fill: none; stroke: var(--sc-ink); stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.sc-thin, .sc-thin * { stroke: var(--sc-soft); stroke-width: 1; }
.sc-b { fill: var(--sc-paper); stroke: var(--sc-ink); stroke-width: 1.5; stroke-linejoin: round; }
.sc-w { fill: var(--sc-well); stroke: none; }
.sc-hotfill { fill: var(--sc-current); stroke: none; }
.sc-txt { font-family: var(--f-num, "IBM Plex Mono", monospace); font-size: 8px; fill: var(--sc-text); stroke: none; }
.sc-txt.is-on-current { fill: var(--sc-on-current); font-weight: 600; }
.sc-txt.is-lcd { fill: var(--sc-glow); }
.sc-ground { stroke: var(--sc-faint); stroke-width: 1; }
.sc-spin, .sc-pop, .sc-dial, .sc-press, .sc-hand { transform-box: fill-box; transform-origin: center; }

/* ---- the line: a wire or a trace, with current running along it ---- */
.sc-wire { fill: none; stroke: var(--sc-soft); stroke-width: 1.25; stroke-linecap: round; stroke-linejoin: round; }
.sc-line--trace .sc-wire { stroke: var(--sc-faint); stroke-width: 1.5; }
.sc-hot, .sc-run { fill: none; stroke: var(--sc-current); stroke-linecap: round; stroke-linejoin: round; }
.sc-hot { stroke-width: 1.5; opacity: .5; }
.sc-run { stroke-width: 2.5; stroke-dasharray: 14 400; stroke-dashoffset: -120; }
.sc-pad { fill: var(--sc-paper); stroke: var(--sc-soft); stroke-width: 1.25; }
.sc-line.is-on .sc-pad, .scene:not(.is-armed) .sc-pad { stroke: var(--sc-current); }

/* ---- lamps: clay while current flows; green only when live or delivered ---- */
.sc-lamp { fill: var(--sc-current); stroke: none; }
.sc-halo { fill: var(--sc-warm); stroke: none; }
.sc-done.is-delivered .sc-lamp, .sc-lamp.is-delivered { fill: var(--sc-live); }
.sc-done.is-delivered .sc-halo { fill: rgba(55, 172, 52, .18); }
.sc-done .sc-tick, .sc-tick { fill: none; stroke: #FFFFFF; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.sc-form .sc-tick, .sc-cal .sc-tick { stroke: var(--sc-current); stroke-width: 1.8; }

/* ---- per part: what is lit in the final frame ---- */
.sc-screen { fill: var(--sc-warm); stroke: none; }
.sc-cell { fill: var(--sc-current); stroke: none; }
.sc-solar .sc-cell { fill: var(--sc-warm); }
.sc-pin-dot { fill: var(--sc-current); stroke: var(--sc-current); stroke-width: 1.25; }
.sc-key { fill: var(--sc-paper); stroke: var(--sc-soft); stroke-width: 1; }
.sc-agent .sc-pin { stroke: var(--sc-current); }
.sc-bolt { fill: var(--sc-current); stroke: none; }
.sc-mark { fill: none; stroke: var(--sc-current); stroke-width: 1.6; }
.sc-typing circle { opacity: 0; }
.sc-kwh text { opacity: 0; }
.sc-kwh text:last-child { opacity: 1; }

/* ---- armed and not yet on: the first frame ---- */
.is-armed :is(.sc-line, [data-at]):not(.is-on) .sc-hot,
.is-armed .sc-line:not(.is-on) .sc-run { opacity: 0; }
.is-armed [data-at]:not(.is-on) :is(.sc-lamp, .sc-halo, .sc-pop, .sc-done, .sc-txt.is-step, .sc-tick,
  .sc-cell, .sc-mark, .sc-bolt, .sc-badge, .sc-bubble-body) { opacity: 0; }
.is-armed [data-at]:not(.is-on) .sc-screen { fill: var(--sc-well); }
.is-armed [data-at]:not(.is-on) .sc-pin-dot { fill: var(--sc-paper); stroke: var(--sc-soft); }
.is-armed [data-at]:not(.is-on) .sc-pin { stroke: var(--sc-soft); }
.is-armed [data-at]:not(.is-on) .sc-pop { transform: scale(.5); }
.is-armed [data-at]:not(.is-on) .sc-tick, .is-armed [data-at]:not(.is-on) .sc-mark { stroke-dashoffset: 1.02; }
.is-armed [data-at]:not(.is-on) .sc-bolt { transform: translateX(-10px); }
.is-armed [data-at]:not(.is-on) .sc-kwh text:first-child { opacity: 1; }
.is-armed [data-at]:not(.is-on) .sc-kwh text:last-child { opacity: 0; }
.is-armed [data-at]:not(.is-on) .sc-txt.is-step { transform: translateY(4px); }
.sc-release .sc-bolt { transition: transform 420ms var(--sc-ease); }
.sc-release.is-on .sc-bolt, .scene:not(.is-armed) .sc-release .sc-bolt { transform: translateX(-10px); }
.is-armed .sc-release:not(.is-on) .sc-door { transform: none; }
.is-armed .sc-vault.is-on .sc-release:not(.is-on) .sc-bolt { opacity: 1; transform: none; }

/* ---- motion: only when armed, only when the reader allows it ---- */
@media (prefers-reduced-motion: no-preference) {
  .is-armed :is(.sc-lamp, .sc-halo, .sc-pop, .sc-done, .sc-txt.is-step, .sc-cell, .sc-bolt, .sc-badge,
    .sc-bubble-body, .sc-screen, .sc-pin-dot, .sc-pin, .sc-hot) {
    transition: opacity 320ms var(--sc-ease), transform 380ms var(--sc-ease), fill 320ms var(--sc-ease),
                stroke 320ms var(--sc-ease);
    transition-delay: calc(var(--i, 0) * var(--sc-stagger, 140ms) + var(--sc-after, 0ms));
  }
  .is-armed :is(.sc-tick, .sc-mark) { stroke-dasharray: 1.02 2; transition: stroke-dashoffset 360ms var(--sc-ease),
    opacity 1ms; transition-delay: calc(var(--i, 0) * var(--sc-stagger, 140ms) + var(--sc-after, 0ms)); }
  .is-armed .sc-line.is-on .sc-run { animation: sc-run var(--dur, 1200ms) linear both; }
  .is-armed .sc-line.is-on .sc-hot { transition-delay: calc(var(--dur, 1200ms) * .8); }
  .is-armed .sc-line.is-repeat.is-on .sc-run { animation: sc-run-rest var(--dur, 3000ms) linear infinite;
                                               animation-delay: var(--lag, 0ms); }
  .is-armed .sc-line.is-repeat .sc-hot { display: none; }
  .is-armed .sc-gen.is-on .sc-spin { animation: sc-spinup 1100ms cubic-bezier(.5, 0, 1, 1) both,
                                                 sc-spinning 600ms linear 1100ms infinite; }
  .is-armed .sc-gen.is-idle .sc-spin { animation: sc-spinning 5s linear infinite; }
  .is-armed .sc-solar.is-on .sc-rays { animation: sc-spinning 24s linear infinite; transform-box: fill-box;
                                       transform-origin: center; }
  .is-armed .sc-agent.is-on .sc-core { animation: sc-breathe 2.4s ease-in-out 900ms infinite; }
  .is-armed .sc-clock.is-on .sc-hand-m { animation: sc-turn 1600ms var(--sc-ease) both; }
  .is-armed .sc-clock.is-on .sc-hand-h { animation: sc-turn-h 1600ms var(--sc-ease) both; }
  .is-armed .sc-vault.is-on .sc-dial { animation: sc-dial 900ms var(--sc-ease) both; }
  .is-armed .sc-pinpad.is-on .sc-press { animation: sc-press 260ms ease-out both;
    animation-delay: calc(var(--i, 0) * var(--sc-stagger, 140ms)); }
  .is-armed .sc-chat.is-on .sc-typing circle { animation: sc-typing 700ms ease-in-out both;
    animation-delay: calc(var(--i, 0) * 90ms); }
  .is-armed .sc-meter.is-on .sc-kwh text { animation: sc-flash var(--for, 500ms) step-end var(--from, 0ms); }
  .is-armed .sc-meter.is-on .sc-kwh text:last-child { animation: none; transition: opacity 1ms linear var(--from, 0ms); }
  .is-armed .sc-done.is-on .sc-halo, .is-armed [data-at].is-on .sc-done .sc-halo {
    animation: sc-breathe 2.8s ease-in-out 1.2s infinite; }
  .scene.is-resetting *, .sc-power.is-resetting * { transition-duration: 240ms !important; transition-delay: 0s !important; }
  .is-paused *, .is-paused *::before, .is-paused *::after { animation-play-state: paused !important; }
}

@keyframes sc-run { from { stroke-dashoffset: 14; } to { stroke-dashoffset: -101; } }
@keyframes sc-run-rest { 0% { stroke-dashoffset: 14; } 55%, 100% { stroke-dashoffset: -101; } }
@keyframes sc-spinup { from { transform: rotate(0); } to { transform: rotate(540deg); } }
@keyframes sc-spinning { from { transform: rotate(0); } to { transform: rotate(360deg); } }
@keyframes sc-breathe { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }
@keyframes sc-turn { from { transform: rotate(-360deg); } to { transform: rotate(0); } }
@keyframes sc-turn-h { from { transform: rotate(-30deg); } to { transform: rotate(0); } }
@keyframes sc-dial { 0% { transform: rotate(0); } 60% { transform: rotate(250deg); } 100% { transform: rotate(180deg); } }
@keyframes sc-press { 0% { transform: scale(1); fill: var(--sc-paper); } 40% { transform: scale(.82); fill: var(--sc-warm); }
                      100% { transform: scale(1); fill: var(--sc-paper); } }
@keyframes sc-typing { 0%, 100% { opacity: 0; } 30%, 70% { opacity: 1; } }
@keyframes sc-flash { 0%, 100% { opacity: 1; } }

/* ---- a spark: an arc across a gap, on a copy or a call that worked ---- */
.sc-spark { position: absolute; left: 50%; top: 50%; width: 44px; height: 44px; margin: -22px 0 0 -22px;
            pointer-events: none; overflow: visible; z-index: 2; }
.sc-spark path { fill: none; stroke: var(--sc-current, #B4431F); stroke-width: 1.6; stroke-linecap: round;
                 stroke-linejoin: round; opacity: 0; transform-origin: 22px 22px; }
@media (prefers-reduced-motion: no-preference) {
  .sc-spark path { animation: sc-arc 520ms var(--sc-ease, ease-out) both; }
  .sc-spark path + path { animation-delay: 60ms; }
}
@keyframes sc-arc { 0% { opacity: 0; transform: scale(.4); } 30% { opacity: 1; } 100% { opacity: 0; transform: scale(1.15); } }
