/* drawflow-editor.css — Editor canvas + Drawflow node restyle.
 *
 * 2026 redesign: pure-neutral charcoal surfaces (#0A0A0A bg / #141414 cards),
 * mint accent (#65D6A5) for selected/active states, IBM Plex Sans + Plex Mono.
 * Drawflow's library-internal classes (.drawflow-node, .drawflow_content_node,
 * .input/.output, .connection .main-path) are overridden visually but never
 * renamed — the library hardcodes them in its JS.
 *
 * Token contract: scoped under .qb-editor (set on the canvas wrapper). The
 * wrapper also carries data-carbon-theme="g100" so any nested cds-* WCs
 * pick up the dark theme.
 */

/* =====================================================================
   Editor scope tokens
   ===================================================================== */
.qb-editor {
    --qbe-bg:           #0A0A0A;
    --qbe-bg-grid:      #181818;
    --qbe-surface-1:    #141414;
    --qbe-surface-2:    #1C1C1C;
    --qbe-surface-3:    #242424;
    --qbe-rule:         #1F1F1F;
    --qbe-rule-2:       #2A2A2A;
    --qbe-rule-hi:      #3A3A3A;
    --qbe-rule-strong:  #4D4D4D;
    --qbe-text:         #FFFFFF;
    --qbe-text-soft:    #EDEDED;
    --qbe-text-dim:     #B5B5B5;
    --qbe-text-faint:   #797979;
    --qbe-text-ghost:   #4D4D4D;
    --qbe-mint:         #65D6A5;
    --qbe-mint-hover:   #84E0BA;
    --qbe-mint-active:  #4DBE8E;
    --qbe-mint-soft:    rgba(101, 214, 165, 0.14);
    --qbe-mint-ink:     #04231A;
    --qbe-up:           #4FA875;
    --qbe-down:         #C25450;
    --qbe-warn:         #D4B248;

    --qbe-font:         "IBM Plex Sans", -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
    --qbe-font-mono:    "IBM Plex Mono", "JetBrains Mono", ui-monospace, monospace;

    position: relative;
    /* Use 100dvh (dynamic viewport height) so the wrapper tracks the real
       visible area on iOS Safari — shrinks when URL bar is shown, grows
       when collapsed. Falls back through 100svh → 100vh on older
       browsers. This makes any absolutely-positioned bottom element
       (the action bar) sit inside the visible viewport without manual
       offset hacks. */
    height: 100vh;
    height: 100svh;
    height: 100dvh;
    width: 100%;
    background: var(--qbe-bg);
    /* Subtle dot-grid — pure-neutral, low contrast so it sits behind content
       without competing with it. */
    background-image: radial-gradient(circle at 1px 1px, var(--qbe-bg-grid) 1px, transparent 0);
    background-size: 24px 24px;
    color: var(--qbe-text-soft);
    font-family: var(--qbe-font);
    overflow: hidden;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}
.qb-editor #drawflow {
    position: relative;
    height: 100%;
    width: 100%;
    z-index: 0;
}

/* =====================================================================
   Drawflow node — Carbon-card aesthetic.
   .drawflow-node + .drawflow_content_node are library-internal classes —
   visual override only.
   ===================================================================== */
.drawflow .drawflow-node {
    background: var(--qbe-surface-2, #1C1C1C) !important;
    border: 1px solid var(--qbe-rule-2, #2A2A2A) !important;
    border-left: 3px solid var(--nc, #3A3A3A) !important;
    border-radius: 0 !important;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4) !important;
    padding: 0 !important;
    min-width: 180px;
    min-height: auto !important;
    transition: border-color 0.18s ease, box-shadow 0.25s ease, transform 0.1s ease;
    overflow: visible !important;
    font-family: var(--qbe-font, "IBM Plex Sans", sans-serif);
}
.drawflow .drawflow-node:hover {
    border-color: var(--qbe-rule-hi, #3A3A3A) !important;
    border-left-color: var(--nc, #3A3A3A) !important;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5) !important;
}
.drawflow .drawflow-node.selected {
    border-color: color-mix(in srgb, var(--nc) 40%, var(--qbe-rule-hi, #3A3A3A)) !important;
    border-left-color: var(--nc) !important;
    box-shadow:
        0 0 0 1.5px color-mix(in srgb, var(--nc) 22%, transparent),
        0 0 24px color-mix(in srgb, var(--nc) 12%, transparent),
        0 4px 16px rgba(0, 0, 0, 0.4) !important;
}
.drawflow .drawflow-node:active { transform: scale(1.005); }
.drawflow .drawflow-node .drawflow_content_node { padding: 0 !important; }
.drawflow .drawflow-delete { display: none !important; }

/* =====================================================================
   Connections — clean sharp stroke, mint when active
   ===================================================================== */
.drawflow .connection .main-path {
    fill: none;
    stroke: var(--qbe-rule-hi, #3A3A3A);
    stroke-width: 2;
    transition: stroke 0.2s ease, stroke-width 0.2s ease;
    cursor: pointer;
}
.drawflow .connection .main-path:hover {
    stroke: var(--qbe-mint, #65D6A5);
    stroke-width: 2.5;
}
.drawflow .connection.selected .main-path {
    stroke: var(--qbe-down, #C25450);
    stroke-width: 2.5;
    stroke-dasharray: 6 3;
}

/* =====================================================================
   Ports — neutral grey default, mint on hover
   ===================================================================== */
.drawflow .drawflow-node .input,
.drawflow .drawflow-node .output {
    width: 12px !important;
    height: 12px !important;
    border-radius: 50% !important;
    background: var(--qbe-rule-strong, #4D4D4D) !important;
    border: 2px solid var(--qbe-bg, #0A0A0A) !important;
    cursor: crosshair !important;
    transition: background 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
    position: relative;
}
/* Larger invisible hitbox — easier to grab without enlarging the dot */
.drawflow .drawflow-node .input::before,
.drawflow .drawflow-node .output::before {
    content: "";
    position: absolute;
    inset: -8px;
    border-radius: 50%;
    background: transparent;
    pointer-events: auto;
}
.drawflow .drawflow-node .input:hover,
.drawflow .drawflow-node .output:hover {
    background: var(--qbe-mint, #65D6A5) !important;
    box-shadow: 0 0 10px rgba(101, 214, 165, 0.5) !important;
    transform: scale(1.3);
}
.drawflow .drawflow-node.selected .input,
.drawflow .drawflow-node.selected .output {
    background: var(--nc, var(--qbe-mint, #65D6A5)) !important;
    box-shadow: 0 0 8px color-mix(in srgb, var(--nc, #65D6A5) 40%, transparent) !important;
}
/* Click-to-connect first-tap state — ring tells user the port is armed */
.drawflow .drawflow-node .input.port-pending,
.drawflow .drawflow-node .output.port-pending {
    background: var(--qbe-mint, #65D6A5) !important;
    box-shadow:
        0 0 0 3px rgba(101, 214, 165, 0.35),
        0 0 16px rgba(101, 214, 165, 0.7) !important;
    transform: scale(1.35);
}

/* =====================================================================
   Node header — block icon + label + info tooltip
   ===================================================================== */
.node-header {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    background: color-mix(in srgb, var(--nc) 7%, transparent);
    border-bottom: 1px solid var(--qbe-rule, #1F1F1F);
    position: relative;
}
.node-header:only-child { border-bottom: none; }
.node-header .hi {
    width: 22px;
    height: 22px;
    background: color-mix(in srgb, var(--nc) 16%, transparent);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}
.node-header .hi svg {
    width: 11px;
    height: 11px;
    color: var(--nc);
}
.node-header .hl {
    font-family: var(--qbe-font-mono, "IBM Plex Mono", monospace);
    font-size: 11px;
    font-weight: 500;
    color: var(--qbe-text-soft, #EDEDED);
    letter-spacing: 0.02em;
    line-height: 1.2;
    flex: 1;
    text-transform: uppercase;
}

/* Info "i" badge in header */
.node-info-btn {
    width: 16px;
    height: 16px;
    border-radius: 50%;
    border: 1px solid var(--qbe-rule-hi, #3A3A3A);
    background: transparent;
    color: var(--qbe-text-faint, #797979);
    cursor: pointer;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font: 600 9px/1 var(--qbe-font, sans-serif);
    transition: border-color 0.15s ease, color 0.15s ease;
    position: relative;
}
.node-info-btn:hover {
    border-color: var(--nc);
    color: var(--nc);
}
.node-tooltip {
    position: absolute;
    bottom: calc(100% + 6px);
    right: -4px;
    background: var(--qbe-surface-3, #242424);
    border: 1px solid var(--qbe-rule-hi, #3A3A3A);
    padding: 8px 12px;
    font-family: var(--qbe-font, sans-serif);
    font-size: 11px;
    font-weight: 400;
    line-height: 1.45;
    color: var(--qbe-text-soft, #EDEDED);
    white-space: normal;
    min-width: 180px;
    max-width: 240px;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
    z-index: 100;
    pointer-events: none;
    opacity: 0;
    transform: translateY(2px);
    transition: opacity 0.15s ease, transform 0.15s ease;
}
.node-info-btn:hover .node-tooltip {
    opacity: 1;
    transform: translateY(0);
}

/* Port type labels (small text near input/output ports) */
.port-label {
    position: absolute;
    font-family: var(--qbe-font-mono, "IBM Plex Mono", monospace);
    font-size: 8px;
    font-weight: 500;
    color: var(--qbe-text-ghost, #4D4D4D);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    pointer-events: none;
    white-space: nowrap;
    line-height: 1;
}
.port-label.in  { left: 4px;  bottom: -12px; }
.port-label.out { right: 4px; bottom: -12px; }

/* =====================================================================
   Node body — param rows
   ===================================================================== */
.node-body { padding: 10px 12px; }
.node-body:empty { display: none; }
.node-body .param-row { margin-top: 8px; }
.node-body .param-row:first-child { margin-top: 0; }
.node-body .param-row.hidden { display: none; }
.node-body .param-row.is-type {
    padding-bottom: 8px;
    margin-bottom: 8px;
    border-bottom: 1px solid var(--qbe-rule, #1F1F1F);
}
.node-body .param-row.is-type label {
    color: var(--nc);
    opacity: 0.85;
}
.node-body label {
    display: block;
    font-family: var(--qbe-font-mono, "IBM Plex Mono", monospace);
    font-size: 9px;
    font-weight: 500;
    color: var(--qbe-text-faint, #797979);
    margin-bottom: 4px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    line-height: 1;
}
.node-body input,
.node-body select {
    width: 100%;
    padding: 6px 9px;
    font-family: var(--qbe-font, "IBM Plex Sans", sans-serif);
    font-size: 12px;
    line-height: 1.4;
    border-radius: 0;
    border: 1px solid var(--qbe-rule-2, #2A2A2A);
    background: var(--qbe-surface-1, #141414);
    color: var(--qbe-text-soft, #EDEDED);
    transition: border-color 0.12s ease, box-shadow 0.12s ease, background-color 0.12s ease;
    box-sizing: border-box;
}
.node-body select {
    appearance: none;
    -webkit-appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='%23797979' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 9px center;
    background-size: 10px;
    padding-right: 26px;
    cursor: pointer;
}
.node-body select:hover { border-color: var(--qbe-rule-hi, #3A3A3A); }
.node-body input:focus,
.node-body select:focus {
    border-color: var(--nc, var(--qbe-mint, #65D6A5));
    box-shadow: 0 0 0 1px var(--nc, var(--qbe-mint, #65D6A5));
    outline: none;
    background: var(--qbe-surface-2, #1C1C1C);
}
.node-body input[type="number"] {
    font-family: var(--qbe-font-mono, "IBM Plex Mono", monospace);
    font-size: 12px;
    font-feature-settings: "tnum";
}
.node-body input[type="number"]::-webkit-inner-spin-button { opacity: 0.3; }

/* Symbol picker widget inside a node. block-html.js emits inline styles
   (border/background/color/font etc.); we override visuals via !important
   on shape/spacing/font but leave color alone so the JS-controlled
   "selected vs placeholder" tint is preserved. */
.sym-picker {
    width: 100%;
    padding: 6px 9px;
    font-family: var(--qbe-font-mono, "IBM Plex Mono", monospace);
    font-size: 12px;
    line-height: 1.4;
    border-radius: 0;
    border: 1px solid var(--qbe-rule-2, #2A2A2A);
    background: var(--qbe-surface-1, #141414);
    color: var(--qbe-text-faint, #797979);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: space-between;
    transition: border-color 0.12s ease, background-color 0.12s ease, color 0.12s ease;
    box-sizing: border-box;
}
.sym-picker--has-value { color: var(--qbe-text-soft, #EDEDED); }
.sym-picker:hover {
    border-color: var(--qbe-rule-hi, #3A3A3A);
    background: var(--qbe-surface-2, #1C1C1C);
}
.sym-picker .sp-val { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.sym-picker svg { flex-shrink: 0; }

/* =====================================================================
   Toolbar buttons — square icon, neutral
   ===================================================================== */
.tb-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border: 1px solid var(--qbe-rule-2, #2A2A2A);
    background: var(--qbe-surface-1, #141414);
    color: var(--qbe-text-faint, #797979);
    cursor: pointer;
    transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
    border-radius: 0;
    padding: 0;
}
.tb-btn:hover {
    border-color: var(--qbe-rule-hi, #3A3A3A);
    color: var(--qbe-text-soft, #EDEDED);
    background: var(--qbe-surface-2, #1C1C1C);
}
.tb-btn:focus-visible {
    outline: 2px solid var(--qbe-mint, #65D6A5);
    outline-offset: -2px;
}
.tb-btn:active {
    background: var(--qbe-surface-3, #242424);
    transform: scale(0.94);
}
.tb-btn svg {
    width: 14px;
    height: 14px;
}

.tb-sep {
    display: inline-block;
    width: 1px;
    height: 18px;
    background: var(--qbe-rule-2, #2A2A2A);
    flex-shrink: 0;
    margin: 0 2px;
}

/* =====================================================================
   Top toolbar bar (clean / delete / fit / zoom)
   ===================================================================== */
.qb-editor-toolbar {
    position: absolute;
    top: calc(12px + env(safe-area-inset-top, 0px));
    left: 50%;
    transform: translateX(-50%);
    z-index: 45;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px;
    background: rgba(20, 20, 20, 0.94);
    border: 1px solid var(--qbe-rule-2, #2A2A2A);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    box-shadow: 0 8px 24px -8px rgba(0, 0, 0, 0.55);
}

/* =====================================================================
   Bottom action bar (save / test / strategy name)
   ===================================================================== */
.qb-editor-bottombar {
    /* `position: absolute` to .qb-editor (which is sized via 100dvh) —
       the dynamic-viewport-height tracks iOS Safari's URL bar in real
       time, so the bar always lives inside the visible area. No JS,
       no magic numbers, no visualViewport-tracking. */
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    bottom: max(20px, env(safe-area-inset-bottom, 0px));
    z-index: 100;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 6px 8px;
    background: rgba(20, 20, 20, 0.94);
    border: 1px solid var(--qbe-rule-2, #2A2A2A);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    box-shadow: 0 12px 32px -10px rgba(0, 0, 0, 0.6);
    pointer-events: auto;
}

/* Strategy / indicator name input */
.qb-editor-name {
    width: 200px;
    height: 30px;
    padding: 0 10px;
    background: var(--qbe-surface-1, #141414);
    border: 1px solid var(--qbe-rule-2, #2A2A2A);
    color: var(--qbe-text-soft, #EDEDED);
    font-family: var(--qbe-font, sans-serif);
    font-size: 12px;
    line-height: 1;
    border-radius: 0;
    box-sizing: border-box;
    transition: border-color 0.12s ease, box-shadow 0.12s ease;
}
.qb-editor-name:focus {
    outline: none;
    border-color: var(--qbe-mint, #65D6A5);
    box-shadow: 0 0 0 1px var(--qbe-mint, #65D6A5);
}
.qb-editor-name::placeholder { color: var(--qbe-text-faint, #797979); }

/* Bottom-bar buttons (save / test / dashboard) */
.qb-editor-btn {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    height: 30px;
    padding: 0 14px;
    font-family: var(--qbe-font, sans-serif);
    font-size: 12px;
    font-weight: 500;
    line-height: 1;
    border: 1px solid transparent;
    background: transparent;
    color: var(--qbe-text-soft, #EDEDED);
    cursor: pointer;
    text-decoration: none;
    transition: background-color 0.12s ease, border-color 0.12s ease, color 0.12s ease;
    border-radius: 0;
    white-space: nowrap;
}
.qb-editor-btn__icon { width: 12px; height: 12px; flex-shrink: 0; }
.qb-editor-btn--primary {
    background: var(--qbe-mint, #65D6A5);
    color: var(--qbe-mint-ink, #04231A);
    border-color: var(--qbe-mint, #65D6A5);
    font-weight: 600;
}
.qb-editor-btn--primary:hover {
    background: var(--qbe-mint-hover, #84E0BA);
    border-color: var(--qbe-mint-hover, #84E0BA);
}
.qb-editor-btn--primary:focus-visible {
    outline: 2px solid var(--qbe-mint, #65D6A5);
    outline-offset: 2px;
}
.qb-editor-btn--accent {
    background: transparent;
    color: var(--qbe-mint, #65D6A5);
    border-color: var(--qbe-mint, #65D6A5);
}
.qb-editor-btn--accent:hover {
    background: var(--qbe-mint-soft, rgba(101, 214, 165, 0.14));
    color: var(--qbe-mint-hover, #84E0BA);
    border-color: var(--qbe-mint-hover, #84E0BA);
}
.qb-editor-btn--ghost {
    background: transparent;
    color: var(--qbe-text-dim, #B5B5B5);
    border-color: var(--qbe-rule-2, #2A2A2A);
}
.qb-editor-btn--ghost:hover {
    color: var(--qbe-text-soft, #EDEDED);
    border-color: var(--qbe-rule-hi, #3A3A3A);
    background: var(--qbe-surface-1, #141414);
}

/* System-indicator badge ("Built-in") */
.qb-editor-badge {
    display: inline-flex;
    align-items: center;
    height: 30px;
    padding: 0 10px;
    font-family: var(--qbe-font-mono, "IBM Plex Mono", monospace);
    font-size: 10px;
    font-weight: 500;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--qbe-text-faint, #797979);
    background: var(--qbe-surface-2, #1C1C1C);
    border: 1px solid var(--qbe-rule-2, #2A2A2A);
}

/* =====================================================================
   Back-to-dashboard button — top-left, safe-area aware
   ===================================================================== */
.editor-back-btn {
    position: absolute;
    top: calc(12px + env(safe-area-inset-top, 0px));
    left: calc(12px + env(safe-area-inset-left, 0px));
    z-index: 45;
    text-decoration: none;
}

/* =====================================================================
   Block palette sidebar
   ===================================================================== */
.palette-toggle-btn {
    position: absolute;
    top: calc(12px + env(safe-area-inset-top, 0px));
    right: calc(12px + env(safe-area-inset-right, 0px));
    z-index: 45;
    display: none;
}
.palette-sidebar {
    position: absolute;
    top: calc(12px + env(safe-area-inset-top, 0px));
    right: calc(12px + env(safe-area-inset-right, 0px));
    z-index: 45;
    width: 224px;
    max-height: calc(100vh - 100px);
    overflow: hidden;
    background: rgba(20, 20, 20, 0.94);
    border: 1px solid var(--qbe-rule-2, #2A2A2A);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    box-shadow: 0 12px 32px -8px rgba(0, 0, 0, 0.6);
    display: flex;
    flex-direction: column;
}
.palette-sidebar__head {
    padding: 10px;
    border-bottom: 1px solid var(--qbe-rule, #1F1F1F);
}
.palette-search {
    width: 100%;
    height: 30px;
    padding: 0 10px;
    background: var(--qbe-surface-1, #141414);
    border: 1px solid var(--qbe-rule-2, #2A2A2A);
    color: var(--qbe-text-soft, #EDEDED);
    font-family: var(--qbe-font-mono, "IBM Plex Mono", monospace);
    font-size: 11px;
    line-height: 1;
    border-radius: 0;
    box-sizing: border-box;
    transition: border-color 0.12s ease, box-shadow 0.12s ease;
}
.palette-search:focus {
    outline: none;
    border-color: var(--qbe-mint, #65D6A5);
    box-shadow: 0 0 0 1px var(--qbe-mint, #65D6A5);
}
.palette-search::placeholder { color: var(--qbe-text-faint, #797979); }
.palette-sidebar__body {
    overflow-y: auto;
    flex: 1;
    padding: 8px;
}
.palette-sidebar__body > .cat-section + .cat-section { margin-top: 6px; }

/* Category disclosure */
.cat-section { display: block; }
.cat-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 6px 8px;
    font-family: var(--qbe-font-mono, "IBM Plex Mono", monospace);
    font-size: 10px;
    font-weight: 500;
    color: var(--qbe-text-faint, #797979);
    letter-spacing: 0.14em;
    text-transform: uppercase;
    cursor: pointer;
    user-select: none;
    transition: color 0.12s ease;
    line-height: 1.4;
}
.cat-toggle:hover { color: var(--qbe-text-soft, #EDEDED); }
.cat-toggle .chv {
    display: inline-block;
    font-size: 7px;
    transition: transform 0.15s ease;
}
.cat-toggle.collapsed .chv { transform: rotate(-90deg); }
.cat-items {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin-top: 2px;
}
.cat-items.hidden { display: none; }

/* Palette item — Carbon-card-ish mini tile */
.palette-item {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 8px;
    padding: 7px 10px;
    cursor: grab;
    background: rgba(255, 255, 255, 0.02);
    border: 1px solid transparent;
    border-left: 2px solid var(--block-color, var(--qbe-rule-hi, #3A3A3A));
    color: var(--block-color, var(--qbe-text-soft, #EDEDED));
    font-family: var(--qbe-font-mono, "IBM Plex Mono", monospace);
    font-size: 10.5px;
    font-weight: 500;
    line-height: 1.3;
    letter-spacing: 0.02em;
    text-decoration: none;
    user-select: none;
    transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease, transform 0.15s ease;
    box-sizing: border-box;
}
.palette-item:hover {
    background: rgba(255, 255, 255, 0.05);
    border-color: var(--qbe-rule-2, #2A2A2A);
    border-left-color: var(--block-color, var(--qbe-mint, #65D6A5));
    color: var(--qbe-text, #FFFFFF);
    transform: translateX(2px);
}
.palette-item:active {
    cursor: grabbing;
    transform: translateX(1px) scale(0.99);
}
.palette-item__label {
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.palette-item__lock {
    flex-shrink: 0;
    width: 11px;
    height: 11px;
    opacity: 0.85;
}
.block-item-locked {
    opacity: 0.55;
    cursor: not-allowed;
}
.block-item-locked:hover { opacity: 1; }

/* =====================================================================
   Selection lasso + multi-selected outline
   ===================================================================== */
.select-rect {
    position: absolute;
    border: 1px solid rgba(101, 214, 165, 0.6);
    background: rgba(101, 214, 165, 0.08);
    pointer-events: none;
    z-index: 100;
}
.drawflow .drawflow-node.multi-selected {
    outline: 1.5px solid rgba(101, 214, 165, 0.45) !important;
    outline-offset: 3px;
}

/* =====================================================================
   Symbol search modal (sym-overlay / sym-modal — DOM hooks from JS)
   ===================================================================== */
.sym-overlay {
    position: fixed;
    inset: 0;
    z-index: 300;
    background: rgba(0, 0, 0, 0.7);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    animation: qb-sym-fade 0.18s ease both;
}
.sym-modal {
    width: 100%;
    max-width: 480px;
    max-height: 70vh;
    background: var(--qbe-surface-1, #141414);
    border: 1px solid var(--qbe-rule-2, #2A2A2A);
    display: flex;
    flex-direction: column;
    box-shadow: 0 32px 64px -16px rgba(0, 0, 0, 0.7);
    animation: qb-sym-pop 0.22s cubic-bezier(0.16, 1, 0.3, 1) both;
    font-family: var(--qbe-font, sans-serif);
}
.sym-header { padding: 16px 16px 0; }
.sym-search {
    width: 100%;
    height: 38px;
    padding: 0 12px;
    font-family: var(--qbe-font, sans-serif);
    font-size: 13px;
    line-height: 1;
    border-radius: 0;
    border: 1px solid var(--qbe-rule-2, #2A2A2A);
    background: var(--qbe-bg, #0A0A0A);
    color: var(--qbe-text, #FFFFFF);
    outline: none;
    box-sizing: border-box;
    transition: border-color 0.12s ease, box-shadow 0.12s ease;
}
.sym-search:focus {
    border-color: var(--qbe-mint, #65D6A5);
    box-shadow: 0 0 0 1px var(--qbe-mint, #65D6A5);
}
.sym-search::placeholder { color: var(--qbe-text-faint, #797979); }
.sym-tabs {
    display: flex;
    gap: 2px;
    padding: 12px 16px 0;
    flex-wrap: wrap;
}
.sym-tab {
    padding: 6px 12px;
    font-family: var(--qbe-font-mono, "IBM Plex Mono", monospace);
    font-size: 11px;
    font-weight: 500;
    color: var(--qbe-text-faint, #797979);
    cursor: pointer;
    transition: background-color 0.12s ease, color 0.12s ease;
    border: 1px solid transparent;
    background: none;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    border-radius: 0;
}
.sym-tab:hover {
    color: var(--qbe-text-soft, #EDEDED);
    background: var(--qbe-surface-2, #1C1C1C);
}
.sym-tab.active {
    color: var(--qbe-mint-ink, #04231A);
    background: var(--qbe-mint, #65D6A5);
    border-color: var(--qbe-mint, #65D6A5);
}
.sym-list {
    flex: 1;
    overflow-y: auto;
    padding: 8px;
}
.sym-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 9px 12px;
    cursor: pointer;
    transition: background-color 0.1s ease;
    border-left: 2px solid transparent;
}
.sym-item:hover {
    background: var(--qbe-surface-2, #1C1C1C);
    border-left-color: var(--qbe-mint, #65D6A5);
}
.sym-item .si-sym {
    font-family: var(--qbe-font-mono, "IBM Plex Mono", monospace);
    font-size: 12px;
    font-weight: 600;
    color: var(--qbe-text, #FFFFFF);
}
.sym-item .si-name {
    font-family: var(--qbe-font, sans-serif);
    font-size: 11px;
    color: var(--qbe-text-faint, #797979);
    margin-left: 10px;
}
.sym-item .si-type {
    font-family: var(--qbe-font-mono, "IBM Plex Mono", monospace);
    font-size: 9px;
    font-weight: 500;
    color: var(--qbe-text-ghost, #4D4D4D);
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

@keyframes qb-sym-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes qb-sym-pop {
    from { opacity: 0; transform: translateY(8px) scale(0.98); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}

/* =====================================================================
   Connection error toast (.conn-toast — DOM hook)
   ===================================================================== */
.conn-toast {
    position: fixed;
    top: 72px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 200;
    display: flex;
    align-items: center;
    gap: 10px;
    background: var(--qbe-surface-1, #141414);
    border: 1px solid var(--qbe-rule-2, #2A2A2A);
    border-left: 3px solid var(--qbe-down, #C25450);
    padding: 12px 14px;
    box-shadow: 0 12px 32px -8px rgba(0, 0, 0, 0.55);
    max-width: 420px;
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    animation: qb-sym-pop 0.22s cubic-bezier(0.16, 1, 0.3, 1) both;
    font-family: var(--qbe-font, sans-serif);
}
.conn-toast .ct-icon {
    flex-shrink: 0;
    color: var(--qbe-down, #C25450);
}
.conn-toast .ct-text {
    font-size: 13px;
    line-height: 1.5;
    color: var(--qbe-text-dim, #B5B5B5);
}
.conn-toast .ct-text strong {
    color: var(--qbe-text-soft, #EDEDED);
    font-weight: 600;
}
.conn-toast .ct-close {
    flex-shrink: 0;
    color: var(--qbe-text-faint, #797979);
    cursor: pointer;
    transition: color 0.15s ease;
    background: transparent;
    border: 0;
    padding: 0;
    display: inline-flex;
    align-items: center;
}
.conn-toast .ct-close:hover { color: var(--qbe-text-soft, #EDEDED); }

/* =====================================================================
   Save / action button loading state (.btn-loading)
   ===================================================================== */
.btn-loading { pointer-events: none; opacity: 0.75; }
.btn-loading::after {
    content: '';
    display: inline-block;
    width: 10px;
    height: 10px;
    border: 1.5px solid currentColor;
    border-top-color: transparent;
    border-radius: 50%;
    animation: qb-btn-spin 0.6s linear infinite;
    margin-left: 8px;
    vertical-align: middle;
}
@keyframes qb-btn-spin { to { transform: rotate(360deg); } }

/* =====================================================================
   Save toast pill (#save-toast)
   ===================================================================== */
#save-toast.editor-save-toast {
    position: absolute;
    bottom: calc(80px + env(safe-area-inset-bottom, 0px));
    left: 50%;
    transform: translateX(-50%) translateY(0);
    display: inline-flex;
    align-items: center;
    gap: 10px;
    padding: 10px 18px;
    background: rgba(20, 20, 20, 0.92);
    border: 1px solid var(--qbe-mint, #65D6A5);
    backdrop-filter: blur(16px) saturate(140%);
    -webkit-backdrop-filter: blur(16px) saturate(140%);
    color: var(--qbe-mint, #65D6A5);
    font-family: var(--qbe-font-mono, "IBM Plex Mono", monospace);
    font-size: 11px;
    font-weight: 500;
    line-height: 1;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    z-index: 46;
    pointer-events: none;
    box-shadow:
        0 14px 40px -8px rgba(0, 0, 0, 0.7),
        0 0 32px -4px rgba(101, 214, 165, 0.28);
    opacity: 1;
    transition:
        opacity 0.32s cubic-bezier(0.16, 1, 0.3, 1),
        transform 0.32s cubic-bezier(0.16, 1, 0.3, 1),
        border-color 0.25s ease,
        color 0.25s ease,
        box-shadow 0.25s ease;
}
#save-toast.editor-save-toast::before {
    content: '';
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
    box-shadow: 0 0 10px currentColor, 0 0 4px currentColor;
    animation: qb-save-dot-pulse 1.8s ease-in-out infinite;
}
#save-toast.editor-save-toast.hidden {
    display: inline-flex !important;
    opacity: 0;
    transform: translateX(-50%) translateY(12px);
    pointer-events: none;
}
#save-toast.editor-save-toast.is-error {
    border-color: var(--qbe-down, #C25450);
    color: var(--qbe-down, #C25450);
    box-shadow:
        0 14px 40px -8px rgba(0, 0, 0, 0.7),
        0 0 32px -4px rgba(194, 84, 80, 0.28);
}
@keyframes qb-save-dot-pulse {
    0%, 100% { opacity: 1; transform: scale(1); }
    50%      { opacity: 0.55; transform: scale(0.85); }
}

/* =====================================================================
   Unsaved-changes nav-guard dialog (#nav-guard-dialog)
   DOM hooks: .nav-guard-overlay/.nav-guard-modal/[data-nav-guard-action]
   ===================================================================== */
.nav-guard-overlay {
    position: fixed;
    inset: 0;
    z-index: 300;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    background: rgba(0, 0, 0, 0.72);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    animation: qb-nav-guard-fade 0.18s ease-out;
    font-family: var(--qbe-font, sans-serif);
}
.nav-guard-overlay.hidden { display: none; }
.nav-guard-modal {
    width: 100%;
    max-width: 440px;
    background: var(--qbe-surface-1, #141414);
    border: 1px solid var(--qbe-rule-2, #2A2A2A);
    box-shadow: 0 32px 64px -16px rgba(0, 0, 0, 0.7);
    padding: 28px 28px 22px;
    animation: qb-nav-guard-pop 0.22s cubic-bezier(0.16, 1, 0.3, 1);
}
.nav-guard-title {
    font-family: var(--qbe-font, sans-serif);
    font-weight: 600;
    font-size: 1.125rem;
    color: var(--qbe-text, #FFFFFF);
    line-height: 1.2;
    letter-spacing: -0.01em;
    margin: 0 0 10px;
}
.nav-guard-body {
    color: var(--qbe-text-dim, #B5B5B5);
    font-size: 14px;
    line-height: 1.55;
    margin: 0 0 24px;
}
.nav-guard-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 8px;
}
.nav-guard-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 38px;
    min-width: 96px;
    padding: 0 16px;
    font-family: inherit;
    font-size: 13px;
    font-weight: 500;
    border-radius: 0;
    border: 1px solid transparent;
    cursor: pointer;
    transition: background-color 0.14s ease, border-color 0.14s ease, color 0.14s ease;
    white-space: nowrap;
    background: transparent;
    line-height: 1;
}
.nav-guard-btn:focus-visible {
    outline: 2px solid var(--qbe-mint, #65D6A5);
    outline-offset: 2px;
}
.nav-guard-btn-ghost {
    color: var(--qbe-text-soft, #EDEDED);
    border-color: var(--qbe-rule-hi, #3A3A3A);
}
.nav-guard-btn-ghost:hover {
    background: var(--qbe-surface-2, #1C1C1C);
    border-color: var(--qbe-rule-strong, #4D4D4D);
    color: var(--qbe-text, #FFFFFF);
}
.nav-guard-btn-discard {
    background: transparent;
    color: var(--qbe-down, #C25450);
    border-color: rgba(194, 84, 80, 0.4);
}
.nav-guard-btn-discard:hover {
    background: rgba(194, 84, 80, 0.12);
    border-color: var(--qbe-down, #C25450);
}
.nav-guard-btn-save {
    background: var(--qbe-mint, #65D6A5);
    color: var(--qbe-mint-ink, #04231A);
    border-color: var(--qbe-mint, #65D6A5);
    font-weight: 600;
}
.nav-guard-btn-save:hover {
    background: var(--qbe-mint-hover, #84E0BA);
    border-color: var(--qbe-mint-hover, #84E0BA);
}
.nav-guard-btn:disabled {
    opacity: 0.55;
    cursor: wait;
}
@keyframes qb-nav-guard-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes qb-nav-guard-pop {
    from { opacity: 0; transform: translateY(8px) scale(0.98); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}

/* =====================================================================
   Read-only canvas mask
   ===================================================================== */
.readonly-overlay {
    position: absolute;
    inset: 0;
    z-index: 50;
    cursor: not-allowed;
}

/* =====================================================================
   Mobile portrait rotate-prompt overlay (#mobile-prompt)
   editor-actions.js toggles .hidden + .flex (legacy class names retained)
   ===================================================================== */
.qb-rotate-overlay {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 0 32px;
    text-align: center;
    background: rgba(10, 10, 10, 0.96);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    color: var(--qbe-text-soft, #EDEDED);
    font-family: var(--qbe-font, sans-serif);
}
.qb-rotate-overlay.hidden { display: none; }
.qb-rotate-overlay.flex   { display: flex; }
.qb-rotate-icon {
    color: var(--qbe-mint, #65D6A5);
    margin-bottom: 28px;
    animation: qb-rotate-hint 3.2s cubic-bezier(0.65, 0, 0.35, 1) infinite;
    transform-origin: center;
    opacity: 0.95;
    filter: drop-shadow(0 0 24px rgba(101, 214, 165, 0.28));
}
.qb-rotate-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    font-family: var(--qbe-font-mono, "IBM Plex Mono", monospace);
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--qbe-mint, #65D6A5);
    margin: 0 0 16px;
}
.qb-rotate-eyebrow::before {
    content: "";
    display: inline-block;
    width: 18px;
    height: 1px;
    background: currentColor;
    opacity: 0.7;
}
.qb-rotate-title {
    font-family: var(--qbe-font, sans-serif);
    font-weight: 600;
    font-size: 1.625rem;
    line-height: 1.18;
    letter-spacing: -0.01em;
    color: var(--qbe-text, #FFFFFF);
    margin: 0 0 12px;
}
.qb-rotate-body {
    font-size: 14px;
    line-height: 1.55;
    color: var(--qbe-text-dim, #B5B5B5);
    max-width: 32ch;
    margin: 0;
}
@keyframes qb-rotate-hint {
    0%, 100% { transform: rotate(0deg); }
    50%      { transform: rotate(-12deg); }
}

/* =====================================================================
   Mobile (<768px) — palette slides in from right
   ===================================================================== */
@media (max-width: 767px) {
    .palette-toggle-btn {
        display: inline-flex !important;
        z-index: 46;
    }

    .palette-sidebar {
        position: fixed !important;
        top: calc(58px + env(safe-area-inset-top, 0px)) !important;
        right: 0 !important;
        bottom: 0 !important;
        max-height: none !important;
        width: 240px !important;
        transform: translateX(110%);
        transition:
            transform 0.25s cubic-bezier(0.16, 1, 0.3, 1),
            opacity 0.25s ease;
        opacity: 0;
        pointer-events: none;
        z-index: 55 !important;
    }
    .palette-sidebar.palette-open {
        transform: translateX(0);
        opacity: 1;
        pointer-events: auto;
    }
    .palette-toggle-btn.palette-toggle-active {
        right: calc(244px + env(safe-area-inset-right, 0px)) !important;
        border-color: var(--qbe-mint, #65D6A5);
        color: var(--qbe-mint, #65D6A5);
    }
}

/* Native dark date picker */
.qb-editor input[type="date"] { color-scheme: dark; }
.qb-editor input[type="date"]::-webkit-calendar-picker-indicator {
    filter: invert(0.6);
    cursor: pointer;
}

@media (max-width: 540px) {
    .sym-modal { width: calc(100vw - 32px); }
    /* Bottom bar fits on phone widths down to ~320px. No bottom-offset
       hack here — the .qb-editor wrapper is now sized via 100dvh, so the
       bar's `bottom: 20px` automatically sits inside the visible area. */
    .qb-editor-bottombar {
        max-width: calc(100vw - 24px);
        gap: 6px;
        padding: 5px 6px;
    }
    .qb-editor-name {
        width: auto;
        flex: 1 1 0;
        min-width: 0;
    }
    .qb-editor-btn {
        flex-shrink: 0;
        padding: 0 10px;
        min-width: 0;
    }
}
@media (max-width: 380px) {
    /* Very narrow phones — hide button labels, keep icons only */
    .qb-editor-btn span,
    .qb-editor-btn .qb-editor-btn__label { display: none; }
    .qb-editor-btn { padding: 0 8px; }
}

/* =====================================================================
   Reduced-motion users — kill marquee animations
   ===================================================================== */
@media (prefers-reduced-motion: reduce) {
    .qb-rotate-icon,
    #save-toast.editor-save-toast::before,
    .drawflow .drawflow-node {
        animation: none !important;
        transition: none !important;
    }
}
