/* =========================================================================
   The Backyard Club — Overview screen
   Recreates the design-system Button / Card / Badge and the two-region shell
   using the tokens in ds-tokens.css. No Bootstrap dependency.
   ========================================================================= */

/* ---------- helpers ------------------------------------------------------- */
.installer .eyebrow {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-subtle);
}

.installer .mono {
    font-family: var(--font-mono);
}

.installer a {
    color: var(--text-link);
    text-decoration: none;
}

@keyframes dcs-spin {
    to {
        transform: rotate(360deg);
    }
}

/* =========================================================================
   Design-system components
   ========================================================================= */

/* ---------- Button -------------------------------------------------------- */
.ds-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    height: 36px;
    padding: 0 16px;
    font-family: var(--font-sans);
    font-size: 14px;
    font-weight: 600;
    letter-spacing: 0.005em;
    border-radius: var(--radius-md);
    border: 1px solid transparent;
    cursor: pointer;
    white-space: nowrap;
    transition: background var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    transform var(--dur-fast) var(--ease-out);
}

.ds-btn:active {
    transform: translateY(0.5px);
}

.ds-btn:focus-visible {
    outline: none;
    box-shadow: var(--shadow-focus);
}

.ds-btn[disabled],
.ds-btn.is-disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.ds-btn--sm {
    height: 28px;
    padding: 0 12px;
    font-size: 13px;
    gap: 6px;
}

.ds-btn--md {
    height: 36px;
    padding: 0 16px;
    font-size: 14px;
    gap: 8px;
}

.ds-btn--primary {
    background: var(--dcs-navy-700);
    color: var(--text-on-dark);
    border-color: var(--dcs-navy-700);
    box-shadow: var(--shadow-xs);
}

.ds-btn--primary:not([disabled]):hover {
    background: var(--dcs-navy-800);
    border-color: var(--dcs-navy-800);
}

/* product="irix" primary */
.ds-btn--primary.ds-btn--irix {
    background: var(--irix);
    border-color: var(--irix);
}

.ds-btn--primary.ds-btn--irix:not([disabled]):hover {
    background: color-mix(in srgb, var(--irix) 88%, black);
    border-color: color-mix(in srgb, var(--irix) 88%, black);
}

.ds-btn--secondary {
    background: var(--surface-card);
    color: var(--text-primary);
    border-color: var(--border-strong);
}

.ds-btn--secondary:not([disabled]):hover {
    background: var(--grey-50);
}

.ds-btn--ghost {
    background: transparent;
    color: var(--text-body);
    border-color: transparent;
}

.ds-btn--ghost:not([disabled]):hover {
    background: var(--dcs-navy-50);
}

/* Anchors used as buttons: keep the variant's text colour instead of the
   generic `.installer a` link colour, which otherwise wins on specificity. */
.installer a.ds-btn--primary,
.installer a.ds-btn--danger {
    color: var(--text-on-dark);
}

.installer a.ds-btn--secondary {
    color: var(--text-primary);
}

.installer a.ds-btn--ghost {
    color: var(--text-body);
}

.ds-btn__spinner {
    width: 16px;
    height: 16px;
    border-radius: 50%;
    border: 2px solid currentColor;
    border-top-color: transparent;
    animation: dcs-spin 700ms linear infinite;
    display: none;
}

.ds-btn--sm .ds-btn__spinner {
    width: 14px;
    height: 14px;
}

.ds-btn.is-loading {
    cursor: not-allowed;
}

.ds-btn.is-loading .ds-btn__spinner {
    display: inline-block;
}

/* button leading/trailing icon */
.ds-btn__icon {
    display: inline-flex;
    flex: 0 0 auto;
}

.ds-btn__icon svg {
    width: 16px;
    height: 16px;
    display: block;
}

.ds-btn--sm .ds-btn__icon svg {
    width: 14px;
    height: 14px;
}

/* hide the leading icon while the spinner is showing (keeps label width steady) */
.ds-btn.is-loading .ds-btn__icon {
    display: none;
}

/* ---------- Card ---------------------------------------------------------- */
.ds-card {
    background: var(--surface-card);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    overflow: hidden; /* clip inner strips/rows to the radius */
}

.ds-card--irix {
    border-top: 3px solid var(--irix);
}

/* ---------- Badge --------------------------------------------------------- */
.ds-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    height: 18px;
    padding: 0 6px;
    font-family: var(--font-sans);
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    border-radius: var(--radius-sm);
    white-space: nowrap;
}

.ds-badge--success {
    background: var(--success-soft);
    color: var(--irix-shade);
}

.ds-badge--warning {
    background: var(--warning-soft);
    color: #7a5a1a;
}

.ds-badge--danger {
    background: var(--danger-soft);
    color: #7a221d;
}

.ds-badge svg {
    width: 12px;
    height: 12px;
    flex: none;
}

/* =========================================================================
   Shell — sidebar + body + topbar + main + footer
   ========================================================================= */
.installer {
    display: flex;
    align-items: stretch;
    min-height: 100vh;
    background: var(--bg-page);
    font-family: var(--font-sans);
    color: var(--text-body);
    font-size: 15px;
}

/* ---------- Sidebar (navy step rail) ------------------------------------- */
.side {
    width: 248px;
    flex: 0 0 248px;
    background: var(--dcs-navy-700);
    display: flex;
    flex-direction: column;
    position: sticky;
    top: 0;
    height: 100vh;
    overflow: hidden; /* clip inner labels while the rail narrows */
    transition: flex-basis var(--dur-base) var(--ease-out),
    width var(--dur-base) var(--ease-out);
}

.side__brand {
    padding: 22px 20px 18px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.10);
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.side__brand-logo {
    height: 20px;
    width: auto;
    align-self: flex-start;
}

.side__brand-word {
    display: flex;
    align-items: baseline;
    gap: 7px;
}

.side__brand-irix {
    font-size: 16px;
    font-weight: 800;
    letter-spacing: 0.02em;
    color: var(--irix);
}

.side__brand-sub {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.55);
}

.side__progress {
    padding: 16px 20px 18px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.10);
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.side__progress-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
}

.side__progress-label {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.45);
}

.side__progress-count {
    font-family: var(--font-mono);
    font-size: 11px;
    font-weight: 500;
    color: rgba(255, 255, 255, 0.75);
}

.side__progress-track {
    height: 3px;
    border-radius: 2px;
    background: rgba(255, 255, 255, 0.14);
    overflow: hidden;
}

.side__progress-fill {
    height: 100%;
    background: var(--irix);
}

.side__nav {
    flex: 1;
    padding: 10px 0;
    display: flex;
    flex-direction: column;
    overflow-y: auto;
}

.side__step {
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: center;
    gap: 12px;
    padding: 9px 20px 9px 18px;
    border-left: 2px solid transparent;
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease-out);
}

.side__step:hover {
    background: rgba(255, 255, 255, 0.06);
    text-decoration: none;
}

.side__step-label {
    font-size: 14px;
    font-weight: 500;
    color: rgba(255, 255, 255, 0.78);
}

.side__step-kicker {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.45);
}

.side__step-name {
    font-size: 14px;
    font-weight: 700;
    color: #ffffff;
}

.side__step-two {
    display: flex;
    flex-direction: column;
    gap: 1px;
}

.side__step.is-active {
    border-left-color: var(--irix);
    background: rgba(255, 255, 255, 0.10);
}

.side__step.is-active .side__step-label {
    color: #ffffff;
    font-weight: 700;
}

.side__foot {
    padding: 14px 20px;
    border-top: 1px solid rgba(255, 255, 255, 0.10);
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.side__foot-version {
    font-family: var(--font-mono);
    font-size: 11px;
    color: rgba(255, 255, 255, 0.45);
}

.side__foot-link {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.55);
}

.side__foot-link:hover {
    color: rgba(255, 255, 255, 0.85);
    text-decoration: none;
}

/* ---------- Sidebar: step icon (shown only when collapsed) ---------------- */
.side__step-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: rgba(255, 255, 255, 0.55);
}

.side__step-icon svg {
    width: 18px;
    height: 18px;
    display: block;
}

.side__step.is-active .side__step-icon {
    color: var(--irix);
}

.side__step.is-completed .side__step-icon {
    color: var(--success);
}

/* ---------- Sidebar: sub-menu groups (e.g. Logs → Activity / Schedules) ---- */
.side__group {
    display: flex;
    flex-direction: column;
}

/* The group header is a <button>, so reset the native chrome and give it the
   third column the caret needs. */
.side__step--group {
    grid-template-columns: auto 1fr auto;
    width: 100%;
    background: transparent;
    border: 0;
    border-left: 2px solid transparent;
    font-family: inherit;
    text-align: left;
    -webkit-appearance: none;
    appearance: none;
}

.side__step-caret {
    display: inline-flex;
    align-items: center;
    color: rgba(255, 255, 255, 0.45);
}

.side__step-caret svg {
    width: 15px;
    height: 15px;
    display: block;
    transition: transform var(--dur-base) var(--ease-out);
}

.side__group.is-open .side__step-caret svg {
    transform: rotate(180deg);
}

/* An open group signals its section is current with a subtle brightening — the full
   active pill (border + fill) is reserved for the actual current child below. */
.side__group.is-open .side__step-label {
    color: #ffffff;
}

.side__group.is-open .side__step-icon,
.side__group.is-open .side__step-caret {
    color: rgba(255, 255, 255, 0.85);
}

.side__sub {
    display: none;
    flex-direction: column;
    padding: 2px 0 4px;
}

.side__group.is-open .side__sub {
    display: flex;
}

.side__substep {
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: center;
    gap: 10px;
    padding: 8px 20px 8px 40px;
    border-left: 2px solid transparent;
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease-out);
}

.side__substep:hover {
    background: rgba(255, 255, 255, 0.06);
    text-decoration: none;
}

.side__substep-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: rgba(255, 255, 255, 0.45);
}

.side__substep-icon svg {
    width: 15px;
    height: 15px;
    display: block;
}

.side__substep-label {
    font-size: 13px;
    font-weight: 500;
    color: rgba(255, 255, 255, 0.70);
}

.side__substep.is-active {
    border-left-color: var(--irix);
    background: rgba(255, 255, 255, 0.10);
}

.side__substep.is-active .side__substep-label {
    color: #ffffff;
    font-weight: 700;
}

.side__substep.is-active .side__substep-icon {
    color: var(--irix);
}

/* ---------- Sidebar: collapse / expand toggle ----------------------------- */
.side__toggle {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    padding: 13px 18px;
    border: 0;
    background: transparent;
    color: rgba(255, 255, 255, 0.60);
    font-family: var(--font-sans);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out);
}

.side__toggle:hover {
    background: rgba(255, 255, 255, 0.06);
    color: #ffffff;
}

.side__toggle:focus-visible {
    outline: 2px solid var(--irix);
    outline-offset: -2px;
}

.side__toggle-icon {
    display: inline-flex;
    flex: 0 0 auto;
}

.side__toggle-icon svg {
    width: 18px;
    height: 18px;
    display: block;
    transition: transform var(--dur-base) var(--ease-out);
}

.side__toggle-text {
    white-space: nowrap;
}

/* ---------- Sidebar: collapsed state -------------------------------------- */
html.is-side-collapsed .side {
    width: 64px;
    flex-basis: 64px;
}

html.is-side-collapsed .side__brand {
    padding: 20px 0 16px;
    align-items: center;
}

html.is-side-collapsed .side__brand-logo {
    align-self: center;
}

html.is-side-collapsed .side__brand-word {
    display: none;
}

html.is-side-collapsed .side__progress {
    padding: 12px 12px 14px;
}

html.is-side-collapsed .side__progress-head {
    display: none;
}

html.is-side-collapsed .side__step {
    grid-template-columns: 1fr;
    gap: 0;
    padding: 10px 0;
    justify-items: center;
}

html.is-side-collapsed .side__step-label,
html.is-side-collapsed .side__step-two {
    display: none;
}

html.is-side-collapsed .side__step-icon svg {
    width: 20px;
    height: 20px;
}

html.is-side-collapsed .side__foot {
    display: none;
}

html.is-side-collapsed .side__toggle {
    justify-content: center;
    padding: 14px 0;
    border-top: 1px solid rgba(255, 255, 255, 0.10);
}

html.is-side-collapsed .side__toggle-text {
    display: none;
}

html.is-side-collapsed .side__toggle-icon svg {
    transform: rotate(180deg);
}

/* In the icon-only rail the group can't expand/collapse on click, so keep it
   always open and show each child as its own centred icon. */
html.is-side-collapsed .side__step--group {
    grid-template-columns: 1fr;
    gap: 0;
    padding: 10px 0;
    justify-items: center;
}

html.is-side-collapsed .side__step-caret {
    display: none;
}

html.is-side-collapsed .side__sub {
    display: flex;
    padding: 0;
}

html.is-side-collapsed .side__substep {
    grid-template-columns: 1fr;
    gap: 0;
    padding: 9px 0;
    justify-items: center;
}

html.is-side-collapsed .side__substep-label {
    display: none;
}

html.is-side-collapsed .side__substep-icon svg {
    width: 18px;
    height: 18px;
}

@media (prefers-reduced-motion: reduce) {
    .side, .side__toggle-icon svg {
        transition: none;
    }
}

/* ---------- Body column --------------------------------------------------- */
.installer__body {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

/* ---------- Topbar -------------------------------------------------------- */
.topbar {
    position: sticky;
    top: 0;
    z-index: 20;
    height: 64px;
    flex: 0 0 64px;
    background: var(--bg-canvas);
    border-bottom: 1px solid var(--border-default);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 24px;
    padding: 0 32px;
}

.topbar__target {
    display: flex;
    align-items: center;
    gap: 14px;
    min-width: 0;
    flex: 1 1 auto;
    overflow: hidden;
}

.topbar__eyebrow {
    flex: 0 0 auto;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-subtle);
}

.topbar__divider {
    flex: 0 0 auto;
    width: 1px;
    height: 20px;
    background: var(--border-default);
}

.topbar__app {
    flex: 0 1 auto;
    min-width: 0;
    font-size: 16px;
    font-weight: 700;
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.topbar__code {
    flex: 0 1 auto;
    min-width: 0;
    font-family: var(--font-mono);
    font-size: 12px;
    font-weight: 500;
    color: var(--text-muted);
    background: var(--grey-100);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-sm);
    padding: 3px 7px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.topbar__flag {
    flex: 0 0 auto;
    width: 20px;
    height: 15px;
    border-radius: 3px;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.10);
}

.topbar__right {
    display: flex;
    align-items: center;
    gap: 18px;
    flex: 0 0 auto;
}

/* Live clock — ambient text (like .topbar__status), not a chip. Clock.js ticks it. */
.topbar__clock {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    color: var(--text-muted);
    white-space: nowrap;
}

.topbar__clock-icon {
    display: inline-flex;
    color: var(--irix-shade);
}

.topbar__clock-icon svg {
    width: 16px;
    height: 16px;
    display: block;
}

.topbar__clock-date {
    font-weight: 600;
}

.topbar__clock-sep {
    color: var(--border-strong);
}

.topbar__clock-time {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.02em;
    color: var(--text-primary);
}

.topbar__status {
    display: flex;
    align-items: center;
    gap: 7px;
    font-size: 13px;
    color: var(--text-muted);
    white-space: nowrap;
}

.topbar__status-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--success);
}

.topbar__stock {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 5px 8px 5px 12px;
    border: 1px solid var(--border-default);
    border-radius: var(--radius-full);
    background: var(--surface-card);
    white-space: nowrap;
}

.topbar__stock-icon {
    display: inline-flex;
    color: var(--irix-shade);
}

.topbar__stock-icon svg {
    width: 16px;
    height: 16px;
    display: block;
}

.topbar__stock-label {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-muted);
}

.topbar__stock-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 24px;
    height: 22px;
    padding: 0 7px;
    border-radius: var(--radius-full);
    background: var(--irix);
    color: #fff;
    font-family: var(--font-mono);
    font-size: 13px;
    font-weight: 700;
}

/* Oversold overall — more consumed than is on hand across the catalogue. */
.topbar__stock-count.is-negative {
    background: var(--danger);
}

/* ---------- Battery chip (host laptop charge, rendered server-side) ----------
   Shared across the topbar (pill) and footer (subtle) variants; see the
   @components/battery.html.twig macro. The charge colour is driven here off the
   is-low / is-critical / is-charging state on the .battery-chip base, so both
   variants stay in sync. */
.battery-chip__fill {
    fill: var(--success);
}

.battery-chip.is-low .battery-chip__fill {
    fill: var(--warning);
}

.battery-chip.is-critical .battery-chip__fill {
    fill: var(--danger);
}

.battery-chip.is-critical .battery-chip__icon {
    color: var(--danger);
}

.battery-chip.is-charging .battery-chip__icon {
    color: var(--success);
}

/* Topbar variant — a bordered pill, matching the stock/weather chips. */
.topbar__battery {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 5px 11px 5px 9px;
    border: 1px solid var(--border-default);
    border-radius: var(--radius-full);
    background: var(--surface-card);
    white-space: nowrap;
}

.topbar__battery-icon {
    display: inline-flex;
    color: var(--text-muted);
}

.topbar__battery-icon svg {
    width: 22px;
    height: 22px;
    display: block;
}

.topbar__battery-pct {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    font-size: 13px;
    font-weight: 700;
    color: var(--text-primary);
}

/* Footer variant — quiet, sized to the footer's small print. */
.installer__footer-battery {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    white-space: nowrap;
}

.installer__footer-battery-icon {
    display: inline-flex;
    color: var(--text-muted);
}

.installer__footer-battery-icon svg {
    width: 20px;
    height: 20px;
    display: block;
}

.installer__footer-battery-pct {
    font-size: 12px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

/* ---------- Account chip + sign out ---------- */
.topbar__account {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 4px 6px 4px 8px;
    border: 1px solid var(--border-default);
    border-radius: var(--radius-full);
    background: var(--surface-card);
    white-space: nowrap;
}

.topbar__account-link {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    min-width: 0;
    padding: 2px 4px;
    border-radius: var(--radius-full);
    color: inherit;
    text-decoration: none;
}

.topbar__account-link:hover .topbar__account-name {
    color: var(--accent);
}

.topbar__account-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: var(--accent-soft);
    color: var(--text-primary);
}

.topbar__account-avatar svg {
    width: 16px;
    height: 16px;
    display: block;
}

.topbar__account-avatar--img {
    background: none;
    overflow: hidden;
}

.topbar__account-avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.topbar__account-meta {
    display: flex;
    flex-direction: column;
    line-height: 1.15;
}

.topbar__account-name {
    max-width: 190px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 13px;
    font-weight: 700;
    color: var(--text-primary);
}

.topbar__account-role {
    font-size: 11px;
    color: var(--text-subtle);
}

/* Whether THIS session cleared a second factor — shield-check + accent when it
   did, a muted plain shield when it was password only. */
.topbar__account-2fa {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

.topbar__account-2fa svg {
    width: 12px;
    height: 12px;
    flex: none;
}

.topbar__account-2fa.is-on {
    color: var(--success);
    font-weight: 700;
}

.topbar__logout-form {
    margin: 0;
    display: inline-flex;
}

.topbar__logout {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    padding: 0;
    border: 1px solid var(--border-default);
    border-radius: 50%;
    background: var(--surface-card);
    color: var(--text-muted);
    cursor: pointer;
    transition: color 0.15s ease, background 0.15s ease, border-color 0.15s ease;
}

.topbar__logout:hover {
    color: var(--danger);
    background: var(--danger-soft);
    border-color: var(--danger);
}

.topbar__logout svg {
    width: 16px;
    height: 16px;
    display: block;
}

/* ---------- Main grid ----------------------------------------------------- */
.installer__main {
    flex: 1;
    padding: 28px 32px 36px;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(250px, 320px);
    gap: 24px;
    align-items: start;
}

.main-col {
    display: flex;
    flex-direction: column;
    gap: 20px;
    min-width: 0;
}

.rail {
    display: flex;
    flex-direction: column;
    gap: 20px;
    position: sticky;
    top: 88px; /* clear the sticky 64px topbar + a 24px gap */
}

/* ---------- Messages (flash / ajax alerts) -------------------------------- */
.installer #messages {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-bottom: 4px;
}

.installer #messages:empty {
    display: none;
}

.installer .alert {
    /* per-type theming — overridden by each .alert-<type> below */
    --alert-accent: var(--grey-400);
    --alert-bg: var(--grey-50);
    --alert-border: var(--border-subtle);
    --alert-chip: var(--grey-150);
    --alert-strong: var(--text-primary);

    position: relative;
    padding: 13px 40px 13px 52px;
    border-radius: var(--radius-lg);
    border: 1px solid var(--alert-border);
    border-left: 3px solid var(--alert-accent);
    background: var(--alert-bg);
    color: var(--text-body);
    font-size: 14px;
    line-height: var(--lh-normal);
    box-shadow: var(--shadow-xs);
    animation: alert-in var(--dur-base) var(--ease-out) both;
}

/* rich content inside alerts (benchmark warning, inline links) */
.installer .alert strong {
    font-weight: var(--fw-semibold);
    color: var(--alert-strong);
}

.installer .alert small {
    display: inline-block;
    margin-top: 2px;
    font-size: 12.5px;
    opacity: 0.75;
}

.installer .alert a {
    color: var(--alert-strong);
    font-weight: var(--fw-semibold);
    text-underline-offset: 2px;
}

/* typed leading icon on a soft chip (flash, runtime, inline) */
.installer .alert::before {
    content: "";
    position: absolute;
    left: 11px;
    top: 10px;
    width: 30px;
    height: 30px;
    border-radius: 8px;
    background-color: var(--alert-chip);
    background-repeat: no-repeat;
    background-position: center;
    background-size: 17px 17px;
}

.installer .alert-success::before {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230c7d3c' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='m9 12 2 2 4-4'/%3E%3C/svg%3E");
}

.installer .alert-warning::before {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%237a5a1a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z'/%3E%3Cpath d='M12 9v4'/%3E%3Cpath d='M12 17h.01'/%3E%3C/svg%3E");
}

.installer .alert-danger::before {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%237a221d' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='m15 9-6 6'/%3E%3Cpath d='m9 9 6 6'/%3E%3C/svg%3E");
}

.installer .alert-info::before {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23103858' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='M12 16v-4'/%3E%3Cpath d='M12 8h.01'/%3E%3C/svg%3E");
}

.installer .alert-success {
    --alert-accent: var(--success);
    --alert-bg: #f1faf5;
    --alert-border: #cfead9;
    --alert-chip: #cdecdb;
    --alert-strong: var(--irix-shade);
}

.installer .alert-warning {
    --alert-accent: var(--warning);
    --alert-bg: #fdf7ec;
    --alert-border: #f1e1c2;
    --alert-chip: #f8e3bc;
    --alert-strong: #8a6318;
}

.installer .alert-danger {
    --alert-accent: var(--danger);
    --alert-bg: #fdf2f1;
    --alert-border: #f2d2ce;
    --alert-chip: #f6cec9;
    --alert-strong: #9b2b25;
}

.installer .alert-info {
    --alert-accent: var(--info);
    --alert-bg: #eff6fc;
    --alert-border: #d3e4f4;
    --alert-chip: #cbe0f4;
    --alert-strong: var(--dcs-navy-700);
}

.installer .alert .btn-close {
    position: absolute;
    top: 8px;
    right: 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    padding: 0;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text-muted);
    font-size: 15px;
    line-height: 1;
    cursor: pointer;
    opacity: 0.7;
    transition: opacity var(--dur-fast) var(--ease-out),
                background-color var(--dur-fast) var(--ease-out),
                color var(--dur-fast) var(--ease-out);
}

.installer .alert .btn-close::before {
    content: '\00d7';
}

.installer .alert .btn-close:hover {
    opacity: 1;
    color: var(--text-body);
    background: rgba(16, 56, 88, 0.08);
}

.installer .alert .btn-close:focus-visible {
    outline: none;
    opacity: 1;
    box-shadow: var(--shadow-focus);
}

@keyframes alert-in {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
    .installer .alert { animation: none; }
}

/* =========================================================================
   Page title row
   ========================================================================= */
.page-head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: 16px 24px;
}

.page-head__left {
    flex: 1 1 320px;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.page-head__eyebrow {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--irix);
}

.page-head__title {
    display: inline-flex;
    align-items: center;
    gap: 14px;
    margin: 0;
    font-size: 32px;
    font-weight: 800;
    letter-spacing: -0.01em;
    line-height: 1.1;
    color: var(--text-primary);
    font-family: var(--font-display);
}

.page-head__title-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: var(--radius-md);
    background: var(--success-soft);
    color: var(--irix-shade);
    flex: 0 0 auto;
}

.page-head__title-icon svg {
    width: 24px;
    height: 24px;
    display: block;
}

.page-head__sub {
    margin: 0;
    font-size: 15px;
    line-height: 1.45;
    color: var(--text-muted);
    text-wrap: pretty;
}

/* The page-head description reads as a caption inline after the title
   (title · blurb), for every section. Scoped to the page-head's own sub — a
   direct child of .page-head__left — so the same class reused as a plain
   paragraph inside card bodies is left alone. The eyebrow keeps its own line;
   the title stays an inline-flex box so the blurb flows beside it and, when
   long, wraps naturally under the title. */
.page-head__left {
    display: block;
}

.page-head__left > .page-head__eyebrow {
    display: block;
    margin-bottom: 6px;
}

.page-head__left > .page-head__title {
    vertical-align: middle;
}

.page-head__left > .page-head__sub {
    display: inline;
    vertical-align: middle;
    font-size: 13px;
    line-height: 1.35;
}

.page-head__left > .page-head__sub::before {
    content: "·";
    margin: 0 8px 0 6px;
    color: var(--border-strong);
}

.page-head__right {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 12px;
    white-space: nowrap;
}

.gate__blocking {
    font-size: 12px;
    font-weight: 600;
    color: var(--danger);
}

/* =========================================================================
   Card header strip (shared by every card)
   ========================================================================= */
.card-strip {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 14px 20px;
    border-bottom: 1px solid var(--border-subtle);
}

/* Tint every main-column card header so the title strip reads as a distinct
   band above the card body — matches the stock/products listing. Rail cards are
   left on the plain card background (as on the stock screen). */
.installer .main-col .card-strip {
    background: var(--surface-sunken);
}

.card-strip__meta {
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--text-subtle);
}

/* Title group: the card eyebrow with an inline count sitting beside it, so the
   count reads as part of the heading rather than a note drifting to the right. */
.card-strip__title {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
}

.card-strip__count {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 12px;
    font-weight: var(--fw-semibold);
    color: var(--text-subtle);
    /* wrap (rather than clip) longer descriptive meta on narrow cards; short
       counts never have a wrap opportunity so this is invisible for them */
    white-space: normal;
    min-width: 0;
}

/* small dot separating the title from its count */
.card-strip__count::before {
    content: "";
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--accent);
    opacity: 0.55;
    flex: 0 0 auto;
}

/* keep the sort control snug on the right of the strip and let the strip wrap
   the sort under the title on narrow viewports rather than overflow. */
.card-strip__sort {
    flex: 0 0 auto;
    margin-left: auto;
}

@media (max-width: 560px) {
    .card-strip:has(.card-strip__sort) {
        flex-wrap: wrap;
        row-gap: 10px;
    }

    .card-strip__sort {
        margin-left: 0;
    }

    .card-strip__sort .form-control {
        width: 100%;
    }
}

/* =========================================================================
   Environment card
   ========================================================================= */
.env-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
}

.env-cell {
    padding: 16px 20px;
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
}

.env-cell--tr {
    border-bottom: 1px solid var(--border-subtle);
}

.env-cell--tl {
    border-right: 1px solid var(--border-subtle);
    border-bottom: 1px solid var(--border-subtle);
}

.env-cell--bl {
    border-right: 1px solid var(--border-subtle);
}

.env-value {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
}

.env-value--num {
    font-family: var(--font-mono);
    font-size: 15px;
    font-weight: 600;
    color: var(--text-primary);
}

.env-value--text {
    font-size: 15px;
    font-weight: 600;
    color: var(--text-primary);
}

.env-value--path {
    font-family: var(--font-mono);
    font-size: 13px;
    font-weight: 500;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

.env-value--ug {
    font-family: var(--font-mono);
    font-size: 13px;
    font-weight: 500;
    color: var(--text-primary);
}

.env-value .muted {
    font-weight: 400;
    color: var(--text-subtle);
}

/* =========================================================================
   Requirements card
   ========================================================================= */
.req-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 14px 20px 13px;
}

.req-head__left {
    display: flex;
    align-items: baseline;
    gap: 14px;
    flex-wrap: wrap;
    min-width: 0;
}

.req-counts {
    font-size: 13px;
    color: var(--text-muted);
}

.req-counts__pass {
    color: var(--success);
}

.req-counts__warn {
    color: var(--warning);
}

.req-counts__fail {
    color: var(--danger);
}

.req-bar {
    display: flex;
    height: 3px;
    margin: 0 20px 2px;
    border-radius: 2px;
    overflow: hidden;
    background: var(--grey-150);
}

.req-bar__seg {
    height: 100%;
    flex-grow: 0;
    transition: flex-grow var(--dur-base) var(--ease-out);
}

.req-bar__seg--pass {
    background: var(--success);
}

.req-bar__seg--warn {
    background: var(--warning);
}

.req-bar__seg--fail {
    background: var(--danger);
}

.req-bar__seg--skip {
    background: var(--grey-300);
}

.req-list {
    display: flex;
    flex-direction: column;
}

.req-row {
    border-top: 1px solid var(--border-subtle);
}

.req-line {
    display: grid;
    grid-template-columns: 14px minmax(0, 1fr) auto auto;
    align-items: center;
    column-gap: 16px;
    row-gap: 6px;
    padding: 12px 20px;
    transition: background var(--dur-fast) var(--ease-out);
}

.req-row:not(.is-fail):hover .req-line {
    background: var(--grey-50);
}

.req-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--grey-300);
}

.req-name {
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
}

.req-status {
    grid-row: 1;
    grid-column: 3;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    white-space: nowrap;
    color: var(--text-subtle);
}

/* per-row re-check button */
.req-check {
    grid-row: 1;
    grid-column: 4;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    color: var(--text-subtle);
    background: transparent;
    border: 1px solid var(--border-default);
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    background var(--dur-fast) var(--ease-out);
}

.req-check svg {
    width: 15px;
    height: 15px;
}

.req-check:hover {
    color: var(--text-primary);
    border-color: var(--border-strong);
    background: var(--grey-50);
}

.req-check:disabled {
    opacity: 0.45;
    cursor: default;
}

.req-check:focus-visible {
    outline: 2px solid var(--border-focus);
    outline-offset: 1px;
}

.req-row.is-checking .req-check svg {
    animation: req-spin 800ms linear infinite;
}

@keyframes req-spin {
    to {
        transform: rotate(360deg);
    }
}

.req-detail {
    grid-row: 2;
    grid-column: 2 / -1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 5px;
    font-family: var(--font-mono);
    font-size: 12px;
    line-height: 1.45;
    color: var(--text-muted);
    overflow-wrap: anywhere;
}

/* one message per line, each with its own status dot */
.req-detail__item {
    position: relative;
    padding-left: 15px;
}

.req-detail__item::before {
    content: "";
    position: absolute;
    left: 1px;
    top: 0.45em;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--grey-300);
}

.req-detail__item.is-pass::before {
    background: var(--success);
}

.req-detail__item.is-warn::before {
    background: var(--warning);
}

.req-detail__item.is-fail::before {
    background: var(--danger);
}

.req-detail__item.is-skip::before {
    background: var(--grey-400);
}

.req-detail__item.is-warn {
    color: var(--grey-800);
}

.req-detail__item.is-fail {
    color: var(--danger);
}

/* status colouring */
.req-row.is-pass .req-dot {
    background: var(--success);
}

.req-row.is-pass .req-status {
    color: var(--success);
}

.req-row.is-warn .req-dot {
    background: var(--warning);
}

.req-row.is-warn .req-status {
    color: var(--warning);
}

.req-row.is-fail .req-dot {
    background: var(--danger);
}

.req-row.is-fail .req-status {
    color: var(--danger);
}

.req-row.is-fail {
    background: var(--danger-soft);
}

.req-row.is-fail .req-name {
    font-weight: 700;
}

.req-row.is-fail .req-detail {
    color: var(--grey-800);
}

.req-row.is-skip .req-dot {
    background: var(--grey-400);
}

.req-row.is-skip .req-status {
    color: var(--text-subtle);
}

.req-row.is-checking .req-dot {
    background: var(--dcs-navy-300);
    animation: dcs-pulse 900ms var(--ease-inout) infinite;
}

@keyframes dcs-pulse {
    0%, 100% {
        opacity: 0.35;
    }
    50% {
        opacity: 1;
    }
}

/* remediation (failed rows) */
.req-remediation {
    padding: 0 20px 16px 50px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.req-remediation__msg {
    font-size: 13px;
    color: var(--grey-800);
}

.req-cmd {
    position: relative;
    margin: 0;
    font-family: var(--font-mono);
    font-size: 12.5px;
    line-height: 1.6;
    color: var(--grey-0);
    background: var(--dcs-navy-900);
    border-radius: var(--radius-md);
    padding: 12px 40px 12px 14px;
    overflow-x: auto;
    white-space: pre;
}

.req-cmd__copy {
    position: absolute;
    top: 8px;
    right: 8px;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    height: 24px;
    padding: 0 8px;
    font-family: var(--font-sans);
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.75);
    background: rgba(255, 255, 255, 0.10);
    border: 1px solid rgba(255, 255, 255, 0.16);
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease-out);
}

.req-cmd__copy:hover {
    background: rgba(255, 255, 255, 0.18);
    color: #fff;
}

/* =========================================================================
   Summary card (right rail)
   ========================================================================= */
.sum-row {
    padding: 14px 18px;
    border-bottom: 1px solid var(--border-subtle);
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.sum-row:last-child {
    border-bottom: 0;
}

.sum-app {
    font-size: 15px;
    font-weight: 700;
    color: var(--text-primary);
}

.sum-code {
    font-family: var(--font-mono);
    font-size: 12.5px;
    font-weight: 500;
    color: var(--text-primary);
}

.sum-line {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.sum-value {
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
}

.sum-tz {
    font-family: var(--font-mono);
    font-size: 13px;
    font-weight: 500;
    color: var(--text-primary);
}

.sum-note {
    font-size: 12px;
    line-height: 1.45;
    color: var(--text-muted);
    text-wrap: pretty;
}

.sum-empty {
    font-size: 13px;
    color: var(--text-subtle);
}

.iso-chip {
    font-family: var(--font-mono);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.06em;
    color: var(--dcs-navy-600);
    background: var(--dcs-navy-50);
    border-radius: var(--radius-sm);
    padding: 2px 6px;
}

/* Country flag as a subtle, quarter-turned watermark behind the whole card.
   The rows carry no background, so the flag whispers through every one of them. */
.ds-card--flagged {
    position: relative;
}

.ds-card--flagged > .card-strip,
.ds-card--flagged > .sum-row {
    position: relative;
    z-index: 1;
}

.sum-flag-card {
    position: absolute;
    z-index: 0;
    top: 50%;
    left: 50%;
    width: auto; /* beat flag-icons' fixed 1.333em width … */
    height: 100%;
    aspect-ratio: 1; /* … so this is a square the height of the card */
    transform: translate(-50%, -50%) rotate(90deg); /* a 90° turn then still covers it edge to edge */
    background-size: cover; /* override flag-icons' `contain` */
    background-position: center;
    opacity: 0.08;
    filter: saturate(1.1);
    pointer-events: none;
}

.sum-flag-card::before {
    content: none;
}

/* drop flag-icons' &nbsp; spacer */

/* =========================================================================
   Tools card (right rail)
   ========================================================================= */
.tool-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 13px 18px;
    border-bottom: 1px solid var(--border-subtle);
    transition: background var(--dur-fast) var(--ease-out);
}

.tool-row:last-child {
    border-bottom: 0;
}

.tool-row:hover {
    background: var(--grey-50);
    text-decoration: none;
}

.tool-main {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
}

.tool-icon {
    display: inline-flex;
    flex: none;
    color: var(--text-subtle);
    transition: color var(--dur-fast) var(--ease-out);
}

.tool-icon svg {
    width: 16px;
    height: 16px;
    display: block;
}

.tool-row:hover .tool-icon {
    color: var(--text-muted);
}

.tool-label {
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
}

.tool-state {
    font-size: 12px;
    color: var(--text-subtle);
}

.tool-state--ready {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--success);
}

.tool-state--mono {
    font-family: var(--font-mono);
}

/* =========================================================================
   Footer
   ========================================================================= */
.installer__footer {
    position: sticky;
    bottom: 0;
    z-index: 20;
    padding: 14px 32px;
    border-top: 1px solid var(--border-default);
    background: var(--bg-canvas);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
}

.installer__footer-text {
    font-size: 12px;
    color: var(--text-subtle);
}

.installer__footer-text b {
    color: var(--text-muted);
}

.installer__footer-logo {
    height: 14px;
    width: auto;
    opacity: 0.5;
}

/* =========================================================================
   Responsive — desktop tool; holds to ~1180px, then rail drops below
   ========================================================================= */
@media (max-width: 1180px) {
    .installer__main {
        grid-template-columns: minmax(0, 1fr);
    }

    .rail {
        position: static;
        top: auto;
    }
}

@media (max-width: 720px) {
    .env-grid {
        grid-template-columns: 1fr;
    }

    .env-cell--tl {
        border-right: 0;
    }

    .env-cell--bl {
        border-right: 0;
        border-bottom: 1px solid var(--border-subtle);
    }

    .installer__main {
        padding: 20px 16px 28px;
    }

    .topbar {
        padding: 0 16px;
    }
}

/* =========================================================================
   Form kit + wizard-step components (steps 1–9)
   ========================================================================= */

/* ---------- utilities (Bootstrap is not loaded on this layout) ------------ */
.installer .d-none {
    display: none !important;
}

.installer .text-center {
    text-align: center;
}

.installer .text-danger {
    color: var(--danger);
}

.installer .text-muted {
    color: var(--text-muted);
}

.installer .text-success {
    color: var(--success);
}

.installer .text-info {
    color: var(--info);
}

/* ---------- extra buttons ------------------------------------------------- */
.ds-btn--danger {
    background: var(--danger);
    color: #fff;
    border-color: var(--danger);
    box-shadow: var(--shadow-xs);
}

.ds-btn--danger:not([disabled]):hover {
    background: #b8362f;
    border-color: #b8362f;
}

/* ---------- card body / footer (cards are padding:0) ---------------------- */
.ds-card__body {
    padding: 20px;
}

.ds-card__body--tight {
    padding: 4px 0;
}

.ds-card__foot {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 12px;
    padding: 16px 20px;
    border-top: 1px solid var(--border-subtle);
}

.ds-card__foot--split {
    justify-content: space-between;
}

.ds-card__foot-group {
    display: flex;
    align-items: center;
    gap: 12px;
}

/* ---------- fields (label-above, one field per row) ---------------------- */
/* Spacing uses margins (not flex gap): Cache toggles its server sub-panels
   with jQuery .show(), which forces display:block and would defeat a gap. */
.form-body {
    padding: 20px;
}

.form-body > * + * {
    margin-top: 18px;
}

.installer .field {
    display: block;
    min-width: 0;
}

.field__label {
    display: block;
    margin-bottom: 6px;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-primary);
}

.field__label .req {
    color: var(--danger);
    margin-left: 4px;
}

.field__control {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.field__help {
    font-size: 12px;
    line-height: 1.4;
    color: var(--text-muted);
}

/* an error message replaces the hint in the same slot */
.field__control:has(.form-message:not(.d-none)) .field__help {
    display: none;
}

/* cache server sub-panels keep the same vertical rhythm */
.server-panel > * + * {
    margin-top: 18px;
}

.field__help code {
    font-family: var(--font-mono);
    font-size: 11.5px;
    color: var(--dcs-navy-600);
    background: var(--dcs-navy-50);
    border-radius: var(--radius-sm);
    padding: 1px 5px;
}

/* ---------- inputs / selects --------------------------------------------- */
.installer .form-control,
.installer .ds-input,
.installer .ds-select {
    width: 100%;
    height: 38px;
    padding: 0 12px;
    font-family: var(--font-sans);
    font-size: 14px;
    color: var(--text-primary);
    background: var(--surface-card);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-inset);
    appearance: none;
    -webkit-appearance: none;
    transition: border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}

.installer textarea.form-control {
    height: auto;
    min-height: 84px;
    padding: 10px 12px;
    line-height: 1.5;
    resize: vertical;
}

.installer .form-control:focus,
.installer select.form-control:focus {
    outline: none;
    border-color: var(--border-focus);
    box-shadow: var(--shadow-focus);
}

.installer .form-control::placeholder {
    color: var(--text-subtle);
}

.installer .form-control:disabled {
    background: var(--grey-100);
    color: var(--text-subtle);
    cursor: not-allowed;
}

.installer input.form-control[value]:read-only {
    background: var(--grey-50);
}

/* monospace where the value is a literal (host/port/path/code) */
.installer .form-control--mono {
    font-family: var(--font-mono);
    font-size: 13px;
}

/* Settings API-key field: masked on screen like a password, but kept type=text
   so browser password managers never autofill a saved login credential into it.
   Reveal.js drops .is-masked to reveal the typed value. */
.installer .form-control.is-masked {
    -webkit-text-security: disc;
    text-security: disc;
}

/* native select chevron */
.installer select.form-control {
    padding-right: 36px;
    cursor: pointer;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%237387a0' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 12px center;
    background-size: 14px;
}

/* validation states (Database / Product modules toggle these) */
.installer .form-control.is-invalid {
    border-color: var(--danger);
}

.installer .form-control.is-invalid:focus {
    box-shadow: 0 0 0 3px rgba(212, 69, 61, 0.28);
}

.installer .form-control.is-valid {
    border-color: var(--success);
}

.installer .form-message .form-text {
    font-size: 12px;
    line-height: 1.4;
}

/* ---------- range slider (Processes memory limit) ------------------------ */
.installer .ds-range {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.installer .ds-range__readout {
    align-self: flex-start;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-width: 120px;
    padding: 7px 14px;
    background: var(--accent-soft);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-inset);
}

.installer .ds-range__icon {
    display: flex;
    color: var(--text-subtle);
}

.installer .ds-range__icon svg {
    width: 16px;
    height: 16px;
    display: block;
}

.installer .ds-range__value {
    font-family: var(--font-mono);
    font-size: 18px;
    font-weight: 700;
    line-height: 1;
    /* tracks the slider position (set on .ds-range by the wiring script) */
    color: var(--thumb-color, var(--text-primary));
    transition: color var(--dur-fast) var(--ease-out);
}

.installer .ds-range__input {
    -webkit-appearance: none;
    appearance: none;
    width: 100%;
    height: 18px;
    margin: 0;
    padding: 0;
    background: transparent;
    cursor: pointer;
    --fill: 0%;
}

/* Track fill = a fixed red→amber→green spectrum revealed up to --fill; the
   region past the thumb is greyed by the top layer. Both engines use the same
   two-layer trick so the gradient maps to track-space (not the fill width). */
.installer .ds-range__input::-webkit-slider-runnable-track {
    height: 8px;
    border-radius: var(--radius-full);
    background-image:
        linear-gradient(to right, transparent var(--fill), var(--border-strong) var(--fill)),
        linear-gradient(to right, var(--danger), var(--warning), var(--success));
}

.installer .ds-range__input::-moz-range-track {
    height: 8px;
    border-radius: var(--radius-full);
    background-image:
        linear-gradient(to right, transparent var(--fill), var(--border-strong) var(--fill)),
        linear-gradient(to right, var(--danger), var(--warning), var(--success));
}

.installer .ds-range__input::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 18px;
    height: 18px;
    margin-top: -5px; /* centre the 18px thumb on the 8px track */
    border-radius: var(--radius-full);
    background: var(--surface-card);
    border: 2px solid var(--thumb-color, var(--success));
    box-shadow: var(--shadow-sm);
    transition: transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}

.installer .ds-range__input::-moz-range-thumb {
    width: 18px;
    height: 18px;
    border-radius: var(--radius-full);
    background: var(--surface-card);
    border: 2px solid var(--thumb-color, var(--success));
    box-shadow: var(--shadow-sm);
    transition: border-color var(--dur-fast) var(--ease-out);
}

.installer .ds-range__input:hover::-webkit-slider-thumb {
    transform: scale(1.08);
}

.installer .ds-range__input:focus {
    outline: none;
}

.installer .ds-range__input:focus-visible::-webkit-slider-thumb {
    box-shadow: 0 0 0 4px rgba(16, 56, 88, 0.18);
}

.installer .ds-range__input:focus-visible::-moz-range-thumb {
    box-shadow: 0 0 0 4px rgba(16, 56, 88, 0.18);
}

/* stepped tick labels under the track (also click targets) */
.installer .ds-range__ticks {
    display: flex;
    justify-content: space-between;
    gap: 4px;
}

.installer .ds-range__tick {
    appearance: none;
    border: 0;
    background: none;
    padding: 2px 4px;
    cursor: pointer;
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--text-subtle);
    border-radius: var(--radius-sm);
    transition: color var(--dur-fast) var(--ease-out);
}

.installer .ds-range__tick:hover {
    color: var(--text-muted);
}

.installer .ds-range__tick.is-active {
    color: var(--thumb-color, var(--success));
    font-weight: 700;
}

/* ---------- size slider (product volume) --------------------------------- */
/* Fixed-stop range for a product's size/volume. The value box is the posted
   field: it mirrors the slider + tick presets but also accepts a custom value.
   Neutral brand fill (not the red->green spectrum) — a small size isn't "bad". */
.installer .size-range {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.installer .size-range__readout {
    align-self: flex-start;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-width: 148px;
    max-width: 100%;
    padding: 6px 12px;
    background: var(--accent-soft);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-inset);
    transition: border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}

.installer .size-range__readout:focus-within {
    border-color: var(--border-focus);
    box-shadow: var(--shadow-focus);
}

.installer .size-range__readout:has(.size-range__value.is-invalid) {
    border-color: var(--danger);
}

.installer .size-range__icon {
    display: flex;
    color: var(--text-subtle);
}

.installer .size-range__icon svg {
    width: 16px;
    height: 16px;
    display: block;
}

.installer .size-range__value {
    flex: 0 1 auto;
    width: 12ch;
    min-width: 0;
    padding: 0;
    border: 0;
    background: transparent;
    box-shadow: none;
    font-family: var(--font-mono);
    font-size: 18px;
    font-weight: 700;
    line-height: 1;
    color: var(--text-primary);
    appearance: none;
    -webkit-appearance: none;
}

.installer .size-range__value:focus {
    outline: none;
}

.installer .size-range__value::placeholder {
    font-size: 14px;
    font-weight: 400;
    color: var(--text-subtle);
}

.installer .size-range__value.is-invalid {
    color: var(--danger);
}

.installer .size-range__input {
    -webkit-appearance: none;
    appearance: none;
    width: 100%;
    height: 18px;
    margin: 0;
    padding: 0;
    background: transparent;
    cursor: pointer;
    --fill: 0%;
}

/* fill = brand green up to the thumb, track grey past it (both engines) */
.installer .size-range__input::-webkit-slider-runnable-track {
    height: 8px;
    border-radius: var(--radius-full);
    background-image: linear-gradient(to right, var(--irix) var(--fill), var(--border-strong) var(--fill));
}

.installer .size-range__input::-moz-range-track {
    height: 8px;
    border-radius: var(--radius-full);
    background-image: linear-gradient(to right, var(--irix) var(--fill), var(--border-strong) var(--fill));
}

.installer .size-range__input::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 18px;
    height: 18px;
    margin-top: -5px; /* centre the 18px thumb on the 8px track */
    border-radius: var(--radius-full);
    background: var(--surface-card);
    border: 2px solid var(--irix);
    box-shadow: var(--shadow-sm);
    transition: transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}

.installer .size-range__input::-moz-range-thumb {
    width: 18px;
    height: 18px;
    border-radius: var(--radius-full);
    background: var(--surface-card);
    border: 2px solid var(--irix);
    box-shadow: var(--shadow-sm);
}

.installer .size-range__input:hover::-webkit-slider-thumb {
    transform: scale(1.08);
}

.installer .size-range__input:focus {
    outline: none;
}

.installer .size-range__input:focus-visible::-webkit-slider-thumb {
    box-shadow: 0 0 0 4px rgba(16, 168, 80, 0.22);
}

.installer .size-range__input:focus-visible::-moz-range-thumb {
    box-shadow: 0 0 0 4px rgba(16, 168, 80, 0.22);
}

/* stepped preset labels under the track (also click targets) */
.installer .size-range__ticks {
    display: flex;
    justify-content: space-between;
    gap: 2px;
    overflow-x: auto;
    scrollbar-width: none;
}

.installer .size-range__ticks::-webkit-scrollbar {
    display: none;
}

.installer .size-range__tick {
    appearance: none;
    border: 0;
    background: none;
    padding: 2px 3px;
    cursor: pointer;
    font-family: var(--font-mono);
    font-size: 10.5px;
    white-space: nowrap;
    color: var(--text-subtle);
    border-radius: var(--radius-sm);
    transition: color var(--dur-fast) var(--ease-out);
}

.installer .size-range__tick:hover {
    color: var(--text-muted);
}

.installer .size-range__tick.is-active {
    color: var(--irix);
    font-weight: 700;
}

/* ---------- segmented code input (Product instance password) -------------- */
/* a hidden proxy input carries the joined value into the form + serialize;
   OtpInput.js mirrors the proxy's is-valid / is-invalid class onto .otp so the
   boxes can reflect validation state (a plain descendant selector, since a
   sibling :has() isn't reliably applied for styling across target browsers) */
.installer .otp {
    display: flex;
    gap: 8px;
}

.installer .otp__box {
    flex: 1 1 0;
    min-width: 0;
    max-width: 52px;
    height: 46px;
    padding: 0;
    text-align: center;
    font-size: 18px;
    line-height: 46px;
    color: var(--text-primary);
    background: var(--surface-card);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-inset);
    appearance: none;
    -webkit-appearance: none;
    transition: border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}

.installer .otp__box:focus {
    outline: none;
    border-color: var(--border-focus);
    box-shadow: var(--shadow-focus);
}

.installer .otp.is-invalid .otp__box {
    border-color: var(--danger);
}

.installer .otp.is-invalid .otp__box:focus {
    box-shadow: 0 0 0 3px rgba(212, 69, 61, 0.28);
}

.installer .otp.is-valid .otp__box {
    border-color: var(--success);
}

/* ---------- segmented instance code (cc-name-env) ------------------------- */
/* same segmented family as .otp: a hidden proxy carries the joined value and
   CodeInput.js mirrors its is-valid / is-invalid class onto .seg-code */
.installer .seg-code {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
}

.installer .seg-code__cc,
.installer .seg-code__name {
    height: 46px;
    padding: 0 12px;
    font-family: var(--font-mono);
    font-size: 16px;
    color: var(--text-primary);
    background: var(--surface-card);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-inset);
    appearance: none;
    -webkit-appearance: none;
    transition: border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}

.installer .seg-code__cc {
    flex: 0 0 auto;
    width: 64px;
    text-align: center;
    letter-spacing: 0.14em;
}

.installer .seg-code__name {
    flex: 1 1 160px;
    min-width: 120px;
}

.installer .seg-code__cc:focus,
.installer .seg-code__name:focus {
    outline: none;
    border-color: var(--border-focus);
    box-shadow: var(--shadow-focus);
}

.installer .seg-code__cc::placeholder,
.installer .seg-code__name::placeholder {
    color: var(--text-subtle);
    letter-spacing: normal;
}

.installer .seg-code__sep {
    flex: 0 0 auto;
    font-family: var(--font-mono);
    font-size: 18px;
    font-weight: 700;
    color: var(--text-subtle);
    user-select: none;
}

/* environment: a connected test | live toggle */
.installer .seg-code__env {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: stretch;
    gap: 4px;
    height: 46px;
    padding: 4px;
    background: var(--surface-sunken);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-inset);
}

.installer .seg-code__env-btn {
    display: inline-flex;
    align-items: center;
    appearance: none;
    border: 0;
    padding: 0 14px;
    background: none;
    border-radius: var(--radius-sm);
    cursor: pointer;
    font-family: var(--font-mono);
    font-size: 13px;
    color: var(--text-muted);
    transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}

.installer .seg-code__env-btn:not(.is-active):hover {
    background: var(--surface-card);
    color: var(--text-primary);
}

.installer .seg-code__env-btn.is-active {
    background: var(--dcs-navy-500);
    color: var(--text-on-dark);
    box-shadow: var(--shadow-xs);
}

.installer .seg-code__env-btn:focus-visible {
    outline: none;
    box-shadow: var(--shadow-focus);
}

/* validation state mirrored from the hidden proxy (CodeInput.js) */
.installer .seg-code.is-invalid .seg-code__cc,
.installer .seg-code.is-invalid .seg-code__name,
.installer .seg-code.is-invalid .seg-code__env {
    border-color: var(--danger);
}

.installer .seg-code.is-invalid .seg-code__cc:focus,
.installer .seg-code.is-invalid .seg-code__name:focus {
    box-shadow: 0 0 0 3px rgba(212, 69, 61, 0.28);
}

.installer .seg-code.is-valid .seg-code__cc,
.installer .seg-code.is-valid .seg-code__name,
.installer .seg-code.is-valid .seg-code__env {
    border-color: var(--success);
}

/* ---------- tag / chips input (Security) — enhances [data-tags] ----------- */
/* chips write a hidden comma-separated carrier input; the field looks and
   focuses like a .form-control but grows to fit wrapped chips */
.installer .ds-tags {
    position: relative;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    width: 100%;
    min-height: 38px;
    padding: 4px 10px 4px 34px;
    background: var(--surface-card);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-inset);
    cursor: text;
    transition: border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}

.installer .input-row > .ds-tags {
    flex: 1 1 180px;
    min-width: 0;
}

.installer .ds-tags.is-focus {
    border-color: var(--border-focus);
    box-shadow: var(--shadow-focus);
}

.installer .ds-tags.is-error {
    border-color: var(--danger);
    box-shadow: 0 0 0 3px rgba(212, 69, 61, 0.28);
}

.installer .ds-tags__lead {
    position: absolute;
    left: 12px;
    top: 10px;
    display: flex;
    color: var(--text-subtle);
    pointer-events: none;
}

.installer .ds-tags__lead svg {
    width: 16px;
    height: 16px;
    display: block;
}

.installer .ds-tags.is-focus .ds-tags__lead {
    color: var(--text-muted);
}

.installer .ds-tag {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    max-width: 100%;
    padding: 2px 4px 2px 8px;
    background: var(--accent-soft);
    border: 1px solid var(--dcs-navy-200);
    border-radius: var(--radius-sm);
    font-family: var(--font-mono);
    font-size: 12.5px;
    line-height: 1.7;
    color: var(--text-primary);
}

.installer .ds-tag__label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.installer .ds-tag__x {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 16px;
    padding: 0;
    border: 0;
    background: none;
    color: var(--text-subtle);
    font-size: 15px;
    line-height: 1;
    cursor: pointer;
    border-radius: var(--radius-xs);
    transition: color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out);
}

.installer .ds-tag__x:hover {
    color: var(--danger);
    background: var(--danger-soft);
}

.installer .ds-tags__entry {
    flex: 1 1 90px;
    min-width: 90px;
    height: 28px;
    padding: 0;
    border: 0;
    background: none;
    outline: none;
    font-family: var(--font-mono);
    font-size: 13px;
    color: var(--text-primary);
}

.installer .ds-tags__entry::placeholder {
    color: var(--text-subtle);
}

/* ---------- flag combobox (Currency) — enhances select[data-flag-select] --- */
.installer .ds-combo {
    position: relative;
    width: 100%;
}

/* the native <select> stays in the form (submit + `required`), visually hidden */
.installer .ds-combo__native {
    position: absolute;
    left: 12px;
    bottom: 0;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

.installer .ds-combo__button {
    display: flex;
    align-items: center;
    gap: 10px;
    padding-left: 12px;
    padding-right: 36px;
    text-align: left;
    cursor: pointer;
}

.installer .ds-combo[data-open="true"] .ds-combo__button {
    border-color: var(--border-focus);
    box-shadow: var(--shadow-focus);
}

.installer .ds-combo__value {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
    flex: 1 1 auto;
}

.installer .ds-combo.is-empty .ds-combo__label {
    color: var(--text-subtle);
}

.installer .ds-combo__label {
    min-width: 0;
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.installer .ds-combo__sub {
    flex: 0 0 auto;
    font-family: var(--font-mono);
    font-size: 12px;
    color: var(--text-subtle);
    white-space: nowrap;
}

.installer .ds-combo__country {
    flex: 0 1 auto;
    min-width: 0;
    font-size: 12px;
    color: var(--text-subtle);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.installer .ds-combo__flag {
    flex: 0 0 auto;
    width: 22px;
    height: 16px;
    border-radius: 3px;
    background-color: var(--grey-100);
    background-size: cover;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.12);
}

.installer .ds-combo__flag::before {
    content: none;
}

/* drop flag-icons' nbsp spacer */
.installer .ds-combo__chevron {
    position: absolute;
    right: 12px;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    color: var(--text-subtle);
    pointer-events: none;
    transition: transform var(--dur-fast) var(--ease-out);
}

.installer .ds-combo[data-open="true"] .ds-combo__chevron {
    transform: translateY(-50%) rotate(180deg);
}

.installer .ds-combo__panel {
    position: fixed;
    z-index: 1000; /* fixed → escapes .ds-card overflow:hidden */
    background: var(--surface-card);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    overflow: hidden; /* clip search / list to the rounded corners */
    display: none;
}

.installer .ds-combo[data-open="true"] .ds-combo__panel {
    display: block;
}

/* filter box (long lists) */
.installer .ds-combo__search {
    position: relative;
    padding: 8px;
    border-bottom: 1px solid var(--border-subtle);
}

.installer .ds-combo__search-icon {
    position: absolute;
    left: 19px;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    color: var(--text-subtle);
    pointer-events: none;
}

.installer .ds-combo__search-input {
    width: 100%;
    height: 36px;
    padding: 0 10px 0 34px;
    font-family: var(--font-sans);
    font-size: 14px;
    color: var(--text-primary);
    background: var(--surface-card);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-inset);
    outline: none;
    transition: border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}

.installer .ds-combo__search-input:focus {
    border-color: var(--border-focus);
    box-shadow: var(--shadow-focus);
}

.installer .ds-combo__search-input::placeholder {
    color: var(--text-subtle);
}

.installer .ds-combo__list {
    margin: 0;
    padding: 6px;
    list-style: none;
    max-height: 264px;
    overflow-y: auto;
}

.installer .ds-combo__opt {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    border-radius: var(--radius-sm);
    font-size: 14px;
    color: var(--text-primary);
    cursor: pointer;
}

.installer .ds-combo__opt[hidden] {
    display: none;
}

/* [hidden] must beat display:flex */
.installer .ds-combo__opt.is-active {
    background: var(--dcs-navy-50);
}

.installer .ds-combo__opt[aria-selected="true"] {
    font-weight: 700;
}

.installer .ds-combo__opt .ds-combo__country {
    margin-left: auto;
}

/* push country + iso to the right */
.installer .ds-combo__opt .ds-combo__country ~ .ds-combo__sub {
    margin-left: 0;
}

.installer .ds-combo__opt .ds-combo__sub {
    margin-left: auto;
}

/* option description (e.g. cache compression) — stacks under the label */
.installer .ds-combo__desc {
    font-size: 12px;
    line-height: 1.35;
    color: var(--text-muted);
}

.installer .ds-combo__opt--desc {
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
}

.installer .ds-combo__opt--desc .ds-combo__label {
    flex: 0 0 auto;
    white-space: normal;
}

.installer .ds-combo__empty {
    padding: 14px 12px;
    font-size: 13px;
    color: var(--text-subtle);
    text-align: center;
}

/* ---- Rich entity rows (RichSelect.js): thumbnail + label/tags + note ---- */
.installer .ds-combo__thumb {
    flex: 0 0 auto;
    width: 30px;
    height: 30px;
    border-radius: var(--radius-sm);
    background: var(--surface-sunken);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    color: var(--text-subtle);
}

.installer .ds-combo__thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Icon variant of the lead thumbnail — a Lucide glyph instead of an image,
   tinted to match the same icon in the listing (see .wq-date__icon). */
.installer .ds-combo__thumb--icon {
    color: var(--water);
}

.installer .ds-combo__thumb--icon svg {
    width: 17px;
    height: 17px;
}

.installer .ds-combo__rich-main {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    flex: 1 1 auto;
}

.installer .ds-combo__rich-main .ds-combo__label {
    flex: 0 0 auto;
}

.installer .ds-combo__tags {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
}

.installer .ds-combo__tag {
    display: inline-flex;
    align-items: center;
    height: 16px;
    padding: 0 6px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: var(--text-muted);
    background: var(--surface-sunken);
    border-radius: var(--radius-sm);
    white-space: nowrap;
}

.installer .ds-combo__note {
    flex: 0 0 auto;
    margin-left: auto;
    padding-left: 8px;
    font-family: var(--font-mono);
    font-size: 12px;
    font-weight: 600;
    color: var(--text-body);
    white-space: nowrap;
}

/* rich rows stay vertically centred even when the meta tags wrap to a 2nd line */
.installer .ds-combo__opt--rich {
    align-items: center;
}

/* checkbox */
.installer .ds-check {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    cursor: pointer;
    font-size: 14px;
    color: var(--text-primary);
}

.installer .ds-check input {
    width: 18px;
    height: 18px;
    accent-color: var(--irix);
    margin: 0;
}

/* ---------- info note (e.g. current DB dsn) ------------------------------- */
.installer .form-note {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    margin-top: 16px;
    padding: 10px 14px;
    font-family: var(--font-mono);
    font-size: 12px;
    color: var(--text-muted);
    background: var(--dcs-navy-50);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    overflow-wrap: anywhere;
}

/* ---------- key/value list (instance kit, geo info) ---------------------- */
.installer .kv-list {
    display: flex;
    flex-direction: column;
}

.installer .kv-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 12px 20px;
    border-top: 1px solid var(--border-subtle);
    font-size: 14px;
}

.installer .kv-row:first-child {
    border-top: 0;
}

.installer .kv-key {
    color: var(--text-muted);
}

.installer .kv-val {
    color: var(--text-primary);
    font-weight: 600;
}

.installer .kv-val--mono {
    font-family: var(--font-mono);
    font-weight: 500;
}

/* ---------- version headline (download / install) ------------------------ */
.installer .version-head {
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 16px 20px;
    border-bottom: 1px solid var(--border-subtle);
}

.installer .version-head__num {
    font-family: var(--font-mono);
    font-size: 18px;
    font-weight: 700;
    color: var(--text-primary);
}

/* ---------- progress bar (Progress.js) ----------------------------------- */
.installer .progress-panel {
    margin-bottom: 20px;
}

/* step label (left) + percent (right) sit ABOVE the track, so a near-empty
   bar never clips its own read-out the way in-bar text used to. */
.installer .progress-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 10px;
    min-height: 18px;
}

.installer .progress-step {
    margin: 0;
    font-size: var(--text-sm);
    font-weight: var(--fw-semibold);
    color: var(--text-primary);
}

.installer .progress-percent {
    font-family: var(--font-mono);
    font-size: var(--text-sm);
    font-weight: var(--fw-semibold);
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.installer .progress {
    height: 16px;
    background: var(--grey-150);
    border-radius: var(--radius-full);
    overflow: hidden;
    box-shadow: var(--shadow-inset);
}

.installer .progress-bar {
    height: 100%;
    width: 0;
    border-radius: var(--radius-full);
    background: var(--info);
    transition: width var(--dur-slow) var(--ease-out), background-color var(--dur-base) var(--ease-out);
}

.installer .progress-bar.bg-info {
    background-color: var(--info);
}

.installer .progress-bar.bg-success {
    background-color: var(--success);
}

.installer .progress-bar.bg-danger {
    background-color: var(--danger);
}

/* a soft sheen sweeping left→right reads as "working" without the dated
   barber-pole; it rides on top of the solid fill colour. */
.installer .progress-bar-striped {
    background-image: linear-gradient(90deg,
        rgba(255, 255, 255, 0) 0%,
        rgba(255, 255, 255, .38) 50%,
        rgba(255, 255, 255, 0) 100%);
    background-size: 200% 100%;
    background-repeat: no-repeat;
    background-position: 180% 0;
}

.installer .progress-bar-animated {
    animation: progress-sheen 1.4s var(--ease-inout) infinite;
}

@keyframes progress-sheen {
    from { background-position: 180% 0; }
    to   { background-position: -80% 0; }
}

@media (prefers-reduced-motion: reduce) {
    .installer .progress-bar-animated { animation: none; }
}

/* footer strip inside the circular-progress card (Download step): the linear
   bar becomes a divided tray at the base of the same card as the ring, so the
   two progress reads harmonise into one unit. Clipped to the card radius by
   .ds-card overflow:hidden. */
.installer .progress-foot {
    padding: 16px 24px 20px;
    border-top: 1px solid var(--border-subtle);
    background: var(--grey-50);
}

/* ---------- "Find package" action card (Download step) ------------------- */
.installer .find-package {
    display: flex;
    align-items: center;
    gap: 16px;
}

.installer .find-package__icon {
    flex: none;
    display: grid;
    place-items: center;
    width: 44px;
    height: 44px;
    border-radius: var(--radius-md);
    background: var(--accent-soft);
    color: var(--accent);
}

.installer .find-package__icon svg {
    width: 20px;
    height: 20px;
}

.installer .find-package__text {
    flex: 1 1 auto;
    min-width: 0;
}

.installer .find-package__title {
    margin: 0 0 2px;
    font-size: var(--text-base);
    font-weight: var(--fw-bold);
    color: var(--text-primary);
}

.installer .find-package__help {
    margin: 0;
    font-size: var(--text-sm);
    color: var(--text-muted);
}

.installer .find-package .ds-btn {
    flex: none;
}

@media (max-width: 560px) {
    .installer .find-package {
        flex-wrap: wrap;
    }

    .installer .find-package .ds-btn {
        flex: 1 1 100%;
        justify-content: center;
    }
}

/* ---------- install actions list ----------------------------------------- */
.installer .action-list {
    display: flex;
    flex-direction: column;
}

.installer .action-item {
    appearance: none;
    -webkit-appearance: none;
    width: 100%;
    text-align: left;
    font-family: inherit;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 14px 20px;
    border: 0;
    border-top: 1px solid var(--border-subtle);
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
    background: var(--surface-card);
    text-decoration: none;
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease-out);
}

.installer .action-item:first-child {
    border-top: 0;
}

.installer .action-item:hover {
    background: var(--grey-50);
    text-decoration: none;
}

.installer .action-item--danger {
    color: var(--danger);
}

.installer .action-item--danger:hover {
    background: var(--danger-soft);
}

.installer .action-item.is-disabled {
    opacity: 0.5;
    pointer-events: none;
}

.installer .action-item--form {
    padding: 0;
}

.installer .action-item--form button {
    all: unset;
    box-sizing: border-box;
    width: 100%;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 14px 20px;
    font-size: 14px;
    font-weight: 600;
    color: inherit;
}

/* ---------- timezone map + custom modal ---------------------------------- */
/* country silhouette, recoloured to brand navy via CSS mask (the SVG is a
   flat black potrace shape loaded through --map-src, set by the template/JS) */
.installer .tz-map-panel {
    max-width: 340px;
    margin: 6px auto 0;
    padding: 20px 20px 16px;
}

.installer .tz-map {
    width: 100%;
    max-width: 260px;
    aspect-ratio: 1 / 1;
    margin: 0 auto;
    /* the country's flag, clipped to its silhouette: flag = background,
       silhouette = mask. Both images are set INLINE per-country (template +
       3.Timezone.js) so their relative url()s resolve against the document,
       not this stylesheet. */
    background-color: var(--dcs-navy-100); /* fallback if the flag can't load */
    background-repeat: no-repeat;
    background-position: center;
    background-size: cover;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
    -webkit-mask-size: contain;
    mask-size: contain;
}

.installer .tz-map-caption {
    margin-top: 14px;
    display: flex;
    visibility: collapse;
    align-items: center;
    justify-content: center;
    gap: 8px;
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
}

.installer .tz-map-caption .fi {
    flex: 0 0 auto;
    width: 22px;
    height: 16px;
    border-radius: 3px;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.12);
}

/* faint flag-filled country watermark behind the whole timezone card
   (same flag background + silhouette mask as .tz-map, set inline per-country) */
.installer .tz-card {
    position: relative;
    isolation: isolate;
}

.installer .tz-card-bg {
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    opacity: 0.08;
    background-repeat: no-repeat;
    background-position: center;
    background-size: cover;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
    -webkit-mask-size: cover;
    mask-size: cover;
}

/* form (left) + map (right) side by side; stacks on narrow screens */
.installer .tz-split {
    display: flex;
    align-items: stretch;
}

.installer .tz-split__form {
    flex: 3 1 0;
    min-width: 0;
}

.installer .tz-split__map {
    flex: 2 1 0;
    min-width: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
}

.installer .tz-split__map .tz-map-panel {
    margin: 0;
    width: 100%;
}

@media (max-width: 640px) {
    .installer .tz-split {
        flex-direction: column;
    }

    .installer .tz-split__map {
        border-left: 0;
        border-top: 1px solid var(--border-subtle);
    }
}

.installer .ds-modal {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: none;
}

.installer .ds-modal.is-open {
    display: block;
}

.installer .ds-modal__backdrop {
    position: absolute;
    inset: 0;
    background: rgba(10, 38, 64, 0.55);
}

.installer .ds-modal__panel {
    position: absolute;
    inset: 24px;
    background: var(--surface-card);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.installer .ds-modal__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 20px;
    border-bottom: 1px solid var(--border-subtle);
}

.installer .ds-modal__title {
    font-size: 16px;
    font-weight: 700;
    color: var(--text-primary);
}

.installer .ds-modal__close {
    border: 0;
    background: none;
    font-size: 24px;
    line-height: 1;
    cursor: pointer;
    color: var(--text-muted);
}

.installer .ds-modal__close:hover {
    color: var(--text-primary);
}

.installer .ds-modal__body {
    flex: 1;
    min-height: 0;
}

.installer .ds-modal__body #chartdiv {
    width: 100%;
    height: 100%;
}

/* ---------- tagify (security) restyle ------------------------------------ */
.installer .tagify {
    --tag-bg: var(--dcs-navy-50);
    --tag-text-color: var(--dcs-navy-700);
    --tag-remove-btn-color: var(--dcs-navy-600);
    width: 100%;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-md);
}

.installer .tagify:focus-within {
    border-color: var(--border-focus);
    box-shadow: var(--shadow-focus);
}

.installer .tagify__tag > div {
    border-radius: var(--radius-sm);
}

/* ---------- empty-state message (install: nothing downloaded) ------------ */
.installer .empty-note {
    padding: 22px 20px;
    font-size: 14px;
    color: var(--text-muted);
}

/* ---------- app-deleted overlay ------------------------------------------ */
.app-deleted {
    display: none;
    min-height: 100vh;
    align-items: center;
    justify-content: center;
    background: var(--bg-page);
}

.app-deleted[style*="block"], .app-deleted.is-shown {
    display: flex;
}

.app-deleted__card {
    display: flex;
    flex-direction: column;
    gap: 8px;
    align-items: center;
    text-align: center;
    padding: 40px 48px;
    background: var(--surface-card);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
}

.app-deleted__text {
    font-size: 15px;
    color: var(--text-body);
}

/* ---------- input row (input + inline action buttons) -------------------- */
.installer .input-row {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.installer .input-row > .form-control,
.installer .input-row > .tagify {
    flex: 1 1 180px;
    min-width: 0;
}

/* ---------- circular progress caption (under the ring) ------------------- */
.installer .progress-description {
    margin: 16px auto 0;
    max-width: 34ch;                   /* keep long steps to a tidy wrap */
    min-height: 1.3em;                 /* reserve space so the ring never jumps */
    color: var(--text-muted);
    font-size: var(--text-sm);
    font-weight: var(--fw-medium);
    letter-spacing: var(--ls-tight);
}

/* ---------- narrow: tighten the field region padding -------------------- */
@media (max-width: 640px) {
    .form-body {
        padding: 16px;
    }
}

/* =========================================================================
   Database (Step 01) — header note, password reveal, test-result strip,
   action bar. Form conventions above apply to every step.
   ========================================================================= */
.card-strip__note {
    font-size: 12px;
    color: var(--text-subtle);
    white-space: nowrap;
}

/* password / affixed inputs */
.installer .input-affix {
    position: relative;
    display: flex;
}

.installer .input-affix .form-control {
    padding-right: 58px;
}

.installer .input-affix__toggle {
    position: absolute;
    right: 6px;
    top: 50%;
    transform: translateY(-50%);
    border: 0;
    background: none;
    cursor: pointer;
    padding: 4px 8px;
    font-family: var(--font-sans);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-subtle);
}

.installer .input-affix__toggle:hover {
    color: var(--text-primary);
}

/* leading icon inside an input / select */
.installer .input-icon {
    position: relative;
    display: flex;
}

.installer .input-icon > .form-control {
    padding-left: 38px;
}

.installer .input-icon__lead {
    position: absolute;
    left: 12px;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    color: var(--text-subtle);
    pointer-events: none;
    z-index: 1
}

.installer .input-icon__lead svg {
    width: 16px;
    height: 16px;
    display: block;
}

.installer .input-icon:focus-within .input-icon__lead {
    color: var(--text-muted);
}

/* leading icon on an input inside an inline action row (Security) */
.installer .input-row > .input-icon {
    flex: 1 1 180px;
    min-width: 0;
}

/* Tagify swaps the input for its own element — pad that so tags clear the icon */
.installer .input-icon > .tagify {
    padding-left: 38px;
}

/* test-result strip */
.db-result {
    margin: 0 20px 18px;
    padding: 12px 14px;
    border-radius: var(--radius-md);
    background: var(--dcs-navy-50);
    display: grid;
    grid-template-columns: 8px minmax(0, 1fr);
    column-gap: 12px;
    row-gap: 4px;
    align-items: center;
}

.db-result__dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--success);
}

.db-result__title {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary);
}

.db-result__banner {
    grid-row: 2;
    grid-column: 2;
    font-family: var(--font-mono);
    font-size: 12px;
    line-height: 1.45;
    color: var(--text-muted);
    overflow-wrap: anywhere;
}

.db-result--error {
    background: var(--danger-soft);
}

.db-result--error .db-result__dot {
    background: var(--danger);
}

.db-result--error .db-result__title {
    color: var(--danger);
}

/* detect-databases picker (Database step) */
.installer .db-picker {
    position: relative;
}

/* needs .input-affix in the selector to outspecify `.input-affix .form-control` (58px) */
.installer .input-affix .db-picker__input {
    padding-right: 92px;
}

/* clear the Detect affix button */

.installer .db-detect {
    display: inline-flex;
    align-items: center;
    gap: 5px;
}

.installer .db-detect svg {
    width: 14px;
    height: 14px;
}

.installer .db-detect__text {
    line-height: 1;
}

.installer .db-detect:disabled {
    cursor: default;
    opacity: 0.65;
}

.installer .db-detect.is-loading svg {
    animation: dcs-spin 0.7s linear infinite;
}

.installer .db-picker__menu {
    /* Database is the last field, and .ds-card clips overflow — so open UPWARD
       over the credential fields (ample room) instead of below the card edge. */
    position: absolute;
    z-index: 50;
    bottom: calc(100% + 6px);
    left: 0;
    right: 0;
    max-height: 244px;
    overflow-y: auto;
    padding: 6px;
    margin: 0;
    background: var(--surface-card);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
}

.installer .db-picker__head {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 8px 10px;
    margin-bottom: 4px;
    border-bottom: 1px solid var(--border-subtle);
}

.installer .db-picker__head-ic {
    display: inline-flex;
    flex: 0 0 auto;
    color: var(--accent);
}

.installer .db-picker__head-ic svg {
    width: 15px;
    height: 15px;
    display: block;
}

.installer .db-picker__server {
    font-size: 12.5px;
    font-weight: 800;
    color: var(--accent);
    white-space: nowrap;
}

.installer .db-picker__count {
    margin-left: auto;
    flex: 0 0 auto;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--text-subtle);
    white-space: nowrap;
}

.installer .db-opt {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 8px 10px;
    border: 0;
    border-radius: var(--radius-sm);
    background: none;
    cursor: pointer;
    text-align: left;
    font-family: var(--font-mono);
    font-size: 13px;
    color: var(--text-primary);
}

.installer .db-opt:not(.db-opt--used):hover,
.installer .db-opt:not(.db-opt--used):focus-visible {
    background: var(--dcs-navy-50);
    outline: none;
}

.installer .db-opt.is-selected {
    font-weight: 700;
}

/* non-empty → shown but inert; make that unmistakable */
.installer .db-opt--used {
    color: var(--text-subtle);
    cursor: not-allowed;
}

.installer .db-opt--used .db-opt__name {
    text-decoration: line-through;
    text-decoration-color: var(--border-strong);
}

.installer .db-opt__name {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.installer .db-opt__badge {
    flex: 0 0 auto;
    font-family: var(--font-sans);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    padding: 2px 7px;
    border-radius: 999px;
}

.installer .db-opt__badge--empty {
    color: var(--success);
    background: var(--success-soft);
}

.installer .db-opt__badge--used {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: var(--warning-shade, #9a6a12);
    background: var(--warning-soft);
}

.installer .db-opt__lock {
    width: 11px;
    height: 11px;
    flex: 0 0 auto;
}

.installer .db-picker__note {
    position: sticky;
    bottom: -6px; /* stay visible while the rows scroll */
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 4px -6px -6px;
    padding: 8px 10px; /* bleed into the menu's padding, full width */
    background: var(--surface-card);
    border-top: 1px solid var(--border-subtle);
    font-size: 11.5px;
    line-height: 1.35;
    color: var(--text-muted);
}

.installer .db-picker__note .db-opt__lock {
    color: var(--warning-shade, #9a6a12);
}

.installer .db-picker__msg {
    padding: 10px;
    font-size: 13px;
    color: var(--text-muted);
}

.installer .db-picker__msg--error {
    color: var(--danger);
}

/* action bar (footer with a timestamp on the left) */
.installer .ds-card__foot.action-bar {
    justify-content: space-between;
    background: var(--grey-50);
}

.action-bar__meta {
    font-size: 12px;
    color: var(--text-subtle);
}

/* Inline icon trailing a footer-meta link (e.g. Facebook insights "Open Page"):
   a bare lucide <svg> has no intrinsic size, so constrain it and align it with
   the text instead of letting it fall back to the default replaced-element box. */
.installer .action-bar__meta a svg {
    width: 13px;
    height: 13px;
    vertical-align: -2px;
    margin-left: 3px;
}

.action-bar__actions {
    display: flex;
    align-items: center;
    gap: 12px;
}

/* =========================================================================
   SweetAlert2
   Dialogs render on <body> (outside .installer), so these selectors are global.
   Tokens live on :root, so var() resolves here too.
   ========================================================================= */
.swal2-popup {
    font-family: var(--font-sans);
    border-radius: var(--radius-lg);
    border: 1px solid var(--border-default);
    box-shadow: var(--shadow-lg);
    padding: 24px 24px 20px;
    color: var(--text-body);
}

.swal2-title {
    font-size: 20px;
    font-weight: 800;
    color: var(--text-primary);
    padding: 4px 8px 0;
}

.swal2-html-container {
    font-size: 14.5px;
    line-height: 1.5;
    color: var(--text-body);
    margin: 10px 0 0;
}

.swal-em {
    color: var(--danger);
    font-weight: 700;
    text-decoration: underline;
}

.swal2-actions {
    gap: 10px;
    margin-top: 20px;
}

.swal2-styled {
    margin: 0;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    border-radius: var(--radius-md);
    border: 1px solid transparent;
    font-family: var(--font-sans);
    font-weight: 600;
    font-size: 14px;
    padding: 9px 18px;
    box-shadow: none;
    transition: background var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}

.swal2-styled:focus {
    outline: none;
    box-shadow: var(--shadow-focus);
}

.swal2-styled.swal2-confirm {
    background: var(--dcs-navy-700);
    color: #fff;
    border-color: var(--dcs-navy-700);
}

.swal2-styled.swal2-confirm:hover {
    background: var(--dcs-navy-800);
    border-color: var(--dcs-navy-800);
}

.swal2-styled.swal2-deny {
    background: var(--danger);
    color: #fff;
    border-color: var(--danger);
}

.swal2-styled.swal2-deny:hover {
    background: #b8362f;
    border-color: #b8362f;
}

.swal2-styled.swal2-cancel {
    background: var(--surface-card);
    color: var(--text-primary);
    border-color: var(--border-strong);
}

.swal2-styled.swal2-cancel:hover {
    background: var(--grey-50);
}

.swal2-btn-icon {
    width: 15px;
    height: 15px;
    flex: 0 0 auto;
}

/* status icons tinted to the DS palette */
.swal2-icon.swal2-question {
    border-color: var(--dcs-navy-200);
    color: var(--dcs-navy-500);
}

.swal2-icon.swal2-warning {
    border-color: #f0d9a8;
    color: var(--warning);
}

.swal2-icon.swal2-error {
    border-color: #eab7b3;
    color: var(--danger);
}

.swal2-icon.swal2-info {
    border-color: var(--dcs-navy-100);
    color: var(--info);
}

.swal2-icon.swal2-success {
    border-color: var(--irix-tint);
    color: var(--success);
}

.swal2-icon.swal2-success .swal2-success-ring {
    border-color: var(--irix-tint);
}

.swal2-icon.swal2-success [class^='swal2-success-line'] {
    background-color: var(--success);
}

/* ---------- products catalogue ------------------------------------------- */
.installer .product-grid {
    list-style: none;
    margin: 0;
    padding: 20px;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 16px;
}

.installer .product-card {
    position: relative;
    display: flex;
    flex-direction: column;
    background: var(--surface-card);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-lg);
    overflow: hidden;
    transition: box-shadow 0.15s ease, border-color 0.15s ease;
}

.installer .product-card:hover {
    border-color: var(--border-strong);
    box-shadow: var(--shadow-md);
}

.installer .product-card__media {
    aspect-ratio: 4 / 3;
    background: var(--surface-sunken);
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}

.installer .product-card__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.installer .product-card__placeholder {
    color: var(--text-subtle);
}

.installer .product-card__placeholder svg {
    width: 40px;
    height: 40px;
}

.installer .product-card__body {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px 14px;
}

.installer .product-card__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
}

.installer .product-card__meta {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.installer .product-card__tag {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border-radius: var(--radius-full);
    background: var(--surface-sunken);
    border: 1px solid var(--border-subtle);
    font-size: 11px;
    font-weight: 600;
    color: var(--text-muted);
}

.installer .product-card__tag--flag {
    background: var(--irix-tint);
    border-color: transparent;
    color: var(--irix-shade);
}

.installer .product-card__name {
    font-weight: 700;
    font-size: 14px;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.installer .product-card__price {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: baseline;
    gap: 4px;
    font-family: var(--font-mono);
    font-weight: 600;
    font-size: 14px;
    color: var(--irix-shade);
}

.installer .product-card__cur {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.04em;
    color: var(--text-subtle);
}

.installer .product-card__actions {
    position: absolute;
    top: 8px;
    right: 8px;
    display: flex;
    gap: 6px;
}

.installer .product-card__act-form {
    margin: 0;
}

.installer .product-card__act {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    padding: 0;
    border: 1px solid var(--border-default);
    border-radius: var(--radius-sm);
    background: var(--surface-card);
    color: var(--text-muted);
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease, opacity 0.15s ease;
}

/* Grid view: reveal actions on card hover/focus. List view keeps them
   always visible, like the devices/users table rows. */
.installer .product-grid:not(.product-grid--list) .product-card__act {
    opacity: 0;
}

.installer .product-grid:not(.product-grid--list) .product-card:hover .product-card__act,
.installer .product-grid:not(.product-grid--list) .product-card__act:focus-visible {
    opacity: 1;
}

.installer .product-card__act:hover {
    color: var(--text-primary);
    border-color: var(--border-strong);
}

.installer .product-card__act--danger:hover {
    color: var(--danger);
    border-color: var(--danger);
    background: var(--danger-soft);
}

.installer .product-card__act[disabled] {
    opacity: 0.45;
    cursor: not-allowed;
}

.installer .product-card__act[disabled]:hover {
    color: var(--text-muted);
    border-color: var(--border-default);
    background: var(--surface-card);
}

.installer .product-card__act svg {
    width: 15px;
    height: 15px;
}

/* ---- Grid / list view switch (segmented control) ---- */
.installer .product-view {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    margin-left: auto;
    padding: 3px;
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    background: var(--surface-sunken);
}

.installer .product-view__btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 26px;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text-subtle);
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
}

.installer .product-view__btn:hover {
    color: var(--text-primary);
}

.installer .product-view__btn.is-active {
    background: var(--surface-card);
    color: var(--irix-shade);
    box-shadow: var(--shadow-sm);
}

.installer .product-view__btn:focus-visible {
    outline: none;
    box-shadow: var(--shadow-focus);
}

.installer .product-view__btn svg {
    width: 16px;
    height: 16px;
}

/* ---- List view: relayout the same cards as horizontal rows ---- */
.installer .product-grid--list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.installer .product-grid--list .product-card {
    flex-direction: row;
    align-items: center;
    gap: 14px;
    padding: 8px;
}

.installer .product-grid--list .product-card__media {
    width: 48px;
    height: 48px;
    aspect-ratio: auto;
    flex: 0 0 auto;
    border-radius: var(--radius-md);
}

.installer .product-grid--list .product-card__placeholder svg {
    width: 20px;
    height: 20px;
}

.installer .product-grid--list .product-card__body {
    flex: 1 1 auto;
    flex-direction: row;
    align-items: center;
    gap: 14px;
    padding: 0;
    min-width: 0;
}

/* let the name and price join the row directly instead of stacking */
.installer .product-grid--list .product-card__head {
    display: contents;
}

.installer .product-grid--list .product-card__name {
    order: 1;
    flex: 1 1 auto;
    min-width: 0;
}

.installer .product-grid--list .product-card__meta {
    order: 2;
    flex: 0 1 auto;
    flex-wrap: nowrap;
    overflow: hidden;
    justify-content: flex-end;
}

.installer .product-grid--list .product-card__price {
    order: 3;
    flex: 0 0 auto;
    justify-content: flex-end;
    min-width: 92px;
}

/* actions sit inline at the row end */
.installer .product-grid--list .product-card__actions {
    order: 4;
    position: static;
    flex: 0 0 auto;
}

/* price input "RON" suffix in the add/edit modal */
.installer .product-form .input-icon {
    position: relative;
}

.installer .product-form .input-icon__suffix {
    position: absolute;
    top: 50%;
    right: 12px;
    transform: translateY(-50%);
    font-family: var(--font-mono);
    font-size: 12px;
    font-weight: 700;
    color: var(--text-subtle);
    pointer-events: none;
}

.installer .product-form #product-price {
    padding-right: 46px;
}

.installer .product-form__row {
    display: flex;
    gap: 16px;
}

.installer .product-form__row .form-element {
    flex: 1 1 0;
    min-width: 0;
}

/* Toggle switch — a wrapped checkbox styled as a switch. Shared by the product
   and device forms; the input stays a real checkbox so the posted value and any
   JS that sets .checked keep working unchanged. */
.installer .field-switch {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.6rem;
    cursor: pointer;
    user-select: none;
}

.installer .field-switch__input {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: 0;
    opacity: 0;
    appearance: none;
    -webkit-appearance: none;
}

.installer .field-switch__track {
    position: relative;
    flex: none;
    box-sizing: border-box;
    width: 42px;
    height: 24px;
    border-radius: var(--radius-full);
    background: var(--surface-sunken);
    border: 1px solid var(--border-default);
    transition: background 0.18s ease, border-color 0.18s ease;
}

.installer .field-switch__thumb {
    position: absolute;
    top: 50%;
    left: 2px;
    transform: translateY(-50%);
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: var(--surface-raised);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.28);
    transition: left 0.18s ease, background 0.18s ease;
}

.installer .field-switch__input:checked + .field-switch__track {
    background: var(--info);
    border-color: var(--info);
}

.installer .field-switch__input:checked + .field-switch__track .field-switch__thumb {
    left: calc(100% - 20px);
    background: #fff;
}

.installer .field-switch__input:focus-visible + .field-switch__track {
    outline: 2px solid var(--info);
    outline-offset: 2px;
}

.installer .field-switch__icon {
    display: inline-flex;
    flex: none;
    color: var(--text-muted);
}

.installer .field-switch__icon svg {
    width: 16px;
    height: 16px;
}

.installer .field-switch__text {
    font-size: var(--text-sm);
    color: var(--text-body);
}

/* ---------- products search + filters ------------------------------------ */
.installer .product-toolbar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px 12px;
    padding: 14px 20px;
    border-bottom: 1px solid var(--border-subtle);
}

.installer .product-toolbar__search {
    flex: 1 1 240px;
    min-width: 200px;
}

.installer .product-toolbar__search .form-control {
    width: 100%;
    padding-right: 34px;
}

.installer .product-toolbar__clear-search {
    position: absolute;
    right: 8px;
    top: 50%;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    padding: 0;
    border: 0;
    border-radius: var(--radius-full);
    background: var(--surface-sunken);
    color: var(--text-subtle);
    cursor: pointer;
    z-index: 1;
}

.installer .product-toolbar__clear-search:hover {
    color: var(--text-primary);
}

.installer .product-toolbar__clear-search svg {
    width: 13px;
    height: 13px;
}

.installer .product-toolbar__group {
    display: inline-flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
}

.installer .filter-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-full);
    background: var(--surface-card);
    font-size: 12px;
    font-weight: 600;
    color: var(--text-muted);
    cursor: pointer;
    white-space: nowrap;
    transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.installer .filter-chip:hover {
    border-color: var(--border-strong);
    color: var(--text-primary);
}

.installer .filter-chip.is-active {
    background: var(--irix);
    border-color: var(--irix);
    color: #fff;
}

.installer .filter-chip:focus-visible {
    outline: none;
    box-shadow: var(--shadow-focus);
}

.installer .filter-chip__icon {
    display: inline-flex;
    width: 0;
    overflow: hidden;
    opacity: 0;
    transition: width 0.15s ease, opacity 0.15s ease;
}

.installer .filter-chip__icon svg {
    width: 14px;
    height: 14px;
}

.installer .filter-chip--toggle.is-active .filter-chip__icon {
    width: 14px;
    opacity: 1;
}

/* Category filter chips carry an always-visible lead icon (unlike the toggle
   chips above, whose icon animates in only when active). */
.installer .filter-chip__lead {
    display: inline-flex;
    align-items: center;
}

.installer .filter-chip__lead svg {
    width: 14px;
    height: 14px;
}

.installer .product-toolbar__sort {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.installer .product-toolbar__sort-label {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-subtle);
}

.installer .product-toolbar__sort .form-control {
    width: auto;
    min-width: 132px;
}

.installer .product-toolbar__reset {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 10px;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    font-size: 12px;
    font-weight: 600;
    color: var(--irix-shade);
    cursor: pointer;
}

.installer .product-toolbar__reset:hover {
    background: var(--irix-tint);
}

.installer .product-toolbar__reset svg {
    width: 14px;
    height: 14px;
}

/* Collapse toggle: sits with the reset button on the right of the strip and
   expands/collapses the filter body below (state remembered per browser). */
.installer .card-strip__actions {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.installer .filter-collapse {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 10px;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    font-size: 12px;
    font-weight: 600;
    color: var(--text-subtle);
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
}

.installer .filter-collapse:hover {
    background: var(--surface-sunken);
    color: var(--text-primary);
}

.installer .filter-collapse:focus-visible {
    outline: none;
    box-shadow: var(--shadow-focus);
}

.installer .filter-collapse__chevron {
    display: inline-flex;
    align-items: center;
}

.installer .filter-collapse__chevron svg {
    width: 15px;
    height: 15px;
    display: block;
    transition: transform var(--dur-base) var(--ease-out);
}

.installer .filter-collapse[aria-expanded="true"] .filter-collapse__chevron svg {
    transform: rotate(180deg);
}

/* Collapsed: hide the filter body. On a dedicated filter card (products, stock)
   the toolbar is the only body, so also drop the now-dangling strip divider; on
   an inline card (orders, events) a listing still follows, so the strip keeps it. */
.installer [data-filter-card].is-collapsed .product-toolbar {
    display: none;
}

.installer [data-filter-solo].is-collapsed > .card-strip {
    border-bottom: 0;
}

/* Sort + display controls sit in their own strip above the listing: the
   display switch on the left, the sort select pushed to the right. */
.installer .product-listbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 10px 16px;
    padding: 14px 20px;
    border-bottom: 1px solid var(--border-subtle);
}

.installer .product-listbar__group {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

/* the switch is aligned by the strip, not by its own auto margin */
.installer .product-listbar .product-view {
    margin-left: 0;
}

/* only a sort control (no display switch) — keep it to the right */
.installer .product-listbar--end {
    justify-content: flex-end;
}

/* Products listing header (HTMX + Alpine): the view switch and sort now live in
   the card strip beside the title + count, mirroring the stock screen. Tint the
   strip so it reads as a distinct band above the grid, and cluster the tools on
   the right. The card clips to its radius, so the fill rounds cleanly. */
.installer #products-listing > .card-strip,
.installer #products-filter > .card-strip {
    background: var(--surface-sunken);
}

.installer .card-strip__tools {
    display: inline-flex;
    align-items: center;
    gap: 14px;
    margin-left: auto;
    flex-wrap: wrap;
}

/* the view switch + sort are aligned by the tools cluster, not their own auto
   margins, so they stay grouped together on the right of the strip. */
.installer .card-strip__tools .product-view,
.installer .card-strip__tools .card-strip__sort {
    margin-left: 0;
}

/* ---------- orders ------------------------------------------------------- */
.installer .order-list {
    list-style: none;
    margin: 0;
    padding: 20px;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: 16px;
}

.installer .order-card {
    display: flex;
    flex-direction: column;
    background: var(--surface-card);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-lg);
    overflow: hidden;
    transition: box-shadow 0.15s ease, border-color 0.15s ease;
}

.installer .order-card:hover {
    border-color: var(--border-strong);
    box-shadow: var(--shadow-md);
}

.installer .order-card__head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 10px;
    padding: 12px 14px;
    background: var(--surface-sunken);
    border-bottom: 1px solid var(--border-subtle);
}

.installer .order-card__ident {
    display: flex;
    flex-direction: column;
    gap: 2px;
    flex: 1 1 auto;
    min-width: 0;
}

.installer .order-card__id {
    font-weight: 800;
    font-size: 14px;
    color: var(--text-primary);
}

.installer .order-card__name {
    font-weight: 800;
    font-size: 14px;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.installer .order-card__date {
    font-size: 12px;
    color: var(--text-subtle);
}

.installer .order-card__desc {
    margin: 0;
    padding: 10px 14px 0;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--text-muted);
    white-space: pre-line;
    word-break: break-word;
}

.installer .order-card__actions {
    display: flex;
    gap: 6px;
}

.installer .order-card__act-form {
    margin: 0;
}

.installer .order-card__act {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border: 1px solid var(--border-default);
    border-radius: var(--radius-full);
    background: var(--surface-card);
    color: var(--text-muted);
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}

.installer .order-card__act:hover {
    color: var(--text-primary);
    border-color: var(--border-strong);
}

.installer .order-card__act--danger:hover {
    color: #fff;
    background: var(--danger);
    border-color: var(--danger);
}

.installer .order-card__act svg {
    width: 15px;
    height: 15px;
}

.installer .order-lines {
    list-style: none;
    margin: 0;
    padding: 8px 14px;
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.installer .order-line {
    display: flex;
    align-items: baseline;
    gap: 8px;
    padding: 4px 0;
    font-size: 13px;
}

.installer .order-line__qty {
    flex: 0 0 auto;
    font-family: var(--font-mono);
    font-weight: 700;
    color: var(--irix-shade);
}

.installer .order-line__name {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--text-body);
}

.installer .order-line__unit {
    flex: 0 0 auto;
    font-family: var(--font-mono);
    font-size: 12px;
    color: var(--text-subtle);
}

.installer .order-line__price {
    flex: 0 0 auto;
    min-width: 72px;
    text-align: right;
    font-family: var(--font-mono);
    font-weight: 600;
    color: var(--text-body);
}

.installer .order-line--missing .order-line__name {
    color: var(--text-subtle);
    font-style: italic;
}

.installer .order-card__foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px 14px;
    border-top: 1px solid var(--border-subtle);
}

.installer .order-card__count {
    font-size: 12px;
    color: var(--text-subtle);
}

.installer .order-card__total {
    font-size: 13px;
    color: var(--text-muted);
}

.installer .order-card__total b {
    font-family: var(--font-mono);
    font-size: 14px;
    color: var(--irix-shade);
}

/* order modal — dynamic line items */
.installer .order-items {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.installer .order-items__labels {
    display: grid;
    grid-template-columns: 1fr 92px 60px 34px;
    gap: 8px;
    padding: 0 2px;
}

.installer .order-items__labels span {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-subtle);
}

.installer .order-item {
    display: grid;
    grid-template-columns: 1fr 92px 60px 34px;
    gap: 8px;
    align-items: center;
}

.installer .order-item__price,
.installer .order-item__qty {
    text-align: center;
}

.installer .order-item__remove {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border: 1px solid var(--border-default);
    border-radius: var(--radius-md);
    background: var(--surface-card);
    color: var(--text-subtle);
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}

.installer .order-item__remove:hover {
    color: #fff;
    background: var(--danger);
    border-color: var(--danger);
}

.installer .order-item__remove svg {
    width: 15px;
    height: 15px;
}

.installer .order-add-item {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    align-self: flex-start;
    padding: 8px 12px;
    border: 1.5px dashed var(--border-strong);
    border-radius: var(--radius-md);
    background: none;
    color: var(--text-muted);
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
}

.installer .order-add-item:hover {
    border-color: var(--border-focus);
    color: var(--text-primary);
    background: var(--accent-soft);
}

.installer .order-add-item svg {
    width: 16px;
    height: 16px;
}

.installer .order-total-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 14px;
    border-radius: var(--radius-md);
    background: var(--surface-sunken);
    font-size: 14px;
    color: var(--text-muted);
}

.installer .order-total-bar__value b {
    font-family: var(--font-mono);
    font-size: 16px;
    color: var(--irix-shade);
}

.installer .order-total-bar__hint {
    margin-left: 6px;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--text-subtle);
}

/* Events modal: add/total sit inside a field, so they miss the form's flex
   gap — restore spacing between the "Add product" button and the total bar. */
.installer .event-total-bar {
    margin-top: 16px;
}

/* ─── Tax rows (order modal) ─── */
.installer .order-taxes {
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.installer .order-taxes__labels {
    display: grid;
    grid-template-columns: 1fr 92px 60px 100px 34px;
    gap: 8px;
    padding: 0 2px;
}
.installer .order-taxes__labels span {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-subtle);
}
.installer .order-tax-item {
    display: grid;
    grid-template-columns: 1fr 92px 60px 100px 34px;
    gap: 8px;
    align-items: center;
}
.installer .order-tax-item__unit-amount,
.installer .order-tax-item__qty {
    text-align: center;
}
.installer .order-tax-item__amount {
    font-family: var(--font-mono);
    font-size: 13px;
    color: var(--text-muted);
    text-align: right;
    white-space: nowrap;
}
/* Subtotal bar — shown only when taxes exist */
.installer .order-total-bar--sub {
    background: none;
    padding: 4px 14px 0;
    font-size: 13px;
    color: var(--text-subtle);
}
.installer .order-total-bar--sub .order-total-bar__value b {
    font-size: 13px;
    color: var(--text-muted);
}
/* ─── Tax summary on the order card ─── */
.installer .order-card__taxes {
    padding: 6px 14px 8px;
    border-top: 1px solid var(--border-subtle);
    display: flex;
    flex-direction: column;
    gap: 3px;
}
.installer .order-card__subtotal,
.installer .order-card__tax-line {
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-size: 12px;
    color: var(--text-muted);
}
.installer .order-card__subtotal {
    color: var(--text-subtle);
    padding-bottom: 4px;
    margin-bottom: 2px;
    border-bottom: 1px dashed var(--border-subtle);
}
.installer .order-card__invoice-link {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 12px;
    color: var(--text-muted);
    text-decoration: none;
}
.installer .order-card__invoice-link:hover {
    color: var(--irix-shade);
}
.installer .order-card__invoice-link svg {
    width: 13px;
    height: 13px;
}

/* ---------- events ------------------------------------------------------- */
.installer .event-list {
    list-style: none;
    margin: 0;
    padding: 20px;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 16px;
}

.installer .event-card {
    /* Per-card status palette: --ev is the accent, --ev-ink its readable text
       tone. Defaults cover an unknown status; the [data-status] rules and the
       --next modifier below reset them. Mirrors the dashboard Upcoming-events
       rows: a discrete status tint plus a coloured left stripe. */
    --ev: var(--dcs-navy-400);
    --ev-ink: var(--text-muted);
    position: relative;
    display: flex;
    flex-direction: column;
    background: color-mix(in srgb, var(--ev) 6%, var(--surface-card));
    border: 1px solid var(--border-subtle);
    border-left: 3px solid var(--ev);
    border-radius: var(--radius-lg);
    padding: 14px;
    transition: box-shadow 0.15s ease, border-color 0.15s ease;
}

.installer .event-card:hover {
    border-color: var(--border-strong);
    border-left-color: var(--ev);
    box-shadow: var(--shadow-md);
}

/* Discrete status colouring — the same palette as the Events status pill. */
.installer .event-card[data-status="Prospect"]  { --ev: var(--warning); --ev-ink: #8a5f16; }
.installer .event-card[data-status="Confirmed"] { --ev: var(--info);    --ev-ink: #1f5c9e; }
.installer .event-card[data-status="Completed"] { --ev: var(--success); --ev-ink: var(--irix-shade); }
.installer .event-card[data-status="Cancelled"] { --ev: var(--danger);  --ev-ink: #7a221d; }

/* The soonest upcoming event — the "next" — outranks its status colour with
   the brand navy and a heavier stripe. Qualified with [data-status] so the
   palette override beats the per-status rules above. */
.installer .event-card.event-card--next[data-status] {
    --ev: var(--dcs-navy-700);
    --ev-ink: var(--dcs-navy-700);
}
.installer .event-card--next {
    border-left-width: 4px;
    background: color-mix(in srgb, var(--dcs-navy-700) 8%, var(--surface-card));
}

/* "Next" tag on the soonest event, in its navy accent. */
.installer .event-card__next {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 10px;
    border-radius: var(--radius-full);
    background: var(--dcs-navy-700);
    color: var(--text-on-dark);
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.installer .event-card__next svg {
    width: 13px;
    height: 13px;
    flex: none;
}

.installer .event-card__body {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.installer .event-card__head {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding-right: 72px;
}

.installer .event-card__name {
    font-weight: 800;
    font-size: 15px;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.installer .event-card__date {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 13px;
    color: var(--text-muted);
}

.installer .event-card__date-icon {
    display: inline-flex;
    color: var(--irix-shade);
}

.installer .event-card__date-icon svg {
    width: 15px;
    height: 15px;
}

.installer .event-card__meta {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.installer .event-card__desc {
    margin: 0;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--text-muted);
    white-space: pre-line;
    word-break: break-word;
}

.installer .event-card__tag {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 9px;
    border-radius: var(--radius-full);
    background: var(--surface-sunken);
    border: 1px solid var(--border-subtle);
    font-size: 12px;
    font-weight: 600;
    color: var(--text-muted);
}

.installer .event-card__tag svg {
    width: 13px;
    height: 13px;
}

.installer .event-card__tag--total {
    background: var(--irix-tint);
    border-color: transparent;
    color: var(--irix-shade);
}

.installer .event-card__tag--cat {
    background: var(--irix-tint);
    border-color: transparent;
    color: var(--irix-shade);
    text-transform: uppercase;
    font-size: 11px;
    letter-spacing: 0.03em;
}

/* Status pill — where the event stands in its lifecycle. Soft tinted fill with
   a strong readable label and a leading icon (the same glyph the status carries
   in the Add/Edit event picker, see EventStatusEnum), coloured per status so the
   state reads at a glance: Prospect amber, Confirmed blue, Completed green. */
.installer .event-card__status {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 10px;
    border-radius: var(--radius-full);
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    background: var(--surface-sunken);
    color: var(--text-muted);
}

.installer .event-card__status svg {
    width: 13px;
    height: 13px;
    flex: none;
}

.installer .event-card__status[data-status="Prospect"] {
    background: var(--warning-soft);
    color: #8a6318;
}

.installer .event-card__status[data-status="Confirmed"] {
    background: var(--info-soft);
    color: #1f5c9e;
}

.installer .event-card__status[data-status="Completed"] {
    background: var(--success-soft);
    color: var(--irix-shade);
}

.installer .event-card__status[data-status="Cancelled"] {
    background: var(--danger-soft);
    color: #7a221d;
}

/* Status filter chips carry a matching colour dot at rest, and adopt the
   status colour when active (the dot flips to the active text colour). */
.installer .filter-chip__dot {
    width: 8px;
    height: 8px;
    border-radius: var(--radius-full);
    background: var(--grey-400);
    flex: none;
}

.installer .filter-chip__dot[data-status="Prospect"]  { background: var(--warning); }
.installer .filter-chip__dot[data-status="Confirmed"] { background: var(--info); }
.installer .filter-chip__dot[data-status="Completed"] { background: var(--success); }
.installer .filter-chip__dot[data-status="Cancelled"] { background: var(--danger); }

.installer .filter-chip.is-active .filter-chip__dot { background: currentColor; }

.installer .filter-chip--status[data-status="Prospect"].is-active {
    background: var(--warning);
    border-color: var(--warning);
    color: #4a3410;
}

.installer .filter-chip--status[data-status="Confirmed"].is-active {
    background: var(--info);
    border-color: var(--info);
    color: #fff;
}

.installer .filter-chip--status[data-status="Completed"].is-active {
    background: var(--success);
    border-color: var(--success);
    color: #fff;
}

.installer .filter-chip--status[data-status="Cancelled"].is-active {
    background: var(--danger);
    border-color: var(--danger);
    color: #fff;
}

.installer .event-card__actions {
    position: absolute;
    top: 12px;
    right: 12px;
    display: flex;
    gap: 6px;
}

.installer .field__optional {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-subtle);
}

.installer .event-items {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-bottom: 8px;
}

.installer .event-item {
    display: grid;
    grid-template-columns: 26px 1fr 62px 84px 30px;
    gap: 8px;
    align-items: center;
}

.installer .event-item__num {
    font-family: var(--font-mono);
    font-size: 12px;
    font-weight: 600;
    color: var(--text-subtle);
    text-align: center;
}

.installer .event-item__price {
    font-family: var(--font-mono);
    font-size: 13px;
    color: var(--irix-shade);
    text-align: right;
    white-space: nowrap;
}

.installer .event-item .order-item__qty:disabled {
    opacity: 0.45;
    cursor: not-allowed;
}

.installer .event-card__consumed {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    padding-top: 10px;
    margin-top: 2px;
    border-top: 1px dashed var(--border-subtle);
}

.installer .event-card__consumed-label {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-subtle);
}

.installer .event-card__consumed-label svg {
    width: 13px;
    height: 13px;
}

.installer .event-consumed-tag {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border-radius: var(--radius-full);
    background: var(--surface-sunken);
    border: 1px solid var(--border-subtle);
    font-size: 12px;
    font-weight: 600;
    color: var(--text-muted);
}

.installer .event-consumed-tag.is-missing {
    color: var(--text-subtle);
    font-style: italic;
}

.installer .event-view {
    padding: 20px;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.installer .event-view__sub {
    margin: 0;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-muted);
}

.installer .event-view__desc {
    margin: 0;
    padding: 10px 12px;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--text-muted);
    white-space: pre-line;
    word-break: break-word;
    background: var(--surface-sunken);
    border-radius: var(--radius-md);
}

.installer .event-view__list {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.installer .event-view__row {
    display: grid;
    grid-template-columns: 28px 1fr auto auto;
    align-items: center;
    gap: 10px;
    padding: 9px 10px;
    border-radius: var(--radius-md);
}

.installer .event-view__row:nth-child(odd) {
    background: var(--surface-sunken);
}

.installer .event-view__num {
    font-family: var(--font-mono);
    font-size: 12px;
    font-weight: 600;
    color: var(--text-subtle);
    text-align: center;
}

.installer .event-view__name {
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.installer .event-view__qty {
    font-family: var(--font-mono);
    font-size: 12px;
    color: var(--text-muted);
    white-space: nowrap;
}

.installer .event-view__line {
    min-width: 76px;
    font-family: var(--font-mono);
    font-size: 13px;
    font-weight: 600;
    color: var(--irix-shade);
    text-align: right;
    white-space: nowrap;
}

.installer .event-view__row.is-missing .event-view__name {
    color: var(--text-subtle);
    font-style: italic;
    font-weight: 500;
}

.installer .event-view__empty {
    padding: 16px;
    text-align: center;
    font-size: 13px;
    color: var(--text-muted);
    background: var(--surface-sunken);
    border-radius: var(--radius-md);
}

.installer .event-card__cost {
    margin-left: auto;
    font-size: 13px;
    color: var(--text-muted);
    white-space: nowrap;
}

.installer .event-card__cost b {
    font-family: var(--font-mono);
    font-size: 14px;
    color: var(--irix-shade);
}

/* Money invoice strip on an event card: products + rental fee, less the deposit
   already paid, ending in the emphasised balance due. Only shown when the event
   carries money. */
.installer .event-card__totals {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 14px;
    padding-top: 10px;
    margin-top: 2px;
    border-top: 1px dashed var(--border-subtle);
}

.installer .event-total {
    display: inline-flex;
    align-items: baseline;
    gap: 5px;
    font-family: var(--font-mono);
    font-size: 13px;
    color: var(--text-body);
}

.installer .event-total__label {
    font-family: var(--font-sans);
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--text-subtle);
}

.installer .event-total--paid {
    color: var(--info);
}

/* Balance due is the bottom line — pushed to the end of the strip and emphasised. */
.installer .event-total--due {
    margin-left: auto;
}

.installer .event-total--due .event-total__label {
    color: var(--text-muted);
}

.installer .event-total--due b {
    font-family: var(--font-mono);
    font-weight: 700;
    color: var(--irix-shade);
}

/* Modal balance bar: the same shell as the products total bar, accented so the
   balance due reads as the headline figure. Spacing comes from the parent
   flex gap (form / view), so no extra margin here. */
.installer .event-balance-bar {
    background: var(--irix-tint);
    color: var(--irix-shade);
}

.installer .event-balance-bar .order-total-bar__hint {
    color: var(--irix-shade);
    opacity: 0.72;
}

/* Read-only view modal: the invoice footer (products / rental / grand / deposit)
   above the balance-due bar. */
.installer .event-view__totals {
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.installer .event-view__trow {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    padding: 6px 10px;
}

.installer .event-view__trow dt {
    margin: 0;
    font-size: 13px;
    color: var(--text-muted);
}

.installer .event-view__trow dd {
    margin: 0;
    font-family: var(--font-mono);
    font-size: 13px;
    font-weight: 600;
    color: var(--text-body);
}

.installer .event-view__trow--grand {
    margin-top: 2px;
    padding-top: 8px;
    border-top: 1px solid var(--border-subtle);
}

.installer .event-view__trow--grand dt {
    font-weight: 700;
    color: var(--text-primary);
}

.installer .event-view__trow--grand dd {
    color: var(--irix-shade);
}

.installer .event-view__trow--paid dd {
    color: var(--info);
}

/* ---------- food & drink estimate modal ---------------------------------- */
.installer .event-estimate {
    gap: 16px;
}

/* Editable per-head rates: a two-up grid of number inputs with a trailing unit. */
.installer .estimate-rates {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.installer .estimate-rates__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.installer .estimate-rates__reset {
    padding: 0;
    border: 0;
    background: none;
    font-size: 12px;
    font-weight: 600;
    color: var(--irix-shade);
    cursor: pointer;
}

.installer .estimate-rates__reset:hover {
    text-decoration: underline;
}

.installer .estimate-rates__grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
}

.installer .estimate-rate {
    display: flex;
    flex-direction: column;
    gap: 5px;
    margin: 0;
}

.installer .estimate-rate__label {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    font-weight: 600;
    color: var(--text-muted);
}

.installer .estimate-rate__label svg {
    width: 15px;
    height: 15px;
    color: var(--text-subtle);
}

.installer .estimate-rate__control {
    position: relative;
    display: flex;
    align-items: center;
}

.installer .estimate-rate__control .form-control {
    padding-right: 34px;
    -moz-appearance: textfield;
    appearance: textfield;
}

/* Drop the native number spinners so they don't collide with the unit suffix. */
.installer .estimate-rate__control .form-control::-webkit-outer-spin-button,
.installer .estimate-rate__control .form-control::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.installer .estimate-rate__unit {
    position: absolute;
    right: 12px;
    font-family: var(--font-mono);
    font-size: 12px;
    color: var(--text-subtle);
    pointer-events: none;
}

/* Headline totals — the four numbers a planner actually shops from. */
.installer .estimate-totals {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 8px;
}

.installer .estimate-total {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    padding: 12px 6px;
    text-align: center;
    background: var(--irix-tint);
    border-radius: var(--radius-md);
}

.installer .estimate-total__num {
    font-family: var(--font-mono);
    font-size: 13px;
    color: var(--text-muted);
}

.installer .estimate-total__num b {
    font-size: 19px;
    font-weight: 700;
    color: var(--irix-shade);
}

.installer .estimate-total__label {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--text-subtle);
}

.installer .estimate-total__label svg {
    width: 13px;
    height: 13px;
}

/* Per-line breakdown, styled like the read-only consumed-products list. */
.installer .estimate-list {
    gap: 2px;
}

.installer .estimate-row {
    display: grid;
    grid-template-columns: 26px minmax(0, 1fr) auto;
    align-items: center;
    gap: 10px;
    padding: 9px 10px;
    border-radius: var(--radius-md);
}

.installer .estimate-row:nth-child(odd) {
    background: var(--surface-sunken);
}

.installer .estimate-row__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--text-subtle);
}

.installer .estimate-row__icon svg {
    width: 16px;
    height: 16px;
}

.installer .estimate-row__body {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
}

.installer .estimate-row__label {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary);
}

.installer .estimate-row__basis {
    font-family: var(--font-mono);
    font-size: 12px;
    color: var(--text-muted);
}

.installer .estimate-row__total {
    font-family: var(--font-mono);
    font-size: 14px;
    font-weight: 700;
    color: var(--irix-shade);
    white-space: nowrap;
}

.installer .estimate-note {
    display: flex;
    align-items: flex-start;
    gap: 7px;
    margin: 0;
    font-size: 12px;
    line-height: 1.5;
    color: var(--text-subtle);
}

.installer .estimate-note svg {
    flex: none;
    width: 14px;
    height: 14px;
    margin-top: 1px;
}

@media (max-width: 560px) {
    .installer .estimate-rates__grid {
        grid-template-columns: minmax(0, 1fr);
    }

    .installer .estimate-totals {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* ---------- calendar ----------------------------------------------------- */
.installer .cal-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 12px;
    padding: 16px 20px;
    border-bottom: 1px solid var(--border-subtle);
}

.installer .cal-toolbar__nav {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.installer .cal-toolbar__month {
    min-width: 148px;
    text-align: center;
    font-size: 16px;
    font-weight: 800;
    color: var(--text-primary);
}

.installer .cal-nav-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: var(--radius-md);
    border: 1px solid var(--border-strong);
    background: var(--surface-card);
    color: var(--text-muted);
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease-out),
                color var(--dur-fast) var(--ease-out),
                border-color var(--dur-fast) var(--ease-out);
}

.installer .cal-nav-btn:hover {
    border-color: var(--irix);
    background: var(--irix-tint);
    color: var(--irix-shade);
}

.installer .cal-nav-btn svg {
    width: 18px;
    height: 18px;
}

.installer .cal-toolbar__right {
    display: inline-flex;
    align-items: center;
    gap: 12px;
}

.installer .cal-toolbar__count {
    font-size: 12px;
    font-weight: 600;
    color: var(--text-subtle);
}

.installer a.ds-btn.is-disabled {
    pointer-events: none;
}

.installer .cal-grid {
    padding: 12px;
}

.installer .cal-weekdays,
.installer .cal-week {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: 6px;
}

.installer .cal-week {
    margin-bottom: 6px;
}

.installer .cal-week:last-child {
    margin-bottom: 0;
}

.installer .cal-weekdays {
    margin-bottom: 6px;
}

.installer .cal-weekday {
    padding: 2px 8px;
    text-align: right;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-subtle);
}

.installer .cal-day {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 5px;
    min-height: 98px;
    padding: 7px;
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    background: var(--surface-card);
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease-out),
                border-color var(--dur-fast) var(--ease-out),
                box-shadow var(--dur-fast) var(--ease-out);
}

.installer .cal-day:hover {
    border-color: var(--irix);
    box-shadow: var(--shadow-md);
}

.installer .cal-day:focus-visible {
    outline: none;
    border-color: var(--irix);
    box-shadow: var(--shadow-focus);
}

.installer .cal-day.is-muted {
    background: var(--surface-sunken);
}

.installer .cal-day.is-muted .cal-day__num {
    opacity: 0.55;
}

.installer .cal-day.is-today {
    border-color: var(--irix);
    background: var(--surface-card);
    box-shadow: inset 0 0 0 1px var(--irix);
}

.installer .cal-day__top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    min-height: 22px;
}

.installer .cal-day__num {
    font-family: var(--font-mono);
    font-size: 13px;
    font-weight: 700;
    color: var(--text-primary);
}

.installer .cal-day.is-today .cal-day__num {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 22px;
    height: 22px;
    padding: 0 5px;
    border-radius: var(--radius-full);
    background: var(--irix);
    color: var(--text-on-dark);
}

.installer .cal-day__add {
    display: inline-flex;
    color: var(--irix-shade);
    opacity: 0;
    transition: opacity var(--dur-fast) var(--ease-out);
}

.installer .cal-day__add svg {
    width: 15px;
    height: 15px;
}

.installer .cal-day:hover .cal-day__add,
.installer .cal-day:focus-visible .cal-day__add {
    opacity: 1;
}

.installer .cal-day__events {
    display: flex;
    flex-direction: column;
    gap: 3px;
    overflow: hidden;
}

.installer .cal-event {
    max-width: 100%;
    padding: 2px 7px;
    border: 1px solid transparent;
    border-radius: var(--radius-full);
    background: var(--surface-sunken);
    color: var(--text-muted);
    font-size: 11px;
    font-weight: 700;
    line-height: 1.5;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Category colours — differentiate events at a glance (see the legend). The
   border keeps a chip legible even when its fill matches the cell (e.g. a muted
   day). */
.installer .cal-event[data-category="Family"] {
    background: var(--irix-tint);
    color: var(--irix-shade);
    border-color: color-mix(in srgb, var(--irix-shade) 22%, transparent);
}

.installer .cal-event[data-category="Friends"] {
    background: var(--info-soft);
    color: var(--info);
    border-color: color-mix(in srgb, var(--info) 28%, transparent);
}

.installer .cal-event[data-category="Others"] {
    background: var(--surface-sunken);
    color: var(--text-muted);
    border-color: var(--border-strong);
}

.installer .cal-event--more {
    background: transparent;
    border-color: transparent;
    color: var(--text-subtle);
    font-weight: 600;
    cursor: default;
}

.installer .cal-event[data-id] {
    cursor: grab;
    user-select: none;
}

.installer .cal-event[data-id]:active {
    cursor: grabbing;
}

.installer .cal-event.is-dragging {
    opacity: 0.4;
}

.installer .cal-day.is-drop-target {
    border-color: var(--irix);
    background: var(--irix-tint);
    box-shadow: inset 0 0 0 2px var(--irix);
}

.installer .cal-delete {
    margin-right: auto;
}

/* Matches the stock legend (see .stock-legend): a sunken bar with a subtle
   divider. The toolbar's border-bottom above acts as the bar's top edge; the
   border-bottom here separates it from the grid that follows. */
.installer .cal-legend {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 16px;
    padding: 12px 20px;
    background: var(--surface-sunken);
    border-bottom: 1px solid var(--border-subtle);
}

.installer .cal-legend__item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    color: var(--text-muted);
}

.installer .cal-legend__dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--grey-400);
    flex: none;
}

.installer .cal-legend__item[data-category="Family"]  .cal-legend__dot { background: var(--irix); }
.installer .cal-legend__item[data-category="Friends"] .cal-legend__dot { background: var(--info); }
.installer .cal-legend__item[data-category="Others"]  .cal-legend__dot { background: var(--grey-400); }

@media (max-width: 640px) {
    .installer .cal-day {
        min-height: 68px;
        padding: 5px;
    }

    .installer .cal-weekday {
        padding: 2px 4px;
    }

    .installer .cal-event {
        padding: 1px 5px;
    }
}

/* ---------- stock -------------------------------------------------------- */
/* Tint the listing's header strip so the title + sort toolbar reads as a
   distinct band, not another header row stacked on the table's column heads.
   The card clips to its radius (overflow:hidden), so the fill rounds cleanly. */
.installer #stock-listing > .card-strip,
.installer #stock-filter > .card-strip {
    background: var(--surface-sunken);
}

/* Compact sort control in the stock listing header strip */
.installer .card-strip__sort .form-control {
    height: 32px;
    font-size: 12px;
}

/* The rail cards are wrapped in #stock-rail / #products-rail / #expenses-rail
   (HTMX out-of-band swap targets); display:contents drops the wrapper from the
   box tree so the cards stay direct flex children of .rail and keep its 20px gap
   between them. Without it the wrapper collapses that gap and the cards touch. */
.installer #stock-rail,
.installer #products-rail,
.installer #expenses-rail {
    display: contents;
}

.installer .stock-table-wrap {
    padding: 8px 8px 4px;
    overflow-x: auto;
}

.installer .stock-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 14px;
}

.installer .stock-table th {
    padding: 10px 14px;
    text-align: right;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-subtle);
    border-bottom: 1px solid var(--border-subtle);
    white-space: nowrap;
}

.installer .stock-table th.stock-table__product {
    text-align: left;
}

.installer .stock-table td {
    padding: 10px 14px;
    border-bottom: 1px solid var(--border-subtle);
    vertical-align: middle;
}

.installer .stock-table tbody tr:last-child td {
    border-bottom: 0;
}

.installer .stock-table__num {
    text-align: right;
    white-space: nowrap;
}

.installer .stock-table__act {
    text-align: right;
    white-space: nowrap;
    width: 1%; /* shrink to content so the numeric columns keep their space */
}

.installer .stock-fill-btn {
    display: inline-flex;
}

/* Manual column: the figure plus its inline "edit manual" pencil. */
.installer .stock-manual-cell {
    display: inline-flex;
    align-items: center;
    justify-content: flex-end;
    gap: 6px;
}

.installer .stock-manual-edit {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    padding: 0;
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-sm);
    background: var(--surface-card);
    color: var(--text-subtle);
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}

.installer .stock-manual-edit:hover {
    color: var(--text-primary);
    border-color: var(--border-strong);
}

.installer .stock-manual-edit:focus-visible {
    outline: none;
    box-shadow: var(--shadow-focus);
}

.installer .stock-manual-edit svg {
    width: 13px;
    height: 13px;
}

.installer td.stock-table__product {
    display: flex;
    align-items: center;
    gap: 10px;
}

.installer .stock-thumb {
    flex: 0 0 auto;
    width: 34px;
    height: 34px;
    border-radius: var(--radius-md);
    background: var(--surface-sunken);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    color: var(--text-subtle);
}

.installer .stock-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.installer .stock-thumb svg {
    width: 18px;
    height: 18px;
}

.installer .stock-name {
    font-weight: 600;
    color: var(--text-primary);
}

.installer .stock-num {
    font-family: var(--font-mono);
    font-weight: 600;
    font-size: 13px;
}

.installer .stock-num--ordered {
    color: var(--dcs-navy-500);
}

.installer .stock-num--manual {
    color: var(--warning);
}

.installer .stock-num--consumed {
    color: var(--danger);
}

.installer .stock-onhand {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 40px;
    padding: 3px 10px;
    border-radius: var(--radius-full);
    background: var(--irix-tint);
    color: var(--irix-shade);
    font-family: var(--font-mono);
    font-weight: 700;
}

.installer .stock-onhand.is-negative {
    background: var(--danger-soft);
    color: var(--danger);
}

.installer .stock-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    padding: 12px 20px;
    background: var(--surface-sunken);
    border-top: 1px solid var(--border-subtle);
}

.installer .stock-legend__item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    color: var(--text-muted);
}

.installer .stock-dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
}

.installer .stock-dot--ordered {
    background: var(--dcs-navy-500);
}

.installer .stock-dot--manual {
    background: var(--warning);
}

.installer .stock-dot--consumed {
    background: var(--danger);
}

/* ---- Stock grid (card) view — the alternate display to the table ---- */
.installer .stock-grid {
    list-style: none;
    margin: 0;
    padding: 20px;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 16px;
}

.installer .stock-card {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 14px;
    background: var(--surface-card);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-lg);
    transition: box-shadow 0.15s ease, border-color 0.15s ease;
}

.installer .stock-card:hover {
    border-color: var(--border-strong);
    box-shadow: var(--shadow-md);
}

.installer .stock-card__top {
    display: flex;
    align-items: center;
    gap: 10px;
}

.installer .stock-card__name {
    flex: 1 1 auto;
    min-width: 0;
    font-weight: 600;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.installer .stock-card__top .stock-onhand {
    flex: 0 0 auto;
}

.installer .stock-card__stats {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
    padding: 10px 0;
    border-top: 1px solid var(--border-subtle);
    border-bottom: 1px solid var(--border-subtle);
}

.installer .stock-card__stat {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    text-align: center;
}

.installer .stock-card__stat-label {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-subtle);
}

.installer .stock-card__fill {
    align-self: stretch;
    justify-content: center;
}

.installer .product-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 4px;
    padding: 56px 24px;
}

.installer .product-empty__icon {
    color: var(--text-subtle);
    margin-bottom: 6px;
}

.installer .product-empty__icon svg {
    width: 44px;
    height: 44px;
}

.installer .product-empty__title {
    margin: 0;
    font-size: 16px;
    font-weight: 700;
    color: var(--text-primary);
}

.installer .product-empty__sub {
    margin: 0 0 12px;
    font-size: 14px;
    color: var(--text-muted);
}

/* ---------- add-product modal (centered form) ---------------------------- */
.installer .ds-modal--form .product-modal__panel {
    position: absolute;
    inset: auto;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: min(480px, calc(100vw - 32px));
    max-height: calc(100vh - 48px);
    overflow: auto;
}

/* Wider variant — used by the event modal, whose consumed-product rows need
   more room for the product picker alongside qty / price / remove. */
.installer .ds-modal--form .product-modal__panel.product-modal__panel--wide {
    width: min(640px, calc(100vw - 32px));
}

.installer .product-form {
    padding: 20px;
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.installer .product-form .form-element {
    margin: 0;
}

.installer .product-form__foot {
    display: flex;
    justify-content: flex-end;
    gap: 12px;
    padding-top: 4px;
}

.installer .product-drop {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 150px;
    padding: 18px;
    border: 1.5px dashed var(--border-strong);
    border-radius: var(--radius-md);
    background: var(--surface-sunken);
    cursor: pointer;
    text-align: center;
    overflow: hidden;
    transition: border-color 0.15s ease, background 0.15s ease;
}

.installer .product-drop:hover {
    border-color: var(--border-focus);
    background: var(--accent-soft);
}

/* Active drag target (JS adds .is-dragover while a file is dragged over). */
.installer .product-drop.is-dragover {
    border-color: var(--border-focus);
    border-style: solid;
    background: var(--accent-soft);
}

.installer .product-drop.is-invalid {
    border-color: var(--danger);
}

.installer .product-drop__body {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    pointer-events: none;
}

.installer .product-drop__icon {
    color: var(--text-subtle);
}

.installer .product-drop__icon svg {
    width: 28px;
    height: 28px;
}

.installer .product-drop__text {
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
}

.installer .product-drop__hint {
    font-size: 12px;
    color: var(--text-subtle);
}

.installer .product-drop__preview {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.installer .product-drop.has-preview .product-drop__body {
    display: none;
}

/* ---------- import-from-CSV modal --------------------------------------- */
/* Intro line + column legend shown above the file picker. */
.installer .import-intro {
    margin: 0;
    font-size: var(--text-sm);
    color: var(--text-muted);
    line-height: var(--lh-normal);
}

.installer .import-format {
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    background: var(--surface-sunken);
    padding: 12px 14px;
}

.installer .import-format__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 10px;
}

.installer .import-format__title {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-size: var(--text-sm);
    font-weight: var(--fw-semibold);
    color: var(--text-primary);
}

.installer .import-format__title svg { width: 15px; height: 15px; color: var(--text-subtle); }

.installer .import-format__cols {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.installer .import-col {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 8px;
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-sm);
    background: var(--surface-card);
}

.installer .import-col code {
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    font-weight: var(--fw-semibold);
    color: var(--text-primary);
}

.installer .import-col__req,
.installer .import-col__hint {
    font-style: normal;
    font-size: 11px;
    color: var(--text-subtle);
}

.installer .import-col__req {
    color: var(--irix-shade);
    font-weight: var(--fw-semibold);
}

/* File picker reuses .product-drop but sits shorter — no image preview here. */
.installer .import-drop {
    min-height: 96px;
}

.installer .import-drop.has-file {
    border-style: solid;
    border-color: var(--border-focus);
    background: var(--accent-soft);
}

.installer .import-drop.has-file .product-drop__icon { color: var(--irix-shade); }

/* Skipped-rows report shown under the result banner (collapsible). */
.installer .import-report {
    margin: 0 0 16px;
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    background: var(--surface-sunken);
    overflow: hidden;
}

.installer .import-report__summary {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 14px;
    cursor: pointer;
    font-size: var(--text-sm);
    font-weight: var(--fw-semibold);
    color: var(--text-primary);
    list-style: none;
    user-select: none;
}

.installer .import-report__summary::-webkit-details-marker { display: none; }
.installer .import-report__summary svg { width: 16px; height: 16px; color: var(--text-subtle); flex: 0 0 auto; }
.installer .import-report[open] .import-report__summary { border-bottom: 1px solid var(--border-subtle); }

.installer .import-report__list {
    margin: 0;
    padding: 6px 0;
    list-style: none;
    max-height: 220px;
    overflow-y: auto;
}

.installer .import-report__row {
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 5px 14px;
    font-size: var(--text-sm);
}

.installer .import-report__line {
    flex: 0 0 auto;
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    font-weight: var(--fw-semibold);
    color: var(--text-subtle);
    min-width: 56px;
}

.installer .import-report__msg { color: var(--text-body); }

.installer .import-report__row--more {
    color: var(--text-subtle);
    font-style: italic;
    padding-left: 14px;
}

/* ---------- logs (activity feed) ---------------------------------------- */
.installer .logs-filters {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    padding: 12px 16px;
    border-bottom: 1px solid var(--border-subtle);
}

.installer .logs-filter {
    appearance: none;
    border: 1px solid var(--border-subtle);
    background: var(--surface-sunken);
    color: var(--text-muted);
    font-family: var(--font-sans);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.02em;
    padding: 5px 12px;
    border-radius: var(--radius-full);
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.installer .logs-filter:hover {
    color: var(--text-primary);
    border-color: var(--border-strong);
}

.installer .logs-filter.is-active {
    background: var(--dcs-navy-500);
    border-color: var(--dcs-navy-500);
    color: #ffffff;
}

.installer .logs-list {
    display: flex;
    flex-direction: column;
}

.installer .logs-row {
    display: grid;
    grid-template-columns: 66px 36px 1fr;
    gap: 14px;
    align-items: start;
    padding: 14px 16px;
    border-bottom: 1px solid var(--border-subtle);
}

.installer .logs-row:last-child {
    border-bottom: 0;
}

.installer .logs-row.is-hidden {
    display: none;
}

.installer .logs-row__time {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding-top: 2px;
}

.installer .logs-row__date {
    font-size: 12px;
    font-weight: 700;
    color: var(--text-primary);
    white-space: nowrap;
}

.installer .logs-row__clock {
    font-family: var(--font-mono);
    font-size: 12px;
    color: var(--text-subtle);
}

.installer .logs-icon {
    width: 36px;
    height: 36px;
    border-radius: var(--radius-md);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--surface-sunken);
    color: var(--text-subtle);
}

.installer .logs-icon svg {
    width: 18px;
    height: 18px;
}

.installer .logs-icon--product {
    background: var(--irix-tint);
    color: var(--irix-shade);
}

.installer .logs-icon--stock {
    background: var(--warning-soft);
    color: var(--warning);
}

.installer .logs-icon--order {
    background: var(--info-soft);
    color: var(--info);
}

.installer .logs-icon--event {
    background: var(--surface-sunken);
    color: var(--dcs-navy-500);
}

.installer .logs-icon--avatar {
    background: none;
    overflow: hidden;
}

.installer .logs-icon img {
    width: 100%;
    height: 100%;
    border-radius: inherit;
    object-fit: cover;
}

.installer .logs-row__body {
    min-width: 0;
}

.installer .logs-row__head {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 3px;
}

.installer .logs-pill {
    font-size: 10px;
    font-weight: 800;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    padding: 2px 8px;
    border-radius: var(--radius-full);
    background: var(--surface-sunken);
    color: var(--text-muted);
}

.installer .logs-pill--created,
.installer .logs-pill--filled {
    background: var(--success-soft);
    color: var(--irix-shade);
}

.installer .logs-pill--updated,
.installer .logs-pill--moved {
    background: var(--info-soft);
    color: var(--info);
}

.installer .logs-pill--deleted {
    background: var(--danger-soft);
    color: var(--danger);
}

.installer .logs-pill--consumed {
    background: var(--warning-soft);
    color: var(--warning);
}

.installer .logs-row__entity {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.03em;
    text-transform: capitalize;
    color: var(--text-subtle);
}

.installer .logs-row__summary {
    margin: 0;
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
}

.installer .logs-row__meta {
    margin: 3px 0 0;
    display: flex;
    flex-wrap: wrap;
    gap: 2px 14px;
    font-size: 12px;
    color: var(--text-muted);
}

.installer .logs-row__meta-item b {
    font-weight: 600;
    color: var(--text-subtle);
}

.installer .logs-empty-filter {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 4px;
    padding: 48px 24px;
}

.installer .logs-empty-filter[hidden] {
    display: none;
}

.installer .logs-empty-filter .product-empty__icon {
    color: var(--text-subtle);
}

/* Logs right-rail: action distribution (reuses the .logs-pill colours). */
.installer .rail-actions {
    list-style: none;
    margin: 0;
    padding: 12px 20px 16px;
    display: grid;
    gap: 11px;
}

.installer .rail-actions__row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
}

.installer .rail-actions__num {
    font-family: var(--font-mono);
    font-size: 14px;
    font-weight: 700;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}

/* =========================================================================
   Overview dashboard (home)
   ========================================================================= */

/* Tighter empty state for the dashboard's smaller cards. */
.installer .product-empty--tight {
    padding: 36px 24px;
}

/* ---------- Header source chip ---------- */
.ov-source {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 7px 12px;
    background: var(--surface-card);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-full);
    box-shadow: var(--shadow-xs);
    font-size: 12px;
    font-weight: 600;
    color: var(--text-muted);
}

.ov-source__icon {
    display: inline-flex;
    color: var(--irix);
}

.ov-source__icon svg { width: 15px; height: 15px; }

.ov-source__text { color: var(--text-primary); }

.ov-source__meta {
    padding-left: 8px;
    margin-left: 2px;
    border-left: 1px solid var(--border-default);
    font-family: var(--font-mono);
    font-size: 11px;
    font-weight: 500;
    color: var(--text-subtle);
}

/* ---------- KPI stat tiles ---------- */
.ov-stats {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 16px;
    margin-top: 24px;
}

.ov-stat {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 18px 20px 16px;
    background: var(--surface-card);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    text-decoration: none;
    color: inherit;
    transition: transform var(--dur-fast) var(--ease-out),
                box-shadow var(--dur-fast) var(--ease-out),
                border-color var(--dur-fast) var(--ease-out);
}

.ov-stat:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-md);
    border-color: var(--border-strong);
}

.ov-stat:hover .ov-stat__go {
    opacity: 1;
    transform: translateX(0);
}

.ov-stat__top {
    display: flex;
    align-items: center;
    gap: 10px;
}

.ov-stat__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: var(--radius-md);
    flex: 0 0 auto;
}

.ov-stat__icon svg { width: 18px; height: 18px; }

.ov-stat__icon--products { background: var(--success-soft); color: var(--irix-shade); }
.ov-stat__icon--orders   { background: var(--info-soft);    color: var(--info); }
.ov-stat__icon--events   { background: var(--warning-soft); color: #8a5f16; }
.ov-stat__icon--stock    { background: var(--dcs-navy-50);  color: var(--dcs-navy-600); }
.ov-stat__icon--pool     { background: var(--water-tint);  color: var(--water-shade); }
/* Devices get an indigo chip so they read distinctly from the five other tiles
   (no violet exists in the token set — a single accent pair, as with the amber
   used for events text). */
.ov-stat__icon--devices  { background: #e7e8fb;            color: #5850c4; }
/* Expenses (finance) take a teal chip — the seventh distinct tile accent, in the
   same single-pair style as the events amber and devices indigo above. */
.ov-stat__icon--expenses { background: #d9f2ee;            color: #0f7d6b; }

.ov-stat__label {
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.ov-stat__go {
    margin-left: auto;
    display: inline-flex;
    color: var(--text-subtle);
    opacity: 0;
    transform: translateX(-4px);
    transition: opacity var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
}

.ov-stat__go svg { width: 16px; height: 16px; }

.ov-stat__value {
    font-family: var(--font-mono);
    font-size: 30px;
    font-weight: 700;
    line-height: 1;
    letter-spacing: -0.01em;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}

.ov-stat__value.is-negative { color: var(--danger); }

/* Currency suffix on a money headline (Expenses) — a small muted unit set just
   after the figure, so a spend tile reads as money not a bare count. */
.ov-stat__cur {
    margin-left: 5px;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-muted);
}

.ov-stat__foot {
    font-size: 12.5px;
    color: var(--text-muted);
}

.ov-stat__foot b { color: var(--text-primary); font-weight: 700; }
.ov-danger { color: var(--danger) !important; }

/* ---------- Next-event countdown ----------
   A full-width counter under the KPI tiles: days left until the soonest event.
   The --tone trio (set by the --far/--soon/--urgent modifiers) warms the left
   rule, the icon chip and the figure from calm navy to amber to red as the
   date closes in. */
.ov-countdown {
    --tone: var(--dcs-navy-500);
    --tone-soft: var(--accent-soft);
    --tone-ink: var(--dcs-navy-700);
    display: flex;
    align-items: center;
    gap: 16px;
    margin-top: 16px;
    padding: 15px 20px;
    background: var(--surface-card);
    border: 1px solid var(--border-default);
    border-left: 4px solid var(--tone);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    text-decoration: none;
    color: inherit;
    transition: transform var(--dur-fast) var(--ease-out),
                box-shadow var(--dur-fast) var(--ease-out),
                border-color var(--dur-fast) var(--ease-out);
}

.ov-countdown:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-md);
    border-color: var(--border-strong);
    border-left-color: var(--tone);
}

.ov-countdown__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 42px;
    height: 42px;
    flex: 0 0 auto;
    border-radius: var(--radius-md);
    background: var(--tone-soft);
    color: var(--tone-ink);
}

.ov-countdown__icon svg { width: 22px; height: 22px; }

.ov-countdown__lead {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.ov-countdown__eyebrow {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-subtle);
}

.ov-countdown__name {
    font-size: 15.5px;
    font-weight: 700;
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.ov-countdown__when { font-size: 12.5px; color: var(--text-muted); }

.ov-countdown__count {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    line-height: 1;
    color: var(--tone-ink);
}

.ov-countdown__num {
    font-family: var(--font-mono);
    font-size: 34px;
    font-weight: 800;
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
}

.ov-countdown__unit {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--text-subtle);
    margin-top: 6px;
}

.ov-countdown__word {
    font-family: var(--font-display);
    font-size: 26px;
    font-weight: 800;
    letter-spacing: -0.01em;
}

.ov-countdown--far    { --tone: var(--dcs-navy-500); --tone-soft: var(--accent-soft);  --tone-ink: var(--dcs-navy-700); }
.ov-countdown--soon   { --tone: var(--warning);      --tone-soft: var(--warning-soft); --tone-ink: #8a5f16; }
.ov-countdown--urgent { --tone: var(--danger);       --tone-soft: var(--danger-soft);  --tone-ink: #7a221d; }

/* Nudge the eye when it is today/tomorrow — stilled for reduced-motion users. */
.ov-countdown--urgent .ov-countdown__icon svg {
    animation: ov-countdown-pulse 1.6s var(--ease-out) infinite;
}

@keyframes ov-countdown-pulse {
    0%, 100% { transform: scale(1); }
    50%      { transform: scale(1.12); }
}

@media (prefers-reduced-motion: reduce) {
    .ov-countdown--urgent .ov-countdown__icon svg { animation: none; }
}

/* When the countdown leads the page, the KPI tiles follow it on the standard
   16px card gap rather than their larger page-top margin. */
.ov-countdown + .ov-stats { margin-top: 16px; }

/* ---------- Two-column card rows ---------- */
.ov-cols {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
    margin-top: 16px;
}

.ov-panel { padding: 18px 20px 20px; }

/* ---------- Customisable dashboard board ----------
   The overview cards sit in one grid. "Customize" (see .is-editing below) turns
   on drag-to-reorder + per-card resize/remove; otherwise the board is static and
   each card shows its own icon. `align-items:start` is the key layout line: it
   lets each card end at its own content instead of stretching to match the
   tallest card in its row. State persists in localStorage — see OverviewBoard.js. */
.ov-board {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 16px;
    align-items: start;
    margin-top: 16px;
}

.ov-board > .ov-card { min-width: 0; }       /* let cards shrink inside the grid */
.ov-card--wide { grid-column: 1 / -1; }      /* span the full width of the board */

/* Every card wears the irix accent along its top edge (matching the weather
   card's .ds-card--irix), so the board reads as one banded set. */
.ov-board .ov-card { border-top: 3px solid var(--irix); }

/* Keep the count/note flush right now the strip has a leading icon/grip slot. */
.ov-board .card-strip > .eyebrow { margin-right: auto; }

/* Leading slot: the card's own icon (view mode) swaps for a drag grip (edit). */
.ov-card__lead {
    display: inline-flex;
    align-items: center;
    flex: 0 0 auto;
    color: var(--accent);
}

.ov-card__lead svg { width: 15px; height: 15px; }
.ov-card__grip { display: none; color: var(--text-subtle); }

/* ---- Board toolbar (Add · Reset + drag hint) ----
   Holds only edit-mode controls now that Customize lives in the page header, so
   the whole row is hidden in view mode and revealed while editing (below). */
.ov-board-tools {
    display: none;
    align-items: center;
    justify-content: flex-end;
    gap: 12px;
    margin-top: 16px;
    font-size: 12px;
    color: var(--text-subtle);
}

.ov-board-tools__hint {
    align-items: center;
    gap: 6px;
    margin-right: auto;   /* push the hint to the far left of the toolbar */
    line-height: 1.35;
}

.ov-board-tools__hint svg { width: 14px; height: 14px; opacity: .7; vertical-align: -2px; margin-right: 3px; }
.ov-board-tools__actions { display: inline-flex; align-items: center; gap: 8px; position: relative; }

.ov-board-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    border: 1px solid var(--border-default);
    border-radius: var(--radius-full);
    background: var(--surface-card);
    color: var(--text-primary);
    font-family: inherit;
    font-size: 12px;
    font-weight: var(--fw-semibold);
    cursor: pointer;
    transition: border-color .15s ease, color .15s ease, background .15s ease;
}

.ov-board-btn svg { width: 14px; height: 14px; }
.ov-board-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.ov-board-btn:disabled { opacity: .5; cursor: default; }

.ov-board-btn--primary {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--text-on, #fff);
}
.ov-board-btn--primary:hover:not(:disabled) { color: var(--text-on, #fff); filter: brightness(1.05); }

/* Customize ⇄ Done label swap, driven by the button's own pressed state so it
   works from the page header, outside the board wrap. */
.ov-board-btn__edit, .ov-board-btn__done { display: inline-flex; align-items: center; gap: 6px; }
.ov-board-btn__done { display: none; }
[data-ov-edit][aria-pressed="true"] .ov-board-btn__edit { display: none; }
[data-ov-edit][aria-pressed="true"] .ov-board-btn__done { display: inline-flex; }

/* Elements that exist only while editing (declared after .ov-board-btn so the
   equal-specificity display:none wins in view mode). */
.ov-edit-only { display: none; }

/* ---- Add-card popover ---- */
.ov-addmenu {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    z-index: 20;
    min-width: 200px;
    padding: 6px;
    background: var(--surface-card);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
}
.ov-addmenu:not([hidden]) { display: flex; flex-direction: column; gap: 2px; }

.ov-addmenu__item {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 8px 10px;
    border: 0;
    border-radius: var(--radius-md, 8px);
    background: transparent;
    color: var(--text-primary);
    font: inherit;
    font-size: 13px;
    text-align: left;
    cursor: pointer;
}
.ov-addmenu__item:hover { background: var(--surface-sunken); }
.ov-addmenu__icon { display: inline-flex; align-items: center; color: var(--accent); }
.ov-addmenu__icon svg { width: 15px; height: 15px; }
.ov-addmenu__empty { margin: 0; padding: 8px 10px; font-size: 12px; color: var(--text-subtle); }

/* ---- Per-card edit controls (resize / remove) ---- */
.ov-card__ctls { display: none; align-items: center; gap: 4px; flex: 0 0 auto; }

.ov-card__ctl {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    padding: 0;
    border: 1px solid var(--border-default);
    border-radius: var(--radius-md, 8px);
    background: var(--surface-card);
    color: var(--text-subtle);
    cursor: pointer;
    transition: border-color .15s ease, color .15s ease, background .15s ease;
}
.ov-card__ctl svg { width: 15px; height: 15px; }
.ov-card__ctl:hover { border-color: var(--accent); color: var(--accent); }
.ov-card__ctl--danger:hover { border-color: var(--danger); color: var(--danger); }

/* The resize button shows one glyph depending on the card's current width. */
.ov-card__size-half { display: none; }
.ov-card--wide .ov-card__size-full { display: none; }
.ov-card--wide .ov-card__size-half { display: inline-flex; }

/* ---- Edit mode: reveal toolbar, swap icon→grip, reveal controls, grab ---- */
.ov-board-wrap.is-editing .ov-board-tools { display: flex; }
.ov-board-wrap.is-editing .ov-edit-only { display: inline-flex; }

.ov-board-wrap.is-editing .ov-card__icon { display: none; }
.ov-board-wrap.is-editing .ov-card__grip { display: inline-flex; align-items: center; }
.ov-board-wrap.is-editing .card-strip__note { display: none; }
.ov-board-wrap.is-editing .ov-card__ctls { display: inline-flex; }

.ov-board-wrap.is-editing .card-strip { cursor: grab; }
.ov-board-wrap.is-editing .card-strip:active { cursor: grabbing; }

.ov-board-wrap.is-editing .ov-card {
    outline: 1px dashed var(--border-strong);
    outline-offset: -1px;
}

/* SortableJS states: the drop-target placeholder, the lifted card, its clone. */
.ov-card--ghost { opacity: .4; }
.ov-card--ghost .card-strip { background: color-mix(in srgb, var(--accent) 12%, var(--surface-sunken)); }
.ov-card--chosen { box-shadow: var(--shadow-md); }
.ov-card--drag { opacity: .96; }

/* ---- Edit mode: the KPI stat tiles reorder too ----
   The whole tile becomes a drag handle, so mark it grabbable, outline it like
   the board cards, and drop the hover lift/navigation cue while editing. */
.ov-stats.is-editing .ov-stat {
    cursor: grab;
    outline: 1px dashed var(--border-strong);
    outline-offset: -1px;
}
.ov-stats.is-editing .ov-stat:active { cursor: grabbing; }
.ov-stats.is-editing .ov-stat:hover {
    transform: none;
    box-shadow: var(--shadow-sm);
    border-color: var(--border-default);
}
.ov-stats.is-editing .ov-stat__go { opacity: 0; }

/* Leading drag affordance: while editing, the entity icon chip swaps for a grip
   (injected by OverviewBoard.js), sitting in a same-sized box so the row doesn't
   jump — mirroring the board cards' icon→grip swap. */
.ov-stat__grip {
    display: none;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: var(--radius-md);
    background: var(--surface-sunken);
    color: var(--text-subtle);
    flex: 0 0 auto;
}
.ov-stat__grip svg { width: 18px; height: 18px; }
.ov-stats.is-editing .ov-stat__icon { display: none; }
.ov-stats.is-editing .ov-stat__grip { display: inline-flex; }

.ov-stat--ghost { opacity: .4; }
.ov-stat--chosen { box-shadow: var(--shadow-md); }
/* The fallback drag-clone follows the pointer via an inline transform set on
   every move. .ov-stat's `transition: transform` would ease each step over
   ~120ms, so the tile visibly trails the cursor — kill the transition on the
   clone for the same snappy feel as the (natively dragged) board cards. */
.ov-stat--drag { opacity: .96; transition: none; }

/* ---------- Catalogue mix: distribution bar + legend ---------- */
.ov-dist {
    display: flex;
    height: 12px;
    border-radius: var(--radius-full);
    overflow: hidden;
    background: var(--surface-sunken);
    gap: 2px;
}

.ov-dist__seg { display: block; height: 100%; min-width: 3px; }

.ov-dist__seg--1 { background: var(--dcs-navy-600); }
.ov-dist__seg--2 { background: var(--irix); }
.ov-dist__seg--3 { background: var(--info); }
.ov-dist__seg--4 { background: var(--warning); }
.ov-dist__seg--5 { background: var(--grey-400); }
.ov-dist__seg--6 { background: var(--dcs-navy-300); }

.ov-legend {
    list-style: none;
    margin: 16px 0 0;
    padding: 0;
    display: grid;
    gap: 9px;
}

.ov-legend__item {
    display: flex;
    align-items: center;
    gap: 9px;
    font-size: 13.5px;
}

.ov-legend__dot {
    width: 10px;
    height: 10px;
    border-radius: var(--radius-xs);
    flex: 0 0 auto;
}

.ov-legend__label { color: var(--text-body); font-weight: 600; }

.ov-legend__val {
    margin-left: auto;
    font-family: var(--font-mono);
    font-size: 12.5px;
    font-weight: 600;
    color: var(--text-primary);
}

.ov-legend__val .muted { color: var(--text-subtle); font-weight: 500; }

.ov-minis {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
    margin-top: 18px;
    padding-top: 16px;
    border-top: 1px solid var(--border-subtle);
}

.ov-mini { display: flex; flex-direction: column; gap: 4px; }

.ov-mini__label {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-subtle);
}

.ov-mini__val {
    font-family: var(--font-mono);
    font-size: 18px;
    font-weight: 700;
    color: var(--text-primary);
}

.ov-mini__unit { font-size: 12px; font-weight: 500; color: var(--text-muted); }

/* ---------- Stock watch ---------- */
.ov-watch {
    list-style: none;
    margin: 0;
    padding: 6px 8px;
}

.ov-watch__row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 12px;
    border-radius: var(--radius-md);
}

.ov-watch__row:hover { background: var(--surface-sunken); }

.ov-watch__thumb {
    width: 34px;
    height: 34px;
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-sm);
    background: var(--surface-sunken);
    border: 1px solid var(--border-subtle);
    overflow: hidden;
    color: var(--text-subtle);
}

.ov-watch__thumb img { width: 100%; height: 100%; object-fit: cover; }
.ov-watch__thumb svg { width: 16px; height: 16px; }

.ov-watch__name {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 14px;
    font-weight: 600;
    color: var(--text-body);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.ov-watch__num {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: baseline;
    gap: 8px;
    font-family: var(--font-mono);
    font-size: 16px;
    font-weight: 700;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}

.ov-watch__tag {
    font-family: var(--font-sans);
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    padding: 2px 6px;
    border-radius: var(--radius-sm);
}

.ov-watch__num--ok   { color: var(--text-primary); }
.ov-watch__num--ok   .ov-watch__tag { background: var(--surface-sunken); color: var(--text-subtle); }
.ov-watch__num--low  { color: #8a5f16; }
.ov-watch__num--low  .ov-watch__tag { background: var(--warning-soft); color: #8a5f16; }
.ov-watch__num--over { color: var(--danger); }
.ov-watch__num--over .ov-watch__tag { background: var(--danger-soft); color: #7a221d; }

/* ---------- "See all" link foot ---------- */
.ov-more {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin: 4px 20px 18px;
    font-size: 13px;
    font-weight: 700;
    color: var(--text-link);
    text-decoration: none;
}

.ov-more--pad { margin-top: 14px; }
.ov-more svg { width: 15px; height: 15px; transition: transform var(--dur-fast) var(--ease-out); }
.ov-more:hover { color: var(--accent-hover); }
.ov-more:hover svg { transform: translateX(3px); }

/* ---------- Upcoming events ---------- */
.ov-events {
    list-style: none;
    margin: 0;
    padding: 6px 8px;
}

.ov-events__row {
    /* Per-row status palette: --ev is the accent, --ev-ink its readable text
       tone. Defaults cover an unknown status; the [data-status] rules below
       and the --next modifier reset them. */
    --ev: var(--dcs-navy-400);
    --ev-ink: var(--text-muted);
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 9px 12px;
    border-radius: var(--radius-md);
    border-left: 3px solid var(--ev);
    background: color-mix(in srgb, var(--ev) 7%, var(--surface-card));
    transition: background var(--dur-fast) var(--ease-out);
}

.ov-events__row + .ov-events__row { margin-top: 5px; }

.ov-events__row:hover { background: color-mix(in srgb, var(--ev) 15%, var(--surface-card)); }

/* Discrete status colouring — mirrors the Events page status badge palette. */
.ov-events__row[data-status="Prospect"]  { --ev: var(--warning); --ev-ink: #8a5f16; }
.ov-events__row[data-status="Confirmed"] { --ev: var(--info);    --ev-ink: #1f5c9e; }
.ov-events__row[data-status="Completed"] { --ev: var(--success); --ev-ink: var(--irix-shade); }
.ov-events__row[data-status="Cancelled"] { --ev: var(--danger);  --ev-ink: #7a221d; }

/* The soonest upcoming event — the "next" — outranks its status colour with
   the brand navy and a heavier stripe, whatever status it actually holds. The
   palette override is qualified with the status attribute the row always
   carries so it outranks the [data-status] rules above. */
.ov-events__row.ov-events__row--next[data-status] {
    --ev: var(--dcs-navy-700);
    --ev-ink: var(--dcs-navy-700);
}
.ov-events__row--next {
    border-left-width: 4px;
    background: color-mix(in srgb, var(--dcs-navy-700) 9%, var(--surface-card));
}
.ov-events__row--next:hover { background: color-mix(in srgb, var(--dcs-navy-700) 15%, var(--surface-card)); }

.ov-events__date {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: var(--radius-md);
    background: color-mix(in srgb, var(--ev) 16%, var(--surface-card));
    border: 1px solid color-mix(in srgb, var(--ev) 32%, transparent);
    line-height: 1;
}

/* "Next" tag on the soonest event, in its navy accent. */
.ov-events__next {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border-radius: var(--radius-full);
    background: var(--dcs-navy-700);
    color: var(--text-on-dark);
    font-size: 10px;
    font-weight: 800;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.ov-events__day {
    font-family: var(--font-mono);
    font-size: 17px;
    font-weight: 700;
    color: var(--text-primary);
}

.ov-events__mon {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-top: 2px;
}

.ov-events__body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 5px; }

.ov-events__name {
    font-size: 14.5px;
    font-weight: 700;
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.ov-events__meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

.ov-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 2px 8px;
    border-radius: var(--radius-full);
    background: var(--surface-sunken);
    font-size: 11.5px;
    font-weight: 600;
    color: var(--text-muted);
}

.ov-chip svg { width: 12px; height: 12px; }

.ov-events__people {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 12px;
    font-weight: 600;
    color: var(--text-subtle);
}

.ov-events__people svg { width: 13px; height: 13px; }

.ov-events__total {
    flex: 0 0 auto;
    display: flex;
    align-items: baseline;
    gap: 3px;
    font-family: var(--font-mono);
    font-size: 15px;
    font-weight: 700;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}

.ov-events__cur { font-size: 10px; font-weight: 600; color: var(--text-subtle); }

/* Footer legend decoding the row/card colours — styled to match the Stock
   page legend (see .stock-legend): a full-bleed sunken bar with a subtle top
   divider and round colour dots. */
.ov-evleg {
    list-style: none;
    margin: 0;
    padding: 12px 20px;
    background: var(--surface-sunken);
    border-top: 1px solid var(--border-subtle);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 16px;
}

.ov-evleg__item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    color: var(--text-muted);
}

.ov-evleg__dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--dcs-navy-400);
    flex: none;
}

.ov-evleg__dot--next                    { background: var(--dcs-navy-700); }
.ov-evleg__dot[data-status="Prospect"]  { background: var(--warning); }
.ov-evleg__dot[data-status="Confirmed"] { background: var(--info); }
.ov-evleg__dot[data-status="Completed"] { background: var(--success); }
.ov-evleg__dot[data-status="Cancelled"] { background: var(--danger); }

/* ---------- Database tables ---------- */
.ov-tables {
    list-style: none;
    margin: 0;
    padding: 8px 20px 16px;
    display: grid;
    gap: 12px;
}

.ov-tables__row {
    display: grid;
    grid-template-columns: minmax(120px, 1fr) minmax(60px, 1.4fr) auto;
    align-items: center;
    gap: 14px;
}

.ov-tables__head { display: flex; align-items: baseline; gap: 8px; min-width: 0; }

.ov-tables__label {
    font-size: 13.5px;
    font-weight: 700;
    color: var(--text-body);
    white-space: nowrap;
}

.ov-tables__code {
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--text-subtle);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.ov-tables__bar {
    height: 8px;
    border-radius: var(--radius-full);
    background: var(--surface-sunken);
    overflow: hidden;
}

.ov-tables__fill {
    display: block;
    height: 100%;
    min-width: 2px;
    border-radius: var(--radius-full);
    background: linear-gradient(90deg, var(--dcs-navy-500), var(--dcs-navy-300));
}

.ov-tables__rows {
    justify-self: end;
    display: flex;
    align-items: baseline;
    gap: 5px;
    font-family: var(--font-mono);
    font-size: 15px;
    font-weight: 700;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}

.ov-tables__unit { font-size: 10px; font-weight: 600; color: var(--text-subtle); }

/* ---------- Pool card: latest-reading metric pills ---------- */
.ov-metrics {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 10px;
}

.ov-metric {
    display: flex;
    flex-direction: column;
    gap: 3px;
    padding: 11px 12px;
    border-radius: var(--radius-md);
    border: 1px solid var(--border-subtle);
    background: var(--surface-sunken);
}

.ov-metric__label {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-subtle);
}

.ov-metric__val {
    font-family: var(--font-mono);
    font-size: 20px;
    font-weight: 700;
    line-height: 1.05;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}

.ov-metric__unit { font-size: 11px; font-weight: 600; color: var(--text-subtle); margin-left: 3px; }

.ov-metric__state { font-size: 11px; font-weight: 700; letter-spacing: 0.02em; }

.ov-metric--good { background: var(--success-soft); }
.ov-metric--good .ov-metric__state { color: var(--success); }

.ov-metric--low,
.ov-metric--high { background: var(--warning-soft); }
.ov-metric--low .ov-metric__val,
.ov-metric--high .ov-metric__val,
.ov-metric--low .ov-metric__state,
.ov-metric--high .ov-metric__state { color: #8a5f16; }

/* ---------- Pool card: latest-reading balance line ---------- */
.ov-balance {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 14px 0 0;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-body);
}

.ov-balance__dot { width: 9px; height: 9px; border-radius: var(--radius-full); flex: 0 0 auto; }
.ov-balance__dot--good { background: var(--success); }
.ov-balance__dot--warn { background: var(--warning); }

.ov-balance__meta {
    margin-left: auto;
    font-family: var(--font-mono);
    font-size: 11.5px;
    font-weight: 500;
    color: var(--text-subtle);
}

/* ---------- Pool card: water-level bar ---------- */
.ov-level { margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--border-subtle); }

.ov-level__head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 8px; }

.ov-level__label {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-subtle);
}

.ov-level__val { font-family: var(--font-mono); font-size: 13px; font-weight: 700; color: var(--text-primary); }
.ov-level__val .muted { color: var(--text-subtle); font-weight: 500; }

/* ---------- Devices card: compact device list ---------- */
.ov-devices {
    list-style: none;
    margin: 0;
    padding: 6px 8px;
}

.ov-devices__row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 12px;
    border-radius: var(--radius-md);
}

.ov-devices__row:hover { background: var(--surface-sunken); }

.ov-devices__icon {
    width: 34px;
    height: 34px;
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-sm);
    background: var(--surface-sunken);
    border: 1px solid var(--border-subtle);
    color: var(--text-muted);
}

.ov-devices__icon svg { width: 16px; height: 16px; }

.ov-devices__body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }

.ov-devices__name {
    font-size: 14px;
    font-weight: 700;
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.ov-devices__meta {
    font-size: 12px;
    color: var(--text-subtle);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.ov-devices__state {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 9px;
    border-radius: var(--radius-full);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}

.ov-devices__dot { width: 7px; height: 7px; border-radius: var(--radius-full); flex: 0 0 auto; }

/* On/off (open/closed) glyph on the state pill — matches the main table's
   icon-led state language. Inherits the pill's colour via currentColor. */
.ov-devices__stateicon { display: inline-flex; flex: 0 0 auto; }
.ov-devices__stateicon svg { width: 13px; height: 13px; }

.ov-devices__state--on  { background: var(--success-soft); color: var(--irix-shade); }
.ov-devices__state--on .ov-devices__dot  { background: var(--success); }
.ov-devices__state--off { background: var(--surface-sunken); color: var(--text-subtle); }
.ov-devices__state--off .ov-devices__dot { background: var(--grey-400); }

/* =========================================================================
   Devices — main table (identity cell, connection, on/off state pill)
   The listing borrows .user-table; these classes give a device row its own
   look: a tinted type-icon tile, and a prominent, icon-led state control that
   is a switch for controllable devices and a read-out for monitor-only ones.
   ========================================================================= */

/* Roomier rows than the users table — the icon tile sets the rhythm. */
.installer .dev-table td { padding-top: 14px; padding-bottom: 14px; }

/* Identity cell: a rounded, tinted type-icon tile beside the name + type. */
.installer .dev-cell { display: flex; align-items: center; gap: 12px; min-width: 0; }

.installer .dev-cell__icon {
    flex: 0 0 auto;
    width: 44px;
    height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 12px;
    background: var(--accent-soft);
    border: 1px solid var(--border-subtle);
    color: var(--dcs-navy-600);
}

.installer .dev-cell__icon svg { width: 21px; height: 21px; }

/* Category tints for the type-icon tile — shared with the overview rail's
   compact list. Cool things (freezer, fan), water, and warm things (light,
   thermostat) each take a soft tone; everything else keeps the neutral navy. */
.installer .dev-cell__icon--cold,
.installer .ov-devices__icon--cold {
    background: var(--info-soft);
    border-color: color-mix(in srgb, var(--info) 22%, transparent);
    color: var(--info);
}
.installer .dev-cell__icon--water,
.installer .ov-devices__icon--water {
    background: var(--water-tint);
    border-color: color-mix(in srgb, var(--water) 22%, transparent);
    color: var(--water-shade);
}
.installer .dev-cell__icon--warm,
.installer .ov-devices__icon--warm {
    background: var(--warning-soft);
    border-color: color-mix(in srgb, var(--warning) 30%, transparent);
    color: #9a6a15;
}

.installer .dev-cell__body { min-width: 0; display: flex; flex-direction: column; gap: 1px; }

.installer .dev-cell__name { font-size: 15px; font-weight: 700; color: var(--text-primary); line-height: 1.3; }

.installer .dev-cell__type { font-size: 12px; font-weight: 500; color: var(--text-subtle); }

/* Connection: a quiet inline label, tinted for cloud (Smart Life) devices. */
.installer .dev-conn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-muted);
}

.installer .dev-conn svg { width: 15px; height: 15px; }
.installer .dev-conn--cloud { color: var(--info); }

/* ---------- State pill ---------- */
/* The on/off (open/closed) control. Both the on and off glyphs are rendered
   inside; the .is-on class chooses which shows and swaps the colour, so a live
   refresh only toggles a class and rewrites [data-state-text]. Off is a calm
   neutral; on is a fresh green. */
.installer .dev-state {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 40px;
    padding: 0 15px;
    border-radius: var(--radius-full);
    border: 1px solid var(--border-default);
    background: var(--surface-sunken);
    color: var(--text-muted);
    font-family: var(--font-sans);
    font-size: 14px;
    font-weight: 700;
    letter-spacing: 0.005em;
    white-space: nowrap;
    transition: background var(--dur-fast) var(--ease-out),
                border-color var(--dur-fast) var(--ease-out),
                color var(--dur-fast) var(--ease-out),
                transform var(--dur-fast) var(--ease-out);
}

.installer .dev-state__icon { display: inline-flex; flex: 0 0 auto; }
.installer .dev-state__icon svg { width: 18px; height: 18px; display: block; }

/* Show the off glyph by default, the on glyph once .is-on. */
.installer .dev-state__icon--on { display: none; }
.installer .dev-state.is-on .dev-state__icon--on { display: inline-flex; }
.installer .dev-state.is-on .dev-state__icon--off { display: none; }

/* Fixed-width, centred label so the pill (and the column) never reflows when
   the word swaps to "Loading…" mid-switch. */
.installer .dev-state__text {
    display: inline-block;
    min-width: 4.75em;
    text-align: center;
}

/* On — fresh green. */
.installer .dev-state.is-on {
    background: var(--success-soft);
    color: var(--irix-shade);
    border-color: color-mix(in srgb, var(--success) 32%, transparent);
}

/* Switchable variant — reads and behaves as a button. */
.installer .dev-state--btn { cursor: pointer; box-shadow: var(--shadow-xs); }
.installer .dev-state--btn:active { transform: translateY(0.5px); }
.installer .dev-state--btn:focus-visible { outline: none; box-shadow: var(--shadow-focus); }
.installer .dev-state--btn:not(.is-on):not([disabled]):hover {
    background: var(--grey-100);
    border-color: var(--border-strong);
    color: var(--text-body);
}
.installer .dev-state--btn.is-on:not([disabled]):hover {
    background: color-mix(in srgb, var(--success-soft) 76%, var(--success));
    border-color: color-mix(in srgb, var(--success) 48%, transparent);
}
/* Disabled toggle (an off-only device that is already off, or a row mid-refresh):
   not actionable, so mute it and drop the clickable hover affordance. */
.installer .dev-state--btn[disabled] { cursor: not-allowed; opacity: .55; }

/* Monitor-only variant — a status read-out, not a switch. */
.installer .dev-state--ro { cursor: default; }

/* =========================================================================
   Devices — grid (card) view
   A second way to look at the same device list, mirroring the products
   grid/list switch. The view toggle only flips the .dev-table--grid modifier
   on the <table>; grid mode relays the identical <tr>/<td> rows out as cards
   with CSS alone, so every toggle / refresh / schedule / edit handler keeps
   working against the same DOM. Selectors are scoped through `tbody` so the
   card rules outrank the base .user-table / .dev-table cell rules.
   ========================================================================= */

/* The listing toolbar (view switch + sort) reuses the products .product-listbar,
   as this page already reuses other product-* pieces (empty state, filter chips,
   toolbar). Grid mode itself is the relayout below. */

/* Table → block, header dropped, tbody becomes the card grid. */
.installer .dev-table.dev-table--grid { display: block; }
.installer .dev-table--grid thead { display: none; }
.installer .dev-table--grid tbody {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(248px, 1fr));
    gap: 16px;
    padding: 16px;
}

/* Each row → a card. */
.installer .dev-table--grid tbody tr {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 16px;
    background: var(--surface-card);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-lg);
    transition: box-shadow 0.15s ease, border-color 0.15s ease;
}
.installer .dev-table--grid tbody tr:hover {
    border-color: var(--border-strong);
    box-shadow: var(--shadow-md);
}

/* Cells → full-width blocks with the table padding/borders stripped. */
.installer .dev-table--grid tbody td {
    display: block;
    width: 100%;
    padding: 0;
    border: 0;
}

/* Card reading order: identity, connection, state, then the meta and actions. */
.installer .dev-table--grid tbody td:first-child     { order: 0; }
.installer .dev-table--grid tbody td.dev-table__conn  { order: 1; }
.installer .dev-table--grid tbody td.dev-table__state { order: 2; }
.installer .dev-table--grid tbody td.dev-table__loc   { order: 3; }
.installer .dev-table--grid tbody td.dev-table__last  { order: 4; }
.installer .dev-table--grid tbody td.user-table__act  { order: 5; }

/* State toggle spans the card for a clear, prominent control. */
.installer .dev-table--grid tbody td.dev-table__state .dev-toggle-form { display: block; width: 100%; }
.installer .dev-table--grid tbody td.dev-table__state .dev-state { display: flex; width: 100%; justify-content: center; }

/* Location + last change: a labelled meta line each. The column headers are
   gone in grid mode, so a ::before label restores the context. */
.installer .dev-table--grid tbody td.dev-table__loc,
.installer .dev-table--grid tbody td.dev-table__last {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    font-size: 13px;
    color: var(--text-body);
}
.installer .dev-table--grid tbody td.dev-table__loc::before  { content: "Location"; }
.installer .dev-table--grid tbody td.dev-table__last::before { content: "Last change"; }
.installer .dev-table--grid tbody td.dev-table__loc::before,
.installer .dev-table--grid tbody td.dev-table__last::before {
    flex: 0 0 auto;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-subtle);
}

/* Actions pinned to the foot of the card (margin-top:auto keeps action rows
   aligned across cards of differing height), right-aligned under a hairline. */
.installer .dev-table--grid tbody td.user-table__act {
    margin-top: auto;
    padding-top: 12px;
    border-top: 1px solid var(--border-subtle);
}
.installer .dev-table--grid tbody td.user-table__act .user-actions { width: 100%; justify-content: flex-end; }

/* ---------- Overview rail: System card (accounts + backups) ---------- */
.installer .rail-sys { list-style: none; margin: 0; padding: 6px; }

.installer .rail-sys__link {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 9px 10px;
    border-radius: var(--radius-md);
    text-decoration: none;
    color: inherit;
    transition: background var(--dur-fast) var(--ease-out);
}

.installer .rail-sys__link:hover { background: var(--surface-sunken); }

.installer .rail-sys__icon {
    width: 32px;
    height: 32px;
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-sm);
    background: var(--accent-soft);
    color: var(--dcs-navy-600);
}

.installer .rail-sys__icon svg { width: 16px; height: 16px; }

.installer .rail-sys__body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }

.installer .rail-sys__label { font-size: 13.5px; font-weight: 700; color: var(--text-body); }

.installer .rail-sys__sub { font-size: 11.5px; color: var(--text-subtle); }

.installer .rail-sys__val {
    font-family: var(--font-mono);
    font-size: 17px;
    font-weight: 700;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}

.installer .rail-sys__go { display: inline-flex; color: var(--text-subtle); }
.installer .rail-sys__go svg { width: 15px; height: 15px; }

/* ---------- Overview rail: water-attention nudge (cyan tone) ---------- */
.installer .rail-nudge--water {
    border-color: rgba(8, 145, 178, 0.3);
    background: var(--water-tint);
}
.installer .rail-nudge--water:hover { border-color: var(--water); }
.installer .rail-nudge--water .rail-nudge__icon { color: var(--water-shade); }
.installer .rail-nudge--water .rail-nudge__text { color: #0b5566; }

/* ---------- Responsive ---------- */
@media (max-width: 1180px) {
    .ov-stats { grid-template-columns: repeat(3, 1fr); }
}

@media (max-width: 820px) {
    .ov-stats { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 900px) {
    .ov-cols { grid-template-columns: 1fr; }
    /* Single column: every card is full width, so the wide-span rule is moot. */
    .ov-board { grid-template-columns: 1fr; }
    .ov-card--wide { grid-column: auto; }
}

@media (max-width: 560px) {
    .ov-stats { grid-template-columns: 1fr; }
    .ov-tables__row { grid-template-columns: 1fr auto; }
    .ov-tables__bar { display: none; }
    .ov-source__meta { display: none; }
}

/* =========================================================================
   Social Media — Google Maps card
   ========================================================================= */
.installer .map-preview {
    position: relative;
    margin-top: 4px;
    aspect-ratio: 16 / 9;
    min-height: 240px;
    border: 1px solid var(--border-default);
    border-radius: var(--radius-lg);
    overflow: hidden;
    background: var(--surface-sunken);
    box-shadow: var(--shadow-inset);
}

.installer .map-preview__frame {
    display: block;
    width: 100%;
    height: 100%;
    border: 0;
}

.installer .map-preview__frame[hidden] {
    display: none;
}

.installer .map-preview__empty {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 24px;
    text-align: center;
    color: var(--text-subtle);
}

.installer .map-preview__empty[hidden] {
    display: none;
}

.installer .map-preview__empty-icon {
    display: inline-flex;
    width: 44px;
    height: 44px;
    align-items: center;
    justify-content: center;
    margin-bottom: 2px;
    border-radius: var(--radius-full);
    background: var(--surface-card);
    border: 1px solid var(--border-subtle);
    color: var(--text-muted);
}

.installer .map-preview__empty-icon svg {
    width: 22px;
    height: 22px;
}

.installer .map-preview__empty-title {
    margin: 0;
    font-weight: 700;
    color: var(--text-body);
}

.installer .map-preview__empty-sub {
    margin: 0;
    max-width: 320px;
    font-size: var(--text-sm);
}

/* ---------- Channel cards — brand chip, status, resolved link ---------- */
/* Brand identity on the left of the card strip: a colour chip + the name. */
.installer .card-strip__brand {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
}

.installer .social-brand {
    display: inline-flex;
    flex: none;
    width: 30px;
    height: 30px;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-md);
    color: #fff;
    box-shadow: var(--shadow-xs);
}

.installer .social-brand svg {
    width: 17px;
    height: 17px;
    display: block;
}

.installer .social-brand--facebook  { background: #1877f2; }
.installer .social-brand--instagram { background: radial-gradient(circle at 30% 107%, #fdf497 0%, #fdf497 5%, #fd5949 45%, #d6249f 60%, #285aeb 90%); }
.installer .social-brand--tiktok    { background: #010101; }
.installer .social-brand--maps      { background: #ea4335; }

/* neutral "Not set" badge — optional channels shouldn't read as an error */
.ds-badge--muted {
    background: var(--grey-150);
    color: var(--text-muted);
}

/* .ds-btn / .ds-badge set display, which beats the UA [hidden] rule — restore
   it so JS toggling the hidden attribute (Open button, status badges) works. */
.installer .ds-btn[hidden],
.installer .ds-badge[hidden] { display: none; }

/* resolved profile link — a clickable chip that updates live as you type */
.installer .social-link {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    max-width: 100%;
    margin-top: 2px;
    padding: 7px 10px;
    border: 1px solid var(--border-default);
    border-radius: var(--radius-md);
    background: var(--surface-sunken);
    color: var(--text-primary);
    text-decoration: none;
    transition: border-color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out);
}

.installer .social-link[hidden] { display: none; }

.installer .social-link:hover {
    border-color: var(--border-focus);
    background: var(--grey-50);
}

.installer .social-link__icon,
.installer .social-link__go {
    display: inline-flex;
    flex: none;
    color: var(--text-subtle);
}

.installer .social-link__icon svg { width: 15px; height: 15px; display: block; }
.installer .social-link__go svg   { width: 14px; height: 14px; display: block; }

.installer .social-link:hover .social-link__go { color: var(--text-primary); }

.installer .social-link__url {
    min-width: 0;
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: var(--font-mono);
    font-size: 12.5px;
}

/* ---------- Facebook Page management (connect · compose · insights) ---------- */
/* Empty / call-to-action states: needs setup, or ready to connect. */
.installer .fb-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 8px;
    padding: 20px 16px 8px;
}

.installer .fb-empty__icon {
    display: inline-flex;
    width: 48px;
    height: 48px;
    align-items: center;
    justify-content: center;
    margin-bottom: 4px;
    border-radius: var(--radius-md);
    background: #1877f2;
    color: #fff;
    box-shadow: var(--shadow-xs);
}

.installer .fb-empty__icon svg { width: 24px; height: 24px; display: block; }

.installer .fb-empty__title {
    margin: 0;
    font-weight: 700;
    color: var(--text-primary);
}

.installer .fb-empty__sub {
    margin: 0 0 8px;
    max-width: 380px;
    font-size: var(--text-sm);
    color: var(--text-muted);
    line-height: var(--lh-normal, 1.5);
}

/* Page picker (several administered Pages). */
.installer .fb-pagepick {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 4px 0 12px;
}

.installer .fb-pagepick__row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 11px 13px;
    border: 1px solid var(--border-default);
    border-radius: var(--radius-md);
    background: var(--surface-sunken);
    cursor: pointer;
    transition: border-color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out);
}

.installer .fb-pagepick__row:hover { border-color: var(--border-focus); background: var(--grey-50); }
.installer .fb-pagepick__name { font-weight: 600; color: var(--text-primary); }

/* Connected identity row: brand chip · name/meta · disconnect. */
.installer .fb-connected {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
}

.installer .fb-connected__brand .social-brand { width: 40px; height: 40px; }
.installer .fb-connected__brand .social-brand svg { width: 22px; height: 22px; }
.installer .fb-connected__body { flex: 1 1 auto; min-width: 0; }

.installer .fb-connected__name {
    margin: 0;
    font-weight: 700;
    font-size: var(--text-md, 1rem);
    color: var(--text-primary);
}

.installer .fb-connected__meta {
    margin: 2px 0 0;
    font-size: var(--text-sm);
    color: var(--text-muted);
}

/* Insights hero: follower count. */
.installer .fb-followers {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 14px;
}

.installer .fb-followers__num {
    font-family: var(--font-mono);
    font-size: 30px;
    font-weight: 700;
    line-height: var(--lh-tight);
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}

.installer .fb-followers__label { font-size: 13px; font-weight: 600; color: var(--text-muted); }
.installer .fb-followers__likes { font-size: 12.5px; color: var(--text-subtle); }

.installer .fb-insights__note {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin-top: 14px;
    padding: 10px 12px;
    border-radius: var(--radius-md);
    background: var(--surface-sunken);
    font-size: var(--text-sm);
    color: var(--text-muted);
}

.installer .fb-insights__note[hidden] { display: none; }
.installer .fb-insights__note svg { flex: none; width: 16px; height: 16px; color: var(--warning, #d97706); }

/* "Remove image" text button under the composer's product-drop picker. */
.installer .fb-image-clear {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-top: 8px;
    padding: 4px 6px;
    border: 0;
    background: none;
    color: var(--text-muted);
    font-size: 12.5px;
    font-weight: 600;
    cursor: pointer;
}

.installer .fb-image-clear:hover { color: var(--danger); }
.installer .fb-image-clear svg { width: 14px; height: 14px; }

/* Row holding the "Remove image" + "Generate message with AI" controls under
   the composer's image picker. */
.installer .fb-image-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    margin-top: 8px;
}
.installer .fb-image-actions .fb-image-clear { margin-top: 0; }

/* The AI caption button reuses the .ds-btn look; keep its icon on-brand. */
.installer .fb-ai-generate svg { color: var(--irix, var(--primary)); }

/* Inline error surfaced when a caption cannot be generated. */
.installer .fb-ai-error { margin-top: 10px; margin-bottom: 0; }

/* =========================================================================
   Orders right rail — glance, removed-products nudge, top products, feed
   ========================================================================= */

/* ---------- Orders at a glance ---------- */
.installer .rail-glance {
    padding: 16px 20px 18px;
}

.installer .rail-glance__spend {
    display: flex;
    align-items: baseline;
    gap: 5px;
    font-family: var(--font-mono);
    font-size: 26px;
    font-weight: 700;
    line-height: var(--lh-tight);
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}

.installer .rail-glance__cur {
    font-size: 12px;
    font-weight: 600;
    color: var(--text-muted);
}

.installer .rail-glance__note {
    display: block;
    margin-top: 5px;
    font-size: 12.5px;
    color: var(--text-muted);
}

.installer .rail-glance__grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
    margin-top: 16px;
    padding-top: 14px;
    border-top: 1px solid var(--border-subtle);
}

.installer .rail-glance__stat {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
}

.installer .rail-glance__val {
    font-family: var(--font-mono);
    font-size: 17px;
    font-weight: 700;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}

.installer .rail-glance__label {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-subtle);
}

/* ---------- Settings: Integrations status list (right rail) ---------- */
.installer .rail-integrations {
    list-style: none;
    margin: 0;
    padding: 12px 14px 8px;
    display: grid;
    gap: 8px;
}
.installer .rail-integration {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 12px;
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    background: var(--surface-card);
    text-decoration: none;
    transition: border-color var(--dur-fast, .15s) var(--ease-out, ease);
}
.installer .rail-integration:hover {
    border-color: var(--irix);
}
.installer .rail-integration__icon {
    display: inline-flex;
    flex: 0 0 auto;
    color: var(--text-subtle);
}
.installer .rail-integration__icon svg {
    width: 16px;
    height: 16px;
}
.installer .rail-integration__name {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 13px;
    font-weight: var(--fw-semibold);
    color: var(--text-body);
}
.installer .rail-integration .ds-badge {
    flex: 0 0 auto;
}
.installer .rail-integrations__foot {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    margin: 4px 16px 16px;
    font-size: var(--text-xs);
    color: var(--text-muted);
    line-height: var(--lh-snug, 1.35);
}
.installer .rail-integrations__foot svg {
    width: 13px;
    height: 13px;
    flex: 0 0 auto;
    margin-top: 1px;
}

/* Social Media rail — public-presence rows carry a resolved-URL meta line and
   an idle (not-set) state layered on top of the shared .rail-integration. */
.installer .rail-integration__body {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 1px;
}
.installer .rail-integration__meta {
    font-family: var(--font-mono);
    font-size: 11.5px;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.installer .rail-integration--idle {
    cursor: default;
}
.installer .rail-integration--idle:hover {
    border-color: var(--border-subtle);
}
.installer .rail-integration--idle .rail-integration__name {
    color: var(--text-muted);
}
.installer .rail-nudge[hidden] { display: none; }

/* A jumped-to section (rail links / timeline dots) clears the sticky topbar. */
.installer [data-settings-section],
.installer [data-timeline-section] {
    scroll-margin-top: 88px;
}

/* =========================================================================
   Section timeline — a sticky, icon-only scroll-spy that lives in the gutter
   between the main column and the rail. It is built and inserted by
   SectionTimeline.js from the [data-timeline-section] cards (progressive
   enhancement), so the grid only gains its middle column when that markup is
   present. Shared by the Settings and Social Media pages; hidden once the rail
   drops below the content (≤1180px).
   ========================================================================= */

/* Give the grid a narrow middle track only while the timeline is mounted, and
   only where the three-column layout still holds (above the 1180px break). */
@media (min-width: 1181px) {
    .installer__main.has-section-timeline {
        grid-template-columns: minmax(0, 1fr) auto minmax(250px, 320px);
    }
}

.installer .section-timeline {
    position: sticky;
    top: 88px; /* clear the sticky 64px topbar + a 24px gap, matching .rail */
    align-self: start;
    justify-self: center;
    padding: 4px 0;
}
.installer .section-timeline[hidden] { display: none; }

.installer .section-timeline__track {
    list-style: none;
    margin: 0;
    padding: 0;
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 20px;
}

/* The spine: a full-height grey rail behind the dots (::before) plus an accent
   fill that rises to the active dot (::after, height driven from JS by
   --tl-fill). Both start/stop at the first/last dot's centre (half of 28px). */
.installer .section-timeline__track::before,
.installer .section-timeline__track::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 14px;
    width: 2px;
    transform: translateX(-50%);
    border-radius: var(--radius-full);
}
.installer .section-timeline__track::before {
    bottom: 14px;
    background: var(--border-subtle);
}
.installer .section-timeline__track::after {
    height: var(--tl-fill, 0px);
    background: var(--irix);
    transition: height var(--dur-fast, .12s) var(--ease-out, ease);
}

.installer .section-timeline__item { display: block; }
.installer .section-timeline__item.is-hidden { display: none; }

.installer .section-timeline__dot {
    position: relative;
    z-index: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: var(--radius-full);
    border: 1px solid var(--border-subtle);
    background: var(--surface-card);
    color: var(--text-subtle);
    text-decoration: none;
    cursor: pointer;
    transition: color var(--dur-fast, .12s) var(--ease-out, ease),
                border-color var(--dur-fast, .12s) var(--ease-out, ease),
                background var(--dur-fast, .12s) var(--ease-out, ease),
                box-shadow var(--dur-fast, .12s) var(--ease-out, ease),
                transform var(--dur-fast, .12s) var(--ease-out, ease);
}
.installer .section-timeline__dot svg {
    width: 15px;
    height: 15px;
}
.installer .section-timeline__dot:hover {
    border-color: var(--irix);
    color: var(--irix-shade);
    transform: scale(1.08);
}
.installer .section-timeline__dot:focus-visible {
    outline: none;
    box-shadow: var(--shadow-focus);
}
/* Sections already scrolled past — accent outline, echoing the spine fill. */
.installer .section-timeline__dot.is-done {
    border-color: var(--irix);
    color: var(--irix);
}
/* The section currently in view — filled, with a soft tint halo. */
.installer .section-timeline__dot.is-active {
    border-color: var(--irix);
    background: var(--irix);
    color: #fff;
    box-shadow: 0 0 0 4px var(--irix-tint);
}

@media (max-width: 1180px) {
    .installer .section-timeline { display: none; }
}

/* ---------- Removed-products nudge ---------- */
.installer .rail-nudge {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 12px 14px;
    border: 1px solid rgba(233, 162, 59, 0.35);
    background: var(--warning-soft);
    border-radius: var(--radius-lg);
    text-decoration: none;
    transition: border-color var(--dur-fast) var(--ease-out);
}

.installer .rail-nudge:hover {
    border-color: var(--warning);
}

.installer .rail-nudge__icon {
    flex: 0 0 auto;
    display: inline-flex;
    padding-top: 1px;
    color: var(--warning);
}

.installer .rail-nudge__icon svg {
    width: 18px;
    height: 18px;
}

.installer .rail-nudge__text {
    font-size: 13px;
    line-height: 1.4;
    color: #7a5a1a;
}

.installer .rail-nudge__text b {
    font-weight: 800;
}

/* ---------- Top products ---------- */
.installer .rail-top {
    list-style: none;
    margin: 0;
    padding: 12px 20px 16px;
    display: grid;
    gap: 13px;
}

.installer .rail-top__row {
    display: grid;
    grid-template-columns: 16px minmax(0, 1fr) auto;
    align-items: center;
    gap: 10px;
}

.installer .rail-top__rank {
    font-family: var(--font-mono);
    font-size: 12px;
    font-weight: 700;
    color: var(--text-subtle);
    text-align: center;
}

.installer .rail-top__body {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.installer .rail-top__name {
    font-size: 13.5px;
    font-weight: 600;
    color: var(--text-body);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.installer .rail-top__bar {
    height: 6px;
    border-radius: var(--radius-full);
    background: var(--surface-sunken);
    overflow: hidden;
}

.installer .rail-top__fill {
    display: block;
    height: 100%;
    min-width: 2px;
    border-radius: var(--radius-full);
    background: linear-gradient(90deg, var(--irix), var(--irix-tint));
}

.installer .rail-top__num {
    display: flex;
    align-items: baseline;
    gap: 3px;
    font-family: var(--font-mono);
    font-size: 14px;
    font-weight: 700;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}

.installer .rail-top__unit {
    font-size: 10px;
    font-weight: 600;
    color: var(--text-subtle);
}

/* ---------- Recent order activity ---------- */
.installer .rail-feed {
    list-style: none;
    margin: 0;
    padding: 6px 0;
}

.installer .rail-feed__row {
    padding: 11px 20px;
    border-bottom: 1px solid var(--border-subtle);
}

.installer .rail-feed__row:last-child {
    border-bottom: 0;
}

.installer .rail-feed__head {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 5px;
}

.installer .rail-feed__time {
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--text-subtle);
}

.installer .rail-feed__summary {
    margin: 0;
    font-size: 13px;
    font-weight: 600;
    line-height: 1.4;
    color: var(--text-primary);
}

/* Rankless breakdown (by container / by status) — drops the rank column. */
.installer .rail-top--plain .rail-top__row {
    grid-template-columns: minmax(0, 1fr) auto;
}

/* Glance values that flag a problem (negative on-hand, oversold count). */
.installer .rail-glance__spend.is-negative,
.installer .rail-glance__val.is-danger {
    color: var(--danger);
}

/* ---------- Upcoming events (calendar rail) ---------- */
.installer .rail-events {
    list-style: none;
    margin: 0;
    padding: 6px 8px;
}

.installer .rail-events__row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 12px;
    border-radius: var(--radius-md);
    text-decoration: none;
}

.installer .rail-events__row:hover {
    background: var(--surface-sunken);
}

.installer .rail-events__date {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: var(--radius-md);
    background: var(--accent-soft);
    border: 1px solid var(--dcs-navy-100);
    line-height: 1;
}

.installer .rail-events__day {
    font-family: var(--font-mono);
    font-size: 16px;
    font-weight: 700;
    color: var(--text-primary);
}

.installer .rail-events__mon {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-top: 2px;
}

.installer .rail-events__body {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.installer .rail-events__name {
    font-size: 13.5px;
    font-weight: 700;
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.installer .rail-events__cat {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    font-weight: 600;
    color: var(--text-muted);
}

.installer .rail-events__dot {
    width: 8px;
    height: 8px;
    border-radius: var(--radius-full);
    background: var(--grey-400);
    flex: none;
}

.installer .rail-events__people {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin-left: 4px;
    color: var(--text-subtle);
}

.installer .rail-events__people svg {
    width: 12px;
    height: 12px;
}

.installer .rail-events__row[data-category="Family"]  .rail-events__dot { background: var(--irix); }
.installer .rail-events__row[data-category="Friends"] .rail-events__dot { background: var(--info); }
.installer .rail-events__row[data-category="Others"]  .rail-events__dot { background: var(--grey-400); }

/* ---------- users ------------------------------------------------------- */
.installer .user-table-wrap {
    padding: 8px 8px 4px;
    overflow-x: auto;
}

.installer .user-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 14px;
}

.installer .user-table th {
    padding: 10px 14px;
    text-align: left;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-subtle);
    border-bottom: 1px solid var(--border-subtle);
    white-space: nowrap;
}

.installer .user-table td {
    padding: 12px 14px;
    border-bottom: 1px solid var(--border-subtle);
    vertical-align: middle;
}

.installer .user-table tbody tr:last-child td {
    border-bottom: 0;
}

.installer .user-table__added {
    color: var(--text-muted);
    white-space: nowrap;
}

.installer .user-table__act {
    text-align: right;
    white-space: nowrap;
    width: 1%; /* shrink to content */
}

.installer .user-cell {
    display: inline-flex;
    align-items: center;
    gap: 11px;
    min-width: 0;
}

.installer .user-cell__avatar {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    background: var(--accent-soft);
    color: var(--text-primary);
}

.installer .user-cell__avatar svg {
    width: 17px;
    height: 17px;
}

.installer .user-cell__avatar--img {
    background: none;
    overflow: hidden;
}

.installer .user-cell__avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.installer .user-cell__id {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
}

.installer .user-cell__email {
    font-weight: 600;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.installer .user-cell__you {
    flex: 0 0 auto;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--irix-shade);
    background: var(--irix-tint);
    border-radius: var(--radius-full);
    padding: 2px 7px;
}

.installer .user-actions {
    display: inline-flex;
    align-items: center;
    justify-content: flex-end;
    gap: 6px;
}

.installer .user-act-form {
    margin: 0;
    display: inline-flex;
}

.installer .user-act {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    padding: 0;
    border: 1px solid var(--border-default);
    border-radius: var(--radius-sm);
    background: var(--surface-card);
    color: var(--text-muted);
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}

.installer .user-act:hover {
    color: var(--text-primary);
    border-color: var(--border-strong);
}

.installer .user-act--danger:hover {
    color: var(--danger);
    border-color: var(--danger);
    background: var(--danger-soft);
}

.installer .user-act[disabled] {
    opacity: 0.45;
    cursor: not-allowed;
}

.installer .user-act[disabled]:hover {
    color: var(--text-muted);
    border-color: var(--border-default);
    background: var(--surface-card);
}

.installer .user-act svg {
    width: 15px;
    height: 15px;
}

/* ---------- Stacked count badge (e.g. schedule windows on the calendar button) ---------- */
/* A small pill in the top-right corner of a .user-act button, overlapping its
   edge. The ring in the button's own surface colour separates it from the icon.
   Hidden via [hidden] when the count is zero. */
.installer .user-act__badge {
    position: absolute;
    top: -5px;
    right: -5px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-full);
    background: var(--irix);
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    box-shadow: 0 0 0 2px var(--surface-card);
    pointer-events: none;
}
.installer .user-act__badge[hidden] {
    display: none;
}

/* ---------- two-factor -------------------------------------------------- */
.installer .user-table__tfa { white-space: nowrap; }

.installer .tfa-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px 4px 8px;
    border-radius: var(--radius-full);
    border: 1px solid var(--border-default);
    font-size: 12px;
    font-weight: 700;
    text-decoration: none;
    transition: color .15s ease, border-color .15s ease, background .15s ease;
}

.installer .tfa-badge svg { width: 14px; height: 14px; }

.installer .tfa-badge--on {
    color: var(--irix-shade);
    background: var(--irix-tint);
    border-color: transparent;
}

.installer .tfa-badge--on:hover { border-color: var(--irix-shade); }

.installer .tfa-badge--off { color: var(--text-muted); background: var(--surface-card); }

.installer .tfa-badge--off:hover { color: var(--text-primary); border-color: var(--border-strong); }

/* enabled status card */
.installer .tfa-status {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 20px;
}

.installer .tfa-status__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 48px;
    height: 48px;
    border-radius: 50%;
    background: var(--irix-tint);
    color: var(--irix-shade);
}

.installer .tfa-status__icon svg { width: 24px; height: 24px; }
.installer .tfa-status__body { flex: 1 1 auto; min-width: 0; }
.installer .tfa-status__title { margin: 0 0 2px; font-weight: 700; color: var(--text-primary); }
.installer .tfa-status__sub { margin: 0; font-size: 13px; color: var(--text-muted); }
.installer .tfa-status__form { margin: 0; flex: 0 0 auto; }

/* ---------- Settings · current-session card ---------- */
.installer .session {
    padding: 20px;
}

/* Identity header: avatar + email + when it signed in. */
.installer .session__head {
    display: flex;
    align-items: center;
    gap: 14px;
    padding-bottom: 18px;
    margin-bottom: 18px;
    border-bottom: 1px solid var(--border-subtle);
}

.installer .session__avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 46px;
    height: 46px;
    border-radius: 50%;
    background: var(--accent-soft);
    color: var(--accent);
    overflow: hidden;
}

.installer .session__avatar svg { width: 22px; height: 22px; }
.installer .session__avatar--img { background: none; }
.installer .session__avatar--img img { width: 100%; height: 100%; object-fit: cover; }

.installer .session__id { min-width: 0; }

.installer .session__email {
    margin: 0;
    font-size: 15px;
    font-weight: 700;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.installer .session__since {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    margin: 3px 0 0;
    font-size: 12.5px;
    color: var(--text-muted);
}

.installer .session__since svg { width: 13px; height: 13px; flex: none; }

/* Detail tiles: browser / OS / IP / location, each with a leading icon chip. */
.installer .session__grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
}

.installer .session__item {
    display: grid;
    grid-template-columns: 36px 1fr;
    grid-template-rows: auto auto;
    align-items: center;
    column-gap: 11px;
    padding: 11px 13px;
    background: var(--grey-50);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
}

.installer .session__icon {
    grid-row: 1 / 3;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: var(--radius-sm);
    background: var(--surface-card);
    border: 1px solid var(--border-subtle);
    color: var(--text-muted);
}

.installer .session__icon svg { width: 17px; height: 17px; }

.installer .session__label {
    align-self: end;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-subtle);
}

.installer .session__value {
    align-self: start;
    font-size: 13.5px;
    font-weight: 600;
    color: var(--text-primary);
    overflow-wrap: anywhere;
}

.installer .session__value--mono {
    font-family: var(--font-mono);
    font-weight: 500;
}

@media (max-width: 560px) {
    .installer .session__grid { grid-template-columns: 1fr; }
}

/* setup card */
.installer .tfa-setup {
    display: flex;
    gap: 28px;
    padding: 22px;
    flex-wrap: wrap;
}

.installer .tfa-setup__qr {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
}

.installer .tfa-qr {
    width: 192px;
    height: 192px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 8px;
    background: #fff;
    border: 1px solid var(--border-default);
    border-radius: var(--radius-md);
}

.installer .tfa-qr img,
.installer .tfa-qr canvas { display: block; }
.installer .tfa-qr__fallback svg { width: 40px; height: 40px; color: var(--text-subtle); }
.installer .tfa-qr__hint { margin: 0; font-size: 12px; color: var(--text-subtle); }

.installer .tfa-setup__body { flex: 1 1 320px; min-width: 260px; }

/* keep the same vertical rhythm between fields as .form-body */
.installer .tfa-setup__body > * + * { margin-top: 18px; }

.installer .tfa-steps {
    margin: 0 0 18px;
    padding-left: 20px;
    display: flex;
    flex-direction: column;
    gap: 12px;
    font-size: 14px;
    color: var(--text-body);
}

.installer .tfa-steps__t { font-weight: 700; color: var(--text-primary); }

.installer .tfa-key {
    display: inline-block;
    margin-top: 8px;
    padding: 8px 12px;
    font-family: var(--font-mono);
    font-size: 15px;
    letter-spacing: .12em;
    color: var(--text-primary);
    background: var(--surface-sunken);
    border-radius: var(--radius-md);
    user-select: all;
}

.installer .tfa-verify { max-width: 360px; }
.installer .tfa-verify .field { margin-bottom: 14px; }

/* segmented code input (OtpInput.js) — the 2FA setup + login-verify code entry.
   A hidden proxy carries the joined value; OtpInput mirrors is-valid/is-invalid
   from the proxy onto .otp so the boxes reflect validation state. */
.installer .otp {
    display: flex;
    gap: 8px;
}

.installer .otp__box {
    flex: 1 1 0;
    min-width: 0;
    max-width: 52px;
    height: 46px;
    padding: 0;
    text-align: center;
    font-family: var(--font-mono);
    font-size: 18px;
    line-height: 46px;
    color: var(--text-primary);
    background: var(--surface-card);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-inset);
    appearance: none;
    -webkit-appearance: none;
    transition: border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}

.installer .otp__box:focus {
    outline: none;
    border-color: var(--border-focus);
    box-shadow: var(--shadow-focus);
}

.installer .otp.is-invalid .otp__box { border-color: var(--danger); }
.installer .otp.is-invalid .otp__box:focus { box-shadow: 0 0 0 3px rgba(212, 69, 61, 0.28); }
.installer .otp.is-valid .otp__box { border-color: var(--success); }

/* =========================================================================
   Pool — water-quality log (table reuses .user-table; adds metric/status bits)
   ========================================================================= */

/* Activity-log icon tint for water entries (Logs page + rails). */
.installer .logs-icon--water {
    background: var(--water-tint);
    color: var(--water-shade);
}

/* ---------- readings table ---------- */
.installer .wq-table__date { white-space: nowrap; }

.installer .wq-table__metric,
.installer .wq-table__status { white-space: nowrap; }

.installer .wq-date {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-weight: 600;
    color: var(--text-primary);
}

.installer .wq-date__icon {
    display: inline-flex;
    color: var(--water);
}

.installer .wq-date__icon svg { width: 15px; height: 15px; }

/* Measured moment: date on top, time muted beneath it. */
.installer .wq-date__text {
    display: inline-flex;
    flex-direction: column;
    line-height: 1.25;
}

.installer .wq-date__time {
    font-weight: 500;
    font-size: 12px;
    color: var(--text-subtle);
    font-variant-numeric: tabular-nums;
}

/* A single measured value; only out-of-range values are tinted, so anomalies
   are the only thing that draws the eye. */
.installer .wq-metric {
    display: inline-flex;
    align-items: baseline;
    gap: 4px;
    color: var(--text-primary);
}

.installer .wq-metric__val {
    font-family: var(--font-mono);
    font-weight: 600;
    font-size: 14px;
}

.installer .wq-metric__unit {
    font-size: 11px;
    color: var(--text-subtle);
}

.installer .wq-metric__caret {
    display: inline-flex;
    align-self: center;
}

.installer .wq-metric__caret svg { width: 14px; height: 14px; }

.installer .wq-metric--good { color: var(--text-primary); }
.installer .wq-metric--low,
.installer .wq-metric--high { color: var(--warning); }
.installer .wq-metric--low .wq-metric__val,
.installer .wq-metric--high .wq-metric__val { color: var(--warning); }

/* ---------- overall status badge ---------- */
.installer .wq-badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 4px 10px 4px 8px;
    border-radius: var(--radius-full);
    font-size: 12px;
    font-weight: 700;
    white-space: nowrap;
}

.installer .wq-badge svg { width: 13px; height: 13px; }

.installer .wq-badge--good {
    color: var(--irix-shade);
    background: var(--irix-tint);
}

.installer .wq-badge--warn {
    color: #7a5a1a;
    background: var(--warning-soft);
}

/* ---------- treatments table ---------- */
.installer .pt-table__type { white-space: nowrap; }

/* A treatment type: a tinted icon chip + its label. The chip colour keys off the
   type (see the .pt-type--* modifiers) so each product reads at a glance. */
.installer .pt-type {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    font-weight: 600;
    color: var(--text-primary);
}

.installer .pt-type__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 26px;
    height: 26px;
    border-radius: var(--radius-full);
    /* Neutral default; per-type tints below. */
    background: var(--water-tint);
    color: var(--water-shade);
}

.installer .pt-type__icon svg { width: 15px; height: 15px; }

.installer .pt-type--phminus .pt-type__icon {
    background: var(--danger-soft);
    color: var(--danger);
}

.installer .pt-type--shockchlorine .pt-type__icon {
    background: var(--warning-soft);
    color: #7a5a1a;
}

.installer .pt-type--algicide .pt-type__icon {
    background: var(--irix-tint);
    color: var(--irix-shade);
}

.installer .pt-type--flocculant .pt-type__icon {
    background: var(--info-soft);
    color: var(--info);
}

/* ---------- live status pill inside the modal number inputs ---------- */
.installer .product-form [data-wq-metric] { padding-right: 62px; }

.installer .input-icon__status {
    position: absolute;
    top: 50%;
    right: 10px;
    transform: translateY(-50%);
    padding: 2px 8px;
    border-radius: var(--radius-full);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.02em;
    pointer-events: none;
    z-index: 2;
}

.installer .input-icon__status:empty { display: none; }

.installer .input-icon__status.is-good {
    color: var(--irix-shade);
    background: var(--irix-tint);
}

.installer .input-icon__status.is-low,
.installer .input-icon__status.is-high {
    color: #7a5a1a;
    background: var(--warning-soft);
}

/* ---------- reagent sliders (water quality) -----------------------------
   Each metric (pH, chlorine, alkalinity) is entered with a range slider whose
   track is that metric's pool test-kit reagent scale — set per metric as
   --wq-track on the .wq-slider--* modifiers below. The thumb and readout value
   are tinted (via --thumb-color, set by the wiring script in pool.html.twig) to
   a darkened sample of that scale at the current position, so they stay legible
   on the light readout. Modelled on .ds-range (the memory-limit slider) but with
   no "fill": the value is a point on a scale, so the whole spectrum stays
   visible. */
.installer .wq-slider {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.installer .wq-slider__readout {
    align-self: flex-start;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 6px 14px;
    background: var(--accent-soft);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-inset);
}

.installer .wq-slider__icon {
    display: flex;
    color: var(--text-subtle);
}

.installer .wq-slider__icon svg { width: 15px; height: 15px; display: block; }

.installer .wq-slider__value {
    font-family: var(--font-mono);
    font-size: 18px;
    font-weight: 700;
    line-height: 1;
    color: var(--thumb-color, var(--text-primary));
    transition: color var(--dur-fast) var(--ease-out);
}

.installer .wq-slider__unit {
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--text-subtle);
    margin-left: -3px;
}

.installer .wq-slider__status {
    margin-left: 2px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--text-subtle);
}

.installer .wq-slider__input {
    -webkit-appearance: none;
    appearance: none;
    width: 100%;
    height: 18px;
    margin: 0;
    padding: 0;
    background: transparent;
    cursor: pointer;
}

/* Track = the metric's reagent gradient (--wq-track, set per modifier below);
   a neutral fallback keeps it visible if a metric is missing its scale. */
.installer .wq-slider__input::-webkit-slider-runnable-track {
    height: 8px;
    border-radius: var(--radius-full);
    background-image: var(--wq-track, linear-gradient(to right, var(--border-strong), var(--border-strong)));
}

.installer .wq-slider__input::-moz-range-track {
    height: 8px;
    border-radius: var(--radius-full);
    background-image: var(--wq-track, linear-gradient(to right, var(--border-strong), var(--border-strong)));
}

.installer .wq-slider__input::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 18px;
    height: 18px;
    margin-top: -5px; /* centre the 18px thumb on the 8px track */
    border-radius: var(--radius-full);
    background: var(--surface-card);
    border: 2px solid var(--thumb-color, var(--text-primary));
    box-shadow: var(--shadow-sm);
    transition: transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}

.installer .wq-slider__input::-moz-range-thumb {
    width: 18px;
    height: 18px;
    border-radius: var(--radius-full);
    background: var(--surface-card);
    border: 2px solid var(--thumb-color, var(--text-primary));
    box-shadow: var(--shadow-sm);
    transition: border-color var(--dur-fast) var(--ease-out);
}

.installer .wq-slider__input:hover::-webkit-slider-thumb { transform: scale(1.08); }
.installer .wq-slider__input:focus { outline: none; }
.installer .wq-slider__input:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 4px rgba(16, 56, 88, 0.18); }
.installer .wq-slider__input:focus-visible::-moz-range-thumb { box-shadow: 0 0 0 4px rgba(16, 56, 88, 0.18); }

.installer .wq-slider__scale {
    display: flex;
    justify-content: space-between;
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--text-subtle);
}

/* Per-metric reagent scales (hex — reagent colours, not design tokens). Stop
   positions map each metric's value onto its slider's own min..max and must
   mirror the JS colour stops in pool.html.twig. */

/* Phenol red: bright yellow (acidic) → coral across the 7.2–7.6 target → magenta (alkaline). */
.installer .wq-slider--ph {
    --wq-track: linear-gradient(to right,
        #f1c40f 0%, #f39c12 14%, #e76f51 29%,
        #e76f51 57%, #e74c3c 72%, #d81b60 100%);
}

/* DPD free chlorine: near-colourless/buff → pink → light purple across 1–3 ppm → deep violet. */
.installer .wq-slider--chlorine {
    --wq-track: linear-gradient(to right,
        #fadbd8 0%, #f1948a 5%, #bb8fce 10%,
        #bb8fce 30%, #5b2c6f 50%, #5b2c6f 100%);
}

/* Total alkalinity: light yellow (low) → forest green across 80–120 ppm → navy (high). */
.installer .wq-slider--alkalinity {
    --wq-track: linear-gradient(to right,
        #f4d03f 0%, #f4d03f 17%, #27ae60 33%,
        #27ae60 50%, #1b4f72 75%, #1b4f72 100%);
}

/* ---------- water-level slider (measurements) ---------------------------
   Unlike the reagent sliders, the height (0–160 cm) is a fill, not a point on
   a spectrum: a cyan level that rises with the value up to --fill (set by the
   wiring script in pool.html.twig), the remainder greyed. --thumb-color tints
   the readout value and thumb the same water tone, as .ds-range does. */
.installer .wq-slider--height { --thumb-color: var(--water-shade); }

.installer .wq-slider--height .wq-slider__input::-webkit-slider-runnable-track {
    background-image: linear-gradient(to right, var(--water) var(--fill, 0%), var(--border-strong) var(--fill, 0%));
}

.installer .wq-slider--height .wq-slider__input::-moz-range-track {
    background-image: linear-gradient(to right, var(--water) var(--fill, 0%), var(--border-strong) var(--fill, 0%));
}

/* ---------- water-level listing + rail ----------------------------------
   The measurements table shows each height as a mini fill bar plus the value;
   the rail card shows the latest level larger, with a full-width bar. */
.installer .wm-table__level { white-space: nowrap; }

.installer .wm-level {
    display: inline-flex;
    align-items: center;
    gap: 10px;
}

.installer .wm-level__bar {
    position: relative;
    display: inline-block;
    width: 84px;
    height: 8px;
    border-radius: var(--radius-full);
    background: var(--border-subtle);
    overflow: hidden;
}

.installer .wm-level__bar--lg {
    display: block;
    width: 100%;
    height: 10px;
    margin: 8px 0;
}

.installer .wm-level__fill {
    position: absolute;
    inset: 0 auto 0 0;
    height: 100%;
    border-radius: var(--radius-full);
    background: linear-gradient(to right, var(--water-shade), var(--water));
}

.installer .wm-level__val {
    font-family: var(--font-mono);
    font-weight: 700;
    font-size: 14px;
    color: var(--text-primary);
}

.installer .wm-level__val small {
    font-family: var(--font-sans);
    font-weight: 600;
    font-size: 11px;
    color: var(--text-subtle);
    margin-left: 2px;
}

.installer .wm-note {
    display: block;
    max-width: 340px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 13px;
    color: var(--text-muted);
}

.installer .wm-note--empty { color: var(--text-subtle); }

.installer .wm-rail { padding: 10px 12px; }

.installer .wm-rail__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
}

.installer .wm-rail__val {
    font-family: var(--font-mono);
    font-weight: 700;
    font-size: 22px;
    line-height: 1;
    color: var(--water-shade);
}

.installer .wm-rail__val small {
    font-family: var(--font-sans);
    font-weight: 600;
    font-size: 12px;
    color: var(--text-subtle);
    margin-left: 3px;
}

.installer .wm-rail__pct {
    font-size: 12px;
    font-weight: 600;
    color: var(--text-muted);
}

.installer .wm-rail__when {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    color: var(--text-muted);
}

.installer .wm-rail__when svg { width: 14px; height: 14px; color: var(--water); }

.installer .wm-rail__note {
    margin: 8px 0 0;
    font-size: 13px;
    color: var(--text-muted);
    line-height: 1.5;
}

/* ---------- rail: latest reading ---------- */
.installer .wq-latest {
    list-style: none;
    margin: 0;
    padding: 6px 4px;
}

.installer .wq-latest__row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 8px 12px;
    border-bottom: 1px solid var(--border-subtle);
}

.installer .wq-latest__row:last-child { border-bottom: 0; }

.installer .wq-latest__name {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    color: var(--text-muted);
}

.installer .wq-latest__name svg { width: 15px; height: 15px; color: var(--water); }

.installer .wq-latest__val {
    font-family: var(--font-mono);
    font-weight: 700;
    font-size: 14px;
    color: var(--text-primary);
}

.installer .wq-latest__val small {
    font-family: var(--font-sans);
    font-weight: 600;
    font-size: 11px;
    color: var(--text-subtle);
}

/* A non-clickable variant of the amber rail nudge (static, not a link). */
.installer .rail-nudge--static { cursor: default; }
.installer .rail-nudge--static:hover { border-color: rgba(233, 162, 59, 0.35); }

/* ---------- AI (Gemini) --------------------------------------------------- */
/* Shared by the Settings form and the Analyse/Summarise cards on Pool & Logs. */

/* Inline sparkles glyph sitting before a card eyebrow. */
.installer .eyebrow svg { width: 13px; height: 13px; vertical-align: -2px; margin-right: 5px; }

/* Settings: AI credentials form */
/* Settings search — page-head filter box (mirrors the products toolbar search) */
.installer .settings-search {
    flex: 0 1 300px;
    min-width: 220px;
    max-width: 100%;
}
.installer .settings-search .form-control {
    width: 100%;
    padding-right: 34px;
}
.installer .settings-search__clear {
    position: absolute;
    right: 8px;
    top: 50%;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    padding: 0;
    border: 0;
    border-radius: var(--radius-full);
    background: var(--surface-sunken);
    color: var(--text-subtle);
    cursor: pointer;
    transition: color .15s ease;
}
.installer .settings-search__clear:hover { color: var(--text-primary); }
.installer .settings-search__clear svg { width: 13px; height: 13px; }

.installer .ai-settings { padding: 18px 20px 20px; }
.installer .ai-settings__lead { margin: 0 0 16px; font-size: var(--text-sm); color: var(--text-muted); line-height: var(--lh-normal); }
.installer .ai-settings__lead b { color: var(--text-body); font-weight: var(--fw-semibold); }
.installer .ai-settings__lead a { color: var(--text-link); font-weight: var(--fw-semibold); }
.installer .ai-settings__lead a svg { width: 11px; height: 11px; vertical-align: -1px; }
/* Inline icon in a bold sub-heading (e.g. Email card's Incoming/Outgoing labels). */
.installer .ai-settings__lead b svg { width: 14px; height: 14px; vertical-align: -2px; margin-right: 4px; }
/* A bold sub-heading that starts a field group: separate it from the group above,
   sit it close to its own fields below (e.g. Email card's Incoming/Outgoing blocks). */
.installer .ai-settings__lead--group { margin-top: 22px; margin-bottom: 10px; }
/* Settings → Email: the list of mailbox accounts (one bordered block each + an add form). */
.installer .mail-accts { display: flex; flex-direction: column; gap: 14px; }
.installer .mail-acct { border: 1px solid var(--ds-border, #e2e8f0); border-radius: 12px; padding: 14px 16px; }
.installer .mail-acct--new { border-style: dashed; background: var(--ds-surface-2, #f8fafc); }
.installer .mail-acct__head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 4px; }
.installer .mail-acct__title { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.installer .mail-acct__label { font-weight: var(--fw-semibold, 600); }
.installer .mail-acct__label svg { width: 15px; height: 15px; vertical-align: -2px; }
.installer .mail-acct__ops { display: flex; gap: 8px; align-items: center; }
.installer .mail-acct__op { margin: 0; }
.installer .mail-acct__op svg { width: 14px; height: 14px; }
.installer .mail-acct .ai-settings.mail-acct__form { padding: 0; }
.installer .ai-settings .mail-acct__row { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 12px; }
.installer .ai-settings .mail-acct__row .field + .field { margin-top: 0; }
.installer .mail-acct__grow { flex: 1 1 180px; min-width: 150px; }
.installer .mail-acct__reuse { display: flex; align-items: center; gap: 8px; font-size: var(--text-sm, 13px); margin: 8px 0; cursor: pointer; }
.installer .ai-settings .field + .field { margin-top: 14px; }
.installer .ai-settings__foot { margin-top: 18px; display: flex; justify-content: flex-end; }

.installer .ai-settings__saved {
    display: flex; align-items: center; gap: 8px;
    margin-bottom: 16px; padding: 9px 12px;
    background: var(--success-soft); color: var(--success-shade, var(--irix-shade));
    border: 1px solid color-mix(in srgb, var(--success) 30%, transparent);
    border-radius: var(--radius-md); font-size: var(--text-sm); font-weight: var(--fw-semibold);
}
.installer .ai-settings__saved svg { width: 15px; height: 15px; }

.installer .ai-settings__error {
    display: flex; align-items: center; gap: 8px;
    margin-bottom: 16px; padding: 9px 12px;
    background: var(--danger-soft); color: var(--danger-shade, var(--danger));
    border: 1px solid color-mix(in srgb, var(--danger) 30%, transparent);
    border-radius: var(--radius-md); font-size: var(--text-sm); font-weight: var(--fw-semibold);
}
.installer .ai-settings__error svg { width: 15px; height: 15px; flex: 0 0 auto; }

.installer .ai-hint {
    display: flex; align-items: flex-start; gap: 6px;
    margin: 7px 0 0; font-size: var(--text-xs); color: var(--text-muted); line-height: var(--lh-snug);
}
.installer .ai-hint svg { width: 13px; height: 13px; flex: 0 0 auto; margin-top: 1px; }
.installer .ai-hint a { color: var(--text-link); font-weight: var(--fw-semibold); white-space: nowrap; }
.installer .ai-hint a svg { width: 11px; height: 11px; vertical-align: -1px; }

/* Pool / Logs: the Analyse & Summarise cards */
.installer .ai-card__body { padding: 18px 20px 20px; }
.installer .ai-card__lead { margin: 0 0 14px; font-size: var(--text-sm); color: var(--text-muted); }
.installer .ai-card__hint { margin: 10px 0 0; font-size: var(--text-xs); color: var(--text-subtle); }

/* A tinted top border keeps the water card visually tied to the pool accent. */
.installer .ai-card--water { border-top: 2px solid var(--water); }

/* Result panel: hidden until the first run, then a soft, readable block. */
.installer .ai-result { margin-top: 16px; }
.installer .ai-result[hidden] { display: none; }
.installer .ai-result__thinking { font-size: var(--text-sm); color: var(--text-muted); font-style: italic; }

.installer .ai-result__body {
    padding: 14px 16px;
    background: var(--surface-sunken);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    font-size: var(--text-sm); color: var(--text-body); line-height: var(--lh-relaxed);
}
.installer .ai-result__body p { margin: 0 0 10px; }
.installer .ai-result__body p:last-child { margin-bottom: 0; }
.installer .ai-result__body strong { color: var(--text-primary); font-weight: var(--fw-semibold); }

.installer .ai-result__error {
    padding: 11px 14px;
    background: var(--danger-soft);
    border: 1px solid color-mix(in srgb, var(--danger) 30%, transparent);
    border-radius: var(--radius-md);
    font-size: var(--text-sm); color: var(--danger);
}

/* Backup-frequency slider (Settings): flip the track so GREEN marks the frequent
   (well-protected) end and RED the infrequent / Off end — the reverse of the
   default .ds-range used by the memory-limit control. Off's thumb is forced red
   by the wiring script. Scoped via .ds-range--flip so other sliders are unaffected. */
.installer .ds-range--flip .ds-range__input::-webkit-slider-runnable-track {
    background-image:
        linear-gradient(to right, transparent var(--fill), var(--border-strong) var(--fill)),
        linear-gradient(to right, var(--success), var(--warning), var(--danger));
}
.installer .ds-range--flip .ds-range__input::-moz-range-track {
    background-image:
        linear-gradient(to right, transparent var(--fill), var(--border-strong) var(--fill)),
        linear-gradient(to right, var(--success), var(--warning), var(--danger));
}

/* ---------- Pool: AI structured analysis + history ----------------------- */

/* Live result panel (structured verdict shown under the Analyse button). */
.installer .ai-analysis__head { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.installer .ai-analysis__meta { font-size: var(--text-xs); color: var(--text-subtle); }
.installer .ai-analysis__assessment { margin: 0 0 14px; font-size: var(--text-sm); color: var(--text-body); line-height: var(--lh-relaxed); }
.installer .ai-analysis__plan-title {
    font-size: var(--text-2xs); font-weight: var(--fw-bold); text-transform: uppercase;
    letter-spacing: var(--ls-caps); color: var(--text-muted); margin-bottom: 8px;
}

/* Verdict badge — balanced / attention / critical. */
.installer .wq-an-badge {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 2px 10px; border-radius: var(--radius-full);
    font-size: var(--text-xs); font-weight: var(--fw-bold);
    border: 1px solid transparent; white-space: nowrap;
}
.installer .wq-an-badge--balanced { background: var(--success-soft); color: var(--irix-shade); border-color: color-mix(in srgb, var(--success) 28%, transparent); }
.installer .wq-an-badge--attention { background: var(--warning-soft); color: #9a6212; border-color: color-mix(in srgb, var(--warning) 32%, transparent); }
.installer .wq-an-badge--critical { background: var(--danger-soft); color: var(--danger); border-color: color-mix(in srgb, var(--danger) 32%, transparent); }

/* Ordered plan of action. */
.installer .wq-plan { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; counter-reset: wq-step; }
.installer .wq-plan__step {
    position: relative; padding: 11px 14px 11px 40px;
    background: var(--surface-sunken); border: 1px solid var(--border-subtle);
    border-left: 3px solid var(--border-strong); border-radius: var(--radius-md);
}
.installer .wq-plan__step::before {
    counter-increment: wq-step; content: counter(wq-step);
    position: absolute; left: 12px; top: 11px;
    width: 20px; height: 20px; border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    background: var(--dcs-navy-700); color: var(--text-on-dark);
    font-size: var(--text-2xs); font-weight: var(--fw-bold);
}
.installer .wq-plan__step--high { border-left-color: var(--danger); }
.installer .wq-plan__step--medium { border-left-color: var(--warning); }
.installer .wq-plan__step--low { border-left-color: var(--success); }

.installer .wq-plan__head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.installer .wq-plan__action { font-size: var(--text-sm); font-weight: var(--fw-semibold); color: var(--text-primary); }
.installer .wq-plan__metric {
    font-size: var(--text-2xs); font-weight: var(--fw-semibold); text-transform: uppercase;
    letter-spacing: 0.04em; color: var(--text-muted);
    background: var(--bg-muted); padding: 1px 6px; border-radius: var(--radius-sm);
}
.installer .wq-plan__prio {
    margin-left: auto; font-size: var(--text-2xs); font-weight: var(--fw-bold);
    text-transform: uppercase; letter-spacing: 0.04em; padding: 1px 7px; border-radius: var(--radius-full);
}
.installer .wq-plan__prio--high { background: var(--danger-soft); color: var(--danger); }
.installer .wq-plan__prio--medium { background: var(--warning-soft); color: #9a6212; }
.installer .wq-plan__prio--low { background: var(--success-soft); color: var(--irix-shade); }
.installer .wq-plan__detail { margin: 5px 0 0; font-size: var(--text-sm); color: var(--text-body); line-height: var(--lh-normal); }

/* "Nothing to do" note. */
.installer .wq-an__none { display: flex; align-items: center; gap: 7px; margin: 4px 0 0; font-size: var(--text-sm); color: var(--irix-shade); }
.installer .wq-an__none svg { width: 16px; height: 16px; flex: 0 0 auto; }

/* History table. */
.installer .wq-an-table .wq-an__when-col { width: 40%; }
.installer .wq-an__when { padding: 0 !important; }
.installer .wq-an__toggle {
    display: flex; align-items: center; gap: 9px; width: 100%;
    padding: 12px 16px; background: none; border: 0; cursor: pointer; text-align: left; font: inherit; color: inherit;
}
.installer .wq-an__toggle:hover { background: var(--dcs-navy-50); }
.installer .wq-an__chev { display: inline-flex; color: var(--text-subtle); transition: transform var(--dur-fast) var(--ease-out); }
.installer .wq-an__chev svg { width: 16px; height: 16px; }
.installer .wq-an__row.is-open .wq-an__chev { transform: rotate(90deg); }
.installer .wq-an__when-text { display: flex; flex-direction: column; line-height: 1.25; }
.installer .wq-an__date { font-size: var(--text-sm); font-weight: var(--fw-semibold); color: var(--text-primary); }
.installer .wq-an__time { font-size: var(--text-2xs); color: var(--text-subtle); }

.installer .wq-an__detail > td { padding: 0 16px 16px 40px; background: var(--surface-card); }
.installer .wq-an__assessment { margin: 4px 0 12px; font-size: var(--text-sm); color: var(--text-body); line-height: var(--lh-relaxed); }

.installer .ai-history__empty { padding: 30px 20px; text-align: center; }

/* Small screens: let the plan header wrap without the priority pill jumping. */
@media (max-width: 560px) {
    .installer .wq-plan__prio { margin-left: 0; }
}

/* =========================================================================
   Backups — snapshot list, contents chips and restore actions
   (tables reuse .user-table; these add the when / type / contents / size bits)
   ========================================================================= */

/* Header "Back up now" sits inline with the title, like a bare button. */
.installer .page-head__right .bk-headform { display: contents; }

/* Result banners: snapshot taken, frequency saved, restored, errors. */
.installer .bk-note {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0 0 16px;
    padding: 10px 14px;
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    font-size: var(--text-sm);
    font-weight: var(--fw-semibold);
    line-height: var(--lh-normal);
}
.installer .bk-note svg { width: 16px; height: 16px; flex: 0 0 auto; }
.installer .bk-note b { font-weight: 800; }
.installer .bk-note--ok  { background: var(--success-soft); color: var(--irix-shade); border-color: color-mix(in srgb, var(--success) 30%, transparent); }
.installer .bk-note--err { background: var(--danger-soft);  color: var(--danger);      border-color: color-mix(in srgb, var(--danger) 30%, transparent); }

/* "Taken / Saved" cell — icon + stacked date, relative age and filename. */
.installer .bk-when { display: inline-flex; align-items: flex-start; gap: 9px; }
.installer .bk-when__icon { flex: 0 0 auto; margin-top: 2px; color: var(--text-subtle); display: inline-flex; }
.installer .bk-when__icon svg { width: 16px; height: 16px; }
.installer .bk-when__text { display: flex; flex-direction: column; line-height: 1.3; min-width: 0; }
.installer .bk-when__date { font-weight: var(--fw-semibold); color: var(--text-primary); white-space: nowrap; }
.installer .bk-when__ago  { font-size: var(--text-xs); color: var(--text-subtle); }
.installer .bk-when__file { margin-top: 2px; font-family: var(--font-mono); font-size: 11px; color: var(--text-subtle); word-break: break-all; }

/* Contents — one chip per catalogue table with its live row count. */
.installer .bk-contents { display: flex; flex-wrap: wrap; gap: 6px; max-width: 340px; }
.installer .bk-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 8px;
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-full, 999px);
    background: var(--surface-sunken);
    font-size: var(--text-xs);
    font-weight: var(--fw-semibold);
    color: var(--text-primary);
}
.installer .bk-chip__icon { display: inline-flex; color: var(--text-subtle); }
.installer .bk-chip__icon svg { width: 13px; height: 13px; }
.installer .bk-chip--zero { opacity: 0.5; }
.installer .bk-chip--na   { opacity: 0.4; }

.installer .bk-size { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--text-muted); white-space: nowrap; }
.installer .bk-restore { white-space: nowrap; }

/* Explanatory strip above the safety-copies table. */
.installer .bk-safety-note {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    padding: 12px 20px;
    border-bottom: 1px solid var(--border-subtle);
    font-size: var(--text-sm);
    color: var(--text-muted);
    line-height: var(--lh-normal);
}
.installer .bk-safety-note svg { width: 16px; height: 16px; flex: 0 0 auto; margin-top: 1px; color: var(--text-subtle); }

/* Offsite-mirror path in the rail. */
.installer .bk-mirror-path {
    display: block;
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    color: var(--text-muted);
    word-break: break-all;
    line-height: 1.4;
}

.installer .bk-table__type,
.installer .bk-table__size { white-space: nowrap; }

/* =========================================================================
   Tooltip — styled replacement for the native `title` bubble (Tooltip.js)
   Deliberately NOT scoped under `.installer`: the bubble is portaled to <body>
   so a transformed / overflow-clipped ancestor can't mis-anchor it, so it lives
   outside the app root and styles itself straight from the :root tokens.
   ========================================================================= */
.tt-tip {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 10000;
    box-sizing: border-box;
    max-width: 280px;
    width: max-content;
    padding: 6px 10px;
    border-radius: var(--radius-md);
    background: var(--bg-inverse-strong);
    color: var(--text-on-dark);
    font-family: var(--font-sans);
    font-size: var(--text-xs);
    font-weight: var(--fw-medium);
    line-height: var(--lh-snug);
    text-align: center;
    box-shadow: var(--shadow-lg);
    pointer-events: none;               /* never let the bubble eat the hover */
    opacity: 0;
    visibility: hidden;
    transform: translateY(4px);
    transition: opacity var(--dur-fast) var(--ease-out),
                transform var(--dur-fast) var(--ease-out),
                visibility 0s linear var(--dur-fast);
}

.tt-tip.tt-tip--below { transform: translateY(-4px); }

.tt-tip.is-visible {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
    transition: opacity var(--dur-fast) var(--ease-out),
                transform var(--dur-fast) var(--ease-out);
}

/* Caret: a rotated square that inherits the bubble background. JS sets
   --tt-caret (px from the left edge) so it tracks the target's centre even when
   the bubble is clamped against a viewport edge. */
.tt-tip::after {
    content: "";
    position: absolute;
    left: var(--tt-caret, 50%);
    bottom: -3px;                       /* default: bubble above, caret points down */
    width: 8px;
    height: 8px;
    background: inherit;
    transform: translateX(-50%) rotate(45deg);
}
.tt-tip.tt-tip--below::after { bottom: auto; top: -3px; }

@media (prefers-reduced-motion: reduce) {
    .tt-tip,
    .tt-tip.is-visible { transform: none; transition: opacity var(--dur-fast) linear; }
}

/* ---------- Settings · Runtime: uptime hero + restart control ------------- */
/* The "server running time" readout at the top of the Runtime card. */
.installer .runtime-uptime {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 18px 20px;
    border-bottom: 1px solid var(--border-subtle);
}

.installer .runtime-uptime__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    flex: 0 0 auto;
    border-radius: var(--radius-md);
    background: var(--success-soft);
    color: var(--irix-shade);
    border: 1px solid color-mix(in srgb, var(--success) 26%, transparent);
}

.installer .runtime-uptime__icon svg { width: 22px; height: 22px; }

.installer .runtime-uptime__body {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.installer .runtime-uptime__label {
    font-size: 11px;
    font-weight: var(--fw-semibold);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-subtle);
}

.installer .runtime-uptime__value {
    font-family: var(--font-mono);
    font-size: 22px;
    font-weight: var(--fw-semibold);
    line-height: 1.15;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}

.installer .runtime-uptime__value--muted {
    font-size: 16px;
    color: var(--text-muted);
}

.installer .runtime-uptime__since {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    margin-top: 2px;
    font-size: var(--text-xs);
    color: var(--text-muted);
}

.installer .runtime-uptime__since svg { width: 12px; height: 12px; flex: 0 0 auto; }

/* Outcome flash for a restart request. */
.installer .runtime-restart-note {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin: 16px 20px 0;
    padding: 10px 12px;
    border-radius: var(--radius-md);
    font-size: var(--text-sm);
    font-weight: var(--fw-semibold);
    line-height: var(--lh-snug);
}

.installer .runtime-restart-note svg { width: 15px; height: 15px; flex: 0 0 auto; margin-top: 1px; }

.installer .runtime-restart-note code {
    font-family: var(--font-mono);
    font-weight: 500;
}

.installer .runtime-restart-note--ok {
    background: var(--success-soft);
    color: var(--irix-shade);
    border: 1px solid color-mix(in srgb, var(--success) 30%, transparent);
}

.installer .runtime-restart-note--err {
    background: var(--danger-soft);
    color: color-mix(in srgb, var(--danger) 80%, #000);
    border: 1px solid color-mix(in srgb, var(--danger) 32%, transparent);
}

/* The restart footer: an explanatory hint on the left, the danger button on the right. */
.installer .runtime-restart {
    flex-wrap: wrap;
    gap: 12px 16px;
}

.installer .runtime-restart__hint {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    margin: 0;
    max-width: 48ch;
    font-size: var(--text-xs);
    color: var(--text-muted);
    line-height: var(--lh-snug);
}

.installer .runtime-restart__hint svg { width: 13px; height: 13px; flex: 0 0 auto; margin-top: 1px; }

.installer .runtime-restart__hint code {
    font-family: var(--font-mono);
    color: var(--text-body);
}

.installer .runtime-restart__form { margin: 0; }

@media (max-width: 560px) {
    .installer .runtime-restart__form { width: 100%; }
    .installer .runtime-restart__form .ds-btn { width: 100%; justify-content: center; }
}

/* =====================================================================
   Expenses — table reuses .user-table; these add the amount / description /
   category-tag bits and keep the "Resync" form inline in the page head.
   ===================================================================== */
.installer .expense-sync-form { margin: 0; }

/* Amount column: right-aligned, monospaced figures, never wraps. */
.installer .expense-table__amount {
    text-align: right;
    white-space: nowrap;
    font-family: var(--font-mono);
    font-weight: 600;
}
.installer .expense-table th.expense-table__amount { text-align: right; }

/* Date stays on one line; description truncates so a long note can't blow out
   the row (the full text is available via its title tooltip). */
.installer .expense-table__date { white-space: nowrap; color: var(--text-muted); }
.installer .expense-table__desc {
    max-width: 340px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--text-muted);
}

.installer .expense-tag {
    display: inline-block;
    padding: 2px 9px;
    border-radius: var(--radius-full);
    background: var(--accent-soft);
    color: var(--text-primary);
    font-size: 12px;
    font-weight: 600;
    white-space: nowrap;
}

.installer .expense-muted { color: var(--text-subtle); }

/* Footer total row: a summed line under the listing that tracks the active
   filters (Alpine keeps `moneyExact` in step). Sits on a sunken strip with a
   firm top rule so it reads as a summary, not another record. */
.installer .expense-row--total td {
    border-top: 2px solid var(--border-default);
    background: var(--surface-sunken);
}
.installer .expense-table__total-label {
    text-align: right;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-size: 11px;
    font-weight: 700;
    color: var(--text-muted);
}
.installer .expense-table__total-amount {
    font-weight: 800;
    color: var(--text-primary);
}

/* "Synced …" note: keep the cloud glyph inline-sized with the text. */
.installer .expense-synced { display: inline-flex; align-items: center; gap: 5px; }
.installer .expense-synced svg { width: 13px; height: 13px; flex: 0 0 auto; }

/* Column-mapping modal: one "field → column" row per expense field. 20px pad to
   match the modal head (14px 20px) and the sibling .product-form, so the body
   lines up with the header instead of sitting flush against the panel edges. */
.installer .expense-map { padding: 20px; }
.installer .expense-map__lead { margin: 0 0 14px; color: var(--text-muted); font-size: 13.5px; }
.installer .expense-map__status {
    display: flex; align-items: center; gap: 8px;
    color: var(--text-muted); font-size: 14px; padding: 8px 0;
}
.installer .expense-map__status svg { width: 16px; height: 16px; }
.installer .expense-map__row {
    display: grid;
    grid-template-columns: 130px 1fr;
    align-items: center;
    gap: 12px;
    margin-bottom: 10px;
}
.installer .expense-map__label { font-size: 14px; font-weight: 600; color: var(--text-primary); }
.installer .expense-map__foot {
    display: flex; justify-content: flex-end; gap: 10px;
    margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--border-subtle);
}
.installer .expense-banner__action { margin-top: 10px; }

/* Expenses date filter: a mode select ("Exact day" / "Month") that swaps between
   an exact-day dropdown and a month+year pair (month = all 12, year = years with
   records; either alone or together). */
.installer .expense-date-filter__mode  { min-width: 108px !important; }
.installer .expense-date-filter__value { min-width: 150px !important; }
.installer .expense-date-filter__month { min-width: 128px !important; }
.installer .expense-date-filter__year  { min-width: 92px  !important; }

@media (max-width: 560px) {
    .installer .expense-map__row { grid-template-columns: 1fr; gap: 5px; }
}

/* =====================================================================
   Expenses — "per month" bar chart (server-rendered, pure CSS bars).
   `monthly` from ExpensesHandler::monthlySeries(); each bar's height is set
   inline as a % of the tallest month. Matches the rail's green bar style.
   ===================================================================== */
.installer .expense-chart .card-strip { align-items: flex-start; gap: 16px; }

.installer .expense-chart__eyebrow-icon {
    display: inline-flex;
    vertical-align: -2px;
    margin-right: 6px;
    color: var(--irix);
}
.installer .expense-chart__eyebrow-icon svg { width: 14px; height: 14px; }

/* Average / peak read-outs on the right of the card strip. */
.installer .expense-chart__stats { display: flex; gap: 26px; flex: 0 0 auto; }
.installer .expense-chart__stat {
    display: flex;
    flex-direction: column;
    gap: 3px;
    text-align: right;
}
.installer .expense-chart__stat-label {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--text-subtle);
    white-space: nowrap;
}
.installer .expense-chart__stat-val {
    font-family: var(--font-mono);
    font-size: 16px;
    font-weight: 700;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}
.installer .expense-chart__stat-unit {
    margin-left: 3px;
    font-size: 10px;
    font-weight: 600;
    color: var(--text-subtle);
}

/* Plot area: a flex row of equal-width columns, bars anchored to the baseline. */
.installer .expense-chart__plot {
    display: flex;
    align-items: flex-end;
    gap: 10px;
    height: 190px;
    padding: 24px 20px 12px;
}
.installer .expense-chart__col {
    flex: 1 1 0;
    min-width: 0;
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-end;
    gap: 6px;
}
.installer .expense-chart__amount {
    font-family: var(--font-mono);
    font-size: 11px;
    font-weight: 700;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    line-height: 1;
}
.installer .expense-chart__track {
    flex: 1 1 auto;
    width: 100%;
    max-width: 48px;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    border-bottom: 1px solid var(--border-subtle);
}
.installer .expense-chart__bar {
    display: block;
    width: 100%;
    min-height: 2px;
    border-radius: var(--radius-sm) var(--radius-sm) 0 0;
    background: linear-gradient(180deg, var(--irix), var(--irix-shade));
    transition: filter var(--dur-fast, .15s) var(--ease-out, ease);
}
.installer .expense-chart__col:hover .expense-chart__bar { filter: brightness(1.08); }

/* The tallest month is highlighted in navy so it reads as the peak at a glance. */
.installer .expense-chart__col.is-peak .expense-chart__bar {
    background: linear-gradient(180deg, var(--dcs-navy-500), var(--dcs-navy-700));
}

.installer .expense-chart__xlabel {
    display: flex;
    flex-direction: column;
    align-items: center;
    line-height: 1.2;
}
.installer .expense-chart__month {
    font-size: 11.5px;
    font-weight: 600;
    color: var(--text-body);
}
.installer .expense-chart__year {
    min-height: 12px;
    font-family: var(--font-mono);
    font-size: 10px;
    font-weight: 600;
    color: var(--text-subtle);
}

@media (max-width: 720px) {
    .installer .expense-chart .card-strip { flex-direction: column; }
    .installer .expense-chart__stats { gap: 22px; }
    .installer .expense-chart__amount { display: none; }
    .installer .expense-chart__plot { gap: 6px; height: 150px; padding: 16px 14px 10px; }
}

/* =====================================================================
   Expenses per month by buyer — stacked bar chart (_chart_buyers.html.twig)
   Reuses the .expense-chart column / track / label scaffolding; only the
   stacked segments, the buyer colour palette and the legend are new.
   `buyerMonthly` from ExpensesHandler::monthlyByBuyerSeries(); each segment's
   flex-basis is set inline as a % of the tallest month total, so a column's
   segments stack to that month's share of the peak.
   ===================================================================== */

/* Buyer series palette — colour per rank (c1 = biggest), c7 = "Other".
   Drawn from the design tokens so it reads as one family with the app. */
.installer .expense-buyers {
    --exp-c1: var(--dcs-navy-500);
    --exp-c2: var(--irix);
    --exp-c3: var(--warning);
    --exp-c4: var(--water);
    --exp-c5: #7c5cbf;          /* violet — no token, kept local to this chart */
    --exp-c6: var(--danger);
    --exp-c7: var(--grey-400);  /* "Other" — muted so named buyers lead */
}

/* Legend: wraps under/next to the title, one swatch + name per series. */
.installer .expense-buyers__legend {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 16px;
    margin: 0;
    padding: 0;
    list-style: none;
    flex: 0 1 auto;
}
.installer .expense-buyers__legend-item {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    min-width: 0;
}
.installer .expense-buyers__swatch {
    flex: 0 0 auto;
    width: 11px;
    height: 11px;
    border-radius: var(--radius-xs);
}
.installer .expense-buyers__legend-name {
    font-size: 12px;
    font-weight: 600;
    color: var(--text-body);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 160px;
}

/* A legend entry backed by a real buyer is a filter button; "Other" stays inert.
   Active = the list is currently filtered to that buyer (from here or the select). */
.installer .expense-buyers__legend-item.is-clickable {
    cursor: pointer;
    padding: 2px 8px;
    margin: -2px 0;
    border-radius: var(--radius-full);
    transition: background var(--dur-fast, .15s) var(--ease-out, ease);
}
.installer .expense-buyers__legend-item.is-clickable:hover { background: var(--surface-sunken); }
.installer .expense-buyers__legend-item.is-clickable:focus-visible {
    outline: 2px solid var(--border-focus);
    outline-offset: 1px;
}
.installer .expense-buyers__legend-item.is-active { background: var(--accent-soft); }
.installer .expense-buyers__legend-item.is-active .expense-buyers__legend-name { color: var(--text-primary); }

/* Taller plot than the plain per-month chart — the stacked segments need the
   extra height to stay legible. */
.installer .expense-buyers__plot { height: 340px; padding: 28px 20px 12px; }

/* Stack: fills the track and packs segments from the baseline up (biggest
   buyer at the bottom — column-reverse renders the first DOM child last). */
.installer .expense-buyers__stack {
    width: 100%;
    max-width: 56px;
    height: 100%;
    display: flex;
    flex-direction: column-reverse;
    align-items: stretch;
    justify-content: flex-start;
    border-radius: var(--radius-sm) var(--radius-sm) 0 0;
    overflow: hidden;
}
.installer .expense-buyers__seg {
    flex-grow: 0;
    flex-shrink: 0;
    width: 100%;
    min-height: 2px;
    transition: filter var(--dur-fast, .15s) var(--ease-out, ease);
}
/* Hairline between stacked segments so adjacent colours read apart. */
.installer .expense-buyers__seg + .expense-buyers__seg {
    box-shadow: 0 1px 0 0 rgba(255, 255, 255, 0.55) inset;
}
.installer .expense-chart__col:hover .expense-buyers__seg { filter: brightness(1.06); }

/* Palette application — shared by the legend swatches and the stack segments. */
.installer .expense-buyers__seg--c1 { background: var(--exp-c1); }
.installer .expense-buyers__seg--c2 { background: var(--exp-c2); }
.installer .expense-buyers__seg--c3 { background: var(--exp-c3); }
.installer .expense-buyers__seg--c4 { background: var(--exp-c4); }
.installer .expense-buyers__seg--c5 { background: var(--exp-c5); }
.installer .expense-buyers__seg--c6 { background: var(--exp-c6); }
.installer .expense-buyers__seg--c7 { background: var(--exp-c7); }

@media (max-width: 720px) {
    .installer .expense-buyers__legend { gap: 5px 12px; }
    .installer .expense-buyers__legend-name { max-width: 110px; font-size: 11.5px; }
    .installer .expense-buyers__plot { height: 260px; padding: 20px 14px 10px; }
}

/* =====================================================================
   Expenses — break-even split (diverging bar chart, _chart_breakeven.html.twig)
   Reuses the .expense-chart card strip / stat read-outs; the plot is its own
   thing: one row per person, a bar that grows right (in credit, green) or left
   (owes, red) from a centre zero line. `breakEven` from
   ExpensesHandler::breakEvenSeries(); each bar's width is set inline as a share
   of the largest deviation from the even share (so it fills half the track).
   ===================================================================== */
.installer .expense-split__plot {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 24px 20px 8px;
}
.installer .expense-split__row {
    display: grid;
    grid-template-columns: 128px 1fr 116px;
    align-items: center;
    gap: 16px;
}

/* Name + the raw spend beneath it, on the left. */
.installer .expense-split__label {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}
.installer .expense-split__name {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-body);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.installer .expense-split__spent {
    font-family: var(--font-mono);
    font-size: 10.5px;
    font-weight: 600;
    color: var(--text-subtle);
    font-variant-numeric: tabular-nums;
}

/* Track: full width, a hairline zero line down the middle; bars anchor to it. */
.installer .expense-split__track {
    position: relative;
    height: 24px;
    min-width: 0;
}
.installer .expense-split__axis {
    position: absolute;
    left: 50%;
    top: -5px;
    bottom: -5px;
    width: 1px;
    background: var(--border-strong);
    transform: translateX(-0.5px);
}
.installer .expense-split__bar {
    position: absolute;
    top: 3px;
    bottom: 3px;
    min-width: 2px;
    transition: filter var(--dur-fast, .15s) var(--ease-out, ease);
}
/* In credit → grows right from centre; owes → grows left from centre. */
.installer .expense-split__bar--pos {
    left: 50%;
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
    background: linear-gradient(90deg, var(--success), color-mix(in srgb, var(--success) 78%, black));
}
.installer .expense-split__bar--neg {
    right: 50%;
    border-radius: var(--radius-sm) 0 0 var(--radius-sm);
    background: linear-gradient(90deg, color-mix(in srgb, var(--danger) 78%, black), var(--danger));
}
.installer .expense-split__row:hover .expense-split__bar { filter: brightness(1.06); }

/* Signed balance on the right, coloured to match its bar. */
.installer .expense-split__value {
    text-align: right;
    font-family: var(--font-mono);
    font-size: 14px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.installer .expense-split__value--pos { color: var(--irix-shade); }
.installer .expense-split__value--neg { color: var(--danger); }
.installer .expense-split__unit {
    margin-left: 3px;
    font-size: 10px;
    font-weight: 600;
    color: var(--text-subtle);
}

/* Footnote / legend under the plot. */
.installer .expense-split__note {
    margin: 6px 20px 4px;
    font-size: 11.5px;
    line-height: 1.5;
    color: var(--text-subtle);
}
.installer .expense-split__key {
    font-weight: 700;
}
.installer .expense-split__key--pos { color: var(--irix-shade); }
.installer .expense-split__key--neg { color: var(--danger); }

@media (max-width: 720px) {
    .installer .expense-split__plot { padding: 18px 14px 6px; gap: 12px; }
    .installer .expense-split__row { grid-template-columns: 92px 1fr 92px; gap: 10px; }
    .installer .expense-split__value { font-size: 12.5px; }
    .installer .expense-split__note { margin: 6px 14px 4px; }
}
