@jjlmoya/utils-travel 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 (58) hide show
  1. package/package.json +60 -0
  2. package/src/category/i18n/en.ts +185 -0
  3. package/src/category/i18n/es.ts +187 -0
  4. package/src/category/i18n/fr.ts +100 -0
  5. package/src/category/index.ts +12 -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 +15 -0
  10. package/src/env.d.ts +5 -0
  11. package/src/index.ts +22 -0
  12. package/src/layouts/PreviewLayout.astro +117 -0
  13. package/src/pages/[locale]/[slug].astro +146 -0
  14. package/src/pages/[locale].astro +278 -0
  15. package/src/pages/index.astro +4 -0
  16. package/src/tests/faq_count.test.ts +8 -0
  17. package/src/tests/locale_completeness.test.ts +21 -0
  18. package/src/tests/mocks/astro_mock.js +2 -0
  19. package/src/tests/no_h1_in_components.test.ts +8 -0
  20. package/src/tests/seo_length.test.ts +8 -0
  21. package/src/tests/tool_validation.test.ts +17 -0
  22. package/src/tool/luggage-calculator/bibliography.astro +14 -0
  23. package/src/tool/luggage-calculator/component.astro +560 -0
  24. package/src/tool/luggage-calculator/i18n/en.ts +617 -0
  25. package/src/tool/luggage-calculator/i18n/es.ts +617 -0
  26. package/src/tool/luggage-calculator/i18n/fr.ts +549 -0
  27. package/src/tool/luggage-calculator/index.ts +53 -0
  28. package/src/tool/luggage-calculator/seo.astro +14 -0
  29. package/src/tool/mini-adventures/bibliography.astro +14 -0
  30. package/src/tool/mini-adventures/component.astro +665 -0
  31. package/src/tool/mini-adventures/i18n/en.ts +161 -0
  32. package/src/tool/mini-adventures/i18n/es.ts +286 -0
  33. package/src/tool/mini-adventures/i18n/fr.ts +144 -0
  34. package/src/tool/mini-adventures/index.ts +70 -0
  35. package/src/tool/mini-adventures/seo.astro +14 -0
  36. package/src/tool/optimal-routes/bibliography.astro +14 -0
  37. package/src/tool/optimal-routes/component.astro +439 -0
  38. package/src/tool/optimal-routes/i18n/en.ts +42 -0
  39. package/src/tool/optimal-routes/i18n/es.ts +52 -0
  40. package/src/tool/optimal-routes/index.ts +63 -0
  41. package/src/tool/optimal-routes/lib/RouteManager.ts +181 -0
  42. package/src/tool/optimal-routes/seo.astro +14 -0
  43. package/src/tool/suitcase-checklist/bibliography.astro +14 -0
  44. package/src/tool/suitcase-checklist/component.astro +710 -0
  45. package/src/tool/suitcase-checklist/i18n/en.ts +261 -0
  46. package/src/tool/suitcase-checklist/i18n/es.ts +261 -0
  47. package/src/tool/suitcase-checklist/i18n/fr.ts +259 -0
  48. package/src/tool/suitcase-checklist/index.ts +75 -0
  49. package/src/tool/suitcase-checklist/seo.astro +14 -0
  50. package/src/tool/tip-calculator/bibliography.astro +14 -0
  51. package/src/tool/tip-calculator/component.astro +683 -0
  52. package/src/tool/tip-calculator/i18n/en.ts +264 -0
  53. package/src/tool/tip-calculator/i18n/es.ts +264 -0
  54. package/src/tool/tip-calculator/i18n/fr.ts +264 -0
  55. package/src/tool/tip-calculator/index.ts +53 -0
  56. package/src/tool/tip-calculator/seo.astro +14 -0
  57. package/src/tools.ts +13 -0
  58. package/src/types.ts +73 -0
@@ -0,0 +1,710 @@
1
+ ---
2
+ import { Icon } from "astro-icon/components";
3
+ import type { SuitcaseChecklistUI } from "./index";
4
+
5
+ interface Props {
6
+ ui: SuitcaseChecklistUI;
7
+ }
8
+
9
+ const { ui } = Astro.props;
10
+ ---
11
+
12
+ <div class="suitcase-checklist">
13
+ <div class="sc-main-card">
14
+ <div class="sc-form" id="sc-form-container">
15
+ <div class="sc-header">
16
+ <h2>{ui.title}</h2>
17
+ </div>
18
+
19
+ <div class="sc-form-grid">
20
+ <div class="sc-form-group">
21
+ <label class="sc-label"><Icon name="mdi:map-marker-radius" /> {ui.form.destTitle}</label>
22
+ <div class="sc-radio-grid">
23
+ {ui.form.destTypes.map((type, idx) => (
24
+ <label class="sc-radio-card">
25
+ <input type="radio" name="dest-type" value={type.id} checked={idx === 0} />
26
+ <div class="sc-radio-content">
27
+ <Icon name={type.icon} />
28
+ <span>{type.name}</span>
29
+ </div>
30
+ </label>
31
+ ))}
32
+ </div>
33
+ </div>
34
+
35
+ <div class="sc-form-row">
36
+ <div class="sc-form-group">
37
+ <label class="sc-label"><Icon name="mdi:calendar-clock" /> {ui.form.daysTitle}</label>
38
+ <div class="sc-number-input">
39
+ <button type="button" class="sc-num-btn" id="sc-minus"><Icon name="mdi:minus" /></button>
40
+ <input type="number" id="sc-travel-days" value="3" min="1" max="90" readonly />
41
+ <button type="button" class="sc-num-btn" id="sc-plus"><Icon name="mdi:plus" /></button>
42
+ </div>
43
+ </div>
44
+
45
+ <div class="sc-form-group">
46
+ <label class="sc-label"><Icon name="mdi:earth" /> {ui.form.intlTitle}</label>
47
+ <label class="sc-toggle">
48
+ <input type="checkbox" id="sc-is-intl" />
49
+ <div class="sc-toggle-slider"></div>
50
+ <span>{ui.form.intlLabel}</span>
51
+ </label>
52
+ </div>
53
+ </div>
54
+
55
+ <div class="sc-form-group">
56
+ <label class="sc-label"><Icon name="mdi:briefcase-variant" /> {ui.form.reasonTitle}</label>
57
+ <div class="sc-radio-grid cols-2">
58
+ {ui.form.reasons.map((reason, idx) => (
59
+ <label class="sc-radio-card">
60
+ <input type="radio" name="travel-type" value={reason.id} checked={idx === 0} />
61
+ <div class="sc-radio-content">
62
+ <Icon name={reason.icon} />
63
+ <span>{reason.name}</span>
64
+ </div>
65
+ </label>
66
+ ))}
67
+ </div>
68
+ </div>
69
+ </div>
70
+
71
+ <button class="sc-submit-btn" id="sc-generate-btn">
72
+ <Icon name="mdi:magic" />
73
+ {ui.form.submitBtn}
74
+ </button>
75
+ </div>
76
+
77
+ <div class="sc-results hidden" id="sc-results-container">
78
+ <div class="sc-results-header">
79
+ <div class="sc-results-title">
80
+ <Icon name="mdi:bag-suitcase-outline" />
81
+ <h2>{ui.results.title}</h2>
82
+ </div>
83
+
84
+ <div class="sc-progress">
85
+ <div class="sc-progress-bar">
86
+ <div class="sc-progress-fill" id="sc-progress-fill"></div>
87
+ </div>
88
+ <span id="sc-progress-text">0% {ui.results.progressText}</span>
89
+ </div>
90
+
91
+ <div class="sc-actions">
92
+ <button class="sc-btn-outline" id="sc-back-btn">
93
+ <Icon name="mdi:arrow-left" />
94
+ {ui.results.editBtn}
95
+ </button>
96
+ <button class="sc-btn-primary" id="sc-print-btn">
97
+ <Icon name="mdi:printer" />
98
+ {ui.results.printBtn}
99
+ </button>
100
+ </div>
101
+ </div>
102
+
103
+ <div class="sc-tips" id="sc-tips-container">
104
+ <h3><Icon name="mdi:lightbulb-on" /> {ui.results.tipsTitle}</h3>
105
+ <ul id="sc-tips-list"></ul>
106
+ </div>
107
+
108
+ <div class="sc-categories">
109
+ {Object.values(ui.itemsDb).map(cat => (
110
+ <div class="sc-category-card" data-cat-id={cat.id}>
111
+ <div class="sc-category-header">
112
+ <Icon name={cat.icon} />
113
+ <h3>{cat.title}</h3>
114
+ </div>
115
+ <ul class="sc-item-list">
116
+ {cat.items.map(item => (
117
+ <li>
118
+ <label class="sc-checkbox">
119
+ <input type="checkbox" class="sc-item-cb" />
120
+ <div class="sc-cb-box"></div>
121
+ <span id={item.dynamicId}>{item.label}</span>
122
+ </label>
123
+ </li>
124
+ ))}
125
+ </ul>
126
+ </div>
127
+ ))}
128
+
129
+ {Object.values(ui.specificItems.destType).map(cat => (
130
+ <div class="sc-category-card hidden" data-cat-id={cat.id}>
131
+ <div class="sc-category-header">
132
+ <Icon name={cat.icon} />
133
+ <h3>{cat.title}</h3>
134
+ </div>
135
+ <ul class="sc-item-list">
136
+ {cat.items.map(item => (
137
+ <li>
138
+ <label class="sc-checkbox">
139
+ <input type="checkbox" class="sc-item-cb" />
140
+ <div class="sc-cb-box"></div>
141
+ <span id={item.dynamicId}>{item.label}</span>
142
+ </label>
143
+ </li>
144
+ ))}
145
+ </ul>
146
+ </div>
147
+ ))}
148
+
149
+ {Object.values(ui.specificItems.travelType).map(cat => (
150
+ <div class="sc-category-card hidden" data-cat-id={cat.id}>
151
+ <div class="sc-category-header">
152
+ <Icon name={cat.icon} />
153
+ <h3>{cat.title}</h3>
154
+ </div>
155
+ <ul class="sc-item-list">
156
+ {cat.items.map(item => (
157
+ <li>
158
+ <label class="sc-checkbox">
159
+ <input type="checkbox" class="sc-item-cb" />
160
+ <div class="sc-cb-box"></div>
161
+ <span id={item.dynamicId}>{item.label}</span>
162
+ </label>
163
+ </li>
164
+ ))}
165
+ </ul>
166
+ </div>
167
+ ))}
168
+ </div>
169
+ </div>
170
+ </div>
171
+ </div>
172
+
173
+ <script is:inline define:vars={{ ui }}>
174
+ const formContainer = document.getElementById("sc-form-container");
175
+ const resultsContainer = document.getElementById("sc-results-container");
176
+ const generateBtn = document.getElementById("sc-generate-btn");
177
+ const backBtn = document.getElementById("sc-back-btn");
178
+ const printBtn = document.getElementById("sc-print-btn");
179
+
180
+ const daysInput = document.getElementById("sc-travel-days");
181
+ const minusBtn = document.getElementById("sc-minus");
182
+ const plusBtn = document.getElementById("sc-plus");
183
+
184
+ const isIntlCheck = document.getElementById("sc-is-intl");
185
+
186
+ const progressFill = document.getElementById("sc-progress-fill");
187
+ const progressText = document.getElementById("sc-progress-text");
188
+ const tipsList = document.getElementById("sc-tips-list");
189
+
190
+ const qtyRopaInterior = document.getElementById("qty-ropa-interior");
191
+ const qtyCamisetas = document.getElementById("qty-camisetas");
192
+ const qtyPantalones = document.getElementById("qty-pantalones");
193
+ const qtyCalcetines = document.getElementById("qty-calcetines");
194
+ const itemIntl = document.getElementById("item-internacional");
195
+ const itemAdap = document.getElementById("item-adaptador");
196
+
197
+ function getSelectedRadio(name) {
198
+ return document.querySelector(`input[name="${name}"]:checked`)?.value;
199
+ }
200
+
201
+ function calculateQuantities(days) {
202
+ const max = 14;
203
+ if (qtyRopaInterior) qtyRopaInterior.textContent = `${ui.itemsDb.clothing_base.items[0].label} (${Math.min(days + 1, max)} mudas)`;
204
+ if (qtyCamisetas) qtyCamisetas.textContent = `${ui.itemsDb.clothing_base.items[1].label} (${Math.min(days, max)} ud.)`;
205
+ if (qtyPantalones) qtyPantalones.textContent = `${ui.itemsDb.clothing_base.items[2].label} (${Math.min(Math.ceil(days / 2) + 1, 8)} ud.)`;
206
+ if (qtyCalcetines) qtyCalcetines.textContent = `${ui.itemsDb.clothing_base.items[3].label} (${Math.min(days + 1, max)} pares)`;
207
+ }
208
+
209
+ function updateProgress() {
210
+ const total = document.querySelectorAll(".sc-category-card:not(.hidden) .sc-item-cb").length;
211
+ const checked = document.querySelectorAll(".sc-category-card:not(.hidden) .sc-item-cb:checked").length;
212
+ const perc = total === 0 ? 0 : Math.round((checked / total) * 100);
213
+
214
+ if (progressFill) progressFill.style.width = `${perc}%`;
215
+ if (progressText) progressText.textContent = `${perc}% ${ui.results.progressText}`;
216
+ }
217
+
218
+ function generateTips(days, isIntl, dType) {
219
+ const tips = [ui.tips.military];
220
+ if (days > 7) tips.push(ui.tips.longTravel);
221
+ if (isIntl) {
222
+ tips.push(ui.tips.intlPassport);
223
+ tips.push(ui.tips.intlBank);
224
+ tips.push(ui.tips.intlAdapter);
225
+ }
226
+ if (dType === "frio") {
227
+ tips.push(ui.tips.coldLayers);
228
+ tips.push(ui.tips.coldHeavyOn);
229
+ }
230
+ if (dType === "playa") tips.push(ui.tips.beachWet);
231
+
232
+ if (tipsList) {
233
+ tipsList.innerHTML = tips.map(t => `<li>${t}</li>`).join("");
234
+ }
235
+ }
236
+
237
+ minusBtn?.addEventListener("click", () => {
238
+ const val = parseInt(daysInput.value);
239
+ if (val > 1) daysInput.value = val - 1;
240
+ });
241
+
242
+ plusBtn?.addEventListener("click", () => {
243
+ const val = parseInt(daysInput.value);
244
+ if (val < 90) daysInput.value = val + 1;
245
+ });
246
+
247
+ generateBtn?.addEventListener("click", () => {
248
+ const days = parseInt(daysInput.value);
249
+ const dType = getSelectedRadio("dest-type");
250
+ const tType = getSelectedRadio("travel-type");
251
+ const isIntl = isIntlCheck.checked;
252
+
253
+ document.querySelectorAll(".sc-category-card[data-cat-id^='dest-'], .sc-category-card[data-cat-id^='travel-']").forEach(el => el.classList.add("hidden"));
254
+
255
+ document.querySelector(`.sc-category-card[data-cat-id="dest-${dType}"]`)?.classList.remove("hidden");
256
+ document.querySelector(`.sc-category-card[data-cat-id="travel-${tType}"]`)?.classList.remove("hidden");
257
+
258
+ calculateQuantities(days);
259
+ if (itemIntl) itemIntl.parentElement.parentElement.style.display = isIntl ? "flex" : "none";
260
+ if (itemAdap) itemAdap.parentElement.parentElement.style.display = isIntl ? "flex" : "none";
261
+
262
+ generateTips(days, isIntl, dType);
263
+
264
+ formContainer.classList.add("hidden");
265
+ resultsContainer.classList.remove("hidden");
266
+ updateProgress();
267
+ resultsContainer.scrollIntoView({ behavior: "smooth" });
268
+ });
269
+
270
+ backBtn?.addEventListener("click", () => {
271
+ resultsContainer.classList.add("hidden");
272
+ formContainer.classList.remove("hidden");
273
+ });
274
+
275
+ printBtn?.addEventListener("click", () => window.print());
276
+
277
+ document.querySelectorAll(".sc-item-cb").forEach(cb => {
278
+ cb.addEventListener("change", updateProgress);
279
+ });
280
+ </script>
281
+
282
+ <style>
283
+ .suitcase-checklist {
284
+ --sc-primary: #3b82f6;
285
+ --sc-primary-hover: #2563eb;
286
+ --sc-bg: #f8fafc;
287
+ --sc-card-bg: #fff;
288
+ --sc-text: #1e293b;
289
+ --sc-text-muted: #64748b;
290
+ --sc-border: #e2e8f0;
291
+ --sc-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
292
+ }
293
+
294
+ :global(.theme-dark) .suitcase-checklist {
295
+ --sc-bg: #0f172a;
296
+ --sc-card-bg: #1e293b;
297
+ --sc-text: #f1f5f9;
298
+ --sc-text-muted: #94a3b8;
299
+ --sc-border: #334155;
300
+ --sc-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.5);
301
+ }
302
+
303
+ .sc-main-card {
304
+ background: var(--sc-card-bg);
305
+ border-radius: 2rem;
306
+ padding: 2.5rem;
307
+ box-shadow: var(--sc-shadow);
308
+ border: 1px solid var(--sc-border);
309
+ }
310
+
311
+ .sc-header h2 {
312
+ font-size: 2rem;
313
+ font-weight: 800;
314
+ margin-bottom: 2rem;
315
+ text-align: center;
316
+ }
317
+
318
+ .sc-form-grid {
319
+ display: grid;
320
+ gap: 2rem;
321
+ }
322
+
323
+ .sc-label {
324
+ display: flex;
325
+ align-items: center;
326
+ gap: 0.5rem;
327
+ font-weight: 700;
328
+ margin-bottom: 1rem;
329
+ color: var(--sc-text-muted);
330
+ text-transform: uppercase;
331
+ font-size: 0.85rem;
332
+ }
333
+
334
+ .sc-radio-grid {
335
+ display: grid;
336
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
337
+ gap: 1rem;
338
+ }
339
+
340
+ .sc-radio-card {
341
+ position: relative;
342
+ cursor: pointer;
343
+ }
344
+
345
+ .sc-radio-card input {
346
+ position: absolute;
347
+ opacity: 0;
348
+ }
349
+
350
+ .sc-radio-content {
351
+ display: flex;
352
+ flex-direction: column;
353
+ align-items: center;
354
+ gap: 0.75rem;
355
+ padding: 1.5rem;
356
+ background: var(--sc-bg);
357
+ border: 2px solid var(--sc-border);
358
+ border-radius: 1.25rem;
359
+ transition: all 0.2s;
360
+ }
361
+
362
+ .sc-radio-content svg {
363
+ font-size: 2rem;
364
+ }
365
+
366
+ .sc-radio-card input:checked + .sc-radio-content {
367
+ border-color: var(--sc-primary);
368
+ background: rgba(59, 130, 246, 0.1);
369
+ color: var(--sc-primary);
370
+ }
371
+
372
+ .sc-form-row {
373
+ display: grid;
374
+ grid-template-columns: 1fr 1fr;
375
+ gap: 2rem;
376
+ }
377
+
378
+ .sc-number-input {
379
+ display: flex;
380
+ align-items: center;
381
+ background: var(--sc-bg);
382
+ padding: 0.25rem;
383
+ border-radius: 1rem;
384
+ border: 1px solid var(--sc-border);
385
+ width: 100%;
386
+ min-height: 56px;
387
+ }
388
+
389
+ .sc-num-btn {
390
+ width: 40px;
391
+ height: 40px;
392
+ border-radius: 0.75rem;
393
+ border: none;
394
+ background: var(--sc-card-bg);
395
+ color: var(--sc-primary);
396
+ cursor: pointer;
397
+ box-shadow: 0 2px 4px rgba(0,0,0,0.05);
398
+ }
399
+
400
+ .sc-number-input input {
401
+ flex: 1;
402
+ text-align: center;
403
+ background: transparent;
404
+ border: none;
405
+ font-size: 1.25rem;
406
+ font-weight: 800;
407
+ color: var(--sc-text);
408
+ }
409
+
410
+ .sc-toggle {
411
+ display: flex;
412
+ align-items: center;
413
+ gap: 1rem;
414
+ cursor: pointer;
415
+ }
416
+
417
+ .sc-toggle-slider {
418
+ width: 50px;
419
+ height: 26px;
420
+ background: #cbd5e1;
421
+ border-radius: 13px;
422
+ position: relative;
423
+ transition: 0.3s;
424
+ }
425
+
426
+ .sc-toggle-slider::after {
427
+ content: '';
428
+ position: absolute;
429
+ width: 20px;
430
+ height: 20px;
431
+ background: white;
432
+ border-radius: 50%;
433
+ top: 3px;
434
+ left: 3px;
435
+ transition: 0.3s;
436
+ }
437
+
438
+ .sc-toggle input:checked + .sc-toggle-slider {
439
+ background: var(--sc-primary);
440
+ }
441
+
442
+ .sc-toggle input:checked + .sc-toggle-slider::after {
443
+ left: 27px;
444
+ }
445
+
446
+ .sc-toggle input { display: none; }
447
+
448
+ .sc-submit-btn {
449
+ display: flex;
450
+ align-items: center;
451
+ justify-content: center;
452
+ gap: 0.75rem;
453
+ width: 100%;
454
+ padding: 1.25rem;
455
+ margin-top: 2rem;
456
+ background: var(--sc-primary);
457
+ color: white;
458
+ border: none;
459
+ border-radius: 1.25rem;
460
+ font-size: 1.1rem;
461
+ font-weight: 700;
462
+ cursor: pointer;
463
+ transition: 0.2s;
464
+ }
465
+
466
+ .sc-submit-btn:hover {
467
+ background: var(--sc-primary-hover);
468
+ transform: translateY(-2px);
469
+ }
470
+
471
+ .sc-results.hidden { display: none; }
472
+ .hidden { display: none; }
473
+
474
+ .sc-results-header {
475
+ display: flex;
476
+ justify-content: space-between;
477
+ align-items: center;
478
+ margin-bottom: 2rem;
479
+ flex-wrap: wrap;
480
+ gap: 1.5rem;
481
+ }
482
+
483
+ .sc-results-title {
484
+ display: flex;
485
+ align-items: center;
486
+ gap: 1rem;
487
+ }
488
+
489
+ .sc-results-title svg {
490
+ font-size: 2.5rem;
491
+ color: var(--sc-primary);
492
+ }
493
+ .sc-results-title h2 {
494
+ margin: 0;
495
+ }
496
+
497
+ .sc-progress {
498
+ display: flex;
499
+ flex-direction: column;
500
+ gap: 0.5rem;
501
+ min-width: 200px;
502
+ }
503
+
504
+ .sc-progress-bar {
505
+ height: 10px;
506
+ background: var(--sc-bg);
507
+ border-radius: 5px;
508
+ overflow: hidden;
509
+ }
510
+
511
+ .sc-progress-fill {
512
+ height: 100%;
513
+ background: var(--sc-primary);
514
+ width: 0%;
515
+ transition: width 0.3s;
516
+ }
517
+
518
+ .sc-progress span {
519
+ font-size: 0.85rem;
520
+ font-weight: 700;
521
+ color: var(--sc-text-muted);
522
+ }
523
+
524
+ .sc-actions {
525
+ display: flex;
526
+ gap: 1rem;
527
+ }
528
+
529
+ .sc-btn-outline {
530
+ display: flex;
531
+ align-items: center;
532
+ gap: 0.5rem;
533
+ padding: 0.75rem 1.25rem;
534
+ border: 2px solid var(--sc-border);
535
+ border-radius: 1rem;
536
+ background: transparent;
537
+ color: var(--sc-text);
538
+ font-weight: 700;
539
+ cursor: pointer;
540
+ }
541
+
542
+ .sc-btn-primary {
543
+ display: flex;
544
+ align-items: center;
545
+ gap: 0.5rem;
546
+ padding: 0.75rem 1.25rem;
547
+ background: var(--sc-primary);
548
+ border: none;
549
+ border-radius: 1rem;
550
+ color: white;
551
+ font-weight: 700;
552
+ cursor: pointer;
553
+ }
554
+
555
+ .sc-tips {
556
+ background: var(--sc-bg);
557
+ padding: 2rem;
558
+ border-radius: 1.5rem;
559
+ margin-bottom: 2.5rem;
560
+ }
561
+
562
+ .sc-tips h3 {
563
+ display: flex;
564
+ align-items: center;
565
+ gap: 0.75rem;
566
+ margin-top: 0;
567
+ color: var(--sc-primary);
568
+ }
569
+ .sc-tips ul {
570
+ margin: 0;
571
+ padding-left: 1.5rem;
572
+ display: grid;
573
+ grid-template-columns: 1fr 1fr;
574
+ gap: 1rem;
575
+ }
576
+ .sc-tips li {
577
+ font-size: 0.95rem;
578
+ line-height: 1.5;
579
+ color: var(--sc-text-muted);
580
+ }
581
+
582
+ .sc-categories {
583
+ display: grid;
584
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
585
+ gap: 2rem;
586
+ }
587
+
588
+ .sc-category-card {
589
+ background: var(--sc-bg);
590
+ border-radius: 1.5rem;
591
+ padding: 1.5rem;
592
+ border: 1px solid var(--sc-border);
593
+ }
594
+
595
+ .sc-category-header {
596
+ display: flex;
597
+ align-items: center;
598
+ gap: 0.75rem;
599
+ margin-bottom: 1.5rem;
600
+ padding-bottom: 0.75rem;
601
+ border-bottom: 2px solid var(--sc-border);
602
+ }
603
+
604
+ .sc-category-header h3 {
605
+ margin: 0;
606
+ font-size: 1.1rem;
607
+ }
608
+ .sc-category-header svg {
609
+ color: var(--sc-primary);
610
+ font-size: 1.5rem;
611
+ }
612
+
613
+ .sc-item-list {
614
+ list-style: none;
615
+ padding: 0;
616
+ margin: 0;
617
+ }
618
+ .sc-item-list li {
619
+ margin-bottom: 0.75rem;
620
+ }
621
+
622
+ .sc-checkbox {
623
+ display: flex;
624
+ align-items: center;
625
+ gap: 1rem;
626
+ cursor: pointer;
627
+ font-size: 1rem;
628
+ font-weight: 500;
629
+ }
630
+
631
+ .sc-cb-box {
632
+ width: 24px;
633
+ height: 24px;
634
+ background: var(--sc-card-bg);
635
+ border: 2px solid var(--sc-border);
636
+ border-radius: 6px;
637
+ position: relative;
638
+ transition: 0.2s;
639
+ flex-shrink: 0;
640
+ }
641
+
642
+ .sc-checkbox input {
643
+ display: none;
644
+ }
645
+ .sc-checkbox input:checked + .sc-cb-box {
646
+ background: var(--sc-primary);
647
+ border-color: var(--sc-primary);
648
+ }
649
+
650
+ .sc-checkbox input:checked + .sc-cb-box::after {
651
+ content: 'X';
652
+ position: absolute;
653
+ color: white;
654
+ font-size: 14px;
655
+ top: 50%;
656
+ left: 50%;
657
+ transform: translate(-50%, -50%);
658
+ }
659
+
660
+ .sc-checkbox input:checked ~ span {
661
+ opacity: 0.5;
662
+ text-decoration: line-through;
663
+ }
664
+
665
+ @media print {
666
+ .sc-form,
667
+ .sc-actions,
668
+ .sc-tips,
669
+ .sc-results-header {
670
+ display: none;
671
+ }
672
+ .suitcase-checklist {
673
+ padding: 0;
674
+ margin: 0;
675
+ max-width: 100%;
676
+ }
677
+ .sc-main-card {
678
+ border: none;
679
+ box-shadow: none;
680
+ padding: 0;
681
+ }
682
+ .sc-results.hidden {
683
+ display: block;
684
+ }
685
+ .sc-categories {
686
+ grid-template-columns: 1fr 1fr;
687
+ gap: 1rem;
688
+ }
689
+ .sc-category-card {
690
+ break-inside: avoid;
691
+ }
692
+ .sc-results-title {
693
+ display: block;
694
+ margin-bottom: 1rem;
695
+ }
696
+ }
697
+
698
+ @media (max-width: 768px) {
699
+ .sc-form-row {
700
+ grid-template-columns: 1fr;
701
+ }
702
+ .sc-tips ul {
703
+ grid-template-columns: 1fr;
704
+ }
705
+ .sc-results-header {
706
+ flex-direction: column;
707
+ align-items: stretch;
708
+ }
709
+ }
710
+ </style>