@jjlmoya/utils-sports 1.1.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 (79) hide show
  1. package/package.json +62 -0
  2. package/src/category/i18n/en.ts +108 -0
  3. package/src/category/i18n/es.ts +108 -0
  4. package/src/category/i18n/fr.ts +95 -0
  5. package/src/category/index.ts +21 -0
  6. package/src/category/seo.astro +15 -0
  7. package/src/components/PreviewNavSidebar.astro +116 -0
  8. package/src/components/PreviewToolbar.astro +143 -0
  9. package/src/data.ts +11 -0
  10. package/src/env.d.ts +5 -0
  11. package/src/index.ts +55 -0
  12. package/src/layouts/PreviewLayout.astro +117 -0
  13. package/src/pages/[locale]/[slug].astro +146 -0
  14. package/src/pages/[locale].astro +251 -0
  15. package/src/pages/index.astro +4 -0
  16. package/src/tests/faq_count.test.ts +19 -0
  17. package/src/tests/locale_completeness.test.ts +42 -0
  18. package/src/tests/mocks/astro_mock.js +2 -0
  19. package/src/tests/no_h1_in_components.test.ts +48 -0
  20. package/src/tests/schemas_fulfillment.test.ts +23 -0
  21. package/src/tests/seo_length.test.ts +22 -0
  22. package/src/tests/title_quality.test.ts +55 -0
  23. package/src/tests/tool_validation.test.ts +17 -0
  24. package/src/tool/gymTracker/bibliography.astro +15 -0
  25. package/src/tool/gymTracker/component.astro +835 -0
  26. package/src/tool/gymTracker/exercises.ts +28 -0
  27. package/src/tool/gymTracker/i18n/en.ts +225 -0
  28. package/src/tool/gymTracker/i18n/es.ts +225 -0
  29. package/src/tool/gymTracker/i18n/fr.ts +225 -0
  30. package/src/tool/gymTracker/index.ts +34 -0
  31. package/src/tool/gymTracker/logic.ts +169 -0
  32. package/src/tool/gymTracker/seo.astro +15 -0
  33. package/src/tool/gymTracker/storage.ts +43 -0
  34. package/src/tool/gymTracker/timer.ts +126 -0
  35. package/src/tool/gymTracker/types.ts +11 -0
  36. package/src/tool/gymTracker/ui-utils.ts +59 -0
  37. package/src/tool/gymTracker/ui.ts +27 -0
  38. package/src/tool/reactionTester/bibliography.astro +2 -0
  39. package/src/tool/reactionTester/component.astro +1074 -0
  40. package/src/tool/reactionTester/i18n/en.ts +144 -0
  41. package/src/tool/reactionTester/i18n/es.ts +144 -0
  42. package/src/tool/reactionTester/i18n/fr.ts +144 -0
  43. package/src/tool/reactionTester/index.ts +34 -0
  44. package/src/tool/reactionTester/seo.astro +12 -0
  45. package/src/tool/reactionTester/ui.ts +43 -0
  46. package/src/tool/scoreKeeper/bibliography.astro +14 -0
  47. package/src/tool/scoreKeeper/component.astro +858 -0
  48. package/src/tool/scoreKeeper/i18n/en.ts +207 -0
  49. package/src/tool/scoreKeeper/i18n/es.ts +207 -0
  50. package/src/tool/scoreKeeper/i18n/fr.ts +207 -0
  51. package/src/tool/scoreKeeper/index.ts +35 -0
  52. package/src/tool/scoreKeeper/logic.ts +275 -0
  53. package/src/tool/scoreKeeper/seo.astro +15 -0
  54. package/src/tool/scoreKeeper/sports.ts +70 -0
  55. package/src/tool/scoreKeeper/ui.ts +19 -0
  56. package/src/tool/tournamentBracket/bibliography.astro +10 -0
  57. package/src/tool/tournamentBracket/component.astro +1092 -0
  58. package/src/tool/tournamentBracket/i18n/en.ts +160 -0
  59. package/src/tool/tournamentBracket/i18n/es.ts +178 -0
  60. package/src/tool/tournamentBracket/i18n/fr.ts +160 -0
  61. package/src/tool/tournamentBracket/index.ts +34 -0
  62. package/src/tool/tournamentBracket/logic/active.controller.ts +106 -0
  63. package/src/tool/tournamentBracket/logic/generator.ts +71 -0
  64. package/src/tool/tournamentBracket/logic/manager.ts +165 -0
  65. package/src/tool/tournamentBracket/logic/setup.controller.ts +84 -0
  66. package/src/tool/tournamentBracket/logic/sharing.ts +81 -0
  67. package/src/tool/tournamentBracket/logic/storage.ts +56 -0
  68. package/src/tool/tournamentBracket/models.ts +34 -0
  69. package/src/tool/tournamentBracket/seo.astro +12 -0
  70. package/src/tool/tournamentBracket/tournament.controller.ts +65 -0
  71. package/src/tool/tournamentBracket/tournament.renderer.ts +45 -0
  72. package/src/tool/tournamentBracket/ui/bracket-desktop.ts +143 -0
  73. package/src/tool/tournamentBracket/ui/bracket-mobile.ts +82 -0
  74. package/src/tool/tournamentBracket/ui/mediator.ts +96 -0
  75. package/src/tool/tournamentBracket/ui/navigator.ts +84 -0
  76. package/src/tool/tournamentBracket/ui/setup.ts +120 -0
  77. package/src/tool/tournamentBracket/ui.ts +42 -0
  78. package/src/tools.ts +13 -0
  79. package/src/types.ts +72 -0
@@ -0,0 +1,1074 @@
1
+ ---
2
+ import type { ReactionTesterUI } from './ui';
3
+ interface Props { ui: ReactionTesterUI }
4
+ const { ui: t } = Astro.props;
5
+
6
+ const LIGHTNING = `<svg xmlns="http://www.w3.org/2000/svg" class="rt-icon-xl" viewBox="0 0 24 24" fill="currentColor"><path d="M11,15H6L13,1V9H18L11,23V15Z"/></svg>`;
7
+ const PLAY_ICON = `<svg xmlns="http://www.w3.org/2000/svg" class="rt-icon-md" viewBox="0 0 24 24" fill="currentColor"><path d="M8,5.14V19.14L19,12.14L8,5.14Z"/></svg>`;
8
+ const ALERT = `<svg xmlns="http://www.w3.org/2000/svg" class="rt-icon-xl" viewBox="0 0 24 24" fill="currentColor"><path d="M13,13H11V7H13M13,17H11V15H13M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z"/></svg>`;
9
+ const COPY_ICON = `<svg xmlns="http://www.w3.org/2000/svg" class="rt-icon-sm" viewBox="0 0 24 24" fill="currentColor"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"/></svg>`;
10
+ const TWITTER = `<svg xmlns="http://www.w3.org/2000/svg" class="rt-icon-sm" viewBox="0 0 24 24" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 22.5H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231 5.45-6.231zm-1.161 17.52h1.833L7.084 4.126H5.117L17.083 19.77z"/></svg>`;
11
+ const HISTORY = `<svg xmlns="http://www.w3.org/2000/svg" class="rt-icon-sm" viewBox="0 0 24 24" fill="currentColor"><path d="M13.5,8H12V13L16.28,15.54L17,14.33L13.5,12.25V8M13,3A9,9 0 0,0 4,12H1L4.96,16.03L9,12H6A7,7 0 0,1 13,5A7,7 0 0,1 20,12A7,7 0 0,1 13,19C11.07,19 9.32,18.21 8.06,16.94L6.64,18.36C8.27,19.99 10.51,21 13,21A9,9 0 0,0 22,12A9,9 0 0,0 13,3"/></svg>`;
12
+ const TROPHY = `<svg xmlns="http://www.w3.org/2000/svg" class="rt-icon-sm" viewBox="0 0 24 24" fill="currentColor"><path d="M5,16L3,5L8.5,10L12,4L15.5,10L21,5L19,16H5M19,19C19,19.6 18.6,20 18,20H6C5.4,20 5,19.6 5,19V18H19V19Z"/></svg>`;
13
+ const CLICK = `<svg xmlns="http://www.w3.org/2000/svg" class="rt-icon-sm" viewBox="0 0 24 24" fill="currentColor"><path d="M10.76,8.69A0.76,0.76 0 0,0 10,9.45V15.05L8.17,13.22C7.8,12.85 7.21,12.89 6.88,13.29C6.57,13.67 6.61,14.23 6.97,14.59L10.96,18.58C11.35,18.97 11.85,19.19 12.38,19.19H16.31A2.31,2.31 0 0,0 18.62,17.0L19.5,12.06C19.61,11.5 19.2,11 18.64,11H15.27L15.73,8.67C15.83,8.15 15.47,7.64 14.95,7.54L14.86,7.53C14.4,7.44 13.94,7.7 13.78,8.14L12.78,10.5H11.5L11.5,8.93A0.76,0.76 0 0,0 10.76,8.69Z"/></svg>`;
14
+ ---
15
+
16
+ <div id="rt-app" class="rt-app" data-rt-ui={JSON.stringify(t)}>
17
+ <div id="rt-area" class="rt-area">
18
+ <div id="rt-idle" class="rt-layer rt-idle rt-active">
19
+ <div class="rt-idle-content">
20
+ <div class="rt-idle-icon-wrap">
21
+ <Fragment set:html={LIGHTNING} />
22
+ </div>
23
+ <h2 class="rt-idle-title">{t.title}</h2>
24
+ <p class="rt-idle-sub">{t.subtitle}</p>
25
+ <div class="rt-start-btn">
26
+ <Fragment set:html={PLAY_ICON} />
27
+ {t.startBtn}
28
+ </div>
29
+ </div>
30
+ </div>
31
+
32
+ <div id="rt-wait" class="rt-layer rt-wait">
33
+ <div class="rt-wait-content">
34
+ <h2 id="rt-wait-title" class="rt-wait-title">{t.wp0t}</h2>
35
+ <p id="rt-wait-sub" class="rt-wait-sub">{t.wp0s}</p>
36
+ </div>
37
+ </div>
38
+
39
+ <div id="rt-go" class="rt-layer rt-go">
40
+ <div class="rt-go-content">
41
+ <h2 class="rt-go-title">{t.goTitle}</h2>
42
+ <p class="rt-go-sub">{t.goSubtitle}</p>
43
+ </div>
44
+ </div>
45
+
46
+ <div id="rt-early" class="rt-layer rt-early">
47
+ <div class="rt-early-content">
48
+ <div class="rt-early-icon">
49
+ <Fragment set:html={ALERT} />
50
+ </div>
51
+ <h2 class="rt-early-title">{t.earlyTitle}</h2>
52
+ <p class="rt-early-sub">{t.earlySubtitle}</p>
53
+ <div class="rt-early-retry">{t.earlyRetry}</div>
54
+ </div>
55
+ </div>
56
+
57
+ <div id="rt-result" class="rt-layer rt-result">
58
+ <div class="rt-result-content">
59
+ <div id="rt-time" class="rt-time">245 ms</div>
60
+ <p id="rt-feedback" class="rt-feedback">...</p>
61
+ <div class="rt-progress-track">
62
+ <div id="rt-bar" class="rt-progress-bar"></div>
63
+ </div>
64
+ <div id="rt-action" class="rt-action">
65
+ <Fragment set:html={CLICK} />
66
+ {t.promptNext} (1/5)
67
+ </div>
68
+ </div>
69
+ </div>
70
+
71
+ <div id="rt-score" class="rt-layer rt-score">
72
+ <div class="rt-score-content">
73
+ <div id="rt-rank" class="rt-rank-badge rt-rank-tigre">{t.rankTigre}</div>
74
+ <h2 class="rt-final-wrap">
75
+ <span id="rt-avg" class="rt-final-avg">232</span>
76
+ <span class="rt-final-unit">ms</span>
77
+ </h2>
78
+ <p class="rt-avg-label">{t.avgLabel}</p>
79
+ <div id="rt-bars" class="rt-bars"></div>
80
+ <div class="rt-share-grid">
81
+ <button id="rt-copy" class="rt-btn-copy">
82
+ <Fragment set:html={COPY_ICON} />
83
+ <span>{t.copyBtn}</span>
84
+ </button>
85
+ <button id="rt-tweet" class="rt-btn-tweet">
86
+ <Fragment set:html={TWITTER} />
87
+ <span>{t.tweetBtn}</span>
88
+ </button>
89
+ </div>
90
+ <button id="rt-retry" class="rt-btn-retry">{t.retryBtn}</button>
91
+ </div>
92
+ </div>
93
+ </div>
94
+
95
+ <div class="rt-hints">
96
+ <span class="rt-hint">
97
+ <span class="rt-hint-key">
98
+ <svg xmlns="http://www.w3.org/2000/svg" class="rt-icon-xs" viewBox="0 0 24 24" fill="currentColor"><path d="M13 3H11C8.24 3 6 5.24 6 8V16C6 18.76 8.24 21 11 21H13C15.76 21 18 18.76 18 16V8C18 5.24 15.76 3 13 3M16 16C16 17.65 14.65 19 13 19H11C9.35 19 8 17.65 8 16V8C8 6.35 9.35 5 11 5H13C14.65 5 16 6.35 16 8V16M13 6V10H11V6H13Z"/></svg>
99
+ </span>
100
+ {t.inputMouse}
101
+ </span>
102
+ <span class="rt-hint">
103
+ <span class="rt-hint-key">
104
+ <svg xmlns="http://www.w3.org/2000/svg" class="rt-icon-xs" viewBox="0 0 24 24" fill="currentColor"><path d="M17.5 12A1.5 1.5 0 0 1 19 13.5V19A5 5 0 0 1 14 24H12A8 8 0 0 1 4 16V13.5A1.5 1.5 0 0 1 5.5 12A1.5 1.5 0 0 1 7 13.5V16H8V5.5A1.5 1.5 0 0 1 9.5 4A1.5 1.5 0 0 1 11 5.5V12H12V3.5A1.5 1.5 0 0 1 13.5 2A1.5 1.5 0 0 1 15 3.5V12H16V6.5A1.5 1.5 0 0 1 17.5 5A1.5 1.5 0 0 1 19 6.5V12H17.5Z"/></svg>
105
+ </span>
106
+ {t.inputTouch}
107
+ </span>
108
+ <span class="rt-hint">
109
+ <span class="rt-hint-key rt-hint-key-text">SPC</span>
110
+ {t.inputSpace}
111
+ </span>
112
+ </div>
113
+
114
+ <div class="rt-history">
115
+ <h2 class="rt-history-title">
116
+ <Fragment set:html={HISTORY} />
117
+ {t.historyTitle}
118
+ </h2>
119
+ <div class="rt-history-grid">
120
+ <div class="rt-history-card">
121
+ <h3 class="rt-history-card-title rt-best-label">
122
+ <Fragment set:html={TROPHY} />
123
+ {t.historyBest}
124
+ </h3>
125
+ <ul id="rt-list-best" class="rt-list">
126
+ <li class="rt-list-empty">{t.historyEmpty}</li>
127
+ </ul>
128
+ </div>
129
+ <div class="rt-history-card">
130
+ <h3 class="rt-history-card-title rt-worst-label">
131
+ <Fragment set:html={ALERT} />
132
+ {t.historyWorst}
133
+ </h3>
134
+ <ul id="rt-list-worst" class="rt-list">
135
+ <li class="rt-list-empty">{t.historyEmpty}</li>
136
+ </ul>
137
+ </div>
138
+ </div>
139
+ </div>
140
+ </div>
141
+
142
+ <script>
143
+ interface RTUI {
144
+ promptNext: string; promptFinal: string; avgLabel: string;
145
+ copyBtn: string; tweetBtn: string; retryBtn: string;
146
+ historyEmpty: string; copySuccess: string; shareText: string;
147
+ rankCiberatleta: string; rankTigre: string; rankHumano: string;
148
+ rankTortuga: string; rankDormido: string;
149
+ f150: string; f180: string; f210: string; f250: string;
150
+ f300: string; f400: string; f600: string; fSlow: string;
151
+ wp0t: string; wp0s: string; wp1t: string; wp1s: string;
152
+ wp2t: string; wp2s: string; wp3t: string; wp3s: string;
153
+ wp4t: string; wp4s: string;
154
+ }
155
+
156
+ interface Rank { max: number; title: string; cls: string; }
157
+ interface ScoreEntry { score: number; rank: string; date: string; }
158
+
159
+ const app = document.getElementById('rt-app') as HTMLElement;
160
+ const ui = JSON.parse(app?.dataset.rtUi ?? '{}') as RTUI;
161
+
162
+ const WAIT_PHRASES = [
163
+ { t: ui.wp0t, s: ui.wp0s }, { t: ui.wp1t, s: ui.wp1s },
164
+ { t: ui.wp2t, s: ui.wp2s }, { t: ui.wp3t, s: ui.wp3s },
165
+ { t: ui.wp4t, s: ui.wp4s },
166
+ ];
167
+
168
+ const RANKS: Rank[] = [
169
+ { max: 180, title: ui.rankCiberatleta, cls: 'rt-rank-ciberatleta' },
170
+ { max: 230, title: ui.rankTigre, cls: 'rt-rank-tigre' },
171
+ { max: 280, title: ui.rankHumano, cls: 'rt-rank-humano' },
172
+ { max: 350, title: ui.rankTortuga, cls: 'rt-rank-tortuga' },
173
+ { max: 9999, title: ui.rankDormido, cls: 'rt-rank-dormido' },
174
+ ];
175
+
176
+ const layers = {
177
+ idle: document.getElementById('rt-idle'),
178
+ wait: document.getElementById('rt-wait'),
179
+ go: document.getElementById('rt-go'),
180
+ early: document.getElementById('rt-early'),
181
+ result: document.getElementById('rt-result'),
182
+ score: document.getElementById('rt-score'),
183
+ };
184
+
185
+ const els = {
186
+ app,
187
+ time: document.getElementById('rt-time'),
188
+ action: document.getElementById('rt-action'),
189
+ bar: document.getElementById('rt-bar'),
190
+ final: document.getElementById('rt-avg'),
191
+ rank: document.getElementById('rt-rank'),
192
+ bars: document.getElementById('rt-bars'),
193
+ feedback: document.getElementById('rt-feedback'),
194
+ waitTitle: document.getElementById('rt-wait-title'),
195
+ waitSub: document.getElementById('rt-wait-sub'),
196
+ listBest: document.getElementById('rt-list-best'),
197
+ listWorst: document.getElementById('rt-list-worst'),
198
+ };
199
+
200
+ const TOTAL = 5;
201
+ let attempts: number[] = [];
202
+ let state = 'idle';
203
+ let startTime = 0;
204
+ let timerId: ReturnType<typeof setTimeout> | number = 0;
205
+
206
+ function getFeedback(ms: number): string {
207
+ if (ms < 150) return ui.f150;
208
+ if (ms < 180) return ui.f180;
209
+ if (ms < 210) return ui.f210;
210
+ if (ms < 250) return ui.f250;
211
+ if (ms < 300) return ui.f300;
212
+ if (ms < 400) return ui.f400;
213
+ if (ms < 600) return ui.f600;
214
+ return ui.fSlow;
215
+ }
216
+
217
+ function showLayer(name: keyof typeof layers) {
218
+ Object.keys(layers).forEach((k) => {
219
+ layers[k as keyof typeof layers]?.classList.toggle('rt-active', k === name);
220
+ });
221
+ }
222
+
223
+ function startAttempt() {
224
+ state = 'waiting';
225
+ const index = Math.floor(Math.random() * WAIT_PHRASES.length);
226
+ const phrase = WAIT_PHRASES[index] || WAIT_PHRASES[0];
227
+ if (!phrase) return;
228
+ if (els.waitTitle) els.waitTitle.textContent = phrase.t;
229
+ if (els.waitSub) els.waitSub.textContent = phrase.s;
230
+ showLayer('wait');
231
+ const delay = Math.floor(Math.random() * 3000) + 1500;
232
+ timerId = setTimeout(() => {
233
+ if (state === 'waiting') {
234
+ state = 'ready';
235
+ showLayer('go');
236
+ startTime = performance.now();
237
+ }
238
+ }, delay);
239
+ }
240
+
241
+ function handleResult() {
242
+ const reaction = performance.now() - startTime;
243
+ state = 'result';
244
+ attempts.push(reaction);
245
+ if (els.time) els.time.textContent = `${Math.round(reaction)} ms`;
246
+ if (els.feedback) els.feedback.textContent = getFeedback(reaction);
247
+ const isLast = attempts.length >= TOTAL;
248
+ if (els.action) {
249
+ els.action.textContent = isLast ? ui.promptFinal : `${ui.promptNext} (${attempts.length + 1}/${TOTAL})`;
250
+ }
251
+ if (els.bar) els.bar.style.width = `${(attempts.length / TOTAL) * 100}%`;
252
+ showLayer('result');
253
+ }
254
+
255
+ function handleInteraction(e: Event) {
256
+ if (e.type === 'keydown' && (e as KeyboardEvent).code === 'Space') e.preventDefault();
257
+ if (e.type === 'mousedown' && (e as MouseEvent).button !== 0) return;
258
+
259
+ const handlers: Record<string, () => void> = {
260
+ idle: () => { attempts = []; startAttempt(); },
261
+ waiting: () => { clearTimeout(timerId); state = 'early'; showLayer('early'); },
262
+ early: startAttempt,
263
+ ready: handleResult,
264
+ result: () => {
265
+ if (attempts.length >= TOTAL) {
266
+ showScore();
267
+ } else {
268
+ startAttempt();
269
+ }
270
+ }
271
+ };
272
+
273
+ handlers[state]?.();
274
+ }
275
+
276
+ function renderItem(item: ScoreEntry, type: string): string {
277
+ const scoreClass = type === 'best' ? 'rt-score-best' : 'rt-score-worst';
278
+ return `<li class="rt-history-entry"><div class="rt-entry-left"><span class="rt-entry-score ${scoreClass}">${item.score}ms</span><span class="rt-entry-rank">${item.rank}</span></div><span class="rt-entry-date">${item.date}</span></li>`;
279
+ }
280
+
281
+ function renderHistory() {
282
+ const history: ScoreEntry[] = JSON.parse(localStorage.getItem('reaction_scores') ?? '[]');
283
+ const empty = `<li class="rt-list-empty">${ui.historyEmpty}</li>`;
284
+ const best = [...history].sort((a, b) => a.score - b.score).slice(0, 5);
285
+ const worst = [...history].sort((a, b) => b.score - a.score).slice(0, 5);
286
+ if (els.listBest) els.listBest.innerHTML = best.length ? best.map((i) => renderItem(i, 'best')).join('') : empty;
287
+ if (els.listWorst) els.listWorst.innerHTML = worst.length ? worst.map((i) => renderItem(i, 'worst')).join('') : empty;
288
+ }
289
+
290
+ function saveScore(score: number, rankTitle: string) {
291
+ const history: ScoreEntry[] = JSON.parse(localStorage.getItem('reaction_scores') ?? '[]');
292
+ history.push({ score, rank: rankTitle, date: new Date().toLocaleDateString() });
293
+ localStorage.setItem('reaction_scores', JSON.stringify(history));
294
+ renderHistory();
295
+ }
296
+
297
+ function buildBars(maxVal: number) {
298
+ if (!els.bars) return;
299
+ els.bars.innerHTML = '';
300
+ attempts.forEach((val) => {
301
+ const bar = document.createElement('div');
302
+ bar.className = 'rt-bar-item';
303
+ bar.style.height = `${Math.min((val / maxVal) * 100, 100)}%`;
304
+ const tip = document.createElement('div');
305
+ tip.className = 'rt-bar-tip';
306
+ tip.textContent = String(Math.round(val));
307
+ bar.appendChild(tip);
308
+ els.bars!.appendChild(bar);
309
+ });
310
+ }
311
+
312
+ function setupShare(avg: number, rankTitle: string) {
313
+ const shareText = ui.shareText
314
+ .replace('{ms}', String(avg))
315
+ .replace('{rank}', rankTitle)
316
+ .replace('{url}', window.location.href);
317
+ const btnCopy = document.getElementById('rt-copy');
318
+ const btnTweet = document.getElementById('rt-tweet');
319
+ if (btnCopy) {
320
+ btnCopy.onclick = (e) => {
321
+ e.stopPropagation();
322
+ void navigator.clipboard.writeText(shareText);
323
+ const orig = btnCopy.innerHTML;
324
+ btnCopy.innerHTML = `<span>${ui.copySuccess}</span>`;
325
+ setTimeout(() => { btnCopy.innerHTML = orig; }, 2000);
326
+ };
327
+ }
328
+ if (btnTweet) {
329
+ btnTweet.onclick = (e) => {
330
+ e.stopPropagation();
331
+ window.open(`https://twitter.com/intent/tweet?text=${encodeURIComponent(shareText)}`, '_blank');
332
+ };
333
+ }
334
+ }
335
+
336
+ function showScore() {
337
+ state = 'finished';
338
+ if (els.app) els.app.classList.add('rt-state-finished');
339
+ const avg = Math.round(attempts.reduce((a, b) => a + b, 0) / attempts.length);
340
+ if (els.final) els.final.textContent = String(avg);
341
+ const rank = RANKS.find((r) => avg <= r.max) || RANKS[RANKS.length - 1];
342
+ if (rank && els.rank) {
343
+ els.rank.className = `rt-rank-badge ${rank.cls}`;
344
+ els.rank.textContent = rank.title;
345
+ }
346
+ if (rank) {
347
+ saveScore(avg, rank.title);
348
+ setupShare(avg, rank.title);
349
+ }
350
+ buildBars(Math.max(...attempts, 400));
351
+ showLayer('score');
352
+ }
353
+
354
+ function reset() {
355
+ state = 'idle';
356
+ if (els.app) els.app.classList.remove('rt-state-finished');
357
+ attempts = [];
358
+ showLayer('idle');
359
+ }
360
+
361
+ const area = document.getElementById('rt-area');
362
+ if (area) {
363
+ area.addEventListener('mousedown', handleInteraction);
364
+ area.addEventListener('touchstart', (e) => { e.preventDefault(); handleInteraction(e); }, { passive: false });
365
+ }
366
+ document.addEventListener('keydown', (e) => { if (e.code === 'Space') handleInteraction(e); });
367
+ document.getElementById('rt-retry')?.addEventListener('click', (e) => { e.stopPropagation(); reset(); });
368
+ renderHistory();
369
+ </script>
370
+
371
+ <style>
372
+ :global(.rt-app) {
373
+ display: flex;
374
+ flex-direction: column;
375
+ gap: 2.5rem;
376
+ width: 100%;
377
+ max-width: 50rem;
378
+ margin: 0 auto;
379
+ padding: 1rem;
380
+ user-select: none;
381
+ }
382
+
383
+ :global(.rt-area) {
384
+ position: relative;
385
+ width: 100%;
386
+ min-height: 480px;
387
+ border-radius: 2rem;
388
+ box-shadow: 0 25px 50px rgba(0, 0, 0, 0.2);
389
+ overflow: hidden;
390
+ cursor: pointer;
391
+ touch-action: manipulation;
392
+ background: var(--bg-surface);
393
+ display: flex;
394
+ flex-direction: column;
395
+ transition: min-height 0.6s cubic-bezier(0.34, 1.56, 0.64, 1), border-radius 0.4s ease;
396
+ }
397
+
398
+ :global(.rt-app.rt-state-finished .rt-area) {
399
+ min-height: 620px;
400
+ }
401
+
402
+ @media (min-width: 768px) {
403
+ :global(.rt-area) {
404
+ min-height: 520px;
405
+ border-radius: 3.5rem;
406
+ }
407
+ :global(.rt-app.rt-state-finished .rt-area) {
408
+ min-height: 720px;
409
+ }
410
+ }
411
+
412
+ :global(.rt-layer) {
413
+ position: absolute;
414
+ inset: 0;
415
+ display: flex;
416
+ flex-direction: column;
417
+ align-items: center;
418
+ justify-content: center;
419
+ opacity: 0;
420
+ pointer-events: none;
421
+ transition: all 0.4s cubic-bezier(0.23, 1, 0.32, 1);
422
+ transform: scale(1.05);
423
+ padding: 2rem;
424
+ }
425
+
426
+ :global(.rt-layer.rt-active) {
427
+ opacity: 1;
428
+ pointer-events: auto;
429
+ transform: scale(1);
430
+ z-index: 5;
431
+ }
432
+
433
+ :global(.rt-idle) {
434
+ background: var(--bg-surface);
435
+ }
436
+
437
+ :global(.rt-wait) {
438
+ background: #f43f5e;
439
+ }
440
+
441
+ :global(.rt-layer.rt-go.rt-active) {
442
+ background: #10b981;
443
+ transition: none;
444
+ transform: scale(1);
445
+ }
446
+
447
+ :global(.rt-early) {
448
+ background: #fb923c;
449
+ }
450
+
451
+ :global(.rt-result) {
452
+ background: #6366f1;
453
+ }
454
+
455
+ :global(.rt-score) {
456
+ background: #0f172a;
457
+ z-index: 10;
458
+ justify-content: center;
459
+ }
460
+
461
+ :global(.rt-idle-content) {
462
+ text-align: center;
463
+ padding: 2rem;
464
+ }
465
+
466
+ :global(.rt-idle-icon-wrap) {
467
+ display: inline-flex;
468
+ padding: 1.75rem;
469
+ border-radius: 2rem;
470
+ background: var(--bg-page);
471
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
472
+ margin-bottom: 2rem;
473
+ color: var(--primary);
474
+ }
475
+
476
+ :global(.rt-idle-title) {
477
+ font-size: clamp(2rem, 8vw, 4rem);
478
+ font-weight: 950;
479
+ color: var(--text-base);
480
+ margin: 0 0 1rem;
481
+ letter-spacing: -0.04em;
482
+ line-height: 1.1;
483
+ }
484
+
485
+ :global(.rt-idle-sub) {
486
+ font-size: 1.15rem;
487
+ color: var(--text-muted);
488
+ max-width: 25rem;
489
+ margin: 0 auto 2.5rem;
490
+ line-height: 1.6;
491
+ }
492
+
493
+ :global(.rt-start-btn) {
494
+ display: inline-flex;
495
+ align-items: center;
496
+ gap: 0.75rem;
497
+ padding: 1.1rem 2.2rem;
498
+ background: var(--primary);
499
+ color: white;
500
+ border-radius: 1.25rem;
501
+ font-weight: 800;
502
+ font-size: 1.15rem;
503
+ text-transform: uppercase;
504
+ letter-spacing: 0.05em;
505
+ box-shadow: 0 10px 30px var(--primary-soft);
506
+ transition: all 0.3s ease;
507
+ }
508
+
509
+ :global(.rt-start-btn:hover) {
510
+ transform: translateY(-4px);
511
+ box-shadow: 0 15px 40px var(--primary-soft);
512
+ }
513
+
514
+ :global(.rt-wait-content) {
515
+ text-align: center;
516
+ color: white;
517
+ padding: 2rem;
518
+ }
519
+
520
+ :global(.rt-wait-title) {
521
+ font-size: clamp(3rem, 12vw, 6.5rem);
522
+ font-weight: 900;
523
+ letter-spacing: -0.05em;
524
+ margin: 0 0 1rem;
525
+ opacity: 0.95;
526
+ animation: rt-pulse 2s ease-in-out infinite;
527
+ }
528
+
529
+ @keyframes rt-pulse {
530
+ 0%,
531
+ 100% {
532
+ opacity: 1;
533
+ transform: scale(1);
534
+ }
535
+ 50% {
536
+ opacity: 0.7;
537
+ transform: scale(0.96);
538
+ }
539
+ }
540
+
541
+ :global(.rt-wait-sub) {
542
+ font-size: clamp(1.25rem, 4vw, 2rem);
543
+ font-weight: 700;
544
+ opacity: 0.8;
545
+ margin: 0;
546
+ }
547
+
548
+ :global(.rt-go-content) {
549
+ text-align: center;
550
+ color: white;
551
+ }
552
+
553
+ :global(.rt-go-title) {
554
+ font-size: clamp(5rem, 20vw, 11rem);
555
+ font-weight: 950;
556
+ letter-spacing: -0.06em;
557
+ margin: 0;
558
+ text-shadow: 0 10px 30px rgba(0, 0, 0, 0.4);
559
+ animation: rt-pop 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
560
+ }
561
+
562
+ @keyframes rt-pop {
563
+ from {
564
+ transform: scale(0.5);
565
+ opacity: 0;
566
+ }
567
+ to {
568
+ transform: scale(1);
569
+ opacity: 1;
570
+ }
571
+ }
572
+
573
+ :global(.rt-go-sub) {
574
+ font-size: clamp(1.5rem, 5vw, 2.5rem);
575
+ font-weight: 800;
576
+ margin-top: 0.5rem;
577
+ text-transform: uppercase;
578
+ }
579
+
580
+ :global(.rt-early-content) {
581
+ text-align: center;
582
+ color: white;
583
+ padding: 2.5rem;
584
+ background: rgba(0, 0, 0, 0.1);
585
+ border-radius: 2rem;
586
+ backdrop-filter: blur(10px);
587
+ border: 1px solid rgba(255, 255, 255, 0.1);
588
+ }
589
+
590
+ :global(.rt-early-icon) {
591
+ margin-bottom: 1.5rem;
592
+ display: flex;
593
+ justify-content: center;
594
+ animation: rt-shake 0.5s ease-in-out;
595
+ }
596
+
597
+ @keyframes rt-shake {
598
+ 0%, 100% { transform: translateX(0); }
599
+ 25% { transform: translateX(-10px); }
600
+ 75% { transform: translateX(10px); }
601
+ }
602
+
603
+ :global(.rt-early-title) {
604
+ font-size: clamp(2rem, 8vw, 3.5rem);
605
+ font-weight: 900;
606
+ margin: 0 0 1rem;
607
+ letter-spacing: -0.03em;
608
+ }
609
+
610
+ :global(.rt-early-sub) {
611
+ font-size: 1.25rem;
612
+ opacity: 0.9;
613
+ margin: 0 0 2.5rem;
614
+ font-weight: 600;
615
+ }
616
+
617
+ :global(.rt-early-retry) {
618
+ display: inline-block;
619
+ padding: 1.15rem 2.25rem;
620
+ background: white;
621
+ color: #fb923c;
622
+ border-radius: 1.25rem;
623
+ font-weight: 800;
624
+ text-transform: uppercase;
625
+ cursor: pointer;
626
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
627
+ transition: all 0.2s ease;
628
+ }
629
+
630
+ :global(.rt-early-retry:hover) {
631
+ transform: translateY(-3px) scale(1.02);
632
+ box-shadow: 0 15px 35px rgba(0, 0, 0, 0.3);
633
+ }
634
+
635
+ :global(.rt-result-content) {
636
+ text-align: center;
637
+ color: white;
638
+ width: 100%;
639
+ max-width: 32rem;
640
+ padding: 2rem;
641
+ }
642
+
643
+ :global(.rt-time) {
644
+ font-size: clamp(4rem, 18vw, 9rem);
645
+ font-weight: 950;
646
+ letter-spacing: -0.05em;
647
+ line-height: 0.9;
648
+ margin-bottom: 1.5rem;
649
+ text-shadow: 0 10px 30px rgba(0, 0, 0, 0.4);
650
+ }
651
+
652
+ :global(.rt-feedback) {
653
+ font-size: clamp(1.25rem, 4vw, 2rem);
654
+ font-weight: 800;
655
+ margin-bottom: 3rem;
656
+ color: rgba(255, 255, 255, 0.95);
657
+ font-style: italic;
658
+ background: rgba(255, 255, 255, 0.1);
659
+ padding: 0.5rem 1.5rem;
660
+ border-radius: 99px;
661
+ display: inline-block;
662
+ }
663
+
664
+ :global(.rt-progress-track) {
665
+ width: 100%;
666
+ height: 0.6rem;
667
+ background: rgba(0, 0, 0, 0.3);
668
+ border-radius: 1rem;
669
+ overflow: hidden;
670
+ margin-bottom: 3rem;
671
+ border: 1px solid rgba(255, 255, 255, 0.05);
672
+ }
673
+
674
+ :global(.rt-progress-bar) {
675
+ height: 100%;
676
+ width: 0%;
677
+ background: #34d399;
678
+ box-shadow: 0 0 20px rgba(52, 211, 153, 0.6);
679
+ transition: width 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
680
+ }
681
+
682
+ :global(.rt-action) {
683
+ font-size: 1.15rem;
684
+ font-weight: 700;
685
+ opacity: 0.9;
686
+ display: flex;
687
+ align-items: center;
688
+ justify-content: center;
689
+ gap: 0.5rem;
690
+ animation: rt-bounce 0.8s ease-in-out infinite alternate;
691
+ text-transform: uppercase;
692
+ letter-spacing: 0.05em;
693
+ }
694
+
695
+ @keyframes rt-bounce {
696
+ from { transform: translateY(0); }
697
+ to { transform: translateY(-12px); }
698
+ }
699
+
700
+ :global(.rt-score-content) {
701
+ text-align: center;
702
+ width: 100%;
703
+ max-width: 42rem;
704
+ padding: 3rem 2rem;
705
+ margin: auto;
706
+ }
707
+
708
+ :global(.rt-rank-badge) {
709
+ display: inline-block;
710
+ padding: 0.75rem 2rem;
711
+ border-radius: 1.25rem;
712
+ color: white;
713
+ font-weight: 950;
714
+ font-size: 1.25rem;
715
+ text-transform: uppercase;
716
+ letter-spacing: 0.12em;
717
+ margin-bottom: 2rem;
718
+ box-shadow: 0 15px 35px rgba(0, 0, 0, 0.4);
719
+ transform: rotate(-3deg);
720
+ border: 2px solid rgba(255, 255, 255, 0.2);
721
+ }
722
+
723
+ :global(.rt-rank-ciberatleta) {
724
+ background: linear-gradient(135deg, #00d2ff, #3a7bd5);
725
+ }
726
+ :global(.rt-rank-tigre) {
727
+ background: linear-gradient(135deg, #fcead2, #f8d49a);
728
+ color: #854d0e;
729
+ border-color: #854d0e;
730
+ }
731
+ :global(.rt-rank-humano) {
732
+ background: linear-gradient(135deg, #43e97b, #38f9d7);
733
+ color: #065f46;
734
+ border-color: #065f46;
735
+ }
736
+ :global(.rt-rank-tortuga) {
737
+ background: linear-gradient(135deg, #bdc3c7, #2c3e50);
738
+ }
739
+ :global(.rt-rank-dormido) {
740
+ background: linear-gradient(135deg, #304352, #d7d2cc);
741
+ }
742
+
743
+ :global(.rt-final-wrap) {
744
+ margin: 0 0 1rem;
745
+ }
746
+
747
+ :global(.rt-final-avg) {
748
+ font-size: clamp(4rem, 18vw, 10rem);
749
+ font-weight: 950;
750
+ color: transparent;
751
+ background: linear-gradient(to bottom, #fff, #64748b);
752
+ -webkit-background-clip: text;
753
+ background-clip: text;
754
+ letter-spacing: -0.06em;
755
+ line-height: 0.8;
756
+ }
757
+
758
+ :global(.rt-final-unit) {
759
+ font-size: clamp(1.5rem, 4vw, 2.75rem);
760
+ color: #475569;
761
+ font-weight: 600;
762
+ margin-left: 0.35rem;
763
+ }
764
+
765
+ :global(.rt-avg-label) {
766
+ color: #64748b;
767
+ font-size: 1.1rem;
768
+ font-weight: 800;
769
+ margin: 0 0 2.5rem;
770
+ text-transform: uppercase;
771
+ letter-spacing: 0.15em;
772
+ }
773
+
774
+ :global(.rt-bars) {
775
+ display: flex;
776
+ justify-content: center;
777
+ align-items: flex-end;
778
+ gap: 0.6rem;
779
+ height: 120px;
780
+ margin-bottom: 3rem;
781
+ padding: 0 1rem;
782
+ }
783
+
784
+ :global(.rt-bar-item) {
785
+ flex: 1;
786
+ max-width: 3.5rem;
787
+ background: var(--primary);
788
+ border-radius: 0.75rem 0.75rem 0 0;
789
+ position: relative;
790
+ box-shadow: inset 0 2px 10px rgba(255, 255, 255, 0.2);
791
+ min-width: 20px;
792
+ }
793
+
794
+ :global(.rt-bar-tip) {
795
+ position: absolute;
796
+ top: -2.75rem;
797
+ left: 50%;
798
+ transform: translateX(-50%);
799
+ background: #000;
800
+ color: #fff;
801
+ font-size: 0.75rem;
802
+ font-weight: 850;
803
+ padding: 0.35rem 0.65rem;
804
+ border-radius: 0.5rem;
805
+ white-space: nowrap;
806
+ opacity: 0;
807
+ transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
808
+ pointer-events: none;
809
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
810
+ }
811
+
812
+ :global(.rt-bar-item:hover .rt-bar-tip) {
813
+ opacity: 1;
814
+ transform: translateX(-50%) translateY(-5px);
815
+ }
816
+
817
+ :global(.rt-share-grid) {
818
+ display: grid;
819
+ grid-template-columns: 1fr 1fr;
820
+ gap: 1.25rem;
821
+ width: 100%;
822
+ max-width: 28rem;
823
+ margin: 0 auto 1.5rem;
824
+ }
825
+
826
+ :global(.rt-btn-copy), :global(.rt-btn-tweet) {
827
+ display: flex;
828
+ align-items: center;
829
+ justify-content: center;
830
+ gap: 0.75rem;
831
+ color: white;
832
+ font-weight: 850;
833
+ padding: 1rem;
834
+ border-radius: 1.25rem;
835
+ cursor: pointer;
836
+ transition: all 0.3s ease;
837
+ font-size: 0.9rem;
838
+ text-transform: uppercase;
839
+ letter-spacing: 0.05em;
840
+ }
841
+
842
+ :global(.rt-btn-copy) {
843
+ background: #1e293b;
844
+ border: 1px solid rgba(255, 255, 255, 0.1);
845
+ }
846
+
847
+ :global(.rt-btn-copy:hover) {
848
+ background: #334155;
849
+ transform: translateY(-3px);
850
+ }
851
+
852
+ :global(.rt-btn-tweet) {
853
+ background: #1da1f2;
854
+ border: none;
855
+ }
856
+
857
+ :global(.rt-btn-tweet:hover) {
858
+ background: #0ea5e9;
859
+ transform: translateY(-3px);
860
+ }
861
+
862
+ :global(.rt-btn-retry) {
863
+ width: 100%;
864
+ max-width: 28rem;
865
+ background: white;
866
+ color: #0f172a;
867
+ font-weight: 900;
868
+ font-size: 1.25rem;
869
+ padding: 1.15rem;
870
+ border-radius: 1.5rem;
871
+ border: none;
872
+ cursor: pointer;
873
+ box-shadow: 0 15px 40px rgba(0, 0, 0, 0.5);
874
+ transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
875
+ text-transform: uppercase;
876
+ letter-spacing: 0.1em;
877
+ }
878
+
879
+ :global(.rt-btn-retry:hover) {
880
+ background: #f8fafc;
881
+ transform: translateY(-5px) scale(1.02);
882
+ box-shadow: 0 20px 50px rgba(0, 0, 0, 0.6);
883
+ }
884
+
885
+ :global(.rt-hints) {
886
+ display: flex;
887
+ flex-wrap: wrap;
888
+ justify-content: center;
889
+ gap: 1.5rem;
890
+ color: var(--text-muted);
891
+ font-size: 0.85rem;
892
+ font-weight: 700;
893
+ text-transform: uppercase;
894
+ letter-spacing: 0.1em;
895
+ }
896
+
897
+ :global(.rt-hint) {
898
+ display: flex;
899
+ align-items: center;
900
+ gap: 0.6rem;
901
+ }
902
+
903
+ :global(.rt-hint-key) {
904
+ padding: 0.3rem 0.6rem;
905
+ border: 2px solid var(--border-base);
906
+ border-radius: 0.6rem;
907
+ background: var(--bg-surface);
908
+ min-width: 2rem;
909
+ height: 2rem;
910
+ display: flex;
911
+ align-items: center;
912
+ justify-content: center;
913
+ font-size: 0.8rem;
914
+ color: var(--text-base);
915
+ box-shadow: 0 2px 5px var(--shadow-base);
916
+ }
917
+
918
+ :global(.rt-history) {
919
+ width: 100%;
920
+ display: flex;
921
+ flex-direction: column;
922
+ gap: 2rem;
923
+ margin-top: 1rem;
924
+ }
925
+
926
+ :global(.rt-history-title) {
927
+ font-size: 1.5rem;
928
+ font-weight: 900;
929
+ color: var(--text-base);
930
+ margin: 0;
931
+ text-align: center;
932
+ display: flex;
933
+ align-items: center;
934
+ justify-content: center;
935
+ gap: 0.85rem;
936
+ text-transform: uppercase;
937
+ letter-spacing: 0.1em;
938
+ }
939
+
940
+ :global(.rt-history-grid) {
941
+ display: grid;
942
+ grid-template-columns: 1fr;
943
+ gap: 1.5rem;
944
+ }
945
+
946
+ @media (min-width: 768px) {
947
+ :global(.rt-history-grid) {
948
+ grid-template-columns: 1fr 1fr;
949
+ }
950
+ }
951
+
952
+ :global(.rt-history-card) {
953
+ background: var(--bg-surface);
954
+ border: 1px solid var(--border-base);
955
+ border-radius: 2rem;
956
+ padding: 1.75rem;
957
+ box-shadow: 0 10px 25px var(--shadow-base);
958
+ transition: transform 0.3s ease;
959
+ }
960
+
961
+ :global(.rt-history-card:hover) {
962
+ transform: translateY(-5px);
963
+ }
964
+
965
+ :global(.rt-history-card-title) {
966
+ font-size: 0.85rem;
967
+ font-weight: 950;
968
+ text-transform: uppercase;
969
+ letter-spacing: 0.1em;
970
+ margin: 0 0 1.25rem;
971
+ padding-bottom: 1rem;
972
+ border-bottom: 1px solid var(--border-base);
973
+ display: flex;
974
+ align-items: center;
975
+ gap: 0.6rem;
976
+ }
977
+
978
+ :global(.rt-best-label) {
979
+ color: #10b981;
980
+ }
981
+ :global(.rt-worst-label) {
982
+ color: #f43f5e;
983
+ }
984
+
985
+ :global(.rt-list) {
986
+ list-style: none;
987
+ margin: 0;
988
+ padding: 0;
989
+ display: flex;
990
+ flex-direction: column;
991
+ gap: 0.75rem;
992
+ }
993
+
994
+ :global(.rt-list-empty) {
995
+ color: var(--text-muted);
996
+ font-size: 0.9rem;
997
+ font-style: italic;
998
+ text-align: center;
999
+ padding: 2rem;
1000
+ }
1001
+
1002
+ :global(.rt-history-entry) {
1003
+ display: flex;
1004
+ justify-content: space-between;
1005
+ align-items: center;
1006
+ background: var(--bg-page);
1007
+ border-radius: 1rem;
1008
+ padding: 0.75rem 1rem;
1009
+ border: 1px solid var(--border-base);
1010
+ transition: all 0.2s ease;
1011
+ }
1012
+
1013
+ :global(.rt-history-entry:hover) {
1014
+ transform: translateX(8px);
1015
+ border-color: var(--primary-soft);
1016
+ }
1017
+
1018
+ :global(.rt-entry-left) {
1019
+ display: flex;
1020
+ align-items: center;
1021
+ gap: 1rem;
1022
+ }
1023
+
1024
+ :global(.rt-entry-score) {
1025
+ font-weight: 900;
1026
+ font-size: 1.25rem;
1027
+ }
1028
+
1029
+ :global(.rt-score-best) {
1030
+ color: #10b981;
1031
+ }
1032
+ :global(.rt-score-worst) {
1033
+ color: #64748b;
1034
+ }
1035
+
1036
+ :global(.rt-entry-rank) {
1037
+ font-size: 0.7rem;
1038
+ padding: 0.25rem 0.6rem;
1039
+ border-radius: 0.6rem;
1040
+ background: var(--bg-surface);
1041
+ color: var(--text-muted);
1042
+ border: 1px solid var(--border-base);
1043
+ font-weight: 800;
1044
+ text-transform: uppercase;
1045
+ }
1046
+
1047
+ :global(.rt-entry-date) {
1048
+ font-size: 0.7rem;
1049
+ font-weight: 700;
1050
+ color: var(--text-muted);
1051
+ opacity: 0.7;
1052
+ }
1053
+
1054
+ :global(.rt-icon-xs) {
1055
+ width: 1.25rem;
1056
+ height: 1.25rem;
1057
+ }
1058
+ :global(.rt-icon-sm) {
1059
+ width: 1.75rem;
1060
+ height: 1.75rem;
1061
+ }
1062
+ :global(.rt-icon-md) {
1063
+ width: 2.25rem;
1064
+ height: 2.25rem;
1065
+ }
1066
+ :global(.rt-icon-xl) {
1067
+ width: 4.5rem;
1068
+ height: 4.5rem;
1069
+ }
1070
+
1071
+ :global(.theme-dark .rt-history-card) {
1072
+ background: rgba(255, 255, 255, 0.02);
1073
+ }
1074
+ </style>