﻿/* Light 2 tints the app surfaces alice blue: the top bar, the cards, the panels inset in them and
   the front of a selected tab. It is one of three themes, so it hangs off an attribute the page sets
   rather than off the light/dark split, and Dark and Light 1 need no rules of their own: without the
   attribute nothing below applies and every surface keeps what Bootstrap gives it.

   The tab rule names the color outright instead of setting --bs-nav-tabs-link-active-bg, which loses
   to whatever paints the tab buttons. */
.gdbv-tint-panel {
    background-color: var(--bs-secondary-bg);
}

[data-gdbv-tint="on"] .gdbv-tint,
[data-gdbv-tint="on"] .gdbv-tint-panel,
[data-gdbv-tint="on"] .nav-tabs .nav-link.active {
    background-color: aliceblue;
}

html, body {
    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

/* Resizable split between the main graph view (.split-main) and the query sidebar (.split-side),
   with a draggable gutter (.split-gutter). Stacks vertically below the lg breakpoint. The sidebar
   width is the --sidebar-w CSS variable (set on :root by SplitterInterop while dragging); unset it
   falls back to the default 1/3 ratio. */
.split-row {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}
.split-gutter { display: none; }

/* Page width. The content sits in a centered column whose max width is a fraction of the viewport
   (80vw), leaving generous side margins. Being viewport-relative, those margins scale with browser
   zoom instead of ballooning — the same reason the 100vh-based height stays put when you zoom. The
   top-bar full-width toggle (.gdbv-fullscreen) drops the cap to fill the viewport. */
.gdbv-page {
    max-width: 80vw;
}

.gdbv-page.gdbv-fullscreen {
    max-width: none;
}

/* Icon-only toolbar buttons (the link / delete / add-component / style / clear cluster above the
   canvas). Their glyph sits on the text baseline, which leaves it slightly high — more space below
   than above — for both the SVG icons and the emoji ones. Flex-center the glyph; min-height keeps the
   btn-sm height so they still line up with the text buttons beside them. */
.gdbv-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: calc(1.5em + 0.5rem + 2px);
}

/* Close (×) button in the linking popup: muted by default, brightens to the body color on hover
   so it reads as clickable. */
.gdbv-x-close {
    transition: color 0.12s ease;
}

.gdbv-x-close:hover {
    color: var(--bs-body-color) !important;
}

/* Icon accent colors: vivid in dark mode; darker / more saturated in light mode where the vivid
   versions wash out. Applied via the SVG fills of the link / eraser toolbar icons. */
:root {
    --gdbv-link-icon: #d9480f;    /* light: deep dark orange */
    --gdbv-eraser-icon: #c2185b;  /* light: dark pink */
}

[data-bs-theme="dark"] {
    --gdbv-link-icon: #ff8c00;    /* dark: dark orange */
    --gdbv-eraser-icon: #ff69b4;  /* dark: hotpink */
}

/* Add-component, style and grid toolbar icons: soften them from the high-contrast body-emphasis color
   to a muted gray in light mode only, so they don't read as harshly. Dark mode keeps the bright color. */
:root:not([data-bs-theme="dark"]) .gdbv-icon-soft {
    color: #6c757d !important;
}

/* Draws attention to the top-bar connection button when a user action needs a live connection. */
@keyframes gdbv-connect-pulse {
    0%   { box-shadow: 0 0 0 0 rgba(var(--bs-danger-rgb), 0.5); }
    70%  { box-shadow: 0 0 0 0.6rem rgba(var(--bs-danger-rgb), 0); }
    100% { box-shadow: 0 0 0 0 rgba(var(--bs-danger-rgb), 0); }
}

.gdbv-pulse {
    position: relative;
    z-index: 1;
    border-color: var(--bs-danger) !important;
    color: var(--bs-danger) !important;
    animation: gdbv-connect-pulse 1s ease-out 3;
}

/* Compact borderless cluster for the canvas action icons (link / delete / add / style / clear):
   no per-button borders, buttons sit flush with a thin divider between them so they read as one
   toolbar and take less room. */
.gdbv-toolbar-group {
    display: inline-flex;
    align-items: stretch;
}

.gdbv-toolbar-group > .btn {
    border: 0;
    border-radius: 0;
    padding-left: 0.45rem;
    padding-right: 0.45rem;
}

.gdbv-toolbar-group > .btn + .btn {
    border-left: 1px solid var(--bs-border-color);
}

.gdbv-toolbar-group > .btn:hover {
    background-color: var(--bs-tertiary-bg);
}

.gdbv-toolbar-group > .btn.active {
    background-color: var(--bs-secondary-bg);
    box-shadow: inset 0 0 0 2px var(--bs-border-color);
}

/* Query-limit warning: the label goes red and pulses a couple of times when the limit is high enough to
   slow the app. The pulse plays when the class is first applied (i.e. as the value crosses the threshold
   or on load if it is already high); the red stays for as long as the limit is high. */
.gdbv-limit-warn {
    color: var(--bs-danger) !important;
    font-weight: bold;
    animation: gdbvLimitPulse 0.4s ease-in-out 2;
}

@keyframes gdbvLimitPulse {
    0%, 100% {
        opacity: 1;
    }

    50% {
        opacity: 0.2;
    }
}

@media (min-width: 992px) {
    .split-row {
        flex-direction: row;
        gap: 0;
        align-items: stretch;
        /* Definite height (not just the inline min-height) so that when a sidebar panel overflows it
           scrolls inside its own box instead of stretching the row and pushing a scrollbar onto the
           whole page. Only on the side-by-side layout; the stacked mobile layout keeps min-height. */
        height: calc(100vh - 123px);
    }
    .split-main {
        flex: 1 1 0;
        min-width: 0;
        min-height: 0;
    }
    .split-side {
        flex: 0 0 var(--sidebar-w, 33.333%);
        min-width: 23.4375rem;/*375px*/
        min-height: 0;
    }
    /* Let the sidebar card shrink below its content so the Component Properties panel (max-height: 50vh)
       scrolls internally rather than growing the column. */
    .split-side > .card {
        min-height: 0;
    }
    /* The same shrink-to-fit fix for the main results card and its in-flow content panes (JSON, Table,
       SPARQL bindings, the debugger): they scroll inside their own box instead of stretching the card
       past the viewport and pushing a scrollbar onto the whole page. The 2D/3D canvases keep their
       inline min-height:50vh (an inline style wins over this rule), so they are unaffected. */
    .split-main > .card {
        min-height: 0;
    }
    .split-main > .card > .flex-grow-1 {
        min-height: 0;
    }
    .split-gutter {
        display: flex;
        align-items: center;
        justify-content: center;
        flex: 0 0 14px;
        align-self: stretch;
        cursor: col-resize;
        touch-action: none;
    }
    .split-gutter-grip {
        width: 4px;
        height: 42px;
        border-radius: 2px;
        background-color: var(--bs-border-color);
        transition: background-color 0.12s;
    }
    .split-gutter:hover .split-gutter-grip,
    .split-gutter:active .split-gutter-grip {
        background-color: var(--bs-primary);
    }
}

/* Light mode: darken the main body text for legibility. Muted/secondary text
   (query limit, "(offline …)", tips, etc.) uses --bs-secondary-color and is left
   lighter on purpose to signify it's less important. */
:root:not([data-bs-theme="dark"]) {
    --bs-body-color: #000000;
    --bs-body-color-rgb: 0, 0, 0;
}

/* A disabled button and an enabled one were telling the same story. Bootstrap fades a disabled
   control to 65% opacity, which against the dark theme's low-contrast surfaces lands close enough to
   the enabled rendering that the query debugger's arrows and its simulate button were both being
   taken for clickable when they were not. Fade further and drain the colour, in both themes. */
.btn:disabled,
.btn.disabled,
fieldset:disabled .btn {
    opacity: 0.55;
}

/* Draining the colour as well is for outline buttons only. An outline button is almost entirely its
   label, so a muted label is what makes it look unavailable — but a solid button already reads as
   disabled from the fade alone, and muting its label on top of that left "Commit Changes" as pale
   text on a yellow block, unreadable rather than unavailable. */
.btn[class*="btn-outline-"]:disabled,
.btn[class*="btn-outline-"].disabled,
fieldset:disabled .btn[class*="btn-outline-"] {
    opacity: 0.45;
    --bs-btn-disabled-color: var(--bs-secondary-color);
    --bs-btn-disabled-border-color: var(--bs-border-color);
}

/* And the other half of the same problem: the step arrows resting in the muted grey outline-secondary
   gives them. --bs-emphasis-color is the theme's strongest text colour, so this lightens them on dark
   and darkens them on light without either being spelled out. Only the resting colour is set, leaving
   the disabled colour above to do its job. */
.debug-step-btn {
    --bs-btn-color: var(--bs-emphasis-color);
    --bs-btn-border-color: var(--bs-border-color);
}

/* The connection note changes with the Server / Browser choice, and the two are not the same length —
   so pressing one moved everything under it. One height for both, tall enough for the longest, with a
   shorter note centered in it rather than sitting at the top of the space it does not fill. */
.gdbv-route-note {
    min-height: 5.5rem;
    display: flex;
    flex-direction: column;
    justify-content: center;
}

/* The three ways of filling the source box stand side by side, so they are the same height whichever
   one you look at first. */
.gdbv-source-text,
.gdbv-dropzone {
    height: 9.5em;
}

.gdbv-source-text {
    resize: vertical;
}

/* A plain panel that happens to be a drop target. The file input covering it is what actually catches
   the file; this is only what you see. */
.gdbv-dropzone {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 0.5rem;
    border: 1px dashed var(--bs-border-color);
    border-radius: var(--bs-border-radius);
    color: var(--bs-secondary-color);
}

.gdbv-dropzone:hover,
.gdbv-dropzone-over {
    border-color: var(--bs-primary);
    color: var(--bs-body-color);
}

/* Stretched over the panel and invisible: a native file input already accepts a dropped file, so this
   is drag-and-drop and click-to-browse from one element rather than two that have to agree. */
.gdbv-dropzone-input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
}

h1:focus {
    outline: none;
}

a, .btn-link {
    color: #0071c1;
}

.btn-primary {
    color: #fff;
    background-color: #1b6ec2;
    border-color: #1861ac;
}

/* Renders an outline button in its filled hover style by default (Load DB, Schema, Debug):
   point the default color variables at the button's hover variables. !important so these win over
   the higher-specificity [data-bs-theme=dark] .btn-outline-* rules (otherwise the text stays the
   un-filled color and vanishes on the filled background). */
.btn-hover-default {
    --bs-btn-bg: var(--bs-btn-hover-bg) !important;
    --bs-btn-border-color: var(--bs-btn-hover-border-color) !important;
    --bs-btn-color: var(--bs-btn-hover-color) !important;
    /*Keep the filled look while disabled too (Bootstrap's disabled opacity still dims it),
      so a disabled Debug button matches the enabled Load DB / Schema buttons.*/
    --bs-btn-disabled-bg: var(--bs-btn-hover-bg) !important;
    --bs-btn-disabled-border-color: var(--bs-btn-hover-border-color) !important;
    --bs-btn-disabled-color: var(--bs-btn-hover-color) !important;
}

/* Debug half of the Run|Debug split button. btn-hover-default fills it solid blue, which in dark
   mode reads as a lighter blue distinct from the Run button — but in light mode it's the same solid
   primary blue as Run, so the two halves are indistinguishable. Keep the filled look in dark mode,
   and render it as an outline in light mode so the split is legible. */
:root[data-bs-theme="light"] .debug-split-btn {
    --bs-btn-bg: transparent !important;
    --bs-btn-border-color: var(--bs-primary) !important;
    --bs-btn-color: var(--bs-primary) !important;
    --bs-btn-disabled-bg: transparent !important;
    --bs-btn-disabled-border-color: var(--bs-primary) !important;
    --bs-btn-disabled-color: var(--bs-primary) !important;
}

/* Toolbar label text (Style, Data model): #dee2e6 reads well on the dark buttons, but is nearly
   invisible on the light-mode outline buttons — swap to a readable dark gray there. */
/* The connection's address preview. Muted, because it is derived rather than typed, but readable:
   it is the line that says what the Connect button is about to dial. */
.gdbv-url-preview {
    color: var(--bs-body-color);
    opacity: 0.75;
}

/* The 2D / 3D coordinate boxes. Short, because they hold a number, and short in height too: the panel
   they live in is a column of sections competing for the same screen. */
.gdbv-coord-input {
    width: 62px;
    flex: 0 0 auto;
    padding-top: 0.1rem;
    padding-bottom: 0.1rem;
}

.gdbv-coord-clear {
    padding: 0.1rem 0.35rem;
}

/* The property row's minus and the add-connection plus. Both stand beside a full-height input, so they
   share that height already; this only makes them the same width as each other. Deliberately NOT applied
   to the buttons that remove a connection — those sit in a small text line, where a full-height block
   would tower over the row it belongs to. */
.gdbv-row-btn {
    height: 31px;
    min-width: 31px;
    padding-left: 0;
    padding-right: 0;
    flex-shrink: 0;
}

/* The buttons floating over the editors. An outline button has no background, so over code its glyph
   competes with whatever token happens to be behind it — a trash icon on top of a red string literal is
   nearly invisible. Give them the page's own background, mostly opaque, so they read as controls sitting
   above the text rather than as more of it. */
.gdbv-editor-float > .btn {
    --bs-btn-bg: rgba(var(--bs-body-bg-rgb), 0.88);
    backdrop-filter: blur(2px);
}

/* The property panel's header row. A long element id used to squeeze the buttons beside it until their
   icon and label folded onto two lines, which turned a normal button into a tall block. The id is the
   thing with slack, so it is the thing that wraps; the buttons keep their shape. */
.gdbv-element-header > .btn {
    flex-shrink: 0;
    white-space: nowrap;
}

.gdbv-element-id {
    min-width: 0;
    overflow-wrap: anywhere;
}

.gdbv-btn-label { color: #dee2e6; }
:root[data-bs-theme="light"] .gdbv-btn-label {
    color: #495057;
}

/* Light mode: fill the neutral (outline-secondary) buttons — zoom −/+, center, filter, style,
   Data model, etc. — with a light gray on hover/active instead of Bootstrap's default dark-gray,
   and keep their text dark so it stays readable. Matches the Data model button. */
:root[data-bs-theme="light"] .btn-outline-secondary {
    --bs-btn-hover-bg: #e9ecef;
    --bs-btn-hover-border-color: #ced4da;
    --bs-btn-hover-color: #495057;
    --bs-btn-active-bg: #dee2e6;
    --bs-btn-active-border-color: #ced4da;
    --bs-btn-active-color: #495057;
}

/* Monochrome action icons: alpha-masked so each one takes its button's text color
   (white on filled buttons, the accent color on outline buttons, adapting to dark mode).
   Paths are relative to this stylesheet (wwwroot/css/), so ../icons/ points at wwwroot/icons/. */
.btn-ico {
    display: inline-block;
    width: 1em;
    height: 1em;
    vertical-align: -0.125em;
    margin-right: 0.35em;
    background-color: currentColor;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
    -webkit-mask-size: contain;
    mask-size: contain;
}

.btn-ico.ico-connect { -webkit-mask-image: url('../icons/connect.png');   mask-image: url('../icons/connect.png'); }
.btn-ico.ico-play    { -webkit-mask-image: url('../icons/startClock.png'); mask-image: url('../icons/startClock.png'); }
.btn-ico.ico-stop    { -webkit-mask-image: url('../icons/stopClock.png');  mask-image: url('../icons/stopClock.png'); }
.btn-ico.ico-step    { -webkit-mask-image: url('../icons/stepClock.png');  mask-image: url('../icons/stepClock.png'); }
.btn-ico.ico-save    { -webkit-mask-image: url('../icons/saveFile.png');   mask-image: url('../icons/saveFile.png'); }
.btn-ico.ico-copy    { -webkit-mask-image: url('../icons/copy.png');       mask-image: url('../icons/copy.png'); }
.btn-ico.ico-program { -webkit-mask-image: url('../icons/program.png');    mask-image: url('../icons/program.png'); }

/* Focus ring. On buttons it shows only for keyboard focus (:focus-visible) so a mouse click doesn't
   leave a blue outline lingering until the next click; form fields keep it on any focus so the active
   field stays marked. */
.btn:focus-visible, .btn-link.nav-link:focus-visible {
  box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
}

.form-control:focus, .form-check-input:focus {
  box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
}

.content {
    padding-top: 1.1rem;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid red;
}

.validation-message {
    color: red;
}

#blazor-error-ui {
    color-scheme: light only;
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

    #blazor-error-ui .dismiss {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

.loading-progress {
    position: absolute;
    display: block;
    width: 8rem;
    height: 8rem;
    inset: 20vh 0 auto 0;
    margin: 0 auto 0 auto;
}

    .loading-progress circle {
        fill: none;
        stroke: #e0e0e0;
        stroke-width: 0.6rem;
        transform-origin: 50% 50%;
        transform: rotate(-90deg);
    }

        .loading-progress circle:last-child {
            stroke: #1b6ec2;
            stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
            transition: stroke-dasharray 0.05s ease-in-out;
        }

.loading-progress-text {
    position: absolute;
    text-align: center;
    font-weight: bold;
    inset: calc(20vh + 3.25rem) 0 auto 0.2rem;
}

    .loading-progress-text:after {
        content: var(--blazor-load-percentage-text, "Loading");
    }

/*The host page renders the boot indicator alongside <Routes>, which stays empty until the WebAssembly
  runtime has started — prerendering is off, so there is nothing to replace it. MainLayout's .page wrapper
  is the first thing the started app puts on the page, so it doubles as the signal to hide the indicator.*/
#app:has(.page) > .loading-progress,
#app:has(.page) > .loading-progress-text {
    display: none;
}

code {
    color: #c02d76;
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
    color: var(--bs-secondary-color);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
    text-align: start;
}

/* Dark mode: the default primary blue (#0d6efd / #0071c1) is hard to read on a dark
   background. Lighten the blue text/links/outline-buttons and bump the weight a touch
   so things like "Load DB", "Edit", the mode buttons and "About" stay legible. */
[data-bs-theme="dark"] a,
[data-bs-theme="dark"] .btn-link,
[data-bs-theme="dark"] .text-primary {
    color: #6ea8fe !important;
    font-weight: 500;
}

[data-bs-theme="dark"] .btn-outline-primary {
    --bs-btn-color: #6ea8fe;
    --bs-btn-border-color: #6ea8fe;
    --bs-btn-hover-bg: #6ea8fe;
    --bs-btn-hover-color: #04132b;
    --bs-btn-hover-border-color: #6ea8fe;
    --bs-btn-active-bg: #6ea8fe;
    --bs-btn-active-border-color: #6ea8fe;
    font-weight: 500;
}

[data-bs-theme="dark"] .nav-tabs .nav-link {
    color: #6ea8fe;
    font-weight: 500;
}
/*The selected tab (both the main query/data-model tabs and the Query/Generated/Examples/History
  sub-tabs) reads white so it stands out from the blue inactive ones on the dark tab strip.*/
[data-bs-theme="dark"] .nav-tabs .nav-link.active {
    color: #fff;
}
/*Query debugger: highlight each traversal step in the editor; the focused step is stronger.*/
.debug-step {
    background: rgba(13, 110, 253, 0.12);
    border-bottom: 1px dashed rgba(13, 110, 253, 0.6);
    cursor: pointer;
}

.debug-step-active {
    background: rgba(253, 126, 20, 0.30);
    border-bottom: 2px solid rgba(253, 126, 20, 0.9);
}

/*The nested sub-traversal step the cursor stepped into (sits inside the active step's range).*/
.debug-step-cursor {
    background: rgba(25, 135, 84, 0.38);
    border-bottom: 2px solid rgba(25, 135, 84, 0.95);
}

/*Small badge behind just the ladybug icon in the debugger title, in the Debug button's blue (#6ea8fe),
  so the icon's black outline reads — no full title-bar background.*/
.gdbv-debug-badge {
    background-color: #6ea8fe;
    border-radius: 0.3rem;
    padding: 0.15rem 0.3rem;
}

/*The debugger header reads as a top bar: a full-width divider line under the title, tabs and ✕. The
  negative side margins reach the panel's edges (the panel has p-2 = 0.5rem), the padding restores the
  content position and leaves room above the line.*/
.gdbv-debug-header {
    border-bottom: 1px solid var(--bs-border-color);
    margin-left: -0.5rem;
    margin-right: -0.5rem;
    padding: 0 0.5rem 0.5rem 0.5rem;
}

/*Table view: size each column to its content so a value stays on one line, instead of Bootstrap's
  width:100% squeezing every column until the text wraps. min-width keeps a small table filling the
  card. Any one column stops growing at 300px — longer text wraps inside that — and once the columns
  together outgrow the card, its container scrolls horizontally.*/
.gdbv-data-table {
    width: max-content;
    min-width: 100%;
}

.gdbv-data-table td,
.gdbv-data-table th {
    max-width: 300px;
    overflow-wrap: break-word;
}

/*The gdbv* column headers carry the same blue as the "Additional properties" link that reveals them
  (the .btn-link / a color above), so the two read as one feature and stand apart from the real data
  columns' black.
  The shade is hard-coded rather than inherited: the header keeps Bootstrap's .table-light background,
  which stays light in BOTH themes, so it needs the link's light-mode blue either way. Following the
  theme would swap in the dark-mode blue (#6ea8fe) — lightened for dark cards — which washes out
  against this permanently light header, as --bs-secondary-color did. Keep in step with the link color
  above. Only the headers are colored: the body cells keep the row's own text color, which a colored
  label row sets for contrast.*/
.gdbv-data-table th.gdbv-extra-col {
    color: #0071c1;
}

/*The linked image / 3D model previewed under its URL, once the column's "preview" box is ticked. Both
  get the same box, so the two preview columns line up. The model box needs a definite width anyway
  (its three.js canvas sizes to the container); the image gets the matching size explicitly, with
  scale-down to letterbox it inside — keeping its aspect and never blowing a small image up.*/
.gdbv-data-table img.gdbv-cell-preview,
.gdbv-data-table div.gdbv-cell-preview {
    width: 220px;
}

.gdbv-data-table img.gdbv-cell-preview {
    display: block;
    height: 170px;
    object-fit: scale-down;
    border-radius: 4px;
    background: rgba(127, 127, 127, 0.08);
}

/*The AI popups. Windows, not modals: fixed where they were dragged, resized from the corner grip, and
  with nothing behind them dimmed or blocked, so the editor and canvas stay usable while one is open.*/
.gdbv-dialog {
    position: fixed;
    z-index: 1060;
    min-width: 380px;
    min-height: 240px;
    max-width: 100vw;
    max-height: 100vh;
    /*The grip below does the resizing, so the browser's own is off: it draws a few faint pixels with a
      hit area to match, which is neither findable nor easy to aim at.*/
    overflow: hidden;
}

.gdbv-dialog-resize {
    position: absolute;
    /*Set in from the corner rather than pressed against it, and big enough to aim at. It has to stay
      clear of whatever sits at the bottom of the window: the Ask AI composer keeps a right margin for
      it (see .gdbv-dialog-composer), which is what lets this be a target rather than a sliver.*/
    right: 6px;
    bottom: 6px;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    cursor: nwse-resize;
    color: var(--bs-body-color);
    opacity: 0.85;
    /*Above the footer buttons it overlaps, and never selectable as text mid-drag.*/
    z-index: 1;
    user-select: none;
}

.gdbv-dialog-resize:hover {
    opacity: 1;
    color: var(--bs-emphasis-color);
}

.gdbv-dialog-header {
    cursor: move;
    /*A drag that starts on the bar should move the window, never select its title.*/
    user-select: none;
}

/*The Ask AI conversation: a scrolling transcript that takes whatever height the window has left.*/
.gdbv-chat {
    flex: 1 1 auto;
    min-height: 8em;
    overflow-y: auto;
}

/*The kinds of turn read as different shades, so a glance down the transcript tells you who was talking
  and where the database was touched. Alpha over whatever the theme's background is, the way the rest of
  this file tints things, so the same rule works in the dark theme and both light ones.*/
/* The asker's turn, in the blue this app already uses for anything you can click — Load DB, links, the
   outline buttons. It was bg-primary-subtle, which is Bootstrap's, and in the dark theme that is a navy
   sitting so close to the panel behind it that the bubble barely read as one. Tinted rather than solid,
   so the text keeps the body color and stays legible in both themes. */
/* The knowledge-graph panel's instruction box and the row of controls beneath it, kept the same width
   so the dropdowns at the right of the row end exactly where the box above them ends. The floor is
   there because the Generate button grows a long label while it runs ("Extracting piece 1 of 12…"),
   which at a narrower cap pushed the dropdowns onto a second row halfway through a generation. */
.gdbv-kg-actions {
    max-width: 65%;
    min-width: min(34rem, 100%);
}

/*The row along the bottom of a dialog stops short of the resize grip in the corner, so the grip has
  room to be a real target and the last control in the row keeps all of itself.*/
.gdbv-dialog-composer {
    padding-right: 22px;
}

.gdbv-chat-user {
    background-color: rgba(var(--bs-primary-rgb), 0.18);
}

[data-bs-theme="dark"] .gdbv-chat-user {
    /* #6ea8fe is the blue the dark theme already lightens links and outline buttons to, below. */
    background-color: rgba(110, 168, 254, 0.25);
}

.gdbv-chat-assistant {
    background-color: rgba(var(--bs-body-color-rgb), 0.10);
}

/*A read the model ran, and a write it ran. Two classes rather than one with a modifier because they
  differ in what they mean, not in degree: amber for something that looked, red for something that changed.
  Specific enough to beat .card, whose own background would otherwise win by source order.*/
.card.gdbv-chat-tool {
    background-color: rgba(var(--bs-warning-rgb), 0.16);
}

.card.gdbv-chat-tool-write {
    background-color: rgba(var(--bs-danger-rgb), 0.16);
}

.gdbv-chat-bubble {
    max-width: 85%;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.gdbv-chat-code {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    max-height: 14em;
    overflow: auto;
}
