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

h1:focus {
    outline: none;
}

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

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

.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .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");
    }

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;
}
/* ---- Retro Texture Studio ---- */
/* Light theme is the default; dark values apply when the system prefers dark. */
:root {
    color-scheme: light dark;
    --bg: #f2f3f6; --panel: #ffffff; --panel2: #e9ebef; --edge: #d0d5db;
    --text: #1d2127; --dim: #68707c; --accent: #2277cc; --ok: #2e9e4a;
    --overlay: #ffffffcc; --overlay-text: #1d2127;
}
@media (prefers-color-scheme: dark) {
    :root {
        --bg: #17191d; --panel: #1f2228; --panel2: #262a31; --edge: #33383f;
        --text: #d6d9de; --dim: #8a919b; --accent: #4f9dde; --ok: #59c96d;
        --overlay: #000000aa; --overlay-text: #d6d9de;
    }
}
body { background: var(--bg); color: var(--text); font: 13px/1.45 -apple-system, "Segoe UI", sans-serif; }
.studio-main { display: flex; flex-direction: column; height: 100vh; }
.topbar, .statusbar { display: flex; gap: 8px; align-items: center; padding: 6px 10px; background: var(--panel); border-bottom: 1px solid var(--edge); flex-wrap: wrap; }
.statusbar { border-top: 1px solid var(--edge); border-bottom: none; color: var(--dim); min-height: 30px;
    flex-wrap: nowrap; }
.statusbar > span:not(.statusbar-spacer):not(.spinner):not(.ws-split) {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
/* Window controls overlay: installed as an app, the OS title bar is replaced by the topbar,
   which becomes the window's drag handle and must keep the reserved rectangle clear for the
   window buttons — on the left on macOS, on the right on Windows, so neither side is assumed.
   Geometry comes from the browser's own env() variables first, because those are the
   purpose-built channel: they are populated in an installed app window and by Edge DevTools'
   overlay simulator, they update on resize without JS, and they are simply unset everywhere
   else. interop.js publishes the same rectangle from getTitlebarAreaRect() as --titlebar-*,
   which serves as the fallback and is what sets .wco. Hence the layered fallbacks: env, then
   the queried rect, then the ordinary in-tab value.

   There is only ONE rectangle to query — the usable strip — not one per control group. So each
   inset comes from an edge of it: the left is where the strip starts (macOS traffic lights sit
   before it), and the right is whatever is left over between the strip's right edge and the
   window (Edge puts its own "..." menu there). Both are derived in CSS so the two terms of that
   subtraction come from the same coordinate space; doing it in JS against innerWidth meant
   mixing sources, and the right inset came out wrong. */
.topbar { position: relative; height: env(titlebar-area-height, var(--titlebar-h, auto));
    padding-left: calc(env(titlebar-area-x, var(--titlebar-l, 0px)) + 10px);
    padding-right: calc(100vw - env(titlebar-area-x, 0px)
                        - env(titlebar-area-width, 100vw) + 10px); }
/* Pin the trailing controls right without a spacer element: an auto margin absorbs the free
   space. It has to sit on whichever control comes first, so when the update pill is showing it
   takes the margin and the view toggle gives its up — otherwise two auto margins would split
   the space between them and separate the group instead of keeping it together. */
.topbar > .view-seg, .topbar > .update-btn { margin-left: auto; }
.topbar > .update-btn ~ .view-seg { margin-left: 0; }
/* Only the structural changes are gated on the overlay actually showing. A fixed height, not
   min-height: matching the OS title bar is what makes the window read as native, and a bar
   that wrapped to two rows would drag from somewhere the OS is not. */
:root.wco .topbar { flex-wrap: nowrap; -webkit-app-region: drag;
    padding-top: 0; padding-bottom: 0;
    /* No hairline divider here, on purpose, and not for want of trying: border-bottom, then a
       box-shadow a pixel below the box, then making the strips transparent so the page's own
       line would show through — all three failed, the last because Chromium flattens alpha in
       theme-color to opaque black (see index.html). The tone is what works: the boundary is a
       change of colour across the whole width, including underneath the strips, so it depends
       on nothing surviving at a single row of pixels. index.html's theme-color metas must
       match this, since that is what the strips themselves are painted in. */
    background: var(--panel2); border-bottom-color: transparent; box-shadow: none;
    /* Above the drawer (41) and its backdrop (40), so a drawer slides *under* the bar rather
       than spilling its shadow across it. The bar is window chrome once the OS title bar is
       gone — it should stay put and stay undimmed while a panel comes and goes beneath it. */
    z-index: 45; }
/* Controls have to opt back out, or the drag region swallows the click. */
:root.wco .topbar button, :root.wco .topbar .seg { -webkit-app-region: no-drag; }
/* The workspace's game, in the status bar beside the workspace it belongs to — click to open
   the Game drawer. Height matches .statusbar button so it sits on the same baseline. */
.game-chip { display: inline-flex; gap: 6px; align-items: center; height: 28px; padding: 0 8px;
    color: var(--dim); font-size: 12px; flex: none; }
.game-chip-edition { color: var(--dim); opacity: 0.75; }
.game-chip-edition::before { content: "·"; margin-right: 6px; }
/* No border: the pill-style controls (update-btn, cta-btn) already went borderless, and a flat
   fill reads calmer than an outlined chip at this density. Squircle rather than a plain
   border-radius arc — the curvature eases into the straight edge instead of meeting it at a
   visible tangent. Both are ignored gracefully by anything that predates them, leaving an
   ordinary rounded-rect button. */
/* height + inline-flex rather than relying on padding: a fixed height needs the content
   centred explicitly, since line-height alone won't reliably centre 16px text in a 27px box
   across every button (icon-only ones especially). More specific rules above set their own
   explicit height (26px bumped to 27px alongside this one) or width for icon-square buttons,
   which still wins the cascade over this. */
/* A literal value, not --panel2: a specific flat grey the button fill and the dropdown outline
   are meant to share (see select, below) — not the theme's general-purpose panel tone, which
   still applies everywhere else. Deliberately the same in both colour schemes; nothing here
   swaps it for dark mode. */
button, .file-button { background: #ececec; color: var(--text); border: none;
    border-radius: 5px; corner-shape: squircle; height: 28px; padding: 0 10px;
    font-size: 16px; display: inline-flex; align-items: center; justify-content: center;
    cursor: pointer; }
button:hover, .file-button:hover { background: color-mix(in srgb, #ececec 92%, #000); }
button:disabled { opacity: 0.45; cursor: default; }
/* Border-color was the only active signal before; without a border, active needs its own tint
   to stay visible — the same idea .seg-btn.active already uses at a lower strength. */
button.active { background: color-mix(in srgb, var(--accent) 14%, #ececec); color: var(--accent); }
button.active:hover { background: color-mix(in srgb, var(--accent) 14%, color-mix(in srgb, #ececec 92%, #000)); }
.file-button input[type=file] { display: none; }
input, textarea { background: var(--panel2); color: var(--text); border: 1px solid var(--edge); border-radius: 5px; padding: 3px 7px; }
/* Dropdowns keep their outline rather than going borderless like buttons — they read as a
   field, not a command — and stay unfilled until hovered, so a page of them doesn't turn into
   a wall of panel2 boxes. The browser's own arrow is replaced with the app's chevron: a native
   <select> can't host a child SVG the way a button can, so it goes in as a background-image
   instead of the IconChevron component, with appearance:none clearing the UA-drawn one it
   would otherwise sit behind. currentColor does not reach into an SVG referenced by url() —
   that SVG is a separate resource, not inline markup — so the chevron's fill is the --dim hex
   baked in twice, once per scheme, the same way index.html's theme-color metas are doubled. */
/* box-sizing explicit rather than assumed: the 1px border has to come out of the 28px height,
   not add to it, or a field would stand 2px taller than a same-height borderless button next
   to it in the same bar. */
select { box-sizing: border-box; background: transparent; color: var(--text);
    border: 1px solid #ececec; border-radius: 5px; corner-shape: squircle;
    height: 28px; padding: 0 26px 0 7px;
    appearance: none; -webkit-appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' width='14' height='14'%3E%3Cpath fill='%2368707c' d='M15.8537 7.64582C16.0493 7.84073 16.0499 8.15731 15.855 8.35292L10.39 13.8374C10.1751 14.0531 9.82574 14.0531 9.6108 13.8374L4.14582 8.35292C3.9509 8.15731 3.95147 7.84073 4.14708 7.64582C4.34269 7.4509 4.65927 7.45147 4.85418 7.64708L10.0004 12.8117L15.1466 7.64708C15.3415 7.45147 15.6581 7.4509 15.8537 7.64582Z'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: right 6px center; background-size: 14px 14px; }
/* Same #ececec as the button fill, on purpose: hovering a dropdown is meant to read as the
   same weight of surface a button sits on at rest. */
select:hover { background-color: #ececec; }
@media (prefers-color-scheme: dark) {
    select { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' width='14' height='14'%3E%3Cpath fill='%238a919b' d='M15.8537 7.64582C16.0493 7.84073 16.0499 8.15731 15.855 8.35292L10.39 13.8374C10.1751 14.0531 9.82574 14.0531 9.6108 13.8374L4.14582 8.35292C3.9509 8.15731 3.95147 7.84073 4.14708 7.64582C4.34269 7.4509 4.65927 7.45147 4.85418 7.64708L10.0004 12.8117L15.1466 7.64708C15.3415 7.45147 15.6581 7.4509 15.8537 7.64582Z'/%3E%3C/svg%3E"); }
}
label { display: inline-flex; gap: 6px; align-items: center; }
.settings { display: flex; gap: 12px; padding: 8px 10px; background: var(--panel); border-bottom: 1px solid var(--edge); flex-wrap: wrap; align-items: flex-start; }
.settings .wide { flex: 1 1 100%; }
.settings textarea { width: 100%; }
.studio-grid { display: grid; grid-template-columns: minmax(280px, 1fr) minmax(420px, 1.6fr) minmax(280px, 0.9fr); gap: 0; flex: 1; min-height: 0; }
.pane { overflow-y: auto; padding: 10px; border-right: 1px solid var(--edge); min-height: 0; }
.pane-header { display: flex; gap: 8px; margin-bottom: 8px; flex-wrap: wrap; align-items: center; }
/* The items panel's category filter: docked under the panel title, full-bleed across the
   pane, and sticky so items scroll beneath it. The pane owns 10px of padding, so the bar
   cancels it sideways and re-adds its own — otherwise content shows through at the edges. */
.grid-pane { padding-top: 0; }
.category-bar { position: sticky; top: 0; z-index: 2; margin: 0 -10px 8px; padding: 10px;
    background: var(--bg); border-bottom: 1px solid var(--edge); }
.pane-header.category-bar select { flex: 1 1 auto; width: 100%; min-width: 0; }
.tile-grid { display: flex; flex-wrap: wrap; gap: 4px; }
.tile-cell { position: relative; width: 68px; height: 68px; border: 2px solid transparent; border-radius: 4px; background: var(--panel2); cursor: pointer; }
.tile-cell img { width: 64px; height: 64px; image-rendering: pixelated; display: block; }
.tile-cell.selected { border-color: var(--accent); }
.tile-placeholder { width: 64px; height: 64px; background: var(--panel2); }
.badge { position: absolute; font-size: 9px; line-height: 1; padding: 1px 3px; border-radius: 3px; background: var(--overlay); color: var(--overlay-text); }
.badge.redraw { right: 2px; top: 2px; width: 8px; height: 8px; background: var(--ok); border-radius: 50%; }
.badge.role { left: 2px; bottom: 2px; color: var(--dim); }
.join-btn { height: 28px; padding: 0 10px; font-size: 12px; }
.join-btn.ticked { border-color: var(--accent); color: var(--accent); }
/* Main-area tabs: the grid is the permanent first tab; every opened job/import result
   gets its own closable tab, decoupled from the group selection. */
.main-tabs { display: flex; gap: 2px; margin-bottom: 10px; flex-wrap: wrap;
    border-bottom: 1px solid var(--edge); }
.main-tab { display: inline-flex; align-items: center; gap: 6px; padding: 5px 8px 6px 10px;
    border: none; border-bottom: 2px solid transparent; margin-bottom: -1px;
    border-radius: 6px 6px 0 0; background: transparent;
    color: var(--dim); cursor: pointer; user-select: none; font-size: 12px; }
.main-tab:hover { background: var(--panel); color: var(--text); }
.main-tab.active { background: var(--panel); color: var(--text);
    border-bottom-color: var(--accent); }
.main-tab .tab-close { padding: 0 4px; font-size: 11px; }
.main-tab .tab-glyph { display: inline-flex; align-items: center; }
/* Platter and group prompt share a row when there's space; the prompt wraps below
   on narrow panes. */
.platter-row { display: flex; gap: 14px 12px; flex-wrap: wrap; align-items: flex-start; margin-bottom: 8px; }
.platter-row .platter-abs { margin-bottom: 0; flex: 0 0 auto; }
.platter-row .prompt-box { flex: 1 1 260px; min-width: 260px; width: auto;
    margin-top: 8px; margin-bottom: 0; resize: vertical; overflow-y: auto; }
/* Segmented icon controls (view source/redraw, generation quality). --seg-bg feeds the
   quality badge's ring so it masks the bars behind it on any segment state. */
.seg { display: inline-flex; }
.seg-btn { --seg-bg: var(--panel2); width: 30px; height: 28px; padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--seg-bg); color: var(--text); border: 1px solid var(--edge);
    border-radius: 0; margin-left: -1px; position: relative; }
.seg-btn:first-child { border-top-left-radius: 5px; border-bottom-left-radius: 5px; margin-left: 0; }
.seg-btn:last-child { border-top-right-radius: 5px; border-bottom-right-radius: 5px; }
.seg-btn:hover { border-color: var(--accent); z-index: 1; }
.seg-btn.active { --seg-bg: color-mix(in srgb, var(--accent) 18%, var(--panel2));
    border-color: var(--accent); z-index: 1; }
.seg-icon { position: relative; width: 16px; height: 16px; display: block; }
.seg-icon svg { display: block; width: 16px; height: 16px; }
.seg-badge { position: absolute; inset: 0; }
.badge-ring { fill: var(--seg-bg); }
.icon-btn.gen-btn { width: 52px; border-color: var(--accent); }
.charref-btn { position: relative; }
.charref-btn.active { border-color: var(--accent); }
.charref-thumb { width: 24px; height: 24px; object-fit: cover; border-radius: 4px; }
.charref-remove { position: absolute; top: -7px; right: -7px; padding: 0 4px; font-size: 10px;
    background: color-mix(in srgb, var(--panel) 82%, transparent);
    opacity: 0; pointer-events: none; transition: opacity 0.1s; }
.charref-btn:hover .charref-remove { opacity: 1; pointer-events: auto; }
.charref-remove:hover { background: color-mix(in srgb, var(--panel2) 92%, transparent); }
/* The platter is a true mini-preview of the planned sheet: cells are absolutely
   positioned from the layout manifest, so seamless runs butt together and their
   end gap renders exactly as it will on the generated sheet. */
.platter-abs { position: relative; aspect-ratio: 1; margin-bottom: 8px; }
.platter-cell { position: relative; aspect-ratio: 1; background: var(--panel2); border: 1px dashed var(--edge); border-radius: 4px; display: flex; align-items: center; justify-content: center; }
/* Must out-rank .platter-cell's position: relative — cells inside .platter-abs are
   placed by the layout manifest, not by flow. */
.platter-cell.abs-cell { position: absolute; box-sizing: border-box; aspect-ratio: auto;
    margin: 0; transition: left 0.18s ease, top 0.18s ease; }
.abs-cell.drop-target { box-shadow: inset 3px 0 0 0 var(--accent); }
/* Accent borders only on edges that still exist — join edges stay borderless so a
   selected run reads as one merged item, not per-cell boxes. */
.abs-cell.sel { border-style: solid; border-color: var(--accent); z-index: 1; }

.platter-cell img { width: 100%; height: 100%; image-rendering: pixelated; object-fit: contain; }
.platter-cell .cell-label, .run-cell .cell-label { position: absolute; left: 3px; top: 2px; font-size: 10px; color: var(--overlay-text); background: var(--overlay); padding: 0 3px; border-radius: 3px; }
.platter-abs .platter-cell .cell-label, .platter-abs .run-cell .cell-label { opacity: 0; transition: opacity 0.1s; }
.platter-abs .platter-cell:hover .cell-label, .platter-abs .run-cell:hover .cell-label { opacity: 1; }
.platter-cell .cell-remove, .run-cell .cell-remove { position: absolute; right: 2px; top: 2px; padding: 0 5px; font-size: 11px;
    background: color-mix(in srgb, var(--panel) 82%, transparent); color: var(--text);
    opacity: 0; pointer-events: none; transition: opacity 0.1s; }
.platter-cell:hover .cell-remove, .run-cell:hover .cell-remove { opacity: 1; pointer-events: auto; }
.platter-cell .cell-remove:hover, .run-cell .cell-remove:hover { background: color-mix(in srgb, var(--panel2) 92%, transparent); }
/* The select and its sibling buttons share one pinned height so they line up in
   every browser (Edge renders selects shorter than the flex row's tallest item).
   The select is the only header item allowed to shrink — ＋ stays glued to it, and
   the whole actions cluster wraps to the next row as one unit before that. */
.pane-header select { height: 28px; flex: 0 1 auto; min-width: 60px; }
/* Select + ＋ live in one non-wrapping group: with wrap on the outer header, the browser
   would move ＋ to the next line instead of ever shrinking the select. */
.group-select-wrap { display: flex; gap: 8px; align-items: center; flex: 0 1 auto; min-width: 0; }
.header-actions { display: flex; gap: 6px; align-items: center; flex: 1 0 auto; }
.cta-split { position: relative; display: inline-flex; }
.cta-split .cta-main { border-top-right-radius: 0; border-bottom-right-radius: 0; border-right: none; }
.cta-split .cta-arrow { border-top-left-radius: 0; border-bottom-left-radius: 0; padding: 0 7px;
    border-left: 1px solid color-mix(in srgb, #000 30%, var(--accent)); }
.cta-menu { position: absolute; right: 0; top: calc(100% + 4px); z-index: 60;
    background: var(--panel); border: 1px solid var(--edge); border-radius: 6px;
    padding: 4px; box-shadow: 0 6px 20px #0004; white-space: nowrap; }
.cta-menu-item { display: flex; gap: 8px; align-items: center; padding: 6px 10px;
    border-radius: 4px; cursor: pointer; font-size: 12px; color: var(--text); }
.cta-menu-item:hover { background: var(--panel2); }
.cta-menu-item.disabled { opacity: 0.45; pointer-events: none; }
.cta-menu-item svg { display: block; }
.cta-menu-item input[type=file] { display: none; }
/* Matches .pane-header select's height on purpose — see the comment above that rule. */
.new-group-wrap > button { width: 28px; height: 28px; padding: 0; display: inline-flex;
    align-items: center; justify-content: center; line-height: 1; }
.sheet-actions { display: flex; gap: 6px; }
.cta-actions { display: flex; gap: 6px; margin-left: auto; align-items: center; }
.cta-btn { display: inline-flex; align-items: center; gap: 6px; height: 28px; padding: 0 12px;
    background: var(--accent); border: none; color: #fff;
    border-radius: 5px; corner-shape: squircle; font-size: 12px; cursor: pointer; }
.cta-btn:hover { background: color-mix(in srgb, var(--accent) 85%, #000); }
.cta-btn:disabled, .cta-btn.disabled { opacity: 0.45; pointer-events: none; cursor: default; }
.cta-btn svg { display: block; }
.cta-btn input[type=file] { display: none; }
.icon-btn { width: 26px; height: 26px; padding: 0; display: inline-flex; align-items: center;
    justify-content: center; background: var(--panel2); color: var(--text);
    border: 1px solid var(--edge); border-radius: 5px; cursor: pointer; }
.icon-btn:hover { border-color: var(--accent); }
.icon-btn:disabled, .icon-btn.disabled { opacity: 0.45; cursor: default; pointer-events: none; }
.icon-btn svg { display: block; }
.icon-btn input[type=file] { display: none; }
.drop-tail { border-style: dotted; color: var(--dim); }
.group-actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-bottom: 8px; }
.prompt-box { width: 100%; margin-bottom: 6px; }
.generate { width: 100%; margin-bottom: 10px; border-color: var(--accent); }
.pending { border: none; border-radius: 0; padding: 0; background: transparent; }
.pending-header { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-bottom: 6px; }
.pending-canvas { position: relative; touch-action: none; user-select: none; }
.pending-canvas img { width: 100%; height: 100%; display: block; }
.region { position: absolute; border: 2px solid #ff3b30; background: #ff3b3022; pointer-events: none; }
.region.dragging { border-style: dashed; }
.revision-row { display: flex; gap: 8px; margin-top: 6px; }
.revision-row input { flex: 1; }
.hint { color: var(--dim); font-size: 12px; }
.inspector-tile label, .dark-panel label { display: flex; flex-direction: column; align-items: stretch; gap: 2px; margin-bottom: 6px; }
.inspector-tile img { width: 128px; height: 128px; image-rendering: pixelated; }
.ab-pair { display: flex; gap: 8px; margin-bottom: 8px; }
figure { margin: 0; }
figcaption { color: var(--dim); font-size: 11px; }
.bulk { border-top: 1px solid var(--edge); margin-top: 10px; padding-top: 8px; display: flex; flex-direction: column; gap: 6px; }
.dark-panel { margin-top: 0; padding-top: 0; }
.dark-panel h4 { margin: 0 0 6px; }
.dark-preview { display: flex; gap: 6px; }
.dark-preview img { width: 84px; height: 84px; image-rendering: pixelated; }
.spinner { width: 12px; height: 12px; border: 2px solid var(--dim); border-top-color: var(--accent); border-radius: 50%; animation: spin 0.8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
.ws-chip { background: var(--panel2); border: 1px solid var(--ok); color: var(--ok); border-radius: 5px; padding: 3px 9px; }
::placeholder { font-style: italic; color: var(--dim); opacity: 1; }
select.mixed { font-style: italic; color: var(--dim); }
.settings .dark-panel { border-top: 1px solid var(--edge); padding-top: 8px; display: flex; gap: 16px; align-items: flex-end; flex-wrap: wrap; }
.settings .dark-panel h4 { margin: 0; flex-basis: 100%; }
.settings .dark-panel label { flex-direction: column; align-items: stretch; min-width: 180px; }
.tile-grid { user-select: none; }
.settings { flex-direction: column; gap: 4px; }
.settings-section { width: 100%; }
.settings-section summary { cursor: pointer; font-weight: 600; padding: 3px 0; }
.settings-section summary:hover { color: var(--accent); }
.settings-body { display: flex; gap: 12px; flex-wrap: wrap; align-items: flex-start; padding: 6px 0 4px 14px; }
.settings .dark-panel { border-top: none; padding-top: 0; }
.ws-chip.blocked { border-color: #e0a030; color: #e0a030; }
.file-button.disabled { opacity: 0.45; cursor: default; pointer-events: none; }
.style-ref { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.style-ref-thumb { max-height: 72px; max-width: 128px; border: 1px solid var(--edge); border-radius: 4px; }
/* ---- Resizable studio layout + jobs ---- */
.studio-body { display: flex; flex: 1; min-height: 0; user-select: none; }
.sidebar { display: flex; flex-direction: column; min-width: 220px; overflow: hidden; border-right: 1px solid var(--edge); }
.side-section { overflow: auto; min-height: 80px; display: flex; flex-direction: column; }
.side-section.grow { flex: 1; }
.side-section h5 { margin: 0; padding: 5px 10px; font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--dim); background: var(--panel); border-bottom: 1px solid var(--edge); position: sticky; top: 0; z-index: 1; }
.side-section .pane { border-right: none; flex: 1; }
.h-splitter { height: 5px; cursor: row-resize; background: var(--edge); flex: none; }
.v-splitter { width: 5px; cursor: col-resize; background: var(--edge); flex: none; }
.h-splitter:hover, .v-splitter:hover { background: var(--accent); }
.main-pane { flex: 1; overflow: auto; min-width: 0; }
.sidebar-strip { width: 26px; flex: none; background: var(--panel); border-right: 1px solid var(--edge);
    display: flex; flex-direction: column; align-items: center; gap: 8px; padding-top: 8px;
    cursor: pointer; user-select: none; }
.sidebar-strip:hover { background: var(--panel2); }
.sidebar-strip .chevron { color: var(--dim); }
.sidebar-strip .strip-label { writing-mode: vertical-rl; transform: rotate(180deg);
    font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--dim); }
.collapse-ctl { cursor: pointer; margin-right: 2px; }
.props-column { flex: none; background: var(--bg); border-right: 1px solid var(--edge); }
.statusbar-spacer { flex: 1; }
.jobs-btn { font-size: 12px; padding: 0 10px; height: 28px; display: inline-flex; align-items: center; gap: 5px; }
.pill { border-radius: 999px; padding: 0 6px; font-size: 10px; line-height: 15px;
    font-weight: 600; color: #fff; }
.pill-progress { background: #b8860b; }
.pill-review { background: var(--accent); }
.pill-done { background: #3fa65b; }
.pill-failed { background: #d94f4f; }
.pill-cancelled { background: var(--dim); }
.jobs-popup { position: fixed; right: 10px; bottom: 40px; z-index: 60; width: 330px;
    max-height: 55vh; overflow-y: auto; background: var(--panel); border: 1px solid var(--edge);
    border-radius: 8px; padding: 6px; box-shadow: 0 8px 28px #0005; }
.close-btn { background: none; border: none; border-radius: 5px; padding: 1px 7px;
    color: var(--dim); }
.close-btn:hover { background: var(--panel2); border: none; color: var(--text); }
.platter-cell.ghost-cell { border: 1px dashed var(--edge); background: var(--panel);
    opacity: 0.55; }
.main-pane .pane { border-right: none; }
.jobs-panel { padding: 8px; display: flex; flex-direction: column; gap: 6px; }
.job { border: 1px solid var(--edge); border-radius: 6px; padding: 6px 8px; cursor: pointer; background: var(--panel2); }
.job:hover { border-color: var(--accent); }
.job.active { border-color: var(--accent); }
.job-line { display: flex; gap: 8px; align-items: center; justify-content: space-between; }
.job-kind { color: var(--dim); font-size: 11px; }
.job-state { display: inline-flex; gap: 5px; align-items: center; font-size: 12px; }
.job.state-running .job-state { color: var(--accent); }
.job.state-awaitingreview .job-state { color: #d9a13c; }
.job.state-placing .job-state { color: #d9a13c; }
.job.state-failed .job-state { color: #e05252; }

/* ---- Slice placement step ---- */
.placement-grid { display: grid; grid-template-columns: repeat(auto-fill, calc(var(--stage, 240px) + 8px)); gap: 10px; margin-top: 8px; }
.placement-cell { border: 1px solid var(--edge); border-radius: 6px; padding: 3px; background: var(--panel); }
.placement-cell.edited { border-color: var(--accent); }
.placement-cell.skipped .placement-stage { opacity: 0.35; cursor: default; }
.placement-cell.focused { outline: 2px solid var(--accent); outline-offset: 1px; }
.placement-stage:focus { outline: none; }

/* ---- Per-frame versions + character reference ---- */
.frame-versions { display: flex; gap: 4px; align-items: center; font-size: 0.75rem; color: var(--dim); }
.frame-versions button { padding: 0 7px; line-height: 1.35; }
.character-ref { display: flex; gap: 8px; align-items: center; margin: 6px 0; }
.character-ref-thumb { height: 44px; border-radius: 4px; border: 1px solid var(--edge); }
.ref-header { display: flex; gap: 4px; align-items: center; margin-bottom: 12px; }
.ref-header strong { flex: 1; }
.ref-header button, .ref-header .file-button {
    padding: 0 6px; font-size: 11px; line-height: 1.4; height: 20px;
    display: inline-flex; align-items: center; justify-content: center; }
.ref-add { width: 20px; padding: 0; line-height: 1; }
.style-ref-thumb-wrap.clickable { cursor: pointer; }
.settings-wrap { position: relative; }
.menu-backdrop { position: fixed; inset: 0; z-index: 59; }
.settings-menu { position: absolute; right: 0; top: calc(100% + 4px); z-index: 60;
    display: flex; flex-direction: column; min-width: 130px; background: var(--panel);
    border: 1px solid var(--edge); border-radius: 6px; overflow: hidden; padding: 4px; }
.settings-menu button { border: none; background: none; border-radius: 4px;
    text-align: left; padding: 6px 10px; }
.settings-menu button:hover { background: var(--panel2); }
.new-group-wrap { position: relative; }
.new-group-menu { position: absolute; left: 0; top: calc(100% + 4px); z-index: 60;
    display: flex; gap: 6px; background: var(--panel); border: 1px solid var(--edge);
    border-radius: 6px; padding: 8px; box-shadow: 0 6px 20px #0004; }
.new-group-menu input { width: 190px; }
.ws-split { display: inline-flex; flex: none; }
.ws-name { background: var(--panel2); border: 1px solid var(--edge);
    border-radius: 5px 0 0 5px; padding: 2px 8px; font-size: 12px; white-space: nowrap;
    max-width: 260px; overflow: hidden; text-overflow: ellipsis; }
.ws-name.blocked { color: #d9a13c; }
/* The × is the right segment of the workspace split button — it must keep the button
   chrome (the global .close-btn rule strips it), sharing the name segment's right
   border as the split divider. */
.ws-close { background: var(--panel2); border: 1px solid var(--edge); border-left: none;
    border-radius: 0 5px 5px 0; padding: 2px 8px; font-size: 12px; color: var(--dim); }
.ws-close:hover { background: color-mix(in srgb, var(--text) 8%, var(--panel2));
    border: 1px solid var(--edge); border-left: none; color: var(--text); }
/* Update offer: centred in the title bar between the two flexible spacers. Deliberately the
   loudest thing in the chrome — it appears rarely and is easy to miss otherwise. */
/* Centred on the bar itself, not on whatever space the controls leave over — with the wordmark
   and game chip gone the left side is empty, so an in-flow offer drifted well left of centre.
   Taken out of flow to do it: the two cannot collide above ~700px of bar, and the studio's grid
   already needs ~1000px. */
/* A bare yellow pill saying "Update", sitting with the other title bar controls rather than
   floating mid-bar — the word and the colour say enough on their own, and the tooltip carries
   the detail. No border: the fill is already the loudest thing in the chrome. There is no
   dismiss; an update that has been found stays on offer until it is taken. */
/* Lighter yellow at rest, darker on hover — inverted from the first version, and now the same
   direction as every other button's hover (color-mix toward black), just with hand-picked
   values instead of a formula so the two yellows stay a specific pairing. */
.update-btn { background: #ffc61a; color: #221a00; border: none; font-weight: 700;
    border-radius: 999px; height: 28px; padding: 0 14px; font-size: 16px; cursor: pointer;
    /* A squircle rather than a plain arc: border-radius alone is a quarter-ellipse, which meets
       the straight edge at a visible tangent, where a superellipse eases into it. Ignored by
       anything that does not know corner-shape, which just leaves an ordinary pill. */
    corner-shape: squircle; }
.update-btn:hover { background: #f5b301; }
@media (prefers-reduced-motion: no-preference) {
    .update-btn { animation: update-in 240ms ease-out; }
}
@keyframes update-in { from { opacity: 0; transform: translateY(-4px); } }

/* Unsupported-browser gate. Above every other layer (toasts are the highest at 65) and
   pointer-blocking, because nothing behind it can actually be used. */
.gate-backdrop { position: fixed; inset: 0; z-index: 200; background: var(--bg);
    opacity: 0.82; backdrop-filter: saturate(0.25) blur(1.5px); }
.gate { position: fixed; z-index: 201; top: 50%; left: 50%; translate: -50% -50%;
    width: min(560px, calc(100vw - 32px)); max-height: calc(100vh - 32px); overflow-y: auto;
    background: var(--panel); color: var(--text); border: 1px solid var(--edge);
    border-radius: 10px; padding: 22px 24px; box-shadow: 0 16px 56px #0007; }
.gate h2 { margin: 0 0 10px; font-size: 17px; }
.gate p { margin: 0 0 12px; color: var(--dim); text-wrap: pretty; }
.gate p strong { color: var(--text); }
.gate-missing { margin: 0 0 14px; padding: 0; list-style: none; display: flex;
    flex-direction: column; gap: 8px; }
.gate-missing li { display: flex; flex-direction: column; gap: 2px; padding: 8px 10px;
    background: var(--panel2); border: 1px solid var(--edge); border-radius: 6px; }
.gate-missing strong { font-size: 13px; }
.gate-missing span { color: var(--dim); font-size: 12px; }

/* Game drawer: the folder being searched, and each located copy of the game. */
.search-row { display: flex; align-items: center; gap: 6px; }
.search-root { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis;
    white-space: nowrap; color: var(--dim); }
.found-row { display: flex; align-items: center; gap: 8px; padding: 6px 8px;
    background: var(--panel2); border: 1px solid var(--edge); border-radius: 5px; }
.found-what { display: flex; align-items: center; gap: 6px; flex: none; }
.found-where { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis;
    white-space: nowrap; color: var(--dim); font-size: 12px; }
/* .badge is an absolutely-positioned grid overlay; this one is inline text. */
.badge.store { position: static; padding: 0 5px; border: 1px solid var(--edge);
    border-radius: 3px; background: none; color: var(--dim); font-size: 11px; }

/* Sidebar stand-in for the items grid before there is anything to list. */
.empty-pane { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
.empty-pane p { margin: 0; }
.empty-pane .hint { text-wrap: pretty; }
.style-ref-row { display: flex; gap: 6px; align-items: stretch; margin: 4px 0; }
.style-ref-row.drop-indicator { box-shadow: 0 -2px 0 0 var(--accent); }
.style-ref-row .drag-handle { align-self: center; }
.style-ref-thumb-wrap { position: relative; width: 64px; height: 64px; flex: none; }
.style-ref-row .style-ref-thumb { width: 100%; height: 100%; object-fit: contain; background: var(--panel2); }
.style-ref-swap { position: absolute; left: 2px; right: 2px; bottom: 2px; padding: 1px 0;
    font-size: 10px; text-align: center; opacity: 0.92; }
.style-ref-row .style-ref-context { flex: 1; height: 64px; min-height: 64px; resize: vertical; }
.approved-ref { margin: 6px 0; }
.approved-ref-thumbs { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
.approved-thumb { width: 40px; height: 40px; object-fit: contain; image-rendering: pixelated;
    background: var(--panel2); border: 1px solid var(--edge); border-radius: 3px; cursor: pointer; }
.approved-thumb.excluded { opacity: 0.3; filter: grayscale(1); border-style: dashed; }
.placement-stage { position: relative; width: var(--stage, 240px); height: var(--stage, 240px); overflow: hidden; border-radius: 4px;
    background: repeating-conic-gradient(var(--panel2) 0% 25%, var(--panel) 0% 50%) 0 0 / 20px 20px;
    touch-action: none; user-select: none; cursor: grab; }
.placement-stage:active { cursor: grabbing; }
.placement-ghost { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0.35;
    image-rendering: pixelated; pointer-events: none; }
.placement-art { position: absolute; image-rendering: pixelated; pointer-events: none; }
.placement-art { transform-origin: center; }
.placement-stage.wall { cursor: default; }
.placement-art.wall { position: absolute; inset: 0; width: 100%; height: 100%; }
.placement-controls { display: flex; gap: 5px; align-items: center; margin-top: 4px; }
.placement-rot { display: flex; gap: 5px; align-items: center; margin-top: 2px; }
.placement-rot input[type=range] { flex: 1; min-width: 0; padding: 0; }
.placement-align { display: flex; gap: 3px; align-items: center; margin-top: 2px; }
.placement-align .placement-reset { flex: 1; padding: 1px 2px; font-size: 0.8rem; white-space: nowrap; }
.generate-row { display: flex; gap: 6px; align-items: stretch; }
.generate-row .generate { flex: 1; }
.thinking-override { max-width: 200px; }
.placement-controls input[type=range] { flex: 1; min-width: 0; padding: 0; }
.placement-label { font-size: 0.72rem; color: var(--dim); max-width: 76px; overflow: hidden;
    text-overflow: ellipsis; white-space: nowrap; }
.placement-scale { font-size: 0.72rem; color: var(--dim); width: 36px; text-align: right; }
.placement-reset { padding: 1px 6px; }
.job.state-done .job-state { color: var(--ok); }
.job-time { color: var(--dim); font-size: 11px; }
.job-dismiss { padding: 0 6px; font-size: 11px; }
.revisions { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; margin-bottom: 8px; }
.revision-chip { font-size: 11px; padding: 2px 8px; }
.revision-chip.active { border-color: var(--ok); color: var(--ok); }
.error-text { color: #e05252; }
.pending.running { border-color: var(--dim); }
.pending-canvas { max-width: 100%; }
.pending-canvas img { user-select: none; -webkit-user-drag: none; }
.engine-meta { border-top: 1px solid var(--edge); margin-top: 10px; padding-top: 6px; }
.engine-meta h6 { margin: 0 0 5px; font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--dim); }
.engine-row { display: flex; gap: 8px; font-size: 12px; margin-bottom: 3px; align-items: baseline; }
.engine-row span { color: var(--dim); min-width: 82px; font-size: 11px; }
.engine-row code { background: var(--panel2); padding: 0 5px; border-radius: 3px; }
/* ---- Item layer ---- */
.item-grid { display: grid; grid-template-columns: repeat(var(--cols, 5), 1fr); gap: 6px; padding: 2px; }
.item-cell { position: relative; border: 2px solid transparent; border-radius: 5px; background: var(--panel2); cursor: pointer; padding: 4px 4px 2px; display: flex; flex-direction: column; align-items: center; min-width: 0; }
.item-cell img, .item-cell .tile-placeholder { width: 100%; height: auto; aspect-ratio: 1; image-rendering: pixelated; object-fit: contain; }
.item-cell.selected { border-color: var(--accent); }
.item-cell .item-name { font-size: 9px; line-height: 1.15; text-align: center; max-height: 22px; overflow: hidden; word-break: break-word; }
.item-cell .item-name.placeholder { color: var(--dim); font-style: italic; }
.badge.frames { right: 2px; bottom: 20px; color: var(--overlay-text); }
.item-props { display: flex; flex-direction: column; gap: 6px; margin-bottom: 10px; }
.item-props label { display: flex; flex-direction: column; align-items: stretch; gap: 2px; }
.item-props label.toggle { flex-direction: row; align-items: center; }
.frame-list { display: flex; flex-direction: column; gap: 4px; }
.frame-row { display: flex; gap: 6px; align-items: flex-start; }
.frame-thumb { width: 40px; height: 40px; image-rendering: pixelated; background: var(--panel2); border-radius: 3px; flex: none; }
.frame-fields { flex: 1; display: flex; flex-direction: column; gap: 3px; }
.frame-purpose { width: 100%; }
.frame-role { display: flex; gap: 4px; flex-wrap: wrap; align-items: center; }
.frame-role .role-source { flex: 1; }
.frame-role .frame-alias { flex-basis: 100%; }
.role-toggle { padding: 2px 6px; color: var(--dim); flex: none; }
.role-toggle.has-role { color: var(--accent); border-color: var(--accent); }
.side-section h5 { cursor: pointer; user-select: none; }
.side-section h5 .chevron { display: inline-block; width: 12px; color: var(--dim); }
.side-section.collapsed { height: auto !important; min-height: 0; flex: none; }
/* ---- Drawers + header size controls ---- */
.drawer-backdrop { position: fixed; inset: 0; background: #0006; z-index: 40; }
/* In overlay mode the title bar is the app's own chrome and the window's only drag handle, so
   a full-height panel swallows it — the window cannot be moved while a drawer is open, and the
   bar's controls disappear under a dimmed backdrop. Start both below the bar instead. */
:root.wco .drawer, :root.wco .drawer-backdrop {
    top: env(titlebar-area-height, var(--titlebar-h, 0px)); }
.drawer { position: fixed; top: 0; right: 0; bottom: 0; width: 400px; max-width: 90vw; background: var(--panel); border-left: 1px solid var(--edge); z-index: 41; display: flex; flex-direction: column; box-shadow: -6px 0 24px #0004; }
.drawer-header { display: flex; justify-content: space-between; align-items: center; padding: 10px 12px; border-bottom: 1px solid var(--edge); }
.drawer-body { padding: 12px; overflow-y: auto; display: flex; flex-direction: column; gap: 10px; }
.drawer-body label { display: flex; flex-direction: column; align-items: stretch; gap: 3px; }
.drawer-body label.toggle { flex-direction: row; align-items: center; }
/* File-picker labels are buttons, not fields — size them to their text. */
.drawer-body label.file-button { display: inline-flex; flex-direction: row; align-items: center;
    justify-content: center; height: 28px; padding: 0 12px; }
.side-section h5 { display: flex; align-items: center; gap: 4px; }
.size-controls { margin-left: auto; display: inline-flex; gap: 8px; align-items: center; }
.size-controls button { padding: 0 10px; font-size: 12px; height: 28px; }
.size-controls .file-button { padding: 0 10px; font-size: 12px; height: 28px;
    text-transform: none; letter-spacing: normal; display: inline-flex; align-items: center; }
/* ---- Item hero preview, frame removal, lightbox ---- */
.item-hero { position: relative; display: flex; justify-content: center; padding: 8px; background: var(--panel2); border-radius: 6px; margin-bottom: 10px; cursor: zoom-in; }
.item-hero img { width: 176px; height: 176px; image-rendering: pixelated; }
.hero-count { position: absolute; right: 8px; bottom: 6px; font-size: 11px; color: var(--overlay-text); background: var(--overlay); padding: 1px 6px; border-radius: 3px; }
.frame-remove { color: var(--dim); cursor: pointer; padding: 2px 6px; font-size: 14px; flex: none; }
.frame-remove:hover { color: #e05252; }
.frame-remove-confirm { color: #fff; background: #c74040; border-color: #c74040; flex: none; }
.lightbox-backdrop { position: fixed; inset: 0; background: #000a; z-index: 60; }
.lightbox { position: fixed; inset: 4vh 8vw; z-index: 61; background: var(--panel); border: 1px solid var(--edge); border-radius: 10px; display: flex; flex-direction: column; padding: 14px; outline: none; box-shadow: 0 12px 48px #0008; }
.lightbox-header { display: flex; gap: 12px; align-items: center; margin-bottom: 10px; }
.lightbox-image { flex: 1; min-height: 0; object-fit: contain; image-rendering: pixelated; width: 100%; }
.lightbox.split .lightbox-body { display: flex; gap: 14px; flex: 1; min-height: 0; }
.lightbox.split .lightbox-side { width: 300px; flex: none; display: flex; flex-direction: column;
    gap: 8px; overflow-y: auto; align-items: stretch; text-align: left; }
.lightbox.split .lightbox-side label { display: flex; flex-direction: column; gap: 3px;
    align-items: stretch; text-align: left; }
.lightbox.split .lightbox-side textarea, .lightbox.split .lightbox-side input,
.lightbox.split .lightbox-side select { width: 100%; }
.lightbox.split .lightbox-side textarea { resize: vertical; }
.lightbox.split .lightbox-stage { position: relative; flex: 1; min-width: 0; min-height: 0;
    display: flex; align-items: center; justify-content: center; }
.lightbox.split .lightbox-image { width: 100%; height: 100%; }
@media (max-width: 900px) {
    .lightbox.split .lightbox-body { flex-direction: column-reverse; }
    .lightbox.split .lightbox-side { width: 100%; flex: none; max-height: 40%; }
    .lightbox.split .lightbox-stage { flex: 1; }
}
.lightbox-nav { display: inline-flex; gap: 4px; }
.lightbox-nav button { padding: 0 10px; }
.lightbox-close { margin-left: auto; }
.lightbox-swap { position: absolute; bottom: 10px; left: 50%; transform: translateX(-50%);
    opacity: 0.92; }
.side-section.disabled-section h5 { color: var(--dim); cursor: default; }
.side-section.disabled-section h5:hover { color: var(--dim); }
/* ---- Responsive properties panel (2-column when wide) ---- */
.inspector-pane { container-type: inline-size; }
.item-head { display: flex; flex-direction: column; gap: 10px; margin-bottom: 10px; }
.item-head .item-hero { margin-bottom: 0; align-self: stretch; }
.item-head-fields { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.item-head-fields .item-props { margin-bottom: 0; }
@container (min-width: 430px) {
    .item-head { flex-direction: row; align-items: flex-start; }
    .item-head .item-hero { flex: none; align-self: flex-start; }
    .item-head-fields { flex: 1; }
}
.item-grid { user-select: none; }
.drag-handle { cursor: grab; color: var(--dim); font-size: 13px; letter-spacing: -2px; padding: 2px 4px 2px 0; flex: none; user-select: none; }
.drag-handle:active { cursor: grabbing; }
.frame-drop-tail { border: 1px dashed var(--edge); border-radius: 4px; color: var(--dim); font-size: 11px; text-align: center; padding: 6px; margin-top: 2px; }
.frame-list { user-select: none; }
.drag-handle { letter-spacing: 0; font-size: 12px; }
.frame-row.drop-indicator { box-shadow: 0 -2px 0 0 var(--accent); }
.frame-drop-tail.drop-indicator { box-shadow: 0 -2px 0 0 var(--accent); border-color: var(--accent); color: var(--accent); }
/* ---- Revision blocks + prompt viewer ---- */
.block-picker { display: flex; gap: 6px; align-items: center; margin-bottom: 6px; }
.block-chip { font-size: 12px; padding: 2px 10px; border-width: 2px; }
.block-chip.c0 { border-color: #ff0000aa; } .block-chip.c0.active { border-color: #ff0000; color: #ff3b30; }
.block-chip.c1 { border-color: #005affaa; } .block-chip.c1.active { border-color: #005aff; color: #2277ff; }
.block-chip.c2 { border-color: #00c800aa; } .block-chip.c2.active { border-color: #00c800; color: #24b53a; }
.block-chip.c3 { border-color: #ff8c00aa; } .block-chip.c3.active { border-color: #ff8c00; color: #f09000; }
.region.c0 { border-color: #ff0000; background: #ff000022; }
.region.c1 { border-color: #005aff; background: #005aff22; }
.region.c2 { border-color: #00c800; background: #00c80022; }
.region.c3 { border-color: #ff8c00; background: #ff8c0022; }
.block-swatch { width: 16px; height: 16px; border-radius: 4px; flex: none; align-self: center; }
.block-swatch.c0 { background: #ff0000; } .block-swatch.c1 { background: #005aff; }
.block-swatch.c2 { background: #00c800; } .block-swatch.c3 { background: #ff8c00; }
.prompt-view { background: var(--panel2); border: 1px solid var(--edge); border-radius: 6px; padding: 8px 10px; margin-bottom: 8px; max-height: 300px; overflow-y: auto; }
.prompt-view h6 { margin: 6px 0 3px; font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--dim); }
.prompt-view pre { margin: 0; white-space: pre-wrap; word-break: break-word; font-size: 11.5px; line-height: 1.45;
    user-select: text; -webkit-user-select: text; cursor: text; }
.prompt-copy { padding: 0 8px; font-size: 10px; margin-left: 8px; text-transform: none; letter-spacing: normal; }

/* Bottom-right job toasts, docked above the Jobs button; enter/exit animations move
   toward the button so cards read as flying in and out of it. */
.job-toasts { position: fixed; right: 10px; bottom: 42px; z-index: 65; display: flex;
    flex-direction: column; gap: 6px; width: 280px; pointer-events: none; }
.job-toast { pointer-events: auto; position: relative; background: var(--panel);
    border: 1px solid var(--edge); border-radius: 6px; padding: 6px 26px 6px 8px;
    box-shadow: 0 6px 20px #0004; cursor: pointer; font-size: 12px;
    transform-origin: bottom right; animation: toast-in 0.22s ease; }
.job-toast:hover { border-color: var(--accent); }
.job-toast.closing { animation: toast-out 0.26s ease forwards; pointer-events: none; }
@keyframes toast-in { from { opacity: 0; transform: translate(20%, 70%) scale(0.4); } }
@keyframes toast-out { to { opacity: 0; transform: translate(20%, 70%) scale(0.4); } }
.job-toast .job-line { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.toast-dismiss { position: absolute; top: 2px; right: 2px; padding: 0 5px; font-size: 11px; }
.toast-cancel { margin-left: auto; padding: 0 8px; font-size: 11px;
    background: #c43c3c; border-color: #c43c3c; color: #fff; }
.toast-cancel:hover { background: #a83232; border-color: #a83232; }
.toast-cancel:disabled { background: #c43c3c; border-color: #c43c3c; }

/* Results-view title bars: left controls, centered stage title, right-aligned CTAs. */
.results-bar { position: relative; }
.pending-title { position: absolute; left: 50%; transform: translateX(-50%);
    font-weight: 600; pointer-events: none; }
.bar-spacer { flex: 1; }
/* Secondary CTA: outlined in the primary colour. */
.cta2-btn { height: 26px; padding: 0 10px; background: transparent;
    border: 1px solid var(--accent); color: var(--accent); border-radius: 5px;
    font-size: 12px; cursor: pointer; }
.cta2-btn:hover { background: color-mix(in srgb, var(--accent) 12%, transparent); }
.cta2-btn:disabled { opacity: 0.45; cursor: default; }
/* Destructive action: filled red. */
.danger-btn { height: 26px; padding: 0 12px; background: #c43c3c;
    border: 1px solid #c43c3c; color: #fff; border-radius: 5px; font-size: 12px;
    cursor: pointer; }
.danger-btn:hover { background: #a83232; border-color: #a83232; }
/* Revision sets: one row each — colour box (count) + prompt + clear. The active row
   sticks to the top of the scrolling pane while marking areas further down. */
.revset-row { display: flex; gap: 8px; align-items: flex-start; margin-bottom: 6px;
    padding: 4px 6px; border-radius: 6px; }
.revset-row.active { position: sticky; top: -10px; z-index: 6; background: var(--bg);
    box-shadow: 0 2px 8px #0003; }
.revset-row:not(.active) { opacity: 0.55; cursor: pointer; }
.revset-box { width: 26px; height: 26px; flex: none; display: inline-flex;
    align-items: center; justify-content: center; border-radius: 5px; color: #fff;
    font-weight: 700; font-size: 12px; }
.revset-box.c0 { background: #ff0000; }
.revset-box.c1 { background: #005aff; }
.revset-box.c2 { background: #00c800; }
.revset-box.c3 { background: #ff8c00; }
.revset-prompt { flex: 1; resize: none; field-sizing: content; min-height: 26px;
    max-height: 68px; overflow-y: auto; }
.revset-row:not(.active) .revset-prompt { max-height: 26px; overflow: hidden; }
.revset-clear { flex: none; margin-top: 3px; }
.placement-hint { display: block; margin-bottom: 8px; }

/* Round-9 chrome: text/filled segments, icon labels, alias fields, jobs popup cap. */
.seg-text .seg-btn { width: auto; padding: 0 12px; font-size: 12px; }
.seg-fill .seg-btn.active { --seg-bg: var(--accent); background: var(--accent);
    border-color: var(--accent); color: #fff; }
.zoom-seg .seg-btn { width: 26px; }
.side-section h5 button { display: inline-flex; align-items: center; gap: 5px; }
.sidebar { container-type: inline-size; }
@container (max-width: 330px) { .side-section h5 .btn-label { display: none; } }
.close-btn { display: inline-flex; align-items: center; justify-content: center; }
.close-btn svg { display: block; }
.chevron { display: inline-flex; align-items: center; }
.chevron svg { display: block; }
.alias-row { display: flex; gap: 4px; align-items: center; }
.alias-row input { flex: 1; min-width: 0; }
.alias-toggle { padding: 2px 4px; background: none; border: none; color: var(--dim);
    display: inline-flex; align-items: center; cursor: pointer; }
.alias-toggle:hover { color: var(--text); border: none; }
.alias-toggle.active { color: var(--accent); }
.alias-input { width: 100%; }
/* Jobs popup shows ~10 rows before scrolling. */
.jobs-popup { max-height: min(560px, 72vh); overflow-y: auto; }

/* Dropdown-opening buttons carry an inline Fluent chevron. */
.settings-wrap > button { display: inline-flex; align-items: center; gap: 4px; }
.cta-split .cta-arrow svg { display: block; }

/* Model API / Generation drawer rows and tuning pair strips. */
.model-row { display: flex; gap: 6px; align-items: center; flex-wrap: nowrap; }
.model-row select { flex: 1; min-width: 0; }
.inline-selects { display: flex; gap: 14px; align-items: flex-start; }
.inline-selects label { flex: 1; }
.field-col { display: flex; flex-direction: column; gap: 3px; flex: 1; }
.field-col .hint { font-size: 11px; }
.pair-strip { display: flex; gap: 10px; flex-wrap: wrap; }
.pair-strip .pair { display: inline-flex; gap: 2px; border: 1px solid var(--edge);
    border-radius: 4px; padding: 2px; }
.pair-strip img { width: 56px; height: 56px; image-rendering: pixelated; }

/* Round-11: banner, job hero, join icons, help panel, numbering chips. */
.pane-banner { display: flex; gap: 8px; align-items: flex-start; padding: 6px 8px;
    margin-bottom: 8px; border: 1px solid var(--edge); border-left: 3px solid var(--accent);
    border-radius: 5px; background: var(--panel); }
.pane-banner .banner-text { flex: 1; min-width: 0; }
.job-hero { min-height: 46vh; display: flex; flex-direction: column; align-items: center;
    justify-content: center; gap: 8px; text-align: center; }
.job-hero h3 { margin: 0; font-size: 16px; }
.job-hero p { margin: 0 0 6px; color: var(--dim); max-width: 480px; }
.job-hero .hero-glyph { font-size: 34px; color: var(--dim); }
.spinner-big { width: 26px; height: 26px; border-width: 3px; }
.join-btn { display: inline-flex; align-items: center; gap: 5px; }
.join-btn svg { display: block; }
.cta2-btn.square { width: 26px; padding: 0; display: inline-flex; align-items: center;
    justify-content: center; }
.main-tab { padding-right: 5px; }
.tab-num { color: var(--dim); font-size: 11px; }
.placement-help { border: 1px solid var(--edge); border-radius: 6px; background: var(--panel);
    padding: 8px 10px; margin: 0 0 8px; display: flex; flex-direction: column; gap: 5px; }
.help-row { display: flex; gap: 8px; align-items: center; color: var(--dim); font-size: 12px; }
.help-row .help-what { display: inline-flex; gap: 3px; align-items: center; min-width: 130px;
    color: var(--text); font-weight: 600; }
.help-row svg { display: block; }
.help-row kbd { background: var(--panel2); border: 1px solid var(--edge); border-radius: 3px;
    padding: 0 4px; font-size: 11px; font-family: inherit; }
.placement-id { z-index: 2; }
.placement-align .placement-reset svg, .placement-controls .placement-reset svg { display: block; margin: 0 auto; }

/* Round-12 sizing sweep: consistent 26px control heights, square dismiss buttons. */
.close-btn { width: 26px; height: 26px; padding: 0; }
button.ws-close { width: auto; height: 28px; padding: 0 8px; }
.ws-name { height: 28px; display: inline-flex; align-items: center; }
.main-tab .tab-close, .platter-cell .cell-remove, .charref-remove,
.job-toast .toast-dismiss, .job .job-dismiss, .revset-clear, .frame-remove { width: 20px; height: 20px; }
.results-bar button, .results-bar .file-button { height: 28px; padding-top: 0; padding-bottom: 0; }
.props-column h5 { padding-right: 4px; }
.side-section h5 .size-controls .seg-btn { height: 28px; }
/* Narrow results bars: the centered title becomes its own first row and every button
   wraps below it. */
.group-pane { container-type: inline-size; }
@container (max-width: 700px) {
    .results-bar .pending-title { position: static; transform: none; order: -1;
        flex-basis: 100%; text-align: center; }
}
/* Effort slider with per-level detents. */
.effort-slider { display: inline-flex; gap: 6px; align-items: center; font-size: 12px;
    color: var(--dim); }
.effort-slider input[type=range] { width: 90px; padding: 0; }
.effort-slider .effort-name { min-width: 52px; color: var(--text); }
.statusbar button { height: 28px; padding-top: 0; padding-bottom: 0; }

/* Icon-only buttons stay square with full-size icons: the 26px control-height sweep
   must not pad seg buttons (padding crushed the flex-shrinking svgs to ~6px). */
.size-controls .seg-btn { padding: 0; width: 26px; }
.size-controls .seg-btn svg { flex: none; }
.side-section h5 button svg { flex: none; }
/* When the sidebar is too narrow for labels, the Properties button becomes a square
   icon button instead of a padded rectangle. */
@container (max-width: 330px) {
    .side-section h5 button:has(> .btn-label) {
        width: 26px; padding: 0; justify-content: center;
    }
}

/* FluentProgressRing themes from our palette (v4 rings are fluent web components —
   the design tokens are host-level CSS custom properties). */
fluent-progress-ring { --accent-fill-rest: var(--accent); --neutral-stroke-rest: var(--edge); }
fluent-progress-ring { flex: none; }

/* Round-13: tighter Apply, notification filter menu. */
.results-bar .cta-btn { padding: 0 10px; gap: 5px; }
.notif-menu { display: flex; flex-direction: column; gap: 6px; padding: 10px; }
.notif-row { font-size: 12px; }

.notif-filter { display: flex; flex-direction: column; gap: 6px; align-items: flex-start; }
.notif-list { display: flex; flex-direction: column; gap: 6px; padding: 8px 10px;
    border: 1px solid var(--edge); border-radius: 6px; background: var(--panel2); }



/* Joined runs as single flex strips: exact internal partitioning, zero seams,
   zero stretching. */
.run-strip { position: absolute; box-sizing: border-box; margin: 0; display: flex;
    background: var(--panel2); border: 1px dashed var(--edge); border-radius: 4px;
    transition: left 0.18s ease, top 0.18s ease; }
.run-strip.sel { border-style: solid; border-color: var(--accent); z-index: 1; }
/* aspect-ratio makes every member box exactly square (the strip's height derives
   from it), so object-fit: contain fills each box with zero letterboxing and zero
   stretching regardless of fractional pixel widths. */
.run-cell { position: relative; flex: 1 1 0; min-width: 0; cursor: pointer; aspect-ratio: 1; }
.run-cell img { width: 100%; height: 100%; object-fit: contain;
    image-rendering: pixelated; display: block; }
.run-cell.drop-target { box-shadow: inset 3px 0 0 0 var(--accent); }
