@jjlmoya/utils-tabletop 1.3.0

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 (121) hide show
  1. package/package.json +65 -0
  2. package/scripts/postinstall.mjs +27 -0
  3. package/src/category/TabletopCategorySEO.astro +14 -0
  4. package/src/category/i18n/de.ts +27 -0
  5. package/src/category/i18n/en.ts +27 -0
  6. package/src/category/i18n/es.ts +27 -0
  7. package/src/category/i18n/fr.ts +27 -0
  8. package/src/category/i18n/id.ts +27 -0
  9. package/src/category/i18n/it.ts +27 -0
  10. package/src/category/i18n/ja.ts +27 -0
  11. package/src/category/i18n/ko.ts +27 -0
  12. package/src/category/i18n/nl.ts +27 -0
  13. package/src/category/i18n/pl.ts +27 -0
  14. package/src/category/i18n/pt.ts +27 -0
  15. package/src/category/i18n/ru.ts +27 -0
  16. package/src/category/i18n/sv.ts +27 -0
  17. package/src/category/i18n/tr.ts +27 -0
  18. package/src/category/i18n/zh.ts +27 -0
  19. package/src/category/index.ts +27 -0
  20. package/src/components/PreviewNavSidebar.astro +116 -0
  21. package/src/components/PreviewToolbar.astro +143 -0
  22. package/src/data.ts +10 -0
  23. package/src/entries.ts +10 -0
  24. package/src/env.d.ts +5 -0
  25. package/src/index.ts +21 -0
  26. package/src/layouts/PreviewLayout.astro +117 -0
  27. package/src/pages/[locale]/[slug].astro +161 -0
  28. package/src/pages/[locale].astro +251 -0
  29. package/src/pages/index.astro +4 -0
  30. package/src/tests/faq_count.test.ts +18 -0
  31. package/src/tests/i18n_coverage.test.ts +36 -0
  32. package/src/tests/locale_completeness.test.ts +29 -0
  33. package/src/tests/mocks/astro_mock.js +2 -0
  34. package/src/tests/no_en_dash.test.ts +41 -0
  35. package/src/tests/no_h1_in_components.test.ts +48 -0
  36. package/src/tests/schemas_fulfillment.test.ts +23 -0
  37. package/src/tests/seo_length.test.ts +22 -0
  38. package/src/tests/shared-test-helpers.ts +56 -0
  39. package/src/tests/slug_language_code_format.test.ts +23 -0
  40. package/src/tests/slug_uniqueness.test.ts +81 -0
  41. package/src/tests/title_quality.test.ts +55 -0
  42. package/src/tests/tool_exports.test.ts +34 -0
  43. package/src/tests/tool_validation.test.ts +16 -0
  44. package/src/tool/board-game-timer/bibliography.astro +16 -0
  45. package/src/tool/board-game-timer/bibliography.ts +12 -0
  46. package/src/tool/board-game-timer/board-game-timer.css +1615 -0
  47. package/src/tool/board-game-timer/client.ts +17 -0
  48. package/src/tool/board-game-timer/component.astro +22 -0
  49. package/src/tool/board-game-timer/components/DuelTimer.astro +75 -0
  50. package/src/tool/board-game-timer/components/MultiplayerTimer.astro +58 -0
  51. package/src/tool/board-game-timer/components/SetupPanel.astro +155 -0
  52. package/src/tool/board-game-timer/components/StatsModal.astro +52 -0
  53. package/src/tool/board-game-timer/entry.ts +76 -0
  54. package/src/tool/board-game-timer/i18n/de.ts +303 -0
  55. package/src/tool/board-game-timer/i18n/en.ts +304 -0
  56. package/src/tool/board-game-timer/i18n/es.ts +303 -0
  57. package/src/tool/board-game-timer/i18n/fr.ts +303 -0
  58. package/src/tool/board-game-timer/i18n/id.ts +303 -0
  59. package/src/tool/board-game-timer/i18n/it.ts +303 -0
  60. package/src/tool/board-game-timer/i18n/ja.ts +306 -0
  61. package/src/tool/board-game-timer/i18n/ko.ts +303 -0
  62. package/src/tool/board-game-timer/i18n/nl.ts +303 -0
  63. package/src/tool/board-game-timer/i18n/pl.ts +303 -0
  64. package/src/tool/board-game-timer/i18n/pt.ts +303 -0
  65. package/src/tool/board-game-timer/i18n/ru.ts +303 -0
  66. package/src/tool/board-game-timer/i18n/sv.ts +303 -0
  67. package/src/tool/board-game-timer/i18n/tr.ts +303 -0
  68. package/src/tool/board-game-timer/i18n/zh.ts +303 -0
  69. package/src/tool/board-game-timer/index.ts +9 -0
  70. package/src/tool/board-game-timer/logic.test.ts +282 -0
  71. package/src/tool/board-game-timer/logic.ts +6 -0
  72. package/src/tool/board-game-timer/modules/ColorHelper.ts +26 -0
  73. package/src/tool/board-game-timer/modules/DuelViewManager.ts +120 -0
  74. package/src/tool/board-game-timer/modules/FormatHelper.ts +12 -0
  75. package/src/tool/board-game-timer/modules/GameRunner.ts +136 -0
  76. package/src/tool/board-game-timer/modules/GameState.ts +48 -0
  77. package/src/tool/board-game-timer/modules/MultiplayerViewManager.ts +163 -0
  78. package/src/tool/board-game-timer/modules/SetupPanelManager.ts +209 -0
  79. package/src/tool/board-game-timer/modules/SoundManager.ts +109 -0
  80. package/src/tool/board-game-timer/modules/SpeechManager.ts +1 -0
  81. package/src/tool/board-game-timer/modules/StatsManager.ts +87 -0
  82. package/src/tool/board-game-timer/modules/StatsModalManager.ts +74 -0
  83. package/src/tool/board-game-timer/modules/TimerEngine.ts +175 -0
  84. package/src/tool/board-game-timer/modules/TimerEngineBase.ts +49 -0
  85. package/src/tool/board-game-timer/modules/TimerEngineClock.ts +127 -0
  86. package/src/tool/board-game-timer/modules/TimerStateHelper.ts +55 -0
  87. package/src/tool/board-game-timer/modules/particles.ts +108 -0
  88. package/src/tool/board-game-timer/seo.astro +16 -0
  89. package/src/tool/board-game-timer/types.ts +97 -0
  90. package/src/tool/dice-roller-simulator/bibliography.astro +16 -0
  91. package/src/tool/dice-roller-simulator/bibliography.ts +12 -0
  92. package/src/tool/dice-roller-simulator/client.ts +273 -0
  93. package/src/tool/dice-roller-simulator/component.astro +75 -0
  94. package/src/tool/dice-roller-simulator/components/DiceGrid.astro +55 -0
  95. package/src/tool/dice-roller-simulator/components/RollHistorySection.astro +26 -0
  96. package/src/tool/dice-roller-simulator/components/RollResultBanner.astro +10 -0
  97. package/src/tool/dice-roller-simulator/components/StatsPanel.astro +36 -0
  98. package/src/tool/dice-roller-simulator/dice-roller-simulator.css +1319 -0
  99. package/src/tool/dice-roller-simulator/entry.ts +39 -0
  100. package/src/tool/dice-roller-simulator/i18n/de.ts +305 -0
  101. package/src/tool/dice-roller-simulator/i18n/en.ts +305 -0
  102. package/src/tool/dice-roller-simulator/i18n/es.ts +305 -0
  103. package/src/tool/dice-roller-simulator/i18n/fr.ts +305 -0
  104. package/src/tool/dice-roller-simulator/i18n/id.ts +305 -0
  105. package/src/tool/dice-roller-simulator/i18n/it.ts +305 -0
  106. package/src/tool/dice-roller-simulator/i18n/ja.ts +305 -0
  107. package/src/tool/dice-roller-simulator/i18n/ko.ts +305 -0
  108. package/src/tool/dice-roller-simulator/i18n/nl.ts +305 -0
  109. package/src/tool/dice-roller-simulator/i18n/pl.ts +305 -0
  110. package/src/tool/dice-roller-simulator/i18n/pt.ts +305 -0
  111. package/src/tool/dice-roller-simulator/i18n/ru.ts +305 -0
  112. package/src/tool/dice-roller-simulator/i18n/sv.ts +305 -0
  113. package/src/tool/dice-roller-simulator/i18n/tr.ts +305 -0
  114. package/src/tool/dice-roller-simulator/i18n/zh.ts +305 -0
  115. package/src/tool/dice-roller-simulator/index.ts +9 -0
  116. package/src/tool/dice-roller-simulator/modules/chart.ts +32 -0
  117. package/src/tool/dice-roller-simulator/modules/history.ts +87 -0
  118. package/src/tool/dice-roller-simulator/modules/particles.ts +22 -0
  119. package/src/tool/dice-roller-simulator/seo.astro +16 -0
  120. package/src/tools.ts +9 -0
  121. package/src/types.ts +70 -0
@@ -0,0 +1,1319 @@
1
+ :root {
2
+ --color-white: #fff;
3
+ --color-d4: #f43f5e;
4
+ --color-d6: #8b5cf6;
5
+ --color-d8: #3b82f6;
6
+ --color-d10: #10b981;
7
+ --color-d12: #f97316;
8
+ --color-d20: #ef4444;
9
+ --color-d100: #64748b;
10
+ --color-crit: #facc15;
11
+ --color-crit-glow: #f59e0b;
12
+ --color-fumble: #ef4444;
13
+ --color-fumble-glow: #991b1b;
14
+ }
15
+
16
+ .tabletop-gaming-dashboard {
17
+ background: var(--bg-surface);
18
+ border: 1px solid var(--border-color);
19
+ border-radius: 1.25rem;
20
+ padding: 1.5rem;
21
+ color: var(--text-base);
22
+ display: flex;
23
+ flex-direction: column;
24
+ gap: 2rem;
25
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05);
26
+ }
27
+
28
+ .forge-and-tray-grid {
29
+ display: grid;
30
+ grid-template-columns: 1fr 1.1fr;
31
+ gap: 2rem;
32
+ align-items: stretch;
33
+ }
34
+
35
+ @media (max-width: 820px) {
36
+ .forge-and-tray-grid {
37
+ grid-template-columns: 1fr;
38
+ }
39
+ }
40
+
41
+ .dice-forge-panel {
42
+ display: flex;
43
+ flex-direction: column;
44
+ gap: 1.25rem;
45
+ background: var(--bg-page);
46
+ border: 1px solid var(--border-color);
47
+ border-radius: 1rem;
48
+ padding: 1.5rem;
49
+ box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.02);
50
+ }
51
+
52
+ .panel-header {
53
+ display: flex;
54
+ justify-content: space-between;
55
+ align-items: center;
56
+ border-bottom: 2px solid var(--border-color);
57
+ padding-bottom: 0.75rem;
58
+ margin-bottom: 0.5rem;
59
+ }
60
+
61
+ .panel-header h3 {
62
+ font-size: 1.25rem;
63
+ font-weight: 900;
64
+ text-transform: uppercase;
65
+ letter-spacing: 0.05em;
66
+ color: var(--accent);
67
+ margin: 0;
68
+ }
69
+
70
+ .btn-text-action {
71
+ background: none;
72
+ border: none;
73
+ color: var(--text-muted);
74
+ font-size: 0.9rem;
75
+ font-weight: 800;
76
+ cursor: pointer;
77
+ transition: all 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
78
+ text-transform: uppercase;
79
+ }
80
+
81
+ .btn-text-action:hover {
82
+ color: var(--accent);
83
+ transform: scale(1.05) rotate(-3deg);
84
+ }
85
+
86
+ .dice-selectors-column {
87
+ display: flex;
88
+ flex-direction: column;
89
+ gap: 0.75rem;
90
+ }
91
+
92
+ .die-control-row {
93
+ display: flex;
94
+ align-items: center;
95
+ gap: 0.75rem;
96
+ background: var(--bg-surface);
97
+ border: 1px solid var(--border-color);
98
+ border-radius: 0.75rem;
99
+ padding: 0.5rem;
100
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.02);
101
+ transition: all 0.25s cubic-bezier(0.175, 0.885, 0.32, 1.275);
102
+ position: relative;
103
+ }
104
+
105
+ .die-control-row:hover {
106
+ border-color: var(--accent);
107
+ box-shadow: 0 8px 20px rgba(244, 63, 94, 0.1);
108
+ transform: translateY(-3px) scale(1.02);
109
+ }
110
+
111
+ .die-control-row:hover .die-visual-icon svg {
112
+ animation: icon-tumble 0.6s ease-in-out;
113
+ }
114
+
115
+ @keyframes icon-tumble {
116
+ 0% { transform: rotate(0deg) scale(1); }
117
+ 50% { transform: rotate(180deg) scale(1.2); }
118
+ 100% { transform: rotate(360deg) scale(1); }
119
+ }
120
+
121
+ .die-control-row:active {
122
+ transform: scale(0.98);
123
+ }
124
+
125
+ .die-adjust-btn {
126
+ width: 3rem;
127
+ height: 3rem;
128
+ border-radius: 0.5rem;
129
+ border: 1px solid var(--border-color);
130
+ background: var(--bg-page);
131
+ color: var(--text-base);
132
+ font-size: 1.5rem;
133
+ font-weight: 800;
134
+ cursor: pointer;
135
+ display: flex;
136
+ align-items: center;
137
+ justify-content: center;
138
+ transition: all 0.25s cubic-bezier(0.175, 0.885, 0.32, 1.275);
139
+ }
140
+
141
+ .die-adjust-btn:hover:not(:disabled) {
142
+ background: var(--accent);
143
+ color: var(--color-white);
144
+ border-color: var(--accent);
145
+ }
146
+
147
+ .inc-btn:hover:not(:disabled) {
148
+ transform: scale(1.15) rotate(90deg);
149
+ }
150
+
151
+ .dec-btn:hover:not(:disabled) {
152
+ transform: scale(1.15) rotate(-90deg);
153
+ }
154
+
155
+ .die-adjust-btn:disabled {
156
+ opacity: 0.25;
157
+ cursor: not-allowed;
158
+ }
159
+
160
+ .die-main-button {
161
+ flex: 1;
162
+ display: flex;
163
+ align-items: center;
164
+ justify-content: center;
165
+ gap: 0.75rem;
166
+ background: var(--bg-page);
167
+ border: 1px solid var(--border-color);
168
+ border-radius: 0.5rem;
169
+ padding: 0.5rem 1rem;
170
+ cursor: pointer;
171
+ transition: all 0.2s ease;
172
+ height: 3rem;
173
+ position: relative;
174
+ user-select: none;
175
+ }
176
+
177
+ .die-main-button:hover {
178
+ border-color: var(--accent);
179
+ background: var(--bg-surface);
180
+ }
181
+
182
+ .die-visual-icon {
183
+ width: 2.25rem;
184
+ height: 2.25rem;
185
+ border-radius: 0.375rem;
186
+ display: flex;
187
+ align-items: center;
188
+ justify-content: center;
189
+ color: var(--color-white);
190
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15);
191
+ position: relative;
192
+ }
193
+
194
+ .die-counter-badge {
195
+ position: absolute;
196
+ top: -0.65rem;
197
+ right: -0.65rem;
198
+ background: var(--accent);
199
+ color: var(--color-white);
200
+ font-size: 0.85rem;
201
+ font-weight: 900;
202
+ width: 1.5rem;
203
+ height: 1.5rem;
204
+ border-radius: 50%;
205
+ display: flex;
206
+ align-items: center;
207
+ justify-content: center;
208
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
209
+ border: 2px solid var(--bg-surface);
210
+ }
211
+
212
+ .die-counter-badge:not(.hidden) {
213
+ animation: badge-bounce 2s infinite ease-in-out;
214
+ }
215
+
216
+ @keyframes badge-bounce {
217
+ 0%, 100% { transform: scale(1) translateY(0); }
218
+ 50% { transform: scale(1.1) translateY(-3px); }
219
+ }
220
+
221
+ .die-counter-badge.hidden {
222
+ display: none;
223
+ }
224
+
225
+ .die-name-label {
226
+ font-weight: 900;
227
+ font-size: 1.15rem;
228
+ color: var(--text-base);
229
+ transition: color 0.2s ease;
230
+ }
231
+
232
+ .die-control-row[data-die-type="D4"] .die-visual-icon { background: linear-gradient(135deg, #ec4899, var(--color-d4)); }
233
+ .die-control-row[data-die-type="D4"] .die-name-label { color: var(--color-d4); }
234
+
235
+ .die-control-row[data-die-type="D6"] .die-visual-icon { background: linear-gradient(135deg, #a855f7, #6366f1); }
236
+ .die-control-row[data-die-type="D6"] .die-name-label { color: var(--color-d6); }
237
+
238
+ .die-control-row[data-die-type="D8"] .die-visual-icon { background: linear-gradient(135deg, var(--color-d8), #06b6d4); }
239
+ .die-control-row[data-die-type="D8"] .die-name-label { color: var(--color-d8); }
240
+
241
+ .die-control-row[data-die-type="D10"] .die-visual-icon { background: linear-gradient(135deg, #14b8a6, var(--color-d10)); }
242
+ .die-control-row[data-die-type="D10"] .die-name-label { color: var(--color-d10); }
243
+
244
+ .die-control-row[data-die-type="D12"] .die-visual-icon { background: linear-gradient(135deg, #eab308, var(--color-d12)); }
245
+ .die-control-row[data-die-type="D12"] .die-name-label { color: var(--color-d12); }
246
+
247
+ .die-control-row[data-die-type="D20"] .die-visual-icon { background: linear-gradient(135deg, var(--color-d20), #ec4899); }
248
+ .die-control-row[data-die-type="D20"] .die-name-label { color: var(--color-d20); }
249
+
250
+ .die-control-row[data-die-type="D100"] .die-visual-icon { background: linear-gradient(135deg, var(--color-d100), #475569); }
251
+ .die-control-row[data-die-type="D100"] .die-name-label { color: var(--color-d100); }
252
+
253
+ .modifier-row-panel {
254
+ border-top: 2px solid var(--border-color);
255
+ padding-top: 1rem;
256
+ margin-top: 0.5rem;
257
+ }
258
+
259
+ .modifier-box {
260
+ display: flex;
261
+ align-items: center;
262
+ justify-content: space-between;
263
+ gap: 1.5rem;
264
+ }
265
+
266
+ .config-label {
267
+ font-size: 0.9rem;
268
+ color: var(--text-muted);
269
+ font-weight: 800;
270
+ text-transform: uppercase;
271
+ letter-spacing: 0.05em;
272
+ }
273
+
274
+ .modifier-input-wrapper {
275
+ display: flex;
276
+ align-items: center;
277
+ background: var(--bg-surface);
278
+ border: 1px solid var(--border-color);
279
+ border-radius: 0.5rem;
280
+ overflow: hidden;
281
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.02);
282
+ }
283
+
284
+ .mod-adjust {
285
+ width: 3rem;
286
+ height: 3rem;
287
+ background: none;
288
+ border: none;
289
+ color: var(--text-base);
290
+ font-size: 1.5rem;
291
+ font-weight: 800;
292
+ cursor: pointer;
293
+ transition: all 0.2s ease;
294
+ }
295
+
296
+ .mod-adjust:hover {
297
+ background: var(--border-color);
298
+ }
299
+
300
+ .mod-val-input {
301
+ width: 3rem;
302
+ background: none;
303
+ border: none;
304
+ color: var(--text-base);
305
+ font-weight: 900;
306
+ text-align: center;
307
+ font-size: 1.35rem;
308
+ outline: none;
309
+ display: inline-block;
310
+ transition: transform 0.15s ease;
311
+ -moz-appearance: textfield;
312
+ }
313
+
314
+ .mod-val-input::-webkit-outer-spin-button,
315
+ .mod-val-input::-webkit-inner-spin-button {
316
+ -webkit-appearance: none;
317
+ margin: 0;
318
+ }
319
+
320
+ .mod-val-input.bounce-effect {
321
+ animation: mod-bounce 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
322
+ }
323
+
324
+ @keyframes mod-bounce {
325
+ 0%, 100% {
326
+ transform: scale(1);
327
+ }
328
+ 50% {
329
+ transform: scale(1.3);
330
+ color: var(--accent);
331
+ }
332
+ }
333
+
334
+ .dashboard-center {
335
+ display: flex;
336
+ flex-direction: column;
337
+ gap: 1.5rem;
338
+ height: 100%;
339
+ }
340
+
341
+ .rolling-tray-container {
342
+ flex: 1;
343
+ display: flex;
344
+ flex-direction: column;
345
+ }
346
+
347
+ .tray-rim {
348
+ flex: 1;
349
+ display: flex;
350
+ flex-direction: column;
351
+ background: linear-gradient(135deg, var(--border-color), var(--bg-surface));
352
+ padding: 0.75rem;
353
+ border-radius: 1.25rem;
354
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.06), inset 0 1px 3px rgba(255, 255, 255, 0.2);
355
+ transition: border-color 0.3s ease, box-shadow 0.3s ease;
356
+ animation: rim-glow-loop 4s infinite ease-in-out;
357
+ }
358
+
359
+ .tray-rim.felt-impact {
360
+ animation: arena-shake 0.25s cubic-bezier(.36,.07,.19,.97) both;
361
+ }
362
+
363
+ @keyframes arena-shake {
364
+ 10%, 90% {
365
+ transform: translate3d(-2px, 1px, 0);
366
+ }
367
+ 20%, 80% {
368
+ transform: translate3d(3px, -2px, 0);
369
+ }
370
+ 30%, 50%, 70% {
371
+ transform: translate3d(-5px, 3px, 0) scale(0.98);
372
+ }
373
+ 40%, 60% {
374
+ transform: translate3d(5px, -3px, 0) scale(1.02);
375
+ }
376
+ }
377
+
378
+ @keyframes rim-glow-loop {
379
+ 0%, 100% {
380
+ border: 1px solid var(--border-color);
381
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.06);
382
+ }
383
+ 50% {
384
+ border: 1px solid var(--accent);
385
+ box-shadow: 0 8px 30px rgba(244, 63, 94, 0.15);
386
+ }
387
+ }
388
+
389
+ .tray-felt {
390
+ flex: 1;
391
+ background: radial-gradient(circle, rgba(244, 63, 94, 0.05) 0%, rgba(139, 92, 246, 0.02) 60%, var(--bg-page) 100%);
392
+ border-radius: 0.85rem;
393
+ display: flex;
394
+ align-items: center;
395
+ justify-content: center;
396
+ padding: 1.5rem;
397
+ box-shadow: inset 0 3px 12px rgba(0, 0, 0, 0.08);
398
+ border: 1px solid var(--border-color);
399
+ position: relative;
400
+ min-height: 380px;
401
+ animation: portal-breathe 8s infinite ease-in-out alternate;
402
+ }
403
+
404
+ @keyframes portal-breathe {
405
+ 0% {
406
+ filter: hue-rotate(0deg);
407
+ }
408
+ 100% {
409
+ filter: hue-rotate(45deg) saturate(1.1);
410
+ }
411
+ }
412
+
413
+ .felt-placeholder {
414
+ position: absolute;
415
+ top: 50%;
416
+ left: 50%;
417
+ transform: translate(-50%, -50%);
418
+ text-align: center;
419
+ pointer-events: none;
420
+ display: flex;
421
+ flex-direction: column;
422
+ align-items: center;
423
+ justify-content: center;
424
+ width: 100%;
425
+ }
426
+
427
+ .felt-crest-svg {
428
+ width: 6.5rem;
429
+ height: 6.5rem;
430
+ color: var(--accent);
431
+ opacity: 0.35;
432
+ margin-bottom: 0.75rem;
433
+ display: block;
434
+ animation: magical-spin 12s infinite linear, magical-float 3s infinite ease-in-out;
435
+ }
436
+
437
+ @keyframes magical-spin {
438
+ 0% {
439
+ transform: rotate(0deg);
440
+ }
441
+ 100% {
442
+ transform: rotate(360deg);
443
+ }
444
+ }
445
+
446
+ @keyframes magical-float {
447
+ 0%, 100% {
448
+ transform: translateY(0) scale(0.96);
449
+ filter: drop-shadow(0 0 2px rgba(244, 63, 94, 0.15));
450
+ }
451
+ 50% {
452
+ transform: translateY(-8px) scale(1.04);
453
+ filter: drop-shadow(0 0 12px rgba(244, 63, 94, 0.3));
454
+ }
455
+ }
456
+
457
+ .felt-hint-text {
458
+ font-size: 0.9rem;
459
+ font-weight: 800;
460
+ text-transform: uppercase;
461
+ letter-spacing: 0.05em;
462
+ color: var(--text-muted);
463
+ margin: 0;
464
+ }
465
+
466
+ .felt-dice-container {
467
+ display: flex;
468
+ flex-wrap: wrap;
469
+ gap: 1.25rem;
470
+ justify-content: center;
471
+ align-items: center;
472
+ width: 100%;
473
+ }
474
+
475
+ .visual-die {
476
+ width: 4rem;
477
+ height: 4rem;
478
+ display: flex;
479
+ align-items: center;
480
+ justify-content: center;
481
+ font-size: 1.6rem;
482
+ font-weight: 900;
483
+ color: var(--color-white);
484
+ text-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
485
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.2);
486
+ animation: die-tumble 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.15);
487
+ position: relative;
488
+ user-select: none;
489
+ }
490
+
491
+ .visual-die.rolling-pulse {
492
+ animation: die-rolling-shake 0.12s infinite ease-in-out, die-rolling-color 0.4s infinite alternate;
493
+ }
494
+
495
+ @keyframes die-rolling-shake {
496
+ 0% { transform: translate(1px, 1px) rotate(0deg) scale(1.05); }
497
+ 20% { transform: translate(-2px, -1px) rotate(-1deg); }
498
+ 40% { transform: translate(-3px, 1px) rotate(1deg); }
499
+ 60% { transform: translate(1px, -2px) rotate(-1deg); }
500
+ 80% { transform: translate(-1px, 2px) rotate(0deg); }
501
+ 100% { transform: translate(1px, -1px) rotate(1deg) scale(1.05); }
502
+ }
503
+
504
+ @keyframes die-rolling-color {
505
+ 0% { filter: hue-rotate(0deg) brightness(1.1); }
506
+ 100% { filter: hue-rotate(120deg) brightness(1.3); }
507
+ }
508
+
509
+ @keyframes die-tumble {
510
+ 0% {
511
+ transform: scale(0.3) rotate(0deg);
512
+ opacity: 0;
513
+ }
514
+ 100% {
515
+ transform: scale(1) rotate(360deg);
516
+ opacity: 1;
517
+ }
518
+ }
519
+
520
+ .visual-die[data-die-type="d4"] {
521
+ background: linear-gradient(135deg, #ec4899, #f43f5e);
522
+ clip-path: polygon(50% 5%, 5% 85%, 95% 85%);
523
+ padding-top: 0.75rem;
524
+ }
525
+
526
+ .visual-die[data-die-type="d6"] {
527
+ background: linear-gradient(135deg, #a855f7, #6366f1);
528
+ border-radius: 0.75rem;
529
+ }
530
+
531
+ .visual-die[data-die-type="d8"] {
532
+ background: linear-gradient(135deg, #3b82f6, #06b6d4);
533
+ clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
534
+ }
535
+
536
+ .visual-die[data-die-type="d10"] {
537
+ background: linear-gradient(135deg, #14b8a6, #10b981);
538
+ clip-path: polygon(50% 0%, 90% 35%, 50% 100%, 10% 35%);
539
+ }
540
+
541
+ .visual-die[data-die-type="d12"] {
542
+ background: linear-gradient(135deg, #eab308, #f97316);
543
+ clip-path: polygon(50% 0%, 95% 32%, 78% 85%, 22% 85%, 5% 32%);
544
+ }
545
+
546
+ .visual-die[data-die-type="d20"] {
547
+ background: linear-gradient(135deg, #ef4444, #ec4899);
548
+ clip-path: polygon(30% 0%, 70% 0%, 100% 30%, 100% 70%, 70% 100%, 30% 100%, 0% 70%, 0% 30%);
549
+ }
550
+
551
+ .visual-die[data-die-type="d100"] {
552
+ background: linear-gradient(135deg, #64748b, #475569);
553
+ border-radius: 50%;
554
+ }
555
+
556
+ .btn-roll-hero {
557
+ height: 4rem;
558
+ border-radius: 0.75rem;
559
+ border: none;
560
+ background: var(--accent);
561
+ color: var(--color-white);
562
+ font-size: 1.4rem;
563
+ font-weight: 900;
564
+ cursor: pointer;
565
+ transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
566
+ width: 100%;
567
+ position: relative;
568
+ overflow: hidden;
569
+ }
570
+
571
+ .btn-roll-hero::before {
572
+ content: '';
573
+ position: absolute;
574
+ top: 0;
575
+ left: -150%;
576
+ width: 50%;
577
+ height: 100%;
578
+ background: linear-gradient(
579
+ to right,
580
+ rgba(255, 255, 255, 0) 0%,
581
+ rgba(255, 255, 255, 0.3) 50%,
582
+ rgba(255, 255, 255, 0) 100%
583
+ );
584
+ transform: skewX(-25deg);
585
+ transition: none;
586
+ }
587
+
588
+ .btn-roll-hero:not(:disabled):hover::before {
589
+ animation: shine-sweep 1.2s infinite ease-in-out;
590
+ }
591
+
592
+ @keyframes shine-sweep {
593
+ 0% {
594
+ left: -150%;
595
+ }
596
+ 100% {
597
+ left: 150%;
598
+ }
599
+ }
600
+
601
+ .btn-roll-hero:not(:disabled) {
602
+ animation: roll-btn-pulse 2.5s infinite ease-in-out;
603
+ }
604
+
605
+ @keyframes roll-btn-pulse {
606
+ 0%, 100% {
607
+ box-shadow: 0 4px 15px rgba(244, 63, 94, 0.3), 0 0 0 0 rgba(244, 63, 94, 0.15);
608
+ transform: scale(1);
609
+ }
610
+ 50% {
611
+ box-shadow: 0 8px 25px rgba(244, 63, 94, 0.6), 0 0 0 8px rgba(244, 63, 94, 0);
612
+ transform: scale(1.02);
613
+ }
614
+ }
615
+
616
+ .btn-roll-hero:hover:not(:disabled) {
617
+ opacity: 0.95;
618
+ transform: translateY(-2px) scale(1.03);
619
+ }
620
+
621
+ .btn-roll-hero:active:not(:disabled) {
622
+ transform: translateY(0) scale(0.98);
623
+ }
624
+
625
+ .btn-roll-hero:disabled {
626
+ opacity: 0.35;
627
+ cursor: not-allowed;
628
+ box-shadow: none;
629
+ }
630
+
631
+ .floating-roll-pop {
632
+ position: absolute;
633
+ top: 50%;
634
+ left: 50%;
635
+ transform: translate(-50%, -50%);
636
+ font-size: 4.5rem;
637
+ font-weight: 900;
638
+ color: var(--accent);
639
+ text-shadow: 0 0 15px rgba(244, 63, 94, 0.8), 0 0 35px rgba(139, 92, 246, 0.6);
640
+ pointer-events: none;
641
+ z-index: 10;
642
+ animation: float-and-fade-pop 1s cubic-bezier(0.25, 1, 0.5, 1) forwards;
643
+ }
644
+
645
+ @keyframes float-and-fade-pop {
646
+ 0% {
647
+ transform: translate(-50%, -20%) scale(0.4);
648
+ opacity: 0;
649
+ }
650
+ 20% {
651
+ transform: translate(-50%, -50%) scale(1.3);
652
+ opacity: 1;
653
+ }
654
+ 100% {
655
+ transform: translate(-50%, -110%) scale(1);
656
+ opacity: 0;
657
+ }
658
+ }
659
+
660
+ .tabletop-extra-tabs {
661
+ background: var(--bg-page);
662
+ border: 1px solid var(--border-color);
663
+ border-radius: 1rem;
664
+ padding: 1.25rem;
665
+ transition: all 0.25s ease;
666
+ }
667
+
668
+ .tabletop-extra-tabs:hover {
669
+ border-color: var(--accent);
670
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.02);
671
+ }
672
+
673
+ .tabs-nav {
674
+ display: flex;
675
+ gap: 1.5rem;
676
+ border-bottom: 2px solid var(--border-color);
677
+ margin-bottom: 1.25rem;
678
+ padding-bottom: 0.5rem;
679
+ }
680
+
681
+ .extra-tab-btn {
682
+ background: none;
683
+ border-bottom: 3px solid transparent;
684
+ color: var(--text-muted);
685
+ font-weight: 800;
686
+ font-size: 1.05rem;
687
+ padding: 0.5rem 1.25rem;
688
+ cursor: pointer;
689
+ transition: all 0.25s cubic-bezier(0.175, 0.885, 0.32, 1.275);
690
+ text-transform: uppercase;
691
+ border-radius: 99px;
692
+ border: 1px solid transparent;
693
+ }
694
+
695
+ .extra-tab-btn:hover {
696
+ color: var(--text-base);
697
+ transform: translateY(-1px);
698
+ }
699
+
700
+ .extra-tab-btn.active {
701
+ background: var(--accent);
702
+ color: var(--color-white);
703
+ border-color: var(--accent);
704
+ box-shadow: 0 4px 12px rgba(244, 63, 94, 0.15);
705
+ }
706
+
707
+ .extra-tab-pane {
708
+ display: none;
709
+ }
710
+
711
+ .extra-tab-pane.active {
712
+ display: block;
713
+ animation: pane-fade-in 0.3s ease;
714
+ }
715
+
716
+ @keyframes pane-fade-in {
717
+ 0% {
718
+ opacity: 0;
719
+ transform: translateY(4px);
720
+ }
721
+ 100% {
722
+ opacity: 1;
723
+ transform: translateY(0);
724
+ }
725
+ }
726
+
727
+ .stats-glow-grid {
728
+ display: grid;
729
+ grid-template-columns: repeat(3, 1fr);
730
+ gap: 1.25rem;
731
+ margin-bottom: 1.5rem;
732
+ }
733
+
734
+ .stat-glass-card {
735
+ background: var(--bg-surface);
736
+ border: 1px solid var(--border-color);
737
+ border-radius: 0.75rem;
738
+ padding: 1rem;
739
+ display: flex;
740
+ flex-direction: column;
741
+ align-items: center;
742
+ box-shadow: 0 2px 6px rgba(0,0,0,0.01);
743
+ transition: all 0.25s cubic-bezier(0.175, 0.885, 0.32, 1.275);
744
+ }
745
+
746
+ .stat-glass-card:hover {
747
+ transform: translateY(-4px) scale(1.04);
748
+ border-color: var(--accent);
749
+ box-shadow: 0 6px 18px rgba(0, 0, 0, 0.04);
750
+ }
751
+
752
+ .stat-card-title {
753
+ font-size: 0.8rem;
754
+ color: var(--text-muted);
755
+ text-transform: uppercase;
756
+ font-weight: 800;
757
+ margin-bottom: 0.35rem;
758
+ letter-spacing: 0.05em;
759
+ }
760
+
761
+ .stat-card-number {
762
+ font-size: 1.5rem;
763
+ font-weight: 900;
764
+ color: var(--text-base);
765
+ display: inline-block;
766
+ transition: transform 0.15s ease;
767
+ }
768
+
769
+ .stat-card-number.pulse-value {
770
+ animation: val-pop 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
771
+ }
772
+
773
+ @keyframes val-pop {
774
+ 0% {
775
+ transform: scale(1);
776
+ color: var(--accent);
777
+ }
778
+ 50% {
779
+ transform: scale(1.35);
780
+ color: var(--color-d10);
781
+ }
782
+ 100% {
783
+ transform: scale(1);
784
+ }
785
+ }
786
+
787
+ .css-chart-viewport {
788
+ height: 140px;
789
+ display: flex;
790
+ align-items: flex-end;
791
+ border-bottom: 2px solid var(--border-color);
792
+ }
793
+
794
+ .distribution-bars-container {
795
+ display: flex;
796
+ align-items: flex-end;
797
+ justify-content: space-around;
798
+ width: 100%;
799
+ height: 100%;
800
+ gap: 0.35rem;
801
+ }
802
+
803
+ .chart-empty-state {
804
+ width: 100%;
805
+ height: 100%;
806
+ display: flex;
807
+ flex-direction: column;
808
+ align-items: center;
809
+ justify-content: center;
810
+ color: var(--text-muted);
811
+ font-size: 0.95rem;
812
+ font-weight: 700;
813
+ gap: 0.75rem;
814
+ align-self: stretch;
815
+ border: 1px dashed var(--border-color);
816
+ border-radius: 0.75rem;
817
+ background: rgba(120, 120, 120, 0.02);
818
+ margin-bottom: 0.5rem;
819
+ }
820
+
821
+ .chart-empty-state::before {
822
+ content: '';
823
+ width: 2.25rem;
824
+ height: 2.25rem;
825
+ background: linear-gradient(180deg, transparent 0%, var(--accent) 100%);
826
+ clip-path: polygon(0% 100%, 0% 60%, 20% 60%, 20% 100%, 40% 100%, 40% 30%, 60% 30%, 60% 100%, 80% 100%, 80% 80%, 100% 80%, 100% 100%);
827
+ opacity: 0.35;
828
+ filter: drop-shadow(0 0 4px rgba(244, 63, 94, 0.4));
829
+ animation: magical-float 3s infinite ease-in-out;
830
+ }
831
+
832
+ .chart-bar-column {
833
+ display: flex;
834
+ flex-direction: column;
835
+ align-items: center;
836
+ flex: 1;
837
+ height: 100%;
838
+ justify-content: flex-end;
839
+ }
840
+
841
+ .chart-bar-fill {
842
+ width: 100%;
843
+ min-height: 4px;
844
+ background: var(--accent);
845
+ border-radius: 4px 4px 0 0;
846
+ position: relative;
847
+ transition: height 0.4s cubic-bezier(0.4, 0, 0.2, 1);
848
+ animation: bar-rise 0.4s cubic-bezier(0.4, 0, 0.2, 1);
849
+ }
850
+
851
+ @keyframes bar-rise {
852
+ 0% {
853
+ height: 0%;
854
+ }
855
+ }
856
+
857
+ .chart-bar-fill:hover::before {
858
+ content: attr(data-count);
859
+ position: absolute;
860
+ top: -1.5rem;
861
+ left: 50%;
862
+ transform: translateX(-50%);
863
+ background: var(--bg-surface);
864
+ color: var(--text-base);
865
+ font-size: 0.75rem;
866
+ font-weight: 900;
867
+ padding: 0.15rem 0.4rem;
868
+ border-radius: 4px;
869
+ border: 1px solid var(--border-color);
870
+ white-space: nowrap;
871
+ box-shadow: 0 2px 8px rgba(0,0,0,0.05);
872
+ }
873
+
874
+ .chart-bar-label {
875
+ font-size: 0.75rem;
876
+ color: var(--text-muted);
877
+ margin-top: 0.35rem;
878
+ font-weight: 700;
879
+ }
880
+
881
+ .btn-clear-all {
882
+ background: none;
883
+ border: none;
884
+ color: var(--text-muted);
885
+ cursor: pointer;
886
+ display: flex;
887
+ align-items: center;
888
+ justify-content: center;
889
+ padding: 0.35rem;
890
+ border-radius: 0.375rem;
891
+ transition: all 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
892
+ }
893
+
894
+ .btn-clear-all:hover {
895
+ color: var(--accent);
896
+ background: var(--bg-surface);
897
+ transform: rotate(15deg) scale(1.1);
898
+ }
899
+
900
+ .history-scroll-viewport {
901
+ max-height: 300px;
902
+ overflow-y: auto;
903
+ }
904
+
905
+ .history-scroll-viewport::-webkit-scrollbar {
906
+ width: 6px;
907
+ }
908
+
909
+ .history-scroll-viewport::-webkit-scrollbar-thumb {
910
+ background: var(--border-color);
911
+ border-radius: 6px;
912
+ }
913
+
914
+ .history-empty-message {
915
+ display: flex;
916
+ flex-direction: column;
917
+ align-items: center;
918
+ justify-content: center;
919
+ padding: 4rem 2rem;
920
+ color: var(--text-muted);
921
+ text-align: center;
922
+ position: relative;
923
+ overflow: hidden;
924
+ }
925
+
926
+ .history-empty-message .empty-icon {
927
+ color: var(--accent);
928
+ opacity: 0.5;
929
+ filter: drop-shadow(0 0 8px rgba(244, 63, 94, 0.4));
930
+ animation: magical-float 3s infinite ease-in-out;
931
+ margin-bottom: 1.25rem;
932
+ width: 3.5rem;
933
+ height: 3.5rem;
934
+ }
935
+
936
+ .history-cards-list {
937
+ display: flex;
938
+ flex-direction: column;
939
+ gap: 0.75rem;
940
+ }
941
+
942
+ .history-card-item {
943
+ background: var(--bg-surface);
944
+ border: 1px solid var(--border-color);
945
+ border-radius: 0.75rem;
946
+ padding: 0.75rem 1rem;
947
+ display: flex;
948
+ flex-direction: column;
949
+ gap: 0.5rem;
950
+ transition: all 0.25s cubic-bezier(0.175, 0.885, 0.32, 1.275);
951
+ animation: log-slide-in 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
952
+ }
953
+
954
+ .history-card-item:hover {
955
+ transform: translateY(-3px) scale(1.02);
956
+ border-color: var(--accent);
957
+ box-shadow: 0 4px 12px rgba(244, 63, 94, 0.05);
958
+ }
959
+
960
+ @keyframes log-slide-in {
961
+ 0% {
962
+ opacity: 0;
963
+ transform: translateY(10px);
964
+ }
965
+ 100% {
966
+ opacity: 1;
967
+ transform: translateY(0);
968
+ }
969
+ }
970
+
971
+ .history-card-header {
972
+ display: flex;
973
+ justify-content: space-between;
974
+ font-size: 0.75rem;
975
+ color: var(--text-muted);
976
+ font-weight: 800;
977
+ }
978
+
979
+ .history-card-body {
980
+ display: flex;
981
+ justify-content: space-between;
982
+ align-items: center;
983
+ }
984
+
985
+ .history-dice-tags {
986
+ display: flex;
987
+ flex-wrap: wrap;
988
+ gap: 0.35rem;
989
+ max-width: 75%;
990
+ }
991
+
992
+ .die-result-tag {
993
+ background: var(--bg-page);
994
+ border: 1px solid var(--border-color);
995
+ font-size: 0.75rem;
996
+ padding: 0.15rem 0.4rem;
997
+ border-radius: 4px;
998
+ font-weight: 700;
999
+ }
1000
+
1001
+ .history-grand-total {
1002
+ font-size: 1.35rem;
1003
+ font-weight: 900;
1004
+ color: var(--accent);
1005
+ }
1006
+
1007
+ .roll-result-banner {
1008
+ background: var(--bg-surface);
1009
+ border: 1px solid var(--border-color);
1010
+ border-radius: 1rem;
1011
+ padding: 1rem 1.5rem;
1012
+ display: flex;
1013
+ flex-direction: column;
1014
+ align-items: center;
1015
+ gap: 0.5rem;
1016
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
1017
+ animation: banner-slide-up 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
1018
+ }
1019
+
1020
+ .roll-result-banner.hidden {
1021
+ display: none;
1022
+ }
1023
+
1024
+ .banner-total {
1025
+ display: flex;
1026
+ align-items: center;
1027
+ gap: 0.75rem;
1028
+ }
1029
+
1030
+ .banner-total-label {
1031
+ font-size: 0.9rem;
1032
+ color: var(--text-muted);
1033
+ font-weight: 800;
1034
+ text-transform: uppercase;
1035
+ letter-spacing: 0.05em;
1036
+ }
1037
+
1038
+ .banner-total-value {
1039
+ font-size: 2.25rem;
1040
+ font-weight: 900;
1041
+ color: var(--accent);
1042
+ text-shadow: 0 0 10px rgba(244, 63, 94, 0.2);
1043
+ }
1044
+
1045
+ .banner-breakdown {
1046
+ font-size: 1.1rem;
1047
+ color: var(--text-base);
1048
+ font-weight: 700;
1049
+ text-align: center;
1050
+ background: var(--bg-page);
1051
+ border: 1px solid var(--border-color);
1052
+ padding: 0.35rem 1rem;
1053
+ border-radius: 99px;
1054
+ box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.02);
1055
+ }
1056
+
1057
+ @keyframes banner-slide-up {
1058
+ 0% {
1059
+ opacity: 0;
1060
+ transform: translateY(15px);
1061
+ }
1062
+ 100% {
1063
+ opacity: 1;
1064
+ transform: translateY(0);
1065
+ }
1066
+ }
1067
+
1068
+ .breakdown-die-tag {
1069
+ display: inline-flex;
1070
+ align-items: center;
1071
+ justify-content: center;
1072
+ width: 1.85rem;
1073
+ height: 1.85rem;
1074
+ font-size: 0.85rem;
1075
+ font-weight: 900;
1076
+ color: var(--color-white);
1077
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
1078
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15);
1079
+ user-select: none;
1080
+ vertical-align: middle;
1081
+ margin: 0 0.15rem;
1082
+ }
1083
+
1084
+ .breakdown-die-tag[data-die-type="d4"] {
1085
+ background: linear-gradient(135deg, #ec4899, var(--color-d4));
1086
+ clip-path: polygon(50% 5%, 5% 85%, 95% 85%);
1087
+ padding-top: 0.35rem;
1088
+ width: 1.75rem;
1089
+ height: 1.75rem;
1090
+ }
1091
+
1092
+ .breakdown-die-tag[data-die-type="d6"] {
1093
+ background: linear-gradient(135deg, #a855f7, #6366f1);
1094
+ border-radius: 0.35rem;
1095
+ }
1096
+
1097
+ .breakdown-die-tag[data-die-type="d8"] {
1098
+ background: linear-gradient(135deg, var(--color-d8), #06b6d4);
1099
+ clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
1100
+ }
1101
+
1102
+ .breakdown-die-tag[data-die-type="d10"] {
1103
+ background: linear-gradient(135deg, #14b8a6, var(--color-d10));
1104
+ clip-path: polygon(50% 0%, 90% 35%, 50% 100%, 10% 35%);
1105
+ }
1106
+
1107
+ .breakdown-die-tag[data-die-type="d12"] {
1108
+ background: linear-gradient(135deg, #eab308, var(--color-d12));
1109
+ clip-path: polygon(50% 0%, 95% 32%, 78% 85%, 22% 85%, 5% 32%);
1110
+ }
1111
+
1112
+ .breakdown-die-tag[data-die-type="d20"] {
1113
+ background: linear-gradient(135deg, var(--color-d20), #ec4899);
1114
+ clip-path: polygon(30% 0%, 70% 0%, 100% 30%, 100% 70%, 70% 100%, 30% 100%, 0% 70%, 0% 30%);
1115
+ }
1116
+
1117
+ .breakdown-die-tag[data-die-type="d100"] {
1118
+ background: linear-gradient(135deg, var(--color-d100), #475569);
1119
+ border-radius: 50%;
1120
+ }
1121
+
1122
+ .breakdown-operator {
1123
+ font-weight: 800;
1124
+ color: var(--text-muted);
1125
+ font-size: 1.1rem;
1126
+ margin: 0 0.25rem;
1127
+ vertical-align: middle;
1128
+ }
1129
+
1130
+ .breakdown-modifier-tag {
1131
+ display: inline-flex;
1132
+ align-items: center;
1133
+ justify-content: center;
1134
+ background: var(--bg-surface);
1135
+ border: 1px solid var(--border-color);
1136
+ color: var(--accent);
1137
+ font-weight: 900;
1138
+ font-size: 1.1rem;
1139
+ padding: 0.15rem 0.6rem;
1140
+ border-radius: 6px;
1141
+ vertical-align: middle;
1142
+ }
1143
+
1144
+ .banner-pop-effect {
1145
+ animation: banner-pop 0.35s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards;
1146
+ }
1147
+
1148
+ @keyframes banner-pop {
1149
+ 0% {
1150
+ transform: scale(0.9);
1151
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
1152
+ }
1153
+ 50% {
1154
+ transform: scale(1.04);
1155
+ box-shadow: 0 8px 25px rgba(244, 63, 94, 0.15);
1156
+ }
1157
+ 100% {
1158
+ transform: scale(1);
1159
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
1160
+ }
1161
+ }
1162
+
1163
+ .floating-magic-particle {
1164
+ position: absolute;
1165
+ color: var(--color-white);
1166
+ font-weight: 900;
1167
+ font-size: 2.25rem;
1168
+ pointer-events: none;
1169
+ z-index: 9999;
1170
+ animation: magic-float-up 0.8s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards;
1171
+ text-shadow: 0 0 10px var(--color-crit), 0 0 20px var(--color-d20), 0 0 30px #ec4899;
1172
+ user-select: none;
1173
+ display: inline-block;
1174
+ }
1175
+
1176
+ @keyframes magic-float-up {
1177
+ 0% {
1178
+ transform: translateY(0) scale(0.6) rotate(-10deg);
1179
+ opacity: 0;
1180
+ }
1181
+ 20% {
1182
+ opacity: 1;
1183
+ transform: translateY(-15px) scale(1.4) rotate(10deg);
1184
+ }
1185
+ 100% {
1186
+ transform: translateY(-90px) scale(1.8) rotate(-15deg);
1187
+ opacity: 0;
1188
+ }
1189
+ }
1190
+
1191
+ .felt-dice-container .visual-die.die-critical {
1192
+ animation: crit-shake-bounce 0.6s cubic-bezier(0.36, 0.07, 0.19, 0.97) both, crit-glow-pulse 1.5s infinite alternate;
1193
+ border: 2px solid var(--color-crit);
1194
+ box-shadow: 0 0 15px var(--color-crit), 0 0 30px var(--color-crit-glow);
1195
+ z-index: 5;
1196
+ }
1197
+
1198
+ .felt-dice-container .visual-die.die-fumble {
1199
+ animation: fumble-shiver-drop 0.6s ease-in-out both, fumble-glow-pulse 1.5s infinite alternate;
1200
+ border: 2px solid var(--color-fumble);
1201
+ box-shadow: 0 0 15px var(--color-fumble), 0 0 30px var(--color-fumble-glow);
1202
+ z-index: 4;
1203
+ }
1204
+
1205
+ .breakdown-die-tag.die-critical {
1206
+ border: 1px solid var(--color-crit);
1207
+ box-shadow: 0 0 8px var(--color-crit);
1208
+ }
1209
+
1210
+ .breakdown-die-tag.die-fumble {
1211
+ border: 1px solid var(--color-fumble);
1212
+ box-shadow: 0 0 8px var(--color-fumble);
1213
+ }
1214
+
1215
+ @keyframes crit-shake-bounce {
1216
+ 0% {
1217
+ transform: scale(0.5) rotate(0deg);
1218
+ }
1219
+ 50% {
1220
+ transform: scale(1.35) rotate(15deg);
1221
+ }
1222
+ 70% {
1223
+ transform: scale(0.95) rotate(-10deg);
1224
+ }
1225
+ 100% {
1226
+ transform: scale(1) rotate(0deg);
1227
+ }
1228
+ }
1229
+
1230
+ @keyframes crit-glow-pulse {
1231
+ 0% {
1232
+ box-shadow: 0 0 10px var(--color-crit), 0 0 20px var(--color-crit-glow);
1233
+ filter: brightness(1);
1234
+ }
1235
+ 100% {
1236
+ box-shadow: 0 0 25px var(--color-crit), 0 0 50px var(--color-fumble);
1237
+ filter: brightness(1.3);
1238
+ }
1239
+ }
1240
+
1241
+ @keyframes fumble-shiver-drop {
1242
+ 0% {
1243
+ transform: scale(0.5) translateY(-20px);
1244
+ }
1245
+ 30% {
1246
+ transform: scale(1.1) translateY(5px) rotate(-10deg);
1247
+ }
1248
+ 60% {
1249
+ transform: scale(0.9) translateY(0) rotate(5deg);
1250
+ }
1251
+ 100% {
1252
+ transform: scale(1) translateY(2px) rotate(0deg);
1253
+ }
1254
+ }
1255
+
1256
+ @keyframes fumble-glow-pulse {
1257
+ 0% {
1258
+ box-shadow: 0 0 10px var(--color-fumble), 0 0 20px var(--color-fumble-glow);
1259
+ filter: grayscale(0.2) brightness(0.9);
1260
+ }
1261
+ 100% {
1262
+ box-shadow: 0 0 20px var(--color-fumble), 0 0 35px var(--color-fumble-glow);
1263
+ filter: grayscale(0.5) brightness(0.7);
1264
+ }
1265
+ }
1266
+
1267
+ .die-val {
1268
+ position: relative;
1269
+ z-index: 2;
1270
+ font-weight: 900;
1271
+ text-shadow: 0 0 8px rgba(0, 0, 0, 0.8);
1272
+ }
1273
+
1274
+ .die-svg-icon-crit {
1275
+ position: absolute;
1276
+ width: 2.25rem;
1277
+ height: 2.25rem;
1278
+ color: var(--color-crit);
1279
+ opacity: 0.3;
1280
+ top: 50%;
1281
+ left: 50%;
1282
+ transform: translate(-50%, -50%);
1283
+ pointer-events: none;
1284
+ animation: spin-crit 10s infinite linear;
1285
+ }
1286
+
1287
+ @keyframes spin-crit {
1288
+ 0% {
1289
+ transform: translate(-50%, -50%) rotate(0deg);
1290
+ }
1291
+ 100% {
1292
+ transform: translate(-50%, -50%) rotate(360deg);
1293
+ }
1294
+ }
1295
+
1296
+ .die-svg-icon-fumble {
1297
+ position: absolute;
1298
+ width: 2rem;
1299
+ height: 2rem;
1300
+ color: var(--color-fumble);
1301
+ opacity: 0.35;
1302
+ top: 50%;
1303
+ left: 50%;
1304
+ transform: translate(-50%, -50%);
1305
+ pointer-events: none;
1306
+ animation: shiver-fumble 0.2s infinite;
1307
+ }
1308
+
1309
+ @keyframes shiver-fumble {
1310
+ 0% {
1311
+ transform: translate(-52%, -48%) rotate(0deg);
1312
+ }
1313
+ 50% {
1314
+ transform: translate(-48%, -52%) rotate(-1deg);
1315
+ }
1316
+ 100% {
1317
+ transform: translate(-50%, -50%) rotate(1deg);
1318
+ }
1319
+ }