Files
brahman/crates/apps/gioser-web/styles.css
T
Sergio 05f2e54ed1 gioser-web: draggable graph nodes, fixed controls, history.pushState routing
- Graph: nodes are draggable via pointer events. Snap back with
  spring transition on release (cubic-bezier 0.34,1.56,0.64,1)
- Removed hover bounce animation (was distracting)
- Page controls (minimize/close): now fixed position in viewport
  (top-right, z-index 100), not inside the deck-page scroll area.
  Created once in sync_page_controls() on show/hide deck.
  Controls detect active page when data-minimize/close-page is empty.
- Hash routing → history.pushState: URLs are /estudio/aire etc.
  popstate listener handles back/forward. Initial path read on boot.
- Added PointerEvent feature to gioser-graph-web Cargo.toml
- Added History feature to gioser-web Cargo.toml
2026-05-23 16:21:01 +00:00

656 lines
16 KiB
CSS

/* === Tokens === */
:root {
--bg: #06050d;
--fg: #e8eaf5;
--gold: #d8a85d;
--gold-deep: #b77e34;
--aire: #d0dbff;
--agua: #6cd0f3;
--fuego: #f59056;
--tierra: #d49873;
--ease-emerge: cubic-bezier(0.22, 0.61, 0.20, 1);
--ease-magma: cubic-bezier(0.32, 0, 0.05, 1);
--ease-page: cubic-bezier(0.22, 0.61, 0.36, 1);
--taskbar-height: 52px;
}
* { box-sizing: border-box; }
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
background: var(--bg);
color: var(--fg);
font-family: 'Inter', system-ui, -apple-system, sans-serif;
font-weight: 300;
overflow: hidden;
}
/* === Canvas WebGL === */
#gioser-canvas {
position: fixed;
inset: 0;
width: 100vw;
height: 100vh;
display: block;
z-index: 0;
transition: opacity 600ms var(--ease-emerge), filter 600ms var(--ease-emerge);
}
body.deck-visible #gioser-canvas {
opacity: 0.30;
filter: blur(4px) saturate(80%);
}
/* === Tips (botones cardinales sobre el aro) === */
#tips {
position: fixed;
inset: 0;
pointer-events: none;
z-index: 5;
transition: opacity 250ms ease;
}
body.deck-visible #tips {
opacity: 0;
pointer-events: none;
}
.tip {
position: absolute;
top: 0; left: 0;
pointer-events: auto;
text-decoration: none;
color: var(--fg);
user-select: none;
cursor: pointer;
display: flex;
flex-direction: column;
align-items: center;
gap: 0.55rem;
padding: 1.1rem 1.6rem 0.95rem;
min-width: 168px;
background:
radial-gradient(ellipse at top, rgba(255, 255, 255, 0.04), transparent 65%),
rgba(8, 6, 22, 0.55);
backdrop-filter: blur(12px) saturate(140%);
-webkit-backdrop-filter: blur(12px) saturate(140%);
border-radius: 20px;
border: 1px solid rgba(216, 168, 93, 0.25);
box-shadow:
0 12px 36px rgba(0, 0, 0, 0.40),
inset 0 0 0 1px rgba(255, 255, 255, 0.04);
transition:
box-shadow 350ms var(--ease-emerge),
border-color 350ms var(--ease-emerge),
background 350ms var(--ease-emerge);
}
.tip::before {
content: "";
position: absolute;
inset: -10px;
border-radius: 26px;
border: 1px solid currentColor;
opacity: 0;
transition: opacity 400ms ease, inset 400ms var(--ease-emerge);
pointer-events: none;
}
.tip:hover {
border-color: currentColor;
background:
radial-gradient(ellipse at top, rgba(255, 255, 255, 0.07), transparent 65%),
rgba(20, 14, 40, 0.72);
}
.tip:hover::before {
opacity: 0.45;
inset: -16px;
}
.tip-glyph {
width: 54px;
height: 54px;
color: currentColor;
filter: drop-shadow(0 0 6px currentColor) drop-shadow(0 0 16px currentColor);
transition: filter 320ms ease, transform 350ms var(--ease-emerge);
}
.tip:hover .tip-glyph {
filter: drop-shadow(0 0 14px currentColor) drop-shadow(0 0 28px currentColor);
transform: translateY(-3px);
}
.tip-label {
font-family: 'Cinzel', serif;
font-size: 0.95rem;
letter-spacing: 0.42em;
font-weight: 600;
text-indent: 0.42em;
margin-top: 0.15rem;
}
.tip-sub {
font-family: 'Inter', sans-serif;
font-size: 0.7rem;
letter-spacing: 0.22em;
font-weight: 300;
color: rgba(232, 234, 245, 0.62);
text-transform: uppercase;
text-indent: 0.22em;
}
.tip-aire { color: var(--aire); }
.tip-fuego { color: var(--fuego); }
.tip-agua { color: var(--agua); }
.tip-tierra { color: var(--tierra); }
/* === DECK: contenedor único de páginas swipeable === */
.deck {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: var(--taskbar-height);
z-index: 100;
pointer-events: none;
opacity: 0;
visibility: hidden;
transform-origin: var(--origin-x, 50%) var(--origin-y, 50%);
transform: scale(0.0);
overflow: hidden;
touch-action: pan-y;
background:
radial-gradient(ellipse at center, var(--deck-glow, rgba(216, 168, 93, 0.15)), transparent 65%),
rgba(6, 5, 13, 0.96);
backdrop-filter: blur(28px) saturate(140%);
-webkit-backdrop-filter: blur(28px) saturate(140%);
transition:
transform 600ms var(--ease-magma),
opacity 450ms ease,
visibility 0s 600ms;
}
.deck.open {
pointer-events: auto;
opacity: 1;
visibility: visible;
transform: scale(1);
transition:
transform 600ms var(--ease-magma),
opacity 450ms ease,
visibility 0s;
}
/* Acento del deck según elemento activo: glow radial del color. */
body.deck-active-aire .deck { --deck-glow: rgba(208, 219, 255, 0.22); }
body.deck-active-fuego .deck { --deck-glow: rgba(245, 144, 86, 0.28); }
body.deck-active-agua .deck { --deck-glow: rgba(108, 208, 243, 0.22); }
body.deck-active-tierra .deck { --deck-glow: rgba(212, 152, 115, 0.24); }
/* Strip horizontal con páginas — vista-web traslada esto.
touch-action: pan-y declara al browser "yo manejo horizontal, el
vertical (scroll interno de cada página) lo dejas pasar". Sin esto
el navegador móvil se traga el gesto horizontal antes de que JS
pueda capturarlo. */
.deck-strip {
display: flex;
flex-direction: row;
width: 100%;
height: 100%;
transform: translate3d(var(--vista-offset, 0px), 0, 0);
transition: transform 360ms var(--ease-page);
will-change: transform;
touch-action: pan-y;
}
/* Asegurar que TODOS los descendientes del strip hereden el contrato
touch-action — si el toque llega a un párrafo o <a>, el browser
chequea el touch-action del target, no del padre. */
.deck-strip * {
touch-action: pan-y;
}
.deck-strip.vista-dragging,
.deck-strip.vista-instant {
transition: none;
}
.deck-page {
flex: 0 0 100%;
width: 100%;
height: 100%;
position: relative;
overflow-y: auto;
overflow-x: hidden;
touch-action: pan-y;
}
.deck-page[data-element="aire"] { --page-accent: var(--aire); }
.deck-page[data-element="fuego"] { --page-accent: var(--fuego); }
.deck-page[data-element="agua"] { --page-accent: var(--agua); }
.deck-page[data-element="tierra"] { --page-accent: var(--tierra); }
/* Ambience por página */
.page-ambience {
position: absolute;
inset: 0;
pointer-events: none;
z-index: 0;
transition: opacity 2s ease;
}
.deck-page[data-element="aire"] .page-ambience {
background: radial-gradient(circle at 50% 60%, rgba(208,219,255,0.18), transparent 70%);
animation: page-breathe 8s ease-in-out infinite alternate;
}
.deck-page[data-element="fuego"] .page-ambience {
background: radial-gradient(circle at 50% 80%, rgba(245,144,86,0.22), transparent 70%);
animation: page-breathe 6s ease-in-out infinite alternate;
}
.deck-page[data-element="agua"] .page-ambience {
background: radial-gradient(circle at 50% 80%, rgba(108,208,243,0.18), transparent 70%);
animation: page-breathe 10s ease-in-out infinite alternate;
}
.deck-page[data-element="tierra"] .page-ambience {
background: radial-gradient(circle at 50% 85%, rgba(140,100,60,0.22), transparent 70%);
animation: page-breathe 7s ease-in-out infinite alternate;
}
@keyframes page-breathe {
from { opacity: 0.35; }
to { opacity: 0.80; }
}
/* Head + controls — fijos en el deck, no dentro de la página */
.page-controls {
position: fixed;
top: 1.2rem;
right: 1.2rem;
z-index: 100;
display: flex;
gap: 0.5rem;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s ease;
}
.deck--visible .page-controls {
opacity: 1;
pointer-events: auto;
}
.page-control-btn {
width: 40px;
height: 40px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.18);
color: var(--page-accent, var(--gold));
font-size: 1.2rem;
line-height: 1;
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0;
font-family: 'Inter', sans-serif;
transition:
background 200ms ease,
border-color 200ms ease,
transform 250ms var(--ease-emerge);
}
.page-control-btn:hover {
background: rgba(255, 255, 255, 0.10);
border-color: currentColor;
}
.page-minimize svg {
width: 18px;
height: 18px;
}
.page-close {
font-size: 1.6rem;
}
.page-close:hover { transform: rotate(90deg); }
.page-head {
position: relative;
z-index: 2;
text-align: center;
padding: 7vh 8vw 2vh;
color: var(--page-accent, var(--gold));
}
.page-mark {
display: inline-block;
font-family: 'Inter', sans-serif;
font-size: 0.7rem;
letter-spacing: 0.55em;
text-transform: uppercase;
color: rgba(232, 234, 245, 0.6);
margin-bottom: 0.4rem;
text-indent: 0.55em;
}
.page-title {
font-family: 'Cinzel', serif;
font-weight: 700;
font-size: clamp(2.4rem, 6vw, 4.6rem);
margin: 0;
letter-spacing: 0.08em;
color: var(--page-accent, var(--gold));
text-shadow: 0 0 28px currentColor, 0 0 56px rgba(255, 255, 255, 0.10);
}
.page-tag {
display: block;
font-family: 'Inter', sans-serif;
font-size: 0.78rem;
letter-spacing: 0.32em;
text-transform: uppercase;
color: rgba(232, 234, 245, 0.55);
margin-top: 0.7rem;
text-indent: 0.32em;
}
.page-content {
position: relative;
z-index: 2;
padding: 1vh 10vw 8vh;
opacity: 0;
transition: opacity 400ms ease 250ms;
}
.deck.open .deck-page .page-content {
opacity: 1;
}
/* === pluma-doc dentro de la página === */
.pluma-doc {
max-width: 760px;
margin: 0 auto;
font-family: 'Inter', sans-serif;
font-weight: 300;
font-size: 1.05rem;
line-height: 1.78;
color: rgba(232, 234, 245, 0.92);
}
.pluma-doc > * + * { margin-top: 1.0em; }
.pluma-doc h1 {
font-family: 'Cinzel', serif;
font-weight: 700;
font-size: clamp(1.7rem, 3vw, 2.4rem);
color: var(--page-accent);
text-shadow: 0 0 18px currentColor;
letter-spacing: 0.04em;
margin-top: 1.4em;
}
.pluma-doc h2 {
font-family: 'Cinzel', serif;
font-weight: 500;
font-size: 1.5rem;
color: var(--page-accent);
letter-spacing: 0.04em;
margin-top: 1.6em;
padding-bottom: 0.3em;
border-bottom: 1px solid rgba(255, 255, 255, 0.10);
}
.pluma-doc h3 {
font-family: 'Inter', sans-serif;
font-weight: 600;
font-size: 1.18rem;
color: rgba(255, 255, 255, 0.92);
letter-spacing: 0.03em;
margin-top: 1.6em;
}
.pluma-doc p { margin: 0; }
.pluma-doc a {
color: var(--page-accent);
text-decoration: none;
border-bottom: 1px solid currentColor;
transition: opacity 200ms ease;
}
.pluma-doc a:hover { opacity: 0.7; }
.pluma-doc strong { color: rgba(255, 255, 255, 0.98); font-weight: 600; }
.pluma-doc em { color: rgba(255, 255, 255, 0.92); }
.pluma-doc code {
font-family: 'JetBrains Mono', ui-monospace, monospace;
background: rgba(255, 255, 255, 0.06);
padding: 0.12em 0.45em;
border-radius: 4px;
font-size: 0.92em;
color: var(--page-accent);
}
.pluma-doc pre {
background: rgba(0, 0, 0, 0.45);
border: 1px solid rgba(255, 255, 255, 0.08);
border-left: 3px solid var(--page-accent);
border-radius: 8px;
padding: 1rem 1.2rem;
overflow-x: auto;
font-size: 0.92rem;
}
.pluma-doc pre code {
background: transparent;
color: rgba(232, 234, 245, 0.92);
padding: 0;
}
.pluma-doc blockquote {
border-left: 3px solid var(--page-accent);
padding: 0.4em 1.2em;
color: rgba(232, 234, 245, 0.75);
font-style: italic;
background: rgba(255, 255, 255, 0.03);
border-radius: 0 6px 6px 0;
}
.pluma-doc ul, .pluma-doc ol { padding-left: 1.6em; }
.pluma-doc li { margin: 0.4em 0; }
.pluma-doc li::marker { color: var(--page-accent); }
.pluma-doc hr {
border: none;
height: 1px;
background: linear-gradient(to right, transparent, var(--page-accent), transparent);
margin: 2em 0;
}
.pluma-doc table {
border-collapse: collapse;
width: 100%;
font-size: 0.95rem;
}
.pluma-doc th, .pluma-doc td {
padding: 0.55em 0.9em;
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
text-align: left;
}
.pluma-doc th {
color: var(--page-accent);
font-weight: 600;
letter-spacing: 0.04em;
}
.pluma-loading, .pluma-error {
display: flex;
align-items: center;
justify-content: center;
min-height: 30vh;
color: rgba(232, 234, 245, 0.55);
font-family: 'Cinzel', serif;
letter-spacing: 0.4em;
font-size: 0.9rem;
}
.pluma-loading::before {
content: "";
width: 28px;
height: 28px;
margin-right: 1rem;
border: 1px solid var(--page-accent);
border-top-color: transparent;
border-radius: 50%;
animation: pluma-spin 1s linear infinite;
}
.pluma-error { color: var(--fuego); font-style: italic; }
@keyframes pluma-spin { to { transform: rotate(360deg); } }
/* === Taskbar estilo Windows === */
.taskbar {
position: fixed;
left: 0;
right: 0;
bottom: 0;
height: var(--taskbar-height);
z-index: 200;
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0 0.8rem;
background: linear-gradient(to top, rgba(6, 5, 13, 0.94), rgba(8, 6, 22, 0.80));
backdrop-filter: blur(24px) saturate(140%);
-webkit-backdrop-filter: blur(24px) saturate(140%);
border-top: 1px solid rgba(216, 168, 93, 0.22);
box-shadow: 0 -10px 36px rgba(0, 0, 0, 0.45);
}
.taskbar-home {
width: 40px;
height: 40px;
display: inline-flex;
align-items: center;
justify-content: center;
background: transparent;
border: 1px solid rgba(216, 168, 93, 0.32);
color: var(--gold);
border-radius: 9px;
cursor: pointer;
padding: 0;
transition: all 220ms var(--ease-emerge);
}
.taskbar-home:hover {
border-color: var(--gold);
background: rgba(216, 168, 93, 0.12);
box-shadow: 0 0 16px rgba(216, 168, 93, 0.35);
transform: translateY(-1px);
}
.taskbar-home-glyph {
width: 22px;
height: 22px;
filter: drop-shadow(0 0 6px currentColor);
}
.taskbar-brand {
font-family: 'Cinzel', serif;
font-weight: 700;
font-size: 1.30rem;
letter-spacing: 0.07em;
color: #f4eedf;
text-decoration: none;
text-shadow: 0 0 14px rgba(216, 168, 93, 0.45);
padding: 0 0.55rem;
user-select: none;
transition: text-shadow 220ms ease, color 220ms ease;
white-space: nowrap;
}
.taskbar-brand:hover {
color: #ffffff;
text-shadow: 0 0 20px rgba(216, 168, 93, 0.7), 0 0 36px rgba(245, 144, 86, 0.30);
}
.taskbar-brand .brand-dot {
color: var(--gold);
margin: 0 0.05em;
}
.taskbar-divider {
display: inline-block;
width: 1px;
height: 26px;
background: rgba(255, 255, 255, 0.12);
margin: 0 0.25rem;
}
.taskbar-list {
list-style: none;
margin: 0;
padding: 0;
display: flex;
gap: 0.4rem;
overflow-x: auto;
scrollbar-width: none;
-ms-overflow-style: none;
}
.taskbar-list::-webkit-scrollbar { display: none; }
.taskbar-item {
height: 38px;
padding: 0 1.0rem;
display: inline-flex;
align-items: center;
gap: 0.55rem;
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.10);
border-radius: 9px;
color: var(--task-color, var(--fg));
font-family: 'Cinzel', serif;
font-size: 0.72rem;
letter-spacing: 0.36em;
text-indent: 0.36em;
font-weight: 600;
cursor: pointer;
transition: all 260ms var(--ease-emerge);
white-space: nowrap;
}
.taskbar-item:hover {
background: rgba(255, 255, 255, 0.09);
border-color: var(--task-color, currentColor);
transform: translateY(-1px);
}
.taskbar-item.active {
background: rgba(255, 255, 255, 0.11);
border-color: var(--task-color);
box-shadow:
0 0 18px var(--task-color),
inset 0 -2px 0 0 var(--task-color);
}
.taskbar-item-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--task-color, var(--gold));
box-shadow: 0 0 8px currentColor;
}
.taskbar-item[data-task="aire"] { --task-color: var(--aire); }
.taskbar-item[data-task="fuego"] { --task-color: var(--fuego); }
.taskbar-item[data-task="tierra"] { --task-color: var(--tierra); }
.taskbar-item[data-task="agua"] { --task-color: var(--agua); }
.taskbar-spacer {
flex: 1;
min-width: 0.6rem;
}
.taskbar-credit {
display: inline-flex;
align-items: center;
gap: 0.4rem;
font-family: 'Inter', sans-serif;
font-size: 0.78rem;
letter-spacing: 0.04em;
color: rgba(216, 168, 93, 0.75);
text-decoration: none;
padding: 0.35rem 0.7rem;
border-radius: 8px;
border: 1px solid transparent;
transition: all 220ms var(--ease-emerge);
white-space: nowrap;
}
.taskbar-credit:hover {
color: var(--gold);
border-color: rgba(216, 168, 93, 0.25);
background: rgba(216, 168, 93, 0.06);
}
.copyleft-mark {
display: inline-block;
font-size: 1rem;
/* © con escala horizontal -1 = copyleft visual. */
transform: scaleX(-1);
color: currentColor;
}
@media (max-width: 720px) {
.tip { min-width: 110px; padding: 0.7rem 0.9rem; }
.tip-glyph { width: 36px; height: 36px; }
.tip-label { font-size: 0.72rem; }
.tip-sub { display: none; }
.page-head { padding: 5vh 5vw 1vh; }
.page-content { padding: 0 5vw 5vh; }
.taskbar { height: 46px; padding: 0 0.4rem; gap: 0.3rem; }
.taskbar-home { width: 36px; height: 36px; }
.taskbar-item { height: 34px; padding: 0 0.7rem; font-size: 0.65rem; }
.taskbar-brand { font-size: 1.05rem; padding: 0 0.3rem; }
.taskbar-credit-text { display: none; }
.deck { bottom: 46px; }
:root { --taskbar-height: 46px; }
}