MatteoScript commited on
Commit
707889b
·
verified ·
1 Parent(s): 9b16e24

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +289 -309
index.html CHANGED
@@ -8,32 +8,45 @@
8
 
9
  <link rel="preconnect" href="https://fonts.googleapis.com">
10
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11
- <link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;600;700;800;900&display=swap" rel="stylesheet">
12
 
13
  <style>
 
 
 
 
 
 
 
 
 
 
 
 
14
  :root {
15
  --blue: #254B6B;
16
- --blue-muted: #8FA3B3;
17
  --olive: #939675;
18
  --sage: #C2C5B2;
19
  --coral: #D08A7A;
20
  --rose: #EDD3CD;
21
  --cream: #F3EFE9;
22
  --paper: #FFFDF8;
23
- --ink-soft: rgba(37, 75, 107, .68);
24
- --line: rgba(147, 150, 117, .34);
25
- --shadow: 0 28px 70px rgba(37, 75, 107, .13);
26
- --font: "Montserrat", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
 
27
  }
28
 
29
  * { box-sizing: border-box; }
30
 
31
  html,
32
  body {
33
- margin: 0;
34
- min-height: 100%;
35
  width: 100%;
36
- font-family: var(--font);
 
 
37
  color: var(--blue);
38
  background: var(--cream);
39
  overflow-x: hidden;
@@ -42,193 +55,169 @@
42
  body {
43
  min-height: 100svh;
44
  background:
45
- radial-gradient(circle at 82% 12%, rgba(237, 211, 205, .42), transparent 28%),
46
- radial-gradient(circle at 10% 90%, rgba(194, 197, 178, .42), transparent 30%),
47
- linear-gradient(180deg, #fffdf8 0%, #f3efe9 100%);
 
 
48
  }
49
 
50
- body::before {
 
 
 
 
 
 
 
 
51
  content: "";
52
  position: fixed;
53
- right: -26vw;
54
- top: -4vh;
55
- width: 105vw;
56
- height: 96vh;
57
  pointer-events: none;
58
- opacity: .13;
59
- background: repeating-conic-gradient(
60
- from 205deg at 72% 52%,
61
- transparent 0deg 6deg,
62
- rgba(147, 150, 117, .70) 6deg 8deg,
63
- transparent 8deg 14deg
64
- );
65
- transform: rotate(-10deg);
66
- z-index: 0;
67
  }
68
 
69
- body::after {
70
  content: "";
71
  position: fixed;
72
- inset: auto -14vw -16vh -14vw;
73
- height: 33vh;
 
 
 
 
 
74
  pointer-events: none;
75
- opacity: .18;
76
- background:
77
- radial-gradient(80% 90% at 50% 0%, rgba(143, 163, 179, .65) 0 11%, transparent 12%),
78
- radial-gradient(80% 90% at 16% 7%, rgba(143, 163, 179, .48) 0 11%, transparent 12%),
79
- radial-gradient(80% 90% at 84% 6%, rgba(143, 163, 179, .42) 0 11%, transparent 12%);
80
- animation: wave 9s ease-in-out infinite alternate;
81
- z-index: 0;
82
- }
83
-
84
- @keyframes wave {
85
- from { transform: translateX(-3vw) rotate(-1deg); }
86
- to { transform: translateX(3vw) translateY(-1vh) rotate(1deg); }
87
  }
88
 
89
- .app {
90
  position: relative;
91
  z-index: 1;
 
92
  min-height: 100svh;
 
93
  display: grid;
94
- place-items: center;
95
- padding: max(18px, env(safe-area-inset-top)) 18px max(22px, env(safe-area-inset-bottom));
96
  }
97
 
98
- .card {
99
- position: relative;
100
- width: min(100%, 440px);
101
- min-height: min(92svh, 760px);
102
  display: flex;
103
- flex-direction: column;
104
  justify-content: center;
105
- overflow: hidden;
106
- border-radius: 34px;
107
- background: rgba(255, 253, 248, .80);
108
- border: 1px solid rgba(37, 75, 107, .10);
109
- box-shadow: var(--shadow);
110
- backdrop-filter: blur(16px);
111
- -webkit-backdrop-filter: blur(16px);
112
- animation: enter .7s cubic-bezier(.2,.86,.2,1.08) both;
113
- }
114
-
115
- .card::before {
116
- content: "";
117
- position: absolute;
118
- inset: 22px;
119
- border: 1px solid rgba(147, 150, 117, .28);
120
- border-radius: 26px;
121
- pointer-events: none;
122
  }
123
 
124
- .card::after {
125
- content: "";
126
- position: absolute;
127
- left: 50%;
128
- top: 23%;
129
- width: 220px;
130
- height: 220px;
131
- transform: translate(-50%, -50%);
132
  border-radius: 50%;
133
- background: rgba(237, 211, 205, .34);
134
- filter: blur(.2px);
135
- pointer-events: none;
136
- z-index: -1;
 
137
  }
138
 
139
- @keyframes enter {
140
- from { opacity: 0; transform: translateY(22px) scale(.98); }
141
- to { opacity: 1; transform: translateY(0) scale(1); }
 
142
  }
143
 
144
  .hero {
145
- position: relative;
146
- padding: 42px 30px 24px;
147
  text-align: center;
 
148
  }
149
 
150
- .mini-mark {
151
- width: 54px;
152
- height: 54px;
153
- margin: 0 auto 24px;
154
- display: grid;
155
- place-items: center;
156
- border-radius: 50%;
157
- border: 1px dashed rgba(208, 138, 122, .70);
158
- color: var(--coral);
159
- font-size: 24px;
160
- background: rgba(255, 253, 248, .62);
161
- }
162
-
163
- h1 {
164
  margin: 0 auto;
165
- max-width: 8ch;
166
  color: var(--blue);
167
- font-size: clamp(50px, 14vw, 76px);
168
- line-height: .90;
169
- letter-spacing: -.065em;
170
- font-weight: 800;
 
171
  text-wrap: balance;
172
  }
173
 
174
- .map-line {
175
- width: min(72%, 250px);
176
- margin: 32px auto 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
177
  color: var(--olive);
178
- opacity: .82;
179
  }
180
 
181
- .map-line svg {
182
  width: 100%;
183
  height: auto;
184
  display: block;
185
  overflow: visible;
186
  }
187
 
188
- .map-line path {
189
  fill: none;
190
  stroke: currentColor;
191
- stroke-width: 2.8;
192
  stroke-linecap: round;
193
  stroke-linejoin: round;
194
- stroke-dasharray: 520;
195
- stroke-dashoffset: 520;
196
- animation: draw 1.4s ease .35s forwards;
197
  }
198
 
199
  @keyframes draw { to { stroke-dashoffset: 0; } }
200
 
201
- .form {
202
- position: relative;
203
- padding: 4px 30px 44px;
204
  }
205
 
206
- label {
207
  display: block;
208
- margin: 0 0 12px;
209
- color: rgba(37, 75, 107, .70);
210
  font-size: 11px;
211
  font-weight: 800;
212
- letter-spacing: .16em;
213
  text-transform: uppercase;
214
  }
215
 
 
 
 
 
216
  input {
217
  width: 100%;
218
- min-height: 64px;
219
- border: 0;
220
- outline: none;
221
- border-radius: 18px;
222
- padding: 0 18px;
223
  color: var(--blue);
224
- background: rgba(255, 255, 255, .88);
225
- font-family: var(--font);
226
- font-size: 17px;
227
  font-weight: 600;
228
- box-shadow:
229
- inset 0 0 0 1px rgba(37, 75, 107, .12),
230
- 0 12px 26px rgba(37, 75, 107, .08);
231
- transition: transform .18s ease, box-shadow .18s ease, background .18s ease;
232
  }
233
 
234
  input::placeholder {
@@ -237,68 +226,51 @@
237
  }
238
 
239
  input:focus {
240
- transform: translateY(-1px);
241
- background: #fff;
242
- box-shadow:
243
- inset 0 0 0 2px rgba(208, 138, 122, .42),
244
- 0 16px 32px rgba(37, 75, 107, .12);
245
  }
246
 
247
  .discover {
248
  position: relative;
249
  width: 100%;
250
- min-height: 64px;
251
- margin-top: 14px;
252
  border: 0;
253
- border-radius: 18px;
254
  overflow: hidden;
255
  cursor: pointer;
256
  color: var(--paper);
257
  background: var(--blue);
258
- box-shadow: 0 16px 32px rgba(37, 75, 107, .20);
259
- font-family: var(--font);
260
- font-size: 16px;
261
  font-weight: 800;
262
- letter-spacing: .01em;
 
263
  transition: transform .16s ease, background .16s ease, box-shadow .16s ease;
264
  }
265
 
266
- .discover::before {
267
- content: "";
268
- position: absolute;
269
- inset: 0;
270
- background: linear-gradient(110deg, transparent 0 35%, rgba(255,255,255,.20) 47%, transparent 60% 100%);
271
- transform: translateX(-120%);
272
- animation: shine 3.5s ease-in-out infinite;
273
- }
274
-
275
  .discover::after {
276
  content: "";
277
  position: absolute;
278
  left: 50%;
279
  bottom: 10px;
280
- width: 58px;
281
  height: 2px;
282
  border-radius: 999px;
283
  background: var(--coral);
284
  transform: translateX(-50%);
285
- opacity: .92;
286
- }
287
-
288
- @keyframes shine {
289
- 0%, 55% { transform: translateX(-120%); }
290
- 100% { transform: translateX(120%); }
291
  }
292
 
293
  .discover:active {
294
- transform: translateY(2px) scale(.99);
295
- background: #1f405c;
296
- box-shadow: 0 10px 24px rgba(37, 75, 107, .18);
297
  }
298
 
299
  .message {
300
  min-height: 0;
301
- margin-top: 14px;
302
  opacity: 0;
303
  transform: translateY(8px);
304
  transition: opacity .24s ease, transform .24s ease;
@@ -311,15 +283,15 @@
311
 
312
  .message-card {
313
  border-radius: 18px;
314
- padding: 15px 16px;
315
- text-align: center;
316
  color: rgba(37, 75, 107, .78);
317
- background: rgba(255, 255, 255, .72);
318
- border: 1px solid rgba(37, 75, 107, .09);
319
- box-shadow: 0 12px 24px rgba(37, 75, 107, .08);
320
  font-size: 13px;
321
- font-weight: 600;
322
  line-height: 1.35;
 
 
323
  }
324
 
325
  .reveal {
@@ -328,150 +300,135 @@
328
  z-index: 20;
329
  display: grid;
330
  place-items: center;
331
- padding: max(18px, env(safe-area-inset-top)) 16px max(20px, env(safe-area-inset-bottom));
332
  color: var(--blue);
333
  background:
334
- radial-gradient(circle at 84% 12%, rgba(237, 211, 205, .50), transparent 30%),
335
- radial-gradient(circle at 12% 88%, rgba(194, 197, 178, .46), transparent 33%),
336
- linear-gradient(180deg, #fffdf8 0%, #f3efe9 100%);
337
  opacity: 0;
 
338
  pointer-events: none;
339
- transform: scale(1.02);
340
- transition: opacity .42s ease, transform .42s ease;
341
  overflow: hidden;
342
  }
343
 
344
- .reveal.show {
345
- opacity: 1;
346
- pointer-events: auto;
347
- transform: scale(1);
 
 
 
348
  }
349
 
350
- .reveal::before {
351
  content: "";
352
  position: absolute;
353
- right: -26vw;
354
- top: -4vh;
355
- width: 105vw;
356
- height: 96vh;
357
- opacity: .13;
358
- background: repeating-conic-gradient(
359
- from 205deg at 72% 52%,
360
- transparent 0deg 6deg,
361
- rgba(147, 150, 117, .70) 6deg 8deg,
362
- transparent 8deg 14deg
363
- );
364
- transform: rotate(-10deg);
365
- z-index: 0;
 
 
 
366
  }
367
 
368
- .reveal-content {
369
  position: relative;
370
  z-index: 2;
371
  width: min(100%, 560px);
372
- min-height: min(82svh, 760px);
373
  display: flex;
374
  flex-direction: column;
375
- align-items: center;
376
  justify-content: center;
377
  text-align: center;
378
- border-radius: 34px;
379
- padding: 34px 22px;
380
- background: rgba(255, 253, 248, .82);
381
- border: 1px solid rgba(37, 75, 107, .10);
382
- box-shadow: 0 30px 90px rgba(37, 75, 107, .15);
383
- backdrop-filter: blur(16px);
384
- -webkit-backdrop-filter: blur(16px);
385
- animation: revealPop .72s cubic-bezier(.2,.9,.16,1.18) both;
386
- overflow: hidden;
387
  }
388
 
389
- .reveal-content::before {
390
- content: "";
391
- position: absolute;
392
- inset: 22px;
393
- border: 1px solid rgba(147, 150, 117, .28);
394
- border-radius: 26px;
395
- pointer-events: none;
396
  }
397
 
398
- .reveal-content::after {
399
- content: "";
400
- position: absolute;
401
- left: 50%;
402
- top: 27%;
403
- width: 250px;
404
- height: 250px;
405
- transform: translate(-50%, -50%);
406
- border-radius: 50%;
407
- background: rgba(237, 211, 205, .34);
408
- z-index: -1;
409
- }
410
-
411
- @keyframes revealPop {
412
- from { opacity: 0; transform: translateY(28px) scale(.92); filter: blur(7px); }
413
- 60% { opacity: 1; transform: translateY(-3px) scale(1.02); filter: blur(0); }
414
- to { opacity: 1; transform: translateY(0) scale(1); filter: blur(0); }
415
  }
416
 
417
  .hello {
418
- margin: 0 0 28px;
419
- color: rgba(37, 75, 107, .68);
420
- font-size: clamp(14px, 4.2vw, 19px);
421
- font-weight: 600;
422
  letter-spacing: .02em;
423
  }
424
 
425
- .small-title {
426
- margin-bottom: 18px;
427
  color: var(--coral);
428
  font-size: 12px;
429
  font-weight: 800;
430
- letter-spacing: .18em;
431
  text-transform: uppercase;
432
  }
433
 
434
  .table-name {
435
- margin: 0;
436
  max-width: 11ch;
437
  color: var(--blue);
438
- font-family: var(--font);
439
- font-size: clamp(48px, 14vw, 92px);
440
- line-height: .92;
441
- letter-spacing: -.055em;
442
- font-weight: 800;
443
  text-wrap: balance;
444
  }
445
 
446
- .divider {
447
- width: 92px;
 
 
 
 
 
448
  height: 2px;
449
- margin: 28px auto 22px;
450
  border-radius: 999px;
451
- background: var(--coral);
 
452
  }
453
 
454
  .reveal-note {
455
- margin: 0 auto;
456
  max-width: 28ch;
457
- color: rgba(37, 75, 107, .68);
458
  font-size: 15px;
459
- line-height: 1.38;
460
  font-weight: 500;
461
  }
462
 
463
  .again {
 
464
  min-height: 52px;
465
- margin-top: 30px;
466
- border: 0;
467
  border-radius: 999px;
468
  padding: 0 24px;
469
- color: var(--paper);
470
- background: var(--blue);
471
- box-shadow: 0 16px 36px rgba(37,75,107,.20);
472
- font-family: var(--font);
473
- font-size: 14px;
474
  font-weight: 800;
 
475
  cursor: pointer;
476
  }
477
 
@@ -494,13 +451,13 @@
494
  }
495
 
496
  @media (max-width: 380px) {
497
- .app { padding-left: 12px; padding-right: 12px; }
498
- .card { min-height: 90svh; border-radius: 30px; }
499
- .hero { padding: 36px 22px 22px; }
500
- h1 { font-size: clamp(48px, 15vw, 70px); }
501
- .form { padding-left: 22px; padding-right: 22px; }
502
- input, .discover { min-height: 60px; }
503
- .reveal-content { border-radius: 30px; padding-left: 16px; padding-right: 16px; }
504
  }
505
 
506
  @media (prefers-reduced-motion: reduce) {
@@ -516,54 +473,58 @@
516
  <body>
517
  <canvas id="confetti"></canvas>
518
 
519
- <main class="app">
520
- <section class="card" aria-label="Scopri il tavolo">
521
- <div class="hero">
522
- <div class="mini-mark" aria-hidden="true">🌊</div>
523
- <h1>Trova la tua Cala</h1>
524
- <div class="map-line" aria-hidden="true">
525
- <svg viewBox="0 0 260 118" role="img">
526
- <path d="M76 72 C64 61 68 48 84 45 C94 43 101 38 99 29 C96 17 112 11 125 19 C137 26 148 25 157 17 C170 6 190 17 184 34 C181 45 193 50 206 50 C224 50 233 66 220 78 C211 87 218 101 203 106 C189 111 181 98 169 103 C153 109 148 120 131 112 C118 106 110 106 97 111 C78 119 62 105 69 89 C72 82 81 79 76 72 Z" />
527
  </svg>
528
  </div>
529
  </div>
530
 
531
- <div class="form">
532
- <label for="guestName">Nome e cognome</label>
533
- <input id="guestName" autocomplete="name" inputmode="text" placeholder="Es. Gaia Pollastrini" />
534
- <button class="discover" id="discover" type="button">Scopri il Tavolo</button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
535
  <div id="message" class="message" aria-live="polite"></div>
536
  <div id="status" class="status" aria-live="polite"></div>
537
- </div>
538
- </section>
539
  </main>
540
 
541
  <section id="reveal" class="reveal" aria-live="assertive" aria-hidden="true">
542
- <div class="reveal-content">
543
  <p class="hello" id="hello"></p>
544
- <div class="small-title">Il tuo tavolo è</div>
545
  <h2 class="table-name" id="tableName"></h2>
546
- <div class="divider" aria-hidden="true"></div>
547
- <p class="reveal-note">Segui la tua cala e goditi la serata.</p>
548
  <button class="again" id="again" type="button">Cerca un altro nome</button>
549
  </div>
550
  </section>
551
 
552
  <script>
553
- const DATA_URL = "";
554
 
555
  const SAMPLE_CSV = `
556
- Nome Cognome,Nome del tavolo
557
- Gaia Pollastrini,Cala Matano
558
- Matteo Bergamelli,Cala delle Arene
559
- Luca Bianchi,Cala Tramontana
560
- Sara Conti,Cala Spido
561
- Marco De Santis,Cala Zio Cesare
562
- Elena Ferri,Cala degli Inglesi
563
- Davide Greco,Cala Tonda
564
- Chiara Romano,Cala dei Benedettini
565
- Alessandro Rinaldi,Cala Pietre di Fucile
566
- Martina Esposito,Cala Sorrentino
567
  `;
568
 
569
  const els = {
@@ -579,6 +540,7 @@ Martina Esposito,Cala Sorrentino
579
  };
580
 
581
  let guests = [];
 
582
 
583
  function normalizeName(value) {
584
  return String(value || "")
@@ -685,8 +647,12 @@ Martina Esposito,Cala Sorrentino
685
  }
686
 
687
  function showReveal(guest) {
 
 
688
  els.hello.textContent = `Ciao ${firstName(guest.fullName)}`;
689
  els.tableName.textContent = guest.tableName;
 
 
690
  els.reveal.classList.add("show");
691
  els.reveal.setAttribute("aria-hidden", "false");
692
  celebrate();
@@ -695,9 +661,13 @@ Martina Esposito,Cala Sorrentino
695
  function hideReveal() {
696
  els.reveal.classList.remove("show");
697
  els.reveal.setAttribute("aria-hidden", "true");
698
- els.input.value = "";
699
- els.message.classList.remove("show");
700
- els.input.focus();
 
 
 
 
701
  }
702
 
703
  function discoverTable() {
@@ -706,7 +676,6 @@ Martina Esposito,Cala Sorrentino
706
 
707
  if (!normalized) {
708
  showMessage("Scrivi nome e cognome per scoprire il tuo tavolo.");
709
- els.input.focus();
710
  return;
711
  }
712
 
@@ -733,6 +702,9 @@ Martina Esposito,Cala Sorrentino
733
  els.input.addEventListener("keydown", event => {
734
  if (event.key === "Enter") discoverTable();
735
  });
 
 
 
736
 
737
  const ctx = els.canvas.getContext("2d");
738
  let confetti = [];
@@ -747,24 +719,24 @@ Martina Esposito,Cala Sorrentino
747
 
748
  function celebrate() {
749
  resizeCanvas();
750
- const colors = ["#254B6B", "#8FA3B3", "#939675", "#C2C5B2", "#D08A7A", "#EDD3CD", "#F3EFE9"];
751
  const centerX = window.innerWidth / 2;
752
- const centerY = window.innerHeight * .42;
753
 
754
- confetti = Array.from({ length: 140 }, () => {
755
  const angle = Math.random() * Math.PI * 2;
756
- const speed = 3.5 + Math.random() * 7;
757
  return {
758
  x: centerX,
759
  y: centerY,
760
- size: 4 + Math.random() * 8,
761
  vx: Math.cos(angle) * speed,
762
- vy: Math.sin(angle) * speed - 4.5,
763
- gravity: .16 + Math.random() * .12,
764
  rotation: Math.random() * Math.PI,
765
- spin: (Math.random() - .5) * .28,
766
  color: colors[Math.floor(Math.random() * colors.length)],
767
- life: 95 + Math.random() * 45
768
  };
769
  });
770
 
@@ -772,6 +744,13 @@ Martina Esposito,Cala Sorrentino
772
  animateConfetti();
773
  }
774
 
 
 
 
 
 
 
 
775
  function animateConfetti() {
776
  ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
777
 
@@ -786,17 +765,18 @@ Martina Esposito,Cala Sorrentino
786
  ctx.save();
787
  ctx.translate(piece.x, piece.y);
788
  ctx.rotate(piece.rotation);
789
- ctx.globalAlpha = Math.max(piece.life / 110, 0);
790
  ctx.fillStyle = piece.color;
791
- ctx.fillRect(-piece.size / 2, -piece.size / 2, piece.size, piece.size * .62);
792
  ctx.restore();
793
  });
794
 
795
- confetti = confetti.filter(piece => piece.life > 0 && piece.y < window.innerHeight + 90);
796
 
797
  if (confetti.length) {
798
  rafId = requestAnimationFrame(animateConfetti);
799
  } else {
 
800
  ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
801
  }
802
  }
 
8
 
9
  <link rel="preconnect" href="https://fonts.googleapis.com">
10
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11
+ <link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;600;700;800&family=Great+Vibes&display=swap" rel="stylesheet">
12
 
13
  <style>
14
+ @font-face {
15
+ font-family: "Amsterdam One";
16
+ src:
17
+ url("./AmsterdamOne.woff2") format("woff2"),
18
+ url("./AmsterdamOne.woff") format("woff"),
19
+ url("/file=AmsterdamOne.woff2") format("woff2"),
20
+ url("/file=AmsterdamOne.woff") format("woff");
21
+ font-weight: 400;
22
+ font-style: normal;
23
+ font-display: swap;
24
+ }
25
+
26
  :root {
27
  --blue: #254B6B;
28
+ --blue-soft: #8FA3B3;
29
  --olive: #939675;
30
  --sage: #C2C5B2;
31
  --coral: #D08A7A;
32
  --rose: #EDD3CD;
33
  --cream: #F3EFE9;
34
  --paper: #FFFDF8;
35
+ --line: rgba(37, 75, 107, .13);
36
+ --line-soft: rgba(147, 150, 117, .24);
37
+ --shadow: 0 18px 46px rgba(37, 75, 107, .10);
38
+ --font-main: "Montserrat", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
39
+ --font-script: "Amsterdam One", "Great Vibes", "Snell Roundhand", cursive;
40
  }
41
 
42
  * { box-sizing: border-box; }
43
 
44
  html,
45
  body {
 
 
46
  width: 100%;
47
+ min-height: 100%;
48
+ margin: 0;
49
+ font-family: var(--font-main);
50
  color: var(--blue);
51
  background: var(--cream);
52
  overflow-x: hidden;
 
55
  body {
56
  min-height: 100svh;
57
  background:
58
+ linear-gradient(180deg, #fffdf8 0%, #f8f4ee 54%, #f3efe9 100%);
59
+ }
60
+
61
+ body.reveal-open {
62
+ overflow: hidden;
63
  }
64
 
65
+ .screen {
66
+ position: relative;
67
+ min-height: 100svh;
68
+ display: flex;
69
+ justify-content: center;
70
+ overflow: hidden;
71
+ }
72
+
73
+ .screen::before {
74
  content: "";
75
  position: fixed;
76
+ inset: 18px;
77
+ border: 1px solid rgba(147, 150, 117, .22);
78
+ border-radius: 28px;
 
79
  pointer-events: none;
 
 
 
 
 
 
 
 
 
80
  }
81
 
82
+ .screen::after {
83
  content: "";
84
  position: fixed;
85
+ left: 50%;
86
+ top: 52%;
87
+ width: min(78vw, 420px);
88
+ height: min(78vw, 420px);
89
+ border-radius: 999px;
90
+ transform: translate(-50%, -50%);
91
+ background: rgba(237, 211, 205, .18);
92
  pointer-events: none;
93
+ filter: blur(.2px);
 
 
 
 
 
 
 
 
 
 
 
94
  }
95
 
96
+ .page {
97
  position: relative;
98
  z-index: 1;
99
+ width: min(100%, 500px);
100
  min-height: 100svh;
101
+ padding: max(30px, env(safe-area-inset-top)) 28px max(28px, env(safe-area-inset-bottom));
102
  display: grid;
103
+ grid-template-rows: auto 1fr auto;
 
104
  }
105
 
106
+ .top-mark {
 
 
 
107
  display: flex;
 
108
  justify-content: center;
109
+ align-items: center;
110
+ min-height: 44px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  }
112
 
113
+ .monogram {
114
+ width: 48px;
115
+ height: 48px;
 
 
 
 
 
116
  border-radius: 50%;
117
+ border: 1px dashed rgba(208, 138, 122, .74);
118
+ display: grid;
119
+ place-items: center;
120
+ color: var(--coral);
121
+ background: rgba(255, 253, 248, .72);
122
  }
123
 
124
+ .monogram svg {
125
+ width: 28px;
126
+ height: 28px;
127
+ display: block;
128
  }
129
 
130
  .hero {
131
+ align-self: center;
 
132
  text-align: center;
133
+ padding: 10px 0 22px;
134
  }
135
 
136
+ .script-title {
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  margin: 0 auto;
138
+ max-width: 390px;
139
  color: var(--blue);
140
+ font-family: var(--font-script);
141
+ font-size: clamp(62px, 18vw, 108px);
142
+ font-weight: 400;
143
+ line-height: .76;
144
+ letter-spacing: -.035em;
145
  text-wrap: balance;
146
  }
147
 
148
+ .script-title span {
149
+ display: block;
150
+ }
151
+
152
+ .script-title span:first-child {
153
+ transform: translateX(-.06em);
154
+ }
155
+
156
+ .script-title span:last-child {
157
+ margin-top: -.02em;
158
+ transform: translateX(.08em);
159
+ }
160
+
161
+ .island-line {
162
+ width: min(72vw, 310px);
163
+ margin: clamp(32px, 7svh, 54px) auto 0;
164
  color: var(--olive);
165
+ opacity: .90;
166
  }
167
 
168
+ .island-line svg {
169
  width: 100%;
170
  height: auto;
171
  display: block;
172
  overflow: visible;
173
  }
174
 
175
+ .island-line path {
176
  fill: none;
177
  stroke: currentColor;
178
+ stroke-width: 3;
179
  stroke-linecap: round;
180
  stroke-linejoin: round;
181
+ stroke-dasharray: 850;
182
+ stroke-dashoffset: 850;
183
+ animation: draw 1.45s ease .2s forwards;
184
  }
185
 
186
  @keyframes draw { to { stroke-dashoffset: 0; } }
187
 
188
+ .form-area {
189
+ align-self: end;
190
+ padding-bottom: clamp(6px, 2.4svh, 26px);
191
  }
192
 
193
+ .field-label {
194
  display: block;
195
+ margin: 0 0 10px;
196
+ color: rgba(37, 75, 107, .74);
197
  font-size: 11px;
198
  font-weight: 800;
199
+ letter-spacing: .15em;
200
  text-transform: uppercase;
201
  }
202
 
203
+ .input-panel {
204
+ padding: 0;
205
+ }
206
+
207
  input {
208
  width: 100%;
209
+ min-height: 62px;
210
+ border: 1px solid var(--line-soft);
211
+ outline: 0;
212
+ border-radius: 999px;
213
+ padding: 0 22px;
214
  color: var(--blue);
215
+ background: rgba(255, 253, 248, .92);
216
+ font-family: var(--font-main);
217
+ font-size: 16px;
218
  font-weight: 600;
219
+ box-shadow: 0 10px 28px rgba(37, 75, 107, .07);
220
+ transition: border-color .18s ease, box-shadow .18s ease, background .18s ease;
 
 
221
  }
222
 
223
  input::placeholder {
 
226
  }
227
 
228
  input:focus {
229
+ border-color: rgba(208, 138, 122, .72);
230
+ background: #fffdf8;
231
+ box-shadow: 0 0 0 5px rgba(237, 211, 205, .28), 0 12px 30px rgba(37, 75, 107, .08);
 
 
232
  }
233
 
234
  .discover {
235
  position: relative;
236
  width: 100%;
237
+ min-height: 62px;
238
+ margin-top: 12px;
239
  border: 0;
240
+ border-radius: 999px;
241
  overflow: hidden;
242
  cursor: pointer;
243
  color: var(--paper);
244
  background: var(--blue);
245
+ font-family: var(--font-main);
246
+ font-size: 15px;
 
247
  font-weight: 800;
248
+ letter-spacing: .02em;
249
+ box-shadow: 0 14px 32px rgba(37, 75, 107, .18);
250
  transition: transform .16s ease, background .16s ease, box-shadow .16s ease;
251
  }
252
 
 
 
 
 
 
 
 
 
 
253
  .discover::after {
254
  content: "";
255
  position: absolute;
256
  left: 50%;
257
  bottom: 10px;
258
+ width: 56px;
259
  height: 2px;
260
  border-radius: 999px;
261
  background: var(--coral);
262
  transform: translateX(-50%);
 
 
 
 
 
 
263
  }
264
 
265
  .discover:active {
266
+ transform: translateY(2px);
267
+ background: #1f405b;
268
+ box-shadow: 0 8px 22px rgba(37, 75, 107, .16);
269
  }
270
 
271
  .message {
272
  min-height: 0;
273
+ margin-top: 12px;
274
  opacity: 0;
275
  transform: translateY(8px);
276
  transition: opacity .24s ease, transform .24s ease;
 
283
 
284
  .message-card {
285
  border-radius: 18px;
286
+ padding: 14px 16px;
 
287
  color: rgba(37, 75, 107, .78);
288
+ background: rgba(255, 253, 248, .86);
289
+ border: 1px solid rgba(147, 150, 117, .22);
290
+ text-align: center;
291
  font-size: 13px;
 
292
  line-height: 1.35;
293
+ font-weight: 600;
294
+ box-shadow: 0 10px 26px rgba(37, 75, 107, .06);
295
  }
296
 
297
  .reveal {
 
300
  z-index: 20;
301
  display: grid;
302
  place-items: center;
303
+ padding: max(28px, env(safe-area-inset-top)) 24px max(24px, env(safe-area-inset-bottom));
304
  color: var(--blue);
305
  background:
306
+ linear-gradient(180deg, #fffdf8 0%, #f8f4ee 54%, #f3efe9 100%);
 
 
307
  opacity: 0;
308
+ visibility: hidden;
309
  pointer-events: none;
310
+ transform: scale(1.012);
311
+ transition: opacity .34s ease, transform .34s ease, visibility 0s linear .34s;
312
  overflow: hidden;
313
  }
314
 
315
+ .reveal::before {
316
+ content: "";
317
+ position: fixed;
318
+ inset: 18px;
319
+ border: 1px solid rgba(147, 150, 117, .22);
320
+ border-radius: 28px;
321
+ pointer-events: none;
322
  }
323
 
324
+ .reveal::after {
325
  content: "";
326
  position: absolute;
327
+ left: 50%;
328
+ top: 45%;
329
+ width: min(82vw, 430px);
330
+ height: min(82vw, 430px);
331
+ border-radius: 999px;
332
+ transform: translate(-50%, -50%);
333
+ background: rgba(237, 211, 205, .18);
334
+ pointer-events: none;
335
+ }
336
+
337
+ .reveal.show {
338
+ opacity: 1;
339
+ visibility: visible;
340
+ pointer-events: auto;
341
+ transform: scale(1);
342
+ transition: opacity .34s ease, transform .34s ease, visibility 0s;
343
  }
344
 
345
+ .reveal-page {
346
  position: relative;
347
  z-index: 2;
348
  width: min(100%, 560px);
349
+ min-height: min(86svh, 780px);
350
  display: flex;
351
  flex-direction: column;
 
352
  justify-content: center;
353
  text-align: center;
354
+ animation: revealIn .56s cubic-bezier(.2,.9,.18,1.08) both;
 
 
 
 
 
 
 
 
355
  }
356
 
357
+ .reveal.show .reveal-page {
358
+ animation: revealIn .56s cubic-bezier(.2,.9,.18,1.08) both;
 
 
 
 
 
359
  }
360
 
361
+ @keyframes revealIn {
362
+ from { opacity: 0; transform: translateY(18px); }
363
+ to { opacity: 1; transform: translateY(0); }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
364
  }
365
 
366
  .hello {
367
+ margin: 0 0 clamp(22px, 5svh, 38px);
368
+ color: rgba(37, 75, 107, .66);
369
+ font-size: clamp(15px, 4vw, 19px);
370
+ font-weight: 500;
371
  letter-spacing: .02em;
372
  }
373
 
374
+ .table-kicker {
375
+ margin: 0 0 8px;
376
  color: var(--coral);
377
  font-size: 12px;
378
  font-weight: 800;
379
+ letter-spacing: .22em;
380
  text-transform: uppercase;
381
  }
382
 
383
  .table-name {
384
+ margin: 0 auto;
385
  max-width: 11ch;
386
  color: var(--blue);
387
+ font-family: var(--font-script);
388
+ font-size: clamp(76px, 23vw, 146px);
389
+ font-weight: 400;
390
+ line-height: .74;
391
+ letter-spacing: -.035em;
392
  text-wrap: balance;
393
  }
394
 
395
+ .table-name[data-long="true"] {
396
+ max-width: 12ch;
397
+ font-size: clamp(58px, 18vw, 112px);
398
+ }
399
+
400
+ .reveal-line {
401
+ width: 88px;
402
  height: 2px;
403
+ margin: clamp(28px, 6svh, 46px) auto 0;
404
  border-radius: 999px;
405
+ background: var(--olive);
406
+ opacity: .68;
407
  }
408
 
409
  .reveal-note {
410
+ margin: 18px auto 0;
411
  max-width: 28ch;
412
+ color: rgba(37, 75, 107, .66);
413
  font-size: 15px;
414
+ line-height: 1.42;
415
  font-weight: 500;
416
  }
417
 
418
  .again {
419
+ align-self: center;
420
  min-height: 52px;
421
+ margin-top: clamp(28px, 6svh, 44px);
422
+ border: 1px solid rgba(37, 75, 107, .14);
423
  border-radius: 999px;
424
  padding: 0 24px;
425
+ color: var(--blue);
426
+ background: rgba(255, 253, 248, .88);
427
+ box-shadow: 0 14px 32px rgba(37, 75, 107, .09);
428
+ font-family: var(--font-main);
429
+ font-size: 13px;
430
  font-weight: 800;
431
+ letter-spacing: .03em;
432
  cursor: pointer;
433
  }
434
 
 
451
  }
452
 
453
  @media (max-width: 380px) {
454
+ .screen::before, .reveal::before { inset: 12px; border-radius: 24px; }
455
+ .page { padding-left: 22px; padding-right: 22px; }
456
+ .script-title { font-size: clamp(58px, 18vw, 92px); }
457
+ .island-line { width: min(72vw, 290px); }
458
+ input, .discover { min-height: 58px; }
459
+ .table-name { font-size: clamp(68px, 22vw, 120px); }
460
+ .table-name[data-long="true"] { font-size: clamp(52px, 17vw, 94px); }
461
  }
462
 
463
  @media (prefers-reduced-motion: reduce) {
 
473
  <body>
474
  <canvas id="confetti"></canvas>
475
 
476
+ <main class="screen">
477
+ <div class="page">
478
+ <div class="top-mark">
479
+ <div class="monogram" aria-hidden="true">
480
+ <svg viewBox="0 0 64 64" role="img">
481
+ <path d="M18 35 C23 25 32 21 43 24 C37 27 34 31 35 40 C28 35 23 35 18 35 Z" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
482
+ <path d="M29 39 C34 32 43 28 53 30" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
 
483
  </svg>
484
  </div>
485
  </div>
486
 
487
+ <section class="hero" aria-label="Trova la tua cala">
488
+ <h1 class="script-title">
489
+ <span>Trova la</span>
490
+ <span>tua Cala</span>
491
+ </h1>
492
+
493
+ <div class="island-line" aria-hidden="true">
494
+ <svg viewBox="0 0 420 300">
495
+ <path d="M202 25 C226 38 241 62 238 83 C254 72 279 79 286 98 C302 98 323 113 319 132 C344 144 350 174 329 191 C313 204 316 224 291 229 C268 233 251 217 231 231 C215 242 198 271 170 262 C149 255 141 232 119 229 C93 226 78 201 91 179 C100 163 81 149 95 126 C108 106 129 109 142 93 C155 76 143 54 165 41 C176 34 190 35 202 25 Z" />
496
+ </svg>
497
+ </div>
498
+ </section>
499
+
500
+ <section class="form-area" aria-label="Ricerca invitato">
501
+ <label class="field-label" for="guestName">Nome e cognome</label>
502
+ <div class="input-panel">
503
+ <input id="guestName" autocomplete="name" inputmode="text" placeholder="Es. Gaia Pollastrini" />
504
+ <button class="discover" id="discover" type="button">Scopri il Tavolo</button>
505
+ </div>
506
  <div id="message" class="message" aria-live="polite"></div>
507
  <div id="status" class="status" aria-live="polite"></div>
508
+ </section>
509
+ </div>
510
  </main>
511
 
512
  <section id="reveal" class="reveal" aria-live="assertive" aria-hidden="true">
513
+ <div class="reveal-page">
514
  <p class="hello" id="hello"></p>
515
+ <p class="table-kicker">Il tuo tavolo è</p>
516
  <h2 class="table-name" id="tableName"></h2>
517
+ <div class="reveal-line" aria-hidden="true"></div>
518
+ <p class="reveal-note">In che cala cenerai? L’hai appena scoperto.</p>
519
  <button class="again" id="again" type="button">Cerca un altro nome</button>
520
  </div>
521
  </section>
522
 
523
  <script>
524
+ const DATA_URL = "https://docs.google.com/spreadsheets/d/e/2PACX-1vSlb-0cSIFaGN_BWrn_S9tQoQsdqGH7qYRYQGC3_3wRB-rGzwZoPoxIBNr9l6NmxW9Ont82YKIdGKIR/pub?output=csv";
525
 
526
  const SAMPLE_CSV = `
527
+
 
 
 
 
 
 
 
 
 
 
528
  `;
529
 
530
  const els = {
 
540
  };
541
 
542
  let guests = [];
543
+ let hideTimer = null;
544
 
545
  function normalizeName(value) {
546
  return String(value || "")
 
647
  }
648
 
649
  function showReveal(guest) {
650
+ clearTimeout(hideTimer);
651
+ const longName = guest.tableName.length > 14;
652
  els.hello.textContent = `Ciao ${firstName(guest.fullName)}`;
653
  els.tableName.textContent = guest.tableName;
654
+ els.tableName.dataset.long = longName ? "true" : "false";
655
+ document.body.classList.add("reveal-open");
656
  els.reveal.classList.add("show");
657
  els.reveal.setAttribute("aria-hidden", "false");
658
  celebrate();
 
661
  function hideReveal() {
662
  els.reveal.classList.remove("show");
663
  els.reveal.setAttribute("aria-hidden", "true");
664
+ document.body.classList.remove("reveal-open");
665
+ stopConfetti();
666
+
667
+ hideTimer = window.setTimeout(() => {
668
+ els.input.value = "";
669
+ els.message.classList.remove("show");
670
+ }, 360);
671
  }
672
 
673
  function discoverTable() {
 
676
 
677
  if (!normalized) {
678
  showMessage("Scrivi nome e cognome per scoprire il tuo tavolo.");
 
679
  return;
680
  }
681
 
 
702
  els.input.addEventListener("keydown", event => {
703
  if (event.key === "Enter") discoverTable();
704
  });
705
+ window.addEventListener("keydown", event => {
706
+ if (event.key === "Escape" && els.reveal.classList.contains("show")) hideReveal();
707
+ });
708
 
709
  const ctx = els.canvas.getContext("2d");
710
  let confetti = [];
 
719
 
720
  function celebrate() {
721
  resizeCanvas();
722
+ const colors = ["#254B6B", "#8FA3B3", "#939675", "#C2C5B2", "#D08A7A", "#EDD3CD"];
723
  const centerX = window.innerWidth / 2;
724
+ const centerY = window.innerHeight * .36;
725
 
726
+ confetti = Array.from({ length: 90 }, () => {
727
  const angle = Math.random() * Math.PI * 2;
728
+ const speed = 3 + Math.random() * 6;
729
  return {
730
  x: centerX,
731
  y: centerY,
732
+ size: 4 + Math.random() * 7,
733
  vx: Math.cos(angle) * speed,
734
+ vy: Math.sin(angle) * speed - 4,
735
+ gravity: .15 + Math.random() * .10,
736
  rotation: Math.random() * Math.PI,
737
+ spin: (Math.random() - .5) * .24,
738
  color: colors[Math.floor(Math.random() * colors.length)],
739
+ life: 86 + Math.random() * 36
740
  };
741
  });
742
 
 
744
  animateConfetti();
745
  }
746
 
747
+ function stopConfetti() {
748
+ if (rafId) cancelAnimationFrame(rafId);
749
+ rafId = null;
750
+ confetti = [];
751
+ ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
752
+ }
753
+
754
  function animateConfetti() {
755
  ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
756
 
 
765
  ctx.save();
766
  ctx.translate(piece.x, piece.y);
767
  ctx.rotate(piece.rotation);
768
+ ctx.globalAlpha = Math.max(piece.life / 100, 0);
769
  ctx.fillStyle = piece.color;
770
+ ctx.fillRect(-piece.size / 2, -piece.size / 2, piece.size, piece.size * .58);
771
  ctx.restore();
772
  });
773
 
774
+ confetti = confetti.filter(piece => piece.life > 0 && piece.y < window.innerHeight + 80);
775
 
776
  if (confetti.length) {
777
  rafId = requestAnimationFrame(animateConfetti);
778
  } else {
779
+ rafId = null;
780
  ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
781
  }
782
  }