:root {
  --bg: #0A0A0B; --surface: #141416; --surface-2: #1C1C1F; --surface-3: #242428;
  --border: #2A2A2E; --border-soft: #1E1E21;
  --accent: #2555A8; --accent-dim: #16233B; --accent-fg: #FFFFFF;
  --ok: #34D399; --ok-dim: #12291F;
  --bad: #E5484D; --bad-dim: #3A1418;
  --warn: #FBBF24; --warn-dim: #33280D;
  --idle: #9A9AA0; --idle-dim: #1F1F22;
  --text: #F2F2F3; --text-dim: #9B9BA1; --text-faint: #616166;
  --radius-lg: 14px; --radius-md: 10px; --radius-sm: 7px;
  --sans: -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, "Cascadia Code", "SF Mono", Consolas, "Roboto Mono", monospace;
}
/* Dark-UI only by design brief - no light-theme fallback. */

* { box-sizing: border-box; }
html, body { margin: 0; background: var(--bg); color: var(--text); font-family: var(--sans); font-size: 14px; -webkit-font-smoothing: antialiased; }
button, input, select { font-family: inherit; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
::selection { background: #2F81F7; color: #FFFFFF; }
input::selection, textarea::selection { background: #2F81F7; color: #FFFFFF; }

.login-page {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 24px;
  background: #0D1117;
}
.login-card {
  width: min(100%, 340px);
  display: flex;
  flex-direction: column;
  gap: 18px;
  padding: 36px 32px 32px;
  background: #161B22;
  border: 1px solid #30363D;
  border-radius: 8px;
  box-shadow: 0 24px 60px rgba(0,0,0,.34);
}
.login-brand { display: flex; align-items: center; gap: 10px; margin-bottom: 4px; }
.login-dot { width: 8px; height: 8px; border-radius: 50%; background: #58A6FF; box-shadow: 0 0 14px rgba(88,166,255,.5); }
.login-brand h1 { margin: 0; font-size: 16px; line-height: 1.2; font-weight: 700; color: #F0F6FC; }
.login-card p { margin: 0; color: #8B949E; font-size: 13px; }
.login-card .field { display: flex; flex-direction: column; gap: 8px; margin: 0; }
.login-card label { color: #9DB6E0; font-size: 11px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; }
.login-card input {
  height: 35px;
  border: 1px solid #30363D;
  border-radius: 6px;
  background: #0D1117;
  color: #F0F6FC;
  padding: 7px 10px;
  outline: none;
}
.login-card input:focus { border-color: #58A6FF; box-shadow: 0 0 0 2px rgba(88,166,255,.18); }
.login-btn { width: 100%; justify-content: center; min-height: 38px; margin-top: 6px; background: #238636; border-color: #238636; color: #fff; font-size: 14px; }
.login-btn:hover { background: #2EA043; }
.login-error {
  border: 1px solid rgba(248,81,73,.35);
  border-radius: 6px;
  background: rgba(248,81,73,.11);
  color: #FFB4B4;
  padding: 9px 10px;
  font-size: 12.5px;
}

* { scrollbar-width: thin; scrollbar-color: var(--surface-3) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--surface-3); border-radius: 999px; border: 2px solid var(--surface); background-clip: padding-box; }
::-webkit-scrollbar-thumb:hover { background: var(--border); background-clip: padding-box; }
::-webkit-scrollbar-corner { background: transparent; }

.stage { width: 100%; max-width: none; height: 100vh; margin: 0; padding: 12px 14px 28px; display: flex; flex-direction: column; overflow: hidden; }

.sticky-controls {
  position: sticky;
  top: 0;
  z-index: 30;
  flex: 0 0 auto;
  padding-top: 8px;
  margin: -8px 0 10px;
  background: var(--bg);
}

.pagehead {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(280px, 460px) minmax(0, 1fr);
  grid-template-areas: "title search filters";
  align-items: center; gap: 12px;
  padding: 0 0 8px; margin-bottom: 8px; border-bottom: 1px solid var(--border-soft);
}
.pagehead .left { grid-area: title; display: flex; align-items: center; gap: 10px; flex-wrap: nowrap; min-width: 0; overflow: hidden; }
.page-title { margin: 0; font-size: 22px; line-height: 1; font-weight: 800; letter-spacing: 0; color: var(--text); flex: 0 0 auto; }
.status-chips { display: flex; align-items: center; gap: 6px; flex-wrap: nowrap; min-width: 0; overflow-x: auto; scrollbar-width: none; }
.status-chips::-webkit-scrollbar { display: none; }

.chip { font: inherit; min-height: 32px; font-size: 12px; font-weight: 600; padding: 0 10px; border-radius: 4px; border: 1px solid var(--border); display: inline-flex; align-items: center; gap: 6px; cursor: pointer; color: var(--text-dim); background: rgba(16,16,18,.76); white-space: nowrap; flex: 0 0 auto; }
.chip[aria-pressed="true"] { border-color: rgba(255,255,255,.24); background: var(--surface-2); color: var(--text); }
.chip-dot { width: 9px; height: 9px; border-radius: 50%; background: currentColor; box-shadow: 0 0 10px currentColor; }
.chip.tot { color: var(--text-dim); }
.chip.ok { color: var(--ok); }
.chip.bad { color: var(--bad); }
.chip.warn { color: var(--warn); }
.chip.idle { color: var(--idle); }
.statusfilter { min-height: 32px; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-md); color: var(--text); font-size: 12px; font-weight: 700; padding: 0 28px 0 10px; cursor: pointer; }
.statusfilter:hover { background: var(--surface-3); }

.right-controls { grid-area: filters; display: flex; align-items: center; justify-content: flex-end; gap: 7px; flex-wrap: wrap; }
.seg { min-height: 32px; display: flex; align-items: center; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-md); padding: 3px; }
.seg button { background: none; color: var(--text-dim); border: none; padding: 6px 10px; font-size: 12px; font-weight: 700; cursor: pointer; border-radius: 7px; }
.seg button[aria-pressed="true"] { background: var(--surface-3); color: var(--text); }
.view-seg button { padding-inline: 11px; }

.btn { display: inline-flex; align-items: center; gap: 7px; border: 1px solid var(--border); border-radius: var(--radius-md); padding: 8px 12px; font-size: 12.5px; font-weight: 600; cursor: pointer; white-space: nowrap; background: var(--surface-2); color: var(--text); }
.btn:hover { background: var(--surface-3); }
.btn:disabled { opacity: .4; cursor: default; pointer-events: none; }
.btn-primary { background: rgba(28,28,31,.86); color: var(--text); border-color: rgba(255,255,255,.12); }
.btn-primary:hover { filter: none; background: rgba(36,36,40,.94); border-color: rgba(255,255,255,.18); }
.btn-primary svg { color: #9DB6E0; }
.btn-ok { background: rgba(28,28,31,.86); color: var(--text); border-color: rgba(255,255,255,.12); }
.btn-ok:hover { background: rgba(36,36,40,.94); border-color: rgba(52,211,153,.28); }
.btn-ok svg { color: #75C995; }
.btn-bad { background: rgba(28,28,31,.86); color: var(--text); border-color: rgba(255,255,255,.12); font-weight: 700; }
.btn-bad:hover { background: rgba(36,28,30,.94); border-color: rgba(229,72,77,.32); }
.btn-bad svg { color: #B85A5F; }

.control-panel {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  gap: 12px; align-items: center; margin-bottom: 0;
}
.control-main { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; min-width: 0; }
.control-side { display: flex; align-items: center; justify-content: flex-end; gap: 12px; min-width: 0; }
.control-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; min-height: 38px; }
.control-divider { display: none; }
.divider { width: 1px; height: 20px; background: var(--border); flex: 0 0 auto; }
.check-label { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--text-dim); cursor: pointer; user-select: none; }
.sel-count { font-size: 12.5px; color: var(--text-faint); }
.sel-count b { color: var(--text); font-family: var(--mono); }
.file { position: relative; display: grid; grid-template-columns: minmax(190px, 220px) auto; align-items: center; gap: 8px; color: var(--text-faint); }
.file > svg { display: none; }
.provider-file-select { width: 100%; height: 38px; padding: 0 28px 0 12px; border: 1px solid var(--border); border-radius: 4px; background: rgba(16,16,18,.8); color: var(--text); font-family: var(--mono); font-size: 13px; }
.fileacts { display: flex; gap: 7px; }
.fileacts .file-action-btn { min-height: 34px; padding: 0 11px; font-size: 12px; }
.alert-settings { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.discord-setting { display: flex; align-items: center; gap: 8px; color: var(--text-dim); font-size: 13px; white-space: nowrap; }
.discord-setting > svg { color: #5865F2; }
.desktop-setting > svg { color: var(--warn); }
.startup-setting > svg { color: var(--accent); }
.discord-unconfigured { color: var(--text-faint); font-size: 11px; }
.discord-switch { appearance: none; padding: 0; margin-left: 2px; }
.discord-switch:disabled { opacity: .45; cursor: default; }

.poll { display: flex; align-items: center; justify-content: flex-end; gap: 10px; min-height: 20px; min-width: 0; }
.poll .countdown { font-size: 13px; color: var(--text-dim); display: flex; align-items: center; gap: 7px; }
.poll .uptime { font-family: var(--mono); font-size: 12px; color: var(--text-faint); border-left: 1px solid var(--border); padding-left: 10px; white-space: nowrap; }
.poll .countdown .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--warn); animation: blink 1.3s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) { .poll .countdown .dot { animation: none; } }
.poll .countdown.stopped { color: var(--text-faint); }
.poll .countdown.stopped .dot { background: var(--idle); animation: none; }

.action-grid { display: flex; align-items: center; gap: 8px; }
.action-grid .btn { min-width: 152px; min-height: 38px; justify-content: center; font-size: 13px; font-weight: 700; white-space: nowrap; text-align: center; line-height: 1.2; }
.search { display: flex; align-items: center; gap: 10px; background: rgba(16,16,18,.8); border: 1px solid var(--border); border-radius: 4px; padding: 8px 11px; }
.top-search { grid-area: search; width: min(100%, 400px); justify-self: center; }
.search svg { opacity: .55; flex-shrink: 0; }
.search input { background: none; border: none; outline: none; color: var(--text); font-size: 13px; width: 100%; }
.search input::placeholder { color: var(--text-faint); }

.tablewrap { margin-top: 14px; border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--surface); overflow: hidden; display: flex; flex-direction: column; min-height: 0; flex: 1 1 auto; }
.tablescroll { overflow: auto; min-height: 0; flex: 1 1 auto; }
.cardswrap { margin-top: 14px; overflow-y: auto; overflow-x: hidden; min-height: 0; flex: 1 1 auto; padding: 0 2px 0 0; }
.modal-body .tablewrap { flex: 0 1 auto; min-height: 0; }

/* The table has a content-driven min-width and won't reflow below it on narrow
   screens - the global thin/dim scrollbar was easy to miss there, making the
   overflow look like clipped content rather than something scrollable. Give the
   table's own horizontal scrollbar a thicker, higher-contrast, always-visible
   groove so it reads as an obvious affordance instead of blending in. */
.tablescroll, .cardswrap { scrollbar-width: auto; scrollbar-color: var(--accent) var(--surface-2); }
.tablescroll::-webkit-scrollbar, .cardswrap::-webkit-scrollbar { width: 14px; height: 14px; }
.tablescroll::-webkit-scrollbar-track, .cardswrap::-webkit-scrollbar-track { background: var(--surface-2); }
.tablescroll::-webkit-scrollbar-thumb, .cardswrap::-webkit-scrollbar-thumb { background: var(--accent); border: 3px solid var(--surface-2); border-radius: 999px; background-clip: padding-box; }
.tablescroll::-webkit-scrollbar-thumb:hover, .cardswrap::-webkit-scrollbar-thumb:hover { background: #3A6BC0; }
table.ptable { width: 100%; min-width: 1180px; border-collapse: collapse; font-size: 13.5px; }
.ptable thead th {
  position: sticky; top: 0; z-index: 12;
  text-align: left; font-size: 12px; font-weight: 600; color: var(--text-dim);
  padding: 13px 16px; border-bottom: 1px solid var(--border); background: var(--surface-2);
  white-space: nowrap; cursor: pointer; user-select: none;
}
.ptable thead th.nosort { cursor: default; }
.ptable th.col-shrink { width: 1%; }
.ptable thead th .arrow { color: var(--accent); margin-left: 3px; }
.ptable tbody tr.row { border-bottom: 1px solid var(--border-soft); cursor: pointer; }
.ptable tbody tr.row:last-child { border-bottom: none; }
.ptable tbody tr.row:hover { background: var(--surface-2); }
.ptable tbody tr.row.is-pending { opacity: .45; cursor: default; }
.ptable tbody tr.row.is-disabled { opacity: .55; }
.ptable tbody tr.row.is-down { background: rgba(248,81,73,.08); box-shadow: inset 3px 0 0 rgba(248,81,73,.75); }
.ptable tbody tr.row.is-down:hover { background: rgba(248,81,73,.12); }
.ptable tbody tr.row.is-critical { background: rgba(210,153,34,.08); box-shadow: inset 3px 0 0 rgba(210,153,34,.75); }
.ptable tbody tr.row.is-critical:hover { background: rgba(210,153,34,.12); }
.ptable td { padding: 13px 16px; vertical-align: middle; }
table.ptable td:first-child, table.ptable th:first-child { padding-right: 6px; }
table.ptable td:nth-child(2), table.ptable th:nth-child(2) { padding-left: 6px; }

/* Compact row density - the Gmail-style display option, on by default.
   Deliberately reuses table-layout:auto (Comfortable's own layout mode)
   rather than table-layout:fixed - fixed layout requires every column to
   carry a hardcoded width, which either truncates real content or drifts
   out of proportion as the window resizes (both tried and rejected). Auto
   layout does the right thing for free: every .col-shrink column (checkbox,
   #, Ver, Status, Run, Err, Total, Provider, Actions, SSH, Enabled) shrinks to
   its own natural content width via the existing `width:1%` shrink-to-fit
   rule, Name/Server URL take only what's left, and nothing is ever
   truncated. Compact's own job is just: tighter padding/font/control sizes,
   and no forced 1180px floor (width:auto instead of 100%) so the table
   hugs its actual content instead of stretching to fill empty space. */
.ptable.compact { min-width: 0; width: auto; font-size: 12.5px; }
.ptable.compact thead th { padding: 7px 10px; white-space: nowrap; }
.ptable.compact td { padding: 5px 10px; white-space: nowrap; }
.ptable.compact th.col-shrink, .ptable.compact td.col-shrink { padding-left: 6px; padding-right: 6px; }
.ptable.compact .pill { padding: 3px 9px; font-size: 11.5px; }
.ptable.compact .ver { padding: 2px 5px; font-size: 10.5px; }
.ptable.compact .icon-btn { width: 24px; height: 24px; }
/* Smaller toggle track/knob to match the tighter Enabled column. */
.ptable.compact .toggle { width: 24px; height: 14px; border-radius: 7px; }
.ptable.compact .toggle::after { width: 10px; height: 10px; top: 1.5px; left: 1.5px; }
.ptable.compact .toggle.on::after { transform: translateX(10px); }
.chev-cell { color: var(--text-faint); display: inline-block; flex-shrink: 0; }

.idx { color: var(--text-faint); font-family: var(--mono); font-size: 12.5px; }
input[type="checkbox"] {
  appearance: none; -webkit-appearance: none;
  width: 16px; height: 16px; border-radius: 5px;
  border: 1.5px solid var(--border); background: var(--surface-2);
  cursor: pointer; flex-shrink: 0; position: relative;
}
input[type="checkbox"]:hover { border-color: var(--text-faint); }
input[type="checkbox"]:checked { background: var(--accent); border-color: var(--accent); }
input[type="checkbox"]:checked::after {
  content: ""; position: absolute; left: 4.5px; top: 1.5px; width: 4px; height: 8px;
  border: solid #fff; border-width: 0 1.6px 1.6px 0; transform: rotate(45deg);
}

.name-wrap { display: flex; align-items: center; gap: 8px; }
.name { font-weight: 600; white-space: nowrap; }
.host { font-family: var(--mono); font-size: 12.5px; color: var(--text-dim); white-space: nowrap; }
.pid { font-family: var(--mono); font-size: 12.5px; color: var(--text-dim); }
.ver { font-family: var(--mono); font-size: 12px; color: var(--text-dim); background: var(--surface-3); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 3px 8px; }
.ver.v3 { color: #C4B5FD; background: #241B3D; border-color: #3D2E63; }
.ver.v4 { color: #67E8F9; background: #0D2E33; border-color: #155E63; }
.ver.v5 { color: #FDBA74; background: #3A2410; border-color: #7C4A16; }

.pill { font-size: 12.5px; font-weight: 600; padding: 5px 11px; border-radius: 999px; border: 1px solid; display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.pill .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex-shrink: 0; }
.pill.ok { color: var(--ok); border-color: var(--ok-dim); background: var(--ok-dim); }
.pill.bad { color: var(--bad); border-color: var(--bad-dim); background: var(--bad-dim); }
.pill.warn { color: var(--warn); border-color: var(--warn-dim); background: var(--warn-dim); }
.pill.warn .dot { animation: blink 1.3s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) { .pill.warn .dot { animation: none; } }
@keyframes blink { 0%,100% { opacity: 1; } 50% { opacity: .3; } }
.pill.idle { color: var(--idle); border-color: var(--border); background: var(--idle-dim); }

.num { font-family: var(--mono); font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; font-size: 13.5px; }
/* Sky blue, not var(--ok) green - the Run count sits right next to the
   Healthy status pill (also green), and two identical greens side by side
   just blurred together instead of reading as two distinct pieces of info. */
.num.ok { color: #38BDF8; }
.num.bad { color: var(--bad); }
.num.mute { color: var(--text-dim); }

.toggle { position: relative; width: 30px; height: 17px; border-radius: 9px; background: var(--surface-3); border: 1px solid var(--border); display: inline-block; cursor: pointer; flex-shrink: 0; }
.toggle::after { content: ""; position: absolute; top: 1.5px; left: 1.5px; width: 12px; height: 12px; border-radius: 50%; background: var(--text-faint); transition: transform .15s ease, background .15s ease; }
.toggle.on { background: #4A4D52; border-color: #5B5F66; }
.toggle.on::after { transform: translateX(13px); background: #fff; }
.ssh-status-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--text-faint); box-shadow: 0 0 0 2px var(--surface-3); vertical-align: middle; }
.ssh-status-dot.on { background: #22D3EE; box-shadow: 0 0 0 2px rgba(34,211,238,.15), 0 0 7px rgba(34,211,238,.5); }
.ssh-status-dot.working { background: var(--warn); box-shadow: 0 0 0 2px rgba(251,191,36,.14), 0 0 7px rgba(251,191,36,.5); }
.ssh-status-dot.recovered { background: var(--ok); box-shadow: 0 0 0 2px rgba(52,211,153,.14), 0 0 7px rgba(52,211,153,.45); }
.ssh-status-dot.failed { background: var(--bad); box-shadow: 0 0 0 2px rgba(229,72,77,.15), 0 0 7px rgba(229,72,77,.5); }
.ssh-status-dot.cooldown { background: #A78BFA; box-shadow: 0 0 0 2px rgba(167,139,250,.15), 0 0 7px rgba(167,139,250,.45); }

.acts { display: flex; align-items: center; gap: 6px; white-space: nowrap; position: relative; }
.icon-btn { width: 30px; height: 30px; border-radius: var(--radius-sm); border: 1px solid transparent; background: none; color: var(--text-dim); display: inline-grid; place-items: center; cursor: pointer; flex-shrink: 0; }
.icon-btn:hover { background: var(--surface-3); color: var(--text); }
.icon-btn[disabled] { opacity: .3; cursor: default; pointer-events: none; }
.icon-btn.act-start { color: var(--ok); }
.icon-btn.act-start:hover { background: var(--ok-dim); }
.icon-btn.act-stop { color: var(--warn); }
.icon-btn.act-stop:hover { background: var(--warn-dim); }
.icon-btn.act-edit { color: #60A5FA; }
.icon-btn.act-edit:hover { background: #132A4D; }
.icon-btn.act-dup { color: #2DD4BF; }
.icon-btn.act-dup:hover { background: #0F2E2A; }
.icon-btn.act-logs { color: #C4B5FD; }
.icon-btn.act-logs:hover { background: #241B3D; }
.icon-btn.act-recover { color: #FBBF24; }
.icon-btn.act-recover:hover { background: var(--warn-dim); }
.icon-btn.act-delete { color: var(--bad); }
.icon-btn.act-delete:hover { background: var(--bad-dim); }

.save-indicator { display: inline-block; max-width: 520px; font-size: 11.5px; color: var(--ok); opacity: 0; transition: opacity .2s ease; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; pointer-events: none; }
.save-indicator.show { opacity: 1; }

.toast-wrap { position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%); z-index: 40; display: flex; flex-direction: column-reverse; gap: 8px; pointer-events: none; align-items: center; }
.toast { pointer-events: auto; background: var(--surface-3); border: 1px solid var(--border); border-radius: var(--radius-md); padding: 11px 14px; display: flex; align-items: center; gap: 14px; font-size: 13px; color: var(--text); box-shadow: 0 10px 30px rgba(0,0,0,.45); opacity: 0; transform: translateY(8px); transition: opacity .15s ease, transform .15s ease; white-space: nowrap; }
.toast.show { opacity: 1; transform: translateY(0); }
.toast .toast-action { color: #9DB6E0; background: none; border: none; font-weight: 600; font-size: 13px; cursor: pointer; white-space: nowrap; padding: 0; }
.toast .toast-action:hover { text-decoration: underline; }

/* ---- Provider right-click / long-press context menu ---- */
.ctx-menu-backdrop { position: fixed; inset: 0; z-index: 29; }
.ctx-menu { position: fixed; z-index: 30; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-md); box-shadow: 0 10px 30px rgba(0,0,0,.45); padding: 5px; min-width: 190px; display: flex; flex-direction: column; }
.ctx-menu button { background: none; border: none; color: var(--text); text-align: left; padding: 9px 12px; border-radius: var(--radius-sm); cursor: pointer; font-size: 13px; }
.ctx-menu button:hover { background: var(--surface-3); }

/* ---- Streams modal table ---- */
/* Always compact - there's no density toggle here, unlike the providers table.
   width:auto (not 100%) so the table hugs its actual content instead of
   stretching the Channel column to fill the modal's leftover space, which is
   exactly what made it look "too wide" - Clients/Status/Uptime/Bandwidth
   already shrink-to-fit via width:1%, so Channel was absorbing 100% minus
   those, regardless of how short the real channel names actually are. */
.sv-title p.sv-host { font-family: var(--mono); }
table.stable { width: auto; min-width: 0; border-collapse: collapse; font-size: 12.5px; }
.stable thead th {
  text-align: left; font-size: 11.5px; font-weight: 600; color: var(--text-dim);
  padding: 8px 12px; border-bottom: 1px solid var(--border); background: var(--surface-2);
  white-space: nowrap;
}
.stable tbody tr { border-bottom: 1px solid var(--border-soft); }
.stable tbody tr:last-child { border-bottom: none; }
.stable tbody tr:hover { background: var(--surface-2); }
.stable td { padding: 5px 12px; vertical-align: middle; white-space: nowrap; }
.channel-cell { font-weight: 600; }

/* ---- Modals ---- */
.scrim { position: fixed; inset: 0; background: rgba(4,4,5,.6); opacity: 0; pointer-events: none; transition: opacity .15s ease; z-index: 200; display: flex; align-items: center; justify-content: center; padding: 40px 20px; overflow-y: auto; }
.scrim#modal-streams { align-items: flex-start; }
.provider-scrim { align-items: flex-start; }
.provider-scrim.provider-scrim-compact { align-items: center; }
.scrim.open { opacity: 1; pointer-events: auto; }
/* dvh (dynamic viewport height) is the load-bearing one on real phones: vh on
   mobile Safari/Chrome is based on the viewport with the address bar hidden,
   so calc(100vh - 80px) computes taller than what's actually visible when the
   bar is showing - the modal LOOKS like it overflows and the page itself has
   to be dragged to see the rest, even though the internal .tablescroll
   scrollbar was working the whole time. dvh tracks the real visible area.
   Declared second (not replacing the vh line) so browsers without dvh
   support just keep using the vh value instead of breaking. */
.modal { position: relative; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); width: 100%; max-width: 460px; max-height: calc(100vh - 80px); max-height: calc(100dvh - 80px); display: flex; flex-direction: column; transform: translateY(8px); transition: transform .15s ease; box-shadow: 0 20px 60px rgba(0,0,0,.5); }
.modal.modal-provider { max-width: min(580px, 96vw); max-height: calc(100vh - 16px); max-height: calc(100dvh - 16px); margin: 8px 0; overflow: hidden; }
.modal.save-copy-modal { max-width: 410px; }
.modal.logs-modal { max-width: min(680px, 96vw); }
/* width:fit-content (not a fixed 900px) so the modal hugs whatever the table
   actually needs by default - short channel names no longer force a wide box
   with a stretched-looking Channel column. min/max keep it from ever getting
   unusably narrow or wider than the viewport before the user resizes it by
   hand. Once JS sets an explicit inline width (see .modal-resize-handle),
   that inline style naturally wins over this rule for the rest of the drag. */
.modal.modal-wide { width: fit-content; min-width: min(480px, 92vw); max-width: min(900px, 95vw); }
.modal-resize-handle { position: absolute; top: 0; bottom: 0; width: 10px; cursor: ew-resize; z-index: 5; touch-action: none; }
.modal-resize-handle.left { left: -5px; }
.modal-resize-handle.right { right: -5px; }
.modal-resize-handle:hover, .modal-resize-handle.dragging { background: var(--accent-dim); }
.scrim.open .modal { transform: translateY(0); }
.modal-head { display: flex; justify-content: space-between; align-items: flex-start; padding: 16px 18px; border-bottom: 1px solid var(--border-soft); flex-shrink: 0; }
.modal-head h3 { font-size: 15px; margin: 0; }
.modal-head p { font-size: 12.5px; color: var(--text-dim); margin: 3px 0 0; }
.modal-head p.danger-copy { color: #FFB4B4; }
.modal-close { background: none; border: 1px solid var(--border); border-radius: 6px; width: 26px; height: 26px; color: var(--text-dim); cursor: pointer; }
.modal-body { padding: 16px 18px; overflow-y: auto; display: flex; flex-direction: column; gap: 12px; flex: 1 1 auto; min-height: 0; }
.delete-targets { display: flex; flex-wrap: wrap; gap: 6px; }
.delete-targets span { border: 1px solid rgba(248,81,73,.24); border-radius: var(--radius-sm); background: rgba(248,81,73,.08); color: var(--text-dim); padding: 4px 7px; font-family: var(--mono); font-size: 11.5px; }
.modal-provider .modal-head { padding: 8px 12px; }
.modal-provider .modal-head h3 { font-size: 13.5px; }
.modal-provider .modal-head p { display: none; }
.modal-provider .modal-body { padding: 9px 12px; gap: 6px; overflow-y: auto; }
.modal-provider .modal-foot { padding: 8px 12px; }
.modal-foot { padding: 14px 18px; border-top: 1px solid var(--border-soft); display: flex; justify-content: flex-end; gap: 8px; flex-shrink: 0; }

.field label { display: block; font-size: 12px; color: var(--text-dim); margin-bottom: 6px; font-weight: 500; }
.field input, .field select, .field textarea { width: 100%; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 9px 11px; color: var(--text); font-size: 13.5px; }
.modal-provider .field label { font-size: 11px; margin-bottom: 3px; }
.modal-provider .field input, .modal-provider .field select, .modal-provider .field textarea { padding: 6px 9px; font-size: 12.5px; }
.field textarea { resize: vertical; min-height: 72px; font-family: var(--mono); line-height: 1.4; }
.modal-provider .field textarea { line-height: 1.25; min-height: 48px; }
.modal-provider .command-box-start { height: 50px; }
.modal-provider .command-box-provider { height: 68px; }
.field input:focus, .field select:focus, .field textarea:focus { border-color: var(--accent); outline: none; }
.field input:disabled { opacity: .4; cursor: not-allowed; }
.password-input { position: relative; }
.password-input input { padding-right: 34px; }
.password-input button { position: absolute; right: 4px; top: 50%; transform: translateY(-50%); width: 26px; height: 26px; padding: 0; display: grid; place-items: center; border: 0; background: transparent; color: var(--text-faint); cursor: pointer; border-radius: 5px; }
.password-input button:hover { color: var(--text); background: var(--surface-3); }
.password-input button:disabled { opacity: .3; cursor: default; background: transparent; }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.modal-provider .field-row { gap: 7px; }
.provider-main-row { grid-template-columns: minmax(170px, .85fr) minmax(230px, 1.15fr); }
.ver-pick { display: flex; gap: 6px; }
.ver-pick button { flex: 1; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 8px; color: var(--text-dim); font-family: var(--mono); font-size: 13px; cursor: pointer; }
.modal-provider .ver-pick button { padding: 6px 7px; font-size: 12px; }
.ver-pick button[aria-pressed="true"] { background: var(--accent-dim); border-color: var(--accent); color: #9DB6E0; }
.check-row { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--text-dim); }
.ssh-group { border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--surface-2); overflow: hidden; }
.ssh-group-head { min-height: 38px; padding: 8px 11px; display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.modal-provider .ssh-group-head { min-height: 30px; padding: 5px 8px; }
.ssh-group-head > span { color: var(--text); font-size: 12.5px; font-weight: 600; }
.ssh-group-head .check-row { cursor: pointer; user-select: none; }
.ssh-head-actions { display: flex; align-items: center; gap: 8px; }
.ssh-fields { border-top: 1px solid var(--border-soft); padding: 10px; display: flex; flex-direction: column; gap: 9px; }
.modal-provider .ssh-fields { padding: 7px 8px 8px; gap: 6px; }
.ssh-fields .field label { margin-bottom: 4px; }
.ssh-test-result { border: 1px solid var(--border-soft); border-radius: var(--radius-sm); padding: 6px 8px; font-size: 12px; }
.ssh-test-result.ok { color: var(--ok); background: var(--ok-dim); }
.ssh-test-result.bad { color: var(--bad); background: var(--bad-dim); }
.ssh-host-row { grid-template-columns: minmax(0, 1fr) 94px; }
.log-list { display: flex; flex-direction: column; gap: 6px; font-family: var(--mono); font-size: 12.5px; }
.log-line { display: grid; grid-template-columns: 66px 86px minmax(0, 1fr); gap: 8px; align-items: start; border: 1px solid var(--border-soft); border-radius: var(--radius-sm); background: var(--surface-2); padding: 8px 10px; }
.log-time { color: var(--text-faint); }
.log-kind { color: var(--accent); white-space: nowrap; }
.log-message { color: var(--text); overflow-wrap: anywhere; }
.log-empty { color: var(--text-faint); font-size: 13px; padding: 8px 0; }

/* Card view keeps every provider visible in a compact grid while reusing the
   same click and context-menu behavior as the table rows. */
.provider-cards { display: none; }
.provider-cards.desktop-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(235px, 1fr)); gap: 8px; align-content: start; }
.provider-card {
  position: relative; min-width: 0; min-height: 168px; cursor: pointer;
  display: grid; grid-template-rows: auto auto auto auto auto; gap: 7px;
  padding: 10px 11px 9px; border: 1px solid var(--border); border-radius: 4px;
  background:
    radial-gradient(circle at 88% 8%, rgba(255,255,255,.035), transparent 34%),
    linear-gradient(135deg, rgba(20,20,22,.98), rgba(12,15,15,.98));
  box-shadow: inset 0 1px 0 rgba(255,255,255,.03), 0 10px 28px rgba(0,0,0,.18);
}
.provider-card.is-down { background: linear-gradient(135deg, rgba(50,18,20,.96), rgba(18,12,13,.98)); border-color: rgba(248,81,73,.45); box-shadow: inset 3px 0 0 rgba(248,81,73,.75); }
.provider-card.is-critical { background: linear-gradient(135deg, rgba(46,35,14,.96), rgba(16,15,12,.98)); border-color: rgba(210,153,34,.45); box-shadow: inset 3px 0 0 rgba(210,153,34,.75); }
.provider-card.is-healthy { border-color: rgba(22,126,86,.34); box-shadow: inset 3px 0 0 rgba(22,126,86,.72), 0 0 16px rgba(22,126,86,.07); }
.provider-card.is-disabled { opacity: .55; }
.provider-card:hover { border-color: rgba(255,255,255,.18); background-color: var(--surface-2); }
.pc-top { display: grid; grid-template-columns: auto auto minmax(0, 1fr) auto; align-items: center; gap: 8px; min-width: 0; }
.pc-select { display: flex; align-items: center; }
.pc-name-text { color: #D4D7DC; font-size: 14.5px; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pc-idx { color: #5F636B; font-family: var(--mono); font-size: 13px; font-weight: 500; opacity: .9; }
.pc-status-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.pc-status { display: inline-flex; align-items: center; gap: 6px; color: #7C7C82; font-size: 12px; }
.pc-status .dot { width: 8px; height: 8px; border-radius: 999px; background: currentColor; box-shadow: 0 0 5px color-mix(in srgb, currentColor 55%, transparent); }
.pc-status.ok { color: #1B8E60; }
.pc-status.bad { color: #B43A40; }
.pc-status.warn { color: #BD8518; }
.pc-status.idle, .pc-status.mute { color: #77777D; }
.provider-card .toggle { width: 22px; height: 13px; border-radius: 999px; }
.provider-card .toggle::after { width: 9px; height: 9px; top: 1px; left: 1px; }
.provider-card .toggle.on::after { transform: translateX(9px); }
.provider-card .ver { padding: 0; background: transparent; border: 0; border-radius: 0; font-size: 12px; font-weight: 700; }
.provider-card .ver.v3 { color: #9B7DD8; background: transparent; border-color: transparent; }
.provider-card .ver.v4 { color: #36A7B8; background: transparent; border-color: transparent; }
.provider-card .ver.v5 { color: #FDBA74; background: transparent; border-color: transparent; }
.pc-details { display: grid; grid-template-columns: minmax(0, 1fr); gap: 5px; align-items: center; min-width: 0; padding-bottom: 7px; border-bottom: 1px solid var(--border-soft); }
.pc-provider, .pc-url { font-family: var(--mono); font-size: 11.5px; color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pc-stat-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 7px; }
.pc-stats { display: grid; grid-template-columns: repeat(3, auto); align-items: center; gap: 0; overflow: hidden; color: var(--text-dim); font-size: 11.5px; white-space: nowrap; }
.pc-stats span { padding: 0 9px; border-right: 1px solid var(--border-soft); }
.pc-stats span:first-child { padding-left: 0; }
.pc-stats span:last-child { border-right: 0; }
.pc-stats b { font-family: var(--mono); font-weight: 700; margin-left: 6px; }
.pc-stats b.ok { color: #279763; }
.pc-stats b.bad { color: #B33A3F; }
.pc-stats b.mute { color: #B9782D; }
.pc-ssh { display: inline-flex; align-items: center; gap: 5px; padding: 5px 7px; border: 1px solid rgba(255,255,255,.06); border-radius: 4px; color: #8B8B91; background: rgba(18,18,20,.76); font-size: 11.5px; }
.pc-ssh .ssh-status-dot { width: 7px; height: 7px; box-shadow: none; opacity: .8; }
.pc-acts { align-self: end; display: grid; grid-template-columns: repeat(5, 1fr); gap: 5px; min-width: 0; }
.pc-action { min-width: 0; min-height: 31px; justify-content: center; padding: 0; border-radius: 4px; font-size: 13px; font-weight: 700; color: #D7D7DA; background: rgba(15,15,17,.72); border-color: rgba(255,255,255,.08); overflow: hidden; text-overflow: ellipsis; }
.pc-action:hover { background: rgba(28,28,31,.86); border-color: rgba(255,255,255,.14); }
.pc-action.act-start { color: #5EA978; background: rgba(15,15,17,.72); border-color: rgba(30,128,88,.22); }
.pc-action.act-start:hover { background: rgba(17,28,22,.9); border-color: rgba(30,128,88,.36); }
.pc-action.act-stop { color: #B85A5F; background: rgba(15,15,17,.72); border-color: rgba(150,50,55,.2); }
.pc-action.act-stop:hover { background: rgba(30,18,20,.9); border-color: rgba(150,50,55,.34); }
.pc-action.act-delete { color: #B85A5F; border-color: rgba(229,72,77,.14); }
.pc-action.act-delete:hover { background: rgba(36,20,22,.86); border-color: rgba(229,72,77,.28); }
.pc-more { font-weight: 800; letter-spacing: .08em; }
.pc-hidden-actions { display: none; }
.empty-cards { grid-column: 1 / -1; text-align: center; color: var(--text-faint); padding: 24px; }

.app-footer {
  flex: 0 0 auto;
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(160px, auto) minmax(0, 1fr);
  align-items: center; gap: 12px;
  padding: 7px 4px 0; color: var(--text-faint); font-family: var(--mono); font-size: 11.5px;
}
.footer-version { display: flex; align-items: center; justify-content: flex-start; gap: 10px; min-width: 0; }
.footer-version span + span::before { content: "•"; margin-right: 10px; color: var(--border); }
.app-footer .save-indicator { justify-self: center; text-align: center; }
.footer-status { justify-self: end; }
.back-top {
  position: fixed; left: 50%; bottom: 48px; transform: translate(-50%, 12px); z-index: 80;
  height: 28px; min-width: 34px; padding: 0 11px; border-radius: 999px; border: 1px solid rgba(88,166,255,.35);
  background: rgba(28,28,31,.68); color: var(--text); font-size: 15px; font-weight: 800;
  cursor: pointer; box-shadow: 0 10px 26px rgba(0,0,0,.26); backdrop-filter: blur(8px);
  opacity: 0; pointer-events: none; transition: opacity .16s ease, transform .16s ease;
}
.back-top.show { opacity: 1; pointer-events: auto; transform: translate(-50%, 0); }
.back-top:hover { background: rgba(36,36,40,.86); }

@media (max-width: 1500px) {
  .stage { padding-inline: 12px; }
  .pagehead {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "title filters"
      "search filters";
    gap: 8px 12px;
  }
  .pagehead .left { justify-content: flex-start; }
  .top-search { width: min(100%, 460px); justify-self: center; }
  .right-controls { justify-content: flex-end; align-self: center; }
  .control-panel { grid-template-columns: 1fr; gap: 8px; }
  .control-main { display: grid; grid-template-columns: minmax(0, auto) minmax(0, 1fr); align-items: center; row-gap: 8px; }
  .file { grid-template-columns: minmax(170px, 220px) auto; }
  .control-row { justify-content: flex-start; }
  .control-side { justify-content: flex-start; }
  .action-grid .btn { min-width: 150px; }
  .cardswrap, .tablewrap { margin-top: 12px; }
}

@media (max-width: 900px) {
  .sticky-controls { margin-bottom: 8px; }
  .pagehead {
    grid-template-columns: 1fr;
    grid-template-areas:
      "title"
      "search"
      "filters";
  }
  .pagehead .left { flex-direction: column; align-items: flex-start; gap: 8px; }
  .status-chips { width: 100%; }
  .top-search { width: 100%; }
  .right-controls { display: grid; grid-template-columns: repeat(3, minmax(0, auto)); justify-content: start; gap: 7px; }
  .statusfilter { min-width: 180px; }
  .seg { min-width: 0; }
  .seg button { padding-inline: 10px; }
  .control-main { grid-template-columns: 1fr; }
  .file { grid-template-columns: minmax(0, 220px) auto; }
  .control-side { justify-content: stretch; }
  .action-grid { width: 100%; }
  .action-grid .btn { flex: 1 1 0; min-width: 0; }
  .app-footer { grid-template-columns: 1fr; gap: 4px; text-align: left; }
  .app-footer .save-indicator { justify-self: start; }
  .footer-status { justify-self: start; }
}

@media (max-width: 640px) {
  .stage { height: auto; overflow: visible; padding: 10px 10px 48px; display: block; }
  .sticky-controls { position: static; padding-top: 0; margin: 0 0 10px; }
  .pagehead { align-items: stretch; }
  .page-title { font-size: 22px; }
  .status-chips { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); width: 100%; overflow: visible; }
  .chip { justify-content: center; min-height: 34px; padding-inline: 8px; font-size: 12px; }
  .right-controls { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .statusfilter { grid-column: 1 / -1; width: 100%; min-width: 0; }
  .version-seg, .view-seg { width: 100%; }
  .right-controls > .btn { justify-content: center; }
  .control-panel { grid-template-columns: 1fr; }
  .control-side { border-left: none; border-top: 0; }
  .file { grid-template-columns: 1fr; }
  .fileacts { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .fileacts .file-action-btn { justify-content: center; padding-inline: 8px; }
  .control-row { gap: 10px; }
  .alert-settings { display: grid; grid-template-columns: repeat(2, minmax(0, auto)); gap: 9px 14px; }
  .startup-setting { grid-column: 1 / -1; }
  .action-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .field-row { grid-template-columns: 1fr; }
  .provider-cards.desktop-cards { grid-template-columns: 1fr; }
  /* Less reserved margin on a small screen - every pixel counts, and the
     scrim's own 40px top/bottom padding was eating into the same space the
     modal needed for its channel list. */
  .scrim { padding: 16px 12px; }
  .modal { max-height: calc(100vh - 32px); max-height: calc(100dvh - 32px); }
}

@media (max-width: 430px) {
  .status-chips { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .right-controls { grid-template-columns: 1fr; }
}

/* ---- Blazor framework boilerplate (not part of the design system) ---- */
#blazor-error-ui {
  display: none;
  position: fixed; bottom: 0; left: 0; right: 0; z-index: 1000;
  background: var(--bad-dim); color: var(--text); border-top: 1px solid var(--bad);
  padding: 10px 16px; box-shadow: 0 -4px 16px rgba(0,0,0,.4);
}
#blazor-error-ui .reload { color: #9DB6E0; text-decoration: underline; margin-left: 8px; }
#blazor-error-ui .dismiss { cursor: pointer; float: right; opacity: .7; }
.loading-progress, .loading-progress-text { display: none; }
