/* style.css - CD Endpoint Monitor
   Design language leans on controld.com's own interface. */

:root {
  --cd-brand: #635bff;
  --cd-brand-hover: #4f46e5;
  --cd-bg: #0b0e14;
  --cd-surface: #161b26;
  --cd-border: #262e3d;
  --cd-text-main: #f8fafc;
  --cd-text-muted: #94a3b8;
  --cd-status-active: #10b981;
  --cd-status-inactive: #f59e0b;
  --cd-status-offline: #ef4444;
  --cd-status-paused: #64748b;
  --cd-status-never-seen: #38bdf8;

  /* Table/grid background - deliberately a shade lighter than --cd-surface
     in dark mode so tables don't disappear into the surrounding card. */
  --cd-table-bg: #1e293b;

  /* Divider between settings rows - needs to be lighter than --cd-border
     in dark mode, since --cd-border all but disappears against the
     lighter --cd-table-bg the settings cards now use. */
  --cd-divider: #334155;

  --cd-radius: 10px;
  --cd-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
}

/* Light theme values (applied via [data-theme="light"] or prefers-color-scheme) */
:root[data-theme="light"],
:root:not([data-theme="dark"]) {
  --cd-bg: #f4f5f8;
  --cd-surface: #ffffff;
  --cd-border: #e2e5eb;
  --cd-text-main: #10131a;
  --cd-text-muted: #5c6472;
  --cd-shadow: 0 2px 10px rgba(20, 20, 40, 0.06);
  --cd-table-bg: #ffffff;
  --cd-divider: #e2e5eb;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --cd-bg: #0b0e14;
    --cd-surface: #161b26;
    --cd-border: #262e3d;
    --cd-text-main: #f8fafc;
    --cd-text-muted: #94a3b8;
    --cd-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
    --cd-table-bg: #1e293b;
    --cd-divider: #334155;
  }
}

:root[data-theme="dark"] {
  --cd-bg: #0b0e14;
  --cd-surface: #161b26;
  --cd-border: #262e3d;
  --cd-text-main: #f8fafc;
  --cd-text-muted: #94a3b8;
  --cd-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
  --cd-table-bg: #1e293b;
  --cd-divider: #334155;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--cd-bg);
  color: var(--cd-text-main);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  transition: background 0.15s ease, color 0.15s ease;
}

a { color: var(--cd-brand); text-decoration: none; }
a:hover { color: var(--cd-brand-hover); }

.container {
  max-width: 1100px;
  margin: 0 auto;
  padding: 24px 20px 64px;
}

/* ---------- Top bar ---------- */
.topbar {
  display: flex;
  align-items: center;
  gap: 24px;
  padding: 14px 20px;
  border-bottom: 1px solid var(--cd-border);
  background: var(--cd-table-bg);
}

.topbar .brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 600;
  font-size: 24px; /* 50% larger than the original 16px */
  flex-shrink: 0;
}

.topbar .brand .dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--cd-brand);
}

.topbar nav {
  display: flex;
  align-items: center;
  gap: 18px;
  margin-left: auto;
}

/* When a .topbar-refresh block is present right before nav (dashboard
   topbar), THAT block carries the push-right margin instead, so it and
   nav end up grouped together at the right edge with no extra gap
   between them. Pages without the refresh block (e.g. settings.php)
   fall back to nav's own auto margin above, keeping their links
   right-aligned too. */
.topbar-refresh + nav {
  margin-left: 0;
}

.topbar nav a, .topbar nav button {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--cd-text-muted);
  background: none;
  border: none;
  font-size: 14px;
  cursor: pointer;
  padding: 6px 8px;
  border-radius: 6px;
  white-space: nowrap;
}

.topbar nav a:hover, .topbar nav button:hover {
  color: var(--cd-text-main);
  background: var(--cd-border);
}

/* Push toggle button states (assets/js/push.js sets data-push-state). */
.topbar nav button#push-toggle-btn[data-push-state="subscribed"] {
  color: var(--cd-status-active);
}
.topbar nav button#push-toggle-btn:disabled {
  cursor: default;
  opacity: 0.55;
}
.topbar nav button#push-toggle-btn:disabled:hover {
  background: none;
}

/* Language switcher: a small custom dropdown (not a native <select>,
   since <option> elements can't render inline SVG flags) - a button
   showing the current language's flag + code, toggling a small menu of
   every language actually found in /lang. Positioned last in nav, so it
   sits furthest right in the topbar. */
.lang-switcher {
  position: relative;
}

.lang-switcher-btn-inner,
#lang-switcher-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.lang-switcher-menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  background: var(--cd-surface);
  border: 1px solid var(--cd-border);
  border-radius: 8px;
  box-shadow: var(--cd-shadow);
  padding: 4px;
  min-width: 140px;
  z-index: 20;
}

.lang-switcher-option {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  text-align: left;
  padding: 8px 10px;
  border-radius: 6px;
  background: none;
  border: none;
  color: var(--cd-text-main);
  font-size: 14px;
  cursor: pointer;
  white-space: nowrap;
}

.lang-switcher-option:hover {
  background: var(--cd-border);
}

.lang-switcher-option[aria-current="true"] {
  color: var(--cd-brand);
  font-weight: 600;
  cursor: default;
}

.flag-icon {
  flex-shrink: 0;
  border-radius: 2px;
  display: block;
}

/* Refresh status block: text line, progress bar, text line - stacked
   vertically with the bar BETWEEN the two lines (not below both),
   thicker and fully rounded, matching the reference design. Sized to
   fit its own text content (not an arbitrary fixed width) so the bar's
   width always matches the text above/below it, and pushed to the right
   of the topbar via the auto left-margin (nav follows right after it). */
.topbar-refresh {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
  font-size: 11px;
  color: var(--cd-text-muted);
  width: max-content;
  max-width: 320px;
  margin-left: auto;
  text-align: left;
  white-space: nowrap;
}

.topbar-refresh-bar {
  width: 100%;
  height: 6px;
  background: var(--cd-border);
  border-radius: 999px;
  overflow: hidden;
}

.topbar-refresh-bar-fill {
  height: 100%;
  background: var(--cd-brand);
  width: 100%;
  border-radius: 999px;
  transition: width 1s linear;
}

/* ---------- Cards ---------- */
.card {
  background: var(--cd-surface);
  border: 1px solid var(--cd-border);
  border-radius: var(--cd-radius);
  box-shadow: var(--cd-shadow);
  padding: 20px;
  margin-bottom: 20px;
}

.card h2 {
  margin-top: 0;
  font-size: 16px;
  font-weight: 600;
}

/* Settings page cards use the same lighter tone as the device table
   (--cd-table-bg) rather than --cd-surface, so the control panel's boxed
   rows read consistently with the dashboard's table instead of blending
   into the page background in dark mode. */
.card-panel {
  background: var(--cd-table-bg);
}

/* Section titles that sit ABOVE their card (not inside its padding), used
   on the settings page so each card is preceded by its heading rather
   than the heading being the card's first internal row. The first title
   on a page sits flush with no extra top gap; later ones get breathing
   room from the card above them. */
.section-title {
  font-size: 16px;
  font-weight: 600;
  color: var(--cd-text-main);
  margin: 28px 0 10px;
}
.section-title:first-of-type { margin-top: 0; }

/* Small pill next to a setting-row's own title, marking that specific
   field as write-only (API keys, tokens, webhook URLs) - shown right
   where the field lives rather than once per card, so it's obvious
   field-by-field which controls never show their current value. */
.hidden-fields-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  font-weight: 600;
  color: var(--cd-text-muted);
  background: var(--cd-surface);
  border: 1px solid var(--cd-border);
  border-radius: 999px;
  padding: 3px 9px 3px 7px;
  margin-left: 8px;
  vertical-align: middle;
  text-transform: none;
  letter-spacing: normal;
}
.hidden-fields-badge svg {
  width: 12px;
  height: 12px;
  flex-shrink: 0;
}

/* ---------- KPI row ---------- */
.kpi-row {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 12px;
  margin-top: 24px;
  margin-bottom: 28px;
}

.kpi {
  background: var(--cd-table-bg);
  border: 1px solid var(--cd-border);
  border-radius: var(--cd-radius);
  padding: 14px 16px;
  cursor: pointer;
  transition: border-color 0.15s ease;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.kpi:hover { border-color: var(--cd-brand); }
.kpi.active-filter { border-color: var(--cd-brand); box-shadow: 0 0 0 1px var(--cd-brand); }

.kpi .value { font-size: 24px; font-weight: 700; }
.kpi .label { color: var(--cd-text-muted); font-size: 12px; text-transform: uppercase; letter-spacing: 0.04em; }

@media (max-width: 720px) {
  .kpi-row { grid-template-columns: repeat(2, 1fr); }
}

/* ---------- Search + toolbar ---------- */
.toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 14px;
  flex-wrap: wrap;
}

.search-box {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--cd-table-bg);
  border: 1px solid var(--cd-border);
  border-radius: 8px;
  padding: 8px 12px;
  flex: 1;
  min-width: 200px;
  color: var(--cd-text-muted);
}

.search-box input {
  border: none;
  background: none;
  outline: none;
  color: var(--cd-text-main);
  width: 100%;
  font-size: 14px;
}

.stale-banner {
  display: flex;
  align-items: center;
  gap: 8px;
  background: rgba(245, 158, 11, 0.12);
  border: 1px solid var(--cd-status-inactive);
  color: var(--cd-status-inactive);
  border-radius: 8px;
  padding: 10px 14px;
  font-size: 13px;
  margin-bottom: 16px;
}

.fresh-note {
  color: var(--cd-text-muted);
  font-size: 12px;
}

/* ---------- Table ---------- */
table {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
  background: var(--cd-table-bg);
  border-radius: 8px;
}

thead th {
  text-align: left;
  color: var(--cd-text-muted);
  font-weight: 600;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 10px 12px;
  border-bottom: 1px solid var(--cd-border);
  user-select: none;
  white-space: nowrap;
}

/* Only columns that are actually sortable get the pointer affordance -
   previously ALL headers (including the notification/actions column,
   which just holds a button) looked clickable even though nothing
   happened on click for non-sortable ones. */
thead th[data-sort-key] {
  cursor: pointer;
}

thead th[data-sort-key]:hover {
  color: var(--cd-text-main);
}

thead th .sort-icon { opacity: 0.5; vertical-align: -3px; }

tbody td {
  padding: 12px;
  border-bottom: 1px solid var(--cd-border);
  vertical-align: middle;
}

tbody tr:hover { background: rgba(99, 91, 255, 0.05); }
tbody tr.is-paused { opacity: 0.7; }

.device-name {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 15px;
  font-weight: 700;
}

.device-icon {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  color: var(--cd-text-muted);
}

/* ---------- Badges ---------- */
.badge-group {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 6px;
}

.badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-width: 108px;
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  cursor: help;
}

.badge-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
  animation: badge-pulse 4.4s ease-in-out infinite;
}

@keyframes badge-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

.badge-active { background: rgba(16, 185, 129, 0.14); color: var(--cd-status-active); }
.badge-inactive { background: rgba(245, 158, 11, 0.14); color: var(--cd-status-inactive); }
.badge-offline { background: rgba(239, 68, 68, 0.14); color: var(--cd-status-offline); }
.badge-never_seen { background: rgba(56, 189, 248, 0.14); color: var(--cd-status-never-seen); }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--cd-brand);
  color: #fff;
  border: none;
  border-radius: 8px;
  padding: 9px 16px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s ease;
}

.btn:hover { background: var(--cd-brand-hover); }
.btn.btn-secondary { background: var(--cd-border); color: var(--cd-text-main); }
.btn.btn-secondary:hover { background: var(--cd-status-paused); color: #fff; }
.btn.btn-sm { padding: 5px 10px; font-size: 12px; }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }

/* Save / Send test notification: same fixed width regardless of label
   length, so the two primary settings-page actions line up evenly. Width
   is sized to comfortably fit the longer "Send test notification" label
   plus its icon in every supported language. */
.btn.btn-equal-width { width: 230px; justify-content: center; }
@media (max-width: 640px) { .btn.btn-equal-width { width: 100%; } }

/* Small square icon-only button (generate/copy next to the cron secret
   field). Same visual language as .btn-secondary but square and compact. */
.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 38px;
  height: 38px;
  background: var(--cd-bg);
  border: 1px solid var(--cd-border);
  border-radius: 8px;
  color: var(--cd-text-main);
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.icon-btn:hover { background: var(--cd-border); }
.icon-btn.is-copied { background: var(--cd-status-active); border-color: var(--cd-status-active); color: #fff; }

/* ---------- Forms ---------- */
label { display: block; font-size: 13px; color: var(--cd-text-muted); margin-bottom: 6px; }

input[type="text"], input[type="password"], input[type="number"], select {
  width: 100%;
  background: var(--cd-bg);
  border: 1px solid var(--cd-border);
  color: var(--cd-text-main);
  border-radius: 8px;
  padding: 9px 12px;
  font-size: 14px;
  outline: none;
}

input:focus, select:focus { border-color: var(--cd-brand); }
input[readonly] { color: var(--cd-text-muted); cursor: default; }

.form-row { margin-bottom: 16px; }
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
@media (max-width: 640px) { .form-grid { grid-template-columns: 1fr; } }

.checkbox-row { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.checkbox-row input { width: auto; }
.checkbox-row label { margin: 0; color: var(--cd-text-main); }

/* ---------- Settings page: one row per setting ---------- */
/* Each row is a title + description on the left and a single control on
   the right, matching the reference design. A thin divider sits BETWEEN
   consecutive rows only (not above the first or below the last), so a
   card's own padding still frames the whole group. */
.setting-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 16px 0;
}
.setting-row + .setting-row { border-top: 1px solid var(--cd-divider); }
.card > .setting-row:first-of-type { padding-top: 4px; }
.card > .setting-row:last-of-type { padding-bottom: 4px; }

/* Group separator: a thicker divider marking the start of a new logical
   group of rows within the same card - e.g. each notification channel
   (Email / Slack / Pushover / ntfy) inside the "Notification channels"
   card, so the eye can tell where one channel's settings end and the
   next one's begin, without needing a whole new card per channel. */
.setting-row + .setting-row.setting-row-group-start {
  border-top: 3px solid var(--cd-divider);
  margin-top: 6px;
  padding-top: 22px;
}

.setting-row-text { flex: 1 1 auto; min-width: 0; }
.setting-row-title { font-size: 14px; font-weight: 600; color: var(--cd-text-main); margin-bottom: 4px; }
.setting-row-desc { font-size: 13px; color: var(--cd-text-muted); line-height: 1.5; }

.setting-row-control { flex: 0 0 auto; width: 240px; }
.setting-row-control.is-narrow { width: 110px; }
.setting-row-control input, .setting-row-control select { margin: 0; }
.setting-row-control input[type="number"] { text-align: right; }

/* Wide rows: title/description stack above a full-width control instead
   of sitting side by side, for every free-text field (URLs, hostnames,
   keys, the cron IP allowlist, etc.) - number fields and dropdowns keep
   the narrower side-by-side layout above. */
.setting-row.setting-row-wide { flex-direction: column; align-items: stretch; gap: 10px; }
.setting-row.setting-row-wide .setting-row-control { width: 100%; }

/* Cron secret field: text input plus a Generate and a Copy icon button. */
.cron-secret-row { display: flex; align-items: center; gap: 8px; }
.cron-secret-row input { flex: 1 1 auto; min-width: 0; font-family: monospace; }

@media (max-width: 640px) {
  .setting-row { flex-direction: column; align-items: stretch; gap: 10px; }
  .setting-row-control, .setting-row-control.is-narrow { width: 100%; }
}

.settings-intro-note {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: 13px;
  line-height: 1.6;
  color: var(--cd-text-muted);
  background: var(--cd-surface);
  border: 1px solid var(--cd-border);
  border-radius: var(--cd-radius);
  padding: 12px 14px;
  margin-bottom: 16px;
}
.settings-intro-note svg { flex-shrink: 0; margin-top: 1px; }

/* iOS-style toggle switch, styled from a plain checkbox so the underlying
   form field (and its name/value submitted on save) doesn't change. */
.switch {
  position: relative;
  display: inline-block;
  width: 42px;
  height: 24px;
  flex-shrink: 0;
  margin: 0;
}
.switch input {
  opacity: 0;
  width: 0;
  height: 0;
  position: absolute;
}
.switch-slider {
  position: absolute;
  inset: 0;
  background: var(--cd-border);
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.15s ease;
}
.switch-slider::before {
  content: "";
  position: absolute;
  height: 18px;
  width: 18px;
  left: 3px;
  top: 3px;
  background: #fff;
  border-radius: 50%;
  transition: transform 0.15s ease;
}
.switch input:checked + .switch-slider { background: var(--cd-brand); }
.switch input:checked + .switch-slider::before { transform: translateX(18px); }
.switch input:focus-visible + .switch-slider { outline: 2px solid var(--cd-brand); outline-offset: 2px; }

.error-list { color: var(--cd-status-offline); font-size: 13px; margin: 8px 0; }
.success-note {
  color: var(--cd-status-active);
  font-size: 13px;
  margin: 8px auto;
  text-align: center;
}

.settings-actions {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
}
.warning-note {
  color: var(--cd-status-inactive);
  font-size: 13px;
  background: rgba(245, 158, 11, 0.1);
  border: 1px solid var(--cd-status-inactive);
  border-radius: 8px;
  padding: 10px 12px;
  margin-bottom: 14px;
}

/* ---------- Auth pages ---------- */
.auth-page {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 20px;
}

.auth-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 600;
  font-size: 16px;
  color: var(--cd-text-main);
}

.auth-brand .dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--cd-brand);
}

.auth-card {
  width: 100%;
  max-width: 380px;
  background: var(--cd-surface);
  border: 1px solid var(--cd-border);
  border-radius: var(--cd-radius);
  box-shadow: var(--cd-shadow);
  padding: 32px;
}

.auth-card h1 {
  font-size: 18px;
  margin-top: 0;
  margin-bottom: 20px;
  display: flex;
  align-items: center;
  gap: 8px;
}

.icon { display: inline-block; }
