@font-face{font-family:'DM Sans';font-style:normal;font-weight:400 700;font-display:optional;src:url(/fonts/dm-sans-normal-400-700.woff2) format('woff2')}
@font-face{font-family:'DM Mono';font-style:normal;font-weight:400;font-display:optional;src:url(/fonts/dm-mono-normal-400.woff2) format('woff2')}
@font-face{font-family:'DM Mono';font-style:normal;font-weight:500;font-display:optional;src:url(/fonts/dm-mono-normal-500.woff2) format('woff2')}

:root{
  --bg:#080e1b;
  --stage:#0a1224;
  --bar:#0c1526;
  --panel:#0d1728;
  --surface:#111d34;
  --rack:#0c1526;
  --line:#20304f;
  --line2:#2c3f63;
  --ink:#e6edfb;
  --dim:#7d8fb3;
  --accent:#4aa8ff;
  --wire:#4aa8ff;
  --warn:#ffb454;
  --danger:#ff6b7a;
  --router:#4aa8ff;
  --switch:#3ad6b0;
  --ap:#b98cff;
  --host:#8aa0c8;
  --server:#f5a742;
  --hv:#ff6b9d;
  --vm:#7fd0ff;
  --internet:#5fe0a0;
}

*{box-sizing:border-box}
[hidden]{display:none!important}
html,body{height:100%;margin:0}
body{
  font-family:"DM Sans",system-ui,sans-serif;
  background:var(--bg);color:var(--ink);
  display:grid;grid-template-rows:auto 1fr;height:100vh;overflow:hidden;
}
.mono{font-family:"DM Mono",ui-monospace,monospace}
button{font-family:inherit;cursor:pointer}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

/* ---------- top bar ---------- */
.bar{display:flex;align-items:center;gap:1.2rem;flex-wrap:wrap;padding:.55rem .9rem;
  background:linear-gradient(180deg,#0e1a30,#0b1424);border-bottom:1px solid var(--line)}
.brand{display:flex;align-items:center;gap:.6rem;min-width:0}
.brand .logo{font-size:1.4rem;color:var(--switch);line-height:1;
  text-shadow:0 0 12px color-mix(in srgb,var(--switch) 60%,transparent)}
.brand .bt{display:flex;flex-direction:column;line-height:1.05}
.brand strong{font-size:1.02rem;letter-spacing:.06em;font-family:"DM Mono",monospace;font-weight:500}
.brand .tag{font-family:"DM Mono",monospace;font-size:.66rem;color:var(--dim);
  text-transform:uppercase;letter-spacing:.16em;max-width:22ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  background:none;border:0;border-bottom:1px dashed transparent;padding:1px 0;text-align:left}
.brand .tag:hover{color:var(--ink);border-bottom-color:var(--line2)}
.brand .tag.untitled{font-style:italic;opacity:.8}
.nameedit{font-family:"DM Mono",monospace;font-size:.72rem;color:var(--ink);background:#0a1526;
  border:1px solid var(--switch);border-radius:5px;padding:2px 6px;width:20ch;letter-spacing:.06em}
.nameedit:focus{outline:none;box-shadow:0 0 0 2px rgba(58,214,176,.25)}

.tools{display:flex;align-items:center;gap:.9rem;flex-wrap:wrap;margin-left:auto}
.grp{display:flex;align-items:center;gap:.3rem;background:#0a1526;
  border:1px solid var(--line);border-radius:9px;padding:.28rem .4rem}
.grp .lbl{font-size:.62rem;color:var(--dim);text-transform:uppercase;letter-spacing:.18em;margin:0 .3rem 0 .15rem;
  font-family:"DM Mono",monospace}
.tools button{background:#13203a;color:var(--ink);border:1px solid var(--line2);border-radius:7px;
  padding:.34rem .55rem;font-size:.78rem;line-height:1;font-family:"DM Mono",monospace;
  transition:background .12s,border-color .12s,transform .06s}
.tools button:hover{background:#1a2b4a;border-color:#3a5183}
.tools button:active{transform:translateY(1px)}
.tools .add.sub{border-color:#3a5183;color:var(--switch)}
.tools .danger{border-color:#5a2b34;color:var(--danger)}
.tools .danger:hover{background:#3a1c22}
.tools button:disabled{opacity:.35;cursor:default;background:#0f1a2e;border-color:var(--line)}
.tools button:disabled:hover{background:#0f1a2e;border-color:var(--line)}
#btnUndo,#btnRedo{font-size:.95rem;padding:.28rem .5rem}
.tools select{background:#13203a;color:var(--ink);border:1px solid var(--line2);border-radius:7px;
  padding:.32rem .5rem;font:inherit;font-size:.78rem;font-family:"DM Mono",monospace;cursor:pointer}
.tools select:hover{border-color:#3a5183}

/* menú desplegable de "Añadir" */
.menu-wrap{position:relative}
.menubtn{font-weight:500}
.menubtn .caret{opacity:.7;font-size:.7em}
.menubtn[aria-expanded="true"]{background:#1a2b4a;border-color:var(--accent)}
.menu{position:absolute;top:calc(100% + 6px);left:0;z-index:40;min-width:210px;
  background:var(--panel);border:1px solid var(--line2);border-radius:10px;padding:.35rem;
  box-shadow:0 14px 34px rgba(0,0,0,.5);display:flex;flex-direction:column;gap:2px}
.menu .mi{display:flex;align-items:center;gap:.6rem;width:100%;text-align:left;
  background:none;border:0;border-radius:7px;color:var(--ink);padding:.46rem .55rem;font-size:.82rem}
.menu .mi:hover{background:#17263f}
.menu .mi .dot{width:11px;height:11px;border-radius:3px;flex:none;box-shadow:0 0 6px -1px currentColor}
.menu .mi .dot.ring{background:none!important;border:2px dashed;border-radius:5px}
.menu .mi .mi-k{margin-left:auto;font:500 .62rem "DM Mono",monospace;color:var(--dim);letter-spacing:.12em}
.menu-sep{height:1px;background:var(--line);margin:.3rem .2rem}

/* ---------- stage / canvas ---------- */
.stage{position:relative;overflow:hidden;
  background:radial-gradient(1200px 620px at 72% -12%, #12233f 0%, var(--stage) 62%)}
#canvas{width:100%;height:100%;display:block;touch-action:none;cursor:grab;position:relative;z-index:1}
#canvas.panning{cursor:grabbing}
#canvas.linking{cursor:crosshair}
#rain{position:absolute;inset:0;width:100%;height:100%;z-index:0;pointer-events:none;display:none}
:root[data-theme="matrix"] #rain{display:block}

/* nodes */
.node{cursor:grab}
.node .card{fill:var(--surface);stroke:var(--line2);stroke-width:1.5}
.node.sel .card{stroke:var(--c,var(--accent));stroke-width:2.5;filter:drop-shadow(0 0 6px color-mix(in srgb,var(--c,var(--accent)) 55%,transparent))}
.node.warn .card{stroke:var(--warn)}
.node .accent{fill:var(--c,var(--accent))}
.node .ttl{fill:var(--ink);font:600 13px "DM Sans",sans-serif}
.node .ip{fill:var(--dim);font:12px "DM Mono",monospace}
.node .typ{font:500 9.5px "DM Mono",monospace;text-transform:uppercase;letter-spacing:.14em;fill:var(--c,var(--accent))}
.node .badge rect{fill:#0b1730;stroke:var(--line2)}
.node .badge text{fill:var(--switch);font:11px "DM Mono",monospace}

/* virtualizer chassis */
.node.hv .card{fill:color-mix(in srgb,var(--hv) 8%,var(--rack));stroke:color-mix(in srgb,var(--hv) 45%,var(--line2))}
.bodybay{fill:rgba(4,9,20,.55);stroke:var(--line2);stroke-dasharray:5 5}
.node.hv.droptarget .bodybay{stroke:var(--hv);stroke-dasharray:none;fill:color-mix(in srgb,var(--hv) 14%,transparent)}
.bodylbl{fill:var(--hv);font:500 10px "DM Mono",monospace;text-transform:uppercase;letter-spacing:.12em}
.bodyhint{fill:var(--dim);font:11px "DM Sans",sans-serif}
.ear{fill:var(--hv)}
.nodelink{cursor:pointer}
.nodelink-bg{fill:color-mix(in srgb,var(--hv) 16%,var(--rack));stroke:color-mix(in srgb,var(--hv) 55%,var(--line2));stroke-width:1}
.nodelink:hover .nodelink-bg{fill:var(--hv);stroke:var(--hv)}
.nodelink-ic{fill:var(--hv);font:600 13px "DM Sans",sans-serif}
.nodelink:hover .nodelink-ic{fill:#0b1220}

/* chip plegar/desplegar VMs */
.hvtoggle{cursor:pointer}
.hvtoggle-bg{fill:color-mix(in srgb,var(--hv) 14%,var(--rack));stroke:color-mix(in srgb,var(--hv) 40%,var(--line2))}
.hvtoggle:hover .hvtoggle-bg{fill:color-mix(in srgb,var(--hv) 26%,var(--rack));stroke:var(--hv)}
.hvtoggle-t{fill:var(--hv);font:600 11px "DM Sans",sans-serif;letter-spacing:.02em;pointer-events:none}
.uplinklbl{fill:var(--dim);font:8.5px "DM Mono",monospace;letter-spacing:.08em}
/* bridge interno (red virtual de las VMs) */
.hv-bridge{fill:color-mix(in srgb,var(--vm) 12%,rgba(4,9,20,.55));stroke:color-mix(in srgb,var(--vm) 45%,var(--line2))}
.hv-bridge-t{fill:var(--vm);font:600 10px "DM Mono",monospace;letter-spacing:.04em}
.link.internal{stroke:var(--vm);stroke-dasharray:2 4;stroke-width:1.6;opacity:.6;fill:none;pointer-events:none}

/* vm blades */
.node.vm .card{fill:color-mix(in srgb,var(--vm) 10%,#0e1a30);stroke:color-mix(in srgb,var(--vm) 40%,var(--line2))}
.node.vm .vmt{font:600 12px "DM Sans",sans-serif}
.node.vm .vmi{font:11px "DM Mono",monospace}
.node.vm .nics{font:500 8.5px "DM Mono",monospace;fill:var(--vm);opacity:.75;letter-spacing:.08em}

/* ports (patch panel) */
.bay{fill:#060c18;stroke:var(--line)}
.port{fill:#0a1424;stroke:var(--line2);stroke-width:1.4;cursor:crosshair}
.port:hover{fill:var(--c,var(--accent));stroke:var(--c,var(--accent))}
.port.tgt{fill:var(--accent);stroke:var(--accent)}
.portlabel{fill:var(--dim);font:9px "DM Mono",monospace}

/* links */
.link{fill:none;stroke:var(--wire);stroke-width:2.4;cursor:pointer;stroke-linecap:round}
.link.wan{stroke:var(--internet)}
.link.wifi{stroke:var(--ap);stroke-dasharray:5 5}
.link.virtual{stroke:var(--vm);stroke-dasharray:2 5;stroke-width:2}
.link.sel{stroke:#fff;stroke-width:3.4;filter:drop-shadow(0 0 5px var(--accent))}
.link-hit{fill:none;stroke:transparent;stroke-width:16;cursor:pointer}
.ghost{fill:none;stroke:var(--switch);stroke-width:2.4;stroke-dasharray:4 4;pointer-events:none}

/* subnets */
.subnet-band{fill:none;stroke-width:1.5;stroke-dasharray:9 6}
.subnet-band.sel{stroke-width:2.5;stroke-dasharray:none}
.subnet-tag{font:500 11px "DM Mono",monospace;letter-spacing:.04em;cursor:pointer}
.subnet-tag:hover{text-decoration:underline}

/* legend / hint / warns */
.legend{position:absolute;z-index:5;top:12px;right:12px;background:rgba(10,18,36,.92);border:1px solid var(--line);
  border-radius:11px;padding:.6rem .75rem;max-width:290px;backdrop-filter:blur(4px)}
.legend h3{margin:0 0 .4rem;font:500 .68rem "DM Mono",monospace;text-transform:uppercase;letter-spacing:.18em;color:var(--dim)}
.legend ul{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.35rem}
.legend li{display:flex;gap:.5rem;align-items:baseline;font-size:.8rem}
.legend li.pick{cursor:pointer;border-radius:6px;margin:-.15rem -.35rem;padding:.15rem .35rem}
.legend li.pick:hover{background:rgba(120,150,200,.12)}
.legend li.pick.sel{background:color-mix(in srgb,var(--accent) 18%,transparent)}
.legend li.pick:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
.legend .sw{width:11px;height:11px;border-radius:3px;flex:0 0 auto;margin-top:.15rem;border:1px solid rgba(255,255,255,.2)}
.legend .cidr{font-family:"DM Mono",monospace;color:var(--ink)}
.legend .meta{color:var(--dim);font-size:.72rem;font-family:"DM Mono",monospace}

.hint{position:absolute;z-index:5;bottom:12px;left:12px;right:12px;text-align:center;font-size:.74rem;color:var(--dim);
  pointer-events:none;text-shadow:0 1px 5px #000;font-family:"DM Mono",monospace;letter-spacing:.02em}
.hint b{color:var(--switch)}

.warns{position:absolute;z-index:5;bottom:44px;left:12px;background:rgba(50,32,8,.94);border:1px solid #6b4a1c;
  border-radius:10px;padding:.5rem .7rem;max-width:360px;font-size:.76rem;color:#ffdca6}
.warns h4{margin:0 0 .3rem;font:500 .68rem "DM Mono",monospace;text-transform:uppercase;letter-spacing:.12em;color:var(--warn)}
.warns ul{margin:0;padding-left:1.1rem;display:flex;flex-direction:column;gap:.2rem}

/* property panel */
.panel{position:fixed;top:0;right:0;bottom:0;width:326px;background:var(--panel);border-left:1px solid var(--line);
  display:flex;flex-direction:column;box-shadow:-14px 0 44px rgba(0,0,0,.45);z-index:20}
.phead{display:flex;align-items:center;justify-content:space-between;padding:.8rem .9rem;border-bottom:1px solid var(--line)}
.phead h2{margin:0;font:500 .82rem "DM Mono",monospace;text-transform:uppercase;letter-spacing:.14em;color:var(--ink)}
.phead button{background:none;border:none;color:var(--dim);font-size:1.1rem}
.phead button:hover{color:var(--ink)}
.pbody{padding:.9rem;overflow:auto;flex:1;display:flex;flex-direction:column;gap:.75rem}
.pfoot{padding:.7rem .9rem;border-top:1px solid var(--line)}
.pfoot .danger{width:100%;background:#3a1c22;color:var(--danger);border:1px solid #5a2b34;border-radius:8px;padding:.5rem;font-size:.85rem}
.pfoot .danger:hover{background:#4c242c}

.field{display:flex;flex-direction:column;gap:.25rem}
.field label{font:.68rem "DM Mono",monospace;color:var(--dim);text-transform:uppercase;letter-spacing:.1em}
.field input,.field select{background:var(--surface);color:var(--ink);border:1px solid var(--line2);border-radius:7px;
  padding:.45rem .55rem;font:14px "DM Sans",sans-serif}
.field input.mono{font-family:"DM Mono",monospace}
.field input:focus,.field select:focus{border-color:var(--accent);outline:none}
.field.chk{flex-direction:row;align-items:center;gap:.55rem}
.field.chk label{text-transform:none;letter-spacing:0;font-size:.9rem;color:var(--ink);font-family:"DM Sans",sans-serif}
.field.chk input{width:18px;height:18px;accent-color:var(--accent);flex:0 0 auto}
.subhdr{font:500 .68rem "DM Mono",monospace;text-transform:uppercase;letter-spacing:.14em;color:var(--accent);
  margin-top:.4rem;border-top:1px solid var(--line);padding-top:.7rem}
.row2{display:grid;grid-template-columns:1fr 1fr;gap:.5rem}
.note{font-size:.75rem;color:var(--dim);line-height:1.45}

.vmlist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.3rem}
.vmpick{width:100%;text-align:left;background:var(--surface);color:var(--ink);border:1px solid var(--line2);
  border-radius:7px;padding:.4rem .55rem;font:12px "DM Mono",monospace}
.vmpick:hover{border-color:var(--vm);background:#13233d}
.addvm{width:100%;background:color-mix(in srgb,var(--vm) 12%,transparent);color:var(--vm);
  border:1px solid color-mix(in srgb,var(--vm) 45%,var(--line2));border-radius:7px;padding:.45rem;font-size:.85rem}
.addvm:hover{background:color-mix(in srgb,var(--vm) 20%,transparent)}
.openurl{display:block;margin-top:.4rem;color:var(--hv);font:12px "DM Mono",monospace;
  text-decoration:none;word-break:break-all;border-bottom:1px dashed color-mix(in srgb,var(--hv) 45%,transparent);
  padding-bottom:2px;width:fit-content}
.openurl:hover{color:#fff;border-bottom-color:var(--hv)}

/* =================== ESTADO (caído / avisos / en línea) =================== */
.node.st-down{opacity:.6}
.node.st-down .card{stroke:var(--danger);stroke-dasharray:6 4}
.node.st-down .accent{fill:var(--danger)}
.node.st-warn .card{stroke:var(--warn)}
.node.st-warn .accent{fill:var(--warn)}
.node.st-up .accent{fill:var(--internet)}
.link.st-down{stroke:var(--danger)!important;stroke-dasharray:7 5;opacity:.85}
.link.st-warn{stroke:var(--warn)!important}
.link.st-up{stroke:var(--internet)!important}
.note.live{color:var(--internet)}

/* chip de estado en vivo */
.livechip{position:absolute;z-index:5;top:12px;left:12px;display:flex;align-items:center;gap:.5rem;
  background:rgba(10,18,36,.92);border:1px solid var(--line);border-radius:999px;padding:.3rem .5rem .3rem .7rem;
  font:500 .72rem "DM Mono",monospace;color:var(--dim);backdrop-filter:blur(4px)}
.livechip .dot{width:9px;height:9px;border-radius:50%;background:var(--dim);flex:none}
.livechip.ok{color:var(--ink)}
.livechip.ok .dot{background:var(--internet);box-shadow:0 0 0 0 color-mix(in srgb,var(--internet) 70%,transparent);animation:pulse 2s infinite}
.livechip.err{color:var(--danger);border-color:#5a2b34}
.livechip.err .dot{background:var(--danger)}
.livechip.loading .dot{background:var(--warn)}
.livechip .lref{background:none;border:0;color:inherit;font-size:.95rem;line-height:1;padding:0 .2rem;cursor:pointer;opacity:.7}
.livechip .lref:hover{opacity:1}
@keyframes pulse{0%{box-shadow:0 0 0 0 color-mix(in srgb,var(--internet) 60%,transparent)}70%{box-shadow:0 0 0 6px transparent}100%{box-shadow:0 0 0 0 transparent}}

/* =================== TEMAS =================== */

/* — Matrix: fósforo verde sobre negro, todo monoespaciado, lluvia de código — */
:root[data-theme="matrix"]{
  --bg:#000600; --stage:#000a01; --bar:#020d02; --panel:#02100a; --surface:#031c05;
  --rack:#010c02; --line:#0c400c; --line2:#12611a; --ink:#4dff6a; --dim:#1f9a35;
  --accent:#39ff14; --wire:#00d43a; --warn:#d7ff2b; --danger:#ff5a5a;
  --router:#39ff14; --switch:#00e676; --ap:#8bffb5; --host:#2fbf49;
  --server:#b6ff3d; --hv:#00ffa0; --vm:#9dffc4; --internet:#5cff7a;
}
:root[data-theme="matrix"] body{font-family:"DM Mono",ui-monospace,monospace}
:root[data-theme="matrix"] .brand strong{color:var(--accent);text-shadow:0 0 8px color-mix(in srgb,var(--accent) 60%,transparent)}
:root[data-theme="matrix"] .bar{background:linear-gradient(180deg,#031203,#010a01)}
:root[data-theme="matrix"] .stage{background:#000700}
:root[data-theme="matrix"] text{font-family:"DM Mono",ui-monospace,monospace!important}
:root[data-theme="matrix"] .node .card{filter:drop-shadow(0 0 3px color-mix(in srgb,var(--c) 55%,transparent))}
:root[data-theme="matrix"] .ttl{fill:var(--accent)}
/* scanlines sutiles sobre el lienzo */
:root[data-theme="matrix"] .stage::after{content:"";position:absolute;inset:0;z-index:2;pointer-events:none;
  background:repeating-linear-gradient(0deg,rgba(0,0,0,.16) 0 1px,transparent 1px 3px);mix-blend-mode:multiply}

/* — Blueprint: plano técnico, cian sobre azul de cianotipo — */
:root[data-theme="blueprint"]{
  --bg:#0a2b4e; --stage:#0d3560; --bar:#0a2748; --panel:#0c2e56; --surface:#123c68;
  --rack:#0b2c52; --line:#2f6ea8; --line2:#4b8cc4; --ink:#eaf4ff; --dim:#a9c8e6;
  --accent:#8fd6ff; --wire:#bfe4ff; --warn:#ffd76b; --danger:#ff9a9a;
  --router:#bfe4ff; --switch:#9be7cf; --ap:#d3c0ff; --host:#cfe3f7;
  --server:#ffdca0; --hv:#ffb3ce; --vm:#c9ecff; --internet:#a9f0c8;
}
:root[data-theme="blueprint"] .stage{background:
  linear-gradient(0deg,rgba(255,255,255,.05) 1px,transparent 1px) 0 0/28px 28px,
  linear-gradient(90deg,rgba(255,255,255,.05) 1px,transparent 1px) 0 0/28px 28px,
  radial-gradient(1200px 620px at 72% -12%,#12467a 0%,var(--stage) 62%)}

@media (prefers-reduced-motion:reduce){*{transition:none!important}}
@media (max-width:620px){.tools{width:100%;margin-left:0}.panel{width:100%}}
