gioser-web: draggable graph nodes, fixed controls, history.pushState routing
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 transition: opacity 2s ease;
235}
236.deck-page[data-element="aire"] .page-ambience {
237 background: radial-gradient(circle at 50% 60%, rgba(208,219,255,0.18), transparent 70%);
238 animation: page-breathe 8s ease-in-out infinite alternate;
239}
240.deck-page[data-element="fuego"] .page-ambience {
241 background: radial-gradient(circle at 50% 80%, rgba(245,144,86,0.22), transparent 70%);
242 animation: page-breathe 6s ease-in-out infinite alternate;
243}
244.deck-page[data-element="agua"] .page-ambience {
245 background: radial-gradient(circle at 50% 80%, rgba(108,208,243,0.18), transparent 70%);
246 animation: page-breathe 10s ease-in-out infinite alternate;
247}
248.deck-page[data-element="tierra"] .page-ambience {
249 background: radial-gradient(circle at 50% 85%, rgba(140,100,60,0.22), transparent 70%);
250 animation: page-breathe 7s ease-in-out infinite alternate;
251}
252@keyframes page-breathe {
253 from { opacity: 0.35; }
254 to { opacity: 0.80; }
255}
256
257/* Head + controls — fijos en el deck, no dentro de la página */
258.page-controls {
259 position: fixed;
260 top: 1.2rem;
261 right: 1.2rem;
262 z-index: 100;
263 display: flex;
264 gap: 0.5rem;
265 opacity: 0;
266 pointer-events: none;
267 transition: opacity 0.3s ease;
268}
269.deck--visible .page-controls {
270 opacity: 1;
271 pointer-events: auto;
272}
273.page-control-btn {
274 width: 40px;
275 height: 40px;
276 border-radius: 50%;
277 background: rgba(255, 255, 255, 0.04);
278 border: 1px solid rgba(255, 255, 255, 0.18);
279 color: var(--page-accent, var(--gold));
280 font-size: 1.2rem;
281 line-height: 1;
282 cursor: pointer;
283 display: inline-flex;
284 align-items: center;
285 justify-content: center;
286 padding: 0;
287 font-family: 'Inter', sans-serif;
288 transition:
289 background 200ms ease,
290 border-color 200ms ease,
291 transform 250ms var(--ease-emerge);
292}
293.page-control-btn:hover {
294 background: rgba(255, 255, 255, 0.10);
295 border-color: currentColor;
296}
297.page-minimize svg {
298 width: 18px;
299 height: 18px;
300}
301.page-close {
302 font-size: 1.6rem;
303}
304.page-close:hover { transform: rotate(90deg); }
305
306.page-head {
307 position: relative;
308 z-index: 2;
309 text-align: center;
310 padding: 7vh 8vw 2vh;
311 color: var(--page-accent, var(--gold));
312}
313.page-mark {
314 display: inline-block;
315 font-family: 'Inter', sans-serif;
316 font-size: 0.7rem;
317 letter-spacing: 0.55em;
318 text-transform: uppercase;
319 color: rgba(232, 234, 245, 0.6);
320 margin-bottom: 0.4rem;
321 text-indent: 0.55em;
322}
323.page-title {
324 font-family: 'Cinzel', serif;
325 font-weight: 700;
326 font-size: clamp(2.4rem, 6vw, 4.6rem);
327 margin: 0;
328 letter-spacing: 0.08em;
329 color: var(--page-accent, var(--gold));
330 text-shadow: 0 0 28px currentColor, 0 0 56px rgba(255, 255, 255, 0.10);
331}
332.page-tag {
333 display: block;
334 font-family: 'Inter', sans-serif;
335 font-size: 0.78rem;
336 letter-spacing: 0.32em;
337 text-transform: uppercase;
338 color: rgba(232, 234, 245, 0.55);
339 margin-top: 0.7rem;
340 text-indent: 0.32em;
341}
342.page-content {
343 position: relative;
344 z-index: 2;
345 padding: 1vh 10vw 8vh;
346 opacity: 0;
347 transition: opacity 400ms ease 250ms;
348}
349.deck.open .deck-page .page-content {
350 opacity: 1;
351}
352
353/* === pluma-doc dentro de la página === */
354.pluma-doc {
355 max-width: 760px;
356 margin: 0 auto;
357 font-family: 'Inter', sans-serif;
358 font-weight: 300;
359 font-size: 1.05rem;
360 line-height: 1.78;
361 color: rgba(232, 234, 245, 0.92);
362}
363.pluma-doc > * + * { margin-top: 1.0em; }
364.pluma-doc h1 {
365 font-family: 'Cinzel', serif;
366 font-weight: 700;
367 font-size: clamp(1.7rem, 3vw, 2.4rem);
368 color: var(--page-accent);
369 text-shadow: 0 0 18px currentColor;
370 letter-spacing: 0.04em;
371 margin-top: 1.4em;
372}
373.pluma-doc h2 {
374 font-family: 'Cinzel', serif;
375 font-weight: 500;
376 font-size: 1.5rem;
377 color: var(--page-accent);
378 letter-spacing: 0.04em;
379 margin-top: 1.6em;
380 padding-bottom: 0.3em;
381 border-bottom: 1px solid rgba(255, 255, 255, 0.10);
382}
383.pluma-doc h3 {
384 font-family: 'Inter', sans-serif;
385 font-weight: 600;
386 font-size: 1.18rem;
387 color: rgba(255, 255, 255, 0.92);
388 letter-spacing: 0.03em;
389 margin-top: 1.6em;
390}
391.pluma-doc p { margin: 0; }
392.pluma-doc a {
393 color: var(--page-accent);
394 text-decoration: none;
395 border-bottom: 1px solid currentColor;
396 transition: opacity 200ms ease;
397}
398.pluma-doc a:hover { opacity: 0.7; }
399.pluma-doc strong { color: rgba(255, 255, 255, 0.98); font-weight: 600; }
400.pluma-doc em { color: rgba(255, 255, 255, 0.92); }
401.pluma-doc code {
402 font-family: 'JetBrains Mono', ui-monospace, monospace;
403 background: rgba(255, 255, 255, 0.06);
404 padding: 0.12em 0.45em;
405 border-radius: 4px;
406 font-size: 0.92em;
407 color: var(--page-accent);
408}
409.pluma-doc pre {
410 background: rgba(0, 0, 0, 0.45);
411 border: 1px solid rgba(255, 255, 255, 0.08);
412 border-left: 3px solid var(--page-accent);
413 border-radius: 8px;
414 padding: 1rem 1.2rem;
415 overflow-x: auto;
416 font-size: 0.92rem;
417}
418.pluma-doc pre code {
419 background: transparent;
420 color: rgba(232, 234, 245, 0.92);
421 padding: 0;
422}
423.pluma-doc blockquote {
424 border-left: 3px solid var(--page-accent);
425 padding: 0.4em 1.2em;
426 color: rgba(232, 234, 245, 0.75);
427 font-style: italic;
428 background: rgba(255, 255, 255, 0.03);
429 border-radius: 0 6px 6px 0;
430}
431.pluma-doc ul, .pluma-doc ol { padding-left: 1.6em; }
432.pluma-doc li { margin: 0.4em 0; }
433.pluma-doc li::marker { color: var(--page-accent); }
434.pluma-doc hr {
435 border: none;
436 height: 1px;
437 background: linear-gradient(to right, transparent, var(--page-accent), transparent);
438 margin: 2em 0;
439}
440.pluma-doc table {
441 border-collapse: collapse;
442 width: 100%;
443 font-size: 0.95rem;
444}
445.pluma-doc th, .pluma-doc td {
446 padding: 0.55em 0.9em;
447 border-bottom: 1px solid rgba(255, 255, 255, 0.08);
448 text-align: left;
449}
450.pluma-doc th {
451 color: var(--page-accent);
452 font-weight: 600;
453 letter-spacing: 0.04em;
454}
455.pluma-loading, .pluma-error {
456 display: flex;
457 align-items: center;
458 justify-content: center;
459 min-height: 30vh;
460 color: rgba(232, 234, 245, 0.55);
461 font-family: 'Cinzel', serif;
462 letter-spacing: 0.4em;
463 font-size: 0.9rem;
464}
465.pluma-loading::before {
466 content: "";
467 width: 28px;
468 height: 28px;
469 margin-right: 1rem;
470 border: 1px solid var(--page-accent);
471 border-top-color: transparent;
472 border-radius: 50%;
473 animation: pluma-spin 1s linear infinite;
474}
475.pluma-error { color: var(--fuego); font-style: italic; }
476@keyframes pluma-spin { to { transform: rotate(360deg); } }
477
478/* === Taskbar estilo Windows === */
479.taskbar {
480 position: fixed;
481 left: 0;
482 right: 0;
483 bottom: 0;
484 height: var(--taskbar-height);
485 z-index: 200;
486 display: flex;
487 align-items: center;
488 gap: 0.5rem;
489 padding: 0 0.8rem;
490 background: linear-gradient(to top, rgba(6, 5, 13, 0.94), rgba(8, 6, 22, 0.80));
491 backdrop-filter: blur(24px) saturate(140%);
492 -webkit-backdrop-filter: blur(24px) saturate(140%);
493 border-top: 1px solid rgba(216, 168, 93, 0.22);
494 box-shadow: 0 -10px 36px rgba(0, 0, 0, 0.45);
495}
496
497.taskbar-home {
498 width: 40px;
499 height: 40px;
500 display: inline-flex;
501 align-items: center;
502 justify-content: center;
503 background: transparent;
504 border: 1px solid rgba(216, 168, 93, 0.32);
505 color: var(--gold);
506 border-radius: 9px;
507 cursor: pointer;
508 padding: 0;
509 transition: all 220ms var(--ease-emerge);
510}
511.taskbar-home:hover {
512 border-color: var(--gold);
513 background: rgba(216, 168, 93, 0.12);
514 box-shadow: 0 0 16px rgba(216, 168, 93, 0.35);
515 transform: translateY(-1px);
516}
517.taskbar-home-glyph {
518 width: 22px;
519 height: 22px;
520 filter: drop-shadow(0 0 6px currentColor);
521}
522
523.taskbar-brand {
524 font-family: 'Cinzel', serif;
525 font-weight: 700;
526 font-size: 1.30rem;
527 letter-spacing: 0.07em;
528 color: #f4eedf;
529 text-decoration: none;
530 text-shadow: 0 0 14px rgba(216, 168, 93, 0.45);
531 padding: 0 0.55rem;
532 user-select: none;
533 transition: text-shadow 220ms ease, color 220ms ease;
534 white-space: nowrap;
535}
536.taskbar-brand:hover {
537 color: #ffffff;
538 text-shadow: 0 0 20px rgba(216, 168, 93, 0.7), 0 0 36px rgba(245, 144, 86, 0.30);
539}
540.taskbar-brand .brand-dot {
541 color: var(--gold);
542 margin: 0 0.05em;
543}
544
545.taskbar-divider {
546 display: inline-block;
547 width: 1px;
548 height: 26px;
549 background: rgba(255, 255, 255, 0.12);
550 margin: 0 0.25rem;
551}
552
553.taskbar-list {
554 list-style: none;
555 margin: 0;
556 padding: 0;
557 display: flex;
558 gap: 0.4rem;
559 overflow-x: auto;
560 scrollbar-width: none;
561 -ms-overflow-style: none;
562}
563.taskbar-list::-webkit-scrollbar { display: none; }
564
565.taskbar-item {
566 height: 38px;
567 padding: 0 1.0rem;
568 display: inline-flex;
569 align-items: center;
570 gap: 0.55rem;
571 background: rgba(255, 255, 255, 0.04);
572 border: 1px solid rgba(255, 255, 255, 0.10);
573 border-radius: 9px;
574 color: var(--task-color, var(--fg));
575 font-family: 'Cinzel', serif;
576 font-size: 0.72rem;
577 letter-spacing: 0.36em;
578 text-indent: 0.36em;
579 font-weight: 600;
580 cursor: pointer;
581 transition: all 260ms var(--ease-emerge);
582 white-space: nowrap;
583}
584.taskbar-item:hover {
585 background: rgba(255, 255, 255, 0.09);
586 border-color: var(--task-color, currentColor);
587 transform: translateY(-1px);
588}
589.taskbar-item.active {
590 background: rgba(255, 255, 255, 0.11);
591 border-color: var(--task-color);
592 box-shadow:
593 0 0 18px var(--task-color),
594 inset 0 -2px 0 0 var(--task-color);
595}
596.taskbar-item-dot {
597 width: 8px;
598 height: 8px;
599 border-radius: 50%;
600 background: var(--task-color, var(--gold));
601 box-shadow: 0 0 8px currentColor;
602}
603.taskbar-item[data-task="aire"] { --task-color: var(--aire); }
604.taskbar-item[data-task="fuego"] { --task-color: var(--fuego); }
605.taskbar-item[data-task="tierra"] { --task-color: var(--tierra); }
606.taskbar-item[data-task="agua"] { --task-color: var(--agua); }
607
608.taskbar-spacer {
609 flex: 1;
610 min-width: 0.6rem;
611}
612
613.taskbar-credit {
614 display: inline-flex;
615 align-items: center;
616 gap: 0.4rem;
617 font-family: 'Inter', sans-serif;
618 font-size: 0.78rem;
619 letter-spacing: 0.04em;
620 color: rgba(216, 168, 93, 0.75);
621 text-decoration: none;
622 padding: 0.35rem 0.7rem;
623 border-radius: 8px;
624 border: 1px solid transparent;
625 transition: all 220ms var(--ease-emerge);
626 white-space: nowrap;
627}
628.taskbar-credit:hover {
629 color: var(--gold);
630 border-color: rgba(216, 168, 93, 0.25);
631 background: rgba(216, 168, 93, 0.06);
632}
633.copyleft-mark {
634 display: inline-block;
635 font-size: 1rem;
636 /* © con escala horizontal -1 = copyleft visual. */
637 transform: scaleX(-1);
638 color: currentColor;
639}
640
641@media (max-width: 720px) {
642 .tip { min-width: 110px; padding: 0.7rem 0.9rem; }
643 .tip-glyph { width: 36px; height: 36px; }
644 .tip-label { font-size: 0.72rem; }
645 .tip-sub { display: none; }
646 .page-head { padding: 5vh 5vw 1vh; }
647 .page-content { padding: 0 5vw 5vh; }
648 .taskbar { height: 46px; padding: 0 0.4rem; gap: 0.3rem; }
649 .taskbar-home { width: 36px; height: 36px; }
650 .taskbar-item { height: 34px; padding: 0 0.7rem; font-size: 0.65rem; }
651 .taskbar-brand { font-size: 1.05rem; padding: 0 0.3rem; }
652 .taskbar-credit-text { display: none; }
653 .deck { bottom: 46px; }
654 :root { --taskbar-height: 46px; }
655}