whiskers.git / assets / whiskers / whiskers-thinking.svg
whiskers-thinking.svg516 lines · 24.8 KB · raw
1<svg xmlns="http://www.w3.org/2000/svg" viewBox="-15 -25 45 45" width="500" height="500">
2  <!-- clawd thinking bubble v25 (2026-05-15)
3
4       v25 = v24 + dreamy edge-flow rewrite.
5       Lu's call: v24 flow pixels read as broken — codex used
6       step-end (hard on/off) + translate jumps + scattered
7       positions across different sides, so the eye reads
8       "buggy detached pixel" not "edge flow".
9
10       Fix: 4 pale-blue 1x1 pixels per bubble, each sitting
11       exactly 1px outside one flat edge (top / right / bottom
12       / left of rim). They fade in and out softly via
13       ease-in-out opacity only (no transform), staggered 6%
14       apart so adjacent pixels overlap during their fades.
15       The eye reads this as a single highlight marching
16       clockwise around the rim — the dreamy / imagining /
17       thought-cloud signature Lu asked for.
18
19       v24 = v23 + "脚站定不动".
20       Lu's call: legs jiggling per body-lean reads as restless.
21       Fix: lift the 4 leg <rect>s out of #clawd-body so they do
22       NOT inherit body-attend rotate/translate or body-breathe
23       scale. Torso / arm / eyes still inherit body motion as
24       before. The leg-*-think keyframes are no longer
25       referenced (kept defined for diff clarity, no perf cost).
26
27       Side note: torso底部边缘旋转时会与脚顶部出现 0.1-0.2px
28       的极小错位 (max body-attend rotate ≈ 2.6deg around y=13
29       即脚顶部基线), 桌宠尺寸下肉眼不可见。
30
31       v23 from v22 critique: "not cute / not精致".
32       Five fixes layered on top of v22 timing:
33         1. Bubble tail: chat-style stair removed.
34            Now a real "thought bubble chain" — main bubble +
35            two recurring small puffs (1px and 0.5px) trailing
36            down to clawd's head. This is the manga thought-cloud
37            signature; clawd looks like he is thinking, not being
38            messaged.
39         2. Eyes react: rect eyes during the thinking hold
40            switch to ^^ smile eyes for a "got it!" beat
41            during the third dot reveal, then blink back to rect
42            before the bubble exits. Uses technique 14
43            (blink-cover swap from rect to smile).
44         3. Inspiration sparkle: a small + pops above the
45            bubble exactly when the smile happens, technique 8
46            "double-flash" reused as a single emphatic blink.
47         4. Chin-rest arm now visible: same-side arm rotates
48            ~50deg with a translate so the hand actually reaches
49            the cheek/chin area, not the previous +22deg micro-tilt.
50         5. Bubble tone switched to white (#FFFFFF), with dots
51            in a slightly deeper Clawd blue (#256891) so they read
52            clearly inside the bubble.
53         6. White bubble gets subtle pale-blue pixels outside the
54            rim, stepping around the outer contour for a small
55            pixel-flow feel while keeping the interior clean.
56
57       Timing, 12s loop (three slow dot reveals per side):
58         0-3%    idle
59         3-7%    notice left + left bubble arrives
60         7-43%   left thinking, three slow dot reveals
61         43-44%  blink (cover swap rect -> smile)
62         44-48%  "got it" smile + + flash
63         48-49%  blink (cover swap smile -> rect)
64         49-52%  left bubble leaves
65         52-54%  very short neutral reset
66         54-58%  notice right + right bubble arrives
67         58-92%  right thinking, three slow dot reveals
68         92-93%  blink (cover swap rect -> smile)
69         93-96%  "got it" smile + + flash
70         96-97%  blink (cover swap smile -> rect)
71         97-99%  right bubble leaves
72         99-100% short loop-end idle
73  -->
74
75  <defs>
76    <style>
77      #ground-shadow {
78        transform-box: view-box;
79        transform-origin: 7.5px 15.5px;
80        animation: shadow-think 12s infinite ease-in-out;
81      }
82
83      .body-breathe {
84        transform-box: view-box;
85        transform-origin: 7.5px 13px;
86        animation: body-breathe 12s infinite ease-in-out;
87      }
88
89      .body-attend {
90        transform-box: view-box;
91        transform-origin: 7.5px 13px;
92        animation: body-attend 12s infinite ease-in-out;
93      }
94
95      .arm-left,
96      .arm-right,
97      .leg-left-inner,
98      .leg-left-outer,
99      .leg-right-inner,
100      .leg-right-outer {
101        transform-box: fill-box;
102        transform-origin: 50% 0%;
103      }
104
105      .arm-left {
106        transform-origin: 100% 0%;
107        animation: arm-left-think 12s infinite ease-in-out;
108      }
109      .arm-right {
110        transform-origin: 0% 0%;
111        animation: arm-right-think 12s infinite ease-in-out;
112      }
113      .leg-right-inner { animation: leg-right-inner-think 12s infinite ease-in-out; }
114      .leg-right-outer { animation: leg-right-outer-think 12s infinite ease-in-out; }
115      .leg-left-inner  { animation: leg-left-inner-think  12s infinite ease-in-out; }
116      .leg-left-outer  { animation: leg-left-outer-think  12s infinite ease-in-out; }
117
118      .eyes {
119        transform-box: view-box;
120        transform-origin: 7.5px 9px;
121        animation: eyes-think 12s infinite ease-in-out;
122      }
123
124      .eyes-rect  { animation: eyes-rect-vis  12s infinite step-end; }
125      .eyes-smile { opacity: 0; animation: eyes-smile-vis 12s infinite step-end; }
126
127      .left-bubble,
128      .right-bubble {
129        transform-box: fill-box;
130        transform-origin: 50% 100%;
131        opacity: 0;
132      }
133      .left-bubble  { animation: left-bubble-life 12s infinite ease-in-out; }
134      .right-bubble { animation: right-bubble-life 12s infinite ease-in-out; }
135
136      .dot { opacity: 0; }
137      .left-bubble  .dot1 { animation: left-dot-1  12s infinite step-end; }
138      .left-bubble  .dot2 { animation: left-dot-2  12s infinite step-end; }
139      .left-bubble  .dot3 { animation: left-dot-3  12s infinite step-end; }
140      .right-bubble .dot1 { animation: right-dot-1 12s infinite step-end; }
141      .right-bubble .dot2 { animation: right-dot-2 12s infinite step-end; }
142      .right-bubble .dot3 { animation: right-dot-3 12s infinite step-end; }
143
144      .bubble-flow {
145        opacity: 0;
146      }
147      .left-bubble  .flow1 { animation: left-flow-1  12s infinite ease-in-out; }
148      .left-bubble  .flow2 { animation: left-flow-2  12s infinite ease-in-out; }
149      .left-bubble  .flow3 { animation: left-flow-3  12s infinite ease-in-out; }
150      .left-bubble  .flow4 { animation: left-flow-4  12s infinite ease-in-out; }
151      .right-bubble .flow1 { animation: right-flow-1 12s infinite ease-in-out; }
152      .right-bubble .flow2 { animation: right-flow-2 12s infinite ease-in-out; }
153      .right-bubble .flow3 { animation: right-flow-3 12s infinite ease-in-out; }
154      .right-bubble .flow4 { animation: right-flow-4 12s infinite ease-in-out; }
155
156      .left-spark,
157      .right-spark {
158        transform-box: fill-box;
159        transform-origin: 50% 50%;
160        opacity: 0;
161      }
162      .left-spark  { animation: left-spark-bling  12s infinite ease-out; }
163      .right-spark { animation: right-spark-bling 12s infinite ease-out; }
164
165      @keyframes shadow-think {
166        0%, 3%, 52%, 99%, 100%      { opacity: 0.5; transform: translateX(0) scaleX(1); }
167        15%, 43%                    { opacity: 0.4; transform: translateX(-0.28px) scaleX(0.9); }
168        70%, 96%                    { opacity: 0.4; transform: translateX(0.28px) scaleX(0.9); }
169      }
170
171      @keyframes body-breathe {
172        0%, 3%, 52%, 99%, 100%      { transform: scale(1, 1) translateY(0); }
173        15%, 29%, 43%, 70%, 84%, 96% { transform: scale(1.006, 0.994) translateY(0.08px); }
174        22%, 36%, 64%, 78%, 90%     { transform: scale(1.014, 0.986) translateY(0.18px); }
175        54%                         { transform: scale(0.996, 1.004) translateY(-0.08px); }
176      }
177
178      @keyframes body-attend {
179        0%, 3%, 52%, 99%, 100%      { transform: translate(0, 0) rotate(0deg); }
180        7%                          { transform: translate(-0.3px, 0.08px) rotate(-1.6deg); }
181        15%                         { transform: translate(-0.48px, 0.14px) rotate(-2.6deg); }
182        30%                         { transform: translate(-0.45px, 0.1px) rotate(-2.3deg); }
183        42%                         { transform: translate(-0.4px, 0.08px) rotate(-2.0deg); }
184        49%                         { transform: translate(-0.2px, 0.04px) rotate(-0.8deg); }
185        51%                         { transform: translate(-0.05px, 0) rotate(-0.2deg); }
186        54%                         { transform: translate(0, 0.08px) rotate(0deg); }
187        58%                         { transform: translate(0.3px, 0.08px) rotate(1.6deg); }
188        70%                         { transform: translate(0.48px, 0.14px) rotate(2.6deg); }
189        84%                         { transform: translate(0.45px, 0.1px) rotate(2.3deg); }
190        96%                         { transform: translate(0.32px, 0.06px) rotate(1.4deg); }
191        98%                         { transform: translate(0.05px, 0) rotate(0.2deg); }
192      }
193
194      /*
195        v23 chin-rest arm: noticeable lift instead of v22's
196        invisible +22deg / -1px microtilt. Same-side arm
197        rotates ~52deg + translate so the hand physically
198        reaches the cheek line.
199      */
200      /*
201        v23 arm: per Lu's call, restored verbatim from v22.
202        v22's micro-tilt feels "still" but does not stutter.
203        The other v23 changes (bubble chain / smile eyes /
204        sparkle / timing) are kept on top.
205      */
206      @keyframes arm-left-think {
207        0%, 3%, 52%, 99%, 100%      { transform: translate(0, 0) rotate(0deg); }
208        7%                          { transform: translate(0.18px, -0.7px) rotate(14deg); }
209        15%, 49%                    { transform: translate(0.35px, -1.05px) rotate(22deg); }
210        30%                         { transform: translate(0.28px, -0.92px) rotate(26deg); }
211        58%, 96%                    { transform: translate(-0.08px, 0.45px) rotate(0deg); }
212        84%                         { transform: translate(-0.12px, 0.55px) rotate(0deg); }
213      }
214      @keyframes arm-right-think {
215        0%, 3%, 52%, 99%, 100%      { transform: translate(0, 0) rotate(0deg); }
216        7%, 49%                     { transform: translate(0.08px, 0.45px) rotate(0deg); }
217        30%                         { transform: translate(0.12px, 0.55px) rotate(0deg); }
218        58%                         { transform: translate(-0.18px, -0.7px) rotate(-14deg); }
219        70%, 96%                    { transform: translate(-0.35px, -1.05px) rotate(-22deg); }
220        84%                         { transform: translate(-0.28px, -0.92px) rotate(-26deg); }
221      }
222
223      @keyframes leg-right-inner-think {
224        0%, 3%, 39%, 98%, 100%      { transform: rotate(0deg) translateY(0); }
225        8%, 34%                     { transform: rotate(7deg) translateY(-0.12px); }
226        20%                         { transform: rotate(9deg) translateY(-0.2px); }
227        42%, 94%                    { transform: rotate(-4deg) translateY(-0.08px); }
228        70%                         { transform: rotate(-5deg) translateY(-0.14px); }
229      }
230      @keyframes leg-right-outer-think {
231        0%, 3%, 39%, 98%, 100%      { transform: rotate(0deg) translateY(0); }
232        8%, 34%                     { transform: rotate(10deg) translateY(-0.18px); }
233        20%                         { transform: rotate(12deg) translateY(-0.26px); }
234        42%, 94%                    { transform: rotate(-5deg) translateY(-0.1px); }
235        70%                         { transform: rotate(-6deg) translateY(-0.16px); }
236      }
237      @keyframes leg-left-inner-think {
238        0%, 3%, 39%, 98%, 100%      { transform: rotate(0deg) translateY(0); }
239        8%, 34%                     { transform: rotate(4deg) translateY(-0.08px); }
240        20%                         { transform: rotate(5deg) translateY(-0.14px); }
241        42%, 94%                    { transform: rotate(-7deg) translateY(-0.12px); }
242        70%                         { transform: rotate(-9deg) translateY(-0.2px); }
243      }
244      @keyframes leg-left-outer-think {
245        0%, 3%, 39%, 98%, 100%      { transform: rotate(0deg) translateY(0); }
246        8%, 34%                     { transform: rotate(5deg) translateY(-0.1px); }
247        20%                         { transform: rotate(6deg) translateY(-0.16px); }
248        42%, 94%                    { transform: rotate(-10deg) translateY(-0.18px); }
249        70%                         { transform: rotate(-12deg) translateY(-0.26px); }
250      }
251
252      /*
253        v23 eyes: thinking squint + blink-cover swap to ^^ smile
254        at 43%/48% (left) and 92%/97% (right).
255        scaleY(0.85) during thinking = subtle squint.
256        scaleY(0.12) at swap = full blink that hides the
257        rect->smile / smile->rect transition.
258      */
259      @keyframes eyes-think {
260        0%, 3%, 52%, 99%, 100%      { transform: translate(0, 0) scaleY(1); }
261        5%                          { transform: translate(-0.3px, -0.5px) scaleY(0.95); }
262        9%, 42%                     { transform: translate(-0.45px, -0.78px) scaleY(0.85); }
263        43%                         { transform: translate(-0.45px, -0.78px) scaleY(0.12); }
264        44%, 47%                    { transform: translate(-0.45px, -0.78px) scaleY(1); }
265        48%                         { transform: translate(-0.45px, -0.78px) scaleY(0.12); }
266        50%                         { transform: translate(-0.15px, -0.25px) scaleY(0.95); }
267        54%                         { transform: translate(0, 0) scaleY(0.18); }
268        55%                         { transform: translate(0.3px, -0.5px) scaleY(0.95); }
269        59%, 88%                    { transform: translate(0.45px, -0.78px) scaleY(0.85); }
270        92%                         { transform: translate(0.45px, -0.78px) scaleY(0.12); }
271        93%, 96%                    { transform: translate(0.45px, -0.78px) scaleY(1); }
272        97%                         { transform: translate(0.45px, -0.78px) scaleY(0.12); }
273        98%                         { transform: translate(0.2px, -0.4px) scaleY(0.95); }
274        100%                        { transform: translate(0, 0) scaleY(1); }
275      }
276
277      @keyframes eyes-rect-vis {
278        0%   { opacity: 1; }
279        43%  { opacity: 0; }
280        48%  { opacity: 1; }
281        92%  { opacity: 0; }
282        97%  { opacity: 1; }
283      }
284      @keyframes eyes-smile-vis {
285        0%   { opacity: 0; }
286        43%  { opacity: 1; }
287        48%  { opacity: 0; }
288        92%  { opacity: 1; }
289        97%  { opacity: 0; }
290      }
291
292      @keyframes left-bubble-life {
293        0%, 3%    { opacity: 0; transform: translate(-0.2px, 0.7px) scale(0.82); }
294        5%        { opacity: 0.75; transform: translate(-0.1px, 0.25px) scale(0.94); }
295        7%        { opacity: 1; transform: translate(0, 0) scale(1.04); }
296        10%, 43%  { opacity: 1; transform: translate(0, 0) scale(1); }
297        46%       { opacity: 1; transform: translate(0, -0.2px) scale(1.02); }
298        48%       { opacity: 1; transform: translate(0, -0.18px) scale(1.01); }
299        49%       { opacity: 1; transform: translate(0, 0) scale(1); }
300        52%       { opacity: 0; transform: translate(0, 0.65px) scale(0.9); }
301        53%, 100% { opacity: 0; transform: translate(0, 0.65px) scale(0.9); }
302      }
303
304      @keyframes right-bubble-life {
305        0%, 53%        { opacity: 0; transform: translate(0.2px, 0.7px) scale(0.82); }
306        54%            { opacity: 0.75; transform: translate(0.1px, 0.25px) scale(0.94); }
307        58%            { opacity: 1; transform: translate(0, 0) scale(1.04); }
308        61%, 92%       { opacity: 1; transform: translate(0, 0) scale(1); }
309        94%            { opacity: 1; transform: translate(0, -0.2px) scale(1.02); }
310        96%            { opacity: 1; transform: translate(0, -0.18px) scale(1.01); }
311        97%            { opacity: 1; transform: translate(0, 0) scale(1); }
312        99%            { opacity: 0; transform: translate(0, 0.65px) scale(0.9); }
313        100%           { opacity: 0; transform: translate(0, 0.65px) scale(0.9); }
314      }
315
316      @keyframes left-dot-1 {
317        0%, 7.99%, 17.99%, 19.99%, 29.99%, 31.99%, 48.99%, 100% { opacity: 0; }
318        8%, 17.98%, 20%, 29.98%, 32%, 48.98%                    { opacity: 1; }
319      }
320      @keyframes left-dot-2 {
321        0%, 11.99%, 17.99%, 23.99%, 29.99%, 35.99%, 48.99%, 100% { opacity: 0; }
322        12%, 17.98%, 24%, 29.98%, 36%, 48.98%                    { opacity: 1; }
323      }
324      @keyframes left-dot-3 {
325        0%, 15.99%, 17.99%, 27.99%, 29.99%, 39.99%, 48.99%, 100% { opacity: 0; }
326        16%, 17.98%, 28%, 29.98%, 40%, 48.98%                    { opacity: 1; }
327      }
328      @keyframes right-dot-1 {
329        0%, 58.99%, 68.99%, 70.99%, 80.99%, 82.99%, 98.49%, 100% { opacity: 0; }
330        59%, 68.98%, 71%, 80.98%, 83%, 98.48%                    { opacity: 1; }
331      }
332      @keyframes right-dot-2 {
333        0%, 62.99%, 68.99%, 74.99%, 80.99%, 86.99%, 98.49%, 100% { opacity: 0; }
334        63%, 68.98%, 75%, 80.98%, 87%, 98.48%                    { opacity: 1; }
335      }
336      @keyframes right-dot-3 {
337        0%, 66.99%, 68.99%, 78.99%, 80.99%, 90.99%, 98.49%, 100% { opacity: 0; }
338        67%, 68.98%, 79%, 80.98%, 91%, 98.48%                    { opacity: 1; }
339      }
340
341      /*
342        v25 edge-flow keyframes.
343        Each pixel: opacity 0 -> 0.7 -> 0 over a 12% window,
344        with 6% stagger between adjacent pixels so two are
345        always overlapping mid-fade. Pure opacity, no transform
346        (v24's translate jumps were the broken-pixel feel).
347        Window math:
348          left thinking phase  = 10-43%
349          right thinking phase = 60-92%
350        flow1 = top rim, flow2 = right rim,
351        flow3 = bottom rim, flow4 = left rim (clockwise).
352      */
353      @keyframes left-flow-1 {
354        0%, 10%, 22%, 100% { opacity: 0; }
355        14%, 18%           { opacity: 0.7; }
356      }
357      @keyframes left-flow-2 {
358        0%, 16%, 28%, 100% { opacity: 0; }
359        20%, 24%           { opacity: 0.7; }
360      }
361      @keyframes left-flow-3 {
362        0%, 22%, 34%, 100% { opacity: 0; }
363        26%, 30%           { opacity: 0.7; }
364      }
365      @keyframes left-flow-4 {
366        0%, 28%, 40%, 100% { opacity: 0; }
367        32%, 36%           { opacity: 0.7; }
368      }
369      @keyframes right-flow-1 {
370        0%, 62%, 74%, 100% { opacity: 0; }
371        66%, 70%           { opacity: 0.7; }
372      }
373      @keyframes right-flow-2 {
374        0%, 68%, 80%, 100% { opacity: 0; }
375        72%, 76%           { opacity: 0.7; }
376      }
377      @keyframes right-flow-3 {
378        0%, 74%, 86%, 100% { opacity: 0; }
379        78%, 82%           { opacity: 0.7; }
380      }
381      @keyframes right-flow-4 {
382        0%, 80%, 92%, 100% { opacity: 0; }
383        84%, 88%           { opacity: 0.7; }
384      }
385
386      /*
387        v23 sparkle bling: single emphatic flash at "got it"
388        moment (left 28-32% / right 71-82%).
389        scale + opacity pulse from technique 8.
390      */
391      @keyframes left-spark-bling {
392        0%, 43%, 49%, 100% { opacity: 0; transform: scale(0.4); }
393        44%                { opacity: 0; transform: scale(0.5); }
394        45%                { opacity: 1; transform: scale(1.35); }
395        46.5%              { opacity: 1; transform: scale(1); }
396        48%                { opacity: 0.4; transform: scale(0.7); }
397      }
398      @keyframes right-spark-bling {
399        0%, 91%, 97%, 100% { opacity: 0; transform: scale(0.4); }
400        92%                { opacity: 0; transform: scale(0.5); }
401        93%                { opacity: 1; transform: scale(1.35); }
402        94.5%              { opacity: 1; transform: scale(1); }
403        96%                { opacity: 0.4; transform: scale(0.7); }
404      }
405    </style>
406  </defs>
407
408  <rect id="ground-shadow" x="3" y="15" width="9" height="1" fill="#000000" opacity="0.5"/>
409
410  <!--
411    v24: legs are lifted out of #clawd-body so they do not inherit
412    body-attend (rotate/translate toward bubble) or body-breathe
413    (scale). Rendered before #master-group so the torso (which is
414    inside master-group) draws on top of the leg tops as before.
415  -->
416  <g id="legs-static" fill="#DE886D">
417    <rect id="outer-left-leg"  x="3"  y="13" width="1" height="2"/>
418    <rect id="inner-left-leg"  x="5"  y="13" width="1" height="2"/>
419    <rect id="inner-right-leg" x="9"  y="13" width="1" height="2"/>
420    <rect id="outer-right-leg" x="11" y="13" width="1" height="2"/>
421  </g>
422
423  <g id="master-group">
424    <g class="body-breathe">
425      <g id="clawd-body" class="body-attend">
426        <g id="body-color-group" fill="#DE886D">
427          <g class="cat-behind" fill="#DE886D">
428        <rect x="2" y="5" width="1" height="2"/><rect x="3" y="4" width="1" height="3"/>
429        <rect x="11" y="4" width="1" height="3"/><rect x="12" y="5" width="1" height="2"/>
430        <rect x="13" y="12" width="2" height="1"/><rect x="14" y="10.5" width="1" height="1.5"/>
431      </g>
432      <g class="cat-inner-ear" fill="#F2A7B0">
433        <rect x="3" y="5" width="1" height="2"/><rect x="11" y="5" width="1" height="2"/>
434      </g>
435      <rect id="torso" x="2" y="6" width="11" height="7"/>
436      <g class="cat-face">
437        <rect x="7" y="9.5" width="1" height="1" fill="#F2A7B0"/>
438        <g fill="#F5EDE6">
439          <rect x="-1" y="8" width="4" height="0.35"/><rect x="-1" y="11.3" width="4" height="0.35"/>
440          <rect x="12" y="8" width="4" height="0.35"/><rect x="12" y="11.3" width="4" height="0.35"/>
441        </g>
442      </g>
443          <rect class="arm-left"  id="left-arm"  x="0"  y="9" width="2" height="2"/>
444          <rect class="arm-right" id="right-arm" x="13" y="9" width="2" height="2"/>
445        </g>
446
447        <g class="eyes" id="eyes-color-group">
448          <g class="eyes-rect" fill="#000000">
449            <rect id="left-eye"  x="4"  y="8" width="1" height="2"/>
450            <rect id="right-eye" x="10" y="8" width="1" height="2"/>
451          </g>
452          <g class="eyes-smile" fill="none" stroke="#000000" stroke-width="0.7" stroke-linecap="round" stroke-linejoin="round">
453            <polyline points="3.5,9 4.5,8 5.5,9"/>
454            <polyline points="9.5,9 10.5,8 11.5,9"/>
455          </g>
456        </g>
457      </g>
458    </g>
459
460    <!--
461      Left thought bubble.
462      v23: bubble path lifted by 1px (path y -3..4 -> -4..3) so
463      there is a 3px gap to clawd's head. Old chat-tail
464      (0,4)(1,4)(1,5) deleted. New chain: 1x1 puff at (1,4) +
465      0.5x0.5 puff at (2,5.5) trailing toward clawd's head top
466      (y=6).
467    -->
468    <g class="left-bubble">
469      <path d="M-1 -4 H6 V-3 H7 V2 H6 V3 H-1 V2 H-2 V-3 H-1 Z" fill="#FFFFFF"/>
470      <!-- v25 rim-flow pixels: clockwise top -> right -> bottom -> left -->
471      <rect class="bubble-flow flow1" x="3"  y="-5" width="1" height="1" fill="#BFEAFF"/>
472      <rect class="bubble-flow flow2" x="8"  y="0"  width="1" height="1" fill="#BFEAFF"/>
473      <rect class="bubble-flow flow3" x="4"  y="4"  width="1" height="1" fill="#BFEAFF"/>
474      <rect class="bubble-flow flow4" x="-3" y="0"  width="1" height="1" fill="#BFEAFF"/>
475      <rect x="1"   y="4"   width="1"   height="1"   fill="#FFFFFF"/>
476      <rect x="2"   y="5.5" width="0.5" height="0.5" fill="#FFFFFF"/>
477      <rect class="dot dot1" x="0" y="-1" width="1" height="1" fill="#256891"/>
478      <rect class="dot dot2" x="2" y="-1" width="1" height="1" fill="#256891"/>
479      <rect class="dot dot3" x="4" y="-1" width="1" height="1" fill="#256891"/>
480    </g>
481
482    <g class="right-bubble">
483      <path d="M9 -4 H16 V-3 H17 V2 H16 V3 H9 V2 H8 V-3 H9 Z" fill="#FFFFFF"/>
484      <!-- v25 rim-flow pixels: clockwise top -> right -> bottom -> left -->
485      <rect class="bubble-flow flow1" x="12" y="-5" width="1" height="1" fill="#BFEAFF"/>
486      <rect class="bubble-flow flow2" x="18" y="0"  width="1" height="1" fill="#BFEAFF"/>
487      <rect class="bubble-flow flow3" x="15" y="4"  width="1" height="1" fill="#BFEAFF"/>
488      <rect class="bubble-flow flow4" x="7"  y="0"  width="1" height="1" fill="#BFEAFF"/>
489      <rect x="13"   y="4"   width="1"   height="1"   fill="#FFFFFF"/>
490      <rect x="12.5" y="5.5" width="0.5" height="0.5" fill="#FFFFFF"/>
491      <rect class="dot dot1" x="10" y="-1" width="1" height="1" fill="#256891"/>
492      <rect class="dot dot2" x="12" y="-1" width="1" height="1" fill="#256891"/>
493      <rect class="dot dot3" x="14" y="-1" width="1" height="1" fill="#256891"/>
494    </g>
495
496    <!--
497      v23 inspiration sparkles. Pixel + (5 small rects) above
498      each bubble, bling at the "got it" moment.
499      Color #FFE066 (per technique 12 anti-boss-gold rule).
500    -->
501    <g class="left-spark">
502      <rect x="6"   y="-7"   width="1"   height="0.6" fill="#FFE066"/>
503      <rect x="6"   y="-6.4" width="1"   height="1"   fill="#FFE066"/>
504      <rect x="6"   y="-5.4" width="1"   height="0.6" fill="#FFE066"/>
505      <rect x="5"   y="-6.4" width="1"   height="1"   fill="#FFE066"/>
506      <rect x="7"   y="-6.4" width="1"   height="1"   fill="#FFE066"/>
507    </g>
508    <g class="right-spark">
509      <rect x="8"   y="-7"   width="1"   height="0.6" fill="#FFE066"/>
510      <rect x="8"   y="-6.4" width="1"   height="1"   fill="#FFE066"/>
511      <rect x="8"   y="-5.4" width="1"   height="0.6" fill="#FFE066"/>
512      <rect x="7"   y="-6.4" width="1"   height="1"   fill="#FFE066"/>
513      <rect x="9"   y="-6.4" width="1"   height="1"   fill="#FFE066"/>
514    </g>
515  </g>
516</svg>