    /* Paleta estilo CAD (AutoCAD / 3ds Max): grises carbón, acento azul Autodesk, esquinas rectas */
    :root {
        --bg: #22252a;
        --panel: #2b2e33;
        --panel-2: #34383e;
        --border: #46494e;
        --text: #d6d8db;
        --muted: #8f959c;
        --accent: #0696d7;
        --green: #3fb96b;
        --red: #e05555;
        --yellow: #e0b23f;
        --purple: #a06bfa;
        --grid-major: #31353b;
        --grid-minor: #2a2d33;
        --node-bg1: #30343a;
        --node-bg2: #282c31;
        --console-bg: #1b1e22;
        --pre-bg: #26292e;
        --label-bg: rgba(43, 46, 51, .93);
        --hl-key: #6cb6ff;
        --hl-str: #7ece81;
        --hl-num: #e0a56b;
        --hl-tag: #6cb6ff;
    }
    /* Estilo claro (Ver → Estilo claro / del sistema) */
    :root[data-theme="light"] {
        --bg: #dfe2e6;
        --panel: #eceef0;
        --panel-2: #ffffff;
        --border: #b6bac0;
        --text: #2b2e33;
        --muted: #697077;
        --accent: #0678b0;
        --grid-major: #c6cad0;
        --grid-minor: #d4d7db;
        --node-bg1: #ffffff;
        --node-bg2: #eef0f3;
        --console-bg: #f4f5f7;
        --pre-bg: #ffffff;
        --label-bg: rgba(255, 255, 255, .93);
        --hl-key: #0b63c5;
        --hl-str: #1a7f37;
        --hl-num: #b35900;
        --hl-tag: #0b63c5;
    }
    * { margin: 0; padding: 0; box-sizing: border-box; }
    html, body { height: 100%; }
    body {
        font-family: 'Segoe UI', system-ui, sans-serif;
        background: var(--bg); color: var(--text);
        display: grid;
        grid-template-rows: auto auto 1fr var(--console-h, 240px) 26px;
        grid-template-columns: 1fr var(--sidebar-w, 330px);
        grid-template-areas: "toolbar toolbar" "actionbar actionbar" "canvas sidebar" "console sidebar" "status status";
        overflow: hidden;
    }

    /* ---------- Action toolbar: las acciones directas del sistema ---------- */
    #actionbar {
        grid-area: actionbar;
        display: flex; align-items: center; gap: 6px;
        padding: 4px 10px;
        background: var(--panel); border-bottom: 1px solid var(--border);
    }
    .ab-btn {
        background: var(--panel-2); color: var(--text);
        border: 1px solid var(--border); border-radius: 2px;
        padding: 5px 12px; cursor: pointer; font: inherit; font-size: .8rem; font-weight: 600;
    }
    .ab-btn:hover { border-color: var(--accent); }
    .ab-btn.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
    .ab-btn.primary:hover { background: var(--accent-borde, var(--accent)); }
    .ab-btn:disabled { opacity: .5; cursor: wait; }
    .ab-sep { width: 1px; height: 20px; background: var(--border); margin: 0 4px; }

    /* ---------- Toolbar ---------- */
    #toolbar {
        grid-area: toolbar;
        display: flex; align-items: center; gap: 8px;
        padding: 10px 14px;
        background: var(--panel); border-bottom: 1px solid var(--border);
        flex-wrap: wrap;
    }
    #toolbar .brand {
        display: flex; align-items: center; gap: 8px;
        font-weight: 800; font-size: 1.05rem; margin-right: 14px;
    }
    #toolbar .brand span { color: var(--accent); }
    .brand-logo { width: 26px; height: 26px; border-radius: 6px; flex: none; }

    /* ---------- Barra de menús estilo WinForms ---------- */
    #menubar { display: flex; align-items: center; gap: 2px; }
    .menu { position: relative; }
    .menu-btn {
        background: transparent; border: none; color: var(--text);
        font: inherit; font-size: .85rem; padding: 6px 12px; cursor: pointer; border-radius: 2px;
    }
    .menu-btn:hover, .menu.open .menu-btn { background: var(--panel-2); }
    .menu-drop {
        display: none; position: absolute; top: 100%; left: 0; z-index: 300;
        min-width: 250px; background: var(--panel-2); border: 1px solid var(--border);
        border-radius: 2px; padding: 4px; box-shadow: 0 12px 30px rgba(0,0,0,.5);
    }
    .menu.open .menu-drop { display: block; }
    .menu-drop button {
        display: block; width: 100%; text-align: left;
        background: transparent; border: none; color: var(--text);
        font: inherit; font-size: .84rem; padding: 7px 10px; border-radius: 2px;
        cursor: pointer; white-space: nowrap;
    }
    .menu-drop button:hover { background: var(--accent); color: #fff; }
    .menu-sep { height: 1px; background: var(--border); margin: 4px 4px; }
    /* Submenú (Archivo → Templates) */
    .submenu { position: relative; }
    .submenu-btn { width: 100%; }
    .submenu-drop {
        display: none; position: absolute; left: 100%; top: -5px; z-index: 310;
        min-width: 240px; background: var(--panel-2); border: 1px solid var(--border);
        border-radius: 2px; padding: 4px; box-shadow: 0 12px 30px rgba(0,0,0,.5);
    }
    /* el combinador de hijo directo importa: Templates anida submenús por
       categoría y sin él se abrirían todos a la vez */
    .submenu:hover > .submenu-drop { display: block; }
    .submenu-drop button {
        display: block; width: 100%; text-align: left;
        background: transparent; border: none; color: var(--text);
        font: inherit; font-size: .84rem; padding: 7px 10px; border-radius: 2px;
        cursor: pointer; white-space: nowrap;
    }
    .submenu-drop button:hover { background: var(--accent); color: #fff; }

    /* Diálogo flotante de Variables del proyecto */
    #vars-modal {
        display: none; position: fixed; left: 340px; top: 110px; z-index: 190;
        width: min(480px, 92vw);
        background: var(--panel); border: 1px solid var(--border); border-radius: 2px;
        box-shadow: 0 16px 44px rgba(0,0,0,.5);
    }
    #vars-head {
        display: flex; align-items: center; justify-content: space-between;
        padding: 8px 12px; cursor: move; user-select: none;
        background: var(--panel-2); border-bottom: 1px solid var(--border);
        font-weight: 700; font-size: .84rem;
    }
    #vars-head .btn { padding: 2px 8px; font-size: .72rem; }
    #vars-body { padding: 12px 14px; max-height: 60vh; overflow-y: auto; }
    #vars-body input {
        background: var(--panel-2); color: var(--text);
        border: 1px solid var(--border); border-radius: 2px;
        padding: 7px 9px; font-size: .82rem; font-family: Consolas, monospace;
    }
    #vars-body input:focus { outline: none; border-color: var(--accent); }

    /* Diálogo de base de datos (connection string) */
    #db-modal, #amanda-modal {
        display: none; position: fixed; left: 300px; top: 140px; z-index: 190;
        width: min(560px, 94vw);
        background: var(--panel); border: 1px solid var(--border); border-radius: 2px;
        box-shadow: 0 16px 44px rgba(0,0,0,.5);
    }
    #db-head, #amanda-head {
        display: flex; align-items: center; justify-content: space-between;
        padding: 8px 12px; cursor: move; user-select: none;
        background: var(--panel-2); border-bottom: 1px solid var(--border);
        font-weight: 700; font-size: .84rem;
    }
    #db-head .btn, #amanda-head .btn { padding: 2px 8px; font-size: .72rem; }
    #db-body, #amanda-body { padding: 12px 14px; }
    #db-body label, #amanda-body label { display: block; font-size: .72rem; font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: .5px; margin-top: 8px; }
    #db-body input, #amanda-body input {
        background: var(--panel-2); color: var(--text);
        border: 1px solid var(--border); border-radius: 2px;
        padding: 8px 10px; font-size: .82rem; font-family: Consolas, monospace;
    }
    #db-body input:focus, #amanda-body input:focus { outline: none; border-color: var(--accent); }
    .toolbar-right { margin-left: auto; display: flex; gap: 8px; align-items: center; }

    /* ---------- ToolBar flotante de herramientas (con dock y resize) ---------- */
    #floatbar {
        position: fixed; left: 14px; top: 64px; z-index: 150; width: 170px;
        display: flex; flex-direction: column; align-items: stretch; gap: 3px;
        background: var(--panel); border: 1px solid var(--border); border-radius: 2px;
        padding: 0 4px 4px; box-shadow: 0 8px 24px rgba(0,0,0,.35);
        user-select: none;
    }
    #floatbar.docked {
        border-radius: 0; box-shadow: none; overflow-y: auto;
    }
    #floatbar.dock-left  { border-left: none; border-top: none; border-bottom: none; }
    #floatbar.dock-right { border-right: none; border-top: none; border-bottom: none; }
    #floatbar-grip {
        cursor: move; font-size: .64rem; font-weight: 700; color: var(--muted);
        text-transform: uppercase; letter-spacing: .5px;
        padding: 5px 4px; margin: 0 -4px 2px; text-align: center;
        background: var(--panel-2); border-bottom: 1px solid var(--border);
        white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    }
    .fb-btn {
        background: transparent; border: 1px solid transparent; border-radius: 2px;
        color: var(--text); font-size: .8rem; font-weight: 600; line-height: 1.2;
        width: 100%; padding: 6px 8px; cursor: pointer;
        text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    }
    .fb-btn:hover { background: var(--panel-2); border-color: var(--accent); }
    .fb-btn:active { cursor: grabbing; }
    .fb-btn.fb-arrastrando { opacity: .5; }
    /* El lienzo resaltado mientras se arrastra un nodo por encima */
    #canvas.drop-activo { outline: 2px dashed var(--accent); outline-offset: -6px; }
    .fb-sep { height: 1px; background: var(--border); margin: 3px 0; }
    /* Paleta agrupada por protocolo: una categoría abierta por vez */
    #fb-palette { display: flex; flex-direction: column; gap: 1px; }
    .fb-cat {
        display: flex; align-items: center; gap: 5px;
        background: transparent; border: 1px solid transparent; border-radius: 2px;
        color: var(--muted); font-size: .7rem; font-weight: 800;
        text-transform: uppercase; letter-spacing: .4px;
        width: 100%; padding: 5px 6px; cursor: pointer;
        text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    }
    .fb-cat:hover { background: var(--panel-2); color: var(--text); }
    .fb-group.open .fb-cat { color: var(--text); }
    .fb-caret { display: inline-block; transition: transform .12s; font-size: .6rem; }
    .fb-group.open .fb-caret { transform: rotate(90deg); }
    .fb-cat-items { display: none; }
    .fb-group.open .fb-cat-items {
        display: flex; flex-direction: column; gap: 1px;
        margin: 1px 0 4px 7px; padding-left: 5px; border-left: 1px solid var(--border);
    }
    #floatbar-resize {
        display: none; position: absolute; top: 0; bottom: 0; width: 7px;
        cursor: ew-resize; z-index: 5;
    }
    #floatbar.docked #floatbar-resize { display: block; }
    #floatbar.dock-left  #floatbar-resize { right: -3px; }
    #floatbar.dock-right #floatbar-resize { left: -3px; }
    #floatbar-resize:hover { background: #0696d755; }

    /* ---------- Status bar (comandos generales de pantalla, estilo CAD) ---------- */
    #statusbar {
        grid-area: status;
        display: flex; align-items: center; gap: 10px;
        padding: 0 12px;
        background: var(--panel); border-top: 1px solid var(--border);
        font-size: .74rem; color: var(--muted);
        user-select: none;
    }
    #statusbar .sb-sep { width: 1px; height: 14px; background: var(--border); }
    #statusbar .sb-flex { flex: 1; }
    #sb-coords { font-family: Consolas, 'Courier New', monospace; min-width: 130px; }
    .sb-btn {
        background: transparent; border: 1px solid transparent; color: var(--text);
        font: inherit; font-size: .8rem; padding: 1px 8px; cursor: pointer; border-radius: 2px;
    }
    .sb-btn:hover { background: var(--panel-2); border-color: var(--border); }
    .btn {
        background: var(--panel-2); color: var(--text);
        border: 1px solid var(--border); border-radius: 2px;
        padding: 7px 14px; cursor: pointer; font-size: .85rem; font-weight: 600;
        transition: background .12s, border-color .12s;
    }
    .btn:hover { background: #28324344; border-color: var(--accent); }
    .btn.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
    .btn.primary:hover { background: #3a76e8; }
    .btn.danger:hover { border-color: var(--red); color: var(--red); }
    .btn:disabled { opacity: .5; cursor: wait; }
    .sep { width: 1px; height: 24px; background: var(--border); margin: 0 6px; }

    /* ---------- Canvas ---------- */
    #canvas-wrap {
        grid-area: canvas; overflow: auto; position: relative;
        background: var(--bg);
    }
    #canvas {
        position: relative; width: 3000px; height: 2000px;
        /* Grilla de líneas estilo CAD: trama menor cada 26px, mayor cada 130px */
        background-image:
            linear-gradient(var(--grid-major) 1px, transparent 1px),
            linear-gradient(90deg, var(--grid-major) 1px, transparent 1px),
            linear-gradient(var(--grid-minor) 1px, transparent 1px),
            linear-gradient(90deg, var(--grid-minor) 1px, transparent 1px);
        background-size: 130px 130px, 130px 130px, 26px 26px, 26px 26px;
        transform-origin: 0 0;
        cursor: grab;   /* click sostenido sobre el fondo = panear la vista */
    }
    #canvas.paneando { cursor: grabbing; }
    #zoom-label {
        min-width: 52px; text-align: center; font-size: .82rem; font-weight: 700;
        color: var(--muted); cursor: pointer; user-select: none;
    }
    #zoom-label:hover { color: var(--accent); }
    #links-svg { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
    #links-svg g { pointer-events: auto; }
    .link-visible { stroke: var(--accent); stroke-width: 2.5; fill: none; opacity: .85; }
    .link-hit { stroke: transparent; stroke-width: 14; fill: none; cursor: pointer; }
    g.link-g:hover .link-visible { stroke: var(--yellow); }
    .temp-link { stroke: var(--yellow); stroke-width: 2; stroke-dasharray: 6 5; fill: none; }

    /* ---------- Nodos ---------- */
    .node { position: absolute; cursor: grab; user-select: none; }
    .node:active { cursor: grabbing; }
    .node .shape {
        width: 100%; height: 100%;
        background: linear-gradient(155deg, var(--node-bg1), var(--node-bg2));
        border: 1.5px solid var(--border);
        display: flex; flex-direction: column; align-items: center; justify-content: center;
        text-align: center; padding: 10px; gap: 3px;
        box-shadow: 0 6px 18px rgba(0,0,0,.35);
        transition: border-color .12s, box-shadow .12s;
    }
    /* Cada método HTTP tiene su forma: GET=círculo, POST=rectángulo, PUT=rombo, PATCH=hexágono, DELETE=octágono */
    .node.rect { width: 190px; height: 84px; }
    .node.rect .shape { border-radius: 3px; }
    .node.rombo { width: 200px; height: 120px; }
    .node.rombo .shape { clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%); border: none; outline: 1.5px solid var(--border); outline-offset: -1px; }
    .node.circulo { width: 140px; height: 140px; }
    .node.circulo .shape { border-radius: 50%; }
    .node.hexagono { width: 210px; height: 100px; }
    .node.hexagono .shape { clip-path: polygon(22% 0, 78% 0, 100% 50%, 78% 100%, 22% 100%, 0 50%); border: none; outline: 1.5px solid var(--border); outline-offset: -1px; }
    .node.octagono { width: 160px; height: 120px; }
    .node.octagono .shape { clip-path: polygon(30% 0, 70% 0, 100% 28%, 100% 72%, 70% 100%, 30% 100%, 0 72%, 0 28%); border: none; outline: 1.5px solid var(--border); outline-offset: -1px; }
    /* FLOW: heptágono (7 lados) — un flujo publicado invocado como nodo */
    .node.heptagono { width: 180px; height: 150px; }
    .node.heptagono .shape { clip-path: polygon(50% 0, 90% 19%, 100% 61%, 74% 100%, 26% 100%, 0 61%, 10% 19%); border: none; outline: 1.5px solid var(--border); outline-offset: -1px; }
    /* Protocolos no-HTTP: cada categoría tiene su figura propia */
    .node.triangulo { width: 210px; height: 150px; }                    /* GraphQL */
    .node.triangulo .shape { clip-path: polygon(50% 0, 100% 100%, 0 100%); border: none; outline: 1.5px solid var(--border); outline-offset: -1px; justify-content: flex-end; padding: 0 22px 12px; }
    /* Condición (IF): triángulo RECTÁNGULO con el lado perpendicular a la derecha.
       La relación de entrada llega al vértice izquierdo y las salidas ✓/✗ se apoyan
       sobre el lado vertical: las líneas quedan en contacto con la figura. */
    .node.condicion { width: 210px; height: 130px; }
    .node.condicion .shape { clip-path: polygon(0 50%, 100% 0, 100% 100%); border: none; outline: 1.5px solid var(--border); outline-offset: -1px; padding: 10px 16px 10px 27%; }
    .node.pentagono { width: 185px; height: 150px; }                    /* gRPC */
    .node.pentagono .shape { clip-path: polygon(50% 0, 100% 38%, 82% 100%, 18% 100%, 0 38%); border: none; outline: 1.5px solid var(--border); outline-offset: -1px; padding-top: 26px; }
    .node.capsula { width: 215px; height: 92px; }                       /* WebSocket */
    .node.capsula .shape { border-radius: 999px; padding: 10px 26px; }
    .node.paralelogramo { width: 220px; height: 92px; }                 /* Colas */
    .node.paralelogramo .shape { clip-path: polygon(14% 0, 100% 0, 86% 100%, 0 100%); border: none; outline: 1.5px solid var(--border); outline-offset: -1px; padding: 10px 30px; }
    .node.galon { width: 225px; height: 96px; }                         /* OAuth 2.0 */
    .node.galon .shape { clip-path: polygon(0 0, 78% 0, 100% 50%, 78% 100%, 0 100%, 18% 50%); border: none; outline: 1.5px solid var(--border); outline-offset: -1px; padding: 10px 34px 10px 44px; }
    .node.trapecio { width: 220px; height: 104px; }                     /* socket TCP / Telnet */
    .node.trapecio .shape { clip-path: polygon(16% 0, 84% 0, 100% 100%, 0 100%); border: none; outline: 1.5px solid var(--border); outline-offset: -1px; padding: 10px 26px; }
    .node.ia { width: 205px; height: 92px; }                            /* Nodo IA (chip) */
    .node.ia .shape { border-radius: 16px; border: 1.5px solid #7c5cff; box-shadow: inset 0 0 0 1px #7c5cff2e; }
    .node.ficha { width: 205px; height: 100px; }                        /* Parser (documento con esquina doblada) */
    .node.ficha .shape { clip-path: polygon(0 0, 82% 0, 100% 24%, 100% 100%, 0 100%); border: none; outline: 1.5px solid var(--border); outline-offset: -1px; padding: 12px 18px; }
    .node.ficha.selected .shape { outline-color: var(--accent); }
    .node.ficha.running .shape { outline-color: var(--yellow); }
    .node.ficha .n-status { right: 50%; transform: translateX(50%); }

    /* Figuras ÚNICAS de los nodos de sistema (grupos CRM / ERP / PMS / Caja).
       Viajan en la propiedad persistida `forma` del nodo (no dependen del método). */
    .node.domo { width: 195px; height: 104px; }                          /* Salesforce */
    .node.domo .shape { border-radius: 999px 999px 10px 10px; padding: 16px 26px 10px; }
    .node.sello { width: 195px; height: 130px; }                         /* HubSpot */
    .node.sello .shape { clip-path: polygon(100% 50%, 90.6% 60.9%, 93.3% 75%, 79.7% 79.7%, 75% 93.3%, 60.9% 90.6%, 50% 100%, 39.1% 90.6%, 25% 93.3%, 20.3% 79.7%, 6.7% 75%, 9.4% 60.9%, 0 50%, 9.4% 39.1%, 6.7% 25%, 20.3% 20.3%, 25% 6.7%, 39.1% 9.4%, 50% 0, 60.9% 9.4%, 75% 6.7%, 79.7% 20.3%, 93.3% 25%, 90.6% 39.1%); border: none; outline: 1.5px solid var(--border); outline-offset: -1px; padding: 16px 26px; }
    .node.cometa { width: 190px; height: 135px; }                        /* Dynamics 365 */
    .node.cometa .shape { clip-path: polygon(50% 0, 100% 36%, 50% 100%, 0 36%); border: none; outline: 1.5px solid var(--border); outline-offset: -1px; padding: 18px 30px 26px; }
    .node.cubo { width: 180px; height: 132px; }                          /* SAP B1 Service Layer */
    .node.cubo .shape { clip-path: polygon(50% 0, 100% 24%, 100% 76%, 50% 100%, 0 76%, 0 24%); border: none; outline: 1.5px solid var(--border); outline-offset: -1px; padding: 20px 16px; }
    .node.archivador { width: 200px; height: 96px; }                     /* SAP B1 SQL directo */
    .node.archivador .shape { border-radius: 6px; }
    .node.archivador .shape::before {
        content: ''; position: absolute; left: 10px; right: 10px; top: 30%; height: 0;
        border-top: 1.5px solid var(--border); pointer-events: none;
    }
    .node.archivador .shape::after {
        content: ''; position: absolute; left: 10px; right: 10px; bottom: 26%; height: 0;
        border-top: 1.5px solid var(--border); pointer-events: none;
    }
    .node.casita { width: 190px; height: 112px; }                        /* Opera (hospedaje) */
    .node.casita .shape { clip-path: polygon(50% 0, 100% 32%, 100% 100%, 0 100%, 0 32%); border: none; outline: 1.5px solid var(--border); outline-offset: -1px; padding: 24px 18px 10px; }
    .node.escudo { width: 190px; height: 110px; }                        /* Cloudbeds */
    .node.escudo .shape { border-radius: 10px 10px 52% 52% / 10px 10px 58% 58%; padding: 10px 26px 18px; }
    .node.etiqueta { width: 215px; height: 92px; }                       /* protel */
    .node.etiqueta .shape { clip-path: polygon(0 0, 82% 0, 100% 50%, 82% 100%, 0 100%); border: none; outline: 1.5px solid var(--border); outline-offset: -1px; padding: 10px 40px 10px 18px; }
    .node.cofre { width: 195px; height: 98px; }                          /* Caja · Integration Framework */
    .node.cofre .shape { border-radius: 22px 22px 6px 6px; padding: 14px 20px 10px; }
    .node.cofre .shape::before {
        content: ''; position: absolute; left: 0; right: 0; top: 32%; height: 0;
        border-top: 1.5px solid var(--border); pointer-events: none;
    }

    .node.sello.selected .shape, .node.cometa.selected .shape, .node.cubo.selected .shape,
    .node.casita.selected .shape, .node.etiqueta.selected .shape { outline-color: var(--accent); }
    .node.sello.running .shape, .node.cometa.running .shape, .node.cubo.running .shape,
    .node.casita.running .shape, .node.etiqueta.running .shape { outline-color: var(--yellow); }
    .node.domo .n-status, .node.sello .n-status, .node.cometa .n-status, .node.cubo .n-status,
    .node.casita .n-status { right: 50%; transform: translateX(50%); }
    /* En las figuras con punta o curva arriba, los botones ▶/✕ van al centro
       (como en círculo/rombo) para no caer fuera del recorte. */
    .node.sello .n-del, .node.cometa .n-del, .node.cubo .n-del, .node.casita .n-del,
    .node.domo .n-del { left: 50%; transform: translateX(-160%); }
    .node.sello .n-run, .node.cometa .n-run, .node.cubo .n-run, .node.casita .n-run,
    .node.domo .n-run { right: 50%; transform: translateX(50%); }
    .node.sello .n-run:hover, .node.cometa .n-run:hover, .node.cubo .n-run:hover,
    .node.casita .n-run:hover, .node.domo .n-run:hover { transform: translateX(50%) scale(1.15); }
    .node.selected .shape { border-color: var(--accent); box-shadow: 0 0 0 3px #4d8bfd44, 0 6px 18px rgba(0,0,0,.35); }
    .node.rombo.selected .shape, .node.hexagono.selected .shape, .node.octagono.selected .shape, .node.heptagono.selected .shape,
    .node.condicion.selected .shape, .node.triangulo.selected .shape, .node.pentagono.selected .shape, .node.paralelogramo.selected .shape, .node.trapecio.selected .shape,
    .node.galon.selected .shape { outline-color: var(--accent); }
    .node .n-name { font-weight: 700; font-size: .88rem; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .node .n-info { font-size: .7rem; color: var(--muted); max-width: 92%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .node .n-method { font-weight: 800; font-size: .68rem; letter-spacing: .5px; }
    .m-GET { color: var(--green); } .m-POST { color: var(--yellow); }
    .m-PUT { color: var(--accent); } .m-PATCH { color: var(--purple); } .m-DELETE { color: var(--red); }
    .m-FLOW { color: #14a3a3; }
    .m-GRAPHQL { color: #e535ab; } .m-GRPC { color: #5b6ef5; } .m-WS { color: #ff8a3d; }
    .m-QUEUE { color: #9bb300; } .m-SOCKET { color: #9aa0a6; } .m-OAUTH { color: #e0574f; }
    .m-DUMMY { color: #b58cf5; } .m-TIMER { color: var(--accent); } .m-DB { color: #e8a33d; } .m-IA { color: #7c5cff; } .m-PARSE { color: #29b6f6; }
/* El nodo Código: una placa con la esquina superior derecha cortada, como una ficha
   de código. El morado es el de C#. */
.node.codigo { width: 150px; height: 84px; }
.node.codigo .shape {
    clip-path: polygon(0 0, calc(100% - 14px) 0, 100% 14px, 100% 100%, 0 100%);
    border-left: 3px solid #68217A;
}
.m-CODIGO { color: #a06ab4; }

/* Los dos nodos del contrato: placas con una muesca que indica por donde entra o sale
   el dato del servicio. Verde para lo que entra, azul para lo que se devuelve: es la
   misma lectura que las flechas del lienzo. */
.node.entrada, .node.salida { width: 150px; height: 78px; }
.node.entrada .shape {
    clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%, 14px 50%);
    border-right: 3px solid #2e9e5b;
}
.node.salida .shape {
    clip-path: polygon(0 0, calc(100% - 14px) 0, 100% 50%, calc(100% - 14px) 100%, 0 100%);
    border-left: 3px solid #2f7de1;
}
.m-IN { color: #2e9e5b; } .m-OUT { color: #2f7de1; }

/* ============================================================
   DEPURACIÓN DEL SERVIDOR — la banderita y el nodo detenido
   La bandera está SIEMPRE en el nodo, apagada y casi invisible: que aparezca recién al
   pasar el mouse la volvería un secreto, y lo que se quiere es que se vea de un vistazo
   dónde va a frenar el flujo.
============================================================ */
/* Se dibuja como una FICHA, no como un caracter suelto: un borde y un fondo la hacen
   leer como algo que se toca. Apagada tiene que VERSE —gris medio, no gris papel—, porque
   si no nadie descubre que el control existe.
   El --zoom lo publica renderZoom(): el lienzo entero se escala con transform, así que sin
   contra-escalar, al 27% esta ficha mediría cinco píxeles. */
.n-bp {
    position: absolute; top: -11px; left: -9px; z-index: 6;
    width: 20px; height: 20px; box-sizing: border-box;
    display: flex; align-items: center; justify-content: center;
    font-size: .74rem; line-height: 1; cursor: pointer;
    border-radius: 50%; border: 1px solid var(--border);
    background: var(--panel); color: var(--muted);
    /* Contra-escala ACOTADA. Sin tope, al 27% la ficha quedaría de 20 px sobre un nodo
       de 19 y lo taparía: cuando mirás todo el lienzo de lejos no estás apretando
       banderas, estás navegando. Con el tope se achica un poco pero se sigue viendo. */
    transform: scale(clamp(0.85, calc(1 / var(--zoom, 1)), 2)); transform-origin: 50% 50%;
    transition: color .12s, background .12s, border-color .12s, box-shadow .12s;
}
.n-bp:hover { color: var(--red, #e5484d); border-color: var(--red, #e5484d); }
.n-bp.on {
    color: #fff; background: var(--red, #e5484d); border-color: var(--red, #e5484d);
    box-shadow: 0 0 8px rgba(229, 72, 77, .6);
}

/* Nodo con breakpoint: un borde rojo tenue, para ubicarlos sin leer bandera por bandera. */
.node.con-bp .shape { box-shadow: inset 0 0 0 1.5px rgba(229, 72, 77, .55); }

/* Nodo donde la ejecución está PARADA ahora: el recuadro que la señala, y late para que
   se encuentre solo aunque el lienzo esté lleno. */
.node.frenado .shape {
    box-shadow: 0 0 0 3px var(--red, #e5484d), 0 0 18px 4px rgba(229, 72, 77, .45);
    animation: bp-late 1.1s ease-in-out infinite;
}
@keyframes bp-late {
    0%, 100% { box-shadow: 0 0 0 3px var(--red, #e5484d), 0 0 18px 4px rgba(229, 72, 77, .45); }
    50%      { box-shadow: 0 0 0 3px var(--red, #e5484d), 0 0 26px 8px rgba(229, 72, 77, .18); }
}
@media (prefers-reduced-motion: reduce) { .node.frenado .shape { animation: none; } }

/* Los controles de la ejecución frenada: flotan abajo, sin robarle lugar al lienzo. */
#bp-controles {
    position: fixed; left: 50%; bottom: 22px; transform: translateX(-50%); z-index: 60;
    display: flex; align-items: center; gap: 8px;
    padding: 8px 12px; border-radius: 10px;
    background: var(--panel-2); border: 1px solid var(--red, #e5484d);
    box-shadow: 0 8px 28px rgba(0, 0, 0, .35);
}
#bp-controles .bp-donde { font-size: .82rem; margin-right: 4px; white-space: nowrap; }

/* Tabla de parametros del nodo Entrada: entra en el panel lateral angosto y crece en
   el modal, por eso el contenedor scrollea en vez de desbordar. */
.in-tabla { width: 100%; border-collapse: collapse; font-size: .78rem; display: block; overflow-x: auto; }
.in-tabla th {
    text-align: left; font-weight: 700; color: var(--muted);
    padding: 3px 4px; border-bottom: 1px solid var(--border); white-space: nowrap;
}
.in-tabla td { padding: 2px 3px; vertical-align: middle; }
.in-tabla input[type=text], .in-tabla select { width: 100%; min-width: 74px; margin: 0; padding: 3px 5px; font-size: .78rem; }
.in-tabla .in-del { padding: 1px 6px; line-height: 1.2; }
/* Fila a medio escribir: existe en el editor pero todavia no en el contrato. */
.in-tabla tr.in-anonima .in-nombre { border-color: var(--yellow, #e0b23f); }
/* Tipos y clases en el resaltado de C# (JsonElement, Enumerable…). */
.hl-tipo { color: var(--hl-tipo, #4ec9b0); }
    .n-status {
        position: absolute; top: -9px; right: 14px;
        font-size: .66rem; font-weight: 800; padding: 2px 8px; border-radius: 999px;
        background: var(--panel-2); border: 1px solid var(--border); color: var(--muted);
    }
    .node.circulo .n-status, .node.rombo .n-status, .node.hexagono .n-status, .node.octagono .n-status, .node.heptagono .n-status,
    .node.condicion .n-status, .node.triangulo .n-status, .node.pentagono .n-status, .node.capsula .n-status, .node.paralelogramo .n-status, .node.trapecio .n-status,
    .node.galon .n-status { right: 50%; transform: translateX(50%); }
    .n-status.ok { color: #fff; background: var(--green); border-color: var(--green); }
    .n-status.err { color: #fff; background: var(--red); border-color: var(--red); }
    .n-status.run { color: #111; background: var(--yellow); border-color: var(--yellow); }

    /* Nodo en ejecución: contorno resaltado para depurar el flujo */
    .node.running .shape {
        border-color: var(--yellow);
        animation: exec-glow .7s ease-in-out infinite alternate;
    }
    .node.rombo.running .shape, .node.hexagono.running .shape, .node.octagono.running .shape, .node.heptagono.running .shape,
    .node.triangulo.running .shape, .node.pentagono.running .shape, .node.paralelogramo.running .shape, .node.trapecio.running .shape,
    .node.galon.running .shape { outline-color: var(--yellow); }
    @keyframes exec-glow {
        from { box-shadow: 0 0 0 3px #e0b23f55, 0 6px 18px rgba(0,0,0,.35); }
        to   { box-shadow: 0 0 0 7px #e0b23f22, 0 0 22px #e0b23fa0; }
    }

    .port {
        position: absolute; width: 15px; height: 15px; border-radius: 50%;
        background: var(--panel-2); border: 2px solid var(--muted);
        top: 50%; transform: translateY(-50%); z-index: 5; cursor: crosshair;
        transition: transform .1s, border-color .1s, background .1s;
    }
    .port-in  { left: -8px; }
    .port-out { right: -8px; border-color: var(--accent); }
    .port:hover { transform: translateY(-50%) scale(1.35); }
    .port-out:hover { background: var(--accent); }
    body.connecting .port-in { border-color: var(--yellow); animation: pulse 1s infinite; }
    body.connecting .port-in:hover { background: var(--yellow); }

    /* Condición: dos salidas en vez de una, apoyadas sobre el lado VERTICAL derecho
       del triángulo rectángulo (la entrada llega al vértice izquierdo): las líneas
       nacen y llegan pegadas a la figura. El color y la marca dicen cuál rama es
       cuál; la posición real la lee portPos() del DOM, no está duplicada en el JS. */
    .node.condicion .port-si { top: 26%; border-color: var(--green); }
    .node.condicion .port-no { top: 74%; border-color: var(--red); }
    .node.condicion .port-si:hover { background: var(--green); }
    .node.condicion .port-no:hover { background: var(--red); }
    .node.condicion .port-si::after, .node.condicion .port-no::after {
        position: absolute; right: 19px; top: 50%; transform: translateY(-50%);
        font-size: 12px; font-weight: 700; line-height: 1; pointer-events: none;
    }
    .node.condicion .port-si::after { content: '\2713'; color: var(--green); }
    .node.condicion .port-no::after { content: '\2717'; color: var(--red); }
    @keyframes pulse { 50% { box-shadow: 0 0 0 5px #e0b23f33; } }

    .n-run {
        position: absolute; bottom: -13px; right: 14px;
        width: 28px; height: 28px; border-radius: 50%;
        background: var(--green); color: #fff; border: 2px solid var(--bg); cursor: pointer;
        font-size: .7rem; line-height: 1; z-index: 5;
        display: flex; align-items: center; justify-content: center;
        box-shadow: 0 2px 8px rgba(0,0,0,.4);
        transition: transform .1s, background .1s;
    }
    .n-run:hover { background: #35a05c; transform: scale(1.15); }
    /* Botón de eliminar del nodo (esquina superior izquierda) */
    .n-del {
        position: absolute; top: -10px; left: 10px;
        width: 22px; height: 22px; border-radius: 50%;
        background: var(--panel-2); color: var(--muted); border: 1px solid var(--border); cursor: pointer;
        font-size: .66rem; line-height: 1; z-index: 6;
        display: flex; align-items: center; justify-content: center;
        opacity: 0; transition: opacity .12s, background .12s, color .12s;
    }
    .node:hover .n-del { opacity: 1; }
    .n-del:hover { background: var(--red); color: #fff; border-color: var(--red); }
    .node.circulo .n-del, .node.rombo .n-del, .node.hexagono .n-del, .node.octagono .n-del, .node.heptagono .n-del { left: 50%; transform: translateX(-160%); }
    .node.circulo .n-run:hover, .node.rombo .n-run:hover, .node.hexagono .n-run:hover, .node.octagono .n-run:hover { transform: translateX(50%) scale(1.15); }
    .node.circulo .n-run, .node.rombo .n-run, .node.hexagono .n-run, .node.octagono .n-run, .node.heptagono .n-run { right: 50%; transform: translateX(50%); }

    /* ---------- Controles de zoom sobre el lienzo ---------- */
    #zoom-overlay {
        grid-area: canvas; align-self: end; justify-self: end;
        margin: 0 16px 16px 0; z-index: 120;
        display: flex; align-items: center; gap: 2px;
        background: var(--panel); border: 1px solid var(--border); border-radius: 2px;
        padding: 3px 4px; box-shadow: 0 6px 18px rgba(0,0,0,.35);
        user-select: none;
    }
    .zo-btn {
        background: transparent; border: 1px solid transparent; border-radius: 2px;
        color: var(--text); font: inherit; font-size: .9rem; line-height: 1;
        padding: 4px 9px; cursor: pointer;
    }
    .zo-btn:hover { background: var(--panel-2); border-color: var(--accent); }
    #zo-label {
        min-width: 48px; text-align: center; font-size: .78rem; font-weight: 700;
        color: var(--muted); cursor: pointer;
    }
    #zo-label:hover { color: var(--accent); }

    /* ---------- Previsualización de un flujo desplegado en el lienzo ---------- */
    .n-expand {
        position: absolute; bottom: -13px; left: 14px;
        width: 26px; height: 26px; border-radius: 50%;
        background: #14a3a3; color: #fff; border: 2px solid var(--bg); cursor: pointer;
        font-size: .7rem; line-height: 1; z-index: 5;
        display: flex; align-items: center; justify-content: center;
        box-shadow: 0 2px 8px rgba(0,0,0,.4);
    }
    .n-expand:hover { background: #0d8a8a; }
    .node.heptagono .n-expand { left: 50%; transform: translateX(-115%); }
    .subflow-box {
        position: absolute; z-index: 1;
        border: 1.5px dashed #14a3a3; border-radius: 3px;
        background: color-mix(in srgb, var(--panel) 55%, transparent);
    }
    .sf-title {
        font-size: .68rem; font-weight: 700; color: #14a3a3;
        padding: 4px 8px; border-bottom: 1px dashed #14a3a355;
        display: flex; justify-content: space-between; align-items: center;
    }
    .sf-close { cursor: pointer; color: var(--muted); font-weight: 700; }
    .sf-close:hover { color: var(--red); }
    .sf-svg { position: absolute; inset: 0; pointer-events: none; }
    .sf-link { stroke: #14a3a3; stroke-width: 2; fill: none; stroke-dasharray: 5 4; opacity: .8; }
    .sf-node { position: absolute; transform-origin: 0 0; pointer-events: none; width: 190px; height: 84px; }
    .sf-node .shape {
        width: 100%; height: 100%;
        background: linear-gradient(155deg, var(--node-bg1), var(--node-bg2));
        border: 1.5px dashed var(--border); border-radius: 3px;
        display: flex; flex-direction: column; align-items: center; justify-content: center;
        text-align: center; padding: 6px; gap: 2px; opacity: .95;
    }
    .sf-node.circulo { width: 140px; height: 140px; } .sf-node.circulo .shape { border-radius: 50%; }
    .sf-node.rombo { width: 200px; height: 120px; }
    .sf-node.hexagono { width: 210px; height: 100px; }
    .sf-node.octagono { width: 160px; height: 120px; }
    .sf-node.heptagono { width: 180px; height: 150px; }
    .sf-node .n-name { font-weight: 700; font-size: .82rem; }
    .sf-node .n-info { font-size: .66rem; color: var(--muted); }
    .sf-node .n-method { font-weight: 800; font-size: .64rem; }

    /* Pestañas dentro del popup del nodo */
    .nm-tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--border); margin-bottom: 8px; }
    .nm-tab {
        background: transparent; border: none; cursor: pointer; font: inherit;
        color: var(--muted); font-weight: 700; font-size: .8rem;
        padding: 6px 12px; border-bottom: 2px solid transparent;
    }
    .nm-tab:hover { color: var(--text); }
    .nm-tab.active { color: var(--text); border-bottom-color: var(--accent); }
    .nm-pane.hidden { display: none; }

    /* ---------- Sidebar (panel de propiedades, dockeable y arrastrable) ---------- */
    #sidebar {
        grid-area: sidebar; background: var(--panel);
        border-left: 1px solid var(--border);
        display: flex; flex-direction: column;
        position: relative; min-width: 0;
    }
    #sidebar-grip {
        cursor: move; font-size: .64rem; font-weight: 700; color: var(--muted);
        text-transform: uppercase; letter-spacing: .5px;
        padding: 5px 8px; text-align: center;
        background: var(--panel-2); border-bottom: 1px solid var(--border);
        white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
        user-select: none;
    }
    #props { flex: 1; overflow-y: auto; padding: 16px; }
    /* pestañas del panel derecho: Propiedades / Jarvis (IA) */
    #side-tabs { display: flex; border-bottom: 1px solid var(--border); background: var(--panel-2); }
    .side-tab {
        flex: 1; padding: 7px 6px; font-size: .74rem; font-weight: 700;
        background: transparent; color: var(--muted); border: 0; cursor: pointer;
        border-bottom: 2px solid transparent;
    }
    .side-tab:hover { color: var(--text); }
    .side-tab.active { color: var(--text); border-bottom-color: var(--accent); background: var(--panel); }
    .side-tab.side-float { flex: 0 0 auto; padding: 7px 10px; font-size: .9rem; }
    #side-amanda { flex: 1; min-height: 0; display: flex; }
    #side-amanda.hidden { display: none; }
    #amanda-frame { flex: 1; width: 100%; height: 100%; border: 0; background: #0b0f14; }
    #sidebar.floating {
        position: fixed; z-index: 160;
        border: 1px solid var(--border);
        box-shadow: 0 14px 40px rgba(0,0,0,.45);
        max-height: 84vh;
    }
    #sidebar.dock-left { border-left: none; border-right: 1px solid var(--border); }
    body.sidebar-out { grid-template-columns: 1fr 0; }

    /* Paneles COLAPSABLES: un clic despeja el lienzo y otro lo restaura (persistente).
       El panel lateral queda como una tira de 30px con su botón vertical; la consola,
       reducida a su fila de pestañas (elegir una pestaña también la restaura). */
    body.panel-colapsado:not(.sidebar-out) { grid-template-columns: 1fr 30px; }
    body.panel-colapsado #sidebar #props,
    body.panel-colapsado #sidebar #side-amanda,
    body.panel-colapsado #sidebar #sidebar-grip,
    body.panel-colapsado #sidebar #sidebar-resize { display: none !important; }
    body.panel-colapsado #side-tabs { flex-direction: column; padding: 4px 2px; gap: 4px; }
    body.panel-colapsado .side-tab { display: none; }
    body.panel-colapsado #side-colapsar { display: block; writing-mode: vertical-rl; padding: 12px 3px; }
    body.consola-colapsada { grid-template-rows: auto auto 1fr 35px 26px; }
    body.consola-colapsada #console-panel > :not(#console-head) { display: none !important; }
    #sidebar-resize {
        position: absolute; left: -3px; top: 0; bottom: 0; width: 7px;
        cursor: ew-resize; z-index: 5;
    }
    #sidebar.dock-left #sidebar-resize { left: auto; right: -3px; }
    #sidebar-resize:hover { background: #0696d755; }

    /* ---------- Popup de datos del nodo (doble click) ---------- */
    #node-modal {
        display: none; position: fixed; inset: 0; z-index: 200;
        background: rgba(0,0,0,.55); align-items: center; justify-content: center;
    }
    #node-box {
        background: var(--panel); border: 1px solid var(--border); border-radius: 2px;
        width: min(760px, 92vw); max-height: 86vh; display: flex; flex-direction: column;
        box-shadow: 0 18px 50px rgba(0,0,0,.5);
        /* OJO: sin transition de width acá — entre min(760px,92vw) y 96vw no es
           interpolable y Chrome se queda clavado en el valor inicial (el maximizado
           "no hacía nada"). El cambio es instantáneo a propósito. */
    }
    /* Maximizado: el formulario ocupa casi toda la ventana, cómodo para editar SQL,
       payloads largos o muchos parámetros. El botón ⛶ del header lo alterna. */
    #node-modal.maximizado #node-box { width: 96vw; max-height: 94vh; }
    #node-head #node-maximizar { padding: 2px 8px; }
    #node-head {
        display: flex; align-items: center; justify-content: space-between;
        padding: 10px 14px; border-bottom: 1px solid var(--border);
        font-weight: 700; font-size: .9rem;
    }
    #node-body { padding: 6px 14px 14px; overflow-y: auto; }
    #node-body label {
        display: block; font-size: .72rem; font-weight: 700; color: var(--muted);
        text-transform: uppercase; letter-spacing: .5px; margin: 10px 0 4px;
    }
    #node-body input[type=text], #node-body textarea {
        width: 100%; background: var(--panel-2); color: var(--text);
        border: 1px solid var(--border); border-radius: 2px;
        padding: 8px 10px; font-size: .85rem; font-family: Consolas, monospace;
    }
    #node-body input:focus, #node-body textarea:focus { outline: none; border-color: var(--accent); }
    #node-body textarea { resize: vertical; }
    .nm-status {
        font-size: .78rem; font-weight: 700; padding: 4px 8px; border-radius: 2px;
        display: inline-block; margin-bottom: 4px;
        background: var(--panel-2); border: 1px solid var(--border);
    }
    .nm-status.ok { color: #fff; background: var(--green); border-color: var(--green); }
    .nm-status.err { color: #fff; background: var(--red); border-color: var(--red); }

    /* ---------- Pantalla de login ---------- */
    #login-overlay {
        position: fixed; inset: 0; z-index: 400;
        background: var(--bg);
        display: flex; align-items: center; justify-content: center;
    }
    #login-overlay.hidden { display: none; }
    #login-box {
        width: min(380px, 92vw);
        background: var(--panel); border: 1px solid var(--border); border-radius: 2px;
        padding: 22px 24px; box-shadow: 0 20px 60px rgba(0,0,0,.45);
    }
    #login-brand {
        display: flex; align-items: center; gap: 10px;
        font-weight: 800; font-size: 1.15rem; margin-bottom: 6px;
    }
    #login-brand span { color: var(--accent); }
    #login-brand .brand-logo { width: 42px; height: 42px; border-radius: 9px; }
    #login-box label {
        display: block; font-size: .72rem; font-weight: 700; color: var(--muted);
        text-transform: uppercase; letter-spacing: .5px; margin: 12px 0 4px;
    }
    #login-box input {
        width: 100%; background: var(--panel-2); color: var(--text);
        border: 1px solid var(--border); border-radius: 2px;
        padding: 9px 11px; font-size: .9rem; font-family: Consolas, monospace;
    }
    #login-box input:focus { outline: none; border-color: var(--accent); }
    #login-box .btn { width: 100%; margin-top: 16px; padding: 9px; }
    #login-status { margin-top: 10px; min-height: 18px; }
    #sb-user { font-weight: 600; color: var(--text); }

    /* ---------- Validación: contexto y chequeos ---------- */
    .val-ctx {
        max-height: 220px; overflow-y: auto;
        border: 1px solid var(--border); border-radius: 2px;
        padding: 8px 10px; background: var(--panel-2);
    }
    .val-ctx .lv-row label { color: var(--hl-key); }
    .val-ctx .v-ctx-add { padding: 2px 8px; font-size: .72rem; }
    .val-row { display: flex; gap: 5px; margin-bottom: 6px; align-items: center; }
    .val-row .v-campo { flex: 1.5; min-width: 0; }
    .val-row .v-op { flex: 1.1; min-width: 0; }
    .val-row .v-exp { flex: 1; min-width: 0; }
    .val-row .v-exp:disabled { opacity: .45; }
    .val-row .v-del { padding: 6px 9px; }

    /* ---------- Abrir Flujo publicado: lista de la base de datos ---------- */
    .of-item {
        border: 1px solid var(--border); border-radius: 2px;
        padding: 10px 12px; margin-bottom: 8px; background: var(--panel-2);
    }
    .of-name { font-weight: 700; font-size: .88rem; }
    .of-item.of-off { opacity: .7; }
    .of-state { font-size: .7rem; font-weight: 700; margin-left: 4px; }
    .of-state.on { color: var(--green); }
    .of-state.off { color: var(--red); }
    .of-meta { color: var(--muted); font-weight: 400; font-size: .74rem; }
    .of-desc { color: var(--muted); font-size: .78rem; margin-top: 3px; line-height: 1.5; }
    .of-desc code {
        background: var(--panel-2); border: 1px solid var(--border); border-radius: 2px;
        padding: 0 4px; font-size: .72rem; color: var(--hl-key);
    }

    /* ---------- Editor con resaltado en vivo (URL y payload editables) ---------- */
    .code-editor { position: relative; }
    /* El texto visible lo pinta el <pre>; el campo va transparente encima. Los dos
       tienen que cortar las líneas EXACTAMENTE igual o el cursor y lo que se ve
       quedan corridos (el carácter aparece donde no va). */
    .code-editor .ce-hl {
        position: absolute; inset: 0; margin: 0; pointer-events: none; overflow: hidden;
        background: var(--panel-2); border: 1px solid var(--border); border-radius: 2px;
        padding: 8px 10px;
        font-family: Consolas, monospace; font-size: .85rem; line-height: 1.45;
        white-space: pre-wrap; word-break: normal; overflow-wrap: break-word; color: var(--text);
    }
    .code-editor.ce-line .ce-hl { white-space: pre; word-break: normal; overflow-wrap: normal; }
    .code-editor textarea, .code-editor input {
        position: relative; z-index: 1; display: block; width: 100%;
        background: transparent !important; color: transparent !important;
        caret-color: var(--text);
        font-family: Consolas, monospace; font-size: .85rem; line-height: 1.45;
        word-break: normal; overflow-wrap: break-word;
    }
    .code-editor textarea::selection, .code-editor input::selection { background: #0696d766; color: transparent; }
    .code-editor textarea::placeholder, .code-editor input::placeholder { color: var(--muted); opacity: .7; }
    /* inputs simples (headers) que contienen variables {{...}} */
    #sidebar input.has-tpl { color: var(--yellow); }

    /* Poda de atributos expuestos */
    .expose-list {
        max-height: 240px; overflow-y: auto;
        border: 1px solid var(--border); border-radius: 2px;
        background: var(--panel-2); padding: 4px 6px;
    }
    .exp-row {
        display: flex; align-items: center; gap: 6px;
        padding: 2px 2px; font-size: .74rem; cursor: pointer;
        font-family: Consolas, 'Courier New', monospace;
    }
    .exp-row:hover { background: #0696d722; }
    .exp-row input { width: auto; flex: 0 0 auto; }
    .exp-path { flex: 0 0 46%; color: var(--hl-key); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .exp-val { flex: 1; color: var(--hl-str); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .exp-row input:not(:checked) ~ .exp-path, .exp-row input:not(:checked) ~ .exp-val { color: var(--muted); text-decoration: line-through; opacity: .65; }

    /* Parámetros recibidos en el panel: formulario con colores del highlighting */
    .io-received { margin-top: 6px; }
    .io-received .lv-row label { color: var(--hl-key); }
    .io-received .lv-row input { color: var(--hl-str); }

    /* Contenedor Request: agrupa insertar variable, URL, headers y payload */
    .req-box {
        border: 1px solid var(--border); border-radius: 2px;
        padding: 10px 12px 12px; margin-top: 14px;
        background: color-mix(in srgb, var(--panel-2) 40%, transparent);
    }
    .req-box-title {
        font-size: .72rem; font-weight: 700; color: var(--accent);
        text-transform: uppercase; letter-spacing: .5px; margin-bottom: 2px;
    }
    .req-box label:first-of-type { margin-top: 6px; }
    .res-box .req-box-title { color: var(--green); }
    .res-box .io-title { font-size: .76rem; margin-top: 12px; }
    #node-body .res-box label { margin-top: 8px; }

    /* Mapeo de entrada al subflujo */
    .map-row { display: flex; gap: 5px; margin-bottom: 6px; align-items: center; }
    .map-row .mp-nodo { flex: 1; min-width: 0; }
    .map-row .mp-campo { flex: 1.2; min-width: 0; }
    .map-row .mp-valor { flex: 1.3; min-width: 0; }
    .map-row .mp-del { padding: 6px 9px; }

    /* Filas de headers (formulario nombre/valor) */
    .hdr-row { display: flex; gap: 6px; margin-bottom: 6px; align-items: center; }
    /* vale para todas las filas nombre/valor: headers, parámetros del payload,
       campos de la trama y las del popup del nodo — sin esto los campos se
       cortan porque el input toma su ancho por defecto */
    .hdr-row > input, .hdr-row > select { flex: 1 1 0; min-width: 0; }
    .hdr-row > input:nth-of-type(2) { flex: 1.4 1 0; }
    .hdr-row .hk { flex: 1 1 0; }
    .hdr-row .hv { flex: 1.4 1 0; }
    .hdr-row > .btn { flex: 0 0 auto; padding: 6px 10px; }
    #sidebar h2 { font-size: .95rem; margin-bottom: 14px; display: flex; align-items: center; gap: 8px; }
    #sidebar label { display: block; font-size: .72rem; font-weight: 700; color: var(--muted); margin: 12px 0 4px; text-transform: uppercase; letter-spacing: .5px; }
    #sidebar input[type=text], #sidebar select, #sidebar textarea {
        width: 100%; background: var(--panel-2); color: var(--text);
        border: 1px solid var(--border); border-radius: 2px;
        padding: 8px 10px; font-size: .85rem; font-family: Consolas, monospace;
    }
    #sidebar input:focus, #sidebar select:focus, #sidebar textarea:focus { outline: none; border-color: var(--accent); }
    #sidebar textarea { resize: vertical; min-height: 70px; }
    #sidebar .row { display: flex; gap: 8px; }
    #sidebar .row > * { flex: 1; }
    #sidebar .actions { margin-top: 18px; display: flex; gap: 8px; }
    .help { font-size: .8rem; color: var(--muted); line-height: 1.55; }
    .help code { background: var(--panel-2); padding: 1px 5px; border-radius: 4px; font-size: .75rem; color: var(--yellow); }
    .help h3 { color: var(--text); font-size: .85rem; margin: 14px 0 6px; }
    .help ul { margin-left: 16px; }
    .help li { margin-bottom: 5px; }

    /* ---------- Consola ---------- */
    #console-panel {
        grid-area: console; background: var(--console-bg);
        border-top: 1px solid var(--border);
        display: flex; flex-direction: column; min-height: 0;
        position: relative;
    }
    #console-resizer {
        position: absolute; top: -4px; left: 0; right: 0; height: 8px;
        cursor: ns-resize; z-index: 50;
    }
    #console-resizer:hover, body.resizing-console #console-resizer { background: #4d8bfd55; }
    body.resizing-console { cursor: ns-resize; user-select: none; }
    #console-head {
        display: flex; align-items: center; justify-content: space-between;
        padding: 6px 14px; border-bottom: 1px solid var(--border);
        font-size: .78rem; font-weight: 700; color: var(--muted);
    }
    #console { flex: 1; overflow-y: auto; padding: 8px 14px; font-family: Consolas, 'Courier New', monospace; font-size: .78rem; line-height: 1.5; }
    .log { margin-bottom: 4px; word-break: break-all; }
    .log .t { color: #566378; margin-right: 8px; }
    .log.req  { color: var(--accent); }
    .log.ok   { color: var(--green); }
    .log.err  { color: var(--red); }
    .log.info { color: var(--muted); }
    .log details { margin: 3px 0 6px 22px; color: #b8c4d6; }
    .log summary { cursor: pointer; color: var(--muted); font-size: .72rem; }
    .log pre { white-space: pre-wrap; background: var(--pre-bg); color: var(--text); border: 1px solid var(--border); border-radius: 2px; padding: 8px 10px; margin-top: 4px; max-height: 260px; overflow: auto; }
    .log details { color: var(--text); }

    /* ---------- Conexiones con datos: etiqueta y ponderación ---------- */
    .link-visible.has-data { stroke-width: 4; opacity: 1; }
    /* con contrato de mapeo: trazo punteado para distinguirlo de un vínculo suelto */
    .link-visible.has-map { stroke: var(--green); stroke-dasharray: 9 4; }
    .link-visible.seleccionado { stroke: var(--yellow); stroke-width: 5; opacity: 1; }
    .link-label text { fill: var(--text); font-size: 10px; font-family: Consolas, 'Courier New', monospace; }
    .link-label rect { fill: var(--label-bg); stroke: var(--border); }
    #links-svg marker path { fill: var(--accent); }
    g.link-g:hover .link-label rect { stroke: var(--yellow); }

    /* ---------- Entrada/salida en el panel de propiedades ---------- */
    #io-preview .io-title { font-size: .8rem; margin: 16px 0 4px; }
    .io-pre {
        white-space: pre-wrap; word-break: break-all;
        background: var(--panel-2); border: 1px solid var(--border); border-radius: 2px;
        padding: 8px 10px; margin-top: 6px;
        font-family: Consolas, 'Courier New', monospace; font-size: .74rem; line-height: 1.5;
        max-height: 240px; overflow: auto;
    }
    .io-pre.io-err { color: var(--red); }
    .io-warn { font-size: .75rem; color: var(--yellow); margin: 4px 0; line-height: 1.5; }
    .io-warn code { background: var(--panel-2); padding: 1px 4px; border-radius: 4px; font-size: .7rem; }

    /* ---------- Pestañas de la consola + Live View ---------- */
    .console-tabs { display: flex; gap: 4px; }
    .ctab {
        background: transparent; border: none; cursor: pointer;
        color: var(--muted); font-weight: 700; font-size: .78rem; font-family: inherit;
        padding: 4px 10px; border-bottom: 2px solid transparent;
    }
    .ctab:hover { color: var(--text); }
    .ctab.active { color: var(--text); border-bottom-color: var(--accent); }
    #liveview {
        flex: 1; overflow-y: auto; padding: 10px 14px;
        display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-start;
    }
    #liveview.hidden { display: none; }
    .lv-card {
        background: var(--panel); border: 1px solid var(--border); border-radius: 2px;
        padding: 10px 12px; flex: 1 1 300px; min-width: 260px; max-width: 480px;
        cursor: pointer;
    }
    .lv-card.selected { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
    .lv-card.lv-total { flex-basis: 100%; max-width: none; border-color: var(--accent); }
    .lv-head { display: flex; gap: 8px; align-items: center; margin-bottom: 6px; font-weight: 700; font-size: .82rem; }
    .lv-status {
        margin-left: auto; font-size: .68rem; font-weight: 800; padding: 2px 8px; border-radius: 999px;
        background: var(--panel-2); border: 1px solid var(--border); color: var(--muted);
    }
    .lv-status.ok { background: var(--green); border-color: var(--green); color: #fff; }
    .lv-status.err { background: var(--red); border-color: var(--red); color: #fff; }
    .lv-sec { font-size: .7rem; font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: .5px; margin: 8px 0 4px; }
    .lv-row { display: flex; gap: 8px; align-items: center; margin-bottom: 4px; }
    .lv-row label {
        flex: 0 0 42%; text-align: right;
        font-size: .72rem; color: var(--muted); font-family: Consolas, 'Courier New', monospace;
        overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    .lv-row input {
        flex: 1; min-width: 0;
        background: var(--panel-2); border: 1px solid var(--border); border-radius: 2px;
        color: var(--text); font-family: Consolas, 'Courier New', monospace; font-size: .74rem;
        padding: 4px 8px;
    }
    .lv-row input:focus { outline: none; border-color: var(--accent); }

    /* ---------- Syntax highlighting de payloads ---------- */
    .hl-key { color: var(--hl-key); }
    .hl-str { color: var(--hl-str); }
    .hl-num { color: var(--hl-num); }
    .hl-bool { color: var(--purple); font-weight: 600; }
    .hl-brace { color: var(--text); font-weight: 700; }
    .hl-punc { color: var(--muted); }
    .hl-tag { color: var(--hl-tag); font-weight: 600; }
    .hl-xmltext { color: var(--hl-str); }
    .hl-comment { color: var(--muted); font-style: italic; }
    .hl-tpl { color: var(--yellow); background: #e0b23f22; border-radius: 2px; }
    .log-sec, .io-sub {
        font-size: .66rem; font-weight: 700; color: var(--muted);
        text-transform: uppercase; letter-spacing: .5px; margin: 6px 0 2px;
    }
    .log .log-sec { margin-left: 22px; }

    /* ---------- Flujo Descriptivo: relato en lenguaje natural ---------- */
    #storyview {
        flex: 1; overflow-y: auto; padding: 12px 16px;
        font-size: .84rem; line-height: 1.7; max-width: 980px;
    }
    #storyview.hidden { display: none; }
    .story-intro { color: var(--text); margin-bottom: 10px; }
    .story-step {
        border-left: 3px solid var(--accent); background: var(--panel);
        border-radius: 2px; padding: 8px 12px; margin-bottom: 8px;
    }
    .story-title { font-weight: 700; margin-bottom: 3px; }
    .story-text { color: var(--text); }
    .story-text code {
        background: var(--panel-2); border: 1px solid var(--border); border-radius: 2px;
        padding: 0 4px; font-size: .76rem; color: var(--yellow);
    }
    .story-place { color: var(--muted); font-size: .78rem; }
    .story-err { color: var(--red); font-weight: 600; }
    .story-end { color: var(--muted); text-align: center; margin-top: 10px; }

    /* ---------- Botón RAW y popup del mensaje original ---------- */
    .lv-raw { padding: 2px 8px; font-size: .66rem; margin-left: 6px; }
    .lv-prune.active, .lv-all.active { background: var(--accent); border-color: var(--accent); color: #fff; }
    /* valores que llegan propagados desde nodos anteriores */
    .lv-row.row-propagated label { color: #14a3a3; }
    .lv-row.row-propagated input { border-style: dashed; }
    .prop-chk {
        display: flex; align-items: center; gap: 6px; margin: 6px 0;
        font-size: .76rem; color: var(--text); cursor: pointer; text-transform: none; letter-spacing: 0;
    }
    .prop-chk input { width: auto; }

    /* atributos podados mostrados por "ver todos" */
    .lv-row.row-pruned label { color: var(--muted); text-decoration: line-through; }
    .lv-row.row-pruned input { color: var(--muted); opacity: .7; }
    .lv-expose { margin: 6px 0 2px; }
    .lv-expose .io-title { margin-top: 4px; }
    .lv-expose .expose-list { max-height: 180px; }
    #raw-modal {
        display: none; position: fixed; inset: 0; z-index: 200;
        background: rgba(0,0,0,.55); align-items: center; justify-content: center;
    }
    #raw-box {
        background: var(--panel); border: 1px solid var(--border); border-radius: 2px;
        width: min(860px, 92vw); max-height: 84vh; display: flex; flex-direction: column;
        box-shadow: 0 18px 50px rgba(0,0,0,.5);
    }
    #raw-head {
        display: flex; align-items: center; justify-content: space-between;
        padding: 10px 14px; border-bottom: 1px solid var(--border);
        font-weight: 700; font-size: .85rem;
    }
    #raw-pre {
        margin: 0; padding: 12px 14px; overflow: auto;
        font-family: Consolas, 'Courier New', monospace; font-size: .76rem; line-height: 1.5;
        color: var(--text); white-space: pre-wrap; word-break: break-all;
    }
    /* buscador del RAW: un cuadro que ubica texto en el request y en la respuesta */
    #raw-head .raw-buscar { display: flex; align-items: center; gap: 4px; margin-left: 10px; flex: 1; min-width: 120px; }
    #raw-head #raw-buscar {
        flex: 1; min-width: 90px; max-width: 260px;
        background: var(--panel-2); border: 1px solid var(--border); border-radius: 2px;
        color: var(--text); font: inherit; font-weight: 400; font-size: .78rem;
        padding: 4px 8px; outline: none;
    }
    #raw-head #raw-buscar:focus { border-color: var(--accent); }
    #raw-head #raw-buscar-n { color: var(--muted); font-weight: 400; font-size: .74rem; white-space: nowrap; }
    /* coincidencias: todas marcadas, la activa resaltada fuerte (a ella se hace scroll) */
    #raw-pre mark.raw-hit { background: rgba(224,178,63,.35); color: inherit; border-radius: 2px; padding: 0 1px; }
    #raw-pre mark.raw-hit--activa { background: var(--accent); color: #fff; }

/* ---------- Reemplazo de estilos inline del HTML ---------- */
.hidden { display: none; }
#console-head .btn { padding: 3px 10px; font-size: .72rem; }

/* ---------- Adaptación a pantallas chicas ----------
   La barra de acciones y la de menús no envolvían: al angostarse la ventana
   los textos se encimaban. Ahora envuelven y la tipografía baja por tramos. */
#actionbar { flex-wrap: wrap; row-gap: 4px; }
#menubar { flex-wrap: wrap; row-gap: 2px; }
#statusbar { flex-wrap: wrap; row-gap: 2px; }
#toolbar .brand { min-width: 0; }

@media (max-width: 1280px) {
    #toolbar { padding: 7px 10px; gap: 6px; }
    #toolbar .brand { font-size: .95rem; margin-right: 8px; }
    .menu-btn { font-size: .8rem; padding: 5px 8px; }
    .ab-btn { font-size: .75rem; padding: 4px 9px; }
}

@media (max-width: 1024px) {
    #toolbar { padding: 6px 8px; }
    #toolbar .brand { font-size: .88rem; margin-right: 4px; }
    .brand-logo { width: 22px; height: 22px; }
    .menu-btn { font-size: .76rem; padding: 5px 6px; }
    .ab-btn { font-size: .72rem; padding: 4px 7px; }
    #statusbar { font-size: .68rem; }
    .menu-drop { min-width: 220px; }
}

@media (max-width: 820px) {
    /* la marca queda solo con el logo: el nombre ya está en el título de la ventana */
    #toolbar .brand { font-size: 0; gap: 0; margin-right: 6px; }
    .menu-btn { font-size: .74rem; padding: 4px 5px; }
    .ab-btn { font-size: .7rem; padding: 4px 6px; }
    .menu-drop { min-width: 200px; }
    .menu-drop button, .submenu-drop button { font-size: .78rem; padding: 6px 8px; }
}

/* ---------- Ayuda: manuales del producto ---------- */
.doc-item {
    border: 1px solid var(--border); border-radius: 2px;
    background: var(--panel-2); padding: 10px 12px; margin-bottom: 8px;
}
.doc-head { display: flex; align-items: center; gap: 8px; font-weight: 700; font-size: .86rem; }
.doc-ico { font-size: 1.05rem; }
.doc-title { flex: 1; }
.doc-desc { color: var(--muted); font-size: .78rem; margin: 4px 0 8px; }
.doc-item .actions { display: flex; gap: 6px; }
.doc-item a.btn { text-decoration: none; display: inline-block; }

/* ---------- Diálogos de la aplicación (reemplazan alert/confirm/prompt) ---------- */
.dlg-box { max-height: 88vh; }
.dlg-head {
    display: flex; align-items: center; gap: 9px;
    padding: 11px 14px; border-bottom: 1px solid var(--border); background: var(--panel-2);
}
.dlg-ico { font-size: 1.05rem; }
.dlg-head h3 { margin: 0; font-size: .92rem; font-weight: 700; flex: 1; }
.dlg-x { padding: 2px 8px; font-size: .72rem; }
.dlg-body { padding: 14px; overflow-y: auto; font-size: .84rem; line-height: 1.55; }
.dlg-msg { margin: 0; }
.dlg-body label {
    display: block; font-size: .72rem; font-weight: 700; color: var(--muted);
    text-transform: uppercase; letter-spacing: .5px; margin: 12px 0 4px;
}
.dlg-body input {
    width: 100%; background: var(--panel-2); color: var(--text);
    border: 1px solid var(--border); border-radius: 2px;
    padding: 8px 10px; font-size: .85rem; font-family: Consolas, monospace;
}
.dlg-body input:focus { outline: none; border-color: var(--accent); }
.dlg-foot {
    display: flex; justify-content: flex-end; gap: 8px;
    padding: 10px 14px; border-top: 1px solid var(--border); background: var(--panel-2);
}
/* ---------- Paneles de conector (socket, GraphQL, gRPC, WebSocket, colas) ---------- */
.s-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 0 10px; }
.s-checks { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 4px; }
.s-check {
    display: flex; align-items: center; gap: 6px;
    font-size: .8rem; font-weight: 600; color: var(--text);
    text-transform: none; letter-spacing: 0; margin: 8px 0 0;
}
.s-check input { width: auto; }
.sk-salida {
    border: 1px solid var(--border); border-left: 3px solid #9aa0a6;
    background: var(--panel-2); padding: 7px 10px; margin-top: 4px;
}
.sk-campo { display: flex; gap: 8px; align-items: baseline; font-size: .76rem; padding: 2px 0; }
.sk-campo code { color: var(--accent); white-space: nowrap; }
.sk-campo span { color: var(--muted); }

.dlg-lista { margin: 8px 0; padding-left: 20px; }
.dlg-lista li { margin: 3px 0; }
.dlg-nota { color: var(--muted); font-size: .78rem; margin: 8px 0 0; }
.dlg-warn { color: var(--yellow); }

/* ---------- Editor del contrato de una conexión ---------- */
.link-box { width: min(720px, 96vw); max-height: 90vh; }
.link-box .dlg-head h3 { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.lk-fila {
    border: 1px solid var(--border); border-left: 3px solid var(--accent);
    background: var(--panel-2); padding: 10px 12px; margin-bottom: 8px;
}
.lk-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 12px; }
.lk-fila label {
    display: block; font-size: .68rem; font-weight: 700; color: var(--muted);
    text-transform: uppercase; letter-spacing: .4px; margin: 6px 0 3px;
}
.lk-fila input, .lk-fila select {
    width: 100%; background: var(--panel); color: var(--text);
    border: 1px solid var(--border); border-radius: 2px;
    padding: 6px 8px; font-size: .8rem; font-family: Consolas, monospace;
}
.lk-fila input:focus, .lk-fila select:focus { outline: none; border-color: var(--accent); }
.lk-pie {
    display: flex; align-items: center; gap: 8px;
    margin-top: 9px; padding-top: 7px; border-top: 1px dashed var(--border);
}
.lk-vista { flex: 1; font-size: .76rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lk-vista code { color: var(--accent); }
.lk-ok { color: var(--green); font-weight: 700; }
.lk-err { color: var(--red); }
.lk-warn { color: var(--yellow); }
.lk-pend { color: var(--muted); font-style: italic; }
.lk-quitar { padding: 2px 8px; font-size: .72rem; }

/* ---------- Acerca de ---------- */
.modal-back {
    position: fixed; inset: 0; z-index: 500;
    background: rgba(0,0,0,.55); display: flex; align-items: center; justify-content: center;
}
.modal-box {
    background: var(--panel); border: 1px solid var(--border); border-radius: 2px;
    box-shadow: 0 18px 50px rgba(0,0,0,.5); display: flex; flex-direction: column;
}
.about-box { width: min(620px, 94vw); max-height: 88vh; }
.about-head {
    display: flex; align-items: center; gap: 14px;
    padding: 16px 18px; border-bottom: 1px solid var(--border);
    background: #001f3e; color: #fff; border-radius: 1px 1px 0 0;
}
.about-logo { width: 60px; height: 60px; border-radius: 12px; flex: none; }
.about-head h2 { margin: 0; font-size: 1.08rem; color: #fff; }
.about-claim { margin: 2px 0 0; font-size: .78rem; color: #07b6ab; }
.about-x {
    margin-left: auto; align-self: flex-start;
    background: transparent; border-color: #ffffff33; color: #fff;
}
.about-x:hover { background: #ffffff1a; border-color: #07b6ab; }
.about-body { padding: 14px 18px; overflow-y: auto; font-size: .82rem; line-height: 1.55; }
.about-body h3 {
    font-size: .74rem; text-transform: uppercase; letter-spacing: .5px;
    color: var(--muted); margin: 16px 0 8px;
}
.about-comps { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 6px; }
.about-comp {
    display: grid; grid-template-columns: 20px 1fr; grid-template-rows: auto auto;
    column-gap: 8px; align-items: center;
    border: 1px solid var(--border); border-left: 3px solid #07b6ab;
    background: var(--panel-2); padding: 7px 10px;
}
.about-comp-ico { grid-row: span 2; font-size: 1rem; }
.about-comp-name { font-weight: 700; font-size: .8rem; }
.about-comp-det { color: var(--muted); font-size: .74rem; }
.about-docs { display: flex; flex-wrap: wrap; gap: 6px; }
.about-docs a {
    color: var(--accent); text-decoration: none; font-size: .78rem;
    border: 1px solid var(--border); background: var(--panel-2); padding: 4px 9px; border-radius: 2px;
}
.about-docs a:hover { border-color: var(--accent); }
.about-legal { color: var(--muted); font-size: .72rem; margin-top: 16px; }
.about-foot {
    display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
    padding: 10px 18px; border-top: 1px solid var(--border); background: var(--panel-2);
}
.about-ver { font-size: .76rem; color: var(--muted); }
.about-upd { font-size: .76rem; margin-left: auto; }
.upd-ok { color: var(--green); }
.upd-new { color: var(--yellow); }
.upd-err { color: var(--red); }
.upd-check { color: var(--muted); }
/* ---------- Asistente de atributos y valores ({{...}} en cualquier campo) ---------- */
#ctx-ac {
    position: fixed; z-index: 5000; display: none;
    max-height: 280px; overflow-y: auto;
    background: var(--panel); border: 1px solid var(--accent); border-radius: 2px;
    box-shadow: 0 8px 24px #00000088;
}
#ctx-ac .ac-item {
    display: flex; gap: 10px; align-items: baseline; justify-content: space-between;
    padding: 4px 8px; cursor: pointer; border-bottom: 1px solid var(--border);
}
#ctx-ac .ac-item code {
    font-family: Consolas, monospace; font-size: .76rem; color: var(--yellow);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
#ctx-ac .ac-item span {
    color: var(--muted); font-size: .7rem; max-width: 45%;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
#ctx-ac .ac-item.sel, #ctx-ac .ac-item:hover { background: var(--panel-2); }
#ctx-ac .ac-item.sel code { color: var(--accent); }
#ctx-ac .ac-pie {
    position: sticky; bottom: 0; padding: 3px 8px;
    background: var(--panel-2); color: var(--muted); font-size: .68rem;
    border-top: 1px solid var(--border);
}

/* ---------- Listas de la respuesta (arreglos con varios elementos) ---------- */
.lista-box {
    border: 1px solid var(--border); border-left: 3px solid var(--accent);
    border-radius: 2px; background: var(--panel-2); margin: 6px 0; padding: 4px 6px 6px;
}
.lista-head {
    display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
    font-size: .74rem; font-weight: 700; color: var(--text); padding: 2px 2px 4px;
}
.lista-path { font-family: Consolas, monospace; }
.lista-acciones { margin-left: auto; display: flex; gap: 4px; }
.lista-acciones .btn { padding: 1px 6px; font-size: .68rem; }
.lista-item { display: flex; gap: 6px; align-items: flex-start; padding: 2px 0; }
.lista-idx {
    flex: 0 0 auto; min-width: 26px; text-align: center;
    font-family: Consolas, monospace; font-size: .7rem; font-weight: 700;
    color: var(--accent); background: var(--panel); border: 1px solid var(--border);
    border-radius: 2px; padding: 2px 4px; margin-top: 2px;
}
.lista-campos { flex: 1 1 auto; min-width: 0; }
.lista-mas { color: var(--muted); font-size: .7rem; padding: 3px 2px 1px; }
.lista-mas code { font-size: .68rem; }

/* ---------- Visor RAW: pestañas de request y respuesta ---------- */
#raw-head .raw-tabs { display: flex; gap: 4px; margin-left: 10px; }
#raw-head .raw-tab.active { border-color: var(--accent); color: var(--accent); }

/* Contrato de entrada del flujo: nombre de la variable a la izquierda */
.hdr-row .fe-k {
    flex: 0 0 42%; background: var(--panel-2); color: var(--muted);
    font-family: Consolas, monospace; font-size: .78rem;
}

/* Desplegable con los atributos que el nodo no expone */
details.attrs-todos { margin: 6px 0 2px; }
details.attrs-todos > summary {
    cursor: pointer; font-size: .74rem; color: var(--muted);
    padding: 3px 4px; border: 1px dashed var(--border); border-radius: 2px;
}
details.attrs-todos > summary:hover { color: var(--text); border-color: var(--accent); }
details.attrs-todos[open] > summary { margin-bottom: 4px; }

/* Contratos publicados de un servicio */
.ct-box {
    margin-top: 8px; border: 1px solid var(--border); border-radius: 2px;
    background: var(--panel-2); padding: 6px 8px;
}
.ct-title { font-size: .74rem; font-weight: 700; color: var(--text); margin-bottom: 4px; }
.ct-row { padding: 5px 0; border-top: 1px solid var(--border); }
.ct-row:first-of-type { border-top: 0; }
.ct-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.ct-name { font-size: .76rem; font-weight: 700; }
.ct-url { width: 100%; font-family: Consolas, monospace; font-size: .72rem; margin-top: 3px; }
.ct-row .actions .btn { padding: 2px 8px; font-size: .7rem; }

/* Atributos que un nodo toma de otro y anexa a su respuesta */
.lv-row.row-externo > label { color: var(--accent); }

/* Asistente de la consola: pegar un request crudo y crear el nodo */
#asistente { padding: 8px 10px; overflow-y: auto; }
#asistente #as-raw { min-height: 120px; }
#asistente .req-box { max-width: 900px; }

/* El pie de la lista es informativo: no debe robar clics del campo de abajo */
#ctx-ac .ac-pie { pointer-events: none; }

/* Zona para soltar la grabación HAR del navegador */
#as-har {
    margin-top: 8px; padding: 12px; text-align: center; cursor: pointer;
    border: 2px dashed var(--border); border-radius: 3px;
    color: var(--muted); font-size: .78rem; background: var(--panel-2);
}
#as-har:hover, #as-har.arrastrando { border-color: var(--accent); color: var(--text); }

/* Vista página del RAW: el HTML de la respuesta renderizado (iframe sin scripts) */
#raw-web-frame {
    border: 0; background: #fff; width: 100%;
    flex: 1 1 auto; min-height: 55vh; border-radius: 0 0 2px 2px;
}
#raw-web-frame.hidden { display: none; }
#raw-head #raw-web.active { border-color: var(--accent); color: var(--accent); }

/* Diálogo de verificación humana del captcha */
.cap-var { border: 1px solid var(--border); border-radius: 3px; padding: 8px; margin-bottom: 8px; background: var(--panel-2); }
.cap-var > input, .cap-var > select, .cap-var > textarea { width: 100%; margin: 3px 0; }
.cap-widget { margin: 6px 0; min-height: 0; }


.cap-var .cap-token { font-family: Consolas, monospace; font-size: .74rem; }

/* Control por IA (MCP): botón activo y chip de estado en vivo */
#btn-mcp.active::after { content: ' ●'; color: var(--green); }
.ab-flex { flex: 1 1 auto; }
#mcp-chip {
    background: var(--green); color: #fff; border-color: var(--green); font-weight: 700;
    animation: mcpPulso 1.6s ease-in-out infinite;
}
#mcp-chip.hidden { display: none; }
@keyframes mcpPulso { 0%,100% { box-shadow: 0 0 0 0 rgba(70,190,110,.6); } 50% { box-shadow: 0 0 0 6px rgba(70,190,110,0); } }

/* Panel MCP: tokens */
.mcp-tok { border: 1px solid var(--border); border-radius: 3px; padding: 6px 8px; margin-bottom: 6px; background: var(--panel-2); }
.mcp-tok-top { font-size: .8rem; margin-bottom: 4px; }
.mcp-tok .lv-row input { font-family: Consolas, monospace; font-size: .72rem; }
#mcp-url { font-family: Consolas, monospace; font-size: .74rem; }
#mcp-ejemplo { white-space: pre; overflow-x: auto; }

/* Vista en vivo de acciones recibidas por MCP */
#mcpview { padding: 6px 10px; overflow-y: auto; }
.ctab.nuevo { position: relative; }
.ctab.nuevo::after { content: '●'; color: var(--green); margin-left: 4px; animation: mcpPulso 1.2s infinite; }
.mcp-head { display: flex; align-items: center; gap: 8px; padding: 2px 0 6px; font-size: .76rem; }
.mcp-live { color: var(--green); font-weight: 700; }
.mcp-off { color: var(--muted); }
.mcp-ev { border: 1px solid var(--border); border-left: 3px solid var(--muted); border-radius: 2px; margin-bottom: 6px; padding: 5px 8px; background: var(--panel-2); }
.mcp-ev-ejecutando { border-left-color: var(--yellow); }
.mcp-ev-ok { border-left-color: var(--green); }
.mcp-ev-error { border-left-color: var(--red); }
.mcp-ev-top { display: flex; align-items: center; gap: 8px; font-size: .76rem; flex-wrap: wrap; }
.mcp-ev-hora { color: var(--muted); font-family: Consolas, monospace; font-size: .7rem; }
.mcp-ev-ia { color: var(--accent); font-weight: 700; }
.mcp-ev-tool { font-family: Consolas, monospace; font-weight: 700; }
.mcp-ev-estado { margin-left: auto; color: var(--muted); font-size: .72rem; }
.mcp-ev-args, .mcp-ev-res { margin: 4px 0 0; padding: 5px 7px; background: var(--panel); border: 1px solid var(--border); border-radius: 2px; font-family: Consolas, monospace; font-size: .72rem; white-space: pre-wrap; word-break: break-word; max-height: 180px; overflow: auto; }

/* Nodo Dummy (endpoint simulado): borde punteado violeta */
.node.mock .shape { border-radius: 10px; outline: 2px dotted #b58cf5; outline-offset: -3px; }
.node.mock.selected .shape { outline-color: var(--accent); }

/* Editor paramétrico del nodo Dummy: fila = atributo + valor + quitar */
.dm-fila { display: grid; grid-template-columns: 1fr 1.4fr auto; gap: 4px; margin-bottom: 4px; align-items: center; }
.dm-fila .dm-k { margin: 0; }
.dm-fila .code-editor { margin: 0; }
.dm-fila .dm-del { padding: 4px 8px; line-height: 1; }
.dm-preview { margin: 2px 0 0; padding: 6px 8px; background: var(--panel); border: 1px solid var(--border); border-radius: 2px; font-family: Consolas, monospace; font-size: .74rem; white-space: pre-wrap; word-break: break-word; max-height: 220px; overflow: auto; }

/* Nodo de base de datos (tambor): el cilindro clásico, con la tapa elíptica
   dibujada por radios asimétricos y una línea que insinúa el borde de la tapa */
.node.tambor .shape {
    border-radius: 50% 50% 50% 50% / 14% 14% 14% 14%;
    outline: 2px solid #e8a33d66; outline-offset: -3px;
    position: relative;
}
.node.tambor .shape::before {
    content: ""; position: absolute; left: 4px; right: 4px; top: 9px; height: 10px;
    border-bottom: 2px solid #e8a33d55; border-radius: 50%;
    pointer-events: none;
}
.node.tambor.selected .shape { outline-color: var(--accent); }

/* Nodo Timer (reloj) y sello de última ejecución correcta */
.node.reloj .shape { border-radius: 999px; outline: 2px dashed var(--accent); outline-offset: -3px; }
.node.reloj.timer-on .shape { outline-color: var(--green); animation: mcpPulso 2s infinite; }
.ultima-ok { font-size: .74rem; color: var(--green); margin: 0 0 6px; }
.ultima-ok.none { color: var(--muted); }
#tm-estado { margin-top: 6px; }

/* Ejecutar / Detener flujo */
.ab-btn.danger { background: var(--red); border-color: var(--red); color: #fff; }
.ab-btn.danger:hover { background: #a83232; border-color: #a83232; }
.ab-btn.danger.hidden { display: none; }
#btn-flow.activo { outline: 2px solid var(--green); outline-offset: -2px; }

/* Respuesta esperada de un nodo SOAP importado de un WSDL */
.wsdl-resp { margin: 8px 0; border: 1px solid var(--border); border-radius: 6px; background: var(--panel); }
.wsdl-resp > summary { cursor: pointer; padding: 7px 10px; font-weight: 600; font-size: 12px; color: var(--text); }
.wsdl-resp[open] > summary { border-bottom: 1px solid var(--border); }
.wsdl-resp pre { margin: 0; padding: 8px 10px; max-height: 220px; overflow: auto; font-family: var(--mono, monospace); font-size: 11px; line-height: 1.45; color: var(--text); white-space: pre; }
.wsdl-resp .help { padding: 6px 10px 9px; margin: 0; }

/* ============================================================================
   PERFILES VISUALES — lenguaje del Ext JS Kitchen Sink reimplementado en CSS
   propio (no se usa el framework: es comercial). Los valores salen de medir los
   temas reales en examples.sencha.com/extjs/8.0.0/examples/kitchensink.

   Dos perfiles elegibles, en el atributo data-skin de <html>:
     triton       (por defecto) escritorio, compacto, barra de titulo azul
     crisp-touch  tactil, tipografia mas grande, titulo azul sobre gris claro

   Va al final a proposito: las variables CSS se resuelven al usarse, asi que
   redefinir los tokens aca los cambia en las ~360 reglas de arriba sin tocarlas.
   Las 10 geometrias de nodo (circulo, capsula, reloj...) NO se aplanan: ahi el
   border-radius es la forma del nodo, no decoracion.
============================================================================ */

/* ---------- PERFIL TRITON (por defecto) ---------- */
:root,
:root[data-skin="triton"] {
    --radio: 0px;
    --fs-base: 13px;
    --fs-titulo: 16px;
    --alto-control: 30px;
    --alto-fila: 32px;
    --alto-cabecera: 44px;
    --peso-titulo: 400;
    --fuente: 'Open Sans', 'Segoe UI', 'Helvetica Neue', helvetica, arial, sans-serif;

    /* Dos azules A PROPÓSITO (auditoría AA ago-2026): la BANDA de cabecera conserva
       el #5fa2dd del Kitchen Sink (es la firma visual, título 16px), pero el azul de
       INTERACCIÓN (texto de tabs activas, botones primarios, selección, links) es el
       Triton profundo #3873ad: blanco sobre él da 5.0:1 (AA ✓); sobre #5fa2dd daba
       2.39:1 y los botones se leían mal. */
    --accent: #3873ad;
    --accent-borde: #30669c;
    --accent-btn: #3873ad;
    --accent-texto: #ffffff;
    --cab-bg: #5fa2dd;      /* Triton: barra de titulo azul llena (firma visual) */
    --cab-texto: #ffffff;
}

/* ---------- PERFIL CRISP TOUCH ---------- */
:root[data-skin="crisp-touch"] {
    --radio: 3px;
    --fs-base: 15px;
    --fs-titulo: 17px;
    --alto-control: 34px;
    --alto-fila: 36px;
    --alto-cabecera: 44px;
    --peso-titulo: 300;
    --fuente: helvetica, arial, verdana, sans-serif;

    /* #157fcc daba 3.9:1 con blanco (y el botón #3892d4, 2.9): se profundiza un
       punto para AA manteniendo el carácter Crisp (auditoría ago-2026). */
    --accent: #1272b8;
    --accent-borde: #106aac;
    --accent-btn: #1272b8;
    --accent-texto: #ffffff;
    --cab-bg: #f5f5f5;      /* Crisp: cabecera gris clara con titulo azul */
    --cab-texto: #1272b8;
}

/* ---------- Superficies: tema claro ---------- */
:root,
:root[data-theme="light"] {
    --bg: #ececec;
    --panel: #e9e9e9;
    --panel-2: #ffffff;
    --border: #d0d0d0;
    --text: #404040;
    /* Estados oscurecidos para AA sobre blanco (auditoría ago-2026): los valores
       anteriores (#3a9d5d/#d64a4a/#c9922b/#707070) daban 2.5–4.2:1 como TEXTO
       ("OK", "ERROR", contadores). Estos dan ≥4.5:1 sin cambiar la familia. */
    --muted: #666666;
    --green: #2f7d4f;
    --red: #c23b3b;
    --yellow: #946f00;
    --purple: #7a4fd0;
    --grid-major: #dcdcdc;
    --grid-minor: #e4e4e4;
    --node-bg1: #ffffff;
    --node-bg2: #f2f2f2;
    --console-bg: #ffffff;
    --pre-bg: #f7f7f7;
    --label-bg: rgba(255, 255, 255, .94);
    --hl-key: #1f6fb2;
    --hl-str: #2e7d32;
    --hl-num: #b35900;
    --hl-tag: #1f6fb2;
    --mono: Consolas, 'Courier New', monospace;
}
:root[data-skin="crisp-touch"],
:root[data-skin="crisp-touch"][data-theme="light"] {
    --bg: #cfcfcf;          /* Crisp usa un gris de fondo mas marcado */
    --panel: #e8e8e8;
    --border: #cfcfcf;
    --text: #000000;
    --muted: #666666;
}

/* ---------- Superficies: tema oscuro (ambos perfiles) ---------- */
:root[data-theme="dark"] {
    --bg: #2b2b2b;
    --panel: #333333;
    --panel-2: #3c3c3c;
    --border: #4a4a4a;
    --text: #e0e0e0;
    --muted: #9a9a9a;
    /* En oscuro la relación se INVIERTE: el azul de interacción tiene que ser
       CLARO para leerse como texto (el #3873ad del perfil claro da 2.2:1 acá).
       El botón primario sí mantiene el fondo azul profundo con texto blanco. */
    --accent: #6db1e8;
    --accent-borde: #5fa2dd;
    --accent-btn: #3873ad;
    --accent-texto: #ffffff;
    --cab-bg: #3873ad;      /* banda más profunda que en claro: #5fa2dd encandila sobre gris oscuro */
    --cab-texto: #ffffff;
    /* Estados aclarados para el fondo oscuro (los del claro, oscurecidos para AA
       sobre blanco, acá quedaban en 2.9–3.0). */
    --green: #52c17a;
    --red: #e06c6c;
    --yellow: #d9a53f;
    --purple: #a98ae8;
    --grid-major: #383838;
    --grid-minor: #313131;
    --node-bg1: #3c3c3c;
    --node-bg2: #333333;
    --console-bg: #262626;
    --pre-bg: #2f2f2f;
    --label-bg: rgba(51, 51, 51, .94);
    --hl-key: #6cb6ff;
    --hl-str: #7ece81;
    --hl-num: #e0a56b;
    --hl-tag: #6cb6ff;
}

/* ---------- Tipografia ----------
   Sin @import ni CDN: si la fuente no esta instalada cae a la siguiente de la
   lista, y la app no depende de ningun recurso externo. */
body { font-family: var(--fuente); font-size: var(--fs-base); font-weight: 400; }

/* ---------- Geometria del chrome (las formas de nodo quedan afuera) ---------- */
.btn, .ab-btn, .fb-btn, .menu-btn, .submenu-btn, .menu-drop, .submenu-drop,
input[type="text"], input[type="password"], input[type="number"], input[type="search"],
select, textarea, .code-editor, .modal-box, .req-box, .res-box, .out-box,
.hdr-row input, .lv-card, .doc-card, .sk-campo, .mcp-card, .cap-box, #ctx-ac,
.tabs button, .console-tabs button, .side-tab, .wsdl-resp, .ivz-grid, .ivz-window {
    border-radius: var(--radio);
}

/* ---------- Botones ---------- */
.btn {
    height: var(--alto-control); padding: 0 12px;
    font-size: calc(var(--fs-base) - 1px); font-weight: 400;
    background: var(--panel-2); color: var(--text);
    border: 1px solid var(--border);
}
.btn:hover { background: #f5f9fd; border-color: var(--accent); }
:root[data-theme="dark"] .btn:hover { background: #45505c; }
.btn.primary {
    background: var(--accent-btn); border-color: var(--accent-borde);
    color: var(--accent-texto); font-weight: 400;
}
/* Hover con color explícito, no filter: brightness() lava el azul sobre fondo
   claro y además desactiva el antialiasing subpixel del texto en Chrome. */
.btn.primary:hover { background: var(--accent-borde); }
.btn.danger { background: var(--red); border-color: var(--red); color: #fff; }
.btn.danger:hover { background: #a83232; border-color: #a83232; }

/* ---------- Campos ---------- */
input[type="text"], input[type="password"], input[type="number"], input[type="search"], select {
    min-height: var(--alto-control); padding: 4px 10px;
    background: var(--panel-2); color: var(--text);
    border: 1px solid var(--border); font-size: var(--fs-base); font-weight: 400;
}
textarea { padding: 6px 10px; font-size: var(--fs-base); }
input:focus, select:focus, textarea:focus {
    outline: none; border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent);
}
label { font-size: var(--fs-base); font-weight: 400; color: var(--text); }

/* ---------- Cabecera de panel y de dialogo ---------- */
.ivz-panel-header, #props h2, .modal-box > h2 {
    display: flex; align-items: center; gap: 8px;
    min-height: var(--alto-cabecera); padding: 10px 16px; margin: 0 0 10px;
    background: var(--cab-bg); color: var(--cab-texto);
    font-size: var(--fs-titulo); font-weight: var(--peso-titulo); border: 0;
}
/* En Crisp la cabecera es clara: necesita una linea que la separe del cuerpo */
:root[data-skin="crisp-touch"] .ivz-panel-header,
:root[data-skin="crisp-touch"] #props h2,
:root[data-skin="crisp-touch"] .modal-box > h2 { border-bottom: 1px solid var(--border); }

.modal-box {
    background: var(--panel-2); border: 1px solid var(--border);
    box-shadow: 0 10px 34px rgba(0, 0, 0, .28);
}
.modal-box > h2 { margin: -1px -1px 12px; }

/* ---------- Grilla de datos ---------- */
.ivz-grid { width: 100%; border-collapse: collapse; background: var(--panel-2); font-size: var(--fs-base); }
.ivz-grid thead th {
    height: var(--alto-fila); padding: 0 10px; text-align: left;
    background: var(--panel-2); color: var(--muted); font-weight: 600;
    border-bottom: 1px solid var(--border); border-right: 1px solid var(--border); white-space: nowrap;
}
.ivz-grid thead th:last-child { border-right: 0; }
.ivz-grid tbody td { height: var(--alto-fila); padding: 0 10px; border-bottom: 1px solid var(--border); }
.ivz-grid tbody tr:nth-child(even) { background: #fafafa; }
.ivz-grid tbody tr:hover { background: #eef6fd; }
.ivz-grid tbody tr.sel { background: var(--accent); color: var(--accent-texto); }
:root[data-theme="dark"] .ivz-grid tbody tr:nth-child(even) { background: #383838; }
:root[data-theme="dark"] .ivz-grid tbody tr:hover { background: #3f4a55; }

/* ---------- Pestanas ---------- */
.tabs button, .console-tabs button, .side-tab {
    height: var(--alto-control); padding: 0 14px;
    font-size: var(--fs-base); font-weight: 400;
    background: transparent; color: var(--muted); border: 0; border-bottom: 2px solid transparent;
}
.tabs button.active, .console-tabs button.active, .side-tab.active {
    color: var(--accent); border-bottom-color: var(--accent); background: transparent;
}

/* ---------- Barras ---------- */
#toolbar, #actionbar { background: var(--panel-2); border-bottom: 1px solid var(--border); }
#actionbar { padding: 6px 8px; }
.ab-btn { height: var(--alto-control); padding: 0 12px; font-size: calc(var(--fs-base) - 1px); font-weight: 400; }
.ab-btn.primary { background: var(--accent-btn); border-color: var(--accent-borde); color: var(--accent-texto); }
#statusbar { background: var(--panel-2); border-top: 1px solid var(--border); color: var(--muted); font-size: calc(var(--fs-base) - 1px); }

/* ============================================================================
   SOPORTE TACTIL
   `pointer: coarse` = el dispositivo apunta con el dedo. Se agrandan los blancos
   a 44px (minimo recomendado de accesibilidad) sin importar el perfil elegido.
============================================================================ */
@media (pointer: coarse) {
    /* Los selectores repiten [data-skin] a proposito: una media query NO aporta
       especificidad, asi que un ':root' pelado perderia contra ':root[data-skin=...]'
       y los blancos nunca se agrandarian. */
    :root, :root[data-skin="triton"], :root[data-skin="crisp-touch"] {
        --alto-control: 44px;
        --alto-fila: 44px;
        --caja-control: 24px;
    }
    .menu-btn, .submenu-btn { min-height: 44px; padding: 0 14px; }
    .btn, .ab-btn, .fb-btn { padding: 0 16px; }
    .menu-drop button, .submenu-drop button { min-height: 44px; padding: 10px 14px; }
    .tabs button, .console-tabs button, .side-tab { min-height: 44px; }
    /* los puertos de conexion del nodo son diminutos para el dedo */
    .port { width: 20px; height: 20px; }
    /* el lienzo maneja el gesto por JS: el navegador no debe robarse el arrastre */
    #canvas-wrap { touch-action: none; }
    .node { touch-action: none; }
    /* sin hover real: que no queden estados pegados */
    .btn:hover, .ab-btn:hover { filter: none; }
}

/* Pantallas chicas: el panel lateral y la consola pasan a ocupar el ancho */
@media (max-width: 820px) {
    body {
        grid-template-columns: 1fr;
        grid-template-areas: "toolbar" "actionbar" "canvas" "console" "status";
    }
    #sidebar { position: fixed; inset: auto 0 0 0; height: 55vh; z-index: 60;
               border-top: 1px solid var(--border); transform: translateY(100%);
               transition: transform .18s ease; }
    #sidebar.abierto { transform: translateY(0); }
    #toolbar { flex-wrap: wrap; }
    /* colapsables también en pantalla chica: la consola queda en su fila de pestañas
       y el panel (hoja inferior) reducido a la tira de pestañas */
    body.consola-colapsada { grid-template-rows: auto auto 1fr 35px 26px; }
    body.panel-colapsado #sidebar { height: auto; }
}

/* ---------------------------------------------------------------------------
   Controles de formulario y grilla — medidos del perfil crisp-touch
   (#form-grid del Kitchen Sink): fila seleccionada #c2ddf2, radio 22px,
   etiquetas #666 peso 300, cuerpo de panel #e9e9e9, fieldset con borde 1px.
--------------------------------------------------------------------------- */
:root, :root[data-skin="triton"] { --fila-sel: #c2ddf2; --fila-sel-texto: #1a1a1a; --caja-control: 18px; }
:root[data-skin="crisp-touch"]   { --fila-sel: #c2ddf2; --fila-sel-texto: #000000; --caja-control: 22px; }
:root[data-theme="dark"]         { --fila-sel: #2f5f8a; --fila-sel-texto: #ffffff; }

/* Casillas y radios: cuadro grande y con el azul del perfil */
input[type="checkbox"], input[type="radio"] {
    width: var(--caja-control); height: var(--caja-control);
    accent-color: var(--accent); cursor: pointer; vertical-align: middle; margin: 0 6px 0 0;
}
input[type="radio"] { border-radius: 50%; }   /* el radio SI es redondo */
label.check, .campo-check { display: flex; align-items: center; gap: 8px; min-height: var(--alto-control); }

/* Etiquetas al estilo Ext: peso liviano y color atenuado */
label, .x-label, .form-label { color: var(--muted); font-weight: 300; }
.req-box-title, .ivz-panel-header { font-weight: var(--peso-titulo); }

/* Fila seleccionada de la grilla */
.ivz-grid tbody tr.sel, .ivz-grid tbody tr[aria-selected="true"] {
    background: var(--fila-sel); color: var(--fila-sel-texto);
}

/* Agrupador tipo fieldset */
.ivz-fieldset, .req-box, .res-box, .out-box {
    border: 1px solid var(--border); padding: 8px 10px; background: transparent;
}
.ivz-fieldset > legend { padding: 0 6px; color: var(--muted); font-size: var(--fs-base); font-weight: 300; }

/* Barra inferior de acciones de un dialogo */
.modal-box .actions, .ivz-footer {
    display: flex; gap: 8px; align-items: center;
    min-height: 44px; padding: 6px; background: #e7e7e7; border-top: 1px solid var(--border);
}
:root[data-theme="dark"] .modal-box .actions, :root[data-theme="dark"] .ivz-footer { background: #2f2f2f; }

/* El submenu tambien se abre con un toque (en tactil no hay hover) */
.submenu.abierto > .submenu-drop { display: block; }

/* Cierre tactil: va al final para ganarle al bloque de controles de arriba */
@media (pointer: coarse) {
    :root, :root[data-skin="triton"], :root[data-skin="crisp-touch"] { --caja-control: 24px; }
}

/* ---------------------------------------------------------------------------
   BARRA DE COMANDOS estilo Visual Studio
   Controles planos que solo muestran su chrome al pasar por encima, separadores
   finos, grip de arrastre y densidad compacta. Los COLORES NO son los de VS:
   salen de los tokens del perfil activo (Triton / Crisp, claro / oscuro), asi
   que la barra cambia sola cuando se cambia de perfil o de tema.
--------------------------------------------------------------------------- */
:root, :root[data-skin="triton"] { --alto-barra: 28px; }
:root[data-skin="crisp-touch"]   { --alto-barra: 32px; }
@media (pointer: coarse) {
    :root, :root[data-skin="triton"], :root[data-skin="crisp-touch"] { --alto-barra: 44px; }
}

#toolbar, #actionbar { background: var(--panel-2); }
#actionbar {
    gap: 1px; padding: 3px 6px;
    border-bottom: 1px solid var(--border);
}

/* Grip: las dos columnas de puntos con las que se arrastra una barra en VS */
.ab-grip {
    width: 10px; align-self: stretch; margin: 2px 4px 2px 0; flex: none; cursor: grab;
    background-image: radial-gradient(var(--muted) 1px, transparent 1px);
    background-size: 3px 3px; background-position: 2px 3px; background-repeat: repeat-y;
    opacity: .55;
}
.ab-grip:active { cursor: grabbing; }

/* Botones planos: sin fondo ni borde en reposo, como los de la barra de VS */
.ab-btn {
    display: inline-flex; align-items: center; gap: 6px;
    height: var(--alto-barra); padding: 0 9px;
    background: transparent; border: 1px solid transparent; color: var(--text);
    font-weight: 400; font-size: calc(var(--fs-base) - 1px);
    white-space: nowrap;
}
/* La primera declaracion es el respaldo para navegadores sin color-mix */
.ab-btn:hover {
    background: var(--panel);
    background: color-mix(in srgb, var(--accent) 14%, transparent);
    border-color: var(--border);
    border-color: color-mix(in srgb, var(--accent) 45%, transparent);
}
.ab-btn:active {
    background: var(--panel);
    background: color-mix(in srgb, var(--accent) 26%, transparent);
}
.ab-btn:focus-visible { outline: 1px solid var(--accent); outline-offset: -1px; }

/* La accion principal si va rellena, como el boton verde de ejecutar de VS */
.ab-btn.primary {
    background: var(--accent-btn); border-color: var(--accent-borde); color: var(--accent-texto);
}
.ab-btn.primary:hover { background: var(--accent-borde, var(--accent)); }
.ab-btn.danger { background: var(--red); border-color: var(--red); color: #fff; }
.ab-btn:disabled { opacity: .45; }

/* Separador vertical fino entre grupos de comandos */
.ab-sep {
    width: 1px; height: calc(var(--alto-barra) - 8px);
    background: var(--border); margin: 0 5px; flex: none;
}

/* Barra de menus: texto plano, el realce aparece al pasar o al abrir */
#menubar { gap: 0; }
.menu-btn {
    height: var(--alto-barra); padding: 0 10px;
    background: transparent; border: 1px solid transparent; color: var(--text);
    font-size: var(--fs-base); font-weight: 400;
}
.menu-btn:hover {
    background: var(--panel);
    background: color-mix(in srgb, var(--accent) 14%, transparent);
}
.menu.open > .menu-btn {
    background: var(--panel);
    background: color-mix(in srgb, var(--accent) 20%, transparent);
    border-color: var(--border);
    border-color: color-mix(in srgb, var(--accent) 45%, transparent);
}

/* Menu desplegable: item completo resaltado con el acento, como en VS */
.menu-drop, .submenu-drop {
    background: var(--panel-2); border: 1px solid var(--border);
    box-shadow: 0 6px 18px rgba(0, 0, 0, .22);
}
.menu-drop button, .submenu-drop button { font-weight: 400; }
.menu-drop button:hover, .submenu-drop button:hover {
    background: var(--accent); color: var(--accent-texto);
}
.menu-sep { height: 1px; background: var(--border); margin: 4px 6px; }

/* ---------------------------------------------------------------------------
   CUADRO DE HERRAMIENTAS estilo Visual Studio
   Ventana acoplable con barra de titulo (grip + fijar + cerrar), buscador,
   categorias plegables y filas de item con icono a la izquierda.
   Los COLORES salen de los tokens del perfil activo: cambia solo al cambiar
   de perfil (Triton / Crisp) o de tema (claro / oscuro).
--------------------------------------------------------------------------- */
#floatbar {
    background: var(--panel-2);
    border: 1px solid var(--border);
    padding: 0;
    gap: 0;
    font-size: calc(var(--fs-base) - 1px);
}

/* Barra de titulo: linea de acento arriba (ventana activa), grip punteado y botones */
#floatbar-grip {
    display: flex; align-items: center; gap: 6px;
    height: var(--alto-barra); padding: 0 6px;
    background: var(--panel);
    border-bottom: 1px solid var(--border);
    border-top: 2px solid var(--accent);
    color: var(--text); font-weight: 600; font-size: calc(var(--fs-base) - 1px);
    cursor: grab; user-select: none;
}
#floatbar-grip:active { cursor: grabbing; }
/* la tira de puntos que en VS separa el titulo de los botones */
#floatbar-grip::after {
    content: ''; flex: 1; height: 7px; margin: 0 4px;
    background-image: radial-gradient(var(--muted) .5px, transparent .5px);
    background-size: 3px 3px; opacity: .5;
}
.fb-win-btn {
    width: 20px; height: 20px; flex: none; display: grid; place-items: center;
    background: transparent; border: 1px solid transparent; color: var(--muted);
    font-size: 11px; line-height: 1; cursor: pointer; padding: 0;
}
.fb-win-btn:hover {
    color: var(--text);
    background: var(--panel-2);
    background: color-mix(in srgb, var(--accent) 18%, transparent);
}

/* Buscador del cuadro de herramientas */
.fb-buscar { position: relative; padding: 4px 5px; border-bottom: 1px solid var(--border); }
.fb-buscar input {
    width: 100%; min-height: 24px; height: auto;
    padding: 3px 22px 3px 6px;
    background: var(--panel-2); color: var(--text);
    border: 1px solid var(--border); font-size: calc(var(--fs-base) - 1px);
}
.fb-buscar::after {
    content: '🔎'; position: absolute; right: 11px; top: 50%; transform: translateY(-50%);
    font-size: 10px; opacity: .55; pointer-events: none;
}

/* La paleta usa TODO el alto disponible del cuadro: al quitar los comandos del pie
   (1.6.29) el tope viejo de 52vh dejaba una franja muerta abajo que escondía
   herramientas. Dockeado ocupa el alto completo; flotante se limita al viewport. */
#fb-palette { overflow-y: auto; flex: 1 1 auto; min-height: 0; }
#floatbar:not(.docked) #fb-palette { max-height: min(78vh, 720px); }

/* Cabecera de categoria: banda con triangulo, ancho completo */
.fb-cat {
    display: flex; align-items: center; gap: 6px; width: 100%;
    padding: 5px 8px; border: 0; border-bottom: 1px solid var(--border);
    background: var(--panel); color: var(--text);
    font-weight: 600; font-size: calc(var(--fs-base) - 1px); text-align: left; cursor: pointer;
}
.fb-cat:hover {
    background: var(--panel);
    background: color-mix(in srgb, var(--accent) 12%, transparent);
}
.fb-caret { font-size: 9px; width: 9px; flex: none; color: var(--muted); }

/* Filas de item: icono en columna fija + etiqueta, como el Toolbox */
.fb-cat-items .fb-btn, #fb-palette .fb-btn {
    display: flex; align-items: center; gap: 8px; width: 100%;
    min-height: 26px; padding: 3px 8px 3px 20px;
    background: transparent; border: 1px solid transparent; color: var(--text);
    font-weight: 400; font-size: calc(var(--fs-base) - 1px); text-align: left;
}
.fb-cat-items .fb-btn > span:first-child,
#fb-palette .fb-btn > span:first-child { width: 16px; flex: none; text-align: center; }
.fb-cat-items .fb-btn:hover, #fb-palette .fb-btn:hover {
    background: var(--panel);
    background: color-mix(in srgb, var(--accent) 16%, transparent);
    border-color: transparent;
}
.fb-cat-items .fb-btn:active, #fb-palette .fb-btn:active {
    background: var(--accent); color: var(--accent-texto);
}

/* Comandos del pie (fuera de la paleta): planos, como la barra de comandos */
#floatbar > .fb-btn {
    display: flex; align-items: center; gap: 8px; width: 100%;
    min-height: var(--alto-barra); padding: 0 10px;
    background: transparent; border: 1px solid transparent; color: var(--text);
    font-weight: 400; text-align: left;
}
#floatbar > .fb-btn:hover {
    background: var(--panel);
    background: color-mix(in srgb, var(--accent) 16%, transparent);
}
.fb-sep { height: 1px; background: var(--border); margin: 0; }

/* Sin resultados de busqueda */
.fb-vacio { padding: 10px; color: var(--muted); font-size: calc(var(--fs-base) - 1px); }

/* ---------------------------------------------------------------------------
   LOGOS DE SISTEMAS (grupos CRM / ERP / PMS del catálogo)
   Insignia SVG de la marca: en la paleta y submenús como icono del renglón, y
   en el lienzo como distintivo del nodo (esquina superior izquierda). */
.n-logo-svg { display: inline-block; width: 15px; height: 15px; flex: none; }
.n-logo-svg svg { width: 100%; height: 100%; display: block; border-radius: 4px; }
.fb-cat-items .fb-btn > .n-logo-svg,
#fb-palette .fb-btn > .n-logo-svg { width: 16px; height: 16px; }

.node .n-logo {
    position: absolute; top: -9px; left: -9px; width: 22px; height: 22px; z-index: 3;
    filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .35));
    pointer-events: none;
}
.node .n-logo svg { width: 100%; height: 100%; display: block; border-radius: 6px; }
/* Dibujito libre (emoji o texto corto) como insignia del nodo */
.node .n-logo-emoji {
    display: flex; align-items: center; justify-content: center;
    background: var(--panel-2); border: 1px solid var(--border); border-radius: 6px;
    font-size: 13px; line-height: 1; overflow: hidden;
}
/* Dibujito por imagen externa (URL) */
.node .n-logo-img { border-radius: 6px; overflow: hidden; background: var(--panel-2); border: 1px solid var(--border); }
.node .n-logo-img img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Acciones por variable del proyecto en la caja de entrada del nodo */
.io-var-row .btn { flex: none; padding: 1px 7px; font-size: .7rem; white-space: nowrap; }

/* Combo del dibujito: lista DESPLEGABLE con icono y nombre por fila (un select
   nativo no puede dibujar los SVG de los logos dentro de las opciones) */
#p-dibujito-combo { position: relative; }
#p-dibujito-btn {
    display: flex; align-items: center; gap: 8px; width: 100%; padding: 4px 8px;
    background: var(--panel-2); border: 1px solid var(--border); border-radius: 2px;
    color: var(--text); text-align: left; cursor: pointer; font-size: calc(var(--fs-base) - 1px);
}
#p-dibujito-btn .dib-caret { margin-left: auto; color: var(--muted); font-size: .7rem; }
#p-dibujito-menu {
    position: absolute; z-index: 250; left: 0; right: 0; top: calc(100% + 2px);
    max-height: 280px; overflow-y: auto; padding: 3px;
    background: var(--panel); border: 1px solid var(--border); border-radius: 4px;
    box-shadow: 0 10px 26px rgba(0, 0, 0, .4);
}
.dib-grupo {
    padding: 5px 8px 2px; margin-top: 2px; border-top: 1px solid var(--border);
    font-size: .66rem; font-weight: 800; text-transform: uppercase;
    letter-spacing: .4px; color: var(--muted);
}
.dib-item {
    display: flex; align-items: center; gap: 8px; width: 100%; padding: 4px 8px;
    background: transparent; border: 1px solid transparent; border-radius: 3px;
    color: var(--text); text-align: left; cursor: pointer; font-size: calc(var(--fs-base) - 1px);
}
.dib-item:hover { background: color-mix(in srgb, var(--accent) 16%, transparent); }
.dib-item > span:first-child { width: 18px; flex: none; text-align: center; }
.dib-item .n-logo-svg, #p-dibujito-btn .n-logo-svg { width: 17px; height: 17px; flex: none; }

/* ---------------------------------------------------------------------------
   PANTALLA DE INGRESO estilo ventana de Ext JS (plantilla Login del Kitchen Sink)
   Ventana centrada con barra de titulo del color de acento, cuerpo gris con los
   campos, y boton principal de ancho completo. Igual que el resto de la app, los
   colores salen de los tokens del perfil y del tema activos.
--------------------------------------------------------------------------- */
#login-overlay { background: var(--bg); padding: 16px; }

#login-box {
    width: min(380px, 94vw);
    padding: 0;                                  /* el padding va por seccion */
    background: var(--panel-2);
    border: 1px solid var(--border);
    border-radius: var(--radio);
    box-shadow: 0 14px 44px rgba(0, 0, 0, .22);
    overflow: hidden;
}

/* Barra de titulo de la ventana: lleva la marca, como el header azul de Ext */
#login-brand {
    display: flex; align-items: center; gap: 10px;
    min-height: var(--alto-cabecera); margin: 0; padding: 10px 16px;
    background: var(--cab-bg); color: var(--cab-texto);
    font-size: var(--fs-titulo); font-weight: var(--peso-titulo);
}
#login-brand span { color: inherit; font-weight: 600; }
#login-brand .brand-logo { width: 26px; height: 26px; border-radius: var(--radio); flex: none; }
/* En Crisp la cabecera es clara: hace falta el borde para despegarla del cuerpo */
:root[data-skin="crisp-touch"] #login-brand { border-bottom: 1px solid var(--border); }

/* Cuerpo de la ventana */
#login-box > .help,
#login-box label,
#login-box input,
#login-box .btn,
#login-box #login-status { margin-left: 16px; margin-right: 16px; }

#login-box > .help {
    display: block; margin-top: 14px; margin-bottom: 2px;
    color: var(--muted); font-size: var(--fs-base); font-weight: 300;
}

#login-box label {
    display: block; margin: 12px 16px 4px;
    color: var(--muted); font-size: var(--fs-base); font-weight: 300;
    text-transform: none; letter-spacing: normal;      /* Ext no usa versalitas */
}

#login-box input {
    display: block; width: calc(100% - 32px);
    min-height: var(--alto-control); padding: 4px 10px;
    background: var(--panel-2); color: var(--text);
    border: 1px solid var(--border); border-radius: var(--radio);
    font-size: var(--fs-base);
}
#login-box input:focus {
    outline: none; border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent);
}

/* Boton principal de ancho completo, como en la plantilla */
#login-box .btn.primary {
    display: block; width: calc(100% - 32px);
    height: var(--alto-control); margin-top: 18px;
    background: var(--accent-btn); border: 1px solid var(--accent-borde);
    color: var(--accent-texto); font-size: var(--fs-base); font-weight: 400;
}
#login-box .btn.primary:hover { background: var(--accent-borde, var(--accent)); }

/* Pie: franja separada donde aparece el estado del ingreso */
#login-box #login-status {
    display: block; margin: 16px 0 0; padding: 8px 16px;
    min-height: 34px;
    background: var(--panel); border-top: 1px solid var(--border);
    color: var(--muted); font-size: calc(var(--fs-base) - 1px);
}
#login-box #login-status:empty { color: transparent; }

/* ---------------------------------------------------------------------------
   INGRESO EN DOS COLUMNAS: formulario a la izquierda, panel descriptivo del
   producto a la derecha sobre un degradado del color de acento.
   El dibujo es un SVG inline propio: la app no descarga ninguna imagen.
--------------------------------------------------------------------------- */
#login-overlay {
    display: grid;
    grid-template-columns: minmax(340px, 420px) 1fr;   /* form | panel */
    align-items: stretch; justify-content: stretch;
    padding: 0; gap: 0;
}

/* --- Columna izquierda: el formulario ocupa la franja completa --- */
#login-box {
    width: 100%; max-width: none; height: 100%;
    display: flex; flex-direction: column; justify-content: center;
    border: 0; border-right: 1px solid var(--border);
    border-radius: 0; box-shadow: none;
    background: var(--panel-2);
    padding-bottom: 0;
}
#login-brand {
    background: transparent; color: var(--text);
    min-height: auto; padding: 0 32px 4px;
    font-size: calc(var(--fs-titulo) + 4px); font-weight: 600;
}
#login-brand span { color: var(--accent); }
#login-brand .brand-logo { width: 34px; height: 34px; }
:root[data-skin="crisp-touch"] #login-brand { border-bottom: 0; }

#login-box > .help,
#login-box label,
#login-box input,
#login-box .btn,
#login-box #login-status { margin-left: 32px; margin-right: 32px; }
#login-box input, #login-box .btn.primary { width: calc(100% - 64px); }

/* el estado deja de ser una franja de pie: es una línea bajo el botón */
#login-box #login-status {
    margin: 14px 32px 0; padding: 0; min-height: 20px;
    background: transparent; border-top: 0;
}

/* --- Columna derecha: panel del producto --- */
#login-hero {
    position: relative; overflow: hidden;
    display: flex; flex-direction: column; justify-content: center; gap: 26px;
    padding: 48px 56px;
    color: #fff;
    background: linear-gradient(135deg,
        var(--accent) 0%,
        color-mix(in srgb, var(--accent) 78%, #0b3c66) 55%,
        color-mix(in srgb, var(--accent) 55%, #06243f) 100%);
}
/* respaldo si el navegador no soporta color-mix */
@supports not (background: color-mix(in srgb, red 50%, blue)) {
    #login-hero { background: linear-gradient(135deg, var(--accent) 0%, #0b3c66 100%); }
}
/* velo de puntos, para que el degradado no quede plano */
#login-hero::after {
    content: ''; position: absolute; inset: 0; pointer-events: none;
    background-image: radial-gradient(rgba(255, 255, 255, .16) 1px, transparent 1px);
    background-size: 22px 22px;
}
#login-hero .hero-txt { position: relative; z-index: 1; max-width: 46ch; }
#login-hero h1 {
    margin: 0 0 12px; font-size: clamp(20px, 2.4vw, 30px);
    font-weight: 300; line-height: 1.25;
}
#login-hero p { margin: 0; font-size: calc(var(--fs-base) + 1px); line-height: 1.6; opacity: .92; }
#login-hero code {
    background: rgba(255, 255, 255, .18); padding: 1px 5px;
    border-radius: var(--radio); font-family: var(--mono); font-size: .92em;
}
.hero-lista { list-style: none; margin: 18px 0 0; padding: 0; display: grid; gap: 7px; }
.hero-lista li { position: relative; padding-left: 20px; font-size: var(--fs-base); opacity: .92; }
.hero-lista li::before { content: '✓'; position: absolute; left: 0; opacity: .85; }
.hero-svg { position: relative; z-index: 1; width: min(420px, 100%); height: auto; opacity: .92; }

/* --- Pantallas angostas: el panel estorba, queda solo el formulario --- */
@media (max-width: 900px) {
    #login-overlay { grid-template-columns: 1fr; place-items: center; padding: 16px; }
    #login-hero { display: none; }
    #login-box {
        width: min(420px, 94vw); height: auto;
        border: 1px solid var(--border); border-radius: var(--radio);
        box-shadow: 0 14px 44px rgba(0, 0, 0, .22);
        padding: 22px 0 24px;
    }
}

/* El formulario va SIEMPRE en la primera columna y el panel en la segunda,
   sin importar el orden del marcado (el <aside> viene antes en el HTML). */
#login-box  { grid-column: 1; grid-row: 1; }
#login-hero { grid-column: 2; grid-row: 1; }
@media (max-width: 900px) {
    #login-box { grid-column: 1; }
}

/* --- Marca de agua del logo IVZ en el panel del producto ---
   Grande, translucido y fundido con el degradado (soft-light) para que se lea
   como textura y no como una imagen pegada encima. --- */
#hero-logo {
    position: absolute; right: -8%; bottom: -12%;
    width: min(62%, 460px); height: auto;
    opacity: .13; mix-blend-mode: soft-light;
    filter: grayscale(1) contrast(1.15);
    pointer-events: none; user-select: none; z-index: 0;
}
/* halo suave detras del logo, para dar profundidad */
#login-hero::before {
    content: ''; position: absolute; z-index: 0; pointer-events: none;
    right: -14%; bottom: -20%; width: 70%; aspect-ratio: 1;
    background: radial-gradient(circle, rgba(255,255,255,.16) 0%, transparent 62%);
}
/* el contenido siempre por encima de la marca de agua */
#login-hero .hero-txt, #login-hero .hero-svg { z-index: 1; }

/* Sin blend en pantallas de bajo contraste o si el usuario pide menos efectos */
@media (prefers-reduced-motion: reduce) { #hero-logo { mix-blend-mode: normal; opacity: .1; } }

/* Atribucion de la empresa en el panel del producto */
.hero-empresa{position:relative;z-index:1;display:flex;align-items:center;gap:8px;margin:0;font-size:calc(var(--fs-base) - 1px);opacity:.8}
.hero-empresa img{width:22px;height:22px;border-radius:var(--radio)}

/* ============================================================
   MODO DEPURACIÓN 🐞
   La barra de pasos y el visor de contexto. En data-modo="debug" se suma la
   barra de depuración SIN quitar nada: el lienzo queda plenamente operable
   (reorganizar, mover nodos, ejecutar, paleta) — pedido de Alejandro al
   depurar flujos publicados, donde antes desaparecían todos los controles.
============================================================ */
/* La barra de depuración vive DENTRO de la barra superior (#toolbar): en modo debug
   se muestra a la derecha de los menús, tomando el espacio restante. */
#debugbar { display: none; }
#debugbar {
    flex: 1; align-items: center; gap: 6px;
    padding: 0 4px 0 14px; margin-left: 10px;
    border-left: 2px solid var(--accent);
}
.dbg-title { font-weight: 600; color: var(--accent); white-space: nowrap; }
.dbg-step { padding: 2px 8px; background: var(--panel-2); border: 1px solid var(--border); border-radius: var(--radio, 2px); font-size: calc(var(--fs-base) - 1px); white-space: nowrap; }

/* Con el modo activo se muestra la barra de pasos en el tope. Nada más se
   oculta ni se bloquea: los controles del lienzo siguen todos disponibles
   (antes se escondían #actionbar y #floatbar y se deshabilitaban puertos,
   ▶ y ✕ — al depurar un flujo publicado no se podía ni reorganizar). */
:root[data-modo="debug"] #toolbar #debugbar { display: flex; }
:root[data-modo="debug"] #canvas-wrap::after {
    content: "🐞 depurando — paso a paso activo (⏹ para salir)";
    position: absolute; top: 8px; left: 50%; transform: translateX(-50%);
    background: var(--accent); color: #fff; padding: 3px 12px; border-radius: 12px;
    font-size: calc(var(--fs-base) - 2px); z-index: 5; pointer-events: none; opacity: .9;
}

/* Visor de contexto del nodo detenido, dentro del panel de propiedades */
.dbg-ctx h2 { display: flex; align-items: center; gap: 8px; }
.dbg-tipo { font-size: calc(var(--fs-base) - 2px); padding: 1px 7px; border-radius: 3px; background: var(--panel-2); border: 1px solid var(--border); }
.dbg-sec { margin: 10px 0; }
.dbg-sec > h3 {
    margin: 0 0 5px; font-size: calc(var(--fs-base) - 1px); text-transform: uppercase;
    letter-spacing: .04em; color: var(--accent); border-bottom: 1px solid var(--border); padding-bottom: 3px;
}
.dbg-warn { background: color-mix(in srgb, #e5484d 14%, transparent); border: 1px solid #e5484d; border-radius: var(--radio, 3px); padding: 8px 10px; }
.dbg-warn ul { margin: 5px 0 0; padding-left: 18px; }
.dbg-warn code { color: #e5484d; }
.dbg-ok { color: #46a758; }
.dbg-status { font-weight: 600; padding: 5px 8px; border-radius: var(--radio, 3px); margin-bottom: 6px; }
.dbg-status.ok { background: color-mix(in srgb, #46a758 18%, transparent); }
.dbg-status.err { background: color-mix(in srgb, #e5484d 18%, transparent); }

/* ============================================================
   MONITOR de flujos publicados
============================================================ */
.mon-salud { display:inline-block; padding:1px 7px; border-radius:10px; font-size:calc(var(--fs-base) - 2px); font-weight:600; border:1px solid var(--border); margin-right:6px; }
.mon-salud.on { background: color-mix(in srgb, #46a758 18%, transparent); }
.mon-salud.off { background: color-mix(in srgb, #e5484d 18%, transparent); }
.mon-nodos { display:flex; flex-wrap:wrap; gap:5px; margin-top:5px; }
.mon-nodo { font-size:calc(var(--fs-base) - 2px); padding:1px 7px; background:var(--panel-2); border:1px solid var(--border); border-radius:var(--radio,3px); }
.mon-logs { margin-top:6px; border-top:1px dashed var(--border); padding-top:6px; }
.mon-log-row { font-size:calc(var(--fs-base) - 2px); padding:4px 0; border-bottom:1px solid var(--border); }
.mon-item { border-left:3px solid var(--accent); }

/* Modal del Monitor (ventana dentro de la app) */
#monitor-modal { position: fixed; inset: 0; background: rgba(0,0,0,.5); z-index: 9000; display: flex; align-items: center; justify-content: center; }
#monitor-modal.hidden { display: none; }
#monitor-modal .mm-card { width: min(920px, 94vw); max-height: 86vh; display: flex; flex-direction: column; background: var(--panel); border: 1px solid var(--border); border-radius: var(--radio,4px); box-shadow: 0 12px 40px rgba(0,0,0,.5); }
#monitor-modal .mm-head { display: flex; align-items: center; justify-content: space-between; padding: 10px 14px; background: var(--accent); color: #fff; font-weight: 600; border-radius: var(--radio,4px) var(--radio,4px) 0 0; }
#monitor-modal .mm-body { padding: 14px; overflow: auto; }
.mm-table { width: 100%; border-collapse: collapse; }
.mm-table th, .mm-table td { text-align: left; padding: 6px 8px; border-bottom: 1px solid var(--border); }
.mm-table thead th { position: sticky; top: 0; background: var(--panel-2); }

/* ============================================================
   MODO MONITOREO INTEGRAL (data-modo="monitor")
   El menú Monitor convierte la app en un tablero: oculta lienzo, cuadro de
   herramientas, paneles y consola, y muestra la vista de monitoreo a pantalla
   completa. La barra superior (menús) sigue disponible.
============================================================ */
#monitor-view { position: fixed; left: 0; right: 0; bottom: 0; top: 44px; z-index: 40; display: flex; flex-direction: column; background: var(--bg); }
:root[data-modo="monitor"] #canvas-wrap,
:root[data-modo="monitor"] #floatbar,
:root[data-modo="monitor"] #actionbar,
:root[data-modo="monitor"] #sidebar,
:root[data-modo="monitor"] #console-panel,
:root[data-modo="monitor"] #zoom-overlay,
:root[data-modo="monitor"] #statusbar { display: none !important; }
.mv-bar { display: flex; align-items: center; gap: 8px; padding: 8px 14px; background: var(--panel); border-bottom: 2px solid var(--accent); }
.mv-title { font-weight: 600; color: var(--accent); font-size: calc(var(--fs-base) + 2px); }
.mv-body { flex: 1; overflow: auto; padding: 16px 20px; max-width: 1100px; width: 100%; margin: 0 auto; }
.mv-legend { background: var(--panel-2); border: 1px solid var(--border); border-radius: var(--radio,3px); padding: 8px 12px; }
.mv-sec { margin: 14px 0 6px; color: var(--accent); border-bottom: 1px solid var(--border); padding-bottom: 4px; }
.mon-vivo { font-weight: 600; color: var(--green); margin-right: 4px; }
.mon-pag { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-top: 8px; font-size: calc(var(--fs-base) - 1px); }
.dep-flujos { margin: 6px 0 4px; padding-left: 8px; border-left: 2px dashed var(--border); }
.dep-flujo { padding: 5px 0; border-bottom: 1px solid var(--border); font-size: calc(var(--fs-base) - 1px); }
.dep-flujo:last-child { border-bottom: none; }

/* --- Grilla de servicios monitoreados: una fila por servicio, clic = detalle --- */
.mon-grid { width: 100%; border-collapse: collapse; background: var(--panel); border: 1px solid var(--border); border-radius: var(--radio,3px); overflow: hidden; }
.mon-grid thead th { text-align: left; padding: 8px 10px; background: var(--panel-2); border-bottom: 2px solid var(--accent); font-size: calc(var(--fs-base) - 1px); color: var(--muted,#888); font-weight: 600; }
.mon-grid td { padding: 8px 10px; border-bottom: 1px solid var(--border); vertical-align: middle; }
.mon-grid .mg-env { width: 64px; text-align: center; font-size: calc(var(--fs-base) + 2px); }
.mon-grid .mg-arrow { width: 20px; text-align: center; color: var(--muted,#999); font-size: calc(var(--fs-base) + 4px); }
.mon-grid .mg-server { color: var(--muted,#888); font-size: calc(var(--fs-base) - 1px); max-width: 180px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mon-grid .mg-serv code { font-size: calc(var(--fs-base) - 1px); }
.mon-grid tr.mon-grupo td { background: var(--panel-2); font-weight: 600; color: var(--accent); border-bottom: 1px solid var(--border); padding: 6px 10px; }
.mon-grid .mon-cuenta { display: inline-block; min-width: 18px; text-align: center; background: var(--accent); color: #fff; border-radius: 10px; padding: 0 6px; font-size: calc(var(--fs-base) - 2px); margin-left: 6px; }
.mon-grid tr.mon-row { cursor: pointer; transition: background .1s; }
.mon-grid tr.mon-row:hover { background: var(--panel-2); }
.mon-grid tr.mon-row:hover .mg-arrow { color: var(--accent); }

/* --- Ventana de detalle de un servicio (modal dentro de la app) --- */
#servicio-modal { position: fixed; inset: 0; background: rgba(0,0,0,.5); z-index: 9100; display: flex; align-items: center; justify-content: center; }
#servicio-modal.hidden { display: none; }
#servicio-modal .sm-card { width: min(880px, 94vw); max-height: 88vh; display: flex; flex-direction: column; background: var(--panel); border: 1px solid var(--border); border-radius: var(--radio,4px); box-shadow: 0 12px 40px rgba(0,0,0,.5); }
#servicio-modal .sm-head { display: flex; align-items: center; justify-content: space-between; padding: 10px 14px; background: var(--accent); color: #fff; font-weight: 600; border-radius: var(--radio,4px) var(--radio,4px) 0 0; }
#servicio-modal .sm-head .sm-env { font-size: calc(var(--fs-base) - 2px); background: rgba(255,255,255,.25); border-radius: 3px; padding: 1px 6px; margin-left: 6px; }
#servicio-modal .sm-body { padding: 14px; overflow: auto; }
.sm-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 4px 18px; margin-bottom: 10px; }
.sm-grid > div { font-size: calc(var(--fs-base) - 1px); padding: 3px 0; border-bottom: 1px dotted var(--border); }
.sm-k { display: inline-block; min-width: 96px; color: var(--muted,#888); font-weight: 600; }
.sm-sec { margin: 12px 0 6px; color: var(--accent); border-bottom: 1px solid var(--border); padding-bottom: 4px; }
.sm-actions { flex-wrap: wrap; margin-top: 10px; }
.msg-ejec { border: 1px solid var(--border); border-radius: var(--radio,3px); margin-bottom: 8px; overflow: hidden; }
.msg-ejec-h { background: var(--panel-2); padding: 6px 10px; font-size: calc(var(--fs-base) - 1px); border-bottom: 1px solid var(--border); }
.msg-nodo { padding: 6px 10px; border-bottom: 1px dashed var(--border); }
.msg-nodo:last-child { border-bottom: none; }
.msg-nodo-h { font-size: calc(var(--fs-base) - 1px); margin-bottom: 3px; }
.msg-st { background: var(--panel-2); border-radius: 3px; padding: 0 5px; font-size: calc(var(--fs-base) - 2px); }
.msg-body { margin: 3px 0 0; padding: 6px 8px; background: var(--bg); border: 1px solid var(--border); border-radius: 3px; max-height: 160px; overflow: auto; font-family: monospace; font-size: calc(var(--fs-base) - 2px); white-space: pre-wrap; word-break: break-word; }

/* ============================================================================
   ACCESIBILIDAD Y PULIDO (auditoría ago-2026)
   Va al FINAL a propósito: cierra los huecos que la auditoría midió sin tocar
   las ~400 reglas de arriba. Foco visible global, movimiento reducido,
   scrollbars del tema y estados de deshabilitado coherentes.
============================================================================ */

/* Foco visible para navegación por teclado en TODO control que no sea un campo
   de texto (los campos ya indican foco con borde + sombra azul). El :where()
   mantiene especificidad 0: cualquier regla existente puede pisarlo adrede. */
:where(button, a, select, [tabindex]):focus-visible {
    outline: 2px solid var(--accent-borde, var(--accent));
    outline-offset: 1px;
}

/* Un control deshabilitado no está "esperando" (cursor wait): está no disponible. */
.btn:disabled, .ab-btn:disabled, .fb-btn:disabled { cursor: not-allowed; opacity: .5; }

/* Scrollbars del tema: los nativos grises pesados desentonan con el chrome claro.
   Firefox usa las propiedades estándar; WebKit el pseudo-elemento. */
* { scrollbar-width: thin; scrollbar-color: var(--border) transparent; }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb { background: var(--border); border: 2px solid transparent; background-clip: content-box; }
*::-webkit-scrollbar-thumb:hover { background-color: var(--muted); }

/* Filas clickeables de la grilla del monitor: también operables por teclado
   (el JS les da tabindex y Enter/Espacio abre el detalle). */
.mon-grid tr.mon-row:focus-visible { outline: 2px solid var(--accent-borde, var(--accent)); outline-offset: -2px; }

/* Movimiento reducido (vestibular): se anulan transiciones y animaciones de la
   app entera; el lienzo sigue siendo funcional, solo que sin interpolaciones. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .01ms !important;
        scroll-behavior: auto !important;
    }
}

/* Nodo OMITIDO por una condición (la rama no tomada): apagado, sin error. */
.node.omitido { opacity: .45; }
.node .n-status.skip { color: var(--muted); }
/* Etiqueta de rama sobre la conexión que sale de un nodo Condición */
.lk-rama { font-size: 11px; font-weight: 600; paint-order: stroke; stroke: var(--label-bg); stroke-width: 3px; }
.lk-rama.si { fill: var(--green); }
.lk-rama.no { fill: var(--red); }

/* ---------- Chip del asistente de atributos ---------- */
#ctx-chip {
    position: fixed; z-index: 5001; display: none;
    width: 22px; height: 20px; padding: 0; line-height: 18px;
    font-size: .74rem; text-align: center; cursor: pointer;
    background: var(--panel-2); color: var(--accent);
    border: 1px solid var(--accent); border-radius: 2px;
}
#ctx-chip:hover { background: var(--accent); color: var(--panel); }
/* Encabezado de procedencia dentro de la lista del asistente */
#ctx-ac .ac-grupo {
    position: sticky; top: 0; padding: 3px 8px;
    background: var(--panel-2); color: var(--accent);
    font-size: .68rem; font-weight: 600;
    border-top: 1px solid var(--border); border-bottom: 1px solid var(--border);
}
