File size: 21,615 Bytes
d32737a
 
 
5de81d5
d32737a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2ce6518
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d32737a
 
 
 
 
 
 
 
 
 
 
9b672a8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2ce6518
 
 
 
 
 
 
 
 
 
 
 
 
9b672a8
 
 
9dde5d4
 
5de81d5
 
 
9b672a8
 
 
 
 
 
cbd6f7b
 
 
 
 
 
 
 
 
 
ea31ddb
cbd6f7b
ea31ddb
cbd6f7b
ea31ddb
cbd6f7b
 
ea31ddb
 
cbd6f7b
ea31ddb
 
cbd6f7b
ea31ddb
 
 
cbd6f7b
ea31ddb
cbd6f7b
 
 
ea31ddb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e5a1b70
5de81d5
 
 
 
 
 
 
 
 
 
 
 
 
 
e5a1b70
 
 
 
5de81d5
 
 
 
 
e5a1b70
5de81d5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
/* manimo concept playground β€” themed per paper via CSS vars (set from the manifest theme by app.js). */
:root {
  --bg: #0E1116; --ink: #E8EDF3; --muted: #8B95A1; --accent: #58A6FF; --accent2: #BC8CFF; --card: #161b22;
  --clip-bg: #0A0D13;   /* close to the Manim clips' encoded dark bg β€” the video dissolves into it */
  --r: 14px; --fast: .22s; --mono: ui-monospace, SFMono-Regular, Menlo, monospace;
}
* { box-sizing: border-box; }
body { margin: 0; font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif; background: #0b0e13; color: #e8edf3; -webkit-font-smoothing: antialiased; }

.topbar { display: flex; align-items: baseline; gap: 14px; padding: 16px 24px; border-bottom: 1px solid #1c2230; position: sticky; top: 0; background: rgba(11,14,19,.85); backdrop-filter: blur(8px); z-index: 5; }
.brand { font-weight: 700; font-size: 19px; letter-spacing: .2px; }
.brand span { color: #6b7686; font-weight: 500; }
.tagline { color: #6b7686; font-size: 13px; }

.layout { display: grid; grid-template-columns: 260px 1fr; min-height: calc(100vh - 58px); }
.nav { border-right: 1px solid #1c2230; padding: 14px 10px; display: flex; flex-direction: column; gap: 6px; position: sticky; top: 58px; align-self: start; max-height: calc(100vh - 58px); overflow: auto; }
.nav-item { text-align: left; background: transparent; border: 1px solid transparent; color: #c9d3df; padding: 10px 12px; border-radius: 10px; cursor: pointer; display: flex; flex-direction: column; gap: 2px; transition: var(--fast); }
.nav-item:hover { background: #131923; }
.nav-item.on { background: #131923; border-color: #2a3346; }
.nav-t { font-weight: 600; font-size: 14px; }
.nav-s { font-size: 11px; color: #6b7686; }

.main { padding: 26px 30px 80px; background: var(--bg); color: var(--ink); transition: background var(--fast); }
.paper-head h1 { margin: 0 0 4px; font-size: 26px; }
.paper-head .sub { margin: 0 0 18px; color: var(--muted); }
.empty, .err { color: var(--muted); padding: 30px 0; }
.err { color: #ff8a8a; }

.card { background: var(--card); border: 1px solid rgba(255,255,255,.06); border-radius: var(--r); margin: 16px 0; overflow: hidden; box-shadow: 0 10px 30px rgba(0,0,0,.25); }
.card-h { display: flex; align-items: center; justify-content: space-between; padding: 13px 18px; border-bottom: 1px solid rgba(255,255,255,.06); }
.card-t { font-weight: 700; font-size: 16px; color: var(--ink); }
.tag { font-size: 11px; color: var(--bg); background: var(--accent); padding: 3px 9px; border-radius: 999px; font-weight: 600; }
.card-b { padding: 18px; }
.explainer { color: var(--muted); margin: 0 0 14px; line-height: 1.5; max-width: 70ch; }

.row { display: flex; flex-wrap: wrap; gap: 14px; align-items: center; }
.row.mats, .row.heat { align-items: flex-start; }
.ctrls { margin: 14px 0; gap: 10px; }
.sliders { gap: 18px; margin-top: 10px; }
.matcol { display: flex; flex-direction: column; gap: 6px; }
.matlbl { font-size: 12px; color: var(--muted); }
.op { font-size: 22px; color: var(--accent2); align-self: center; padding-top: 18px; }

table.mx { border-collapse: collapse; }
table.mx td { padding: 2px; }
input.cell { width: 46px; height: 34px; text-align: center; border: 1px solid rgba(255,255,255,.12); background: rgba(255,255,255,.03); color: var(--ink); border-radius: 8px; font-variant-numeric: tabular-nums; transition: var(--fast); }
input.cell:focus { outline: none; border-color: var(--accent); }
input.cell.hot { background: color-mix(in srgb, var(--accent) 28%, transparent); border-color: var(--accent); }
input.cell[readonly] { background: rgba(255,255,255,.02); color: var(--accent2); font-weight: 700; }

.btn { background: var(--accent); color: var(--bg); border: 0; padding: 9px 16px; border-radius: 10px; font-weight: 600; cursor: pointer; transition: var(--fast); }
.btn:hover { filter: brightness(1.08); transform: translateY(-1px); }
.btn.ghost { background: transparent; color: var(--ink); border: 1px solid rgba(255,255,255,.18); }
.chip { display: inline-block; background: rgba(255,255,255,.06); color: var(--ink); padding: 4px 10px; border-radius: 999px; font-size: 12px; }
.chip.acc { background: var(--accent2); color: var(--bg); font-weight: 600; }
.fld { display: inline-flex; align-items: center; gap: 8px; color: var(--muted); font-size: 13px; }
.fld input[type=range] { accent-color: var(--accent); }
.sval { color: var(--accent2); font-variant-numeric: tabular-nums; min-width: 34px; }
.sel, .lbledit { background: rgba(255,255,255,.04); color: var(--ink); border: 1px solid rgba(255,255,255,.14); border-radius: 8px; padding: 6px 8px; }
.lbledit { min-width: 260px; }
.readout { font-family: var(--mono); font-size: 13px; color: var(--ink); }

canvas.heat, canvas.plot { background: var(--bg); border: 1px solid rgba(255,255,255,.08); border-radius: 10px; }

.steps { margin-top: 14px; background: rgba(0,0,0,.18); border: 1px solid rgba(255,255,255,.06); border-radius: 10px; padding: 10px 12px; max-height: 190px; overflow: auto; font-family: var(--mono); font-size: 12.5px; }
.steps-h { color: var(--muted); font-family: system-ui; font-size: 12px; margin-bottom: 6px; text-transform: uppercase; letter-spacing: .4px; }
.step { padding: 3px 0; color: #c9d3df; opacity: .8; }
.step.acc { color: var(--ink); opacity: 1; border-left: 2px solid var(--accent2); padding-left: 8px; }
.step b { color: var(--accent2); }

/* narrative beat header (problem / prior work / takeaway …) */
.beat-head { display: flex; align-items: center; gap: 10px; margin: 0 0 8px; }
.beat-kind { font-size: 11px; font-weight: 700; letter-spacing: .5px; text-transform: uppercase; color: var(--bg);
  background: linear-gradient(135deg, var(--accent), var(--accent2)); padding: 3px 10px; border-radius: 999px; }
.beat-ttl { color: var(--ink); font-weight: 600; font-size: 15px; }

/* results: metric cards */
.metrics { display: flex; flex-wrap: wrap; gap: 12px; }
.metric { background: rgba(255,255,255,.04); border: 1px solid rgba(255,255,255,.08); border-radius: 12px; padding: 14px 18px; min-width: 130px; animation: pop var(--fast) both; }
.m-val { font-size: 26px; font-weight: 800; color: var(--accent2); font-variant-numeric: tabular-nums; }
.m-name { font-size: 12px; color: var(--muted); margin-top: 2px; }
.m-delta { font-size: 12px; color: var(--accent); margin-top: 4px; font-weight: 600; }
canvas.chart { width: 100%; max-width: 560px; }

/* compare: existing approaches vs this work */
.diagram.compare { align-items: stretch; gap: 14px; }
.vs-col { flex: 1 1 0; min-width: 140px; display: flex; flex-direction: column; gap: 8px; padding: 12px; border-radius: 12px; border: 1px solid rgba(255,255,255,.08); }
.vs-col.old { background: rgba(255,255,255,.03); }
.vs-col.new { background: color-mix(in srgb, var(--accent) 12%, transparent); border-color: color-mix(in srgb, var(--accent) 40%, transparent); }
.vs-h { font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .4px; color: var(--muted); margin-bottom: 2px; }
.vs-col.new .vs-h { color: var(--accent2); }
.vs-mid { align-self: center; color: var(--accent2); font-weight: 800; font-size: 15px; padding: 0 2px; }

/* generic diagram */
.diagram { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; padding: 16px 4px; }
.diagram.vert { flex-direction: column; align-items: flex-start; }
.diagram .node { background: var(--card); border: 2px solid var(--accent); color: var(--ink); padding: 9px 14px; border-radius: 10px; font-weight: 600; animation: pop var(--fast) both; }
.diagram .node.root { border-color: var(--accent2); }
.diagram .kids { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 8px; }
.diagram .arrow { color: var(--accent2); font-size: 20px; }
.node.flowy { box-shadow: 0 0 0 0 var(--accent); animation: pop var(--fast) both, glow 2.4s ease-in-out infinite; }
@keyframes pop { from { opacity: 0; transform: translateY(6px) scale(.92); } to { opacity: 1; transform: none; } }
@keyframes glow { 0%,100% { box-shadow: 0 0 0 0 transparent; } 50% { box-shadow: 0 0 16px -2px var(--accent); } }

/* ── Play-all transport: one click β†’ the whole paper animates in order, like the Manim video ── */
.transport {
  position: sticky; top: 58px; z-index: 4;
  display: flex; gap: 16px; align-items: center;
  padding: 14px 16px; margin: 4px 0 20px;
  border: 1px solid rgba(255,255,255,.10); border-radius: 16px;
  background:
    radial-gradient(140% 180% at 0% 0%, color-mix(in srgb, var(--accent) 16%, transparent), transparent 58%),
    color-mix(in srgb, var(--bg) 78%, #000);
  backdrop-filter: blur(10px);
  box-shadow: 0 12px 34px rgba(0,0,0,.35);
}
.transport .tbtns { display: flex; gap: 8px; flex: 0 0 auto; }
.transport .tmeta { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 9px; }
.transport .caprow { display: flex; align-items: baseline; gap: 12px; justify-content: space-between; }
.transport .cap { color: var(--ink); font-size: 13.5px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.transport .cap.ok { color: var(--accent2); }
.transport .count { color: var(--muted); font-size: 12px; font-variant-numeric: tabular-nums; font-family: var(--mono); flex: 0 0 auto; }
.transport .rail { height: 6px; border-radius: 999px; background: rgba(255,255,255,.10); overflow: hidden; }
.transport .rail .fill { display: block; height: 100%; width: 0; border-radius: 999px;
  background: linear-gradient(90deg, var(--accent), var(--accent2));
  box-shadow: 0 0 12px -1px var(--accent);
  transition: width .45s cubic-bezier(.4, 0, .2, 1); }
.btn.play { font-size: 14px; padding: 11px 20px; color: #fff;
  background: linear-gradient(135deg, var(--accent), var(--accent2));
  box-shadow: 0 6px 18px -4px var(--accent); }
.btn.play:hover { filter: brightness(1.07); }
.btn[disabled] { opacity: .42; cursor: default; transform: none; filter: none; box-shadow: none; }

/* cinema spotlight: the playing card glows, the rest recede */
.card { transition: var(--fast), opacity .35s ease, transform .35s ease, box-shadow .35s ease, border-color .35s ease; }
.main:has(.card.playing) .card:not(.playing) { opacity: .4; filter: saturate(.72); }
.card.playing { border-color: color-mix(in srgb, var(--accent) 55%, transparent);
  box-shadow: 0 0 0 1px var(--accent), 0 0 30px -4px var(--accent), 0 22px 52px rgba(0,0,0,.45);
  transform: translateY(-2px); }
.card.playing .card-h { background: linear-gradient(90deg, color-mix(in srgb, var(--accent) 14%, transparent), transparent); }

/* numbered storyboard badge on every card */
.card-h { gap: 10px; }
.card-t { flex: 1 1 auto; }
.card-n { font-family: var(--mono); font-size: 12px; font-weight: 700; color: var(--bg);
  background: var(--accent2); border-radius: 7px; padding: 2px 7px; letter-spacing: .5px; }

/* interconnection: a value flowing from one card into the next */
.flowlink { display: flex; align-items: center; gap: 9px; margin: -4px 0 -2px; padding: 6px 18px; color: var(--muted); font-size: 12.5px; }
.flowlink::before { content: ""; width: 2px; height: 20px; margin-left: 11px;
  background: linear-gradient(var(--accent), var(--accent2)); border-radius: 2px; }
.flow-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--accent2); box-shadow: 0 0 10px -1px var(--accent2); flex: 0 0 auto; }
.flow-var { font-family: var(--mono); font-weight: 700; color: var(--accent2);
  background: color-mix(in srgb, var(--accent2) 16%, transparent); padding: 1px 8px; border-radius: 6px; }
.flow-txt { color: var(--muted); }

/* token-row labels next to the input matrix */
.rowlbls { display: flex; flex-direction: column; gap: 2px; padding-top: 2px; }
.rowlbl { height: 36px; display: flex; align-items: center; color: var(--accent2); font-family: var(--mono); font-size: 12px; }

@media (prefers-reduced-motion: reduce) {
  .card, .transport .rail .fill { transition: none; }
  .card.playing { transform: none; }
  /* kill the JS-staggered reveals + infinite glow + count-up pop for motion-sensitive users */
  .diagram .node, .node.flowy, .metric { animation: none !important; }
  /* water-drop flow: drop still moves (it tracks the slide) but without the bouncy stretch/ripple/shimmer */
  .flow-stream::after, .flow-drop .bulb, .flow-ripple, body.theater .card.playing .card-b { animation: none !important; }
  .flow-drop, .flow-fill { transition: top .01s linear, height .01s linear; }
}

@media (max-width: 760px) {
  .layout { grid-template-columns: 1fr; } .nav { flex-direction: row; overflow-x: auto; position: static; max-height: none; }
  .transport { flex-direction: column; align-items: stretch; }
}

/* ── Theater mode: "Play all" goes big-screen ──────────────────────────────────────────────────────
 * Auto-entered (and OS-fullscreen requested) the instant Play all is pressed. Nav + topbar fold away,
 * the page narrows to a single column, and the ONE playing card fills the viewport so its animation is
 * large and legible β€” the rest hide so there's a single clear focus, like the Manim video full-frame.
 * Placed after the mobile query so its hiding wins even on small screens. */
body.theater { overflow: hidden; }
body.theater .topbar { display: none; }
body.theater .layout { grid-template-columns: 1fr; min-height: 100vh; }
body.theater .nav { display: none; }
body.theater .main { padding: 8px 2.5vw 0; min-height: 100vh; }
body.theater .paper-head, body.theater .flowlink { display: none; }
body.theater .transport { top: 0; margin: 0 0 8px; }

/* one card on stage, centered, filling the whole screen below the transport; the rest step aside */
body.theater .card { display: none; }
body.theater .card.playing {
  display: flex; flex-direction: column; margin: 0; overflow: hidden; transform: none;
  height: calc(100vh - 104px); width: 100%; border-radius: 18px;
}
body.theater .card.playing .card-h { padding: 14px 28px; }
body.theater .card.playing .card-t { font-size: 24px; }
body.theater .card.playing .card-b {
  flex: 1 1 auto; min-height: 0; overflow: auto;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 16px; padding: 18px 24px;
}
body.theater .card.playing .row { justify-content: center; gap: 3vw; }
body.theater .card.playing .ctrls { justify-content: center; }

/* enlarge the actual animation surfaces so they truly use the screen */
body.theater .card.playing canvas.heat { width: min(40vh, 38vw); height: min(40vh, 38vw); }
body.theater .card.playing canvas.plot { width: min(82vw, 1280px); height: auto; max-height: 60vh; }
body.theater .card.playing canvas.chart { width: min(82vw, 1280px); max-width: none; height: auto; max-height: 60vh; }
body.theater .card.playing input.cell { width: 66px; height: 50px; font-size: 21px; }
body.theater .card.playing .rowlbl { height: 52px; font-size: 15px; }
body.theater .card.playing .matlbl { font-size: 15px; }
body.theater .card.playing .op { font-size: 34px; padding-top: 24px; }
body.theater .card.playing .steps { font-size: 15px; max-height: 18vh; width: min(82vw, 1280px); }
body.theater .card.playing .diagram { padding: 8px; gap: 14px; }
body.theater .card.playing .diagram .node { font-size: 22px; padding: 16px 24px; }
body.theater .card.playing .vs-col { padding: 20px; min-width: 220px; }
body.theater .card.playing .metric { padding: 24px 34px; min-width: 190px; }
body.theater .card.playing .m-val { font-size: 44px; }
body.theater .card.playing .explainer { font-size: 17px; max-width: 90ch; text-align: center; }

/* narration toggle sits with the transport buttons */
.transport .btn.mute { padding: 9px 13px; font-size: 15px; line-height: 1; }

/* ── Manim clip hero: the real 3D Manim animation tops each slide; the widget sits below as "try it" ──
 * Seamless background: NO border/box β€” the clip's dark bg is feathered on all four edges so the video
 * dissolves into the page (the Manim scenes render on the same dark palette as the site). The feather
 * survives re-rendering, so it works no matter the exact encoded bg of each clip. */
.hero-wrap { display: flex; justify-content: center; margin: 0 0 4px; background: transparent; }
.manim-hero { width: 100%; max-width: 820px; display: block; border-radius: 14px; background: var(--clip-bg);
  -webkit-mask-image:
    linear-gradient(to right, transparent, #000 3%, #000 97%, transparent),
    linear-gradient(to bottom, transparent, #000 3.5%, #000 96.5%, transparent);
  -webkit-mask-composite: source-in;
  mask-image:
    linear-gradient(to right, transparent, #000 3%, #000 97%, transparent),
    linear-gradient(to bottom, transparent, #000 3.5%, #000 96.5%, transparent);
  mask-composite: intersect; }
.tryit { font-size: 11px; text-transform: uppercase; letter-spacing: .6px; color: var(--muted);
  display: flex; align-items: center; gap: 10px; margin: 12px 0 14px; }
.tryit::before, .tryit::after { content: ""; flex: 1 1 auto; height: 1px; background: rgba(255,255,255,.10); }

/* in theater (Play-all), the Manim clip IS the slide β€” go big, hide the widget, and drop the card panel
 * so the feathered video sits straight on the page background (fully seamless). */
body.theater .card.playing { background: transparent; box-shadow: none; border-color: transparent; }
body.theater .card.playing .card-h { background: transparent; border-bottom-color: rgba(255,255,255,.06); }
body.theater .card.playing .manim-hero { max-width: min(88vw, 1360px); max-height: 74vh; }
body.theater .card.playing .widget-body, body.theater .card.playing .tryit { display: none; }
/* hide the native video control-bar during Play-all so the clip is fully seamless β€” the transport +
 * flow rail drive playback; the gallery (non-theater) keeps controls so you can scrub each clip. */
body.theater .manim-hero::-webkit-media-controls { display: none !important; }
body.theater .manim-hero::-webkit-media-controls-enclosure { display: none !important; }
/* each new slide's content rises in from below as the drop falls to it β€” the "flowing down" feel */
body.theater .card.playing .card-b { animation: riseIn .55s cubic-bezier(.2,.7,.2,1) both; }
@keyframes riseIn { from { opacity: 0; transform: translateY(46px); } to { opacity: 1; transform: none; } }

/* ── Water-drop flow rail: a glowing teardrop descends a vertical stream, pausing at each slide ──────
 * Visible during Play-all (theater). One station per slide; the drop FALLS to the active station (a
 * gravity-eased transition), LANDS with a ripple while the slide's video plays, then falls to the next.
 * The stream shimmers like flowing water; the fill above the drop shows progress. */
.flowrail { position: fixed; left: 20px; top: 64px; bottom: 18px; width: 46px; z-index: 30;
  display: none; pointer-events: none; }
body.theater .flowrail { display: block; }
.flow-stream { position: absolute; left: 50%; top: 4%; bottom: 4%; width: 3px; transform: translateX(-50%);
  border-radius: 3px; background: rgba(255,255,255,.09); overflow: hidden; }
.flow-stream::after { content: ""; position: absolute; left: 0; right: 0; top: 0; height: 40%;
  background: linear-gradient(180deg, transparent, color-mix(in srgb, var(--accent) 75%, transparent), transparent);
  animation: streamflow 2.4s linear infinite; }
@keyframes streamflow { from { transform: translateY(-120%); } to { transform: translateY(360%); } }
.flow-fill { position: absolute; left: 50%; top: 4%; width: 3px; height: 0; transform: translateX(-50%);
  border-radius: 3px; background: linear-gradient(180deg, var(--accent), var(--accent2));
  box-shadow: 0 0 10px -1px var(--accent); transition: height .72s cubic-bezier(.5,0,.35,1); }
.flow-station { position: absolute; left: 50%; width: 11px; height: 11px; transform: translate(-50%,-50%);
  border-radius: 50%; background: #1b2230; border: 1.5px solid #2a3346; transition: var(--fast); z-index: 2; }
.flow-station.done { background: var(--accent2); border-color: var(--accent2); box-shadow: 0 0 8px -1px var(--accent2); }
.flow-station.active { background: var(--accent); border-color: #fff; box-shadow: 0 0 16px 0 var(--accent); transform: translate(-50%,-50%) scale(1.25); }
.flow-ripple { position: absolute; left: 50%; width: 12px; height: 12px; transform: translate(-50%,-50%);
  border-radius: 50%; border: 2px solid var(--accent); opacity: 0; pointer-events: none; z-index: 1; }
.flow-ripple.go { animation: rippleout .85s ease-out; }
@keyframes rippleout { 0% { opacity: .9; width: 8px; height: 8px; } 100% { opacity: 0; width: 64px; height: 64px; } }
.flow-drop { position: absolute; left: 50%; top: 4%; width: 22px; height: 22px; transform: translate(-50%,-50%);
  transition: top .72s cubic-bezier(.5,0,.35,1); z-index: 3; }
.flow-drop .bulb { width: 100%; height: 100%; border-radius: 0 50% 50% 50%; transform: rotate(45deg);
  background: radial-gradient(circle at 32% 28%, #fff, var(--accent) 46%, var(--accent2) 100%);
  box-shadow: 0 0 18px 2px color-mix(in srgb, var(--accent) 70%, transparent); }
.flow-drop.falling .bulb { animation: dropstretch .72s ease-in; }
@keyframes dropstretch { 0% { transform: rotate(45deg) scale(1,1); } 40% { transform: rotate(45deg) scale(.82,1.25); } 100% { transform: rotate(45deg) scale(1,1); } }
.flow-drop.land .bulb { animation: dropland .5s ease-out; }
@keyframes dropland { 0% { transform: rotate(45deg) scale(1.18,.8); } 55% { transform: rotate(45deg) scale(.84,1.18); } 100% { transform: rotate(45deg) scale(1,1); } }
/* clear the rail in theater so cards don't sit under it */
body.theater .main { padding-left: 78px; }