/* The product demo (LEDGER 2026-10-13, "a plain product demo"): the real screens in a phone drawn in CSS, one step
   after another. Motion is transform and opacity only: steps crossfade, frames captured at different moments
   crossfade inside a step (the haze lifting, the burst), a touch dot follows the set dial, a ripple marks a tap.
   demo.js runs the timeline and pauses it off screen; under Reduce Motion it never runs, each step shows its key frame
   and prev / next move by hand. Colours and sizes come from /canon.css and /tokens.css. */
.demo, .device.still {
  --w: min(18rem, 72vw); /* the device */
  --bz: calc(var(--w) * 0.034); /* its bezel */
  --sw: calc(var(--w) - 2 * var(--bz)); /* its screen */
}
@media (min-width: 56rem) { .demo { --w: 19.5rem; } .device.still { --w: 16.5rem; } }
.demo { margin: 0; display: grid; justify-items: center; gap: var(--space-4); width: max-content; max-width: 100%; }

/* the phone */
.device {
  position: relative; width: var(--w); padding: var(--bz); border-radius: calc(var(--sw) * 0.14 + var(--bz));
  background: var(--ground-deep); box-shadow: var(--glass-edge), 0 0 0 1px var(--hairline), var(--frost-drop);
}
.screen {
  position: relative; aspect-ratio: 1320 / 2868; border-radius: calc(var(--sw) * 0.14);
  overflow: hidden; background: var(--ground); isolation: isolate;
}
.island {
  position: absolute; z-index: 3; left: 50%; top: calc(var(--bz) + var(--sw) * 0.026);
  width: calc(var(--sw) * 0.33); height: calc(var(--sw) * 0.098); margin-left: calc(var(--sw) * -0.165);
  border-radius: var(--radius-pill); background: var(--ground-deep);
}
.screen img { position: absolute; inset: 0; width: 100%; height: 100%; max-width: none; object-fit: cover; }

/* steps and their frames */
.step { position: absolute; inset: 0; opacity: 0; transition: opacity 0.5s ease; }
.step.on { opacity: 1; z-index: 2; }
.step.was { opacity: 1; z-index: 1; transition: none; }
.step .f { opacity: 0; }
.step .f:first-child { opacity: 1; }

.step.on .dial-a, .step.was .dial-a { animation: dial-a var(--d) linear both; }
.step.on .dial-b, .step.was .dial-b { animation: dial-b var(--d) linear both; }
.step.on .dial-c, .step.was .dial-c { animation: dial-c var(--d) linear both; }
.step.on .dial-d, .step.was .dial-d { animation: dial-d var(--d) linear both; }
.step.on .haze-a, .step.was .haze-a { animation: haze-a var(--d) linear both; }
.step.on .haze-b, .step.was .haze-b { animation: haze-b var(--d) linear both; }
.step.on .burst-a, .step.was .burst-a { animation: burst-a var(--d) linear both; }
.step.on .burst-b, .step.was .burst-b { animation: burst-b var(--d) linear both; }
.step.on .burst-c, .step.was .burst-c { animation: burst-c var(--d) ease-out both; }
/* Declare: the set dial turned from 25 to 50 minutes, as five captures of the real screen (25, 30, 35, 42, 50). Each
   fades in as the touch dot passes its handle (the dot's own timeline is `drag` below), so the ring turns. */
@keyframes dial-a { 0%, 21% { opacity: 0; } 25%, 100% { opacity: 1; } }
@keyframes dial-b { 0%, 31% { opacity: 0; } 35%, 100% { opacity: 1; } }
@keyframes dial-c { 0%, 45% { opacity: 0; } 49%, 100% { opacity: 1; } }
@keyframes dial-d { 0%, 60% { opacity: 0; } 65%, 100% { opacity: 1; } }
@keyframes haze-a { 0%, 14% { opacity: 0; } 50%, 100% { opacity: 1; } }
@keyframes haze-b { 0%, 56% { opacity: 0; } 90%, 100% { opacity: 1; } }
@keyframes burst-a { 0%, 7% { opacity: 0; } 18%, 100% { opacity: 1; } }
@keyframes burst-b { 0%, 22% { opacity: 0; } 36%, 100% { opacity: 1; } }
@keyframes burst-c { 0%, 42% { opacity: 0; } 70%, 100% { opacity: 1; } }

/* a touch: a soft dot with a ring. The drag rides a 0 x 0 pivot at the dial's centre, so a rotation walks it round. */
.touch, .drag i {
  position: absolute; width: calc(var(--sw) * 0.13); height: calc(var(--sw) * 0.13);
  border-radius: 50%; border: 2px solid var(--ink); background: var(--track); opacity: 0;
}
.touch { left: var(--x); top: var(--y); margin: calc(var(--sw) * -0.065) 0 0 calc(var(--sw) * -0.065); }
.drag { position: absolute; left: var(--x); top: var(--y); width: 0; height: 0; transform: rotate(150deg); }
.drag i { left: calc(var(--sw) * -0.065); top: calc(var(--sw) * -0.065); transform: translateY(calc(var(--sw) * var(--r) * -1)); }

.step.on .drag { animation: drag var(--d) both; }
.step.on .drag i { animation: drag-dot var(--d) linear both; }
.step.on .touch.late { animation: tap-late var(--d) linear both; }
.step.on .touch.early { animation: tap-early var(--d) linear both; }
/* the set dial, from 25 to 50 minutes: its handle sits at 6 degrees a minute (150, 180, 210, 252 and 300 degrees in the
   five captures); the dot is held on the handle at 25 and rides the ring to 50, then the finger lifts and taps Declare it */
@keyframes drag {
  0%, 12% { transform: rotate(150deg); animation-timing-function: cubic-bezier(0.4, 0, 1, 1); }
  23% { transform: rotate(180deg); animation-timing-function: linear; }
  33% { transform: rotate(210deg); animation-timing-function: linear; }
  47% { transform: rotate(252deg); animation-timing-function: cubic-bezier(0, 0, 0.4, 1); }
  62%, 100% { transform: rotate(300deg); }
}
@keyframes drag-dot { 0%, 6% { opacity: 0; } 11%, 66% { opacity: 1; } 72%, 100% { opacity: 0; } }
@keyframes tap-late {
  0%, 77% { opacity: 0; transform: scale(0.5); }
  81% { opacity: 1; transform: scale(0.7); }
  96%, 100% { opacity: 0; transform: scale(1.5); }
}
@keyframes tap-early {
  0%, 4% { opacity: 0; transform: scale(0.5); }
  8% { opacity: 1; transform: scale(0.7); }
  24%, 100% { opacity: 0; transform: scale(1.5); }
}

/* the caption: one line per step, in one grid cell so the height never jumps */
.demo figcaption { display: grid; gap: var(--space-3); justify-items: center; width: 100%; }
.caps { display: grid; margin: 0; padding: 0; list-style: none; width: min(100%, calc(var(--w) + var(--space-16))); }
.cap {
  grid-area: 1 / 1; text-align: center; opacity: 0; transition: opacity 0.4s ease;
  font: var(--w-heading) var(--fs-heading)/1.3 var(--font-sans);
}
.cap.on { opacity: 1; }

/* controls: prev, six segments (discrete steps), next, pause. Hidden until demo.js runs. */
.controls { display: none; align-items: center; gap: var(--space-1); }
.demo.live .controls { display: flex; }
.ctl {
  display: inline-grid; place-items: center; width: var(--space-12); height: var(--space-12); padding: 0;
  border: 0; border-radius: var(--radius-pill); color: var(--ink); cursor: pointer;
}
.ctl svg { width: var(--space-5); height: var(--space-5); }
.ctl .play, .ctl.stopped .pause { display: none; }
.ctl.stopped .play { display: block; }
.segs { display: flex; }
.seg {
  position: relative; width: calc(var(--space-6) + var(--space-1)); height: var(--space-12);
  padding: 0; border: 0; background: none; cursor: pointer;
}
.seg::before, .seg i {
  content: ''; position: absolute; left: var(--space-1); right: var(--space-1); top: 50%; height: var(--space-1);
  margin-top: calc(var(--space-1) / -2); border-radius: var(--radius-pill); background: var(--track);
}
.seg i { background: var(--ink); transform: scaleX(0); transform-origin: left center; }
.seg.done i { transform: scaleX(1); background: var(--ink-muted); }
.seg.on i { transform: scaleX(1); }
.demo.live:not(.manual) .seg.on i { animation: fill var(--d) linear both; }
@keyframes fill { from { transform: scaleX(0); } to { transform: scaleX(1); } }

/* held: off screen, or the viewer pressed pause */
.demo.paused .step *, .demo.paused .seg i { animation-play-state: paused !important; }

/* ?demo=N&t=0.5: one step held at one moment, for review shots (no crossfade between steps, so the shot is that step) */
.demo.frozen .step, .demo.frozen .cap { transition: none; }
.demo.frozen .step.on, .demo.frozen .step.on *, .demo.frozen .seg.on i {
  animation-play-state: paused !important; animation-delay: calc(var(--d) * var(--t) * -1) !important;
}

/* Reduce Motion, or no script: no timeline. Each step shows its key frame; crossfades stay (CANON § Animation budget). */
.demo.manual .step .f { opacity: 0; animation: none !important; }
.demo.manual .step .f.key { opacity: 1; }
.demo.manual .drag, .demo.manual .drag i, .demo.manual .touch { animation: none !important; }
.demo.manual .ctl[data-toggle] { display: none; }
@media (prefers-reduced-motion: reduce) {
  .step, .cap { transition-duration: 0.16s; }
}
