/* Colours, header, buttons and panels come from eknir-ui.css (shared by all apps). Only what is
   specific to the mapper canvas is defined here. */
:root {
    --accent-hover: #4f52d9;
    --warning: #fff4d6;
    --warning-text: #6b4e00;

    /* Canvas palette. */
    --chip-src-bg: #eef0ff;
    --chip-src-border: #6366f1;
    --col-src-bg: #f8f8ff;
    --chip-tgt-bg: #e6f7ee;
    --chip-tgt-border: #2fa66a;
    --col-tgt-bg: #f6fbf8;
    --functoid-bg: #fff7e0;
    --functoid-border: #f0a52a;
    --link: #7c7ff3;
    --link-highlight: #4338ca;
    /* Repetition: red, because it is the one relation in the map that multiplies the output. */
    --loop: #e5484d;

    /* The two column widths are rewritten by canvas.js while a splitter is dragged. They live on
       the root element, which Blazor never re-renders, so a resize survives a server render. */
    --col-src-w: 16rem;
    --col-tgt-w: 16rem;

    --sidebar-w: 7.75rem;
    --status-h: 1.75rem;
    --top-h: 4.5rem;
}

:root[data-theme="dark"] {
    --accent-hover: #7f82f5;
    --warning: #3d3210; --warning-text: #ffd98a;
    --chip-src-bg: #232a5c; --chip-src-border: #7c7ff3; --col-src-bg: #151935;
    --chip-tgt-bg: #17342a; --chip-tgt-border: #4cc58a; --col-tgt-bg: #131f24;
    --functoid-bg: #3a2f14; --functoid-border: #f0a52a;
    --link: #8b8ef5; --link-highlight: #c0c2ff;
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --accent-hover: #7f82f5;
        --warning: #3d3210; --warning-text: #ffd98a;
        --chip-src-bg: #232a5c; --chip-src-border: #7c7ff3; --col-src-bg: #151935;
        --chip-tgt-bg: #17342a; --chip-tgt-border: #4cc58a; --col-tgt-bg: #131f24;
        --functoid-bg: #3a2f14; --functoid-border: #f0a52a;
        --link: #8b8ef5; --link-highlight: #c0c2ff;
    }
}

/* The canvas is dense, so it keeps a smaller base size than the 15px of the shared header. */
body { font-size: 13px; }

h1 { font-size: 1.6rem; }
h2 { font-size: .8rem; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); margin: 0 0 .5rem; }

/* ---- Shell ---- */

/* One grid for the whole page: header, menu and content are placed per layout (see "Layouts" below).
   .topbar and .shell only group markup, so they do not take part in the layout themselves. */
.app {
    height: 100vh;
    display: grid;
    padding: 0 28px 24px;
    column-gap: 14px;
}

.topbar, .shell { display: contents; }

.brand { grid-area: brand; display: flex; align-items: center; gap: 10px; height: var(--top-h); }
.hdr-actions { grid-area: tools; display: flex; align-items: center; justify-self: end; height: var(--top-h); }

/* Blazor focuses the first <h1> on load (FocusOnNavigate); a title is not interactive, so no focus ring. */


.content {
    grid-area: content;
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    overflow: hidden;
}

/* ---- Menu ---- */

/* In the top layout the menu is the shared .tabs / .tab pill bar (eknir-ui.css), so nothing is repeated
   for it here. Everything below that is prefixed with data-layout="side" is the first layout: a sidebar. */

:root[data-layout="side"] .sidebar {
    margin: 0;
    grid-area: nav;
    flex: 0 0 var(--sidebar-w);
    width: var(--sidebar-w);
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: .25rem;
    padding: .6rem .5rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    overflow-y: auto;
}
:root[data-layout="side"] .side-section {
    margin-top: .5rem;
    padding: 0 .2rem;
    font-size: .65rem;
    font-weight: 600;
    letter-spacing: .08em;
    color: var(--muted);
}

/* Icon above caption, like the desktop app's ribbon-style buttons. Used on both <button> and
   <label> (the file pickers), so everything here has to work for either element. */
:root[data-layout="side"] .side-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .15rem;
    width: 100%;
    padding: .4rem .25rem;
    font: inherit;
    text-align: center;
    color: var(--text);
    background: transparent;
    border: 1px solid transparent;
    border-radius: 12px;
    cursor: pointer;
}

:root[data-layout="side"] .side-btn svg { width: 20px; height: 20px; flex: 0 0 auto; }
:root[data-layout="side"] .side-btn .cap { font-size: .7rem; line-height: 1.2; }

:root[data-layout="side"] .side-btn:hover:not(:disabled):not(.disabled) { background: var(--surface-3); border-color: var(--border); }
:root[data-layout="side"] .side-btn:disabled,
:root[data-layout="side"] .side-btn.disabled { opacity: .45; cursor: default; pointer-events: none; }

/* The main action: outlined and a size up, not filled — a filled one reads as an active toggle,
   which is what .side-btn.on means here. The :not() pair is there to match the generic hover
   rule's specificity, which would otherwise drop the accent border. */
:root[data-layout="side"] .side-btn.accent {
    color: var(--accent);
    border-color: var(--accent);
    padding: .5rem .25rem;
    font-weight: 600;
}

:root[data-layout="side"] .side-btn.accent svg { width: 22px; height: 22px; }
:root[data-layout="side"] .side-btn.accent .cap { font-size: .74rem; }

:root[data-layout="side"] .side-btn.accent:hover:not(:disabled):not(.disabled) {
    background: var(--surface-3);
    border-color: var(--accent);
}

/* A toggle that is on gets the accent as a filled state, so it is readable without the tooltip. */
:root[data-layout="side"] .side-btn.on {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--accent-text);
}

/* Beats the generic .side-btn:hover, which would otherwise grey out an active toggle. */
:root[data-layout="side"] .side-btn.on:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.side-btn input[type=file] { display: none; }



/* Both layouts. */
.side-btn:disabled, .side-btn.disabled { opacity: .45; cursor: default; pointer-events: none; }
/* ---- Banners ---- */

.banner {
    flex: 0 0 auto;
    padding: .5rem .75rem;
    border-bottom: 1px solid var(--border);
}

.banner.error {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    background: var(--danger);
    color: #fff;
}

.banner.error button { background: transparent; border: none; color: #fff; }
.banner.warning { background: var(--warning); color: var(--warning-text); }
.banner.warning summary { cursor: pointer; font-weight: 600; }
.banner.warning ul { margin: .5rem 0 0; padding-left: 1.2rem; }
.banner.warning li { margin-bottom: .35rem; }

.hint { color: var(--muted); }
.pad { padding: .6rem; }
.error-text { color: var(--danger); margin: 0 0 .5rem; }

/* ---- Canvas ---- */

/* Source column, splitter, the functoid area, splitter, target column. The link overlay is
   absolutely positioned over the whole grid, which is why this is the positioning context. */
.canvas {
    position: relative;
    flex: 1;
    min-height: 0;
    display: grid;
    grid-template-columns: var(--col-src-w) 5px minmax(0, 1fr) 5px var(--col-tgt-w);
    background: var(--border);
    gap: 0;
}

.col { display: flex; flex-direction: column; min-width: 0; overflow: hidden; }
.col-src { background: var(--col-src-bg); }
.col-tgt { background: var(--col-tgt-bg); }

.col-head {
    flex: 0 0 auto;
    padding: .35rem .5rem .2rem;
    font-size: .65rem;
    font-weight: 600;
    letter-spacing: .08em;
    color: var(--muted);
    background: var(--surface-2);
}

/* The schema button for this pane, between the header and the search box. Two rows with the icon
   spanning both: caption on top, loaded file name underneath, so neither has to be tiny. */
.col-load {
    flex: 0 0 auto;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: center;
    column-gap: .5rem;
    margin: .15rem .5rem .4rem;
    padding: .45rem .55rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, .06);
    cursor: pointer;
    transition: background .12s, border-color .12s;
}

.col-load svg { grid-row: 1 / span 2; width: 22px; height: 22px; color: var(--muted); }
.col-load .cap { font-size: .78rem; font-weight: 600; line-height: 1.25; }
.col-load input[type=file] { display: none; }

/* Clipped rather than allowed to widen the column, which the splitter owns. */
.col-load .file {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: .65rem;
    line-height: 1.25;
    color: var(--muted);
}

/* Recognised standard or system: a quiet third line under the file name. The dot takes the pane's
   own colour and fades with confidence, so a guess never looks as certain as a certainty. */
.col-load .ident {
    grid-column: 2;
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    min-width: 0;
    margin-top: .1rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: .62rem;
    font-weight: 600;
    line-height: 1.25;
    color: var(--text);
    opacity: .75;
}

.col-load .ident i {
    flex: 0 0 auto;
    width: .42rem;
    height: .42rem;
    border-radius: 50%;
    background: var(--dot, var(--muted));
}

.col-src .col-load .ident { --dot: var(--chip-src-border); }
.col-tgt .col-load .ident { --dot: var(--chip-tgt-border); }
.col-load .ident.medium i { opacity: .55; }
.col-load .ident.low i { background: transparent; box-shadow: inset 0 0 0 1.5px var(--dot, var(--muted)); }

/* Hover picks up the column's own chip colour, so the button reads as part of its pane. */
.col-load:hover { background: var(--surface-3); }
.col-src .col-load:hover { border-color: var(--chip-src-border); }
.col-src .col-load:hover svg { color: var(--chip-src-border); }
.col-tgt .col-load:hover { border-color: var(--chip-tgt-border); }
.col-tgt .col-load:hover svg { color: var(--chip-tgt-border); }

/* Sibling of the header, above the scrolling body: it must not scroll away with the fields. */
.search {
    flex: 0 0 auto;
    margin: 0 .5rem .35rem;
    padding: .25rem .4rem;
    font: inherit;
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 10px;
}

.col-body {
    flex: 1;
    min-height: 0;
    overflow: auto;
    padding: .1rem 0 2rem;
    border-top: 1px solid var(--border);
}

/* No left padding: the row's inline style sets padding-left for the tree indent and would
   otherwise override it away, leaving depth-0 chips flush against the column edge. */
.row { display: flex; padding: 1px .5rem 1px 0; }

/* A chip is the link endpoint: canvas.js reads its bounding box, so it must be the element that
   carries data-anchor and must not be wider than the text it holds. */
.chip {
    display: inline-flex;
    align-items: baseline;
    gap: .35rem;
    max-width: 100%;
    padding: .12rem .45rem;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface);
    cursor: pointer;
    user-select: none;
}

.chip.src { background: var(--chip-src-bg); border-color: var(--chip-src-border); }
.chip.tgt { background: var(--chip-tgt-bg); border-color: var(--chip-tgt-border); }

/* Containers are structure, not endpoints: no fill, and the twisty carries the affordance. */
.chip.container { background: transparent; border-color: transparent; font-weight: 600; color: var(--muted); }
.chip.container:hover { background: color-mix(in srgb, var(--accent) 10%, transparent); }

.chip.selected { outline: 2px solid var(--accent); outline-offset: 0; }
.chip.mapped { box-shadow: inset 3px 0 0 var(--ok); }

/* Both ends of a repetition: the red rule under the chip says this element is written once per
   record, and marks it even while the other end of the line is scrolled away or collapsed. Inset,
   so it costs no height and the rows do not shift when a mapping starts looping. */
.chip.looped { box-shadow: inset 0 -2px 0 var(--loop); }
.chip.mapped.looped { box-shadow: inset 3px 0 0 var(--ok), inset 0 -2px 0 var(--loop); }

.chip:hover { filter: brightness(.97); }

/* Shows where a dragged field or functoid may be dropped; set by canvas.js during the drag. */
.chip.drop-ok, .functoid.drop-ok { outline: 2px dashed var(--accent); outline-offset: 1px; }

/* While a link is being dragged the transparent hit strokes of the lines must not sit in front of the
   chips, or the chip under a line could not be hit-tested as the drop target. Selecting text is off
   for the duration too, so dragging across the labels does not smear a selection over both columns. */
body.linking { user-select: none; }
body.linking .link-hit { pointer-events: none; }

.chip-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chip-type { flex: 0 0 auto; font-size: .8em; color: var(--muted); }
.twisty { flex: 0 0 auto; width: .7rem; color: var(--muted); }

/* ---- Functoid area ---- */

/* overflow:hidden, not auto: there are no scrollbars here, panning is the way around. It is still a
   scroll container, so canvas.js can move it with scrollLeft/scrollTop. */
.canvas-mid {
    background: var(--surface);
    overflow: hidden;
    position: relative;
    touch-action: none;
    cursor: grab;
}

.canvas-mid.panning { cursor: grabbing; }

/* Bigger than the viewport so functoids can be dragged out and the area panned to reach them. */
.canvas-inner { position: relative; width: 3000px; height: 2000px; }

/* Centred over the functoid area: the offsets are the two column widths plus a splitter, the same
   vars the grid uses, so it stays put while a splitter is dragged. */
.canvas-title {
    position: absolute;
    top: 0;
    left: calc(var(--col-src-w) + 5px);
    right: calc(var(--col-tgt-w) + 5px);
    text-align: center;
    pointer-events: none;
}

/* A tab hanging from the top edge, so the label is only as wide as its text. */
.canvas-title span {
    display: inline-block;
    padding: .2rem .75rem .25rem;
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .08em;
    color: var(--muted);
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-top: none;
    border-radius: 0 0 10px 10px;
}

.canvas-hint {
    position: absolute;
    top: 2.2rem;
    left: 1rem;
    right: 1rem;
    color: var(--muted);
    pointer-events: none;
}

.functoid {
    position: absolute;
    display: flex;
    flex-direction: column;
    line-height: 1.3;
    min-width: 6.5rem;
    max-width: 12rem;
    padding: .25rem .45rem;
    background: var(--functoid-bg);
    border: 1px solid var(--functoid-border);
    border-radius: 10px;
    cursor: move;
    user-select: none;
    touch-action: none;
}

.functoid-name { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.functoid-inputs { font-size: .75rem; color: var(--muted); }

/* ---- Link overlay ---- */

/* Transparent to the mouse as a whole, so chips underneath stay clickable; only the hit paths
   opt back in, and only along their stroke. */
.link-overlay {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
    overflow: visible;
}

.link-path { fill: none; stroke: var(--link); stroke-width: 1.6; }
.link-path.hl { stroke: var(--link-highlight); stroke-width: 2.6; }

/* The line that follows the pointer while a link is being dragged: dashed, so it reads as a
   proposal rather than as a mapping that already exists. */
.link-path.dragging { stroke: var(--accent); stroke-dasharray: 5 3; }

/* One xsl:for-each: the target record on the right is written once per source record on the left.
   Dashed and red, because it is not a value that flows but a repetition of everything below it, and
   unlike a link there is nothing to right-click — it follows from the schemas, not from an edit. */
.loop-path { fill: none; stroke: var(--loop); stroke-width: 1.8; stroke-dasharray: 7 4; }

.link-hit {
    fill: none;
    stroke: transparent;
    stroke-width: 12;
    pointer-events: stroke;
    cursor: context-menu;
}

/* ---- Splitters ---- */

.splitter { background: var(--border); cursor: col-resize; touch-action: none; }
.splitter:hover { background: var(--accent); }

/* ---- Context menu ---- */

.ctx-backdrop { position: fixed; inset: 0; z-index: 40; }

.ctx-menu {
    position: fixed;
    z-index: 41;
    min-width: 12rem;
    padding: .2rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    box-shadow: var(--shadow);
}

.ctx-item {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .5rem;
    width: 100%;
    padding: .3rem .5rem;
    font: inherit;
    text-align: left;
    color: var(--text);
    background: transparent;
    border: none;
    border-radius: 8px;
    cursor: pointer;
}

.ctx-item:hover { background: var(--surface-3); }
.ctx-item.danger { color: var(--danger); }
.ctx-arrow { color: var(--muted); }
.ctx-sep { height: 1px; margin: .2rem .3rem; background: var(--border); }

/* Hover-revealed submenu: no state on the server for opening it. */
.ctx-sub {
    display: none;
    position: absolute;
    top: -.2rem;
    left: 100%;
    min-width: 11rem;
    padding: .2rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    box-shadow: var(--shadow);
}

.ctx-item.has-sub:hover > .ctx-sub, .ctx-sub:hover { display: block; }

/* ---- Status ---- */

.status {
    flex: 0 0 auto;
    height: var(--status-h);
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: 0 .75rem;
    background: var(--surface-2);
    border-top: 1px solid var(--border);
    color: var(--muted);
}

.status > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Indeterminate: the AI call gives no progress to report, only that it is running. */
.progress {
    flex: 0 0 8rem;
    height: .4rem;
    border-radius: 2px;
    background: var(--surface-3);
    overflow: hidden;
}

.progress::after {
    content: "";
    display: block;
    width: 40%;
    height: 100%;
    background: var(--accent);
    animation: progress-slide 1.1s ease-in-out infinite;
}

@keyframes progress-slide {
    0% { transform: translateX(-100%); }
    100% { transform: translateX(250%); }
}

/* ---- BizTalk script panel ---- */

.script-panel {
    flex: 0 0 auto;
    max-height: 40vh;
    padding: .4rem .75rem .6rem;
    background: var(--surface-2);
    border-top: 1px solid var(--border);
    overflow: auto;
}

.script-panel summary { cursor: pointer; color: var(--muted); font-weight: 600; }

.script-panel textarea {
    width: 100%;
    min-height: 8rem;
    margin-top: .4rem;
    padding: .4rem;
    font: 12px/1.45 Consolas, "Cascadia Mono", monospace;
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 10px;
    resize: vertical;
}

/* ---- Modal ---- */

.modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(14, 16, 32, .5);
}

.modal {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: min(30rem, calc(100vw - 2rem));
    padding: 1.25rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: 0 24px 60px -16px rgba(0, 0, 0, .5);
}

.modal h2 { color: var(--text); font-size: 1rem; text-transform: none; letter-spacing: 0; }
.modal label { display: block; margin-bottom: .75rem; color: var(--muted); }
.modal input, .modal select, .modal textarea {
    display: block;
    width: 100%;
    margin-top: .2rem;
    padding: .35rem .5rem;
    font: inherit;
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 10px;
}

/* The one label in the dialog that is a tick box: those want the box beside the text instead of a
   full-width field under it, so both rules above have to be undone for it. */
.modal label.check { display: flex; align-items: center; gap: .45rem; margin-bottom: .35rem; color: var(--text); }
.modal label.check input { display: inline-block; width: auto; margin: 0; }
/* Explains the tick box it sits under, so it hangs closer to it than a paragraph would. */
.modal .hint.sub { margin: 0 0 .75rem; font-size: .78rem; }
.modal h3 { margin: 1rem 0 .35rem; padding-top: .75rem; border-top: 1px solid var(--border); color: var(--text); font-size: .9rem; }
.modal .api-info { margin: 0; font-size: .82rem; line-height: 1.6; word-break: break-all; }
.modal .api-info code { font: 12px Consolas, "Cascadia Mono", monospace; color: var(--text); }

.modal textarea.code {
    font: 12px/1.45 Consolas, "Cascadia Mono", monospace;
    resize: vertical;
}

.root-choices { max-height: 50vh; overflow-y: auto; margin-bottom: .5rem; }
.root-choices label.check { align-items: baseline; padding: .25rem 0; }
.root-choices label.all { border-top: 1px solid var(--border); margin-top: .25rem; padding-top: .5rem; }
.root-choices .hint { margin-left: .4rem; }
.root-choices .badge {
    margin-left: .4rem;
    padding: .05rem .45rem;
    font-size: .72rem;
    color: var(--accent);
    border: 1px solid currentColor;
    border-radius: 999px;
}

.modal-actions { display: flex; justify-content: flex-end; gap: .5rem; margin-top: 1rem; }

/* Referenced files: one row per schemaLocation, with a tick, a cross or an open circle in front. */
.modal.wide { width: min(40rem, calc(100vw - 2rem)); }
.modal label.btn { display: inline-flex; align-items: center; margin: 0; color: var(--text); cursor: pointer; }
.modal label.btn input[type=file] { display: none; }
.modal-actions .several { margin-right: auto; }
.ref-files { list-style: none; margin: 0; padding: 0; max-height: 50vh; overflow-y: auto; border: 1px solid var(--border); border-radius: 10px; }
.ref-files li { display: grid; grid-template-columns: 1.2rem minmax(0, 1fr) auto; gap: .75rem; align-items: center; padding: .55rem .8rem; }
.ref-files li + li { border-top: 1px solid var(--border); }
.ref-files .mark { font-weight: 700; color: var(--muted); text-align: center; }
.ref-files .good .mark { color: var(--ok); }
.ref-files .bad .mark { color: var(--danger); }
.ref-files .file { font-family: var(--mono); font-size: .82rem; font-weight: 600; overflow-wrap: anywhere; }
.ref-files .where { color: var(--muted); font-size: .75rem; overflow-wrap: anywhere; }
.ref-files .msg { color: var(--danger); font-size: .8rem; margin-top: .1rem; }

#blazor-error-ui {
    display: none;
    position: fixed;
    bottom: 0;
    width: 100%;
    padding: .6rem 1.25rem;
    background: #ffc;
    color: #333;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, .2);
    z-index: 1000;
}

#blazor-error-ui .dismiss { cursor: pointer; float: right; }

/* ---- Layouts ---- */

/* "side" (the first layout): icon sidebar on the left, canvas next to it. */
:root[data-layout="side"] .app {
    grid-template-columns: var(--sidebar-w) minmax(0, 1fr) auto;
    grid-template-rows: auto minmax(0, 1fr);
    grid-template-areas: "brand brand tools" "nav content content";
}

/* Default: the menu is the shared pill bar next to the brand, like the tabs in XMLtools. */
:root:not([data-layout="side"]) .app {
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-rows: auto minmax(0, 1fr);
    grid-template-areas: "brand nav tools" "content content content";
    /* Same header geometry as XMLtools: 16px above and below the bar, 20px between brand and menu. */
    padding-top: 16px;
    column-gap: 20px;
    row-gap: 16px;
}

:root:not([data-layout="side"]) .brand,
:root:not([data-layout="side"]) .hdr-actions { height: auto; }

:root:not([data-layout="side"]) .sidebar {
    grid-area: nav;
    font-size: 15px;            /* the canvas below is 13px; the menu is sized like the XMLtools tabs */
    margin: 0 auto 0 8px;
    max-width: 100%;
    justify-self: start;
    align-self: center;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: thin;
}

:root:not([data-layout="side"]) .side-btn { display: inline-flex; align-items: center; gap: .45rem; flex: none; white-space: nowrap; }
:root:not([data-layout="side"]) .side-btn svg { display: none; }   /* the pill bar is text only */
:root:not([data-layout="side"]) .side-btn:hover:not(:disabled):not(.disabled) { color: var(--text); }

/* The main action keeps an outline (an inset ring, so the button stays the size of the others). */
:root:not([data-layout="side"]) .side-btn.accent { color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
:root:not([data-layout="side"]) .side-btn.accent:hover:not(:disabled):not(.disabled) { color: var(--accent); background: var(--surface-3); }

/* Section captions become thin dividers. */
:root:not([data-layout="side"]) .side-section { font-size: 0; width: 1px; height: 22px; margin: 0 4px; padding: 0; background: var(--border); flex: none; }
:root:not([data-layout="side"]) .side-section:first-child { display: none; }

/* Narrow window: the menu gets its own full-width row. */
@media (max-width: 1180px) {
    :root:not([data-layout="side"]) .app { grid-template-columns: minmax(0, 1fr) auto; grid-template-rows: auto auto minmax(0, 1fr); grid-template-areas: "brand tools" "nav nav" "content content"; }
    :root:not([data-layout="side"]) .sidebar { margin: 0 0 10px; justify-self: stretch; }
}
