gioser-web: fix graph widget — rect nodes, edge weight, CSS anim, layout
1/* === Tokens === */
2:root {
3 --bg: #06050d;
4 --fg: #e8eaf5;
5 --gold: #d8a85d;
6 --gold-deep: #b77e34;
7 --aire: #d0dbff;
8 --agua: #6cd0f3;
9 --fuego: #f59056;
10 --tierra: #d49873;
11
12 --ease-emerge: cubic-bezier(0.22, 0.61, 0.20, 1);
13 --ease-magma: cubic-bezier(0.32, 0, 0.05, 1);
14 --ease-page: cubic-bezier(0.22, 0.61, 0.36, 1);
15
16 --taskbar-height: 52px;
17}
18
19* { box-sizing: border-box; }
20
21html, body {
22 margin: 0;
23 padding: 0;
24 width: 100%;
25 height: 100%;
26 background: var(--bg);
27 color: var(--fg);
28 font-family: 'Inter', system-ui, -apple-system, sans-serif;
29 font-weight: 300;
30 overflow: hidden;
31}
32
33/* === Canvas WebGL === */
34#gioser-canvas {
35 position: fixed;
36 inset: 0;
37 width: 100vw;
38 height: 100vh;
39 display: block;
40 z-index: 0;
41 transition: opacity 600ms var(--ease-emerge), filter 600ms var(--ease-emerge);
42}
43body.deck-visible #gioser-canvas {
44 opacity: 0.30;
45 filter: blur(4px) saturate(80%);
46}
47
48/* === Tips (botones cardinales sobre el aro) === */
49#tips {
50 position: fixed;
51 inset: 0;
52 pointer-events: none;
53 z-index: 5;
54 transition: opacity 250ms ease;
55}
56body.deck-visible #tips {
57 opacity: 0;
58 pointer-events: none;
59}
60
61.tip {
62 position: absolute;
63 top: 0; left: 0;
64 pointer-events: auto;
65 text-decoration: none;
66 color: var(--fg);
67 user-select: none;
68 cursor: pointer;
69
70 display: flex;
71 flex-direction: column;
72 align-items: center;
73 gap: 0.55rem;
74 padding: 1.1rem 1.6rem 0.95rem;
75 min-width: 168px;
76
77 background:
78 radial-gradient(ellipse at top, rgba(255, 255, 255, 0.04), transparent 65%),
79 rgba(8, 6, 22, 0.55);
80 backdrop-filter: blur(12px) saturate(140%);
81 -webkit-backdrop-filter: blur(12px) saturate(140%);
82 border-radius: 20px;
83 border: 1px solid rgba(216, 168, 93, 0.25);
84
85 box-shadow:
86 0 12px 36px rgba(0, 0, 0, 0.40),
87 inset 0 0 0 1px rgba(255, 255, 255, 0.04);
88
89 transition:
90 box-shadow 350ms var(--ease-emerge),
91 border-color 350ms var(--ease-emerge),
92 background 350ms var(--ease-emerge);
93}
94.tip::before {
95 content: "";
96 position: absolute;
97 inset: -10px;
98 border-radius: 26px;
99 border: 1px solid currentColor;
100 opacity: 0;
101 transition: opacity 400ms ease, inset 400ms var(--ease-emerge);
102 pointer-events: none;
103}
104.tip:hover {
105 border-color: currentColor;
106 background:
107 radial-gradient(ellipse at top, rgba(255, 255, 255, 0.07), transparent 65%),
108 rgba(20, 14, 40, 0.72);
109}
110.tip:hover::before {
111 opacity: 0.45;
112 inset: -16px;
113}
114.tip-glyph {
115 width: 54px;
116 height: 54px;
117 color: currentColor;
118 filter: drop-shadow(0 0 6px currentColor) drop-shadow(0 0 16px currentColor);
119 transition: filter 320ms ease, transform 350ms var(--ease-emerge);
120}
121.tip:hover .tip-glyph {
122 filter: drop-shadow(0 0 14px currentColor) drop-shadow(0 0 28px currentColor);
123 transform: translateY(-3px);
124}
125.tip-label {
126 font-family: 'Cinzel', serif;
127 font-size: 0.95rem;
128 letter-spacing: 0.42em;
129 font-weight: 600;
130 text-indent: 0.42em;
131 margin-top: 0.15rem;
132}
133.tip-sub {
134 font-family: 'Inter', sans-serif;
135 font-size: 0.7rem;
136 letter-spacing: 0.22em;
137 font-weight: 300;
138 color: rgba(232, 234, 245, 0.62);
139 text-transform: uppercase;
140 text-indent: 0.22em;
141}
142.tip-aire { color: var(--aire); }
143.tip-fuego { color: var(--fuego); }
144.tip-agua { color: var(--agua); }
145.tip-tierra { color: var(--tierra); }
146
147/* === DECK: contenedor único de páginas swipeable === */
148.deck {
149 position: fixed;
150 top: 0;
151 left: 0;
152 right: 0;
153 bottom: var(--taskbar-height);
154 z-index: 100;
155 pointer-events: none;
156 opacity: 0;
157 visibility: hidden;
158 transform-origin: var(--origin-x, 50%) var(--origin-y, 50%);
159 transform: scale(0.0);
160 overflow: hidden;
161 touch-action: pan-y;
162 background:
163 radial-gradient(ellipse at center, var(--deck-glow, rgba(216, 168, 93, 0.15)), transparent 65%),
164 rgba(6, 5, 13, 0.96);
165 backdrop-filter: blur(28px) saturate(140%);
166 -webkit-backdrop-filter: blur(28px) saturate(140%);
167 transition:
168 transform 600ms var(--ease-magma),
169 opacity 450ms ease,
170 visibility 0s 600ms;
171}
172.deck.open {
173 pointer-events: auto;
174 opacity: 1;
175 visibility: visible;
176 transform: scale(1);
177 transition:
178 transform 600ms var(--ease-magma),
179 opacity 450ms ease,
180 visibility 0s;
181}
182/* Acento del deck según elemento activo: glow radial del color. */
183body.deck-active-aire .deck { --deck-glow: rgba(208, 219, 255, 0.22); }
184body.deck-active-fuego .deck { --deck-glow: rgba(245, 144, 86, 0.28); }
185body.deck-active-agua .deck { --deck-glow: rgba(108, 208, 243, 0.22); }
186body.deck-active-tierra .deck { --deck-glow: rgba(212, 152, 115, 0.24); }
187
188/* Strip horizontal con páginas — vista-web traslada esto.
189 touch-action: pan-y declara al browser "yo manejo horizontal, el
190 vertical (scroll interno de cada página) lo dejas pasar". Sin esto
191 el navegador móvil se traga el gesto horizontal antes de que JS
192 pueda capturarlo. */
193.deck-strip {
194 display: flex;
195 flex-direction: row;
196 width: 100%;
197 height: 100%;
198 transform: translate3d(var(--vista-offset, 0px), 0, 0);
199 transition: transform 360ms var(--ease-page);
200 will-change: transform;
201 touch-action: pan-y;
202}
203/* Asegurar que TODOS los descendientes del strip hereden el contrato
204 touch-action — si el toque llega a un párrafo o <a>, el browser
205 chequea el touch-action del target, no del padre. */
206.deck-strip * {
207 touch-action: pan-y;
208}
209.deck-strip.vista-dragging,
210.deck-strip.vista-instant {
211 transition: none;
212}
213
214.deck-page {
215 flex: 0 0 100%;
216 width: 100%;
217 height: 100%;
218 position: relative;
219 overflow-y: auto;
220 overflow-x: hidden;
221 touch-action: pan-y;
222}
223.deck-page[data-element="aire"] { --page-accent: var(--aire); }
224.deck-page[data-element="fuego"] { --page-accent: var(--fuego); }
225.deck-page[data-element="agua"] { --page-accent: var(--agua); }
226.deck-page[data-element="tierra"] { --page-accent: var(--tierra); }
227
228/* Ambience por página */
229.page-ambience {
230 position: absolute;
231 inset: 0;
232 pointer-events: none;
233 z-index: 0;
234}
235.deck-page[data-element="aire"] .page-ambience {
236 background:
237 radial-gradient(circle at 18% 22%, rgba(208, 219, 255, 0.20), transparent 38%),
238 radial-gradient(circle at 78% 68%, rgba(208, 219, 255, 0.14), transparent 40%),
239 radial-gradient(circle at 45% 90%, rgba(180, 200, 255, 0.10), transparent 45%);
240 animation: aire-drift 45s ease-in-out infinite alternate;
241}
242.deck-page[data-element="fuego"] .page-ambience {
243 background:
244 radial-gradient(circle at 50% 100%, rgba(245, 144, 86, 0.35), transparent 55%),
245 radial-gradient(circle at 25% 80%, rgba(255, 90, 40, 0.18), transparent 35%),
246 radial-gradient(circle at 80% 85%, rgba(255, 140, 60, 0.18), transparent 35%);
247 animation: fuego-flicker 12s ease-in-out infinite;
248}
249.deck-page[data-element="agua"] .page-ambience {
250 background:
251 radial-gradient(ellipse at 50% 95%, rgba(60, 160, 230, 0.30), transparent 60%),
252 radial-gradient(ellipse at 20% 70%, rgba(108, 208, 243, 0.15), transparent 50%),
253 radial-gradient(ellipse at 80% 75%, rgba(108, 208, 243, 0.12), transparent 50%);
254 animation: agua-tide 30s ease-in-out infinite alternate;
255}
256.deck-page[data-element="tierra"] .page-ambience {
257 background:
258 radial-gradient(ellipse at 50% 100%, rgba(120, 80, 40, 0.40), transparent 60%),
259 radial-gradient(ellipse at 22% 88%, rgba(180, 130, 80, 0.20), transparent 45%),
260 radial-gradient(ellipse at 78% 88%, rgba(150, 100, 60, 0.22), transparent 45%);
261}
262/* Animaciones sutiles — solo opacidad, sin desplazamiento visible.
263 El movimiento (transform) del fondo causaba un "respiro" molesto
264 al abrir el deck. */
265@keyframes aire-drift {
266 from { opacity: 0.60; }
267 to { opacity: 0.90; }
268}
269@keyframes fuego-flicker {
270 0%, 100% { opacity: 0.65; }
271 35% { opacity: 0.90; }
272 60% { opacity: 0.75; }
273}
274@keyframes agua-tide {
275 from { opacity: 0.55; }
276 to { opacity: 0.85; }
277}
278
279/* Head + controls */
280.page-controls {
281 position: absolute;
282 top: 1.8vh;
283 right: 1.8vw;
284 z-index: 5;
285 display: flex;
286 gap: 0.5rem;
287}
288.page-control-btn {
289 width: 40px;
290 height: 40px;
291 border-radius: 50%;
292 background: rgba(255, 255, 255, 0.04);
293 border: 1px solid rgba(255, 255, 255, 0.18);
294 color: var(--page-accent, var(--gold));
295 font-size: 1.2rem;
296 line-height: 1;
297 cursor: pointer;
298 display: inline-flex;
299 align-items: center;
300 justify-content: center;
301 padding: 0;
302 font-family: 'Inter', sans-serif;
303 transition:
304 background 200ms ease,
305 border-color 200ms ease,
306 transform 250ms var(--ease-emerge);
307}
308.page-control-btn:hover {
309 background: rgba(255, 255, 255, 0.10);
310 border-color: currentColor;
311}
312.page-minimize svg {
313 width: 18px;
314 height: 18px;
315}
316.page-close {
317 font-size: 1.6rem;
318}
319.page-close:hover { transform: rotate(90deg); }
320
321.page-head {
322 position: relative;
323 z-index: 2;
324 text-align: center;
325 padding: 7vh 8vw 2vh;
326 color: var(--page-accent, var(--gold));
327}
328.page-mark {
329 display: inline-block;
330 font-family: 'Inter', sans-serif;
331 font-size: 0.7rem;
332 letter-spacing: 0.55em;
333 text-transform: uppercase;
334 color: rgba(232, 234, 245, 0.6);
335 margin-bottom: 0.4rem;
336 text-indent: 0.55em;
337}
338.page-title {
339 font-family: 'Cinzel', serif;
340 font-weight: 700;
341 font-size: clamp(2.4rem, 6vw, 4.6rem);
342 margin: 0;
343 letter-spacing: 0.08em;
344 color: var(--page-accent, var(--gold));
345 text-shadow: 0 0 28px currentColor, 0 0 56px rgba(255, 255, 255, 0.10);
346}
347.page-tag {
348 display: block;
349 font-family: 'Inter', sans-serif;
350 font-size: 0.78rem;
351 letter-spacing: 0.32em;
352 text-transform: uppercase;
353 color: rgba(232, 234, 245, 0.55);
354 margin-top: 0.7rem;
355 text-indent: 0.32em;
356}
357.page-content {
358 position: relative;
359 z-index: 2;
360 padding: 1vh 10vw 8vh;
361 opacity: 0;
362 transition: opacity 400ms ease 250ms;
363}
364.deck.open .deck-page .page-content {
365 opacity: 1;
366}
367
368/* === pluma-doc dentro de la página === */
369.pluma-doc {
370 max-width: 760px;
371 margin: 0 auto;
372 font-family: 'Inter', sans-serif;
373 font-weight: 300;
374 font-size: 1.05rem;
375 line-height: 1.78;
376 color: rgba(232, 234, 245, 0.92);
377}
378.pluma-doc > * + * { margin-top: 1.0em; }
379.pluma-doc h1 {
380 font-family: 'Cinzel', serif;
381 font-weight: 700;
382 font-size: clamp(1.7rem, 3vw, 2.4rem);
383 color: var(--page-accent);
384 text-shadow: 0 0 18px currentColor;
385 letter-spacing: 0.04em;
386 margin-top: 1.4em;
387}
388.pluma-doc h2 {
389 font-family: 'Cinzel', serif;
390 font-weight: 500;
391 font-size: 1.5rem;
392 color: var(--page-accent);
393 letter-spacing: 0.04em;
394 margin-top: 1.6em;
395 padding-bottom: 0.3em;
396 border-bottom: 1px solid rgba(255, 255, 255, 0.10);
397}
398.pluma-doc h3 {
399 font-family: 'Inter', sans-serif;
400 font-weight: 600;
401 font-size: 1.18rem;
402 color: rgba(255, 255, 255, 0.92);
403 letter-spacing: 0.03em;
404 margin-top: 1.6em;
405}
406.pluma-doc p { margin: 0; }
407.pluma-doc a {
408 color: var(--page-accent);
409 text-decoration: none;
410 border-bottom: 1px solid currentColor;
411 transition: opacity 200ms ease;
412}
413.pluma-doc a:hover { opacity: 0.7; }
414.pluma-doc strong { color: rgba(255, 255, 255, 0.98); font-weight: 600; }
415.pluma-doc em { color: rgba(255, 255, 255, 0.92); }
416.pluma-doc code {
417 font-family: 'JetBrains Mono', ui-monospace, monospace;
418 background: rgba(255, 255, 255, 0.06);
419 padding: 0.12em 0.45em;
420 border-radius: 4px;
421 font-size: 0.92em;
422 color: var(--page-accent);
423}
424.pluma-doc pre {
425 background: rgba(0, 0, 0, 0.45);
426 border: 1px solid rgba(255, 255, 255, 0.08);
427 border-left: 3px solid var(--page-accent);
428 border-radius: 8px;
429 padding: 1rem 1.2rem;
430 overflow-x: auto;
431 font-size: 0.92rem;
432}
433.pluma-doc pre code {
434 background: transparent;
435 color: rgba(232, 234, 245, 0.92);
436 padding: 0;
437}
438.pluma-doc blockquote {
439 border-left: 3px solid var(--page-accent);
440 padding: 0.4em 1.2em;
441 color: rgba(232, 234, 245, 0.75);
442 font-style: italic;
443 background: rgba(255, 255, 255, 0.03);
444 border-radius: 0 6px 6px 0;
445}
446.pluma-doc ul, .pluma-doc ol { padding-left: 1.6em; }
447.pluma-doc li { margin: 0.4em 0; }
448.pluma-doc li::marker { color: var(--page-accent); }
449.pluma-doc hr {
450 border: none;
451 height: 1px;
452 background: linear-gradient(to right, transparent, var(--page-accent), transparent);
453 margin: 2em 0;
454}
455.pluma-doc table {
456 border-collapse: collapse;
457 width: 100%;
458 font-size: 0.95rem;
459}
460.pluma-doc th, .pluma-doc td {
461 padding: 0.55em 0.9em;
462 border-bottom: 1px solid rgba(255, 255, 255, 0.08);
463 text-align: left;
464}
465.pluma-doc th {
466 color: var(--page-accent);
467 font-weight: 600;
468 letter-spacing: 0.04em;
469}
470.pluma-loading, .pluma-error {
471 display: flex;
472 align-items: center;
473 justify-content: center;
474 min-height: 30vh;
475 color: rgba(232, 234, 245, 0.55);
476 font-family: 'Cinzel', serif;
477 letter-spacing: 0.4em;
478 font-size: 0.9rem;
479}
480.pluma-loading::before {
481 content: "";
482 width: 28px;
483 height: 28px;
484 margin-right: 1rem;
485 border: 1px solid var(--page-accent);
486 border-top-color: transparent;
487 border-radius: 50%;
488 animation: pluma-spin 1s linear infinite;
489}
490.pluma-error { color: var(--fuego); font-style: italic; }
491@keyframes pluma-spin { to { transform: rotate(360deg); } }
492
493/* === Taskbar estilo Windows === */
494.taskbar {
495 position: fixed;
496 left: 0;
497 right: 0;
498 bottom: 0;
499 height: var(--taskbar-height);
500 z-index: 200;
501 display: flex;
502 align-items: center;
503 gap: 0.5rem;
504 padding: 0 0.8rem;
505 background: linear-gradient(to top, rgba(6, 5, 13, 0.94), rgba(8, 6, 22, 0.80));
506 backdrop-filter: blur(24px) saturate(140%);
507 -webkit-backdrop-filter: blur(24px) saturate(140%);
508 border-top: 1px solid rgba(216, 168, 93, 0.22);
509 box-shadow: 0 -10px 36px rgba(0, 0, 0, 0.45);
510}
511
512.taskbar-home {
513 width: 40px;
514 height: 40px;
515 display: inline-flex;
516 align-items: center;
517 justify-content: center;
518 background: transparent;
519 border: 1px solid rgba(216, 168, 93, 0.32);
520 color: var(--gold);
521 border-radius: 9px;
522 cursor: pointer;
523 padding: 0;
524 transition: all 220ms var(--ease-emerge);
525}
526.taskbar-home:hover {
527 border-color: var(--gold);
528 background: rgba(216, 168, 93, 0.12);
529 box-shadow: 0 0 16px rgba(216, 168, 93, 0.35);
530 transform: translateY(-1px);
531}
532.taskbar-home-glyph {
533 width: 22px;
534 height: 22px;
535 filter: drop-shadow(0 0 6px currentColor);
536}
537
538.taskbar-brand {
539 font-family: 'Cinzel', serif;
540 font-weight: 700;
541 font-size: 1.30rem;
542 letter-spacing: 0.07em;
543 color: #f4eedf;
544 text-decoration: none;
545 text-shadow: 0 0 14px rgba(216, 168, 93, 0.45);
546 padding: 0 0.55rem;
547 user-select: none;
548 transition: text-shadow 220ms ease, color 220ms ease;
549 white-space: nowrap;
550}
551.taskbar-brand:hover {
552 color: #ffffff;
553 text-shadow: 0 0 20px rgba(216, 168, 93, 0.7), 0 0 36px rgba(245, 144, 86, 0.30);
554}
555.taskbar-brand .brand-dot {
556 color: var(--gold);
557 margin: 0 0.05em;
558}
559
560.taskbar-divider {
561 display: inline-block;
562 width: 1px;
563 height: 26px;
564 background: rgba(255, 255, 255, 0.12);
565 margin: 0 0.25rem;
566}
567
568.taskbar-list {
569 list-style: none;
570 margin: 0;
571 padding: 0;
572 display: flex;
573 gap: 0.4rem;
574 overflow-x: auto;
575 scrollbar-width: none;
576 -ms-overflow-style: none;
577}
578.taskbar-list::-webkit-scrollbar { display: none; }
579
580.taskbar-item {
581 height: 38px;
582 padding: 0 1.0rem;
583 display: inline-flex;
584 align-items: center;
585 gap: 0.55rem;
586 background: rgba(255, 255, 255, 0.04);
587 border: 1px solid rgba(255, 255, 255, 0.10);
588 border-radius: 9px;
589 color: var(--task-color, var(--fg));
590 font-family: 'Cinzel', serif;
591 font-size: 0.72rem;
592 letter-spacing: 0.36em;
593 text-indent: 0.36em;
594 font-weight: 600;
595 cursor: pointer;
596 transition: all 260ms var(--ease-emerge);
597 white-space: nowrap;
598}
599.taskbar-item:hover {
600 background: rgba(255, 255, 255, 0.09);
601 border-color: var(--task-color, currentColor);
602 transform: translateY(-1px);
603}
604.taskbar-item.active {
605 background: rgba(255, 255, 255, 0.11);
606 border-color: var(--task-color);
607 box-shadow:
608 0 0 18px var(--task-color),
609 inset 0 -2px 0 0 var(--task-color);
610}
611.taskbar-item-dot {
612 width: 8px;
613 height: 8px;
614 border-radius: 50%;
615 background: var(--task-color, var(--gold));
616 box-shadow: 0 0 8px currentColor;
617}
618.taskbar-item[data-task="aire"] { --task-color: var(--aire); }
619.taskbar-item[data-task="fuego"] { --task-color: var(--fuego); }
620.taskbar-item[data-task="tierra"] { --task-color: var(--tierra); }
621.taskbar-item[data-task="agua"] { --task-color: var(--agua); }
622
623.taskbar-spacer {
624 flex: 1;
625 min-width: 0.6rem;
626}
627
628.taskbar-credit {
629 display: inline-flex;
630 align-items: center;
631 gap: 0.4rem;
632 font-family: 'Inter', sans-serif;
633 font-size: 0.78rem;
634 letter-spacing: 0.04em;
635 color: rgba(216, 168, 93, 0.75);
636 text-decoration: none;
637 padding: 0.35rem 0.7rem;
638 border-radius: 8px;
639 border: 1px solid transparent;
640 transition: all 220ms var(--ease-emerge);
641 white-space: nowrap;
642}
643.taskbar-credit:hover {
644 color: var(--gold);
645 border-color: rgba(216, 168, 93, 0.25);
646 background: rgba(216, 168, 93, 0.06);
647}
648.copyleft-mark {
649 display: inline-block;
650 font-size: 1rem;
651 /* © con escala horizontal -1 = copyleft visual. */
652 transform: scaleX(-1);
653 color: currentColor;
654}
655
656@media (max-width: 720px) {
657 .tip { min-width: 110px; padding: 0.7rem 0.9rem; }
658 .tip-glyph { width: 36px; height: 36px; }
659 .tip-label { font-size: 0.72rem; }
660 .tip-sub { display: none; }
661 .page-head { padding: 5vh 5vw 1vh; }
662 .page-content { padding: 0 5vw 5vh; }
663 .taskbar { height: 46px; padding: 0 0.4rem; gap: 0.3rem; }
664 .taskbar-home { width: 36px; height: 36px; }
665 .taskbar-item { height: 34px; padding: 0 0.7rem; font-size: 0.65rem; }
666 .taskbar-brand { font-size: 1.05rem; padding: 0 0.3rem; }
667 .taskbar-credit-text { display: none; }
668 .deck { bottom: 46px; }
669 :root { --taskbar-height: 46px; }
670}