@import '/vendor/normalize/normalize.css';
@import '/vendor/fontsource/inter/index.css';
@import '/vendor/fontsource/geist-mono/index.css';

/* DCM360's own design tokens, tile/card component and state badges — see
   vendor/dcm360-design/README.md. Everything below this line is specific to
   this service's pages, built on top of those tokens. */
@import './vendor/dcm360-design/colors.css';
@import './vendor/dcm360-design/badges.css';
@import './vendor/dcm360-design/tiles.css';
@import './vendor/dcm360-design/ui-primitives.css';

html, body {
    height: 100%;
}

body {
    margin: 0;
    font-family: 'Inter', sans-serif;
    font-size: 14px;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

/* #app carries the theme's custom properties (see colors.css), so the
   background/text colors must be applied on #app itself — setting them on
   body would resolve against :root's (always light) defaults instead. */
#app {
    min-height: 100%;
    background: var(--background);
    color: var(--foreground);
}

a {
    color: var(--main-color-text);
}

.app-nav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    min-height: var(--header-height);
    padding: var(--space-2) var(--space-5);
    background: var(--background);
    border-bottom: var(--border-width) solid var(--border-subtle);
    flex-wrap: wrap;
}

.app-nav .brand {
    font-family: 'Geist Mono', monospace;
    font-size: 16px;
    color: var(--foreground);
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.app-nav .nav-link {
    color: var(--muted-foreground);
    text-decoration: none;
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-control);
    font-size: 13px;
    white-space: nowrap;
    transition: background .15s ease-out, color .15s ease-out;
}

.app-nav .nav-link:hover {
    background: var(--hover-overlay);
    color: var(--foreground);
}

main {
    padding: var(--space-6) var(--space-5);
    max-width: 1400px;
    margin: 0 auto;
}

.overview-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: var(--space-4);
}

.overview-grid .tile {
    display: block;
    width: 100%;
    text-decoration: none;
    border-left-width: var(--space-1);
    border-left-style: solid;
    border-left-color: var(--tile-border-color);
    transition: background .2s ease-out, transform .15s ease-out;
}

/* The auto-fit grid (fixed cols-N mode) stretches a tile's grid *cell* to
   fill leftover width when there are fewer objects than columns — good for
   the grid, but the widget rows inside don't grow to match, so an
   unbounded tile just grew a dead gap on its own right side instead. Cap
   normal tiles at a width their content actually fills and center them in
   whatever cell they land in. size-wide/size-full are exempt: spanning
   extra columns *is* their point, so they should use all of it. */
.overview-grid .tile:not(.size-wide):not(.size-full) {
    max-width: 640px;
    margin: 0 auto;
}

.overview-grid .tile:hover {
    background: var(--hover-overlay);
}

.overview-grid .tile.status-ok { border-left-color: var(--running-color); }
.overview-grid .tile.status-warning { border-left-color: var(--warning-color); }
.overview-grid .tile.status-alarm { border-left-color: var(--alarm-color); }
.overview-grid .tile.status-offline { border-left-color: var(--stopped-color); opacity: 0.7; }

/* Per-object size override — for tiles carrying enough widgets that the
   default column width leaves them cramped (see "Размер плитки" in admin). */
.overview-grid .tile.size-wide { grid-column: span 2; }
.overview-grid .tile.size-full { grid-column: 1 / -1; }

@media (max-width: 720px) {
    .overview-grid .tile.size-wide,
    .overview-grid .tile.size-full {
        grid-column: 1 / -1;
    }
}

/* Compact density (toggle in the nav) — trades the rich, spacious cards for
   a NOC-wall-friendly layout that fits many objects on screen at once:
   smaller photo, tighter grid, shrunk widgets. Practical once you're past
   ~8-10 objects and the default cards mean constant scrolling. */
#app.compact main {
    max-width: 1900px;
}

#app.compact .overview-grid {
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: var(--space-2);
}

/* Fixed column count (video-wall mode) — each track is sized to exactly
   1/N of the row (relative, so the column count itself doesn't change as
   the window resizes), same as repeat(N, 1fr). The difference is auto-fit:
   when there are fewer than N tiles, the tracks with nothing in them
   collapse to 0 instead of sitting there empty, and the actual tiles
   stretch to fill the freed-up row width rather than leaving dead space
   on the side. */
#app.cols-2 main, #app.cols-3 main, #app.cols-4 main, #app.cols-5 main, #app.cols-6 main {
    max-width: 1900px;
}

#app.cols-2 .overview-grid { grid-template-columns: repeat(auto-fit, minmax(calc((100% - 1 * var(--space-4)) / 2), 1fr)); }
#app.cols-3 .overview-grid { grid-template-columns: repeat(auto-fit, minmax(calc((100% - 2 * var(--space-4)) / 3), 1fr)); }
#app.cols-4 .overview-grid { grid-template-columns: repeat(auto-fit, minmax(calc((100% - 3 * var(--space-4)) / 4), 1fr)); }
#app.cols-5 .overview-grid { grid-template-columns: repeat(auto-fit, minmax(calc((100% - 4 * var(--space-4)) / 5), 1fr)); }
#app.cols-6 .overview-grid { grid-template-columns: repeat(auto-fit, minmax(calc((100% - 5 * var(--space-4)) / 6), 1fr)); }

#app.compact .tile-photo {
    aspect-ratio: 21 / 5;
}

#app.compact .tile-title {
    height: 40px;
    padding: 0 var(--space-2);
}

#app.compact .tile-content {
    padding: var(--space-1) var(--space-2);
    font-size: 12px;
    line-height: 1.4;
}

/* Every widget type shares this one width — see the comment on .widget-row
   for why they all need to match exactly, not just be "similar" — set once
   here so it inherits down into every row/widget in the tile, shrinking
   metric, gauge, battery, text and spacer together, still all equal to
   each other. */
#app.compact .widget-layout {
    --widget-col-width: 64px;
    gap: var(--space-1);
    padding: var(--space-1) 0;
}

#app.compact .widget-row {
    gap: var(--space-2);
}

/* Width now comes from .widget-gauge's own --widget-col-width (100% of it) —
   only the height still needs its own compact value, since the SVG doesn't
   scale proportionally on its own. */
#app.compact .gauge-svg {
    height: 42px;
}

#app.compact .battery-shell {
    width: 24px;
    height: 40px;
}

#app.compact .widget-gauge-label,
#app.compact .widget-metric-label {
    font-size: 10px;
}

#app.compact .widget-gauge-value,
#app.compact .widget-metric-value {
    font-size: 12px;
}

#app.compact .widget-group-body {
    padding: var(--space-2);
    gap: var(--space-1);
}

#app.compact .widget-group-title {
    padding: var(--space-1) var(--space-2);
    font-size: 12px;
}

#app.compact .widget-status-bar {
    padding: var(--space-1);
}

#app.compact .status-bar-item {
    font-size: 11px;
}

.overview-grid .tile-photo {
    aspect-ratio: 16 / 9;
    overflow: hidden;
    background: var(--muted);
    border-bottom: var(--border-width) solid var(--tile-border-color);
}

.overview-grid .tile-photo img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.overview-grid .tile-title {
    padding: 0 var(--space-3);
}

/* tiles.css's generic ".tile-title div" rule sets align-items:center, which
   also matches .tile-caption-group (a div) and centers its nowrap text
   horizontally instead of stretching it — clipping both edges once the
   title is wider than the group. Override back to left-aligned/stretched. */
.overview-grid .tile-caption-group {
    align-items: stretch;
}

.overview-grid .tile-content .var-name {
    color: var(--muted-foreground);
}

.overview-grid .tile-error {
    color: var(--alarm-color);
    font-size: 12px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.empty-state {
    color: var(--muted-foreground);
    font-size: 14px;
}

.error-banner {
    background: var(--alarm-color-plus-90);
    border: var(--border-width) solid var(--alarm-color);
    color: var(--alarm-color-minus-20);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-surface);
    font-size: 13px;
    margin-bottom: var(--space-4);
    display: none;
}

.success-banner {
    background: var(--running-color-plus-90);
    border: var(--border-width) solid var(--running-color);
    color: var(--running-color);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-surface);
    font-size: 13px;
    margin-bottom: var(--space-4);
    display: none;
}

.app-panel {
    background: var(--tile-background);
    border: var(--border-width) solid var(--tile-border-color);
    border-radius: var(--tile-border-radius);
    padding: var(--space-4);
    margin-bottom: var(--space-5);
}

.app-form-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
    gap: var(--space-3);
    align-items: end;
}

.app-field {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    font-size: 12px;
    color: var(--muted-foreground);
}

.app-field input {
    height: var(--control-height);
    background: var(--background);
    border: var(--border-width) solid var(--border);
    border-radius: var(--radius-control);
    color: var(--foreground);
    padding: 0 var(--space-3);
    font: inherit;
    font-size: 13px;
    transition: border-color .15s ease-out, box-shadow .15s ease-out;
}

.app-field-checkbox {
    flex-direction: row;
    align-items: center;
    height: var(--control-height);
    font-size: 13px;
    color: var(--foreground);
}

.app-field-checkbox input {
    margin-right: var(--space-1);
}

.app-field input:focus-visible {
    outline: none;
    border-color: var(--main-color);
    box-shadow: 0 0 0 2px var(--focus-ring);
}

.app-form-actions {
    grid-column: 1 / -1;
}

.table-scroll {
    overflow-x: auto;
    border-radius: var(--tile-border-radius);
}

table {
    width: 100%;
    border-collapse: collapse;
    background: var(--tile-background);
    border: var(--border-width) solid var(--tile-border-color);
    border-radius: var(--tile-border-radius);
    overflow: hidden;
}

th, td {
    text-align: left;
    padding: var(--space-3) var(--space-4);
    border-bottom: var(--border-width) solid var(--tile-separator-color);
    font-size: 13px;
}

th {
    color: var(--muted-foreground);
    font-weight: 600;
    text-transform: uppercase;
    font-size: 11px;
    letter-spacing: 0.04em;
}

tbody tr:last-child td {
    border-bottom: none;
}

.theme-toggle {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    height: var(--control-height);
    padding: 0 var(--space-3);
    border-radius: var(--radius-control);
    color: var(--muted-foreground);
    font-size: 13px;
    white-space: nowrap;
    cursor: pointer;
    border: var(--border-width) solid var(--border);
    background: transparent;
    flex: 0 0 auto;
}

.theme-toggle:hover {
    background: var(--hover-overlay);
    color: var(--foreground);
}

.nav-actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex: 0 0 auto;
    white-space: nowrap;
}

.params-section {
    margin-top: var(--space-1);
}

.params-row-actions {
    display: flex;
    justify-content: flex-end;
    padding: var(--space-2) var(--space-4) var(--space-3);
}

.params-empty-hint {
    color: var(--muted-foreground);
    font-size: 12px;
    padding: 0 var(--space-4) var(--space-3);
}

/* Tile widget builder — rendered both on the real tile (app.js) and as a
   live preview in the admin builder (admin.js). */
.widget-layout {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: var(--space-2) 0;
}

/* flex's default align-items is stretch, which would fill the whole tile
   edge to edge instead of the widget's own (capped) natural width — centers
   it instead. Only matters for a widget alone in its own row; inside
   .widget-row it's justify-self doing the equivalent job on the grid axis. */
.widget-layout > .widget-metric,
.widget-layout > .widget-gauge,
.widget-layout > .widget-battery,
.widget-layout > .widget-text,
.widget-layout > .widget-spacer {
    align-self: center;
}

.mi {
    flex: 0 0 auto;
    display: block;
}

/* Icon on top, value on one line below — same shape as the gauge/battery
   widgets, so a row mixing widget types lines up instead of "dancing"
   (metric used to be an icon-beside-text row, a different height than the
   icon-on-top widgets next to it, and would wrap to 2 lines besides). */
.widget-metric {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 2px;
    color: var(--foreground);
    width: 100%;
    max-width: var(--widget-col-width, 100px);
}

.widget-metric-label {
    font-size: 11px;
    color: var(--muted-foreground);
    line-height: 1.3;
    white-space: nowrap;
}

.widget-metric--warning .mi,
.widget-metric--warning .widget-metric-value {
    color: var(--warning-color);
}

.widget-metric--alarm .mi,
.widget-metric--alarm .widget-metric-value {
    color: var(--alarm-color);
}

/* Beyond color alone — a slow pulsing glow on anything currently in alarm,
   so a crossed threshold is noticeable at a glance on a wall display, not
   just on close inspection. */
@keyframes widget-alarm-pulse {
    0%, 100% { box-shadow: 0 0 0 0 color-mix(in oklch, var(--alarm-color) 55%, transparent); }
    50% { box-shadow: 0 0 0 7px color-mix(in oklch, var(--alarm-color) 0%, transparent); }
}

.widget-metric--alarm,
.widget-gauge--alarm .gauge-svg,
.widget-battery--alarm .battery-shell {
    animation: widget-alarm-pulse 1.8s ease-in-out infinite;
    border-radius: var(--radius-control);
}

.widget-metric-value {
    font-size: 14px;
    font-weight: 600;
    line-height: 1.3;
    white-space: nowrap;
}

.widget-text {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    font-size: 14px;
    color: var(--foreground);
    width: 100%;
    max-width: var(--widget-col-width, 100px);
}

/* Grid, not flex-wrap: a row is an explicit "these go side by side" grouping
   — flex-wrap silently reflowed extra widgets onto a second line once the
   row didn't fit, at a wrap point that shifted with tile_size/density
   (looked like widgets randomly changing position). grid-auto-flow: column
   with no template sidesteps that: exactly as many columns as there are
   widgets in *this* row, always one line, period — never reflows.
   minmax(0, 1fr), not a fixed pixel width: a fixed width doesn't shrink when
   a row has more widgets than the tile has room for — the grid's own total
   width then exceeds the tile's, spilling widgets past its edge into
   whatever's next (tried this, with 5+ widgets in a row it visibly ate
   neighboring content). 1fr always divides up exactly the space actually
   available, so the row can never be wider than its tile. Each widget's own
   max-width (--widget-col-width, shared by metric/gauge/battery/text/
   spacer — see each widget's own rule) still caps how big it gets when
   there IS room to spare, and pads a shorter row with spacer widgets to
   match a longer row's column *count* and both divide their (equal, same
   tile) width the same way — same result, without the overflow risk. */
.widget-row {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
    align-items: end;
    gap: var(--space-4);
}

/* justify-self:center, not the grid's default stretch: at less than max
   width the grid column IS this wide already (nothing to center within),
   but once there's spare room this keeps every widget at its own capped
   size instead of stretching out across it. */
.widget-row > .widget-metric,
.widget-row > .widget-gauge,
.widget-row > .widget-battery,
.widget-row > .widget-text {
    justify-self: center;
}

.widget-gauge {
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 100%;
    max-width: var(--widget-col-width, 100px);
    text-align: center;
}

.gauge-svg {
    width: 100%;
    height: 65px;
}

/* .widget-spacer itself needs no rules at all — no content to cap or
   center, so it just takes the grid's default (stretch to fill its column),
   same as every other column in the row. */

.widget-gauge-label {
    font-size: 11px;
    color: var(--muted-foreground);
    margin-top: -6px;
    white-space: nowrap;
}

.widget-gauge-value {
    font-size: 13px;
    font-weight: 600;
    color: var(--foreground);
    white-space: nowrap;
}

/* Fillable level indicator (battery/tank/humidity-style) — shares the
   gauge's label/value text styling below it, and the same --widget-col-width
   cap as every other widget type (the label/value below the shell is still
   free to size to its own nowrap content within that box, same as before). */
.widget-battery {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    width: 100%;
    max-width: var(--widget-col-width, 100px);
}

/* .widget-gauge-label's -6px margin-top pulls it up into a gauge's arc,
   which has empty space there to spare — a battery/tank shell doesn't: it's
   a solid rectangle down to a hard bottom edge (often filled right to the
   top), so that same pull just ran the label into the fill. Small positive
   gap instead. */
.widget-battery .widget-gauge-label {
    margin-top: var(--space-1);
}

.battery-shell {
    position: relative;
    width: 34px;
    height: 58px;
    margin-top: 6px;
    border: 2px solid var(--muted-foreground);
    border-radius: 4px;
    box-sizing: border-box;
    padding: 2px;
    display: flex;
    align-items: flex-end;
    overflow: hidden;
}

.battery-shell::before {
    content: '';
    position: absolute;
    top: -5px;
    left: 50%;
    transform: translateX(-50%);
    width: 14px;
    height: 4px;
    background: var(--muted-foreground);
    border-radius: 2px 2px 0 0;
}

.battery-fill {
    width: 100%;
    min-height: 2px;
    border-radius: 2px;
    transition: height .3s ease-out, background-color .3s ease-out;
}

/* Fuel/water/level tank — rounded silo top instead of the battery's
   terminal nub, and a touch wider so it doesn't read as "a fat battery". */
.battery-shell--tank {
    width: 40px;
    border-radius: 45% 45% 6px 6px / 26% 26% 6px 6px;
}

.battery-shell--tank::before {
    display: none;
}

#app.compact .battery-shell--tank {
    width: 28px;
}

.widget-status-bar {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    background: var(--muted);
    border-radius: var(--radius-control);
    padding: var(--space-2);
}

.status-bar-item {
    display: flex;
    align-items: center;
    gap: 4px;
    font-size: 12px;
    font-weight: 600;
    padding: 2px var(--space-2);
    border-radius: var(--radius-full);
    color: var(--muted-foreground);
}

.status-bar-item--ok { color: var(--running-color); }
.status-bar-item--stopped { color: var(--stopped-color); }
.status-bar-item--warning { color: var(--warning-foreground); background: var(--warning-color); }
.status-bar-item--alarm { color: #fff; background: var(--alarm-color); }
.status-bar-item--disconnected { color: var(--muted-foreground); }
.status-bar-item--service { color: var(--service-color); }

.widget-group {
    border: var(--border-width) solid var(--tile-border-color);
    border-radius: var(--radius-surface);
    overflow: hidden;
}

.widget-group-title {
    background: var(--muted);
    padding: var(--space-2) var(--space-3);
    font-weight: 600;
    font-size: 13px;
}

.widget-group-body {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-3);
}

/* Admin builder — the live preview (renderTileLayout(), the exact same
   markup the real overview page uses) is click-to-edit only; repositioning
   is the separate .builder-rowlist below it (row-number inputs, not
   dragging — see admin.js for why). */

/* Applied to a widget's own rendered root element (.widget-metric,
   .widget-gauge, …) — no extra wrapper, so it never affects the widget-row
   grid it may sit inside. position:relative anchors .builder-widget-remove;
   the outline (not border) avoids nudging the widget's own box/alignment. */
.builder-widget {
    position: relative;
    cursor: pointer;
    border-radius: var(--radius-control);
    outline: 2px solid transparent;
    outline-offset: 3px;
    transition: outline-color .1s ease-out;
}

.builder-widget:hover {
    outline-color: var(--main-color);
}

.builder-widget-remove {
    position: absolute;
    top: -8px;
    right: -8px;
    width: 20px;
    height: 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: 50%;
    background: var(--alarm-color);
    color: #fff;
    font-size: 11px;
    line-height: 1;
    cursor: pointer;
    opacity: 0;
    transition: opacity .1s ease-out;
    z-index: 1;
}

.builder-widget:hover .builder-widget-remove {
    opacity: 1;
}

/* .widget-group normally clips to round its corners — harmless on the real
   overview page, but it would also clip .builder-widget-remove's
   negative-offset corner position here, since this class is only ever
   added in the builder. */
.builder-widget.widget-group {
    overflow: visible;
}

/* .widget-spacer is genuinely empty on the real overview page (0 height,
   invisible) — it only needs to occupy its column's width. In the builder
   it needs to be visible/clickable too, so it can be told apart from an
   empty gap and still be selected to edit/remove; .builder-widget is only
   ever added here, never on the public page. */
.builder-widget.widget-spacer {
    min-height: 24px;
    border: var(--border-width) dashed var(--border);
    border-radius: var(--radius-control);
}

/* One item per widget, grouped visually by row via .builder-rowlist-sep
   forcing a line break — flex-wrap, not a grid: these are small badges, not
   real tile content, so there's no width-per-density concern to solve for
   here the way there is in the actual tile. */
.builder-rowlist {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
}

.builder-rowlist-sep {
    flex-basis: 100%;
    height: 0;
}

.builder-rowlist-item {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    border: var(--border-width) solid var(--tile-border-color);
    border-radius: var(--radius-control);
    background: var(--tile-background);
    font-size: 13px;
}

.builder-rowlist-summary {
    max-width: 160px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.builder-rowlist-row-input {
    display: flex;
    align-items: center;
    gap: 4px;
    font-size: 11px;
    color: var(--muted-foreground);
}

.builder-rowlist-row-input input {
    width: 44px;
    height: 28px;
    text-align: center;
    border: var(--border-width) solid var(--border);
    border-radius: var(--radius-control);
    background: var(--background);
    color: var(--foreground);
    font: inherit;
}

.icon-picker {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(36px, 1fr));
    gap: 4px;
    max-height: 160px;
    overflow-y: auto;
    padding: var(--space-2);
    border: var(--border-width) solid var(--border);
    border-radius: var(--radius-control);
    background: var(--background);
}

.icon-picker-item {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 32px;
    border-radius: var(--radius-control);
    color: var(--muted-foreground);
    cursor: pointer;
    border: var(--border-width) solid transparent;
}

.icon-picker-item:hover {
    background: var(--hover-overlay);
    color: var(--foreground);
}

.icon-picker-item.selected {
    border-color: var(--main-color);
    color: var(--main-color);
    background: var(--focus-ring);
}

/* Matches the real tile's own max-width (see .overview-grid .tile) so the
   preview is an honest WYSIWYG of what visitors will actually see, instead
   of stretching across the whole (much wider) admin page. */
/* 640px by default — matches a real normal-size tile — but draggable via
   the native resize handle at the bottom-right corner, so you can stretch
   it out while building the layout to check how it'd look wide (or shrink
   it back) instead of being stuck with empty space you can't do anything
   about. min/max bound the drag to sane values: no narrower than the
   smallest real tile, no wider than the panel itself. */
.builder-preview {
    background: var(--tile-background);
    border: var(--border-width) dashed var(--tile-border-color);
    border-radius: var(--tile-border-radius);
    padding: var(--space-4);
    margin-bottom: var(--space-3);
    width: 640px;
    min-width: 320px;
    max-width: 100%;
    resize: horizontal;
    overflow: auto;
}

/* Keeps Save/Cancel in view while scrolling a long widget editor (e.g. a
   "group" widget's children list, or the icon picker) instead of leaving
   them below the fold where they read as missing. */
.widget-editor-actions {
    display: flex;
    gap: var(--space-2);
    margin: var(--space-3) calc(-1 * var(--space-4)) calc(-1 * var(--space-4));
    padding: var(--space-3) var(--space-4);
    position: sticky;
    bottom: 0;
    background: var(--tile-background);
    border-top: var(--border-width) solid var(--tile-border-color);
    border-radius: 0 0 var(--tile-border-radius) var(--tile-border-radius);
    z-index: 2;
}
