/* Udder Fleet Admin — brand palette per "Udder Branding Guide March 2026" */

:root,
:root[data-theme="light"] {
  color-scheme: light;
  --color-bg: #F3F4F8;
  --color-surface: #FFFFFF;
  --color-surface-alt: #F3F4F8;
  --color-text: #091330;
  --color-text-muted: rgba(9, 19, 48, 0.62);
  --color-border: rgba(9, 19, 48, 0.12);
  --color-primary: #10396E;
  --color-primary-text: #FFFFFF;
  --color-charcoal: #222A38;
  --color-success: #2F8F6B;
  --color-warning: #D47A2C;
  --color-danger: #C23A45;
  --color-yellow: #D1A72E;
  --color-purple: #6B63B5;
  --color-pink: #C2618E;
  --shadow-card: 0 1px 2px rgba(9, 19, 48, 0.06), 0 1px 8px rgba(9, 19, 48, 0.04);
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --color-bg: #091330;
  --color-surface: #15203F;
  --color-surface-alt: #1B2747;
  --color-text: #F4F4F4;
  --color-text-muted: rgba(244, 244, 244, 0.66);
  --color-border: rgba(244, 244, 244, 0.14);
  --color-primary: #4D7FC2;
  --color-primary-text: #091330;
  --color-charcoal: #222A38;
  --color-success: #3FAE85;
  --color-warning: #E2924B;
  --color-danger: #E0606C;
  --color-yellow: #E0BD55;
  --color-purple: #8C84D4;
  --color-pink: #D586AC;
  --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.3), 0 1px 8px rgba(0, 0, 0, 0.25);
}

* { box-sizing: border-box; }

/* The hidden attribute must win even when an element also has a class that
   sets its own display (e.g. .field-row's display:flex), otherwise it's
   silently ignored. */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: "Montserrat", system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
}

body {
  min-height: 100vh;
}

h1, h2, h3 {
  font-weight: 700;
  margin: 0;
}

.muted { color: var(--color-text-muted); font-size: 0.9rem; }
.text-danger { color: var(--color-danger); }
.text-warning { color: var(--color-warning); }

a { color: var(--color-primary); }
:root[data-theme="dark"] a { color: #8FB4E6; }

/* Top bar */
.topbar {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
  padding: 10px 20px;
}

.topbar-left {
  display: flex;
  align-items: center;
  gap: 10px;
}

.logo { height: 32px; width: auto; }

.brand-sub {
  font-weight: 600;
  color: var(--color-text-muted);
  font-size: 0.85rem;
}

.topbar-nav {
  display: flex;
  gap: 16px;
  flex: 1;
  flex-wrap: wrap;
}

.navlink {
  text-decoration: none;
  font-weight: 500;
  font-size: 0.92rem;
  color: var(--color-text-muted);
}
.navlink:hover { color: var(--color-primary); }
.navlink-active { color: var(--color-primary); font-weight: 700; }

/* Topbar dropdown (Debug menu) — keeps the low-traffic debug pages off the
   main nav row, which had run out of horizontal space. */
.navmenu { position: relative; }

.navmenu-trigger {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 0;
  border: none;
  background: none;
  font-family: inherit;
  cursor: pointer;
}
.navmenu-caret { font-size: 0.7em; }

.navmenu-panel {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  z-index: 20;
  min-width: 190px;
  display: flex;
  flex-direction: column;
  padding: 6px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 10px;
  box-shadow: var(--shadow-card);
}

.navmenu-item {
  padding: 7px 10px;
  border-radius: 7px;
  text-decoration: none;
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--color-text);
  white-space: nowrap;
}
.navmenu-item:hover { background: var(--color-surface-alt); color: var(--color-primary); }
.navmenu-item-active { color: var(--color-primary); font-weight: 700; }

.navmenu-sep {
  height: 1px;
  margin: 5px 4px;
  background: var(--color-border);
}

.topbar-right {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* Mobile drawer scaffolding, all inert until the @media block at the end of this file
   turns it on. admin-nav.js wraps .topbar-nav + .topbar-right in .topbar-drawer on
   every page; display:contents keeps the topbar's flex layout exactly as it was. */
.topbar-drawer { display: contents; }
.brand-page { display: none; }
.nav-toggle { display: none; }
.nav-backdrop { display: none; }

.user-email {
  font-size: 0.85rem;
  color: var(--color-text-muted);
}

.icon-btn, .btn {
  font-family: inherit;
  font-size: 0.88rem;
  font-weight: 500;
  border-radius: 8px;
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-text);
  padding: 7px 12px;
  cursor: pointer;
}
.icon-btn { padding: 6px 9px; }
.btn:hover, .icon-btn:hover { border-color: var(--color-primary); }

.btn-primary {
  background: var(--color-primary);
  color: var(--color-primary-text);
  border-color: var(--color-primary);
}
.btn-secondary { background: var(--color-surface-alt); }
.btn-ghost { background: transparent; }
.btn-danger { color: var(--color-danger); border-color: var(--color-danger); background: transparent; }
.btn:disabled, .icon-btn:disabled { opacity: 0.55; cursor: not-allowed; }

/* Content */
.content {
  max-width: 1280px;
  margin: 0 auto;
  padding: 24px 20px 60px;
}

.empty-state {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 12px;
  padding: 40px 24px;
  text-align: center;
  margin-top: 40px;
}

.panel {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 12px;
  box-shadow: var(--shadow-card);
  margin-bottom: 24px;
  overflow: hidden;
}

.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  padding: 16px 18px;
  border-bottom: 1px solid var(--color-border);
}

.panel-head-actions {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

.subsection-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  padding: 14px 18px 10px;
  border-top: 1px solid var(--color-border);
}
.subsection-head:first-of-type { border-top: none; }
.subsection-head h3 {
  margin: 0;
  font-size: 0.9rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--color-text-muted);
}

.notification-toolbar, .filter-toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 12px 18px;
  border-bottom: 1px solid var(--color-border);
}
.notification-toolbar input[type="text"] {
  min-width: 260px;
  flex: 1;
}
.filter-toolbar input[type="search"] { flex: 1 1 240px; min-width: 200px; }
.filter-toolbar select { max-width: 220px; }
.filter-toolbar label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.85rem;
  color: var(--color-text-muted);
  white-space: nowrap;
}

/* Tables */
.table-wrap { overflow-x: auto; }

.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.92rem;
}

.data-table th {
  text-align: left;
  padding: 10px 14px;
  background: var(--color-surface-alt);
  color: var(--color-text-muted);
  font-weight: 600;
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  white-space: nowrap;
}

.data-table td {
  padding: 10px 14px;
  border-top: 1px solid var(--color-border);
  vertical-align: middle;
}

.col-chevron { width: 28px; }
.col-center { text-align: center; }

.data-table th.sortable {
  cursor: pointer;
  user-select: none;
}
.data-table th.sortable:hover { color: var(--color-primary); }
.data-table th.sort-active { color: var(--color-text); }

.row-clickable { cursor: pointer; }
.row-clickable:hover { background: var(--color-surface-alt); }

.row-expanded { background: var(--color-surface-alt); }

.chevron {
  display: inline-block;
  transition: transform 0.15s ease;
  color: var(--color-text-muted);
}
.chevron.open { transform: rotate(90deg); }

.loading-row { padding: 20px; text-align: center; }

/* Farm group header rows in the feeders table (see renderFeeders). The row names the
   farm and doubles as its show/hide control: a hidden farm keeps its row and drops to
   the bottom of the table, so nothing is ever filtered out of reach. */
.group-row td {
  padding: 0;
  background: var(--color-surface-alt);
}

.group-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  /* Matches .data-table td so the chevron lines up with the cells below it. */
  padding: 10px 14px;
  border: none;
  background: none;
  font-family: inherit;
  font-size: 0.92rem;
  font-weight: 700;
  color: var(--color-text);
  text-align: left;
  cursor: pointer;
}

.group-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.group-count { font-size: 0.78rem; font-weight: 500; white-space: nowrap; }
.group-action {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--color-primary);
}
/* Hidden farms are parked at the bottom — dimmed so they read as set aside rather
   than as just another farm that happens to be collapsed. */
.group-row-collapsed .group-toggle { color: var(--color-text-muted); }

code, .mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
  font-size: 0.85em;
}

/* Status dots */
.dot {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 999px;
  margin-right: 6px;
  vertical-align: middle;
}
.dot-ok { background: var(--color-success); }
.dot-bad { background: var(--color-danger); }
.dot-warn { background: var(--color-warning); }
.dot-loading {
  background: var(--color-text-muted);
  opacity: 0.5;
  animation: pulse 1.2s ease-in-out infinite;
}
@keyframes pulse {
  0%, 100% { opacity: 0.25; }
  50% { opacity: 0.7; }
}

.badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 600;
  /* A pill broken over two lines reads as damage, not as a label. It also means a
     shrink-to-fit column sizes to the badge's full label rather than its longest word
     — see the feeders table widths in the mobile block. */
  white-space: nowrap;
}
.badge-danger { background: rgba(194, 58, 69, 0.12); color: var(--color-danger); }
.badge-warning { background: rgba(212, 122, 44, 0.14); color: var(--color-warning); }
.badge-success { background: rgba(47, 143, 107, 0.14); color: var(--color-success); }
.badge-muted { background: var(--color-surface-alt); color: var(--color-text-muted); }
/* Live feeder-state badges (see feeder-status.js): Feeding/Feed Complete read blue.
   Offline is orange, not red — a feeder we can't reach is not the same as one
   reporting a fault, and red should mean "this device is telling us it's broken".
   The inset ring (rather than a border, which would make the badge 2px taller than
   its neighbours) sets it apart from the flat orange of Paused/Manual/Training. */
.badge-info { background: rgba(16, 57, 110, 0.12); color: var(--color-primary); }
.badge-offline {
  background: rgba(212, 122, 44, 0.14);
  color: var(--color-warning);
  box-shadow: inset 0 0 0 1px rgba(212, 122, 44, 0.45);
}
/* The light-theme navy tint disappears against the dark surface. */
:root[data-theme="dark"] .badge-info { background: rgba(77, 127, 194, 0.18); }

/* "NOT SYNCING": streaming live_state but the /api/v1/sync loop has stopped. Every
   other column reads healthy in this state, so the badge has to shout. */
.badge-nosync {
  background: rgba(212, 122, 44, 0.18);
  color: var(--color-warning);
  border: 1px solid rgba(212, 122, 44, 0.5);
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.03em;
}

/* "NEEDS ATTENTION": a failed GET /api/fs/status check (LittleFS full/unmounted, or
   the upload queue disabled/critical-only/backing up). Like NOT SYNCING this is a
   state every other column reads as healthy — the feeder is online and feeding while
   its events pile up on-device. */
.badge-attention {
  background: rgba(212, 122, 44, 0.18);
  color: var(--color-warning);
  border: 1px solid rgba(212, 122, 44, 0.5);
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.03em;
  cursor: help;
}

/* Dot + version + channel + 🐛 as one unbreakable unit, so a shrink-to-fit Firmware
   column sizes to the whole version string and never splits it across lines. The
   "update available" badge sits outside this and is free to wrap onto its own line. */
.fw-version { white-space: nowrap; }

/* Unread coredump waiting on the device, shown in the Firmware column. Deliberately
   tight — it sits directly after the version string. */
.coredump-bug {
  font-size: 0.9rem;
  line-height: 1;
  cursor: help;
}
.data-table td .coredump-bug { margin-left: 4px; }

/* Feeders table Status cell: badges on the first line, up/down duration beneath. */
.status-stack {
  display: flex;
  flex-direction: column;
  gap: 3px;
  align-items: flex-start;
}
.status-badges {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px;
}
/* nowrap so "(3 days up)" can't break across two lines in a narrow Status column. */
.status-sub { font-size: 0.8rem; white-space: nowrap; }
.status-sub-down { color: var(--color-warning); }
/* This cell spaces its children with flex gap, so the margin-based spacing the badges
   and dots carry for other cells must not double up on top of it. */
.data-table td .status-badges > .badge,
.data-table td .status-badges > .live-badges,
.data-table td .status-badges > .sync-limit-badge,
.data-table td .status-badges > .dot {
  margin-left: 0;
  margin-right: 0;
}

/* Row of per-teat live status badges in the feeders table's Status column. */
.live-badges {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px;
}
.data-table td .live-badges { margin-left: 6px; }
.data-table td .live-badges:first-child { margin-left: 0; }
.data-table td .live-badges .badge { margin-left: 0; }

.sync-limit-badge {
  display: inline-flex;
  align-items: center;
  margin-left: 6px;
  padding: 3px 8px;
  border-radius: 8px;
  background: rgba(194, 58, 69, 0.18);
  color: var(--color-danger);
  border: 1px solid rgba(194, 58, 69, 0.45);
  font-size: 0.76rem;
  font-weight: 800;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  box-shadow: 0 0 0 2px rgba(194, 58, 69, 0.08), 0 0 16px rgba(194, 58, 69, 0.32);
}

/* Detail row */
.detail-row td {
  background: var(--color-surface-alt);
  padding: 18px;
}

.detail-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 18px;
}

.detail-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 10px;
  padding: 14px 16px;
}

.detail-card-sync-throttled {
  border-color: rgba(194, 58, 69, 0.75);
  box-shadow: 0 0 0 3px rgba(194, 58, 69, 0.12), 0 0 24px rgba(194, 58, 69, 0.28);
}

/* Storage/queue checks failing, or an unread coredump — the amber counterpart to
   detail-card-sync-throttled, which is reserved for a deliberate red-alert setting. */
.detail-card-attention {
  border-color: rgba(212, 122, 44, 0.7);
  box-shadow: 0 0 0 3px rgba(212, 122, 44, 0.1);
}

.attention-list {
  margin-top: 12px;
  padding: 10px 12px;
  border-radius: 8px;
  border: 1px solid rgba(212, 122, 44, 0.55);
  background: rgba(212, 122, 44, 0.12);
  color: var(--color-warning);
  font-size: 0.85rem;
}
.attention-list strong {
  display: block;
  margin-bottom: 6px;
  font-size: 0.78rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.attention-list ul { margin: 0; padding-left: 18px; display: grid; gap: 4px; }

/* Coredump upload */
.coredump-reason { width: 100%; min-width: 0; }

.coredump-progress {
  margin-top: 12px;
  display: grid;
  gap: 6px;
}
.coredump-progress-bar {
  height: 6px;
  border-radius: 999px;
  background: var(--color-surface-alt);
  overflow: hidden;
}
.coredump-progress-bar span {
  display: block;
  height: 100%;
  background: var(--color-primary);
  transition: width 0.3s ease;
}

/* Coredump triage (Debug page detail row) */
.coredump-triage-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 0.78rem;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}
.coredump-triage-field select { min-width: 170px; text-transform: none; letter-spacing: normal; }
.coredump-triage input[type="text"],
.coredump-triage textarea { flex: 1 1 100%; width: 100%; min-width: 0; }

/* The device's own note about the crash — preserve the line breaks it sent. */
.coredump-message {
  white-space: pre-wrap;
  font-size: 0.9rem;
  padding: 10px 12px;
  border-radius: 8px;
  border: 1px solid var(--color-border);
  background: var(--color-surface-alt);
}

.coredump-comments {
  display: grid;
  gap: 8px;
  max-height: 320px;
  overflow-y: auto;
}
.coredump-comment {
  border: 1px solid var(--color-border);
  border-radius: 8px;
  padding: 8px 10px;
  background: var(--color-surface-alt);
}
.coredump-comment-head {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.8rem;
}
.coredump-comment-head .icon-btn { margin-left: auto; padding: 2px 7px; }
.coredump-comment-body {
  white-space: pre-wrap;
  font-size: 0.88rem;
  margin-top: 4px;
}

.sync-limit-warning {
  display: grid;
  gap: 4px;
  margin-bottom: 10px;
  padding: 10px 12px;
  border-radius: 8px;
  border: 1px solid rgba(194, 58, 69, 0.65);
  background: rgba(194, 58, 69, 0.14);
  color: var(--color-danger);
}

.sync-limit-warning strong {
  font-size: 0.78rem;
  letter-spacing: 0.04em;
}

.detail-card h4 {
  margin: 0 0 10px 0;
  font-size: 0.82rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--color-text-muted);
}

.kv-list { display: grid; grid-template-columns: auto 1fr; gap: 6px 12px; font-size: 0.88rem; }
.kv-list dt { color: var(--color-text-muted); }
.kv-list dd { margin: 0; word-break: break-word; }

.detail-card-wide { grid-column: 1 / -1; }

.detail-card h5 {
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--color-text-muted);
  font-weight: 700;
}

.options-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 2px 12px;
}

.option-row {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 3px 0;
  font-size: 0.85rem;
  cursor: pointer;
}
.option-row input[type="checkbox"] { margin: 0; }

.field-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 10px;
}

select, input[type="text"], input[type="email"], input[type="number"], input[type="search"], input[type="date"], textarea {
  font-family: inherit;
  font-size: 0.88rem;
  padding: 6px 10px;
  border-radius: 8px;
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-text);
}

textarea {
  min-width: 240px;
  resize: vertical;
}

.result-msg { font-size: 0.85rem; margin-top: 6px; }
.result-msg.ok { color: var(--color-success); }
.result-msg.err { color: var(--color-danger); }

.org-id-tooltip { cursor: help; border-bottom: 1px dotted var(--color-text-muted); }

/* Farms view */
.farm-summary {
  display: flex;
  gap: 24px;
  padding: 16px 18px;
  border-bottom: 1px solid var(--color-border);
}
.farm-stat-value { font-size: 1.6rem; font-weight: 700; line-height: 1.2; }
.farm-stat-label { font-size: 0.8rem; color: var(--color-text-muted); text-transform: uppercase; letter-spacing: 0.03em; }

.segmented {
  display: inline-flex;
  border: 1px solid var(--color-border);
  border-radius: 8px;
  overflow: hidden;
}
.segmented-btn {
  font-family: inherit;
  font-size: 0.85rem;
  font-weight: 500;
  border: none;
  background: var(--color-surface);
  color: var(--color-text-muted);
  padding: 6px 14px;
  cursor: pointer;
}
.segmented-btn + .segmented-btn { border-left: 1px solid var(--color-border); }
.segmented-btn.active { background: var(--color-primary); color: var(--color-primary-text); }

.chart-toolbar {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 12px 18px 0;
}

.chart-wrap {
  padding: 12px 18px 18px;
  height: 46vh;
  min-height: 280px;
  max-height: 520px;
}
.chart-wrap canvas { width: 100% !important; height: 100% !important; }

/* ---------------- Tracker (tracker.html) ---------------- */

.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.85rem; }

.tracker-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 28px;
  padding: 16px 18px;
  border-bottom: 1px solid var(--color-border);
}

.tracker-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  padding: 14px 18px;
  border-bottom: 1px solid var(--color-border);
}
.tracker-toolbar input[type="search"] { flex: 1 1 240px; min-width: 180px; }
.tracker-toolbar select { max-width: 190px; }

.tracker-check { display: flex; align-items: center; gap: 6px; font-size: 0.88rem; white-space: nowrap; }
.tracker-check input { margin: 0; }

.tracker-footer { padding: 10px 18px; }

.data-table td .badge { margin-left: 6px; }

/* Editor drawer */
.drawer-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(9, 19, 48, 0.45);
  z-index: 40;
}

.drawer {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: min(760px, 100vw);
  display: flex;
  flex-direction: column;
  background: var(--color-surface);
  border-left: 1px solid var(--color-border);
  box-shadow: -8px 0 30px rgba(9, 19, 48, 0.18);
  z-index: 41;
}

.drawer-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  padding: 16px 20px;
  border-bottom: 1px solid var(--color-border);
}
.drawer-head h3 { margin: 2px 0 0; font-size: 1.05rem; }
.drawer-ref { font-size: 0.8rem; letter-spacing: 0.04em; text-transform: uppercase; }

.drawer-body { flex: 1; overflow-y: auto; padding: 18px 20px 24px; }

.drawer-foot {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 20px;
  border-top: 1px solid var(--color-border);
  background: var(--color-surface-alt);
}
.drawer-foot-right { margin-left: auto; display: flex; gap: 8px; }

.drawer-meta { margin-top: 18px; font-size: 0.8rem; }

.field-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px 16px;
}
.field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.field-wide { grid-column: 1 / -1; }
.field > span { font-size: 0.78rem; color: var(--color-text-muted); text-transform: uppercase; letter-spacing: 0.03em; }
.field input, .field select, .field textarea { width: 100%; }

/* Links */
.links-list { display: flex; flex-direction: column; gap: 6px; }
.link-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 10px;
  border: 1px solid var(--color-border);
  border-radius: 8px;
  font-size: 0.86rem;
}
.link-relation { color: var(--color-text-muted); white-space: nowrap; font-size: 0.8rem; }
.link-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.link-row .icon-btn { margin-left: auto; padding: 2px 7px; }

.link-add { display: flex; gap: 8px; margin-top: 10px; }
.link-add input { flex: 1; }

/* Mobile
   Below this width the topbar collapses to logo + page name + a ☰ drawer, and the
   admin tables go full-bleed so the columns that matter fit without a sideways
   scroll. Keep the breakpoint in step with MOBILE_QUERY in admin-nav.js (which builds
   the drawer) and in admin.js (which groups the feeders table by farm at the same
   point) — the three have to flip together. */
@media (max-width: 720px) {
  /* --- Topbar + drawer --- */
  .topbar { padding: 8px 12px; gap: 10px; flex-wrap: nowrap; }
  .topbar-left { flex: 1; min-width: 0; gap: 8px; }
  .logo { height: 26px; }
  .brand-sub { display: none; }
  .brand-page {
    display: block;
    min-width: 0;
    font-weight: 700;
    font-size: 0.98rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .nav-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 1.05rem;
    line-height: 1;
  }

  .nav-backdrop {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 9; /* under the sticky topbar (z-index 10), over the page */
    background: rgba(9, 19, 48, 0.35);
  }

  /* Anchored to .topbar, which is sticky and therefore already a positioned ancestor —
     so the drawer never has to know how tall the bar is. */
  .topbar-drawer {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    gap: 2px;
    max-height: 76vh;
    overflow-y: auto;
    padding: 8px 12px 12px;
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
    box-shadow: var(--shadow-card);
  }
  body.nav-open .topbar-drawer { display: flex; }
  /* The drawer scrolls itself; the page behind the backdrop shouldn't. */
  body.nav-open { overflow: hidden; }

  .topbar-drawer .topbar-nav { flex: none; flex-direction: column; gap: 0; }
  .topbar-drawer .navlink { padding: 11px 8px; border-radius: 8px; font-size: 0.98rem; }
  .topbar-drawer .navlink:hover { background: var(--color-surface-alt); }
  .topbar-drawer .navmenu { width: 100%; }
  /* The More dropdown flattens into the list: no trigger, every item always visible.
     admin-nav.js clears the panel's `hidden` attribute while this layout is active. */
  .topbar-drawer .navmenu-trigger { display: none; }
  .topbar-drawer .navmenu-panel {
    position: static;
    min-width: 0;
    padding: 0;
    border: none;
    border-radius: 0;
    background: none;
    box-shadow: none;
  }
  .topbar-drawer .navmenu-item { padding: 11px 8px; font-size: 0.98rem; }
  .topbar-drawer .topbar-right {
    flex-wrap: wrap;
    margin-top: 8px;
    padding-top: 10px;
    border-top: 1px solid var(--color-border);
  }
  .topbar-drawer .user-email {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  /* --- Tables run edge to edge --- */
  /* The card inset costs ~24px either side, close to a tenth of the screen, and buys
     nothing on a table that is already the full width of the viewport. */
  .content { padding: 12px 0 48px; }
  .panel {
    border-radius: 0;
    border-left: none;
    border-right: none;
    margin-bottom: 14px;
  }
  .empty-state { margin: 24px 12px 0; padding: 28px 18px; }
  .panel-head { padding: 12px 14px; }
  .notification-toolbar, .filter-toolbar, .tracker-toolbar { padding: 12px 14px; }
  .data-table { font-size: 0.88rem; }
  .data-table th, .data-table td { padding: 4px 5px; }
  .group-toggle { padding: 8px 5px; } /* keeps step with the tighter cell padding */
  .data-table th { white-space: normal; } /* let long headers wrap instead of widening the table */

  .detail-row td { padding: 12px; }
  .detail-grid { grid-template-columns: minmax(0, 1fr); gap: 12px; }
  .field-grid { grid-template-columns: minmax(0, 1fr); }
  textarea { min-width: 0; width: 100%; }
  /* An expanded row shares the table's column widths, so a control that refuses to
     shrink below its default size would set a new floor for the whole table and bring
     the sideways scroll back the moment someone taps a feeder. */
  .detail-card input[type="text"],
  .detail-card input[type="number"],
  .detail-card select { min-width: 0; max-width: 100%; }
  .tracker-stats { gap: 18px; }

  /* --- Feeders table: what survives the narrow view --- */
  /* Device id and serial are identity columns you look up rather than scan, and both
     are in the Identity card of the expanded row; the farm group rows carry the
     organisation; app options and auto update are single dots. The chevron goes too —
     the whole row is the control, and 28px is worth more to the Name column. That
     leaves Name / Status / Firmware. */
  #feedersTable .col-chevron,
  #feedersTable .col-id,
  #feedersTable .col-serial,
  #feedersTable .col-org,
  #feedersTable .col-appOptions,
  #feedersTable .col-autoUpdate { display: none; }

  /* Shrink-to-fit for Status and Firmware, everything left over to Name.
     A `width` in px or % is only a hint to the auto table algorithm, which sizes each
     column from its content and then shares out the slack however it likes — which is
     why asking for 85px doesn't stick. These two declarations do stick, because they
     work *with* that algorithm rather than against it:
       width: 1%   — smaller than the content can possibly be, so the column collapses
                     to exactly its minimum content width and asks for nothing more.
       width: 100% — asks for more than exists, so this column absorbs all the slack.
     Net effect: Status and Firmware are as narrow as their text allows, and Name takes
     every remaining pixel — so it, and only it, grows on a larger phone. */
  #feedersTable .col-status,
  #feedersTable .col-firmware { width: 1%; }
  /* `anywhere` rather than `break-word`: both break a long word to avoid overflow, but
     only `anywhere` also lowers the column's *minimum* content width, and that minimum
     is what the table can't render below. With `break-word` a name like
     "UF-260018-1-north" still set a floor for the whole table and pushed the last of
     the Firmware column off a 320px screen. Name gives up its floor instead — it has
     all the slack anyway, so it only ever breaks mid-word on the narrowest phones. */
  #feedersTable .col-name {
    width: 100%;
    overflow-wrap: break-word; /* fallback for anything without `anywhere` */
    overflow-wrap: anywhere;
  }

  /* "Minimum content width" is the longest unbreakable run in the cell, so a single
     long label would set the width of that column for every row in the table. Badges
     are nowrap by default (a pill reading over two lines looks broken), but these
     three are long enough to do real damage, and they're rare — let them wrap. */
  #feedersTable .badge-nosync,
  #feedersTable .badge-attention,
  #feedersTable .col-firmware .badge { white-space: normal; }
}
