@markuxt/markuxt 0.1.4

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 (94) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +168 -0
  3. package/app.config.d.ts +33 -0
  4. package/nuxt.config.ts +170 -0
  5. package/package.json +43 -0
  6. package/src/components/AppFooter.vue +225 -0
  7. package/src/components/AppHeader.vue +342 -0
  8. package/src/components/Hero.vue +438 -0
  9. package/src/components/Icon.vue +131 -0
  10. package/src/components/LanguageSwitcher.vue +71 -0
  11. package/src/components/MemberCard.vue +198 -0
  12. package/src/components/MembersGrid.vue +129 -0
  13. package/src/components/MermaidDiagram.vue +99 -0
  14. package/src/components/NewsCard.vue +119 -0
  15. package/src/components/PublicationCard.vue +245 -0
  16. package/src/components/SectionTitle.vue +75 -0
  17. package/src/components/content/ProseImg.vue +29 -0
  18. package/src/components/content/ProsePre.vue +58 -0
  19. package/src/components/content/ProseVideo.vue +45 -0
  20. package/src/composables/resolveContentImage.ts +35 -0
  21. package/src/content-transformers/binary-assets.ts +20 -0
  22. package/src/error.vue +58 -0
  23. package/src/layouts/default.vue +37 -0
  24. package/src/middleware/navigation-guard.ts +22 -0
  25. package/src/pages/index.vue +232 -0
  26. package/src/pages/members/[...slug].vue +542 -0
  27. package/src/pages/members/index.vue +147 -0
  28. package/src/pages/news/[...slug].vue +280 -0
  29. package/src/pages/news/index.vue +102 -0
  30. package/src/pages/positions/[...slug].vue +425 -0
  31. package/src/pages/positions/index.vue +266 -0
  32. package/src/pages/projects/[...slug].vue +441 -0
  33. package/src/pages/projects/index.vue +499 -0
  34. package/src/pages/publications/[...slug].vue +435 -0
  35. package/src/pages/publications/index.vue +145 -0
  36. package/src/plugins/mathml-components.ts +33 -0
  37. package/src/plugins/suppress-warnings.ts +40 -0
  38. package/src/public/_markuxt/components/AppFooter.vue +225 -0
  39. package/src/public/_markuxt/components/AppHeader.vue +342 -0
  40. package/src/public/_markuxt/components/Hero.vue +430 -0
  41. package/src/public/_markuxt/components/Icon.vue +131 -0
  42. package/src/public/_markuxt/components/LanguageSwitcher.vue +71 -0
  43. package/src/public/_markuxt/components/MemberCard.vue +198 -0
  44. package/src/public/_markuxt/components/MembersGrid.vue +129 -0
  45. package/src/public/_markuxt/components/MermaidDiagram.vue +99 -0
  46. package/src/public/_markuxt/components/NewsCard.vue +119 -0
  47. package/src/public/_markuxt/components/PublicationCard.vue +245 -0
  48. package/src/public/_markuxt/components/SectionTitle.vue +75 -0
  49. package/src/public/_markuxt/components/content/ProseImg.vue +29 -0
  50. package/src/public/_markuxt/components/content/ProsePre.vue +58 -0
  51. package/src/public/_markuxt/components/content/ProseVideo.vue +45 -0
  52. package/src/public/_markuxt/composables/resolveContentImage.ts +35 -0
  53. package/src/public/_markuxt/content-transformers/binary-assets.ts +20 -0
  54. package/src/public/_markuxt/error.vue +58 -0
  55. package/src/public/_markuxt/layouts/default.vue +37 -0
  56. package/src/public/_markuxt/middleware/navigation-guard.ts +22 -0
  57. package/src/public/_markuxt/pages/index.vue +232 -0
  58. package/src/public/_markuxt/pages/members/[...slug].vue +542 -0
  59. package/src/public/_markuxt/pages/members/index.vue +147 -0
  60. package/src/public/_markuxt/pages/news/[...slug].vue +280 -0
  61. package/src/public/_markuxt/pages/news/index.vue +102 -0
  62. package/src/public/_markuxt/pages/positions/[...slug].vue +425 -0
  63. package/src/public/_markuxt/pages/positions/index.vue +266 -0
  64. package/src/public/_markuxt/pages/projects/[...slug].vue +441 -0
  65. package/src/public/_markuxt/pages/projects/index.vue +499 -0
  66. package/src/public/_markuxt/pages/publications/[...slug].vue +435 -0
  67. package/src/public/_markuxt/pages/publications/index.vue +145 -0
  68. package/src/public/_markuxt/plugins/mathml-components.ts +33 -0
  69. package/src/public/_markuxt/plugins/suppress-warnings.ts +40 -0
  70. package/src/public/_markuxt/server/plugins/content-locale.ts +47 -0
  71. package/src/public/_markuxt/server/plugins/fix-content-anchors.ts +63 -0
  72. package/src/public/_markuxt/styles/_animations.css +99 -0
  73. package/src/public/_markuxt/styles/_base.css +31 -0
  74. package/src/public/_markuxt/styles/_code.css +109 -0
  75. package/src/public/_markuxt/styles/_components.css +109 -0
  76. package/src/public/_markuxt/styles/_layout.css +220 -0
  77. package/src/public/_markuxt/styles/_markdown.css +52 -0
  78. package/src/public/_markuxt/styles/_tokens.css +62 -0
  79. package/src/public/_markuxt/styles/_typography.css +144 -0
  80. package/src/public/_markuxt/styles/_utilities.css +110 -0
  81. package/src/public/_markuxt/styles/main.css +784 -0
  82. package/src/public/images/logo.png +0 -0
  83. package/src/server/plugins/content-locale.ts +47 -0
  84. package/src/server/plugins/fix-content-anchors.ts +63 -0
  85. package/src/styles/_animations.css +99 -0
  86. package/src/styles/_base.css +31 -0
  87. package/src/styles/_code.css +109 -0
  88. package/src/styles/_components.css +109 -0
  89. package/src/styles/_layout.css +220 -0
  90. package/src/styles/_markdown.css +52 -0
  91. package/src/styles/_tokens.css +62 -0
  92. package/src/styles/_typography.css +144 -0
  93. package/src/styles/_utilities.css +110 -0
  94. package/src/styles/main.css +784 -0
@@ -0,0 +1,784 @@
1
+ /* KaTeX math rendering styles */
2
+ @import 'katex/dist/katex.min.css';
3
+
4
+ @import './_tokens.css';
5
+ @import './_base.css';
6
+ @import './_typography.css';
7
+ @import './_layout.css';
8
+ @import './_components.css';
9
+ @import './_animations.css';
10
+ @import './_utilities.css';
11
+ @import './_code.css';
12
+ @import './_markdown.css';
13
+
14
+
15
+ /* CSS Custom Properties - Design System */
16
+ :root {
17
+ /* Colors */
18
+ --color-primary: #0a2540;
19
+ --color-primary-light: #1a3a5c;
20
+ --color-accent: #00d9ff;
21
+ --color-accent-hover: #00b8d9;
22
+ --color-secondary: #009bc1;
23
+ --color-secondary-light: #4db8d1;
24
+ --color-bg: #f8fafc;
25
+ --color-bg-alt: #ffffff;
26
+ --color-text: #0f172a;
27
+ --color-text-muted: #64748b;
28
+ --color-border: #e2e8f0;
29
+
30
+ /* Typography */
31
+ --font-display: 'Fraunces', serif;
32
+ --font-body: 'DM Sans', sans-serif;
33
+
34
+ /* Spacing */
35
+ --spacing-xs: 0.25rem;
36
+ --spacing-sm: 0.5rem;
37
+ --spacing-md: 1rem;
38
+ --spacing-lg: 1.5rem;
39
+ --spacing-xl: 2rem;
40
+ --spacing-2xl: 3rem;
41
+ --spacing-3xl: 4rem;
42
+ --spacing-4xl: 6rem;
43
+
44
+ /* Border Radius */
45
+ --radius-sm: 0.25rem;
46
+ --radius-md: 0.5rem;
47
+ --radius-lg: 0.75rem;
48
+ --radius-xl: 1rem;
49
+ --radius-2xl: 1.5rem; /* added: used by multiple pages (positions, projects, news) */
50
+ --radius-full: 9999px;
51
+
52
+ /* Shadows */
53
+ --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.05);
54
+ --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
55
+ --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1);
56
+ --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1);
57
+
58
+ /* Transitions */
59
+ --transition-fast: 150ms ease;
60
+ --transition-base: 250ms ease;
61
+ --transition-slow: 350ms ease;
62
+
63
+ /* ============================================
64
+ Responsive Breakpoints
65
+ ============================================ */
66
+ --breakpoint-sm: 480px; /* Small mobile */
67
+ --breakpoint-md: 768px; /* Tablet */
68
+ --breakpoint-lg: 1024px; /* Desktop */
69
+
70
+ /* ============================================
71
+ Layout Variables
72
+ ============================================ */
73
+ --header-height: 80px;
74
+ --card-min-width: 280px;
75
+ --touch-target-size: 44px;
76
+ }
77
+
78
+ /* ============================================
79
+ Base Styles
80
+ ============================================ */
81
+
82
+ *,
83
+ *::before,
84
+ *::after {
85
+ box-sizing: border-box;
86
+ margin: 0;
87
+ padding: 0;
88
+ }
89
+
90
+ html {
91
+ font-size: 16px;
92
+ scroll-behavior: smooth;
93
+ -webkit-font-smoothing: antialiased;
94
+ -moz-osx-font-smoothing: grayscale;
95
+ }
96
+
97
+ body {
98
+ font-family: var(--font-body);
99
+ font-size: 1rem;
100
+ line-height: 1.6;
101
+ color: var(--color-text);
102
+ background-color: var(--color-bg);
103
+ background-image:
104
+ linear-gradient(rgba(10, 37, 64, 0.02) 1px, transparent 1px),
105
+ linear-gradient(90deg, rgba(10, 37, 64, 0.02) 1px, transparent 1px);
106
+ background-size: 40px 40px;
107
+ min-height: 100vh;
108
+ }
109
+
110
+ /* ============================================
111
+ Typography
112
+ ============================================ */
113
+
114
+ h1,
115
+ h2,
116
+ h3,
117
+ h4,
118
+ h5,
119
+ h6 {
120
+ font-family: var(--font-display);
121
+ font-weight: 700;
122
+ line-height: 1.2;
123
+ color: var(--color-primary);
124
+ margin-bottom: var(--spacing-md);
125
+ scroll-margin-top: calc(var(--header-height) + var(--spacing-lg));
126
+ }
127
+
128
+ h1 {
129
+ font-size: clamp(2.5rem, 5vw, 4rem);
130
+ font-weight: 800;
131
+ letter-spacing: -0.02em;
132
+ }
133
+
134
+ h2 {
135
+ font-size: clamp(2rem, 4vw, 2.5rem);
136
+ font-weight: 700;
137
+ letter-spacing: -0.01em;
138
+ }
139
+
140
+ h3 {
141
+ font-size: clamp(1.5rem, 3vw, 1.875rem);
142
+ font-weight: 600;
143
+ }
144
+
145
+ h4 {
146
+ font-size: 1.25rem;
147
+ font-weight: 600;
148
+ }
149
+
150
+ p {
151
+ margin-bottom: var(--spacing-md);
152
+ }
153
+
154
+ /* Lists */
155
+ ul {
156
+ margin-bottom: var(--spacing-md);
157
+ padding-left: 0;
158
+ list-style: none !important;
159
+ }
160
+
161
+ ol {
162
+ margin-bottom: var(--spacing-md);
163
+ padding-left: 0;
164
+ list-style: none !important;
165
+ counter-reset: item;
166
+ }
167
+
168
+ li {
169
+ margin-bottom: var(--spacing-xs);
170
+ position: relative;
171
+ padding-left: 1.5rem;
172
+ }
173
+
174
+ ul > li::before {
175
+ content: '•' !important;
176
+ position: absolute !important;
177
+ left: 0 !important;
178
+ color: var(--color-secondary) !important;
179
+ }
180
+
181
+ ol > li::before {
182
+ content: counter(item) '.' !important;
183
+ counter-increment: item !important;
184
+ position: absolute !important;
185
+ left: 0 !important;
186
+ color: var(--color-secondary) !important;
187
+ font-weight: 600 !important;
188
+ }
189
+
190
+ /* Ensure ol li doesn't get ul's bullet */
191
+ ol li::before {
192
+ content: counter(item) '.' !important;
193
+ }
194
+
195
+ /* Task lists (GitHub-style checkboxes): the global `ul > li::before` bullet
196
+ and `li` indent don't apply here — the checkbox is the marker. Suppress the
197
+ blue dot and vertically center the box with its label line via flex. */
198
+ .task-list-item {
199
+ display: flex;
200
+ align-items: center;
201
+ padding-left: 0;
202
+ list-style: none;
203
+ }
204
+
205
+ .task-list-item::before {
206
+ content: none !important;
207
+ }
208
+
209
+ /* Custom checkbox: replace the native control (which is disabled/read-only for
210
+ markdown task lists) with a box that matches the design system. Flex-center
211
+ so the checkmark sits in the middle of the box on both axes. */
212
+ .task-list-item input[type='checkbox'] {
213
+ appearance: none;
214
+ -webkit-appearance: none;
215
+ display: inline-flex;
216
+ align-items: center;
217
+ justify-content: center;
218
+ flex-shrink: 0;
219
+ width: 1.05em;
220
+ height: 1.05em;
221
+ margin: 0 var(--spacing-sm) 0 0;
222
+ background: var(--color-bg-alt);
223
+ border: 2px solid var(--color-border);
224
+ border-radius: var(--radius-sm);
225
+ cursor: default;
226
+ transition: all var(--transition-fast);
227
+ }
228
+
229
+ /* Checked: accent fill + a CSS-drawn checkmark */
230
+ .task-list-item input[type='checkbox']:checked {
231
+ background: var(--color-secondary);
232
+ border-color: var(--color-secondary);
233
+ }
234
+
235
+ .task-list-item input[type='checkbox']:checked::after {
236
+ content: '';
237
+ width: 0.3em;
238
+ height: 0.55em;
239
+ margin-top: -0.1em;
240
+ border: solid #fff;
241
+ border-width: 0 0.16em 0.16em 0;
242
+ transform: rotate(45deg);
243
+ }
244
+
245
+ a {
246
+ color: var(--color-secondary);
247
+ text-decoration: none;
248
+ transition: color var(--transition-fast);
249
+ }
250
+
251
+ a:hover {
252
+ color: var(--color-accent);
253
+ }
254
+
255
+ /* ============================================
256
+ Layout
257
+ ============================================ */
258
+
259
+ .container {
260
+ width: 100%;
261
+ max-width: 1280px;
262
+ margin-left: auto;
263
+ margin-right: auto;
264
+ padding-left: var(--spacing-lg);
265
+ padding-right: var(--spacing-lg);
266
+ }
267
+
268
+ .container-narrow {
269
+ width: 100%;
270
+ max-width: 896px;
271
+ margin-left: auto;
272
+ margin-right: auto;
273
+ padding-left: var(--spacing-lg);
274
+ padding-right: var(--spacing-lg);
275
+ }
276
+
277
+ .section {
278
+ padding-top: var(--spacing-3xl);
279
+ padding-bottom: var(--spacing-3xl);
280
+ }
281
+
282
+ .grid {
283
+ display: grid;
284
+ gap: var(--spacing-xl);
285
+ }
286
+
287
+ .grid-2 {
288
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
289
+ }
290
+
291
+ .grid-3 {
292
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
293
+ }
294
+
295
+ .grid-4 {
296
+ grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
297
+ }
298
+
299
+ /* ============================================
300
+ Components
301
+ ============================================ */
302
+
303
+ /* IconPark / inline icon helper */
304
+ .icon-inline {
305
+ display: inline-flex;
306
+ align-items: center;
307
+ justify-content: center;
308
+ vertical-align: middle;
309
+ }
310
+ .icon-inline svg {
311
+ display: block;
312
+ }
313
+
314
+ /* Buttons */
315
+ .btn {
316
+ display: inline-flex;
317
+ align-items: center;
318
+ justify-content: center;
319
+ gap: var(--spacing-sm);
320
+ padding: var(--spacing-sm) var(--spacing-lg);
321
+ font-family: var(--font-body);
322
+ font-size: 0.875rem;
323
+ font-weight: 600;
324
+ line-height: 1;
325
+ text-align: center;
326
+ text-decoration: none;
327
+ border: none;
328
+ border-radius: var(--radius-md);
329
+ cursor: pointer;
330
+ transition: all var(--transition-base);
331
+ }
332
+
333
+ .btn-primary {
334
+ background: linear-gradient(
335
+ 135deg,
336
+ var(--color-accent) 0%,
337
+ var(--color-secondary) 100%
338
+ );
339
+ color: white;
340
+ }
341
+
342
+ .btn-primary:hover {
343
+ transform: translateY(-2px);
344
+ box-shadow: 0 10px 20px -5px rgba(0, 217, 255, 0.4);
345
+ }
346
+
347
+ .btn-secondary {
348
+ background-color: transparent;
349
+ color: var(--color-primary);
350
+ border: 2px solid var(--color-primary);
351
+ }
352
+
353
+ .btn-secondary:hover {
354
+ background-color: var(--color-primary);
355
+ color: white;
356
+ }
357
+
358
+ /* Cards */
359
+ .card {
360
+ background: var(--color-bg-alt);
361
+ border-radius: var(--radius-xl);
362
+ padding: var(--spacing-xl);
363
+ box-shadow: var(--shadow-md);
364
+ border: 1px solid var(--color-border);
365
+ transition: all var(--transition-base);
366
+ }
367
+
368
+ .card:hover {
369
+ transform: translateY(-4px);
370
+ box-shadow: var(--shadow-xl);
371
+ border-color: var(--color-secondary);
372
+ }
373
+
374
+ /* Badge */
375
+ .badge {
376
+ display: inline-flex;
377
+ align-items: center;
378
+ padding: var(--spacing-xs) var(--spacing-sm);
379
+ font-size: 0.75rem;
380
+ font-weight: 600;
381
+ line-height: 1;
382
+ border-radius: var(--radius-full);
383
+ background-color: var(--color-secondary);
384
+ color: white;
385
+ }
386
+
387
+ .badge-accent {
388
+ background-color: var(--color-accent);
389
+ }
390
+
391
+ .badge-muted {
392
+ background-color: var(--color-border);
393
+ color: var(--color-text-muted);
394
+ }
395
+
396
+ /* Divider */
397
+ .divider {
398
+ width: 100%;
399
+ height: 2px;
400
+ background: linear-gradient(
401
+ 90deg,
402
+ transparent,
403
+ var(--color-border),
404
+ transparent
405
+ );
406
+ margin: var(--spacing-2xl) 0;
407
+ }
408
+
409
+ /* ============================================
410
+ Animation Classes
411
+ ============================================ */
412
+
413
+ @keyframes fadeInUp {
414
+ from {
415
+ opacity: 0;
416
+ transform: translateY(20px);
417
+ }
418
+ to {
419
+ opacity: 1;
420
+ transform: translateY(0);
421
+ }
422
+ }
423
+
424
+ @keyframes fadeIn {
425
+ from {
426
+ opacity: 0;
427
+ }
428
+ to {
429
+ opacity: 1;
430
+ }
431
+ }
432
+
433
+ @keyframes slideInLeft {
434
+ from {
435
+ opacity: 0;
436
+ transform: translateX(-30px);
437
+ }
438
+ to {
439
+ opacity: 1;
440
+ transform: translateX(0);
441
+ }
442
+ }
443
+
444
+ @keyframes slideInRight {
445
+ from {
446
+ opacity: 0;
447
+ transform: translateX(30px);
448
+ }
449
+ to {
450
+ opacity: 1;
451
+ transform: translateX(0);
452
+ }
453
+ }
454
+
455
+ .animate-fade-in-up {
456
+ animation: fadeInUp 0.6s ease forwards;
457
+ }
458
+
459
+ .animate-fade-in {
460
+ animation: fadeIn 0.4s ease forwards;
461
+ }
462
+
463
+ .animate-slide-left {
464
+ animation: slideInLeft 0.5s ease forwards;
465
+ }
466
+
467
+ .animate-slide-right {
468
+ animation: slideInRight 0.5s ease forwards;
469
+ }
470
+
471
+ /* Stagger delays */
472
+ .delay-100 {
473
+ animation-delay: 0.1s;
474
+ }
475
+ .delay-200 {
476
+ animation-delay: 0.2s;
477
+ }
478
+ .delay-300 {
479
+ animation-delay: 0.3s;
480
+ }
481
+ .delay-400 {
482
+ animation-delay: 0.4s;
483
+ }
484
+ .delay-500 {
485
+ animation-delay: 0.5s;
486
+ }
487
+
488
+ /* ============================================
489
+ Page Transitions
490
+ ============================================ */
491
+
492
+ .page-enter-active,
493
+ .page-leave-active {
494
+ transition:
495
+ opacity 0.3s ease,
496
+ transform 0.3s ease;
497
+ }
498
+
499
+ .page-enter-from {
500
+ opacity: 0;
501
+ transform: translateY(10px);
502
+ }
503
+
504
+ .page-leave-to {
505
+ opacity: 0;
506
+ transform: translateY(-10px);
507
+ }
508
+
509
+ /* ============================================
510
+ Utility Classes
511
+ ============================================ */
512
+
513
+ .sr-only {
514
+ position: absolute;
515
+ width: 1px;
516
+ height: 1px;
517
+ padding: 0;
518
+ margin: -1px;
519
+ overflow: hidden;
520
+ clip: rect(0, 0, 0, 0);
521
+ white-space: nowrap;
522
+ border: 0;
523
+ }
524
+
525
+ .text-center {
526
+ text-align: center;
527
+ }
528
+ .text-left {
529
+ text-align: left;
530
+ }
531
+ .text-right {
532
+ text-align: right;
533
+ }
534
+
535
+ .mt-sm {
536
+ margin-top: var(--spacing-sm);
537
+ }
538
+ .mt-md {
539
+ margin-top: var(--spacing-md);
540
+ }
541
+ .mt-lg {
542
+ margin-top: var(--spacing-lg);
543
+ }
544
+ .mt-xl {
545
+ margin-top: var(--spacing-xl);
546
+ }
547
+
548
+ .mb-sm {
549
+ margin-bottom: var(--spacing-sm);
550
+ }
551
+ .mb-md {
552
+ margin-bottom: var(--spacing-md);
553
+ }
554
+ .mb-lg {
555
+ margin-bottom: var(--spacing-lg);
556
+ }
557
+ .mb-xl {
558
+ margin-bottom: var(--spacing-xl);
559
+ }
560
+
561
+ /* ============================================
562
+ Responsive Breakpoints
563
+ Mobile-first approach using CSS custom properties
564
+
565
+ Usage:
566
+ @media (min-width: var(--breakpoint-md)) { ... }
567
+ ============================================ */
568
+
569
+ /* Small Mobile (below 480px) - default styles apply */
570
+
571
+ /* Tablet (768px and up) */
572
+ @media (min-width: 768px) {
573
+ .section {
574
+ padding-top: var(--spacing-2xl);
575
+ padding-bottom: var(--spacing-2xl);
576
+ }
577
+
578
+ .container,
579
+ .container-narrow {
580
+ padding-left: var(--spacing-md);
581
+ padding-right: var(--spacing-md);
582
+ }
583
+ }
584
+
585
+ /* Desktop (1024px and up) */
586
+ @media (min-width: 1024px) {
587
+ .section {
588
+ padding-top: var(--spacing-3xl);
589
+ padding-bottom: var(--spacing-3xl);
590
+ }
591
+ }
592
+
593
+ /* ============================================
594
+ Reduced Motion - Accessibility
595
+ Respects user's preference for reduced motion
596
+ ============================================ */
597
+ @media (prefers-reduced-motion: reduce) {
598
+ *,
599
+ *::before,
600
+ *::after {
601
+ animation-duration: 0.01ms !important;
602
+ animation-iteration-count: 1 !important;
603
+ transition-duration: 0.01ms !important;
604
+ }
605
+
606
+ /* Specific overrides for common animations */
607
+ .carousel__track,
608
+ .hero__shape,
609
+ .about-shape,
610
+ .floating {
611
+ animation: none !important;
612
+ }
613
+
614
+ /* Keep hover transforms for accessibility but remove transitions */
615
+ .btn:hover,
616
+ .card:hover,
617
+ .member-card:hover {
618
+ transform: none !important;
619
+ }
620
+ }
621
+
622
+ /* ============================================
623
+ Markdown Code Blocks (ProsePre override)
624
+ Light theme: very light grey surface, subtle border
625
+ ============================================ */
626
+
627
+ /* Wrapper around a highlighted code block */
628
+ .code-block {
629
+ margin: var(--spacing-lg) 0;
630
+ border: 1px solid var(--color-border);
631
+ border-radius: var(--radius-lg);
632
+ overflow: hidden;
633
+ background: #f6f8fa;
634
+ box-shadow: var(--shadow-sm);
635
+ }
636
+
637
+ /* Header strip: language label + copy button */
638
+ .code-block__header {
639
+ display: flex;
640
+ align-items: center;
641
+ justify-content: space-between;
642
+ gap: var(--spacing-md);
643
+ padding: var(--spacing-xs) var(--spacing-md);
644
+ background: #eaeef2;
645
+ border-bottom: 1px solid var(--color-border);
646
+ }
647
+
648
+ .code-block__lang {
649
+ font-family: var(--font-body);
650
+ font-size: 0.75rem;
651
+ font-weight: 600;
652
+ letter-spacing: 0.04em;
653
+ text-transform: uppercase;
654
+ color: var(--color-text-muted);
655
+ }
656
+
657
+ .code-block__copy {
658
+ display: inline-flex;
659
+ align-items: center;
660
+ justify-content: center;
661
+ padding: 0.3rem;
662
+ color: var(--color-text-muted);
663
+ background: transparent;
664
+ border: none;
665
+ border-radius: var(--radius-sm);
666
+ cursor: pointer;
667
+ transition: all var(--transition-fast);
668
+ }
669
+
670
+ .code-block__copy:hover {
671
+ background: rgba(0, 0, 0, 0.06);
672
+ color: var(--color-text);
673
+ }
674
+
675
+ .code-block__copy.is-copied {
676
+ color: #1a7f37;
677
+ }
678
+
679
+ /* The <pre> emitted inside our wrapper: reset chrome, keep scrolling */
680
+ .code-block pre {
681
+ margin: 0;
682
+ padding: var(--spacing-md) var(--spacing-lg);
683
+ overflow-x: auto;
684
+ background: transparent;
685
+ font-size: 0.875rem;
686
+ line-height: 1.6;
687
+ -webkit-overflow-scrolling: touch;
688
+ }
689
+
690
+ .code-block pre code {
691
+ font-family: ui-monospace, 'SF Mono', 'Cascadia Code', 'Fira Code', Menlo, Consolas, monospace;
692
+ font-size: inherit;
693
+ color: var(--color-text);
694
+ background: none;
695
+ padding: 0;
696
+ display: block;
697
+ counter-reset: line;
698
+ }
699
+
700
+ .code-block pre code .line {
701
+ display: block;
702
+ }
703
+
704
+ /* Line-number gutter: rendered from a CSS counter so the digits are never
705
+ part of the copied text (manual selection skips ::before; the copy button
706
+ copies the raw source). Sticky so numbers stay pinned while a long line
707
+ scrolls horizontally, GitHub-style. */
708
+ .code-block pre code .line::before {
709
+ counter-increment: line;
710
+ content: counter(line);
711
+ position: sticky;
712
+ left: 0;
713
+ display: inline-block;
714
+ width: 2.5ch;
715
+ margin-right: var(--spacing-md);
716
+ padding-right: var(--spacing-sm);
717
+ text-align: right;
718
+ color: var(--color-text-muted);
719
+ background: #f6f8fa;
720
+ border-right: 1px solid var(--color-border);
721
+ user-select: none;
722
+ -webkit-user-select: none;
723
+ }
724
+
725
+ /* Shiki dual-theme: the parser writes both colors as CSS vars
726
+ (--shiki-default = github-light, --shiki-dusk = github-dark) rather than a
727
+ plain `color`. We render on a light surface, so use the light-theme var. */
728
+ .code-block pre code span {
729
+ color: var(--shiki-default, inherit);
730
+ }
731
+
732
+ /* ============================================
733
+ Markdown Tables (data tables, prominent borders)
734
+ ============================================ */
735
+
736
+ /* Markdown pipe tables always render a <thead>; raw-HTML layout tables (e.g.
737
+ the media-gallery image grid) do not, so :has(thead) styles only real data
738
+ tables and leaves layout tables borderless. */
739
+ table:has(thead) {
740
+ width: 100%;
741
+ border-collapse: collapse;
742
+ margin: var(--spacing-lg) 0;
743
+ border: 2px solid var(--color-text);
744
+ font-size: 0.9375rem;
745
+ }
746
+
747
+ table:has(thead) th,
748
+ table:has(thead) td {
749
+ border: 1px solid var(--color-text);
750
+ padding: var(--spacing-sm) var(--spacing-md);
751
+ text-align: left;
752
+ vertical-align: top;
753
+ }
754
+
755
+ table:has(thead) thead th {
756
+ background: var(--color-bg);
757
+ font-family: var(--font-display);
758
+ font-weight: 700;
759
+ color: var(--color-primary);
760
+ }
761
+
762
+ table:has(thead) tbody tr:nth-child(even) {
763
+ background: #f8fafc;
764
+ }
765
+
766
+ /* ============================================
767
+ KaTeX Math (rehype-katex output)
768
+ ============================================ */
769
+
770
+ /* Display math ($$...$$) can be wider than the column; allow it to scroll
771
+ horizontally instead of overflowing the layout. */
772
+ .katex-display {
773
+ overflow-x: auto;
774
+ overflow-y: hidden;
775
+ padding: var(--spacing-sm) 0;
776
+ margin: var(--spacing-md) 0;
777
+ }
778
+
779
+ /* Keep inline math from inflating line-height */
780
+ .katex {
781
+ font-size: 1.05em;
782
+ line-height: normal;
783
+ }
784
+