/* Sources / tags / proxies admin page — full-width tabular layout */

/* Native <option> rendering ignores most CSS and falls back to OS colors,
   which on dark theme produces white-on-white. Setting background/color
   explicitly forces Chrome/Edge to use our palette. (Used as a fallback
   for any select that the combo enhancer hasn't taken over.) */
html[data-page="sources"] select option,
html[data-page="sources"] select optgroup {
    background-color: var(--bg-elevated);
    color: var(--text);
}

/* === Combo (custom select) === */

.combo {
    position: relative;
    display: inline-flex;
    flex-direction: column;
    min-width: 0;
    width: 100%;
}
.combo > select {
    /* Keep the native select in the DOM (form value, change events) but
       fully out of layout — never visible, never tabbable. */
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
    opacity: 0;
    pointer-events: none;
}
.combo-trigger {
    display: inline-flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    width: 100%;
    padding: 11px 12px;
    font-family: inherit;
    font-size: 14px;
    color: var(--text);
    background: var(--bg-subtle);
    border: 1px solid var(--border);
    border-radius: 4px;
    cursor: pointer;
    transition: border-color .15s ease, box-shadow .15s ease, background-color .15s ease;
    text-align: left;
    min-height: 46px;
}
.combo-trigger:hover:not(:disabled) { border-color: var(--border-strong); }
.combo-trigger:focus-visible {
    outline: none;
    border-color: var(--accent);
    background-color: var(--bg-elevated);
    box-shadow: 0 0 0 3px var(--focus-ring);
}
.combo.is-open > .combo-trigger {
    border-color: var(--accent);
    background-color: var(--bg-elevated);
    box-shadow: 0 0 0 3px var(--focus-ring);
}
.combo.is-disabled .combo-trigger {
    opacity: 0.6;
    cursor: not-allowed;
}
.combo-value {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 500;
}
.combo-caret {
    flex-shrink: 0;
    color: var(--text-muted);
    display: inline-flex;
    transition: transform .18s ease, color .15s ease;
}
.combo.is-open .combo-caret { transform: rotate(180deg); color: var(--text); }

.combo-menu {
    z-index: 200;
    margin: 0;
    padding: 4px;
    list-style: none;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: 6px;
    box-shadow: var(--shadow-dropdown);
    overflow-y: auto;
    overscroll-behavior: contain;
    animation: comboIn 0.12s ease-out;
}
.combo-menu[hidden] { display: none; }
.combo-menu--up { animation-name: comboInUp; }
@keyframes comboIn {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: translateY(0); }
}
@keyframes comboInUp {
    from { opacity: 0; transform: translateY(4px); }
    to   { opacity: 1; transform: translateY(0); }
}

.combo-option {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 8px 10px;
    border-radius: 4px;
    cursor: pointer;
    color: var(--text);
    font-size: 13.5px;
    line-height: 1.4;
    user-select: none;
}
.combo-option.is-active { background: var(--bg-subtle); }
.combo-option.is-selected {
    color: var(--accent);
    font-weight: 600;
    background: var(--bg-subtle);
}
html[data-theme="dark"] .combo-option.is-selected {
    color: var(--text);
    background: rgba(255, 255, 255, 0.06);
}
.combo-option.is-selected::after {
    content: '';
    width: 14px;
    height: 14px;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'><polyline points='20 6 9 17 4 12'/></svg>");
    background-size: contain;
    background-repeat: no-repeat;
    flex-shrink: 0;
}

.admin-main {
    flex: 1;
    padding: 28px 32px 56px;
    width: 100%;
    max-width: 1080px;
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.admin-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 14px;
    flex-wrap: wrap;
}
.admin-header-text h1 {
    font-size: 22px;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--text);
    margin-bottom: 4px;
}
.admin-header-text p {
    font-size: 13px;
    color: var(--text-muted);
    line-height: 1.5;
}

.admin-tabs-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 14px;
    flex-wrap: wrap;
}
.admin-tabs-row .projects-tabs { margin-bottom: 0; }

/* Toolbar: search + filters + new */

.admin-toolbar {
    display: flex;
    gap: 10px;
    margin-bottom: 14px;
    flex-wrap: wrap;
    align-items: center;
}
.admin-toolbar .projects-search { flex: 1 1 320px; min-width: 220px; }

.admin-filter-btn {
    width: 40px;
    height: 40px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: 6px;
    color: var(--text-muted);
    cursor: pointer;
    transition: border-color .15s ease, box-shadow .15s ease, color .15s ease;
    flex-shrink: 0;
    position: relative;
}
.admin-filter-btn:hover { border-color: var(--border-strong); color: var(--text); }
.admin-filter-btn:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--focus-ring); }
.admin-filter-btn[hidden] { display: none; }
.admin-filter-btn .filter-count {
    position: absolute;
    top: -4px;
    right: -4px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: 8px;
    background: var(--accent);
    color: var(--accent-fg);
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: 10px;
    font-weight: 600;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
    box-shadow: 0 0 0 2px var(--bg-elevated);
}
/* Unapplied draft indicator — small amber dot in the top-left corner,
   positioned away from the count badge in the top-right. */
.admin-filter-btn.is-dirty::before {
    content: '';
    position: absolute;
    top: -3px;
    left: -3px;
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: #f59e0b;
    box-shadow: 0 0 0 2px var(--bg-elevated);
}
/* Apply button gets a subtle amber ring when there are unapplied changes
   inside the drawer — gives the user a visual cue while they're editing. */
#filter-apply.is-dirty {
    box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.28);
}

.fgroup-empty {
    font-size: 12.5px;
    color: var(--text-muted);
    line-height: 1.4;
}

.fgroup-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    /* Reserve space for the .admin-pass-mode toggle even when it's hidden,
       so the block doesn't jump vertically the moment a 2nd tag is added. */
    min-height: 36px;
}

/* Multi-select dropdown for drawer filters */
.mselect { position: relative; width: 100%; }
.mselect-trigger {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    width: 100%;
    padding: 9px 12px;
    background: var(--bg-subtle);
    border: 1px solid var(--border);
    border-radius: 4px;
    color: var(--text);
    font: inherit;
    font-size: 13px;
    cursor: pointer;
    text-align: left;
    transition: border-color .15s ease, box-shadow .15s ease, background-color .15s ease;
}
.mselect-trigger:hover { border-color: var(--border-strong); }
.mselect-trigger:focus-visible {
    outline: none;
    border-color: var(--accent);
    background-color: var(--bg-elevated);
    box-shadow: 0 0 0 3px var(--focus-ring);
}
.mselect.is-open > .mselect-trigger {
    border-color: var(--accent);
    background-color: var(--bg-elevated);
    box-shadow: 0 0 0 3px var(--focus-ring);
}
.mselect-value {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 500;
}
.mselect-value.is-empty {
    color: var(--text-subtle);
    font-weight: 400;
}
.mselect-caret {
    flex-shrink: 0;
    color: var(--text-muted);
    transition: transform .18s ease;
}
.mselect.is-open .mselect-caret { transform: rotate(180deg); color: var(--text); }

.mselect-menu {
    margin: 4px 0 0;
    padding: 4px;
    list-style: none;
    max-height: 240px;
    overflow-y: auto;
    overscroll-behavior: contain;
    border: 1px solid var(--border);
    border-radius: 4px;
    background: var(--bg-elevated);
    box-shadow: var(--shadow-dropdown);
    display: flex;
    flex-direction: column;
    gap: 1px;
}
.mselect-menu[hidden] { display: none; }
.mselect-option {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 7px 10px;
    border-radius: 3px;
    cursor: pointer;
    color: var(--text);
    font-size: 13px;
    user-select: none;
}
.mselect-option:hover { background: var(--bg-subtle); }
.mselect-check {
    flex-shrink: 0;
    width: 14px;
    height: 14px;
    border: 1.5px solid var(--border-strong);
    border-radius: 3px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background-color .12s ease, border-color .12s ease;
}
.mselect-option.is-selected .mselect-check {
    background: var(--accent);
    border-color: var(--accent);
}
.mselect-option.is-selected .mselect-check::after {
    content: '';
    width: 8px;
    height: 8px;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'><polyline points='20 6 9 17 4 12'/></svg>");
    background-size: contain;
    background-repeat: no-repeat;
}
html[data-theme="dark"] .mselect-option.is-selected .mselect-check::after {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'><polyline points='20 6 9 17 4 12'/></svg>");
}

#admin-tag-filter .admin-tagpicker-list {
    max-height: 200px;
}

/* Table wrapper — horizontal scroll on narrow viewports */

.admin-table-wrap {
    width: 100%;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: 8px;
    box-shadow: var(--shadow-card);
    overflow-x: auto;
    overflow-y: visible;
    overscroll-behavior-x: contain;
}

.admin-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
    color: var(--text);
}
/* Sources tab: lock column widths so rows stay stable as data loads/filters
   change. Widths come from inline `width` attrs on the thead row. */
.admin-table.is-fixed {
    table-layout: fixed;
}
.admin-table thead th {
    text-align: left;
    padding: 10px 12px;
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: 10.5px;
    font-weight: 500;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-subtle);
    background: var(--bg-subtle);
    border-bottom: 1px solid var(--border);
    white-space: nowrap;
    position: sticky;
    top: 0;
    z-index: 1;
}
.admin-table tbody tr {
    border-bottom: 1px solid var(--border);
    transition: background-color .12s ease;
}
.admin-table tbody tr:last-child { border-bottom: none; }
.admin-table tbody tr:hover { background: var(--bg-subtle); }
.admin-table td {
    padding: 10px 12px;
    vertical-align: middle;
    line-height: 1.4;
}
.admin-table td.cell-actions {
    width: 1px;
    white-space: nowrap;
    text-align: right;
}
.admin-table td.cell-actions > .project-action {
    margin-left: 4px;
}
.admin-table td.cell-actions > .project-action:first-child {
    margin-left: 0;
}
/* Enabled toggle column — collapses to switch width and is centered. */
.admin-table th.cell-enabled-head {
    text-align: center;
}
.admin-table td.cell-enabled {
    width: 1px;
    text-align: center;
    white-space: nowrap;
}
.admin-table td.cell-mono {
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: 12px;
    color: var(--text-muted);
}
.admin-table td.cell-name {
    font-weight: 600;
    color: var(--text);
    max-width: 240px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.admin-table td.cell-url {
    max-width: 320px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--text-muted);
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: 12px;
}
.admin-table td.cell-tags {
    max-width: 280px;
}
.admin-table td.cell-desc {
    max-width: 320px;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.admin-table td.cell-host {
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: 12px;
    color: var(--text);
    max-width: 280px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.admin-table td.cell-country {
    color: var(--text);
    white-space: nowrap;
}
.cell-country-flag {
    display: inline-block;
    width: 24px;
    height: auto;
    border-radius: 2px;
    box-shadow: 0 0 0 1px var(--border-subtle, rgba(255, 255, 255, 0.08));
    vertical-align: middle;
    object-fit: cover;
    cursor: help;
}
.cell-country-name {
    font-size: 13px;
    cursor: help;
}
.cell-country-loading {
    display: inline-block;
    width: 12px;
    height: 12px;
    border: 1.5px solid var(--text-subtle);
    border-top-color: transparent;
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
    vertical-align: -2px;
    opacity: 0.6;
}
.admin-table .empty-cell {
    color: var(--text-subtle);
    font-style: italic;
}

/* Inline delete-confirm — overlays the right portion of the row whose
   trash icon was clicked, mirroring .project-card-confirm on project cards.
   The panel lives inside the row's cell-actions <td>, but is absolutely
   positioned relative to the <tr> via position:relative on the row. */
.admin-table tbody tr.is-confirming {
    position: relative;
}
.admin-table tbody tr.is-confirming > td.cell-actions {
    position: static;
}
.admin-table tbody tr.is-confirming > td.cell-actions > .project-card-confirm {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    min-width: 320px;
    max-width: 70%;
    padding: 8px 14px;
}
.admin-table tbody tr.is-confirming .project-card-confirm-msg {
    -webkit-line-clamp: 1;
    flex: 1 1 auto;
    margin: 0;
}
.admin-table tbody tr.is-confirming .project-card-confirm-row {
    flex: 0 0 auto;
}

/* Status / type chips — flat, no rounded-pill background.
   Status: colored dot (::before) + plain mixed-case label.
   Type:   small monospace label (reads as an identifier). */

.admin-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--text-muted);
    white-space: nowrap;
    line-height: 1.3;
    font-size: 12px;
}
.admin-chip[class*="is-status-"]::before {
    content: '';
    display: inline-block;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: currentColor;
    flex-shrink: 0;
}
.admin-chip.is-status-polling { color: #15803d; }
html[data-theme="dark"] .admin-chip.is-status-polling { color: #86efac; }
.admin-chip.is-status-auto_configuring,
.admin-chip.is-status-needs_manual { color: var(--warning); }
.admin-chip.is-status-auto_suspended,
.admin-chip.is-status-disabled { color: var(--text-subtle); }
.admin-chip.is-type {
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: 12px;
    color: var(--text-muted);
    letter-spacing: 0.02em;
}
/* Bool chips keep the rounded-pill look (used on proxies for "has password"). */
.admin-chip.is-bool-on,
.admin-chip.is-bool-off {
    padding: 2px 8px;
    border-radius: 999px;
    border: 1px solid var(--border);
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
.admin-chip.is-bool-on {
    color: #15803d;
    border-color: #15803d;
    background: #f0fdf4;
}
html[data-theme="dark"] .admin-chip.is-bool-on {
    color: #86efac;
    border-color: #16a34a;
    background: rgba(22, 163, 74, 0.12);
}
.admin-chip.is-bool-off {
    color: var(--text-subtle);
    background: var(--bg-subtle);
}

.admin-tag-pill {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    margin: 2px 4px 2px 0;
    border-radius: 4px;
    background: var(--bg-subtle);
    border: 1px solid var(--border);
    color: var(--text);
    font-size: 11.5px;
    line-height: 1.4;
    white-space: nowrap;
}
.admin-tag-pill .admin-tag-pill-cat {
    color: var(--text-subtle);
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: 10px;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

/* Empty / loader states inside the table area */

.admin-empty {
    padding: 32px 16px;
    text-align: center;
    color: var(--text-muted);
    font-size: 14px;
    background: var(--bg-elevated);
    border: 1px dashed var(--border);
    border-radius: 8px;
}
.admin-loader {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 48px 0;
}
.admin-loader-spinner {
    width: 22px;
    height: 22px;
    border: 2px solid var(--border);
    border-top-color: var(--text-muted);
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
}

.admin-loadmore-wrap {
    display: flex;
    justify-content: center;
    margin-top: 16px;
}

/* Modal — wider variant, reusing project-modal skeleton */

.project-modal.admin-modal-wide .project-modal-panel {
    width: 720px;
}
.project-modal.admin-modal-narrow .project-modal-panel {
    width: 480px;
}

/* Wizard stepper — splits a long form into ordered steps.
   Each step is a numbered circle with its label underneath; circles
   are linked by a connector line. The active and completed steps
   are filled with accent; future steps stay muted/outlined. */
.modal-stepper {
    display: flex;
    align-items: flex-start;
    margin: 4px 0 24px;
    padding: 0;
    counter-reset: modal-step;
}
.modal-step {
    flex: 1 1 0;
    min-width: 0;
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    counter-increment: modal-step;
    color: var(--text-muted);
    transition: color .15s ease;
}
/* Numbered bullet: rendered via ::before so it becomes the first
   flex item, sitting above the label. */
.modal-step::before {
    content: counter(modal-step);
    position: relative;
    z-index: 1;
    box-sizing: border-box;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--surface, transparent);
    border: 2px solid var(--border-strong);
    color: var(--text-muted);
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: 12px;
    font-weight: 600;
    line-height: 1;
    margin-bottom: 10px;
    transition: background .15s ease, border-color .15s ease, color .15s ease;
}
/* Connector line to the next step. The line spans from the right edge
   of this circle to the left edge of the next circle, sitting behind
   the bullets via z-index. */
.modal-step::after {
    content: '';
    position: absolute;
    top: 13px;
    left: calc(50% + 18px);
    right: calc(-50% + 18px);
    height: 2px;
    background: var(--border-strong);
    z-index: 0;
    transition: background .15s ease;
}
.modal-step:last-child::after {
    display: none;
}
.modal-step.is-active,
.modal-step.is-complete {
    color: var(--text);
}
.modal-step.is-active::before,
.modal-step.is-complete::before {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--accent-fg);
}
/* Connector lights up only once the step is complete (i.e. the user
   has crossed it on the way forward). */
.modal-step.is-complete::after {
    background: var(--accent);
}
.modal-step-label {
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    line-height: 1.3;
    word-break: break-word;
}
/* In edit mode, step bullets become navigable — opt into pointer cursor
   and a hover/focus highlight so the affordance is visible. */
.modal-step.is-clickable {
    cursor: pointer;
    outline: none;
}
.modal-step.is-clickable:hover {
    color: var(--text);
}
.modal-step.is-clickable:hover::before {
    border-color: var(--accent);
}
.modal-step.is-clickable:focus-visible::before {
    box-shadow: 0 0 0 3px var(--focus-ring, rgba(99, 102, 241, 0.35));
}

/* Panel container — all steps live in the same grid cell, stacked
   on top of each other. The container's height equals the tallest
   panel, so switching steps never resizes the dialog. The inactive
   panels stay in flow (visibility: hidden keeps them out of focus
   order while preserving layout). */
.modal-stepper-panels {
    display: grid;
    grid-template-columns: 1fr;
}
.modal-tabpanel {
    grid-column: 1;
    grid-row: 1;
    min-width: 0;
}
.modal-tabpanel:not(.is-active) {
    visibility: hidden;
    pointer-events: none;
}

/* Wizard action bar: Cancel pinned to the left, Back/Next/Finish right. */
.project-form-actions.is-wizard > .wizard-cancel {
    margin-right: auto;
}

.admin-form-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 14px;
}
.admin-form-grid .field { margin: 0; }
.admin-form-grid .field--full { grid-column: 1 / -1; }
/* Auto-mark labels of fields whose control has the `required` attribute.
   Keeps HTML clean: just add `required` to the input and the asterisk
   appears next to the label. Descendant `:has` (no `>`) so it still
   matches when combo.js wraps the <select> inside an extra .combo div. */
.admin-form-grid .field:has(input:required, textarea:required, select:required) > label::after {
    content: '*';
    color: var(--danger);
    font-weight: 700;
    margin-left: 3px;
    font-size: 9px;
    vertical-align: top;
    position: relative;
    top: -1px;
    line-height: 1;
}
/* Soft validation: a required field that is empty when the user tries
   to advance gets aria-invalid="true". Just a red border — no toast,
   no message — on the field itself. Cleared on first input.
   `input[type]` (any value) raises specificity above the per-type rules
   below (input[type="url"], input[type="number"]) which would otherwise
   overwrite border-color for invalid inputs of those types. */
.admin-form-grid .field input[type][aria-invalid="true"],
.admin-form-grid .field textarea[aria-invalid="true"],
.admin-form-grid .field select[aria-invalid="true"] {
    border-color: var(--danger);
}
.admin-form-grid .field input[type][aria-invalid="true"]:focus,
.admin-form-grid .field textarea[aria-invalid="true"]:focus,
.admin-form-grid .field select[aria-invalid="true"]:focus {
    border-color: var(--danger);
    box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.18);
}
/* The native <select> behind a custom combo is hidden, so propagate the
   invalid state to the visible trigger. */
.admin-form-grid .field .combo:has(> select[aria-invalid="true"]) > .combo-trigger {
    border-color: var(--danger);
}
.admin-form-grid .field .combo:has(> select[aria-invalid="true"]).is-open > .combo-trigger,
.admin-form-grid .field .combo:has(> select[aria-invalid="true"]) > .combo-trigger:focus-visible {
    border-color: var(--danger);
    box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.18);
}
/* Placeholder option (value="") — render as muted text in the trigger
   so the empty state reads as "not chosen yet". */
.admin-form-grid .field .combo:has(> select:invalid) .combo-value {
    color: var(--text-subtle);
}

.admin-form-grid .field input[type="number"] {
    width: 100%;
    padding: 12px 14px;
    font-family: inherit;
    font-size: 15px;
    color: var(--text);
    background: var(--bg-subtle);
    border: 1px solid var(--border);
    border-radius: 4px;
    transition: border-color 0.15s ease, box-shadow 0.15s ease, background-color 0.15s ease;
    -webkit-appearance: none;
    appearance: none;
}
.admin-form-grid .field input[type="number"]:focus {
    outline: none;
    border-color: var(--accent);
    background: var(--bg-elevated);
    box-shadow: 0 0 0 3px var(--focus-ring);
}
.admin-form-grid .field input[type="url"] {
    width: 100%;
    padding: 12px 14px;
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: 13.5px;
    color: var(--text);
    background: var(--bg-subtle);
    border: 1px solid var(--border);
    border-radius: 4px;
    transition: border-color 0.15s ease, box-shadow 0.15s ease, background-color 0.15s ease;
}
.admin-form-grid .field input[type="url"]:focus {
    outline: none;
    border-color: var(--accent);
    background: var(--bg-elevated);
    box-shadow: 0 0 0 3px var(--focus-ring);
}
.admin-form-grid .field select {
    width: 100%;
    padding: 12px 14px;
    font-family: inherit;
    font-size: 14px;
    color: var(--text);
    background: var(--bg-subtle);
    border: 1px solid var(--border);
    border-radius: 4px;
    appearance: none;
    -webkit-appearance: none;
    background-image:
        linear-gradient(45deg, transparent 50%, var(--text-muted) 50%),
        linear-gradient(135deg, var(--text-muted) 50%, transparent 50%);
    background-position:
        calc(100% - 16px) 50%,
        calc(100% - 11px) 50%;
    background-size: 5px 5px, 5px 5px;
    background-repeat: no-repeat;
    padding-right: 32px;
    cursor: pointer;
}
.admin-form-grid .field select:focus {
    outline: none;
    border-color: var(--accent);
    background-color: var(--bg-elevated);
    box-shadow: 0 0 0 3px var(--focus-ring);
}

.admin-form-grid .field textarea {
    width: 100%;
    min-height: 84px;
    max-height: 200px;
    resize: vertical;
    padding: 12px 14px;
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: 13px;
    line-height: 1.5;
    color: var(--text);
    background: var(--bg-subtle);
    border: 1px solid var(--border);
    border-radius: 4px;
    transition: border-color 0.15s ease, box-shadow 0.15s ease, background-color 0.15s ease;
}
.admin-form-grid .field textarea:focus {
    outline: none;
    border-color: var(--accent);
    background: var(--bg-elevated);
    box-shadow: 0 0 0 3px var(--focus-ring);
}
.admin-form-grid .field--text textarea {
    font-family: inherit;
    font-size: 14px;
}

/* Toggle row (enabled checkbox) */

.admin-toggle {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    cursor: pointer;
    user-select: none;
    padding: 6px 0;
}
/* Inline switch in table cells — no padding, focus ring lives on the
   track (no surrounding pill to compete with). Disabled while the
   PATCH is in flight; reverts to interactive on success or rollback. */
.admin-toggle--cell {
    padding: 0;
    vertical-align: middle;
}
.admin-toggle input:disabled ~ .admin-toggle-track {
    opacity: 0.55;
    cursor: progress;
}
.admin-toggle input { position: absolute; opacity: 0; pointer-events: none; }
.admin-toggle-track {
    width: 38px;
    height: 22px;
    border-radius: 999px;
    background: var(--border-strong);
    position: relative;
    transition: background-color .18s ease;
    flex-shrink: 0;
}
.admin-toggle-track::after {
    content: '';
    position: absolute;
    top: 2px;
    left: 2px;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: #fff;
    transition: transform .18s ease;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
}
.admin-toggle input:checked + .admin-toggle-track { background: var(--toggle-on); }
.admin-toggle input:checked + .admin-toggle-track::after { transform: translateX(16px); }
.admin-toggle input:focus-visible + .admin-toggle-track { box-shadow: 0 0 0 3px var(--focus-ring); }
html[data-theme="dark"] .admin-toggle-track::after { background: #e4e4e3; }
.admin-toggle-label {
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-muted);
}

/* Tag picker (multiselect, used inside source modal) */

.admin-tagpicker {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 10px;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--bg-subtle);
    min-height: 88px;
}
.admin-tagpicker-selected {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    min-height: 22px;
}
.admin-tagpicker-empty {
    color: var(--text-subtle);
    font-style: italic;
    font-size: 12.5px;
    align-self: center;
}
.admin-tagpicker-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 4px 3px 10px;
    border-radius: 4px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    font-size: 12px;
    color: var(--text);
}
.admin-tagpicker-chip-rm {
    width: 18px;
    height: 18px;
    border: none;
    background: transparent;
    color: var(--text-muted);
    border-radius: 3px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: color .12s ease, background-color .12s ease;
}
.admin-tagpicker-chip-rm:hover { color: var(--danger); background: var(--danger-bg); }
.admin-tagpicker-chip-rm:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--focus-ring); }

.admin-tagpicker-search {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 34px;
    padding: 0 10px;
    border: 1px solid var(--border);
    border-radius: 4px;
    background: var(--bg-elevated);
    color: var(--text-muted);
    transition: border-color .15s ease;
}
.admin-tagpicker-search:focus-within {
    border-color: var(--border-strong);
}
.admin-tagpicker-search input {
    flex: 1;
    min-width: 0;
    height: 100%;
    border: 0;
    outline: 0;
    background: transparent;
    color: var(--text);
    font: inherit;
    font-size: 13px;
    padding: 0;
    -webkit-appearance: none;
    appearance: none;
}
.admin-tagpicker-search input::-webkit-search-cancel-button,
.admin-tagpicker-search input::-webkit-search-decoration {
    display: none;
    -webkit-appearance: none;
}
.admin-tagpicker-search input:focus,
.admin-tagpicker-search input:focus-visible {
    outline: 0;
    border: 0;
    background: transparent;
    box-shadow: none;
}

.admin-tagpicker-list {
    max-height: 160px;
    overflow-y: auto;
    overscroll-behavior: contain;
    border: 1px solid var(--border);
    border-radius: 4px;
    background: var(--bg-elevated);
    list-style: none;
    margin: 0;
    padding: 4px;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.admin-tagpicker-list[hidden] { display: none; }
.admin-tagpicker-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 6px 8px;
    border-radius: 3px;
    cursor: pointer;
    color: var(--text);
    font-size: 13px;
    transition: background-color .1s ease;
}
.admin-tagpicker-item:hover,
.admin-tagpicker-item:focus-visible,
.admin-tagpicker-item.is-active {
    background: var(--bg-subtle);
    outline: none;
}
.admin-tagpicker-item.is-selected {
    color: var(--text-subtle);
    cursor: default;
}
.admin-tagpicker-item-cat {
    color: var(--text-subtle);
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: 10px;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}
.admin-tagpicker-empty-results {
    padding: 10px;
    text-align: center;
    color: var(--text-subtle);
    font-style: italic;
    font-size: 12.5px;
}

/* "Category | Name" pair, used in tag pickers, pills, and dropdown items. */
.admin-tag-display {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}
.admin-tag-display-sep {
    color: var(--text-muted);
    font-size: 11px;
    user-select: none;
}
.admin-tag-display-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Category autocomplete (used in tag modal). */
.admin-cat-autocomplete {
    position: relative;
}
.admin-cat-suggestions {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    right: 0;
    z-index: 10;
    list-style: none;
    margin: 0;
    padding: 4px;
    max-height: 220px;
    overflow-y: auto;
    overscroll-behavior: contain;
    background: var(--bg-elevated);
    border: 1px solid var(--border-strong);
    border-radius: 6px;
    box-shadow: var(--shadow-dropdown);
    display: flex;
    flex-direction: column;
    gap: 1px;
}
.admin-cat-suggestions[hidden] { display: none; }
.admin-cat-suggestions li {
    padding: 9px 13px;
    border-radius: 4px;
    cursor: pointer;
    font-size: 14px;
    line-height: 1.3;
    color: var(--text);
    transition: background-color .12s ease, color .12s ease;
    user-select: none;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.admin-cat-suggestions li:hover {
    background: var(--bg-subtle);
}
.admin-cat-suggestions li.is-active {
    background: var(--accent);
    color: var(--accent-fg);
    outline: none;
}

/* Proxy auth section */

.admin-auth-block {
    grid-column: 1 / -1;
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 12px;
    background: var(--bg-subtle);
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.admin-auth-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
}
.admin-auth-row .admin-toggle-label { color: var(--text); }
.admin-auth-fields {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
}
.admin-auth-fields[hidden] { display: none; }
.admin-pass-mode {
    display: inline-flex;
    gap: 4px;
    padding: 3px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 6px;
}
.admin-pass-mode button {
    padding: 5px 10px;
    border: none;
    background: transparent;
    color: var(--text-muted);
    font: inherit;
    font-size: 11.5px;
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    border-radius: 4px;
    cursor: pointer;
    transition: all .12s ease;
}
.admin-pass-mode button.is-active {
    background: var(--bg-elevated);
    color: var(--text);
    box-shadow: var(--shadow-card);
}
.admin-pass-mode button:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--focus-ring); }
.admin-pass-mode--full { display: flex; width: 100%; }
.admin-pass-mode--full button { flex: 1; text-align: center; }

/* Responsive */

@media (max-width: 920px) {
    .admin-form-grid { grid-template-columns: 1fr; }
    .admin-auth-fields { grid-template-columns: 1fr; }
}
@media (max-width: 720px) {
    .admin-main { padding: 18px 14px 56px; }
    .admin-table thead { display: none; }
    .admin-table,
    .admin-table tbody,
    .admin-table tr,
    .admin-table td {
        display: block;
        width: 100%;
    }
    .admin-table tbody tr {
        padding: 12px;
        border-bottom: 1px solid var(--border);
    }
    .admin-table td {
        padding: 4px 0;
        white-space: normal !important;
        max-width: none !important;
    }
    .admin-table td.cell-actions { text-align: left; padding-top: 8px; }
    .admin-table td::before {
        content: attr(data-label);
        display: block;
        font-family: "IBM Plex Mono", ui-monospace, monospace;
        font-size: 9.5px;
        font-weight: 500;
        letter-spacing: 0.1em;
        text-transform: uppercase;
        color: var(--text-subtle);
        margin-bottom: 2px;
    }
    .admin-table td.cell-actions::before { display: none; }
    .admin-table-wrap {
        overflow: visible;
        background: transparent;
        border: none;
        box-shadow: none;
        border-radius: 0;
    }
    .admin-table tbody tr {
        background: var(--bg-elevated);
        border: 1px solid var(--border);
        border-radius: 6px;
        margin-bottom: 8px;
    }
    .admin-table tbody tr:hover { background: var(--bg-elevated); }

    /* Mobile: each row is a stacked card. The confirm panel can't overlay
       the right side meaningfully, so it falls in-flow as a strip below the
       row content, replacing the action buttons. */
    .admin-table tbody tr.is-confirming { position: static; }
    .admin-table tbody tr.is-confirming > td.cell-actions > .project-action {
        display: none;
    }
    .admin-table tbody tr.is-confirming > td.cell-actions > .project-card-confirm {
        position: static;
        margin-top: 6px;
        min-width: 0;
        max-width: none;
        width: 100%;
        padding: 10px 12px;
    }
}
