/* ===========================================================================
   Illustration: "The Prediction" (chapter IV, ember theme)
   Part 1 (.il-prediction-race): signature antivirus vs prediction, time running down.
   Part 2 (.il-prediction-tree): the nine US patents by family, on a time axis.
   Style follows #b-light (.lf / .vp): solid shapes, soft gradients, brass = checked,
   violet var(--accent) = the point (the threat, and where it is stopped).
   Default (no JS / reduced motion) is the finished drawing. Motion is one-shot,
   keyed off .is-in, which site.js adds to the .reveal figure. Each animated part
   carries its own start time in --t (and draw duration in --d). Timeline: both files
   leave at .3s; prediction stops at the gate at ~1s, protected at 1.25s; the signature
   file runs at 1.04s and is protected at 2.05s; everything settles by ~2.6s.
   =========================================================================== */
.illus--prediction { margin: 0; }
.il-prediction-grid { display: grid; gap: clamp(2.5rem, 5vw, 4rem); max-width: 620px; margin-inline: auto; }
.il-prediction-panel-wrap { min-width: 0; }
.il-prediction-kicker { font-family: var(--sans); font-weight: 600; font-size: .95rem; letter-spacing: .01em; color: var(--muted); margin: 0 0 1rem; }
.il-prediction-svg { display: block; width: 100%; height: auto; overflow: visible; color: var(--fg); }
.illus--prediction .lf-label { font-size: 18px; }
.illus--prediction .lf-small { font-family: var(--sans); font-size: 15px; font-weight: 500; }
.illus--prediction .il-prediction-h { font-size: 20px; }
.il-prediction-accent-small { fill: var(--accent); }

/* Cards, rails, nodes */
.il-prediction-card { fill: url(#il-prediction-card); stroke: var(--hair); stroke-width: 1.5; }
.il-prediction-bed { fill: none; stroke: currentColor; stroke-opacity: .12; stroke-width: 10; stroke-linecap: round; }
.il-prediction-rail { fill: none; stroke: currentColor; stroke-opacity: .5; stroke-width: 2.5; stroke-linecap: round; stroke-dasharray: 1; stroke-dashoffset: 0; }
.il-prediction-node { fill: url(#il-prediction-ball); stroke: currentColor; stroke-opacity: .5; stroke-width: 1.5; }
.il-prediction-exec { stroke: currentColor; stroke-opacity: .45; stroke-width: 1.5; stroke-dasharray: 6 7; }
.il-prediction-hit { fill: var(--accent); filter: drop-shadow(0 0 7px rgba(217,195,255,.55)); }
.il-prediction-burst { fill: none; stroke: var(--accent); stroke-width: 2; opacity: 0; }
.il-prediction-gate { fill: var(--accent); filter: drop-shadow(0 0 8px rgba(217,195,255,.6)); }
.il-prediction-tok { fill: var(--accent); stroke: rgba(255,255,255,.55); stroke-width: 1.5; filter: drop-shadow(0 0 6px rgba(217,195,255,.7)); }
.il-prediction-tok--sig { opacity: 0; } /* only seen while it travels; the finished drawing shows where it ran */
.il-prediction-port-ring { fill: none; stroke: url(#il-prediction-brass); stroke-width: 3; }
.il-prediction-port-notch { stroke: #c8b89a; stroke-width: 3; stroke-linecap: round; }
.il-prediction-port-glass { fill: url(#il-prediction-glass); }
.il-prediction-port-stripe { stroke: #e6d6b4; stroke-width: 3; stroke-linecap: round; } /* level = checked, as in the site's .port motif */

/* Patent tree */
.il-prediction-ticks { stroke: currentColor; stroke-opacity: .4; stroke-width: 1.5; }
.il-prediction-branch { fill: none; stroke: #c8b89a; stroke-width: 4; stroke-linecap: round; stroke-dasharray: 1; stroke-dashoffset: 0; }
.il-prediction-branch--ml { stroke: var(--accent); filter: drop-shadow(0 0 5px rgba(217,195,255,.45)); }
.il-prediction-leaf { fill: url(#il-prediction-ball2); stroke: url(#il-prediction-brass); stroke-width: 2.5; }
.il-prediction-leaf--ml { fill: var(--accent); stroke: rgba(255,255,255,.5); stroke-width: 1.5; filter: drop-shadow(0 0 7px rgba(217,195,255,.55)); }
.il-prediction-marks circle { fill: #c8b89a; }
.il-prediction-marks .il-prediction-mark--ml { fill: var(--accent); }

/* Light chapters (paper/day): the glows are softer and the brass deeper */
[data-theme="paper"] .illus--prediction .lf-label--brass, [data-theme="day"] .illus--prediction .lf-label--brass { fill: #7a6247; }
[data-theme="paper"] .il-prediction-branch, [data-theme="day"] .il-prediction-branch { stroke: #9c8a68; }
[data-theme="paper"] .il-prediction-branch--ml, [data-theme="day"] .il-prediction-branch--ml { stroke: var(--accent); }

/* Two panels side by side on wide screens; larger type so labels stay readable at that scale */
@media (min-width: 1200px) {
  .il-prediction-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); max-width: none; align-items: start; }
  .illus--prediction .lf-label { font-size: 19px; }
  .illus--prediction .lf-small { font-size: 16px; }
  .illus--prediction .il-prediction-h { font-size: 21px; }
}
/* Phones: the SVGs scale to ~0.6x, so every label is set at 22px to render at 12px or more */
@media (max-width: 600px) {
  .illus--prediction .lf-label, .illus--prediction .lf-small, .illus--prediction .il-prediction-h { font-size: 22px; }
  .il-prediction-kicker { font-size: .9rem; }
}
.illus--prediction figcaption { margin-top: 1.6rem; max-width: 44rem; font-size: .9rem; line-height: 1.6; letter-spacing: 0; }
.illus--prediction figcaption p + p { margin-top: .6rem; }
.illus--prediction figcaption .cite { display: inline; margin-left: .3rem; }

/* ---- Motion (one-shot) ---------------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {
  /* Steps and labels fade up as the file reaches them */
  .js .illus--prediction .il-prediction-step { transition: opacity .45s ease var(--t, 0s); }
  .js .illus--prediction:not(.is-in) .il-prediction-step { opacity: 0; }

  /* Nodes, the gate, the ports and the leaves pop into place */
  .js .illus--prediction .il-prediction-pop { transform-box: fill-box; transform-origin: center; transition: transform .55s cubic-bezier(.34, 1.56, .64, 1) var(--t, 0s), opacity .3s ease var(--t, 0s); }
  .js .illus--prediction:not(.is-in) .il-prediction-pop { transform: scale(.15); opacity: 0; }
  .js .illus--prediction:not(.is-in) .il-prediction-gate { transform: scaleX(0); }

  /* The rails light up behind the travelling file */
  .js .illus--prediction:not(.is-in) .il-prediction-rail,
  .js .illus--prediction:not(.is-in) .il-prediction-branch { stroke-dashoffset: 1; }
  .js .illus--prediction .il-prediction-rail--sig { transition: stroke-dashoffset 1.75s linear .3s; }
  .js .illus--prediction .il-prediction-rail--pre { transition: stroke-dashoffset .7s cubic-bezier(.3, .5, .4, 1) .3s; }
  .js .illus--prediction .il-prediction-branch { transition: stroke-dashoffset var(--d, .6s) linear var(--t, 0s); }

  /* The file: on the left it keeps going (it runs); on the right it is stopped at the gate */
  .js .illus--prediction.is-in .il-prediction-tok--sig { animation: il-prediction-sig 1.75s linear .3s both; }
  .js .illus--prediction.is-in .il-prediction-tok--pre { animation: il-prediction-pre .7s cubic-bezier(.3, .5, .4, 1) .3s both; }
  .js .illus--prediction:not(.is-in) .il-prediction-tok { opacity: 0; }

  /* The moment it runs: one soft ring, once */
  .js .illus--prediction.is-in .il-prediction-burst { animation: il-prediction-burst .9s ease-out 1.04s both; }

  /* The brass check swings level when protection arrives */
  .js .illus--prediction .il-prediction-port-stripe { transform-box: fill-box; transform-origin: center; transition: transform .5s var(--ease-out, ease-out) calc(var(--t, 0s) + .05s); }
  .js .illus--prediction:not(.is-in) .il-prediction-port-stripe { transform: rotate(-28deg); }
}
@keyframes il-prediction-sig {
  0% { transform: translateY(0); opacity: 1; }
  93% { opacity: 1; }
  100% { transform: translateY(556px); opacity: 0; }
}
@keyframes il-prediction-pre {
  from { transform: translateY(-182px); }
  to { transform: translateY(0); }
}
@keyframes il-prediction-burst {
  0% { transform: scale(1); opacity: .9; }
  100% { transform: scale(3.2); opacity: 0; }
}
.il-prediction-burst { transform-box: fill-box; transform-origin: center; }
