GHSsda/HotelManagement
0
1<!DOCTYPE html>
2<html lang="it">
3<head>
4<meta charset="UTF-8">
5<meta name="viewport" content="width=device-width, initial-scale=1.0">
6<title>Flora · Yield Intelligence</title>
7<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
8<link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;1,9..40,300&display=swap" rel="stylesheet">
9
10<style>
11/* ═══════════════════════════════════════
12 TOKENS — Apple HIG 2025
13═══════════════════════════════════════ */
14:root {
15 /* Neutrals */
16 --ink: #1a1a1a;
17 --ink-2: #3d3d3d;
18 --ink-3: #8a8a8e;
19 --ink-4: #c7c7cc;
20 --ink-5: #e5e5ea;
21 --ink-6: #f2f2f7;
22 --bg: #fafafa;
23 --white: #ffffff;
24
25 /* Accent — single restrained blue */
26 --blue: #006edc;
27 --blue-soft: rgba(0, 110, 220, 0.08);
28 --blue-ring: rgba(0, 110, 220, 0.2);
29
30 /* Semantic */
31 --green: #30a46c;
32 --green-soft: rgba(48, 164, 108, 0.08);
33 --amber: #e07b00;
34 --amber-soft: rgba(224, 123, 0, 0.08);
35 --red: #e5484d;
36 --red-soft: rgba(229, 72, 77, 0.08);
37
38 /* Surface */
39 --card-bg: rgba(255,255,255,0.72);
40 --card-border: rgba(0,0,0,0.06);
41 --card-shadow: 0 1px 3px rgba(0,0,0,0.04), 0 4px 16px rgba(0,0,0,0.04);
42 --card-shadow-hover: 0 1px 3px rgba(0,0,0,0.06), 0 8px 28px rgba(0,0,0,0.08);
43
44 /* Layout */
45 --sidebar-w: 228px;
46 --bar-h: 50px;
47 --r: 14px;
48 --r-sm: 9px;
49 --r-xs: 6px;
50
51 /* Motion */
52 --spring: cubic-bezier(0.34, 1.56, 0.64, 1);
53 --ease: cubic-bezier(0.25, 0.1, 0.25, 1);
54 --fast: 0.15s;
55 --mid: 0.25s;
56 --slow: 0.4s;
57}
58
59[data-theme="dark"] {
60 --ink: #f7f7fb;
61 --ink-2: #e4e7ef;
62 --ink-3: #9aa3b2;
63 --ink-4: #657083;
64 --ink-5: #263142;
65 --ink-6: #151c28;
66 --bg: #0b111b;
67 --white: #111827;
68 --blue: #63a7ff;
69 --blue-soft: rgba(99, 167, 255, 0.14);
70 --blue-ring: rgba(99, 167, 255, 0.28);
71 --green: #57d08d;
72 --green-soft: rgba(87, 208, 141, 0.13);
73 --amber: #ffb454;
74 --amber-soft: rgba(255, 180, 84, 0.13);
75 --red: #ff6b72;
76 --red-soft: rgba(255, 107, 114, 0.13);
77 --card-bg: rgba(17,24,39,0.72);
78 --card-border: rgba(255,255,255,0.08);
79 --card-shadow: 0 1px 3px rgba(0,0,0,0.24), 0 14px 42px rgba(0,0,0,0.22);
80 --card-shadow-hover: 0 1px 3px rgba(0,0,0,0.30), 0 18px 56px rgba(0,0,0,0.30);
81}
82
83/* ═══ RESET ═══ */
84*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
85html { height: 100%; }
86body {
87 font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', 'DM Sans', sans-serif;
88 background:
89 linear-gradient(180deg, rgba(255,255,255,0.88) 0%, rgba(242,244,248,0.9) 46%, rgba(238,241,246,1) 100%),
90 var(--bg);
91 color: var(--ink);
92 height: 100vh;
93 overflow: hidden;
94 -webkit-font-smoothing: antialiased;
95 text-rendering: optimizeLegibility;
96 font-size: 13px;
97 line-height: 1.5;
98}
99
100/* ═══ SCROLLBAR ═══ */
101::-webkit-scrollbar { width: 4px; height: 4px; }
102::-webkit-scrollbar-track { background: transparent; }
103::-webkit-scrollbar-thumb { background: var(--ink-5); border-radius: 4px; }
104::-webkit-scrollbar-thumb:hover { background: var(--ink-4); }
105.hide-scroll::-webkit-scrollbar { display: none; }
106
107/* ═══ SELECTION ═══ */
108::selection { background: var(--blue-soft); color: var(--blue); }
109
110/* ═══════════════════════════════════════
111 LAYOUT
112═══════════════════════════════════════ */
113.app { display: flex; height: 100vh; }
114
115/* ═══════════════════════════════════════
116 SIDEBAR
117═══════════════════════════════════════ */
118.sidebar {
119 width: var(--sidebar-w);
120 flex-shrink: 0;
121 background: rgba(250,250,252,0.88);
122 backdrop-filter: blur(24px) saturate(180%);
123 -webkit-backdrop-filter: blur(24px) saturate(180%);
124 border-right: 1px solid var(--card-border);
125 display: flex;
126 flex-direction: column;
127 overflow: hidden;
128 position: relative;
129 z-index: 10;
130}
131
132/* Subtle noise texture overlay */
133.sidebar::before {
134 content: '';
135 position: absolute;
136 inset: 0;
137 background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)' opacity='0.03'/%3E%3C/svg%3E");
138 pointer-events: none;
139 z-index: 0;
140}
141.sidebar > * { position: relative; z-index: 1; }
142
143/* Logo area */
144.sb-top {
145 padding: 20px 16px 16px;
146 border-bottom: 1px solid var(--card-border);
147}
148.wordmark {
149 display: flex; align-items: center; gap: 10px;
150 user-select: none; cursor: default;
151}
152.wordmark-icon {
153 width: 32px; height: 32px;
154 border-radius: 9px;
155 background: var(--ink);
156 display: flex; align-items: center; justify-content: center;
157 flex-shrink: 0;
158 position: relative;
159 overflow: hidden;
160}
161.wordmark-icon::after {
162 content: '';
163 position: absolute;
164 top: 0; left: 0; right: 0;
165 height: 50%;
166 background: linear-gradient(180deg, rgba(255,255,255,0.12) 0%, transparent 100%);
167 border-radius: 9px 9px 0 0;
168}
169.wi-letter {
170 font-size: 15px;
171 font-weight: 700;
172 color: #fff;
173 letter-spacing: -0.04em;
174 line-height: 1;
175}
176.wordmark-text { flex: 1; }
177.wm-name {
178 font-size: 14px;
179 font-weight: 700;
180 letter-spacing: -0.02em;
181 color: var(--ink);
182 line-height: 1.1;
183}
184.wm-sub {
185 font-size: 10.5px;
186 font-weight: 400;
187 color: var(--ink-3);
188 margin-top: 1px;
189 letter-spacing: 0.01em;
190}
191
192/* Room switcher */
193.room-sw {
194 margin-top: 14px;
195 background: var(--ink-6);
196 border-radius: var(--r-xs);
197 padding: 3px;
198 display: flex;
199 position: relative;
200}
201.room-sw-track {
202 position: absolute;
203 top: 3px; bottom: 3px;
204 width: calc(50% - 3px);
205 background: var(--white);
206 border-radius: 4px;
207 box-shadow: 0 1px 3px rgba(0,0,0,0.12);
208 transition: transform var(--mid) var(--spring);
209 pointer-events: none;
210 left: 3px;
211}
212.room-sw-track.right { transform: translateX(calc(100% + 0px)); }
213.room-btn {
214 flex: 1;
215 padding: 5px 0;
216 font-size: 11px;
217 font-weight: 600;
218 letter-spacing: 0.02em;
219 text-transform: uppercase;
220 font-family: 'DM Sans', sans-serif;
221 border: none;
222 background: transparent;
223 color: var(--ink-3);
224 cursor: pointer;
225 transition: color var(--fast) var(--ease);
226 position: relative; z-index: 1;
227}
228.room-btn.active { color: var(--ink); }
229
230/* Nav */
231.sb-nav { flex: 1; overflow-y: auto; padding: 10px 8px; }
232.nav-section-label {
233 font-size: 10px;
234 font-weight: 600;
235 letter-spacing: 0.09em;
236 text-transform: uppercase;
237 color: var(--ink-4);
238 padding: 10px 8px 5px;
239}
240
241.nav-item {
242 display: flex; align-items: center; gap: 9px;
243 width: 100%; padding: 8px 10px;
244 border-radius: var(--r-xs);
245 border: none;
246 background: transparent;
247 color: var(--ink-3);
248 font-family: 'DM Sans', sans-serif;
249 font-size: 13px;
250 font-weight: 500;
251 cursor: pointer;
252 text-align: left;
253 transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
254 position: relative;
255 margin-bottom: 1px;
256}
257.nav-item svg { width: 15px; height: 15px; flex-shrink: 0; transition: opacity var(--fast); opacity: 0.5; }
258.nav-item:hover { background: rgba(0,0,0,0.04); color: var(--ink-2); }
259.nav-item:hover svg { opacity: 0.75; }
260.nav-item.active { background: var(--white); color: var(--ink); font-weight: 600; box-shadow: 0 1px 3px rgba(0,0,0,0.08); }
261.nav-item.active svg { opacity: 1; }
262.nav-item.active::before {
263 content: '';
264 position: absolute;
265 left: 0; top: 50%;
266 transform: translateY(-50%);
267 width: 3px; height: 16px;
268 background: var(--blue);
269 border-radius: 0 2px 2px 0;
270}
271
272/* Sidebar footer */
273.sb-footer {
274 padding: 10px 10px 14px;
275 border-top: 1px solid var(--card-border);
276 display: flex; flex-direction: column; gap: 8px;
277}
278
279.status-chip {
280 display: flex; align-items: center; gap: 7px;
281 padding: 7px 10px;
282 border-radius: var(--r-xs);
283 background: var(--green-soft);
284 border: 1px solid rgba(48,164,108,0.12);
285}
286.s-dot {
287 width: 6px; height: 6px;
288 border-radius: 50%;
289 background: var(--green);
290 flex-shrink: 0;
291 animation: breathe 2.4s ease-in-out infinite;
292}
293@keyframes breathe {
294 0%,100% { opacity: 1; transform: scale(1); }
295 50% { opacity: 0.3; transform: scale(0.7); }
296}
297.s-label { font-size: 11px; font-weight: 600; color: var(--green); letter-spacing: 0.01em; }
298.s-clock { font-size: 11px; color: var(--ink-3); margin-left: auto; font-variant-numeric: tabular-nums; letter-spacing: -0.01em; }
299
300/* ═══════════════════════════════════════
301 MAIN AREA
302═══════════════════════════════════════ */
303.main { flex: 1; display: flex; flex-direction: column; overflow: hidden; min-width: 0; }
304
305/* Topbar */
306.topbar {
307 height: var(--bar-h);
308 background: rgba(250,250,252,0.88);
309 backdrop-filter: blur(24px);
310 -webkit-backdrop-filter: blur(24px);
311 border-bottom: 1px solid var(--card-border);
312 display: flex; align-items: center;
313 justify-content: space-between;
314 padding: 0 20px;
315 flex-shrink: 0;
316 gap: 12px;
317}
318
319.topbar-left { display: flex; align-items: center; gap: 12px; }
320.topbar-title {
321 font-size: 14px;
322 font-weight: 700;
323 letter-spacing: -0.02em;
324 color: var(--ink);
325}
326.topbar-div { width: 1px; height: 16px; background: var(--ink-5); }
327.topbar-meta {
328 font-size: 11.5px;
329 color: var(--ink-3);
330 font-weight: 400;
331 display: flex; align-items: center; gap: 5px;
332}
333.topbar-meta svg { width: 12px; height: 12px; opacity: 0.5; }
334.topbar-actions { display: flex; align-items: center; gap: 8px; }
335.scan-state {
336 display: flex; align-items: center; gap: 6px;
337 padding: 6px 9px;
338 border-radius: var(--r-xs);
339 background: var(--ink-6);
340 border: 1px solid var(--card-border);
341 color: var(--ink-3);
342 font-size: 11px;
343 font-weight: 600;
344 white-space: nowrap;
345}
346.scan-state.running { color: var(--blue); background: var(--blue-soft); }
347.scan-state.error { color: var(--red); background: var(--red-soft); }
348.theme-toggle {
349 width: 32px; height: 32px;
350 border: 1px solid var(--card-border);
351 border-radius: var(--r-sm);
352 background: var(--card-bg);
353 color: var(--ink-2);
354 display: flex; align-items: center; justify-content: center;
355 cursor: pointer;
356 transition: transform var(--fast) var(--spring), background var(--fast), color var(--fast);
357}
358.theme-toggle:hover { transform: translateY(-1px); color: var(--ink); }
359.theme-toggle svg { width: 15px; height: 15px; }
360
361/* Scan button */
362.scan-btn {
363 display: flex; align-items: center; gap: 7px;
364 padding: 7px 15px;
365 background: var(--ink);
366 color: #fff;
367 border: none;
368 border-radius: var(--r-sm);
369 font-family: 'DM Sans', sans-serif;
370 font-size: 12px;
371 font-weight: 600;
372 cursor: pointer;
373 transition: opacity var(--fast), transform var(--fast) var(--spring), background var(--fast);
374 letter-spacing: -0.01em;
375 position: relative;
376 overflow: hidden;
377}
378.scan-btn::after {
379 content: '';
380 position: absolute;
381 top: 0; left: 0; right: 0;
382 height: 50%;
383 background: linear-gradient(180deg, rgba(255,255,255,0.08) 0%, transparent 100%);
384}
385.scan-btn:hover { opacity: 0.85; }
386.scan-btn:active { transform: scale(0.96); }
387.scan-btn:disabled { opacity: 0.3; cursor: not-allowed; }
388.scan-btn svg { width: 12px; height: 12px; position: relative; z-index: 1; }
389.scan-btn span { position: relative; z-index: 1; }
390
391[data-theme="dark"] .sidebar,
392[data-theme="dark"] .topbar { background: rgba(13,20,32,0.88); }
393[data-theme="dark"] body {
394 background:
395 linear-gradient(180deg, rgba(11,17,27,1) 0%, rgba(16,24,38,1) 48%, rgba(9,14,23,1) 100%),
396 var(--bg);
397}
398[data-theme="dark"] .kpi-card,
399[data-theme="dark"] .panel,
400[data-theme="dark"] .decision-card { background: rgba(17,24,39,0.78); }
401[data-theme="dark"] .decision-metric { background: rgba(255,255,255,0.04); }
402[data-theme="dark"] .legend-line.comp { background: rgba(255,255,255,0.32); }
403[data-theme="dark"] .nav-item:hover,
404[data-theme="dark"] .mtx tbody tr:hover td { background: rgba(255,255,255,0.04); }
405[data-theme="dark"] .nav-item.active { background: rgba(255,255,255,0.08); }
406[data-theme="dark"] .room-sw { background: rgba(255,255,255,0.06); }
407[data-theme="dark"] .room-sw-track { background: rgba(255,255,255,0.12); }
408[data-theme="dark"] .mtx thead th { background: rgba(13,20,32,0.96); }
409[data-theme="dark"] .mtx tbody td { border-bottom-color: rgba(255,255,255,0.05); }
410[data-theme="dark"] .mtx tbody tr:hover td:first-child { background: rgba(20,29,44,0.98); }
411[data-theme="dark"] .modal-box { background: rgba(17,24,39,0.94); border-color: var(--card-border); }
412
413@media (max-width: 860px) {
414 .app { flex-direction: column; }
415 .sidebar { width: 100%; height: auto; max-height: 220px; border-right: none; border-bottom: 1px solid var(--card-border); }
416 .sb-nav { display: flex; overflow-x: auto; padding: 8px; }
417 .nav-section-label { display: none; }
418 .nav-item { width: auto; white-space: nowrap; }
419 .sb-footer { display: none; }
420 .topbar { height: auto; min-height: var(--bar-h); align-items: flex-start; flex-direction: column; padding: 12px 14px; }
421 .topbar-actions { width: 100%; justify-content: flex-end; flex-wrap: wrap; }
422 .decision-panel { grid-template-columns: 1fr; }
423 .decision-main { align-items: flex-start; flex-direction: column; }
424 .decision-side { width: 100%; grid-template-columns: 1fr 1fr; }
425 .kpi-row, .g2, .g2eq { grid-template-columns: 1fr; }
426 .content { padding: 14px; }
427}
428
429@media (max-width: 520px) {
430 .decision-side { grid-template-columns: 1fr; }
431 .decision-card { padding: 18px; }
432}
433
434/* ═══════════════════════════════════════
435 CONTENT
436═══════════════════════════════════════ */
437.content {
438 flex: 1;
439 overflow-y: auto;
440 padding: 20px 22px 30px;
441}
442
443/* Page transition */
444.view { animation: viewIn var(--mid) var(--ease) both; }
445@keyframes viewIn {
446 from { opacity: 0; transform: translateY(6px); }
447 to { opacity: 1; transform: translateY(0); }
448}
449
450/* ═══════════════════════════════════════
451 KPI ROW
452═══════════════════════════════════════ */
453.decision-panel {
454 display: grid;
455 grid-template-columns: minmax(0, 1.4fr) minmax(280px, 0.8fr);
456 gap: 12px;
457 margin-bottom: 12px;
458}
459
460.decision-card {
461 min-height: 154px;
462 padding: 22px 24px;
463 border-radius: 8px;
464 border: 1px solid var(--card-border);
465 background:
466 linear-gradient(135deg, rgba(255,255,255,0.88), rgba(255,255,255,0.64)),
467 rgba(255,255,255,0.78);
468 box-shadow: var(--card-shadow);
469 backdrop-filter: blur(22px) saturate(170%);
470 -webkit-backdrop-filter: blur(22px) saturate(170%);
471 display: flex;
472 flex-direction: column;
473 justify-content: space-between;
474 overflow: hidden;
475}
476
477.decision-main {
478 display: flex;
479 align-items: flex-end;
480 justify-content: space-between;
481 gap: 18px;
482}
483
484.decision-copy { min-width: 0; }
485.decision-eyebrow {
486 font-size: 11px;
487 font-weight: 700;
488 color: var(--ink-3);
489 letter-spacing: 0.06em;
490 text-transform: uppercase;
491 margin-bottom: 10px;
492}
493.decision-value {
494 font-size: clamp(44px, 5vw, 68px);
495 line-height: 0.95;
496 letter-spacing: -0.06em;
497 color: var(--ink);
498 font-weight: 750;
499 font-variant-numeric: tabular-nums;
500}
501.decision-sub {
502 margin-top: 12px;
503 display: flex;
504 align-items: center;
505 gap: 8px;
506 flex-wrap: wrap;
507 color: var(--ink-3);
508 font-size: 12px;
509 font-weight: 500;
510}
511.decision-chip {
512 display: inline-flex;
513 align-items: center;
514 gap: 6px;
515 padding: 5px 9px;
516 border-radius: 999px;
517 background: var(--blue-soft);
518 color: var(--blue);
519 font-weight: 700;
520}
521.decision-side {
522 display: grid;
523 grid-template-columns: 1fr;
524 gap: 8px;
525 min-width: 190px;
526}
527.decision-metric {
528 padding: 12px 14px;
529 border-radius: 8px;
530 border: 1px solid var(--card-border);
531 background: rgba(255,255,255,0.52);
532}
533.dm-label {
534 color: var(--ink-3);
535 font-size: 10.5px;
536 font-weight: 700;
537 letter-spacing: 0.05em;
538 text-transform: uppercase;
539}
540.dm-value {
541 color: var(--ink);
542 font-size: 20px;
543 font-weight: 750;
544 letter-spacing: -0.04em;
545 margin-top: 4px;
546 font-variant-numeric: tabular-nums;
547}
548.dm-value.clickable {
549 cursor: pointer;
550 text-decoration: underline;
551 text-decoration-color: var(--ink-4);
552 text-underline-offset: 4px;
553 transition: color 0.2s;
554}
555.dm-value.clickable:hover {
556 color: var(--blue);
557 text-decoration-color: var(--blue);
558}
559
560.chart-legend {
561 display: flex;
562 align-items: center;
563 gap: 12px;
564 flex-wrap: wrap;
565 font-size: 11px;
566 color: var(--ink-3);
567 font-weight: 600;
568}
569.legend-item {
570 display: inline-flex;
571 align-items: center;
572 gap: 6px;
573 white-space: nowrap;
574}
575.legend-line {
576 width: 22px;
577 height: 2px;
578 border-radius: 999px;
579 background: var(--ink-4);
580}
581.legend-line.flora { background: var(--green); height: 3px; }
582.legend-line.avg {
583 background: repeating-linear-gradient(90deg, var(--blue) 0 6px, transparent 6px 10px);
584 height: 3px;
585}
586.legend-line.comp { background: rgba(0,0,0,0.22); }
587
588.kpi-row {
589 display: grid;
590 grid-template-columns: repeat(4, minmax(0, 1fr));
591 gap: 10px;
592 margin-bottom: 12px;
593}
594
595.kpi-card {
596 background: rgba(255,255,255,0.78);
597 backdrop-filter: blur(18px) saturate(160%);
598 -webkit-backdrop-filter: blur(18px) saturate(160%);
599 border: 1px solid var(--card-border);
600 border-radius: 8px;
601 padding: 16px 18px;
602 box-shadow: var(--card-shadow);
603 transition: box-shadow var(--mid) var(--ease), transform var(--mid) var(--spring), border-color var(--fast);
604 cursor: default;
605 position: relative;
606 overflow: hidden;
607}
608.kpi-card::before {
609 content: '';
610 position: absolute;
611 top: 0; left: 0; right: 0;
612 height: 1px;
613 background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.9) 50%, transparent 100%);
614}
615.kpi-card:hover {
616 box-shadow: var(--card-shadow-hover);
617 transform: translateY(-1px);
618 border-color: rgba(0,0,0,0.09);
619}
620
621.kpi-eyebrow {
622 display: flex; align-items: center; gap: 5px;
623 font-size: 10.5px;
624 font-weight: 500;
625 color: var(--ink-3);
626 letter-spacing: 0.04em;
627 text-transform: uppercase;
628 margin-bottom: 10px;
629}
630.kpi-eyebrow svg { width: 11px; height: 11px; opacity: 0.6; }
631
632.kpi-value {
633 font-size: 28px;
634 font-weight: 700;
635 letter-spacing: -0.04em;
636 line-height: 1;
637 color: var(--ink);
638 transition: color var(--mid);
639}
640.kpi-value.blue { color: var(--blue); }
641.kpi-value.green { color: var(--green); }
642.kpi-value.amber { color: var(--amber); }
643
644.kpi-hint {
645 display: flex; align-items: center; gap: 5px;
646 font-size: 11px;
647 color: var(--ink-3);
648 margin-top: 6px;
649 font-weight: 400;
650}
651
652/* ═══════════════════════════════════════
653 PANELS
654═══════════════════════════════════════ */
655.panel {
656 background: rgba(255,255,255,0.78);
657 backdrop-filter: blur(18px) saturate(160%);
658 -webkit-backdrop-filter: blur(18px) saturate(160%);
659 border: 1px solid var(--card-border);
660 border-radius: 8px;
661 box-shadow: var(--card-shadow);
662 overflow: hidden;
663 position: relative;
664 transition: box-shadow var(--mid) var(--ease);
665}
666.panel::before {
667 content: '';
668 position: absolute;
669 top: 0; left: 0; right: 0;
670 height: 1px;
671 background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.9) 50%, transparent 100%);
672 z-index: 1;
673}
674.panel:hover { box-shadow: var(--card-shadow-hover); }
675
676.panel-head {
677 display: flex; align-items: center; justify-content: space-between;
678 padding: 13px 18px;
679 border-bottom: 1px solid var(--card-border);
680 gap: 12px;
681 flex-wrap: wrap;
682}
683.panel-title {
684 display: flex; align-items: center; gap: 7px;
685 font-size: 12.5px;
686 font-weight: 700;
687 color: var(--ink);
688 letter-spacing: -0.01em;
689}
690.panel-title svg { width: 14px; height: 14px; color: var(--ink-3); }
691
692/* Date range control */
693.date-range {
694 display: flex; align-items: center; gap: 8px;
695 background: var(--ink-6);
696 border: 1px solid var(--card-border);
697 border-radius: var(--r-xs);
698 padding: 5px 10px;
699}
700.dr-lbl {
701 font-size: 9.5px;
702 font-weight: 600;
703 letter-spacing: 0.07em;
704 text-transform: uppercase;
705 color: var(--ink-3);
706}
707.dr-sep { width: 1px; height: 10px; background: var(--ink-5); }
708input[type="date"], select {
709 background: transparent;
710 border: none;
711 outline: none;
712 color: var(--ink-2);
713 font-family: 'DM Sans', sans-serif;
714 font-size: 11.5px;
715 font-weight: 500;
716 cursor: pointer;
717}
718input[type="date"]:focus, select:focus { color: var(--ink); }
719
720/* ═══════════════════════════════════════
721 TWO-COLUMN GRID
722═══════════════════════════════════════ */
723.g2 { display: grid; grid-template-columns: 1fr 295px; gap: 10px; }
724.g2eq { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
725.mb10 { margin-bottom: 10px; }
726.mb12 { margin-bottom: 12px; }
727
728/* ═══════════════════════════════════════
729 MATRIX TABLE
730═══════════════════════════════════════ */
731.mtx-scroll { overflow: auto; max-height: 420px; }
732.mtx { width: 100%; border-collapse: collapse; }
733.mtx thead th {
734 position: sticky; top: 0; z-index: 10;
735 background: rgba(250,250,252,0.95);
736 backdrop-filter: blur(8px);
737 font-size: 9.5px;
738 font-weight: 600;
739 letter-spacing: 0.07em;
740 text-transform: uppercase;
741 color: var(--ink-3);
742 padding: 9px 14px;
743 border-bottom: 1px solid var(--card-border);
744 white-space: nowrap;
745 text-align: center;
746 cursor: pointer;
747 transition: color 0.15s, background 0.15s;
748}
749.mtx thead th:hover {
750 color: var(--blue);
751 background: rgba(0,110,220,0.04);
752}
753.mtx thead th:first-child { text-align: left; position: sticky; left: 0; z-index: 20; cursor: default; }
754.mtx thead th:first-child:hover { color: var(--ink-3); background: rgba(250,250,252,0.95); }
755.mtx tbody td {
756 padding: 8px 14px;
757 font-size: 12px;
758 text-align: center;
759 color: var(--ink-2);
760 border-bottom: 1px solid rgba(0,0,0,0.04);
761 font-variant-numeric: tabular-nums;
762 transition: background var(--fast);
763}
764.mtx tbody td:first-child {
765 text-align: left;
766 position: sticky; left: 0;
767 background: var(--card-bg);
768 z-index: 5;
769}
770.mtx tbody tr:last-child td { border-bottom: none; }
771.mtx tbody tr { transition: background var(--fast); }
772.mtx tbody tr:hover td { background: rgba(0,0,0,0.015); }
773.mtx tbody tr:hover td:first-child { background: rgba(250,250,252,0.98); }
774.mtx tbody tr.is-target td:first-child { background: var(--blue-soft); }
775.mtx tbody tr.is-target:hover td:first-child { background: rgba(0,110,220,0.1); }
776
777.h-cell { display: flex; align-items: center; justify-content: space-between; gap: 6px; }
778.h-name {
779 font-size: 12px;
780 font-weight: 500;
781 color: var(--ink-2);
782 white-space: nowrap;
783 overflow: hidden;
784 text-overflow: ellipsis;
785 max-width: 126px;
786}
787.h-name.target { color: var(--ink); font-weight: 600; }
788
789.badge {
790 display: inline-flex; align-items: center;
791 font-size: 9px;
792 font-weight: 700;
793 letter-spacing: 0.06em;
794 text-transform: uppercase;
795 padding: 2px 6px;
796 border-radius: 4px;
797 flex-shrink: 0;
798}
799.badge-you { background: var(--blue-soft); color: var(--blue); }
800.badge-so { background: var(--red-soft); color: var(--red); }
801
802.p-val { font-size: 12px; font-weight: 500; font-variant-numeric: tabular-nums; color: var(--ink-2); }
803.p-val.target { color: var(--green); font-weight: 600; }
804
805.mv-btn {
806 background: none; border: none; cursor: pointer;
807 color: var(--ink-4);
808 font-size: 9px;
809 padding: 1px 2px;
810 border-radius: 3px;
811 line-height: 1;
812 transition: color var(--fast), background var(--fast);
813}
814.mv-btn:hover { color: var(--ink); background: var(--ink-6); }
815
816/* ═══════════════════════════════════════
817 ACTION PLAN
818═══════════════════════════════════════ */
819.apl {
820 padding: 8px;
821 display: flex;
822 flex-direction: column;
823 gap: 5px;
824 max-height: 420px;
825 overflow-y: auto;
826}
827
828.acard {
829 border: 1px solid var(--card-border);
830 border-radius: var(--r-sm);
831 padding: 11px 13px;
832 cursor: pointer;
833 background: rgba(0,0,0,0.014);
834 transition: background var(--fast), border-color var(--fast), transform var(--fast) var(--spring), box-shadow var(--fast);
835 position: relative;
836}
837.acard:hover {
838 background: var(--white);
839 border-color: rgba(0,0,0,0.1);
840 box-shadow: 0 2px 8px rgba(0,0,0,0.06);
841 transform: translateY(-1px);
842}
843.acard.sel {
844 background: var(--blue-soft);
845 border-color: var(--blue-ring);
846 box-shadow: 0 0 0 1px var(--blue-ring);
847}
848.acard.sel:hover { transform: none; }
849
850.ac-top { display: flex; align-items: center; justify-content: space-between; margin-bottom: 9px; }
851.ac-date {
852 font-size: 12.5px;
853 font-weight: 700;
854 color: var(--ink);
855 letter-spacing: -0.02em;
856 font-variant-numeric: tabular-nums;
857}
858.pill {
859 font-size: 9.5px;
860 font-weight: 700;
861 letter-spacing: 0.04em;
862 text-transform: uppercase;
863 padding: 3px 8px;
864 border-radius: 20px;
865}
866.pill-g { background: var(--green-soft); color: var(--green); }
867.pill-b { background: var(--blue-soft); color: var(--blue); }
868.pill-a { background: var(--amber-soft); color: var(--amber); }
869.pill-r { background: var(--red-soft); color: var(--red); }
870
871.ac-body { display: grid; grid-template-columns: 1fr 1fr; gap: 0; }
872.ac-metric {}
873.ac-metric-lbl { font-size: 10px; color: var(--ink-3); font-weight: 400; }
874.ac-metric-val {
875 font-size: 15px;
876 font-weight: 700;
877 color: var(--ink);
878 letter-spacing: -0.03em;
879 font-variant-numeric: tabular-nums;
880 margin-top: 1px;
881}
882.ac-metric-val.accent { color: var(--blue); }
883
884/* ═══════════════════════════════════════
885 SECTION HEADER
886═══════════════════════════════════════ */
887.view-head { margin-bottom: 16px; }
888.vh-title {
889 font-size: 22px;
890 font-weight: 700;
891 letter-spacing: -0.04em;
892 color: var(--ink);
893}
894.vh-sub {
895 font-size: 12.5px;
896 color: var(--ink-3);
897 margin-top: 3px;
898 font-weight: 400;
899}
900
901/* ═══════════════════════════════════════
902 SELECT CONTROL
903═══════════════════════════════════════ */
904.sel-box {
905 background: var(--ink-6);
906 border: 1px solid var(--card-border);
907 border-radius: var(--r-xs);
908 padding: 5px 10px;
909 font-family: 'DM Sans', sans-serif;
910 font-size: 11.5px;
911 font-weight: 500;
912 color: var(--ink-2);
913 outline: none;
914 cursor: pointer;
915 transition: border-color var(--fast), color var(--fast);
916}
917.sel-box:focus { border-color: var(--blue); color: var(--ink); }
918.sel-box:hover { border-color: var(--ink-4); }
919
920/* ═══════════════════════════════════════
921 YIELD RULES
922═══════════════════════════════════════ */
923.yield-rule {
924 background: rgba(0,0,0,0.015);
925 border: 1px solid var(--card-border);
926 border-left: 2px solid;
927 border-radius: var(--r-sm);
928 padding: 14px 16px;
929 transition: background var(--fast);
930}
931.yield-rule:hover { background: rgba(0,0,0,0.03); }
932.yr-title { font-size: 12.5px; font-weight: 700; margin-bottom: 5px; letter-spacing: -0.01em; }
933.yr-body { font-size: 12px; color: var(--ink-2); line-height: 1.6; }
934
935/* ═══════════════════════════════════════
936 VIEWS
937═══════════════════════════════════════ */
938#view-radar, #view-seasonal { display: none; }
939
940/* ═══════════════════════════════════════
941 EMPTY STATE
942═══════════════════════════════════════ */
943.empty-state {
944 display: flex; flex-direction: column; align-items: center; justify-content: center;
945 padding: 52px 24px; text-align: center;
946}
947.empty-state svg { width: 28px; height: 28px; color: var(--ink-4); margin-bottom: 12px; }
948.es-title { font-size: 13.5px; font-weight: 600; color: var(--ink-2); margin-bottom: 4px; }
949.es-sub { font-size: 12px; color: var(--ink-3); }
950
951/* ═══════════════════════════════════════
952 MODAL
953═══════════════════════════════════════ */
954.modal-ov {
955 position: fixed; inset: 0; z-index: 200;
956 background: rgba(0,0,0,0.25);
957 backdrop-filter: blur(10px) saturate(160%);
958 -webkit-backdrop-filter: blur(10px) saturate(160%);
959 display: flex; align-items: center; justify-content: center;
960 animation: fadeOv var(--fast) var(--ease) both;
961}
962@keyframes fadeOv { from { opacity: 0; } to { opacity: 1; } }
963
964.modal-box {
965 background: rgba(255,255,255,0.9);
966 backdrop-filter: blur(32px) saturate(200%);
967 -webkit-backdrop-filter: blur(32px) saturate(200%);
968 border: 1px solid rgba(0,0,0,0.08);
969 border-radius: 18px;
970 width: 100%;
971 max-width: 580px;
972 margin: 0 16px;
973 overflow: hidden;
974 box-shadow: 0 4px 8px rgba(0,0,0,0.04), 0 24px 64px rgba(0,0,0,0.12), 0 0 0 1px rgba(255,255,255,0.6) inset;
975 animation: modalIn var(--mid) var(--spring) both;
976}
977@keyframes modalIn {
978 from { opacity: 0; transform: scale(0.96) translateY(4px); }
979 to { opacity: 1; transform: scale(1) translateY(0); }
980}
981
982.modal-head {
983 padding: 14px 18px;
984 border-bottom: 1px solid var(--card-border);
985 display: flex; align-items: center; justify-content: space-between;
986}
987.modal-close {
988 width: 24px; height: 24px;
989 border-radius: 50%;
990 background: var(--ink-6);
991 border: 1px solid var(--card-border);
992 display: flex; align-items: center; justify-content: center;
993 cursor: pointer;
994 color: var(--ink-3);
995 transition: background var(--fast), color var(--fast), transform var(--fast) var(--spring);
996}
997.modal-close:hover { background: var(--ink-5); color: var(--ink); transform: scale(1.1); }
998.modal-close svg { width: 11px; height: 11px; }
999
1000/* ═══════════════════════════════════════
1001 INLINE SVG ICONS (no external dep)
1002═══════════════════════════════════════ */
1003.ico { display: inline-block; vertical-align: middle; flex-shrink: 0; }
1004</style>
1005</head>
1006<body>
1007
1008<div class="app">
1009
1010 <!-- ════════════════════════
1011 SIDEBAR
1012 ════════════════════════ -->
1013 <aside class="sidebar">
1014 <div class="sb-top">
1015 <div class="wordmark">
1016 <div class="wordmark-icon">
1017 <span class="wi-letter">F</span>
1018 </div>
1019 <div class="wordmark-text">
1020 <div class="wm-name">Flora</div>
1021 <div class="wm-sub">Yield Intelligence</div>
1022 </div>
1023 </div>
1024
1025 <!-- Room switcher -->
1026 <div class="room-sw" id="room-sw">
1027 <div class="room-sw-track" id="room-track"></div>
1028 <button class="room-btn" id="btn-room-Singola" onclick="setRoom('Singola')">Singola</button>
1029 <button class="room-btn active" id="btn-room-Doppia" onclick="setRoom('Doppia')">Doppia</button>
1030 </div>
1031 </div>
1032
1033 <nav class="sb-nav">
1034 <div class="nav-section-label">Analisi</div>
1035 <button class="nav-item active" id="btn-dashboard" onclick="setView('dashboard')">
1036 <svg class="ico" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="1" y="1" width="6" height="6" rx="1.5"/><rect x="9" y="1" width="6" height="6" rx="1.5"/><rect x="1" y="9" width="6" height="6" rx="1.5"/><rect x="9" y="9" width="6" height="6" rx="1.5"/></svg>
1037 Operativa
1038 </button>
1039 <button class="nav-item" id="btn-radar" onclick="setView('radar')">
1040 <svg class="ico" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="8" cy="8" r="7"/><circle cx="8" cy="8" r="4"/><circle cx="8" cy="8" r="1" fill="currentColor" stroke="none"/><line x1="8" y1="1" x2="8" y2="4"/><line x1="11.5" y1="4.5" x2="9.5" y2="6.5"/></svg>
1041 Radar 365
1042 </button>
1043 <button class="nav-item" id="btn-seasonal" onclick="setView('seasonal')">
1044 <svg class="ico" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="1,12 5,7 9,10 15,3"/><line x1="1" y1="15" x2="15" y2="15"/></svg>
1045 Stagionale
1046 </button>
1047 </nav>
1048
1049 <div class="sb-footer">
1050 <div class="status-chip">
1051 <div class="s-dot"></div>
1052 <span class="s-label">Live</span>
1053 <span class="s-clock" id="hclock">--:--</span>
1054 </div>
1055 </div>
1056 </aside>
1057
1058 <!-- ════════════════════════
1059 MAIN
1060 ════════════════════════ -->
1061 <div class="main">
1062
1063 <!-- Topbar -->
1064 <header class="topbar">
1065 <div class="topbar-left">
1066 <span class="topbar-title" id="topbar-title">Operativa</span>
1067 <div class="topbar-div"></div>
1068 <span class="topbar-meta">
1069 <svg class="ico" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><rect x="1" y="2" width="10" height="9" rx="1.5"/><line x1="4" y1="1" x2="4" y2="3"/><line x1="8" y1="1" x2="8" y2="3"/><line x1="1" y1="5" x2="11" y2="5"/></svg>
1070 Hotel Flora · 50 camere
1071 </span>
1072 </div>
1073 <div class="topbar-actions">
1074 <div class="scan-state" id="scan-state">Pronto</div>
1075 <button class="theme-toggle" id="theme-toggle" onclick="toggleTheme()" title="Cambia tema">
1076 <svg id="theme-icon" class="ico" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><circle cx="8" cy="8" r="3.5"/><path d="M8 1v2M8 13v2M1 8h2M13 8h2M3.1 3.1l1.4 1.4M11.5 11.5l1.4 1.4M12.9 3.1l-1.4 1.4M4.5 11.5l-1.4 1.4"/></svg>
1077 </button>
1078 <button class="scan-btn" id="btn-run-bot" onclick="avviaBotRemoto()">
1079 <svg id="bot-icon" class="ico" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><polygon points="3,1 11,6 3,11"/></svg>
1080 <span id="bot-text">Avvia Scansione</span>
1081 </button>
1082 </div>
1083 </header>
1084
1085 <!-- Content -->
1086 <div class="content">
1087
1088 <!-- ══════════ DASHBOARD ══════════ -->
1089 <div id="view-dashboard" class="view">
1090
1091 <div class="decision-panel">
1092 <section class="decision-card">
1093 <div>
1094 <div class="decision-eyebrow">Decisione tariffaria</div>
1095 <div class="decision-main">
1096 <div class="decision-copy">
1097 <div class="decision-value" id="hero-suggested">—</div>
1098 <div class="decision-sub">
1099 <span class="decision-chip" id="hero-strategy">Strategia —</span>
1100 <span id="hero-delta">vs media aggregata —</span>
1101 </div>
1102 </div>
1103 <div class="decision-side">
1104 <div class="decision-metric">
1105 <div class="dm-label">Media aggregata</div>
1106 <div class="dm-value" id="hero-avg">—</div>
1107 </div>
1108 <div class="decision-metric">
1109 <div class="dm-label">Data selezionata</div>
1110 <div class="dm-value clickable" id="hero-date" onclick="pickDate()" title="Clicca per cambiare data">—</div>
1111 </div>
1112 </div>
1113 </div>
1114 </div>
1115 </section>
1116
1117 <section class="decision-card">
1118 <div class="decision-eyebrow">Mercato</div>
1119 <div class="decision-side" style="min-width:0;">
1120 <div class="decision-metric">
1121 <div class="dm-label">Competitor attivi</div>
1122 <div class="dm-value" id="hero-active">—</div>
1123 </div>
1124 <div class="decision-metric">
1125 <div class="dm-label">Incasso stimato</div>
1126 <div class="dm-value" id="hero-revenue">—</div>
1127 </div>
1128 </div>
1129 </section>
1130 </div>
1131
1132 <!-- KPIs -->
1133 <div class="kpi-row mb12">
1134 <div class="kpi-card">
1135 <div class="kpi-eyebrow">
1136 <svg class="ico" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><polyline points="1,9 4,5 7,7 11,2"/></svg>
1137 Stato Mercato
1138 </div>
1139 <div class="kpi-value blue" id="kpi-strategy">—</div>
1140 <div class="kpi-hint" id="kpi-active-comps">— competitor attivi</div>
1141 </div>
1142 <div class="kpi-card">
1143 <div class="kpi-eyebrow">
1144 <svg class="ico" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><polygon points="6,1 8,4 11,4.5 9,7 9.5,11 6,9.5 2.5,11 3,7 1,4.5 4,4"/></svg>
1145 Prezzo Suggerito
1146 </div>
1147 <div style="display:flex;align-items:baseline;gap:7px;">
1148 <div class="kpi-value green" id="kpi-suggested">—</div>
1149 <div class="kpi-hint" id="kpi-avg" style="margin-top:0;">vs — media</div>
1150 </div>
1151 <div class="kpi-hint" id="kpi-strategy-desc">Strategia: —</div>
1152 </div>
1153 <div class="kpi-card">
1154 <div class="kpi-eyebrow">
1155 <svg class="ico" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><line x1="1" y1="9" x2="11" y2="9"/><line x1="2" y1="6" x2="10" y2="6"/><line x1="3" y1="3" x2="9" y2="3"/></svg>
1156 Media Aggregata
1157 </div>
1158 <div class="kpi-value blue" id="kpi-aggregate">—</div>
1159 <div class="kpi-hint">Benchmark competitor filtrato</div>
1160 </div>
1161 <div class="kpi-card">
1162 <div class="kpi-eyebrow">
1163 <svg class="ico" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><polyline points="1,10 4,6 7,8 11,3"/><polyline points="8,3 11,3 11,6"/></svg>
1164 Proiezione Incasso
1165 </div>
1166 <div class="kpi-value amber" id="kpi-revenue">—</div>
1167 <div class="kpi-hint" id="kpi-revenue-desc">Target 20 camere · 100% occupazione</div>
1168 </div>
1169 </div>
1170
1171 <!-- Chart -->
1172 <div class="panel mb10">
1173 <div class="panel-head">
1174 <div class="panel-title">
1175 <svg class="ico" viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="1,10 5,5.5 8,8 13,2.5"/></svg>
1176 Andamento Prezzi
1177 </div>
1178 <div class="chart-legend" aria-label="Legenda andamento prezzi">
1179 <span class="legend-item"><span class="legend-line flora"></span>Hotel Flora</span>
1180 <span class="legend-item"><span class="legend-line avg"></span>Media aggregata</span>
1181 <span class="legend-item"><span class="legend-line comp"></span>Competitor</span>
1182 </div>
1183 <div class="date-range">
1184 <span class="dr-lbl">Da</span>
1185 <input type="date" id="dash-chart-start" onchange="renderFilteredChart()">
1186 <div class="dr-sep"></div>
1187 <span class="dr-lbl">A</span>
1188 <input type="date" id="dash-chart-end" onchange="renderFilteredChart()">
1189 </div>
1190 </div>
1191 <div style="padding:16px 18px;">
1192 <div style="height:318px;position:relative;"><canvas id="filteredChart"></canvas></div>
1193 </div>
1194 </div>
1195
1196 <!-- Matrix + Action -->
1197 <div class="g2">
1198 <div class="panel" style="display:flex;flex-direction:column;">
1199 <div class="panel-head">
1200 <div class="panel-title">
