* { box-sizing: border-box; }
[hidden] { display: none !important; }
/* Shared palette tokens. Added for forward use / drift-prevention — existing
   rules keep their literal hex (no visual change). New code references these. */
:root {
  --ft-bg: #1a1a1a;
  --ft-panel: #222;
  --ft-header: #2b1d1a;
  --ft-accent: #b34a2a;
  --ft-accent-bright: #e88a5a;
  --ft-text: #e0e0e0;
}
html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  background: #1a1a1a;
  color: #e0e0e0;
}
body { display: flex; flex-direction: column; }
header {
  background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
  border-bottom: none;
  padding: 8px 20px;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: nowrap;
  flex-shrink: 0;
  box-shadow: 0 2px 8px rgba(0,0,0,0.2);
}
header h1 {
  margin: 0;
  font-size: 1.25rem;
  font-weight: 600;
  color: #fff;
  letter-spacing: 0;
}
.page-title {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  flex: 0 0 auto;
}
.back-btn {
  background: #1b2530;
  color: #d0d7de;
  border: 1px solid #3b4754;
  border-radius: 8px;
  padding: 4px 9px;
  cursor: pointer;
  font-size: 0.9rem;
  line-height: 1;
}
.back-btn:hover {
  background: #223041;
}
.back-btn:focus-visible {
  outline: 2px solid #d0d7de;
  outline-offset: 2px;
}
#status {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex: 1;
  font-size: 0.86rem;
}
#status select {
  background: #1a1a1a;
  color: #e0e0e0;
  border: 1px solid #555;
  padding: 0.25rem 0.5rem;
  border-radius: 3px;
}
#conn-state {
  font-weight: 600;
  padding: 0.15rem 0.5rem;
  border-radius: 3px;
  background: #444;
}
#conn-state.live { background: #2a6b2a; color: #d0ffd0; }
#conn-state.error { background: #6b2a2a; color: #ffd0d0; }
#last-update { color: #999; font-size: 0.8rem; }

/* Ping button — round-trip Pi liveness check. Sits next to conn-state in
   the header so the IC has connection-related controls clustered. The
   result span shifts color based on heartbeat status. */
.ping-btn {
  background: #1a1a1a;
  color: #e88a5a;
  border: 1px solid #b34a2a;
  border-radius: 3px;
  padding: 0.2rem 0.7rem;
  font-family: inherit;
  font-size: 0.8rem;
  font-weight: 600;
  cursor: pointer;
  -webkit-appearance: none;
}
.ping-btn:hover { background: #2a2a2a; }
.ping-btn:active { background: #b34a2a; color: #fff; }
.ping-btn:disabled { opacity: 0.5; cursor: progress; }
.ping-result {
  font-size: 0.78rem;
  font-weight: 600;
  padding: 0.15rem 0.55rem;
  border-radius: 3px;
  background: transparent;
  color: #999;
}
.ping-result:empty { display: none; }
.ping-result.pending  { background: #333; color: #ddd; }
.ping-result.live     { background: #2a6b2a; color: #d0ffd0; }
.ping-result.stale    { background: #6b5a2a; color: #ffe0a0; }
.ping-result.offline  { background: #6b2a2a; color: #ffd0d0; }
.ping-result.missing  { background: #444; color: #ccc; }
.ping-result.error    { background: #6b2a2a; color: #ffd0d0; }
.ping-result.none     { background: #444; color: #ccc; }
main {
  flex: 1;
  display: flex;
  min-height: 0;
}
#map {
  flex: 1;
  background: #111;
}
#side-panel {
  width: 320px;
  border-left: 1px solid #333;
  padding: 0.75rem 1rem;
  overflow-y: auto;
  background: #222;
}
/* Panel toggle styled like a heading on desktop, like a bottom-sheet handle
   on mobile. Single <button> for both contexts so the markup is consistent
   and the JS handler always has somewhere to bind. */
.panel-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  background: none;
  border: none;
  color: #e88a5a;
  font-family: inherit;
  font-size: 0.95rem;
  font-weight: 600;
  text-align: left;
  padding: 0;
  margin: 0 0 0.5rem 0;
  cursor: default;
}
.panel-toggle:focus-visible {
  outline: 2px solid #e88a5a;
  outline-offset: 2px;
}
.panel-chevron {
  display: none;
  font-size: 1rem;
  transition: transform 0.25s ease;
}
#panel-body {
  /* Desktop: normal flow inside the side panel. */
}
#drop-list {
  list-style: none;
  padding: 0;
  margin: 0;
}
#drop-list li {
  padding: 0.5rem;
  margin-bottom: 0.4rem;
  background: #2a2a2a;
  border-left: 3px solid #b34a2a;
  border-radius: 3px;
  font-size: 0.8rem;
  cursor: pointer;
}
#drop-list li:hover { background: #333; }
#drop-list li.no-fix { border-left-color: #888; opacity: 0.7; }
#drop-list .seq { color: #888; font-size: 0.7rem; }
#drop-list .meta { color: #aaa; margin-top: 0.2rem; }
#empty-msg { color: #666; font-style: italic; font-size: 0.85rem; }
.leaflet-popup-content { font-size: 0.85rem; }
.leaflet-popup-content table td { padding: 0.1rem 0.4rem; }
.leaflet-popup-content table td:first-child { color: #666; }

/* ---------- Aircraft selector overlay (Leaflet control, top-left) ----------
   The tail-number picker is the IC's primary anchor: every other view in
   this dashboard is filtered through "which aircraft are we watching?"
   It sits inside Leaflet's control corner so it scales with the map and
   doesn't fight the page header layout. The styling matches the dark/
   ember palette of the app shell. */
.tail-control {
  background: #2b1d1a;
  border: 1px solid #b34a2a;
  border-radius: 4px;
  padding: 0.5rem 0.6rem 0.55rem 0.6rem;
  min-width: 14rem;
  max-width: 22rem;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.4);
  font-family: inherit;
}
.tail-control .tail-label {
  color: #e88a5a;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  margin-bottom: 0.25rem;
}
.tail-control select {
  width: 100%;
  background: #1a1a1a;
  color: #f0f0f0;
  border: 1px solid #555;
  border-radius: 3px;
  padding: 0.35rem 0.5rem;
  font-size: 0.9rem;
  font-family: inherit;
  font-weight: 600;
  -webkit-appearance: none;
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, #e88a5a 50%),
                    linear-gradient(135deg, #e88a5a 50%, transparent 50%);
  background-position: calc(100% - 0.9rem) 50%, calc(100% - 0.55rem) 50%;
  background-size: 0.35rem 0.35rem, 0.35rem 0.35rem;
  background-repeat: no-repeat;
  padding-right: 1.5rem;
}
.tail-control select:focus {
  outline: none;
  border-color: #e88a5a;
}
.tail-control .tail-meta {
  margin-top: 0.35rem;
  color: #c0c0c0;
  font-size: 0.72rem;
  line-height: 1.3;
}
.tail-control .tail-meta:empty {
  display: none;
}

/* ---------- Page navigation ---------- */
.page-nav {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  flex-wrap: nowrap;
  margin-left: auto;
  white-space: nowrap;
  flex: 0 1 auto;
}
.page-nav a {
  padding: 6px 10px;
  text-decoration: none;
  color: #d0d7de;
  background: #1b2530;
  border: 1px solid #3b4754;
  border-radius: 8px;
  font-size: 0.86rem;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.page-nav a:hover { background: #223041; }
.page-nav a.active {
  background: #b34a2a;
  border-color: #e88a5a;
  color: #fff;
}
.page-nav a.logout {
  border-color: #444;
  color: #aaa;
}
.page-nav a.logout:hover {
  background: #2a2a2a;
  color: #e88a5a;
  border-color: #555;
}
.sysadmin-banner {
  background: linear-gradient(135deg, #151c25 0%, #1f2a37 100%);
  border-top: 1px solid #314150;
  border-bottom: 1px solid #314150;
  padding: 8px 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: nowrap;
  flex-shrink: 0;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);
}
.sysadmin-banner .page-title {
  gap: 10px;
}
.sysadmin-banner h2 {
  margin: 0;
  font-size: 1.25rem;
  font-weight: 600;
  color: #fff;
  letter-spacing: 0;
}
.sysadmin-banner .sysadmin-nav {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: nowrap;
  margin-left: auto;
}
.auth-block {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 8px;
}
.auth-block .logout {
  margin: 0;
}
.session-user {
  font-size: 0.72rem;
  color: #9fb0bf;
  line-height: 1;
  white-space: nowrap;
}
.session-role {
  font-size: 0.72rem;
  color: #8ea0af;
  line-height: 1;
  white-space: nowrap;
}
.session-user[hidden] {
  display: none;
}
.session-role[hidden] {
  display: none;
}

/* ---------- Shared modal system ---------- */
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  display: grid;
  place-items: center;
  padding: 18px;
  z-index: 40;
}
.modal-backdrop[hidden] {
  display: none;
}
.modal {
  width: min(760px, 100%);
  background: #141d27;
  border: 1px solid #315067;
  border-radius: 12px;
  padding: 16px;
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.4);
}
.modal h3 {
  margin: 0 0 10px;
  color: #dce7ef;
  font-size: 1.02rem;
}
.modal p {
  margin: 0 0 10px;
  color: #b8cad8;
  line-height: 1.5;
  font-size: 0.92rem;
}
.modal ul {
  margin: 0 0 12px;
  padding-left: 18px;
  color: #c7d7e2;
}
.modal li {
  margin: 4px 0;
  font-size: 0.9rem;
}
.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}

/* ---------- Calibration page ---------- */
.cal-main {
  flex: 1;
  display: flex;
  min-height: 0;
  overflow: hidden;
}
#device-list-panel {
  width: 280px;
  border-right: 1px solid #333;
  padding: 0.75rem 1rem;
  overflow-y: auto;
  background: #222;
  flex-shrink: 0;
}
#device-list-panel h2 {
  margin: 0 0 0.5rem 0;
  font-size: 0.95rem;
  color: #e88a5a;
}
#device-list { list-style: none; padding: 0; margin: 0; }
.device-card {
  padding: 0.5rem 0.6rem;
  margin-bottom: 0.4rem;
  background: #2a2a2a;
  border-left: 3px solid #555;
  border-radius: 3px;
  cursor: pointer;
  font-size: 0.82rem;
  transition: background 0.1s;
}
.device-card:hover { background: #333; }
.device-card.active {
  background: #4a2c22;
  border-left-color: #e88a5a;
  border-left-width: 5px;
  padding-left: 0.4rem; /* compensate for thicker border so text doesn't shift */
}
.device-card:focus-visible {
  outline: 2px solid #e88a5a;
  outline-offset: -2px;
}
.device-card .device-id {
  font-weight: 600;
  color: #f0f0f0;
  margin-bottom: 0.2rem;
}
.device-card .device-meta {
  color: #aaa;
  font-size: 0.75rem;
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}
.device-card .device-meta .tail { color: #c0c0c0; }
.device-card .device-meta .incident { font-style: italic; }
.device-card .device-ts {
  color: #888;
  font-size: 0.7rem;
  margin-top: 0.2rem;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
}
#device-empty, #device-error, #cal-error {
  color: #888;
  font-style: italic;
  font-size: 0.85rem;
  padding: 0.5rem 0;
}
#device-error, #cal-error { color: #e88a5a; font-style: normal; }

#cal-detail {
  flex: 1;
  overflow-y: auto;
  padding: 1rem 1.5rem;
  background: #1a1a1a;
}
#select-prompt {
  color: #888;
  font-style: italic;
  margin-top: 1rem;
}
#device-count { color: #888; font-size: 0.85rem; }
.cal-meta {
  border-bottom: 1px solid #333;
  padding-bottom: 0.75rem;
  margin-bottom: 1rem;
}
.cal-meta h2 {
  margin: 0 0 0.5rem 0;
  font-size: 1rem;
  color: #e88a5a;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
}
.meta-grid {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0.15rem 1rem;
  margin: 0;
  font-size: 0.85rem;
}
.meta-grid dt { color: #888; }
.meta-grid dd { margin: 0; color: #e0e0e0; }
.meta-grid.compact { font-size: 0.8rem; margin-top: 0.4rem; }
#download-json {
  margin-top: 0.6rem;
  padding: 0.3rem 0.8rem;
  background: #2a2a2a;
  color: #e0e0e0;
  border: 1px solid #555;
  border-radius: 3px;
  cursor: pointer;
  font-size: 0.8rem;
}
#download-json:hover { background: #b34a2a; border-color: #e88a5a; color: #fff; }
.cal-section {
  margin: 1rem 0 1.5rem 0;
  padding: 0.75rem;
  background: #222;
  border-radius: 4px;
  border-left: 3px solid #b34a2a;
}
.cal-section h3 {
  margin: 0 0 0.5rem 0;
  font-size: 0.9rem;
  color: #e88a5a;
}
.cal-table {
  border-collapse: collapse;
  width: auto;
  font-size: 0.8rem;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  margin-bottom: 0.5rem;
}
.cal-table th, .cal-table td {
  padding: 0.2rem 0.8rem;
  border: 1px solid #333;
  text-align: right;
}
.cal-table th {
  background: #2a2a2a;
  color: #e88a5a;
  font-weight: 600;
}
.cal-table td.empty-row {
  text-align: center;
  color: #666;
  font-style: italic;
}

/* ---------- Mobile / narrow-viewport layout ---------- */
/* Below 768px:
   - Live dashboard stacks: map gets 60vh, drops panel is a collapsible
     bottom sheet (40vh expanded, ~3rem collapsed). User taps the panel
     header to toggle. Map calls invalidateSize() on toggle.
   - Calibration page stacks: device list on top (35vh, internal scroll),
     detail panel below.
*/
@media (max-width: 768px) {
  header {
    flex-wrap: wrap;
    gap: 0.5rem 0.75rem;
  }
  .page-nav {
    flex: 0 0 auto;
  }
  /* #status row on the live dashboard wraps cleanly */
  #status {
    flex: 1 0 100%;
    flex-wrap: wrap;
    font-size: 0.8rem;
  }
  /* Live dashboard: map + collapsible drops panel.
     Map flex-grows to fill any space the panel doesn't take, so collapsing
     the panel makes the map larger without leaving dead area. */
  main:not(.cal-main) {
    flex-direction: column;
  }
  main:not(.cal-main) #map {
    width: 100%;
    flex: 1 1 0;
    min-height: 50vh;
    min-height: 50dvh; /* stable vs iOS Safari URL-bar show/hide */
  }
  #side-panel {
    width: 100%;
    border-left: none;
    border-top: 1px solid #333;
    /* `0 0 auto` so the panel sizes to its content (capped by max-height)
       and never grows past it — the map gets all the leftover room. */
    flex: 0 0 auto;
    padding: 0;
    overflow: hidden;
    max-height: 40vh;
    max-height: 40dvh;
    transition: max-height 0.25s ease;
  }
  #side-panel.collapsed {
    max-height: 2.75rem;
  }
  /* Tail control: shrink to fit narrow viewports. The IC still needs to
     read the tail number at a glance, but on a 360px screen we can't
     afford 22rem. */
  .tail-control {
    min-width: 11rem;
    max-width: calc(100vw - 4rem);
    padding: 0.4rem 0.5rem;
  }
  .tail-control .tail-label {
    font-size: 0.65rem;
  }
  .tail-control select {
    font-size: 0.85rem;
    padding: 0.3rem 1.4rem 0.3rem 0.4rem;
  }
  .tail-control .tail-meta {
    font-size: 0.68rem;
  }
  .panel-toggle {
    padding: 0.65rem 1rem;
    margin: 0;
    background: #2a2a2a;
    border-bottom: 1px solid #333;
    cursor: pointer;
  }
  .panel-toggle:active {
    background: #333;
  }
  .panel-chevron {
    display: inline-block;
  }
  #side-panel.collapsed .panel-chevron {
    transform: rotate(-90deg);
  }
  #panel-body {
    overflow-y: auto;
    height: calc(40vh - 2.75rem);
    height: calc(40dvh - 2.75rem);
    padding: 0.5rem 1rem;
  }
  /* Calibration page: stacked device-list / detail layout */
  .cal-main {
    flex-direction: column;
    overflow: auto;
    min-height: 0;
  }
  #device-list-panel {
    width: 100%;
    border-right: none;
    border-bottom: 1px solid #333;
    max-height: 35vh;
    max-height: 35dvh;
    flex: 0 0 auto;
  }
  #cal-detail {
    flex: 1 1 auto;
    padding: 0.75rem 1rem;
  }
  .cal-meta {
    /* Stack header info + download button vertically on narrow screens. */
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.4rem;
  }
  .meta-grid {
    grid-template-columns: max-content 1fr;
    gap: 0.1rem 0.5rem;
    width: 100%;
  }
  .cal-section {
    padding: 0.5rem;
    margin: 0.5rem 0 1rem 0;
  }
  .cal-section h3 {
    font-size: 0.85rem;
  }
  .cal-table th,
  .cal-table td {
    padding: 0.15rem 0.5rem;
  }
}

/* ===========================================================================
   Mobile hardening — appended 2026-05-17 (do not fold into the 389-516 block).
   Adds small-phone + landscape tiers, iOS-safe tap targets, safe-area insets,
   and the calibration table -> stacked-card transform. Cross-page (style.css)
   lane; live-page structural CSS lives inline in index.html.
   =========================================================================== */

/* --- Shared mobile: ≥44px touch targets, no iOS zoom-on-focus, safe-area --- */
@media (max-width: 768px) {
  /* Notch / rounded-corner safe area for every page's header. */
  header {
    padding-top: calc(0.5rem + env(safe-area-inset-top));
    padding-left: calc(1rem + env(safe-area-inset-left));
    padding-right: calc(1rem + env(safe-area-inset-right));
  }
  /* 16px+ font on any control stops iOS Safari auto-zooming on focus. */
  select,
  input,
  button,
  textarea {
    font-size: 1rem;
  }
  /* Apple HIG / Material minimum hit area. */
  .page-nav a {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    padding: 0.5rem 0.85rem;
  }
  .ping-btn {
    min-height: 44px;
    padding: 0.5rem 1rem;
  }
  #status select {
    min-height: 44px;
    padding: 0.4rem 0.6rem;
  }
  #drop-list li {
    padding: 0.7rem 0.6rem;
  }
  /* Calibration device list: bigger tap rows. */
  .device-card {
    min-height: 44px;
    padding: 0.7rem 0.7rem;
  }
}

/* --- Landscape phones: the map matters most here; give it more height --- */
@media (max-width: 768px) and (orientation: landscape) {
  main:not(.cal-main) #map {
    min-height: 78vh;
    min-height: 78dvh;
  }
  #side-panel {
    max-height: 60vh;
    max-height: 60dvh;
  }
  #panel-body {
    height: calc(60vh - 2.75rem);
    height: calc(60dvh - 2.75rem);
  }
  /* Calibration: device list shorter so the detail pane is reachable. */
  #device-list-panel {
    max-height: 30vh;
    max-height: 30dvh;
  }
}

/* --- Small phones (≤480): calibration tables become stacked cards --------- */
@media (max-width: 480px) {
  header h1 {
    font-size: 1rem;
  }
  /* Each .cal-table row becomes a label/value card. cal.js tags every <td>
     with data-col="<header>"; the ::before surfaces that as the row label so
     no <thead> is needed on a phone. DOM shape is unchanged (desktop intact). */
  .cal-table,
  .cal-table tbody,
  .cal-table tr,
  .cal-table td {
    display: block;
    width: 100%;
  }
  .cal-table thead {
    display: none;
  }
  .cal-table tr {
    margin-bottom: 0.5rem;
    border: 1px solid #333;
    border-radius: 4px;
    overflow: hidden;
  }
  .cal-table td {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    text-align: right;
    border: none;
    border-bottom: 1px solid #2a2a2a;
    padding: 0.45rem 0.7rem;
  }
  .cal-table td:last-child {
    border-bottom: none;
  }
  .cal-table td::before {
    content: attr(data-col);
    color: #888;
    font-weight: 600;
    text-align: left;
  }
  .cal-table td.empty-row {
    justify-content: center;
  }
  .cal-table td.empty-row::before {
    content: none;
  }
}

/* --- iPhone-SE-class final tightening (≤400) ------------------------------ */
@media (max-width: 400px) {
  header h1 {
    font-size: 0.95rem;
    letter-spacing: 0.02em;
  }
  .page-title {
    width: 100%;
  }
  .page-nav a {
    padding: 0.5rem 0.6rem;
    font-size: 0.8rem;
  }
}
