@wenathlan/cobaia 0.0.0-stage → 2.0.155

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/App.tsx +52 -0
  2. package/Dockerfile +45 -0
  3. package/Sol/Sol.tsx +91 -0
  4. package/Sol/apps/apps.tsx +66 -0
  5. package/Sol/blog/blog.tsx +86 -0
  6. package/Sol/home/home.tsx +140 -0
  7. package/Sol/intro/intro.tsx +187 -0
  8. package/Sol/legal/legal.tsx +76 -0
  9. package/Sol/notfound/notfound.tsx +32 -0
  10. package/Sol/pricing/pricing.tsx +98 -0
  11. package/Sol/shell/Shell.tsx +161 -0
  12. package/Sol/sol.css +1944 -0
  13. package/Sol/support/support.tsx +102 -0
  14. package/Sol/wingets/IntroFooter.tsx +69 -0
  15. package/Sol/wingets/IntroPlans.tsx +93 -0
  16. package/Sol/wingets/IntroSplash.tsx +105 -0
  17. package/Sol/wingets/ShellAdsslot.tsx +47 -0
  18. package/Sol/wingets/ShellBrand.tsx +86 -0
  19. package/Sol/wingets/index.ts +18 -0
  20. package/_headers +4 -0
  21. package/_redirects +1 -0
  22. package/adsconfig.ts +59 -0
  23. package/biome.jsonc +134 -0
  24. package/bun.lock +2331 -0
  25. package/capacitor.config.ts +51 -0
  26. package/checkoutlinks.ts +80 -0
  27. package/content.ts +425 -0
  28. package/db.ts +219 -0
  29. package/devthink.toml +5 -0
  30. package/docs/.gitkeep +0 -0
  31. package/familyurl.ts +22 -0
  32. package/favicon.svg +1 -0
  33. package/icon.svg +1 -0
  34. package/index.html +26 -0
  35. package/labels.ts +291 -0
  36. package/manifest.webmanifest +56 -0
  37. package/mime.types +12 -0
  38. package/netlify.toml +2 -0
  39. package/package.json +200 -4
  40. package/pnpm-workspace.yaml +82 -0
  41. package/posts.ts +54 -0
  42. package/robots.txt +90 -0
  43. package/roster.ts +29 -0
  44. package/sandboxmodality.ts +138 -0
  45. package/schema.prisma +31 -0
  46. package/sitemap.xml +42 -0
  47. package/tests/adsconfig.test.ts +51 -0
  48. package/tests/checkoutlinks.test.ts +73 -0
  49. package/tests/familyurl.test.ts +40 -0
  50. package/tests/posts.test.ts +76 -0
  51. package/tests/sandboxmodality.test.ts +77 -0
  52. package/tsconfig.json +22 -0
  53. package/tsconfig.node.json +22 -0
  54. package/vercel.json +3 -0
  55. package/vite.config.ts +44 -0
  56. package/vitest.config.ts +42 -0
  57. package/wrangler.toml +7 -0
  58. package/README.md +0 -3
package/Sol/sol.css ADDED
@@ -0,0 +1,1944 @@
1
+ @import "tailwindcss";
2
+
3
+ /* ==========================================================================
4
+ COBAIA THEME SOL — the single stylesheet of the cobaia content site (the
5
+ monetization canvas), wearing the TRYLLE RULER with the WINDOWS hands on
6
+ the controls: the press bounce (scale .7, 100ms), the dtPopIntro mount
7
+ pop on the nav pins, the 3px ladder indicator, the focus underline on the
8
+ Windows accent, the Win11 scrollbar, the skeleton shimmer by opacity.
9
+ cobaia is a CONTENT site: no onboarding, no entry gate — the home renders
10
+ directly and every page is public; the intro (/intro) is the one bare
11
+ presentation page outside the window chrome (the family law: every app
12
+ carries one). Sections: foundation · tokens · light face · base · chrome ·
13
+ page · components · ad slot · 404 · brand mark · responsive · keyframes ·
14
+ intro · guards (reduced-motion hard-stop last).
15
+ doctrine: the trylle canvas #0a0a0b flat (deep #060607) · the 8-step
16
+ trylle surface ladder #171717→#484848 · ink #fafafa · hairlines ink
17
+ 5%/10% · the ONE Sol accent is the WHITE SUN (pure #ffffff on the dark
18
+ ladder — the name is Sol but the sun is white, never the amber it once
19
+ was; the light face carries the graphite contrast pole of the same
20
+ semantic token) · focus, CTA and every interactive accent answer it ·
21
+ body 13px weight 450 · Inter Variable everywhere, Geist Mono
22
+ on labels and numbers · H1 clamp(2.25rem,5vw,3.75rem) tracking -0.02em ·
23
+ radii .625rem law (inner controls 4) · micro 150ms cubic-bezier(0.22,1,
24
+ 0.36,1) · popintro 800ms · press scale(.7) on the icon button · linear
25
+ shadows (1px ring + doubling layers) · card hover = one rung up + one
26
+ shadow rung up · grid entrances stagger 60ms · targets ≥44px · grain
27
+ feTurbulence .86 / 2 octaves / 6% / soft-light / 140px · no pills · no
28
+ all-properties transitions · no glow · no scale-from-zero except the
29
+ windows pin law · scrollbar invisible until hover · selection
30
+ rgb(76 194 255/38%) · reduced-motion hard stop last. The @theme block
31
+ mirrors the canonical :root tokens for the Tailwind utility layer.
32
+ ========================================================================== */
33
+
34
+ /* the light-theme variant: the theme flips on the html[data-theme] class,
35
+ not on the OS preference — components use light: utilities */
36
+ @custom-variant light (&:where([data-theme="light"], [data-theme="light"] *));
37
+
38
+ /* ==========================================================================
39
+ 0. TOKEN FOUNDATION — the one source of truth (the trylle @theme)
40
+ ========================================================================== */
41
+ @theme {
42
+ /* ---- type: the trylle ruler ---- */
43
+ --font-display: "Inter Variable", "Inter", ui-sans-serif, system-ui, sans-serif;
44
+ --font-sans:
45
+ "Inter Variable", "Inter", "Segoe UI Variable Text", "Segoe UI", "Selawik", ui-sans-serif, system-ui, sans-serif;
46
+ --font-mono: "Geist Mono Variable", "Geist Mono", "Fira Code", ui-monospace, SFMono-Regular, Menlo, monospace;
47
+
48
+ /* ---- the trylle canvas and the 8-step surface ladder ---- */
49
+ --color-canvas: #0a0a0b;
50
+ --color-deep: #060607;
51
+ --color-s0: #171717;
52
+ --color-s1: #1e1e1e;
53
+ --color-s2: #252525;
54
+ --color-s3: #2c2c2c;
55
+ --color-s4: #333333;
56
+ --color-s5: #3a3a3a;
57
+ --color-s6: #414141;
58
+ --color-s7: #484848;
59
+
60
+ /* ---- the ink ladder and the hairlines ---- */
61
+ --color-ink: #fafafa;
62
+ --color-ink-2: #c3c3c3;
63
+ --color-ink-3: #999999;
64
+ --color-hairline: color-mix(in oklab, #fafafa 5%, transparent);
65
+ --color-hairline-strong: color-mix(in oklab, #fafafa 10%, transparent);
66
+
67
+ /* ---- the signal: THE WHITE SUN — one Sol, one light; the name is Sol
68
+ but the sun is WHITE, never the yellow of the retired identities ---- */
69
+ --color-signal: #ffffff;
70
+ --color-signal-strong: #ffffff;
71
+ --color-signal-2: #c9cdd6;
72
+ --color-signal-3: #8b909b;
73
+ --color-signal-ink: #14161a;
74
+
75
+ /* ---- the WINDOWS accent: focus, CTA and the interactive voices ---- */
76
+ --color-win: #4cc2ff;
77
+ --color-win-ink: #0a0a0a;
78
+
79
+ /* ---- focus rides the WINDOWS accent (the family law) ---- */
80
+ --color-focus: var(--color-win);
81
+
82
+ /* ---- radius law: 4/6/8/10(base)/12/16/24 — inner ≤ outer ---- */
83
+ --radius-xs: 4px;
84
+ --radius-sm: 6px;
85
+ --radius-md: 8px;
86
+ --radius-lg: 10px;
87
+ --radius-xl: 12px;
88
+ --radius-2xl: 16px;
89
+ --radius-3xl: 24px;
90
+
91
+ /* ---- motion curves: the micro ruler and the windows press exit ---- */
92
+ --ease-micro: cubic-bezier(0.22, 1, 0.36, 1);
93
+ --ease-exit: cubic-bezier(0.7, 0, 1, 0.5);
94
+
95
+ /* ---- animation tokens mapped to the keyframes this file owns ---- */
96
+ --animate-popintro: dtPopIntro 800ms ease-in-out backwards;
97
+ --animate-skel: cbSkel 1.8s ease-in-out infinite;
98
+ }
99
+
100
+ /* ---------- 1. TOKENS — the trylle ruler with the windows hands ------ */
101
+ :root {
102
+ /* the doctrine tokens as plain literals — the zero-build static face
103
+ renders these without the tailwind plugin; the @theme above mirrors
104
+ them for the utility layer */
105
+ --color-canvas: #0a0a0b;
106
+ --color-deep: #060607;
107
+ --color-s0: #171717;
108
+ --color-s1: #1e1e1e;
109
+ --color-s2: #252525;
110
+ --color-s3: #2c2c2c;
111
+ --color-s4: #333333;
112
+ --color-s5: #3a3a3a;
113
+ --color-s6: #414141;
114
+ --color-s7: #484848;
115
+ --color-ink: #fafafa;
116
+ --color-ink-2: #c3c3c3;
117
+ --color-ink-3: #999999;
118
+ --color-hairline: color-mix(in oklab, #fafafa 5%, transparent);
119
+ --color-hairline-strong: color-mix(in oklab, #fafafa 10%, transparent);
120
+ --color-signal: #ffffff;
121
+ --color-signal-strong: #ffffff;
122
+ --color-signal-2: #c9cdd6;
123
+ --color-signal-3: #8b909b;
124
+ --color-signal-ink: #14161a;
125
+ --color-win: #4cc2ff;
126
+ --color-win-ink: #0a0a0a;
127
+ --color-focus: var(--color-win);
128
+
129
+ /* the canvas + the 8 surface rungs (elevation by color, never by border) */
130
+ --sol-canvas: var(--color-canvas);
131
+ --sol-canvas-deep: var(--color-deep);
132
+ --sol-surface-1: var(--color-s0);
133
+ --sol-surface-2: var(--color-s1);
134
+ --sol-surface-3: var(--color-s2);
135
+ --sol-surface-4: var(--color-s3);
136
+ --sol-surface-5: var(--color-s4);
137
+ --sol-surface-6: var(--color-s5);
138
+ --sol-surface-7: var(--color-s6);
139
+ --sol-surface-8: var(--color-s7); /* the hover pole */
140
+
141
+ /* ink — primary / muted / faint */
142
+ --sol-ink: var(--color-ink);
143
+ --sol-muted: var(--color-ink-2);
144
+ --sol-faint: var(--color-ink-3);
145
+
146
+ /* hairlines (5% / 10% ink, re-mixed on the light face) */
147
+ --sol-hairline: var(--color-hairline);
148
+ --sol-hairline-strong: var(--color-hairline-strong);
149
+
150
+ /* the linear shadows: the 1px ring first, then the doubling layers —
151
+ one rung deeper per elevation, level 3+ gains the inset highlight */
152
+ --sol-shadow-1: 0 0 0 1px var(--sol-hairline), 0 1px 1px -0.5px rgb(0 0 0 / 30%);
153
+ --sol-shadow-2: 0 0 0 1px var(--sol-hairline), 0 1px 1px -0.5px rgb(0 0 0 / 28%), 0 2px 4px -1px rgb(0 0 0 / 26%);
154
+ --sol-shadow-3:
155
+ 0 0 0 1px var(--sol-hairline), 0 1px 1px -0.5px rgb(0 0 0 / 26%),
156
+ 0 2px 4px -1px rgb(0 0 0 / 24%), 0 4px 8px -2px rgb(0 0 0 / 20%),
157
+ inset 0 1px 0 rgb(255 255 255 / 5%);
158
+ --sol-shadow-4: var(--sol-shadow-3), 0 8px 16px -4px rgb(0 0 0 / 18%);
159
+ --sol-shadow-5: var(--sol-shadow-4), 0 16px 32px -8px rgb(0 0 0 / 16%);
160
+ --sol-shadow-6: var(--sol-shadow-5), 0 32px 64px -16px rgb(0 0 0 / 14%);
161
+ --sol-shadow-7: var(--sol-shadow-6);
162
+
163
+ /* typography — the trylle triad: Inter Variable rides every surface,
164
+ Geist Mono Variable rides micro-labels and every number */
165
+ --sol-sans:
166
+ "Inter Variable", "Inter", "Segoe UI Variable Text", "Segoe UI", "Selawik", ui-sans-serif, system-ui, sans-serif;
167
+ --sol-mono: "Geist Mono Variable", "Geist Mono", "Fira Code", ui-monospace, SFMono-Regular, Menlo, monospace;
168
+ --sol-track-display: -0.02em;
169
+ --sol-track-label: 0.14em;
170
+ --sol-text-h1: clamp(2.25rem, 5vw, 3.75rem);
171
+ --sol-text-h2: clamp(1.65rem, 3vw, 2rem);
172
+ --sol-text-h3: clamp(1.3rem, 2vw, 1.5rem);
173
+
174
+ /* radius — the trylle law (base .625rem = --radius-lg) beside the
175
+ windows control blend: the inner controls wear 4 (the 10), inner ≤ outer */
176
+ --radius-xs: 4px;
177
+ --radius-sm: 6px;
178
+ --radius-md: 8px;
179
+ --radius-lg: 10px;
180
+ --radius-xl: 12px;
181
+ --radius-2xl: 16px;
182
+ --radius-3xl: 24px;
183
+ --sol-radius: var(--radius-lg);
184
+ --sol-radius-sm: var(--radius-md);
185
+ --sol-radius-lg: var(--radius-xl);
186
+ --sol-radius-xl: var(--radius-2xl);
187
+ --sol-radius-2xl: 16px;
188
+ --sol-radius-3xl: 24px;
189
+ --win-radius-ctl: var(--radius-xs);
190
+
191
+ /* motion — micro 150ms on the trylle out curve · press 100ms on the
192
+ windows exit curve (the hands stay; the windows/panels duration goes:
193
+ a content site opens no windows) */
194
+ --sol-micro: 150ms;
195
+ --ease-micro: cubic-bezier(0.22, 1, 0.36, 1);
196
+ --sol-ease-out: var(--ease-micro);
197
+ --win-ease-exit: cubic-bezier(0.7, 0, 1, 0.5);
198
+ --ease-silk: cubic-bezier(0.2, 0.8, 0.2, 1);
199
+ /* the win shell doctrine tokens (the token union law — the master's
200
+ numbers): taskbar 48px over the saturate(3) blur(20px) acrylic bed,
201
+ tint rgb(32 32 32 / 75%) dark / rgb(243 243 243 / 85%) light; the side
202
+ panel curve cubic-bezier(0.62,0,0.32,1), the start curve
203
+ cubic-bezier(0.79,0.14,0.15,0.86), the window curve
204
+ cubic-bezier(0.85,0.14,0.14,0.85) carried as the literal (the union
205
+ name the family speaks); the close red rgb(232 17 35) as the literal
206
+ (the site carries no --color-close seat of its own) */
207
+ --win-taskbar-h: 48px;
208
+ --win-taskbar-tint: rgb(32 32 32 / 75%);
209
+ --win-taskbar-filter: saturate(3) blur(20px);
210
+ --win-ease-panel: cubic-bezier(0.62, 0, 0.32, 1);
211
+ --win-ease-start: cubic-bezier(0.79, 0.14, 0.15, 0.86);
212
+ --win-ease-window: cubic-bezier(0.85, 0.14, 0.14, 0.85);
213
+ --win-close: rgb(232 17 35);
214
+
215
+ /* the interactive accent: the WHITE SUN (the one Sol) governs the focus,
216
+ the CTA and every interactive voice of the site; the windows accent
217
+ stays the system voice of the chrome hands */
218
+ --sol-accent: var(--color-signal);
219
+ --sol-accent-deep: var(--color-signal-2);
220
+ --sol-accent-ink: var(--color-signal-ink);
221
+ --win-accent: var(--color-win);
222
+ --win-accent-ink: var(--color-win-ink);
223
+ --sol-focus: var(--color-win);
224
+
225
+ /* washes, the bar acrylic and the scrollbar thumb (never the native blue) */
226
+ --wash: rgb(255 255 255 / 10%);
227
+ --wash-soft: rgb(255 255 255 / 5%);
228
+ --bar-acrylic: rgb(10 10 11 / 75%);
229
+ --bar-hairline: rgb(0 0 0 / 55%);
230
+ --scroll: rgb(255 255 255 / 45%);
231
+ --scroll-hover: rgb(255 255 255 / 55%);
232
+
233
+ /* the windows grain: one data-uri turbulence, tile 140×140, drawn at
234
+ 6% over the bar acrylic (soft-light) — zero image files; beside it
235
+ the doctrine mica wall (the token union law: the master's radial bed
236
+ carries the site canvas now) */
237
+ --win-noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.86' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.06'/%3E%3C/svg%3E");
238
+ --mica: #202020 radial-gradient(#1a1f35 25%, #202020 100%) no-repeat fixed;
239
+
240
+ /* the content measure, the z bands and the shell geometry */
241
+ --cb-maxw: 1060px;
242
+
243
+ /* z bands: atmosphere 0 · content 10 · float 20 · bar 50 · menu 60 ·
244
+ overlay 100 · dock 150 · modal 200 · toast 300 · tooltip 400 */
245
+ --z-atmosphere: 0;
246
+ --z-content: 10;
247
+ --z-float: 20;
248
+ --z-bar: 50;
249
+ --z-menu: 60;
250
+ --z-overlay: 100;
251
+ --z-dock: 150;
252
+ --z-modal: 200;
253
+ --z-toast: 300;
254
+ --z-tooltip: 400;
255
+
256
+ /* shell geometry: the positioning variables the resize and the re dock
257
+ write, so the browser relayouts without a re render of the interface */
258
+ --shell-sidebar: 264px;
259
+ --shell-sidebar-min: 208px;
260
+ --shell-topbar: 52px;
261
+ --shell-gutter: 12px;
262
+ --shell-handle: 4px;
263
+ --shell-radius: 8px;
264
+
265
+ /* status tones: the outcome voices of the eight state family (the ok and
266
+ err fills of the success and danger buttons, the semantic accents) */
267
+ --color-ok: #7fd1a8;
268
+ --color-warn: #e2c26a;
269
+ --color-err: #f08a7a;
270
+ --ok: var(--color-ok);
271
+ --warn: var(--color-warn);
272
+ --err: var(--color-err);
273
+
274
+ color-scheme: dark;
275
+ font-size: 16px;
276
+ }
277
+
278
+ /* the light face: the trylle daylight ladder — the tokens are ready for
279
+ the toggle even though cobaia ships dark-first today */
280
+ [data-theme="light"] {
281
+ --color-canvas: #f4f4f5;
282
+ --color-deep: #ececed;
283
+ --color-s0: #f4f4f5;
284
+ --color-s1: #fafafa;
285
+ --color-s2: #fcfcfc;
286
+ --color-s3: #fefefe;
287
+ --color-s4: #ffffff;
288
+ --color-s5: #f1f1f2;
289
+ --color-s6: #e5e5e7;
290
+ --color-s7: #d6d6d9;
291
+ --color-ink: #1a1a1a;
292
+ --color-ink-2: #3c3c3c;
293
+ --color-ink-3: #555555;
294
+ --color-hairline: color-mix(in oklab, #1a1a1a 8%, transparent);
295
+ --color-hairline-strong: color-mix(in oklab, #1a1a1a 16%, transparent);
296
+ --color-signal: #3f434b;
297
+ --color-signal-strong: #18181b;
298
+ --color-signal-2: #52565e;
299
+ --color-signal-3: #8b909b;
300
+ --color-signal-ink: #fefefe;
301
+ --color-win: #0067c0;
302
+ --color-win-ink: #fefefe;
303
+ --sol-accent: var(--color-signal);
304
+ --sol-accent-deep: var(--color-signal-2);
305
+ --sol-accent-ink: var(--color-signal-ink);
306
+ --wash: rgb(0 0 0 / 8%);
307
+ --wash-soft: rgb(0 0 0 / 4%);
308
+ --bar-acrylic: rgb(244 244 245 / 85%);
309
+ --bar-hairline: rgb(0 0 0 / 10%);
310
+ --scroll: rgb(0 0 0 / 35%);
311
+ --scroll-hover: rgb(0 0 0 / 45%);
312
+ --color-ok: #1e7f4f;
313
+ --color-warn: #9a6b00;
314
+ --color-err: #c23b2c;
315
+ --mica: #f3f3f3 radial-gradient(#eff4f9 75%, #f3f3f3 100%) no-repeat fixed;
316
+ /* the taskbar tint flips with the face (the token union law: the master's
317
+ light bed) */
318
+ --win-taskbar-tint: rgb(243 243 243 / 85%);
319
+ color-scheme: light;
320
+ }
321
+
322
+ /* ---------- 1b. SHORT NAMES — the aliases the family law sections compose
323
+ (they track the :root tokens above, so the light flip follows) ---------- */
324
+ :root {
325
+ --ink: var(--color-ink);
326
+ --s1: var(--color-s1);
327
+ }
328
+
329
+ /* ---------- 2. BASE — the trylle body on the windows controls ---------- */
330
+ * {
331
+ box-sizing: border-box;
332
+ }
333
+ html {
334
+ scroll-behavior: smooth;
335
+ }
336
+ body {
337
+ margin: 0;
338
+ min-height: 100vh;
339
+ background: var(--mica);
340
+ color: var(--sol-ink);
341
+ font-family: var(--sol-sans);
342
+ font-size: 13px;
343
+ font-weight: 450;
344
+ line-height: 1.55;
345
+ -webkit-font-smoothing: antialiased;
346
+ }
347
+ main {
348
+ display: block;
349
+ }
350
+ a {
351
+ color: inherit;
352
+ text-decoration: none;
353
+ }
354
+ a:hover {
355
+ color: var(--sol-ink);
356
+ }
357
+ h1,
358
+ h2,
359
+ h3 {
360
+ margin: 0 0 0.5em;
361
+ font-weight: 600;
362
+ letter-spacing: var(--sol-track-display);
363
+ line-height: 1.1;
364
+ color: var(--sol-ink);
365
+ }
366
+ h1 {
367
+ font-size: var(--sol-text-h1);
368
+ }
369
+ h2 {
370
+ font-size: var(--sol-text-h2);
371
+ }
372
+ h3 {
373
+ font-size: var(--sol-text-h3);
374
+ }
375
+ p {
376
+ margin: 0 0 1em;
377
+ color: var(--sol-muted);
378
+ }
379
+ strong {
380
+ color: var(--sol-ink);
381
+ }
382
+ ::selection {
383
+ background: color-mix(in srgb, var(--win-accent) 38%, transparent);
384
+ color: var(--sol-ink);
385
+ }
386
+ :focus-visible {
387
+ outline: 2px solid var(--sol-focus);
388
+ outline-offset: 2px;
389
+ border-radius: var(--win-radius-ctl);
390
+ }
391
+ kbd,
392
+ code {
393
+ font-family: var(--sol-mono);
394
+ font-size: 0.85em;
395
+ background: var(--sol-surface-2);
396
+ border: 1px solid var(--sol-hairline);
397
+ border-radius: 6px;
398
+ padding: 1px 6px;
399
+ font-variant-numeric: tabular-nums;
400
+ }
401
+ [hidden] {
402
+ display: none !important;
403
+ }
404
+
405
+ /* the win11 scrollbar: invisible until the surface is hovered — lane 10px,
406
+ thumb 4px, 6px under the pointer (the border trims the paint) */
407
+ * {
408
+ scrollbar-width: thin;
409
+ scrollbar-color: transparent transparent;
410
+ }
411
+ *:hover,
412
+ *:focus-within {
413
+ scrollbar-color: var(--scroll) transparent;
414
+ }
415
+ ::-webkit-scrollbar {
416
+ width: 10px;
417
+ height: 10px;
418
+ }
419
+ ::-webkit-scrollbar-track {
420
+ background: transparent;
421
+ }
422
+ ::-webkit-scrollbar-thumb {
423
+ border: 3px solid transparent;
424
+ border-radius: 6px;
425
+ background: transparent;
426
+ background-clip: padding-box;
427
+ }
428
+ *:hover::-webkit-scrollbar-thumb,
429
+ *:focus-within::-webkit-scrollbar-thumb {
430
+ background-color: var(--scroll);
431
+ }
432
+ ::-webkit-scrollbar-thumb:hover {
433
+ background-color: var(--scroll-hover);
434
+ border-width: 2px;
435
+ }
436
+
437
+ /* ---------- 3. CHROME — the acrylic bar, the nav pins, the footer ---------- */
438
+ .cb-root {
439
+ display: flex;
440
+ flex-direction: column;
441
+ min-height: 100%;
442
+ }
443
+
444
+ /* the skip link: hidden until keyboard focus; chrome answers the windows accent */
445
+ .cb-skip {
446
+ position: absolute;
447
+ top: -48px;
448
+ left: 16px;
449
+ z-index: var(--z-bar);
450
+ display: inline-flex;
451
+ align-items: center;
452
+ min-height: 44px;
453
+ padding: 10px 14px;
454
+ border-radius: var(--win-radius-ctl);
455
+ background: var(--win-accent);
456
+ color: var(--win-accent-ink);
457
+ font: 600 13px / 1 var(--sol-sans);
458
+ transition: top var(--sol-micro) var(--sol-ease-out);
459
+ }
460
+ .cb-skip:focus-visible {
461
+ top: 12px;
462
+ }
463
+
464
+ /* the top bar: the taskbar acrylic — saturate(3) blur(20px), one black
465
+ hairline under, flat (zero gradient, zero diffuse shadow) */
466
+ .cb-top {
467
+ position: sticky;
468
+ top: 0;
469
+ z-index: var(--z-bar);
470
+ display: flex;
471
+ align-items: center;
472
+ justify-content: space-between;
473
+ gap: 16px;
474
+ max-width: var(--cb-maxw);
475
+ margin: 0 auto;
476
+ padding: 6px clamp(16px, 4vw, 32px);
477
+ width: 100%;
478
+ border-bottom: 1px solid var(--bar-hairline);
479
+ background-color: var(--bar-acrylic);
480
+ background-image: var(--win-noise);
481
+ background-blend-mode: soft-light;
482
+ -webkit-backdrop-filter: saturate(3) blur(20px);
483
+ backdrop-filter: saturate(3) blur(20px);
484
+ }
485
+
486
+ /* the brand: the mark rides the pin grammar — a 44px wash box (the touch
487
+ floor), r4, the press bounce lands on the mark itself */
488
+ .cb-brand {
489
+ display: inline-flex;
490
+ align-items: center;
491
+ gap: 10px;
492
+ min-height: 44px;
493
+ margin: 0 3px;
494
+ padding: 4px 10px 4px 4px;
495
+ border-radius: var(--win-radius-ctl);
496
+ font-size: 0.95rem;
497
+ letter-spacing: var(--sol-track-display);
498
+ transition:
499
+ background-color 200ms ease,
500
+ color var(--sol-micro) var(--sol-ease-out);
501
+ }
502
+ .cb-brand:hover {
503
+ background: var(--wash);
504
+ color: var(--sol-ink);
505
+ }
506
+ .cb-brand strong {
507
+ color: var(--sol-ink);
508
+ font-weight: 600;
509
+ }
510
+ .cb-brand:active .cbMarkSvg {
511
+ transform: scale(0.7);
512
+ transition-duration: 100ms;
513
+ transition-timing-function: ease-in-out;
514
+ }
515
+ .cb-brandtag {
516
+ color: var(--sol-faint);
517
+ font: 500 10.5px / 1.4 var(--sol-mono);
518
+ letter-spacing: var(--sol-track-label);
519
+ text-transform: uppercase;
520
+ }
521
+
522
+ /* the section links: the windows pins of the bar — r4 wash boxes with the
523
+ press bounce, the mount pop and the 3px ladder indicator underneath
524
+ (0 closed → 6px gray open → 12px windows-accent active); the touch
525
+ floor rules the pin height */
526
+ .cb-nav {
527
+ display: flex;
528
+ gap: clamp(6px, 2vw, 16px);
529
+ }
530
+ .cb-navlink {
531
+ position: relative;
532
+ display: inline-flex;
533
+ align-items: center;
534
+ min-height: 44px;
535
+ margin: 0 3px;
536
+ padding: 6px 10px;
537
+ border-radius: var(--win-radius-ctl);
538
+ color: var(--sol-muted);
539
+ font: 600 13.5px / 1.4 var(--sol-sans);
540
+ letter-spacing: 0.01em;
541
+ transition:
542
+ background-color 200ms ease,
543
+ color var(--sol-micro) var(--sol-ease-out),
544
+ transform 100ms ease-in-out;
545
+ }
546
+ .cb-navlink:hover {
547
+ background: var(--wash);
548
+ color: var(--sol-ink);
549
+ text-decoration: none;
550
+ }
551
+ .cb-navlink:active {
552
+ transform: scale(0.7);
553
+ }
554
+ .cb-navlink:focus-visible {
555
+ outline: none;
556
+ box-shadow: inset 0 -2px 0 var(--sol-focus);
557
+ }
558
+ .cb-navlink::after {
559
+ content: "";
560
+ position: absolute;
561
+ left: 50%;
562
+ bottom: 2px;
563
+ width: 12px;
564
+ height: 3px;
565
+ border-radius: var(--win-radius-ctl);
566
+ background: var(--sol-accent);
567
+ transform: translateX(-50%) scaleX(0);
568
+ transition:
569
+ transform 0.2s ease-in-out,
570
+ background-color 0.2s ease-in-out;
571
+ }
572
+ .cb-navlink:hover::after {
573
+ background: #858585;
574
+ transform: translateX(-50%) scaleX(0.5);
575
+ }
576
+ .cb-navlink[aria-current="page"] {
577
+ color: var(--sol-ink);
578
+ }
579
+ .cb-navlink[aria-current="page"]::after {
580
+ background: var(--sol-accent);
581
+ transform: translateX(-50%) scaleX(1);
582
+ }
583
+
584
+ .cb-main {
585
+ flex: 1;
586
+ width: 100%;
587
+ max-width: var(--cb-maxw);
588
+ margin: 0 auto;
589
+ padding: 0 clamp(16px, 4vw, 32px);
590
+ }
591
+
592
+ /* the footer: hairline top, three columns, the family row with the accents */
593
+ .cb-foot {
594
+ margin-top: clamp(48px, 8vw, 88px);
595
+ border-top: 1px solid var(--sol-hairline);
596
+ background: var(--sol-canvas-deep);
597
+ }
598
+ .cb-footgrid {
599
+ display: grid;
600
+ grid-template-columns: minmax(0, 1.4fr) minmax(0, 0.6fr) minmax(0, 1.2fr);
601
+ gap: clamp(24px, 4vw, 48px);
602
+ max-width: var(--cb-maxw);
603
+ margin: 0 auto;
604
+ padding: clamp(28px, 4vw, 44px) clamp(16px, 4vw, 32px) 20px;
605
+ }
606
+ .cb-footcol {
607
+ min-width: 0;
608
+ }
609
+ .cb-footabout .cb-foottext {
610
+ max-width: 42ch;
611
+ }
612
+ .cb-foothead {
613
+ margin: 0 0 12px;
614
+ color: var(--sol-faint);
615
+ font: 600 10.5px / 1.4 var(--sol-mono);
616
+ letter-spacing: var(--sol-track-label);
617
+ text-transform: uppercase;
618
+ }
619
+ .cb-foottext {
620
+ margin: 0;
621
+ max-width: 42ch;
622
+ color: var(--sol-muted);
623
+ font-size: 0.85rem;
624
+ }
625
+ .cb-footlink {
626
+ display: flex;
627
+ align-items: center;
628
+ min-height: 44px;
629
+ color: var(--sol-muted);
630
+ font: 500 13px / 1.5 var(--sol-sans);
631
+ transition: color var(--sol-micro) var(--sol-ease-out);
632
+ }
633
+ .cb-famgrid {
634
+ display: grid;
635
+ grid-template-columns: repeat(auto-fill, minmax(128px, 1fr));
636
+ gap: 6px 14px;
637
+ }
638
+ .cb-famlink {
639
+ display: inline-flex;
640
+ align-items: center;
641
+ gap: 8px;
642
+ min-height: 44px;
643
+ color: var(--sol-muted);
644
+ font: 500 12.5px / 1.5 var(--sol-mono);
645
+ transition: color var(--sol-micro) var(--sol-ease-out);
646
+ }
647
+ .cb-famlink:hover {
648
+ color: var(--sol-ink);
649
+ }
650
+ .cb-famdot {
651
+ flex: none;
652
+ width: 7px;
653
+ height: 7px;
654
+ border-radius: 2px;
655
+ background: var(--cb-dot, var(--sol-accent));
656
+ }
657
+ .cb-colophon {
658
+ max-width: var(--cb-maxw);
659
+ margin: 0 auto;
660
+ padding: 14px clamp(16px, 4vw, 32px) 22px;
661
+ border-top: 1px solid var(--sol-hairline);
662
+ color: var(--sol-faint);
663
+ font: 400 11px / 1.6 var(--sol-mono);
664
+ }
665
+
666
+ /* ---------- 3b. FULLSCREEN LAW — the family fullscreen contract (pull
667
+ ninety one and ninety eight): the direct url owns the whole viewport —
668
+ the window chrome exists only inside the os power clip and the os draws
669
+ that window itself, so the site renders full-bleed with its own voice
670
+ (the sticky section bar, the page surface, the worked footer); inside
671
+ the power clip the routed page rides the host window bare. The floating
672
+ frame, the title bar, the captions and the resize handles the old
673
+ window carried are retired by this law — the brand mark moved to the
674
+ section bar pin (cb-brand) and the close door lives on as the /intro
675
+ route (the relaunch metaphor). ---------- */
676
+ .shell--standalone {
677
+ display: flex;
678
+ flex-direction: column;
679
+ width: 100%;
680
+ min-height: 100dvh;
681
+ max-width: none;
682
+ margin: 0;
683
+ padding: 0;
684
+ background-color: var(--sol-canvas);
685
+ }
686
+
687
+ /* the embedded contract: inside the os power clip the app rides the SAME
688
+ site surface as the direct url (the window-era law: one design) — the
689
+ seat fills the window body (the iframe viewport is the 100dvh there)
690
+ with the sticky section bar, the page surface and the worked footer
691
+ intact; the window chrome belongs to the os frame drawn around it */
692
+ .shell--embedded {
693
+ display: flex;
694
+ flex-direction: column;
695
+ width: 100%;
696
+ min-height: 100dvh;
697
+ max-width: none;
698
+ margin: 0;
699
+ padding: 0;
700
+ background-color: var(--sol-canvas);
701
+ }
702
+
703
+ /* ---------- 4. PAGE SCAFFOLDING — hero, sections, entrance ---------- */
704
+ .cb-page {
705
+ padding-bottom: 8px;
706
+ }
707
+ .cb-hero {
708
+ padding: clamp(48px, 9vw, 110px) 0 clamp(20px, 4vw, 36px);
709
+ }
710
+ .cb-eyebrow {
711
+ margin: 0 0 16px;
712
+ color: var(--sol-faint);
713
+ font: 600 11px / 1.4 var(--sol-mono);
714
+ letter-spacing: var(--sol-track-label);
715
+ text-transform: uppercase;
716
+ }
717
+ .cb-title {
718
+ margin: 0 0 18px;
719
+ max-width: 22ch;
720
+ }
721
+ .cb-lede {
722
+ margin: 0;
723
+ max-width: 58ch;
724
+ font-size: 1.125rem;
725
+ color: var(--sol-muted);
726
+ }
727
+ .cb-section {
728
+ padding: clamp(28px, 5vw, 52px) 0 0;
729
+ }
730
+ .cb-secthead {
731
+ max-width: 620px;
732
+ margin-bottom: 24px;
733
+ }
734
+ .cb-secttitle {
735
+ margin: 0 0 8px;
736
+ font-size: var(--sol-text-h2);
737
+ }
738
+ .cb-sectlede {
739
+ margin: 0;
740
+ color: var(--sol-muted);
741
+ }
742
+ .cb-in {
743
+ animation: cbRise 640ms var(--sol-ease-out) backwards;
744
+ animation-delay: calc(var(--cb-d, 0) * 60ms);
745
+ }
746
+
747
+ /* ---------- 5. COMPONENTS ---------- */
748
+
749
+ /* buttons: the trylle tone stack over the windows 4px control — the inset
750
+ top highlight, the inset pool, the 1px ring and the two drop levels;
751
+ hover raises the alphas, the press dips on the exit curve, the focus
752
+ underline rides the windows accent, no lift on the wash */
753
+ .cb-btnrow {
754
+ display: flex;
755
+ flex-wrap: wrap;
756
+ gap: 12px;
757
+ margin-top: 26px;
758
+ }
759
+ .cb-btn {
760
+ display: inline-flex;
761
+ align-items: center;
762
+ justify-content: center;
763
+ gap: 8px;
764
+ min-height: 44px;
765
+ padding: 0 20px;
766
+ border: 0;
767
+ border-radius: var(--win-radius-ctl);
768
+ background: var(--sol-accent);
769
+ color: var(--sol-accent-ink);
770
+ font: 600 14px / 1 var(--sol-sans);
771
+ cursor: pointer;
772
+ /* the resting physics: the top highlight of the fluent key and the
773
+ small drop shadow, both suppressed while pressed */
774
+ box-shadow:
775
+ inset 0 1px 0 0 rgb(255 255 255 / 16%),
776
+ 0 1px 2px rgb(0 0 0 / 14%);
777
+ transition:
778
+ background-color var(--sol-micro) var(--sol-ease-out),
779
+ box-shadow var(--sol-micro) var(--sol-ease-out),
780
+ color var(--sol-micro) var(--sol-ease-out),
781
+ transform 100ms var(--win-ease-exit);
782
+ }
783
+ .cb-btn:hover {
784
+ background: color-mix(in oklab, var(--sol-accent) 90%, #ffffff);
785
+ box-shadow:
786
+ inset 0 1px 0 0 rgb(255 255 255 / 16%),
787
+ 0 1px 2px rgb(0 0 0 / 14%);
788
+ text-decoration: none;
789
+ }
790
+ .cb-btn:focus-visible {
791
+ outline: none;
792
+ box-shadow:
793
+ inset 0 1px 0 0 rgb(255 255 255 / 16%),
794
+ inset 0 -2px 0 var(--sol-focus),
795
+ 0 1px 2px rgb(0 0 0 / 14%);
796
+ }
797
+ .cb-btn:active {
798
+ transform: scale(0.97);
799
+ box-shadow: inset 0 1px 0 0 rgb(0 0 0 / 8%);
800
+ }
801
+ .cb-btn:disabled,
802
+ .cb-btn[aria-disabled="true"] {
803
+ opacity: 0.5;
804
+ cursor: not-allowed;
805
+ transform: none;
806
+ box-shadow: var(--sol-shadow-1);
807
+ }
808
+ /* the outcome voices of the eight state family: the same key, the ok and
809
+ err tones riding the declared variables */
810
+ .cb-btn.success {
811
+ background: var(--ok);
812
+ color: #0a0a0a;
813
+ }
814
+ .cb-btn.success:hover {
815
+ background: color-mix(in srgb, var(--ok) 90%, #fefefe);
816
+ }
817
+ .cb-btn.danger {
818
+ background: var(--err);
819
+ color: #0a0a0a;
820
+ }
821
+ .cb-btn.danger:hover {
822
+ background: color-mix(in srgb, var(--err) 90%, #fefefe);
823
+ }
824
+ /* the loading voice: aria-busy hides the label and spins the honest wheel
825
+ in place — the layout holds, the action never pretends to be done */
826
+ .cb-btn[aria-busy="true"] {
827
+ position: relative;
828
+ color: transparent;
829
+ pointer-events: none;
830
+ }
831
+ .cb-btn[aria-busy="true"]::after {
832
+ content: "";
833
+ position: absolute;
834
+ top: 50%;
835
+ left: 50%;
836
+ width: 15px;
837
+ height: 15px;
838
+ margin: -7.5px 0 0 -7.5px;
839
+ border-radius: 50%;
840
+ border: 2px solid color-mix(in srgb, var(--sol-accent) 35%, transparent);
841
+ border-top-color: var(--sol-accent);
842
+ animation: solSpin 700ms linear infinite;
843
+ }
844
+ .cb-btn--ghost {
845
+ background: var(--wash-soft);
846
+ color: var(--sol-ink);
847
+ box-shadow:
848
+ inset 0 1px 0 0 rgb(255 255 255 / 10%),
849
+ 0 0 0 1px var(--sol-hairline-strong),
850
+ 0 1px 2px rgb(0 0 0 / 14%);
851
+ }
852
+ .cb-btn--ghost:hover {
853
+ background: var(--wash);
854
+ border-color: transparent;
855
+ color: var(--sol-ink);
856
+ box-shadow:
857
+ inset 0 1px 0 0 rgb(255 255 255 / 14%),
858
+ 0 0 0 1px color-mix(in oklab, var(--sol-ink) 16%, transparent),
859
+ 0 1px 2px rgb(0 0 0 / 16%);
860
+ }
861
+ .cb-btn--ghost:focus-visible {
862
+ outline: none;
863
+ box-shadow:
864
+ inset 0 1px 0 0 rgb(255 255 255 / 10%),
865
+ inset 0 -2px 0 var(--sol-focus),
866
+ 0 0 0 1px var(--sol-hairline-strong),
867
+ 0 1px 2px rgb(0 0 0 / 14%);
868
+ }
869
+ .cb-btn--ghost:active {
870
+ transform: scale(0.97);
871
+ box-shadow:
872
+ inset 0 1px 0 0 rgb(0 0 0 / 8%),
873
+ 0 0 0 1px var(--sol-hairline-strong);
874
+ }
875
+
876
+ /* the text link voice — the focus underline answers the windows accent */
877
+ .cb-link {
878
+ color: var(--sol-ink);
879
+ font-weight: 600;
880
+ text-decoration: underline;
881
+ text-underline-offset: 3px;
882
+ text-decoration-color: var(--sol-hairline-strong);
883
+ transition:
884
+ color var(--sol-micro) var(--sol-ease-out),
885
+ text-decoration-color var(--sol-micro) var(--sol-ease-out);
886
+ }
887
+ .cb-link:hover {
888
+ color: var(--sol-accent);
889
+ text-decoration-color: color-mix(in oklab, var(--sol-accent) 55%, transparent);
890
+ }
891
+ .cb-link:focus-visible,
892
+ .cb-footlink:focus-visible,
893
+ .cb-famlink:focus-visible,
894
+ .cb-postlink:focus-visible {
895
+ outline: none;
896
+ color: var(--sol-ink);
897
+ text-decoration: underline;
898
+ text-decoration-color: var(--sol-focus);
899
+ text-decoration-thickness: 2px;
900
+ text-underline-offset: 3px;
901
+ }
902
+
903
+ /* the honest note: mono, quiet, a hairline left edge */
904
+ .cb-note {
905
+ margin: 10px 0 0;
906
+ padding: 8px 12px;
907
+ border-left: 2px solid var(--sol-hairline-strong);
908
+ color: var(--sol-faint);
909
+ font: 400 11.5px / 1.6 var(--sol-mono);
910
+ }
911
+ .cb-note.is-live {
912
+ border-left-color: color-mix(in oklab, var(--sol-accent) 55%, transparent);
913
+ color: var(--sol-muted);
914
+ }
915
+
916
+ /* the empty state: hairline + muted, honest — nothing fakes content; the
917
+ skeleton shimmer breathes on opacity only (never a transform) */
918
+ .cb-empty {
919
+ display: inline-flex;
920
+ align-items: center;
921
+ justify-content: center;
922
+ min-height: 44px;
923
+ padding: 10px 18px;
924
+ border: 1px solid var(--sol-hairline);
925
+ border-radius: var(--sol-radius-sm);
926
+ color: var(--sol-faint);
927
+ font: 400 11.5px / 1.5 var(--sol-mono);
928
+ letter-spacing: 0.04em;
929
+ }
930
+ .cb-skel {
931
+ animation: cbSkel 1.8s ease-in-out infinite;
932
+ }
933
+
934
+ /* cards: surface well, ring shadow, one hover raise — one rung up on the
935
+ surface ladder and one rung deeper on the shadow ladder */
936
+ .cb-grid {
937
+ display: grid;
938
+ gap: 16px;
939
+ }
940
+ .cb-grid--2 {
941
+ grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
942
+ }
943
+ .cb-grid--3 {
944
+ grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
945
+ }
946
+ .cb-card {
947
+ padding: 22px;
948
+ border-radius: var(--sol-radius-lg);
949
+ background: var(--sol-surface-1);
950
+ box-shadow: var(--sol-shadow-1);
951
+ transition:
952
+ background-color var(--sol-micro) var(--sol-ease-out),
953
+ box-shadow var(--sol-micro) var(--sol-ease-out),
954
+ transform var(--sol-micro) var(--sol-ease-out);
955
+ }
956
+ .cb-card:hover {
957
+ background: var(--sol-surface-2);
958
+ box-shadow: var(--sol-shadow-4);
959
+ transform: translateY(-2px);
960
+ }
961
+ .cb-cardtitle {
962
+ margin: 0 0 6px;
963
+ font-size: 1.05rem;
964
+ }
965
+ .cb-cardtext {
966
+ margin: 0;
967
+ font-size: 0.9rem;
968
+ color: var(--sol-muted);
969
+ }
970
+ .cb-cardmeta {
971
+ margin: 12px 0 0;
972
+ color: var(--sol-faint);
973
+ font: 500 11px / 1.5 var(--sol-mono);
974
+ letter-spacing: 0.06em;
975
+ }
976
+
977
+ /* the pricing table: three honest plans, the studio plan leads raised */
978
+ .cb-plans {
979
+ display: grid;
980
+ grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
981
+ gap: 16px;
982
+ align-items: stretch;
983
+ }
984
+ .cb-plan {
985
+ display: flex;
986
+ flex-direction: column;
987
+ padding: 26px 24px 22px;
988
+ border-radius: var(--sol-radius-lg);
989
+ background: var(--sol-surface-1);
990
+ box-shadow: var(--sol-shadow-2);
991
+ }
992
+ .cb-plan--lead {
993
+ background: var(--sol-surface-2);
994
+ box-shadow:
995
+ var(--sol-shadow-3),
996
+ inset 0 2px 0 var(--sol-accent);
997
+ }
998
+ .cb-planname {
999
+ margin: 0 0 4px;
1000
+ font: 600 12px / 1.4 var(--sol-mono);
1001
+ letter-spacing: var(--sol-track-label);
1002
+ text-transform: uppercase;
1003
+ color: var(--sol-faint);
1004
+ }
1005
+ .cb-plan--lead .cb-planname {
1006
+ color: var(--sol-accent);
1007
+ }
1008
+ .cb-planprice {
1009
+ margin: 0;
1010
+ font-size: 2.2rem;
1011
+ font-weight: 600;
1012
+ letter-spacing: var(--sol-track-display);
1013
+ color: var(--sol-ink);
1014
+ font-variant-numeric: tabular-nums;
1015
+ }
1016
+ .cb-planper {
1017
+ margin: 0 0 10px;
1018
+ color: var(--sol-faint);
1019
+ font: 500 12px / 1.5 var(--sol-mono);
1020
+ }
1021
+ .cb-planblurb {
1022
+ margin: 0 0 14px;
1023
+ font-size: 0.9rem;
1024
+ color: var(--sol-muted);
1025
+ }
1026
+ .cb-planfeats {
1027
+ margin: 0 0 20px;
1028
+ padding: 0;
1029
+ list-style: none;
1030
+ flex: 1;
1031
+ }
1032
+ .cb-planfeat {
1033
+ padding: 9px 0;
1034
+ border-top: 1px solid var(--sol-hairline);
1035
+ font-size: 0.86rem;
1036
+ color: var(--sol-muted);
1037
+ }
1038
+
1039
+ /* the app directory: cards with the one accent dot each */
1040
+ .cb-appgrid {
1041
+ display: grid;
1042
+ grid-template-columns: repeat(auto-fill, minmax(min(280px, 100%), 1fr));
1043
+ gap: 14px;
1044
+ }
1045
+ .cb-appcard {
1046
+ display: flex;
1047
+ flex-direction: column;
1048
+ gap: 4px;
1049
+ padding: 18px 18px 16px;
1050
+ border-radius: var(--sol-radius-lg);
1051
+ background: var(--sol-surface-1);
1052
+ box-shadow: var(--sol-shadow-1);
1053
+ transition:
1054
+ background-color var(--sol-micro) var(--sol-ease-out),
1055
+ box-shadow var(--sol-micro) var(--sol-ease-out),
1056
+ transform var(--sol-micro) var(--sol-ease-out);
1057
+ }
1058
+ .cb-appcard:hover {
1059
+ background: var(--sol-surface-2);
1060
+ box-shadow: var(--sol-shadow-4);
1061
+ transform: translateY(-2px);
1062
+ }
1063
+ .cb-appcard:active {
1064
+ transform: translateY(0) scale(0.99);
1065
+ transition-duration: 100ms;
1066
+ transition-timing-function: ease-in-out;
1067
+ }
1068
+ .cb-apphead {
1069
+ display: flex;
1070
+ align-items: center;
1071
+ gap: 9px;
1072
+ margin: 0 0 4px;
1073
+ }
1074
+ .cb-appdot {
1075
+ flex: none;
1076
+ width: 8px;
1077
+ height: 8px;
1078
+ border-radius: 2px;
1079
+ background: var(--cb-dot, var(--sol-accent));
1080
+ }
1081
+ .cb-appname {
1082
+ margin: 0;
1083
+ color: var(--sol-ink);
1084
+ font: 600 14.5px / 1.4 var(--sol-mono);
1085
+ letter-spacing: -0.01em;
1086
+ }
1087
+ .cb-approle {
1088
+ margin: 0;
1089
+ font-size: 0.85rem;
1090
+ color: var(--sol-muted);
1091
+ }
1092
+ .cb-appopen {
1093
+ margin: 10px 0 0;
1094
+ color: var(--sol-faint);
1095
+ font: 500 10.5px / 1.4 var(--sol-mono);
1096
+ letter-spacing: var(--sol-track-label);
1097
+ text-transform: uppercase;
1098
+ transition: color var(--sol-micro) var(--sol-ease-out);
1099
+ }
1100
+ .cb-appcard:hover .cb-appopen {
1101
+ color: var(--sol-accent);
1102
+ }
1103
+
1104
+ /* the support channels: one honest card per way to help */
1105
+ .cb-channeltext {
1106
+ margin: 0 0 12px;
1107
+ font-size: 0.9rem;
1108
+ color: var(--sol-muted);
1109
+ }
1110
+
1111
+ /* the blog index and the article bodies */
1112
+ .cb-postlist {
1113
+ margin: 0;
1114
+ padding: 0;
1115
+ list-style: none;
1116
+ }
1117
+ .cb-postrow {
1118
+ padding: 16px 2px;
1119
+ border-top: 1px solid var(--sol-hairline);
1120
+ transition: background-color var(--sol-micro) var(--sol-ease-out);
1121
+ }
1122
+ .cb-postrow:hover {
1123
+ background: var(--wash-soft);
1124
+ }
1125
+ .cb-postdate {
1126
+ margin: 0 0 2px;
1127
+ color: var(--sol-faint);
1128
+ font: 500 11px / 1.5 var(--sol-mono);
1129
+ font-variant-numeric: tabular-nums;
1130
+ letter-spacing: 0.06em;
1131
+ }
1132
+ .cb-postlink {
1133
+ display: inline-flex;
1134
+ align-items: center;
1135
+ min-height: 44px;
1136
+ color: var(--sol-ink);
1137
+ font-weight: 600;
1138
+ font-size: 1.05rem;
1139
+ letter-spacing: var(--sol-track-display);
1140
+ }
1141
+ .cb-postlink:hover {
1142
+ color: var(--sol-accent);
1143
+ }
1144
+ .cb-postexcerpt {
1145
+ margin: 6px 0 0;
1146
+ max-width: 64ch;
1147
+ font-size: 0.9rem;
1148
+ color: var(--sol-muted);
1149
+ }
1150
+ .cb-article {
1151
+ margin-top: clamp(30px, 5vw, 48px);
1152
+ padding-top: clamp(18px, 3vw, 28px);
1153
+ border-top: 1px solid var(--sol-hairline-strong);
1154
+ }
1155
+ .cb-article .cb-secttitle {
1156
+ max-width: 30ch;
1157
+ }
1158
+
1159
+ /* the display voice of a post title: the trylle display clamp and the
1160
+ -0.02em track — the article opens like the site hero does */
1161
+ .cb-posttitle {
1162
+ margin: 0 0 10px;
1163
+ max-width: 30ch;
1164
+ font-size: var(--sol-text-h1);
1165
+ letter-spacing: var(--sol-track-display);
1166
+ line-height: 1.08;
1167
+ color: var(--sol-ink);
1168
+ }
1169
+ .cb-articlebody {
1170
+ max-width: 65ch;
1171
+ }
1172
+ .cb-articlebody p {
1173
+ font-size: 0.95rem;
1174
+ line-height: 1.7;
1175
+ }
1176
+
1177
+ /* ---------- 6. THE AD SLOT — reserved, labeled, honest ----------
1178
+ fixed aspect ratio, the visible "advertisement" label, and while no
1179
+ network id is configured the empty state breathes on the opacity-only
1180
+ skeleton shimmer — no script ever ships in this repository */
1181
+ .cb-ads {
1182
+ margin-top: clamp(32px, 5vw, 56px);
1183
+ border-top: 1px solid var(--sol-hairline);
1184
+ padding-top: 14px;
1185
+ }
1186
+ .cb-adslabel {
1187
+ display: block;
1188
+ margin-bottom: 10px;
1189
+ color: var(--sol-faint);
1190
+ font: 600 10px / 1.4 var(--sol-mono);
1191
+ letter-spacing: var(--sol-track-label);
1192
+ text-transform: uppercase;
1193
+ }
1194
+ .cb-adsbox {
1195
+ display: grid;
1196
+ place-items: center;
1197
+ aspect-ratio: var(--cb-ads-ratio, 728 / 90);
1198
+ border: 1px dashed var(--sol-hairline-strong);
1199
+ border-radius: var(--sol-radius);
1200
+ background: var(--sol-surface-1);
1201
+ max-width: 100%;
1202
+ }
1203
+ .cb-adsnote {
1204
+ color: var(--sol-faint);
1205
+ font: 400 11.5px / 1.5 var(--sol-mono);
1206
+ letter-spacing: 0.04em;
1207
+ }
1208
+
1209
+ /* ---------- 7. THE 404 ---------- */
1210
+ .cb-missing {
1211
+ min-height: 42vh;
1212
+ display: flex;
1213
+ flex-direction: column;
1214
+ justify-content: center;
1215
+ }
1216
+
1217
+ /* ---------- 8. THE BRAND MARK MOTION — transform only, guarded ---------- */
1218
+ .cbMark {
1219
+ display: inline-block;
1220
+ flex: none;
1221
+ line-height: 0;
1222
+ }
1223
+ .cbMarkSvg {
1224
+ display: block;
1225
+ width: 100%;
1226
+ height: 100%;
1227
+ overflow: visible;
1228
+ shape-rendering: geometricPrecision;
1229
+ transition: transform 260ms var(--sol-ease-out);
1230
+ will-change: transform;
1231
+ }
1232
+ .cbMark:hover .cbMarkSvg {
1233
+ transform: perspective(340px) rotateX(4deg) rotateY(-5deg) scale(1.02);
1234
+ }
1235
+ @media (hover: none), (pointer: coarse) {
1236
+ .cbMark:hover .cbMarkSvg {
1237
+ transform: none;
1238
+ }
1239
+ }
1240
+
1241
+ /* ---------- 9. RESPONSIVE — one design, only the ratio changes ---------- */
1242
+ @media (max-width: 760px) {
1243
+ .cb-brandtag {
1244
+ display: none;
1245
+ }
1246
+ .cb-top {
1247
+ flex-wrap: wrap;
1248
+ }
1249
+ .cb-footgrid {
1250
+ grid-template-columns: 1fr;
1251
+ }
1252
+ }
1253
+
1254
+ /* ---------- 10. KEYFRAMES — the entrances and the windows pop ---------- */
1255
+ @keyframes cbRise {
1256
+ from {
1257
+ opacity: 0;
1258
+ transform: translateY(16px);
1259
+ }
1260
+ }
1261
+ /* the skeleton shimmer: opacity only — the reserved wells breathe while
1262
+ the real content is not configured yet */
1263
+ @keyframes cbSkel {
1264
+ 0%,
1265
+ 100% {
1266
+ opacity: 1;
1267
+ }
1268
+ 50% {
1269
+ opacity: 0.45;
1270
+ }
1271
+ }
1272
+ /* the honest wheel of the aria-busy loading voice */
1273
+ @keyframes solSpin {
1274
+ to {
1275
+ transform: rotate(1turn);
1276
+ }
1277
+ }
1278
+ /* dtPopIntro — the pin entrance of the windows recipe: 0 → 1.125 (40%) →
1279
+ 0.725 (70%) → 1 (the bounce); the bar entries pop on mount, staggered */
1280
+ @media (prefers-reduced-motion: no-preference) {
1281
+ .cb-brand {
1282
+ animation: dtPopIntro 800ms ease-in-out backwards;
1283
+ }
1284
+ .cb-navlink {
1285
+ animation: dtPopIntro 800ms ease-in-out backwards;
1286
+ }
1287
+ .cb-navlink:nth-child(2) {
1288
+ animation-delay: 60ms;
1289
+ }
1290
+ .cb-navlink:nth-child(3) {
1291
+ animation-delay: 120ms;
1292
+ }
1293
+ .cb-navlink:nth-child(4) {
1294
+ animation-delay: 180ms;
1295
+ }
1296
+ }
1297
+ @keyframes dtPopIntro {
1298
+ 0% {
1299
+ opacity: 0;
1300
+ transform: scale(0);
1301
+ }
1302
+ 40% {
1303
+ opacity: 1;
1304
+ transform: scale(1.125);
1305
+ }
1306
+ 70% {
1307
+ transform: scale(0.725);
1308
+ }
1309
+ 100% {
1310
+ opacity: 1;
1311
+ transform: scale(1);
1312
+ }
1313
+ }
1314
+
1315
+ /* ---------- 10b. INTRO — the bare presentation page (/intro) ---------- */
1316
+ /* the family grammar's last seat: every app carries an intro; the cobaia
1317
+ one mounts BARE — no window chrome — riding the site voice. The akash
1318
+ splash plays the family recipe (the mark spring on the overshoot curve
1319
+ cubic-bezier(.34,1.56,.64,1), the leave cubic-bezier(0.76,0,0.24,1) at
1320
+ 0.8s), the landing rides the cb-in stagger under the second, the layers
1321
+ ride the surface-ladder bands (canvas → s0 → deep), the door panes ride
1322
+ the silk law (layered shadows, the inset highlight, the silk curve).
1323
+ Reduced motion stills the splash and the entrances; reduced transparency
1324
+ lands the bar on the solid floor. */
1325
+
1326
+ /* the bare page: the canvas floor, no frame, no window padding */
1327
+ .cb-intro {
1328
+ display: flex;
1329
+ flex-direction: column;
1330
+ min-height: 100dvh;
1331
+ background: var(--sol-canvas);
1332
+ }
1333
+
1334
+ /* the measure of the bare page: the site measure without the window gutters */
1335
+ .cb-introwrap {
1336
+ width: 100%;
1337
+ max-width: var(--cb-maxw);
1338
+ margin: 0 auto;
1339
+ padding: 0 clamp(16px, 4vw, 32px);
1340
+ box-sizing: border-box;
1341
+ }
1342
+
1343
+ /* the intro bar: the same acrylic voice as the site bar, unframed */
1344
+ .cb-introbar {
1345
+ position: sticky;
1346
+ top: 0;
1347
+ z-index: var(--z-bar);
1348
+ border-bottom: 1px solid var(--bar-hairline);
1349
+ background-color: var(--bar-acrylic);
1350
+ background-image: var(--win-noise);
1351
+ background-blend-mode: soft-light;
1352
+ -webkit-backdrop-filter: saturate(3) blur(20px);
1353
+ backdrop-filter: saturate(3) blur(20px);
1354
+ }
1355
+ .cb-introbar__in {
1356
+ display: flex;
1357
+ align-items: center;
1358
+ gap: 14px;
1359
+ max-width: var(--cb-maxw);
1360
+ margin: 0 auto;
1361
+ padding: 10px clamp(16px, 4vw, 32px);
1362
+ }
1363
+ .cb-introbar__brand {
1364
+ display: inline-flex;
1365
+ align-items: center;
1366
+ gap: 9px;
1367
+ }
1368
+ .cb-introbar__word {
1369
+ color: var(--sol-ink);
1370
+ font: 600 13px / 1 var(--sol-sans);
1371
+ letter-spacing: var(--sol-track-display);
1372
+ }
1373
+ .cb-introbar__spacer {
1374
+ flex: 1;
1375
+ }
1376
+ .cb-introbar__nav {
1377
+ display: flex;
1378
+ align-items: center;
1379
+ gap: 6px;
1380
+ }
1381
+ .cb-introdoor {
1382
+ display: inline-flex;
1383
+ align-items: center;
1384
+ min-height: 36px;
1385
+ padding: 0 12px;
1386
+ border-radius: var(--win-radius-ctl);
1387
+ color: var(--sol-muted);
1388
+ font: 600 13px / 1 var(--sol-sans);
1389
+ transition:
1390
+ background-color var(--sol-micro) var(--sol-ease-out),
1391
+ color var(--sol-micro) var(--sol-ease-out);
1392
+ }
1393
+ .cb-introdoor:hover {
1394
+ background: var(--wash);
1395
+ color: var(--sol-ink);
1396
+ text-decoration: none;
1397
+ }
1398
+ .cb-introdoor:active {
1399
+ background: var(--wash-soft);
1400
+ }
1401
+ .cb-introdoor:focus-visible {
1402
+ outline: none;
1403
+ box-shadow: inset 0 -2px 0 var(--sol-focus);
1404
+ }
1405
+
1406
+ /* the hero band: the canvas floor, the mark opens the stagger */
1407
+ .cb-introhero {
1408
+ padding: clamp(56px, 9vw, 112px) 0 clamp(40px, 6vw, 72px);
1409
+ }
1410
+ .cb-introhero__mark {
1411
+ display: inline-grid;
1412
+ place-items: center;
1413
+ margin-bottom: 26px;
1414
+ }
1415
+
1416
+ /* the ladder bands: the layers step the surface ladder — canvas (hero) →
1417
+ the s0 rung (plans) → the deep floor (doors); hairlines close each band */
1418
+ .cb-introband {
1419
+ border-top: 1px solid var(--sol-hairline);
1420
+ padding: clamp(32px, 5vw, 56px) 0 clamp(40px, 6vw, 72px);
1421
+ }
1422
+ .cb-introband--s1 {
1423
+ background: var(--sol-surface-1);
1424
+ }
1425
+ .cb-introband--deep {
1426
+ background: var(--sol-canvas-deep);
1427
+ border-bottom: 1px solid var(--sol-hairline);
1428
+ }
1429
+
1430
+ /* the door panes: the silk law — the inset highlight, the layered drop
1431
+ shadows, the silk curve on the transitions, one hover raise */
1432
+ .cb-introdoorgrid {
1433
+ display: grid;
1434
+ grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
1435
+ gap: 16px;
1436
+ margin-top: 24px;
1437
+ }
1438
+ .cb-intropane {
1439
+ display: flex;
1440
+ flex-direction: column;
1441
+ padding: 22px;
1442
+ border: 1px solid var(--sol-hairline-strong);
1443
+ border-radius: var(--sol-radius-lg);
1444
+ background: var(--sol-surface-2);
1445
+ box-shadow:
1446
+ inset 0 1px 0 rgb(255 255 255 / 5%),
1447
+ 0 1px 2px rgb(0 0 0 / 28%),
1448
+ 0 10px 28px -18px rgb(0 0 0 / 55%);
1449
+ transition:
1450
+ background-color 140ms var(--ease-silk),
1451
+ box-shadow 140ms var(--ease-silk),
1452
+ transform 140ms var(--ease-silk);
1453
+ }
1454
+ .cb-intropane:hover {
1455
+ background: var(--sol-surface-3);
1456
+ box-shadow:
1457
+ inset 0 1px 0 rgb(255 255 255 / 6%),
1458
+ 0 2px 4px rgb(0 0 0 / 28%),
1459
+ 0 16px 36px -18px rgb(0 0 0 / 50%);
1460
+ transform: translateY(-2px);
1461
+ }
1462
+ .cb-intropane__text {
1463
+ margin: 6px 0 16px;
1464
+ font-size: 0.9rem;
1465
+ line-height: 1.6;
1466
+ color: var(--sol-muted);
1467
+ }
1468
+ .cb-intropane__door {
1469
+ display: inline-flex;
1470
+ align-items: center;
1471
+ gap: 9px;
1472
+ align-self: flex-start;
1473
+ min-height: 44px;
1474
+ margin-top: auto;
1475
+ padding: 0 16px;
1476
+ border-radius: var(--win-radius-ctl);
1477
+ background: var(--wash-soft);
1478
+ color: var(--sol-ink);
1479
+ font: 600 14px / 1 var(--sol-sans);
1480
+ box-shadow:
1481
+ inset 0 1px 0 rgb(255 255 255 / 10%),
1482
+ 0 0 0 1px var(--sol-hairline-strong),
1483
+ 0 1px 2px rgb(0 0 0 / 14%);
1484
+ transition:
1485
+ background-color 140ms var(--ease-silk),
1486
+ color 140ms var(--ease-silk),
1487
+ box-shadow 140ms var(--ease-silk);
1488
+ }
1489
+ .cb-intropane__door:hover {
1490
+ background: var(--wash);
1491
+ color: var(--sol-ink);
1492
+ text-decoration: none;
1493
+ box-shadow:
1494
+ inset 0 1px 0 rgb(255 255 255 / 14%),
1495
+ 0 0 0 1px color-mix(in oklab, var(--sol-ink) 16%, transparent),
1496
+ 0 2px 4px rgb(0 0 0 / 16%);
1497
+ }
1498
+ .cb-intropane__door:active {
1499
+ transform: scale(0.97);
1500
+ box-shadow:
1501
+ inset 0 1px 0 rgb(0 0 0 / 8%),
1502
+ 0 0 0 1px var(--sol-hairline-strong);
1503
+ }
1504
+ .cb-intropane__door:focus-visible {
1505
+ outline: none;
1506
+ box-shadow:
1507
+ inset 0 1px 0 rgb(255 255 255 / 10%),
1508
+ inset 0 -2px 0 var(--sol-focus),
1509
+ 0 0 0 1px var(--sol-hairline-strong);
1510
+ }
1511
+ .cb-intropane__glyph {
1512
+ flex: none;
1513
+ color: var(--sol-accent);
1514
+ transition: transform 140ms var(--ease-silk);
1515
+ }
1516
+ .cb-intropane__door:hover .cb-intropane__glyph {
1517
+ transform: translateX(2px);
1518
+ }
1519
+
1520
+ /* the plans door line: the one text link under the table */
1521
+ .cb-introdoorline {
1522
+ margin: 22px 0 0;
1523
+ }
1524
+
1525
+ /* the footer strip: hairline top, the door rows and the legal line */
1526
+ .cb-introfoot {
1527
+ margin-top: auto;
1528
+ border-top: 1px solid var(--sol-hairline);
1529
+ background: var(--sol-canvas-deep);
1530
+ }
1531
+ .cb-introfoot__row {
1532
+ display: flex;
1533
+ flex-wrap: wrap;
1534
+ align-items: baseline;
1535
+ gap: 6px 18px;
1536
+ }
1537
+ .cb-introfoot__door {
1538
+ display: inline-flex;
1539
+ align-items: center;
1540
+ min-height: 36px;
1541
+ color: var(--sol-muted);
1542
+ font: 600 13px / 1 var(--sol-sans);
1543
+ transition: color var(--sol-micro) var(--sol-ease-out);
1544
+ }
1545
+ .cb-introfoot__door:hover {
1546
+ color: var(--sol-ink);
1547
+ text-decoration: underline;
1548
+ text-underline-offset: 3px;
1549
+ text-decoration-color: var(--sol-hairline-strong);
1550
+ }
1551
+ .cb-introfoot__fam {
1552
+ display: inline-flex;
1553
+ align-items: center;
1554
+ gap: 7px;
1555
+ color: var(--sol-muted);
1556
+ font: 500 12.5px / 1 var(--sol-mono);
1557
+ transition: color var(--sol-micro) var(--sol-ease-out);
1558
+ }
1559
+ .cb-introfoot__fam:hover {
1560
+ color: var(--sol-ink);
1561
+ }
1562
+ .cb-introfoot__dot {
1563
+ flex: none;
1564
+ width: 7px;
1565
+ height: 7px;
1566
+ border-radius: 2px;
1567
+ background: var(--cb-dot, var(--sol-accent));
1568
+ }
1569
+ .cb-introfoot__legal {
1570
+ margin: 18px 0 0;
1571
+ padding: 14px 0 22px;
1572
+ border-top: 1px solid var(--sol-hairline);
1573
+ color: var(--sol-faint);
1574
+ font: 400 11px / 1.6 var(--sol-mono);
1575
+ letter-spacing: 0.02em;
1576
+ }
1577
+ .cb-introfoot .cb-eyebrow {
1578
+ margin: 8px 0;
1579
+ }
1580
+ .cb-introfoot .cb-introwrap {
1581
+ padding-top: 26px;
1582
+ }
1583
+
1584
+ /* the splash: the akash floor — the deep canvas + the grain, the mark
1585
+ springing on the overshoot curve, the name rising with the same spring,
1586
+ the role fading late; the leave slides the whole overlay up in 0.8s on
1587
+ the leave curve and reveals the landing beneath. No loading dots. */
1588
+ .cb-splash {
1589
+ position: fixed;
1590
+ inset: 0;
1591
+ z-index: var(--z-overlay);
1592
+ display: grid;
1593
+ place-items: center;
1594
+ background: var(--sol-canvas-deep);
1595
+ cursor: pointer;
1596
+ }
1597
+ .cb-splash::after {
1598
+ content: "";
1599
+ position: absolute;
1600
+ inset: 0;
1601
+ background-image: var(--win-noise);
1602
+ mix-blend-mode: soft-light;
1603
+ pointer-events: none;
1604
+ }
1605
+ .cb-splash__stage {
1606
+ position: relative;
1607
+ display: grid;
1608
+ justify-items: center;
1609
+ gap: 18px;
1610
+ padding: 0 24px;
1611
+ text-align: center;
1612
+ }
1613
+ .cb-splash__mark {
1614
+ display: grid;
1615
+ place-items: center;
1616
+ animation: cbSplashSpring 600ms cubic-bezier(0.34, 1.56, 0.64, 1) backwards;
1617
+ }
1618
+ .cb-splash__name {
1619
+ margin: 0;
1620
+ color: var(--sol-ink);
1621
+ font: 800 clamp(2rem, 5vw, 3rem) / 1.05 var(--sol-sans);
1622
+ letter-spacing: var(--sol-track-display);
1623
+ animation: cbSplashRise 550ms cubic-bezier(0.34, 1.56, 0.64, 1) 140ms backwards;
1624
+ }
1625
+ .cb-splash__role {
1626
+ margin: 0;
1627
+ color: var(--sol-muted);
1628
+ font: 400 12px / 1.6 var(--sol-sans);
1629
+ letter-spacing: var(--sol-track-label);
1630
+ text-transform: lowercase;
1631
+ animation: cbSplashFade 300ms var(--sol-ease-out) 400ms backwards;
1632
+ }
1633
+ .cb-splash__skip {
1634
+ position: absolute;
1635
+ bottom: 22px;
1636
+ left: 0;
1637
+ right: 0;
1638
+ color: var(--sol-faint);
1639
+ font: 500 11px / 1 var(--sol-mono);
1640
+ letter-spacing: var(--sol-track-label);
1641
+ text-align: center;
1642
+ text-transform: lowercase;
1643
+ animation: cbSplashFade 300ms var(--sol-ease-out) 600ms backwards;
1644
+ }
1645
+ .cb-splash[data-leaving="true"] {
1646
+ animation: cbSplashLeave 800ms cubic-bezier(0.76, 0, 0.24, 1) forwards;
1647
+ }
1648
+
1649
+ @keyframes cbSplashSpring {
1650
+ from {
1651
+ opacity: 0;
1652
+ transform: scale(0.72);
1653
+ }
1654
+ }
1655
+ @keyframes cbSplashRise {
1656
+ from {
1657
+ opacity: 0;
1658
+ transform: translateY(20px);
1659
+ }
1660
+ }
1661
+ @keyframes cbSplashFade {
1662
+ from {
1663
+ opacity: 0;
1664
+ }
1665
+ }
1666
+ @keyframes cbSplashLeave {
1667
+ to {
1668
+ transform: translateY(-100%);
1669
+ }
1670
+ }
1671
+
1672
+ /* the intro's own stops: reduced motion stills the splash and the entrances
1673
+ (the splash never mounts under the preference — the belt here is the
1674
+ second one), reduced transparency lands the bar on the solid floor */
1675
+ @media (prefers-reduced-motion: reduce) {
1676
+ .cb-splash,
1677
+ .cb-splash__mark,
1678
+ .cb-splash__name,
1679
+ .cb-splash__role,
1680
+ .cb-splash__skip {
1681
+ animation: none !important;
1682
+ }
1683
+ .cb-intropane,
1684
+ .cb-intropane__door,
1685
+ .cb-introdoor,
1686
+ .cb-introfoot__door,
1687
+ .cb-introfoot__fam,
1688
+ .cb-intropane__glyph {
1689
+ transition: none !important;
1690
+ }
1691
+ .cb-intropane:hover,
1692
+ .cb-intropane__door:active,
1693
+ .cb-intropane__door:hover .cb-intropane__glyph {
1694
+ transform: none;
1695
+ }
1696
+ }
1697
+ @media (prefers-reduced-transparency: reduce) {
1698
+ .cb-introbar {
1699
+ background-color: #0a0a0b;
1700
+ background-image: none;
1701
+ -webkit-backdrop-filter: none;
1702
+ backdrop-filter: none;
1703
+ }
1704
+ .cb-splash::after {
1705
+ display: none;
1706
+ }
1707
+ }
1708
+
1709
+ /* ---------- 11. GUARDS — the house stops (reduced motion WINS, last) ---------- */
1710
+ @media (prefers-reduced-transparency: reduce) {
1711
+ /* the solid floors: the bar acrylic lands on a rung, the blur dies */
1712
+ .cb-top {
1713
+ background-color: #0a0a0b;
1714
+ background-image: none;
1715
+ -webkit-backdrop-filter: none;
1716
+ backdrop-filter: none;
1717
+ }
1718
+ }
1719
+ @media (prefers-reduced-motion: reduce) {
1720
+ .cb-in,
1721
+ .cb-brand,
1722
+ .cb-navlink,
1723
+ .cb-skel {
1724
+ animation: none !important;
1725
+ }
1726
+ .cb-skip,
1727
+ .cb-brand,
1728
+ .cb-navlink,
1729
+ .cb-btn,
1730
+ .cb-card,
1731
+ .cb-appcard,
1732
+ .cb-appopen,
1733
+ .cb-postrow,
1734
+ .cb-footlink,
1735
+ .cb-famlink,
1736
+ .cb-link,
1737
+ .cbMarkSvg {
1738
+ transition: none !important;
1739
+ }
1740
+ .cb-navlink:active,
1741
+ .cb-brand:active .cbMarkSvg,
1742
+ .cb-btn:active,
1743
+ .cb-appcard:active {
1744
+ transform: none;
1745
+ }
1746
+ .cbMark:hover .cbMarkSvg {
1747
+ transform: none;
1748
+ }
1749
+ html {
1750
+ scroll-behavior: auto;
1751
+ }
1752
+ }
1753
+ /* the hard stop: every animation and transition dies — this block is LAST
1754
+ so it wins every earlier duration in the file */
1755
+ @media (prefers-reduced-motion: reduce) {
1756
+ *,
1757
+ *::before,
1758
+ *::after {
1759
+ animation-duration: 0.01ms !important;
1760
+ animation-iteration-count: 1 !important;
1761
+ transition-duration: 0.01ms !important;
1762
+ }
1763
+ }
1764
+
1765
+ /* ==========================================================================
1766
+ the family motion law: the duty cycled loops, the reduced motion and the
1767
+ pause hook. the loops ride the stepped keyframes so the compositor draws
1768
+ a handful of frames per cycle instead of repainting every vsync, the
1769
+ offscreen surfaces pause through the anim paused attribute, and the
1770
+ reduced motion preference zeroes every custom animation.
1771
+ ========================================================================== */
1772
+
1773
+ @keyframes skeletonStep {
1774
+ 0% {
1775
+ opacity: 0.45;
1776
+ }
1777
+ 50% {
1778
+ opacity: 0.8;
1779
+ }
1780
+ 100% {
1781
+ opacity: 0.45;
1782
+ }
1783
+ }
1784
+
1785
+ @keyframes pulseStep {
1786
+ 0% {
1787
+ opacity: 1;
1788
+ transform: scale(1);
1789
+ }
1790
+ 50% {
1791
+ opacity: 0.6;
1792
+ transform: scale(1.06);
1793
+ }
1794
+ 100% {
1795
+ opacity: 1;
1796
+ transform: scale(1);
1797
+ }
1798
+ }
1799
+
1800
+ @keyframes pingStep {
1801
+ 0% {
1802
+ opacity: 0.7;
1803
+ transform: scale(1);
1804
+ }
1805
+ 70% {
1806
+ opacity: 0;
1807
+ transform: scale(2.2);
1808
+ }
1809
+ 100% {
1810
+ opacity: 0;
1811
+ transform: scale(2.2);
1812
+ }
1813
+ }
1814
+
1815
+ .anim-skeleton {
1816
+ animation: skeletonStep 2.4s steps(8, end) infinite;
1817
+ }
1818
+ .anim-pulse {
1819
+ animation: pulseStep 2s steps(8, end) infinite;
1820
+ }
1821
+ .anim-ping {
1822
+ animation: pingStep 2s steps(8, end) infinite;
1823
+ }
1824
+
1825
+ [data-anim-paused] .anim-skeleton,
1826
+ [data-anim-paused] .anim-pulse,
1827
+ [data-anim-paused] .anim-ping,
1828
+ [data-anim-paused] [class*="anim-"] {
1829
+ animation-play-state: paused;
1830
+ }
1831
+
1832
+ @media (prefers-reduced-motion: reduce) {
1833
+ .anim-skeleton,
1834
+ .anim-pulse,
1835
+ .anim-ping,
1836
+ [class*="anim-"] {
1837
+ animation: none;
1838
+ }
1839
+ *,
1840
+ *::before,
1841
+ *::after {
1842
+ transition-duration: 0.01ms !important;
1843
+ animation-duration: 0.01ms !important;
1844
+ }
1845
+ }
1846
+
1847
+ /* ==========================================================================
1848
+ the silk surface law: the panels, the buttons and the inputs of the
1849
+ family ride the layered shadows with the inset highlight, the silk curve
1850
+ for the transitions, and the guards of the reduced transparency, so the
1851
+ app chrome renders exactly like the design showcase of the os app.
1852
+ ========================================================================== */
1853
+
1854
+ .panel-silk {
1855
+ border: 1px solid rgb(255 255 255 / 8%);
1856
+ background: color-mix(in srgb, var(--s1) 86%, transparent);
1857
+ border-radius: var(--shell-radius);
1858
+ padding: 14px;
1859
+ box-shadow:
1860
+ inset 0 1px 0 rgb(255 255 255 / 5%),
1861
+ 0 1px 2px rgb(0 0 0 / 28%),
1862
+ 0 10px 28px -18px rgb(0 0 0 / 55%);
1863
+ backdrop-filter: blur(14px) saturate(120%);
1864
+ -webkit-backdrop-filter: blur(14px) saturate(120%);
1865
+ }
1866
+
1867
+ .silk-btn {
1868
+ border: 1px solid rgb(255 255 255 / 10%);
1869
+ border-radius: 10px;
1870
+ min-height: 44px;
1871
+ padding: 0 14px;
1872
+ color: var(--ink);
1873
+ background: rgb(255 255 255 / 5%);
1874
+ font: inherit;
1875
+ font-weight: 700;
1876
+ cursor: pointer;
1877
+ box-shadow:
1878
+ inset 0 1px 0 rgb(255 255 255 / 6%),
1879
+ 0 1px 2px rgb(0 0 0 / 30%);
1880
+ transition:
1881
+ transform 140ms var(--ease-silk),
1882
+ box-shadow 140ms var(--ease-silk),
1883
+ opacity 140ms var(--ease-silk),
1884
+ background-color 140ms var(--ease-silk),
1885
+ border-color 140ms var(--ease-silk);
1886
+ }
1887
+
1888
+ .silk-btn:hover {
1889
+ background: rgb(255 255 255 / 9%);
1890
+ box-shadow:
1891
+ inset 0 1px 0 rgb(255 255 255 / 6%),
1892
+ 0 2px 4px rgb(0 0 0 / 28%),
1893
+ 0 8px 20px -10px rgb(0 0 0 / 48%);
1894
+ }
1895
+
1896
+ .silk-btn:active {
1897
+ transform: translateY(1px);
1898
+ }
1899
+
1900
+ .silk-btn:focus-visible,
1901
+ .silk-input:focus-visible,
1902
+ .silk-area:focus-visible {
1903
+ outline: 2px solid var(--color-focus);
1904
+ outline-offset: 2px;
1905
+ }
1906
+
1907
+ .silk-btn:disabled {
1908
+ cursor: not-allowed;
1909
+ opacity: 0.5;
1910
+ transform: none;
1911
+ box-shadow: none;
1912
+ }
1913
+
1914
+ .silk-input,
1915
+ .silk-area {
1916
+ width: 100%;
1917
+ color: var(--ink);
1918
+ background: rgb(0 0 0 / 26%);
1919
+ border: 1px solid rgb(255 255 255 / 8%);
1920
+ border-radius: 10px;
1921
+ padding: 11px 12px;
1922
+ font: inherit;
1923
+ box-shadow: inset 0 1px 2px rgb(0 0 0 / 24%);
1924
+ transition:
1925
+ border-color 140ms var(--ease-silk),
1926
+ background-color 140ms var(--ease-silk);
1927
+ }
1928
+
1929
+ .silk-area {
1930
+ resize: vertical;
1931
+ }
1932
+
1933
+ .silk-input:hover,
1934
+ .silk-area:hover {
1935
+ border-color: rgb(255 255 255 / 18%);
1936
+ }
1937
+
1938
+ @media (prefers-reduced-transparency: reduce) {
1939
+ .panel-silk {
1940
+ background: var(--s1);
1941
+ backdrop-filter: none;
1942
+ -webkit-backdrop-filter: none;
1943
+ }
1944
+ }