/* ═══════════════════════════════════════════════════════════
   Design tokens
   All colour, radius, and spacing values live here so both
   the internal dashboard and client status views stay in sync.
   ═══════════════════════════════════════════════════════════ */

/* The Squadron wordmark's face, served by us rather than fetched from a third
   party on every page load. A render-blocking cross-origin stylesheet for one
   decorative word puts first paint on someone else's uptime, and an extension
   that blocks that host stalls it: caddis-www lost five seconds to exactly this
   (caddis-www#6). Latin subset only, which is all "SQUADRON" needs, at 9,968
   bytes -- less than the request it replaces. See static/fonts/README.md. */
@font-face {
  font-family: 'Chakra Petch';
  font-style: normal;
  font-weight: 600;
  /* Same swap the Google stylesheet asked for: draw in the fallback first and
     repaint when the face lands, rather than holding the header blank. */
  font-display: swap;
  src: url("../fonts/chakra-petch-600-latin.27489a499469.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  --bg-page:        #0f1117;
  --bg-card:        #1c1f2e;
  --bg-subtle:      rgba(255, 255, 255, 0.04);
  --border-default: rgba(255, 255, 255, 0.07);
  --border-hover:   rgba(99, 179, 237, 0.4);
  --text-primary:   #e2e8f0;
  --text-secondary: #8892a4;

  /* The caddis fly mark's lightest blue (#3f95c5) lifted until it carries text.
     Against the #303030 navbar the mark's own blue manages 3.97:1, under the
     4.5:1 WCAG AA asks for; this reads 5.78:1. The Squadron wordmark is painted
     in it so the name and the mark beside it read as one lockup. */
  --brand-blue:     #63b3ed;
  --radius-card:    12px;
  --radius-badge:   20px;

  --color-ok:       #48c78e;
  --color-ok-bg:    rgba(72, 199, 142, 0.15);
  --color-ok-border:rgba(72, 199, 142, 0.3);

  --color-warn:     #ffb74d;
  --color-warn-bg:  rgba(255, 183, 77, 0.15);
  --color-warn-border: rgba(255, 183, 77, 0.3);

  --color-crit:     #fc6464;
  --color-crit-bg:  rgba(252, 100, 100, 0.15);
  --color-crit-border: rgba(252, 100, 100, 0.3);

  /* One colour per sensor, so a trend chart and the card that opened it are
     never two different colours for the same measurement. Hue is picked where
     it is free -- warm for temperature, water-blue for clarity, the pink of a
     pH strip, brass for the electrical probe -- and lightness carries the rest,
     which is what keeps them apart for a viewer who cannot separate the hues.
     Each clears 4.7:1 against --bg-card, and the closest pair measures 36.6
     CIELAB dE under simulated deuteranopia and protanopia against the 29 dE bar
     dashboards/basemaps.py sets for the map palette. Changing one of these means
     re-checking both numbers, not just eyeballing it. */
  --sensor-ph:           #c964d8;
  --sensor-temp:         #ba7a5e;
  --sensor-turbidity:    #a9d0da;
  --sensor-conductivity: #c4ab31;

  /* The other two values the conductivity probe reports. These three are the
     only sensor colours ever drawn together, so they are the ones that have to
     be told apart at a glance: every pair clears 35 dE in normal vision and
     under both dichromacies, and 45 dE against the near-white trend line laid
     over them. That is close to the ceiling -- red-green colourblindness folds
     hue onto a single blue-yellow axis, so three categorical colours cannot be
     three unrelated hues -- which is why the chart also gives each line its own
     marker shape rather than resting on colour alone. */
  --sensor-tds:          #b38a61;
  --sensor-salinity:     #7c86c0;

  /* The pond map's field overlay, which answers a different question from the
     --sensor-* colours above: those name WHICH sensor, these name whether the
     water is good. So the map's colour changes with the reading while the
     chart's stays put, and the two never have to agree.

     Deliberately not red-against-green as the two poles. Red-green is the pair
     that collapses under deuteranopia and protanopia, and it is the pair
     carrying the whole signal here. Blue against red survives both, because
     they separate on the blue-yellow axis dichromacy leaves intact. Green is
     kept for the healthy middle, where it is only ever drawn at ~14% alpha and
     means "nothing to look at" -- so the one risky pairing never carries
     information. Good and bad are told apart by saturation before hue. */
  --field-low:  #5b9bd5;
  /* Deliberately not --color-ok, and deliberately not spelled as the route's
     own value either -- dashboards/basemaps.py owns that one, and a copy here
     is exactly what test_no_template_or_static_file_hardcodes... exists to
     stop. The point is the collision: on the dark basemap the run route is a
     vivid green meaning "where the boat went", and at overlay alpha the ok
     green was near enough to it that the field read as more route rather than
     as a reading. This is deeper and cooler, so the two stay separable where
     they overlap. */
  --field-good: #2f8f74;
  --field-high: var(--color-crit);
}


/* ─── Base ───────────────────────────────────────────────── */

/* The root element, not only the body. A transparent root leaves the browser
   painting its own default -- white -- for the moment between one document and
   the next, which is the flash on every navigation that changes the run date.
   color-scheme closes the same gap from the other side: it tells the browser
   the default it should be reaching for is dark, and carries scrollbars and
   form controls with it. */
html {
  background-color: var(--bg-page);
  color-scheme: dark;
}

body {
  background-color: var(--bg-page);
  color: var(--text-primary);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

main {
  flex: 1 1 auto;
}


/* ─── Site header ────────────────────────────────────────── */

/* Three columns around the mark. The side columns are equal so the mark stays
   centred, which also means each side gets only half the leftover width: that is
   why the row folds into the Menu button below lg rather than wrapping its labels.
   Which half shows at which width is Bootstrap's d-* utilities in the template,
   not this file (#127). */
.site-header {
  display: block;  /* Bootstrap's .navbar is a wrapping flex row; this is a grid. */
  flex-shrink: 0;
  padding: 0;
  --bs-navbar-brand-padding-y: 0;
  --bs-navbar-brand-margin-end: 0;
}

.site-header-bar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  column-gap: 1rem;
  min-height: 56px;
  padding: 0 1rem;
}

.site-header-start {
  display: flex;
  align-self: stretch;
  align-items: center;
  min-width: 0;
}

.site-header-end {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.75rem;
  min-width: 0;
}

.site-header-mark {
  display: flex;
  align-items: center;
}

.site-header-mark img {
  display: block;
  width: auto;
  height: 36px;
  object-fit: contain;
}

/* The Squadron wordmark. Squared and letter-spaced so it reads as a name rather
   than as one more label in the bar. */
.navbar-wordmark {
  font-family: 'Chakra Petch', system-ui, -apple-system, 'Segoe UI', sans-serif;
  font-weight: 600;
  font-size: 1rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--brand-blue);
  line-height: 1;
  white-space: nowrap;
  flex-shrink: 0;
  /* Letter-spacing pads the right of the final glyph too, which would leave the
     wordmark short of the bar's edge by that much. */
  margin-right: -0.16em;
}

@media (min-width: 768px) {
  .site-header-bar {
    min-height: 72px;
    padding: 0 1.5rem;
    column-gap: 1.5rem;
  }

  .site-header-mark img {
    height: 52px;
  }

  .navbar-wordmark {
    font-size: 1.2rem;
  }
}

/* Labels never wrap. A two-line "Fleet / Status" is the bug this layout replaced. */
.site-header .nav-link {
  display: flex;
  align-items: center;
  min-height: 44px;
  white-space: nowrap;
  position: relative;
}

.site-header-links {
  align-self: stretch;
  /* Pull the first label's padding back so its text lines up with the bar edge. */
  margin-left: -0.75rem;
}

.site-header-links .nav-link {
  height: 100%;
  padding: 0 0.75rem;
}

/* The current page is told apart by more than brightness: it also gets a bar in
   the brand colour along the header's bottom edge. */
.site-header .nav-link[aria-current="page"] {
  color: var(--bs-navbar-active-color);
}

.site-header-links .nav-link[aria-current="page"]::after {
  content: "";
  position: absolute;
  left: 0.75rem;
  right: 0.75rem;
  bottom: 0;
  height: 3px;
  border-radius: 3px 3px 0 0;
  background: var(--brand-blue);
}

.site-header-menu-button {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 44px;
  padding: 0 0.75rem;
  color: var(--bs-navbar-active-color);
  background: transparent;
  border: 1px solid var(--bs-navbar-toggler-border-color);
  border-radius: 0.5rem;
}

.site-header-menu-button .navbar-toggler-icon {
  width: 1.25rem;
  height: 1.25rem;
}

.site-header-you {
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
}

/* View as is a mode, not a page, so it is a control beside the account rather than
   a link among the pages. It turns the banner's yellow while it is on. */
.site-header-view-as {
  display: inline-flex;
  align-items: center;
  min-width: 0;
  max-width: 13rem;
  min-height: 44px;
  padding: 0 1rem;
  border: 1px solid var(--bs-navbar-toggler-border-color);
  border-radius: 999px;
  /* A <button> in the employee header, where the dark color-scheme would
     otherwise paint the browser's grey button fill behind the label. */
  background: transparent;
  color: var(--bs-navbar-color);
  text-decoration: none;
  white-space: nowrap;
}

/* Cut long customer names here only. The banner under the bar gives the whole name. */
.site-header-view-as span {
  overflow: hidden;
  text-overflow: ellipsis;
}

.site-header-view-as:hover {
  color: var(--bs-navbar-active-color);
  border-color: var(--bs-navbar-active-color);
}

.site-header-view-as.is-on {
  background: var(--bs-warning);
  border-color: var(--bs-warning);
  color: var(--bs-dark);
  font-weight: 700;
}

/* #512's list of customers can be long; it scrolls inside the menu instead. */
.site-header-view-as-menu {
  max-height: 60vh;
  max-width: min(24rem, calc(100vw - 2rem));
  overflow-y: auto;
}

/* A long customer name wraps rather than widening the menu past the screen. */
.site-header-view-as-menu .dropdown-item {
  white-space: normal;
}

.site-header-account {
  display: grid;
  place-items: center;
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1px solid var(--bs-navbar-toggler-border-color);
  border-radius: 50%;
  background: transparent;
  color: var(--bs-navbar-active-color);
  font-size: 0.9rem;
  font-weight: 700;
}

.site-header-who {
  display: grid;
}

/* The inactive links' colour, 5.83:1 on the bar and the menu. --text-secondary
   reads 4.21:1 there, under the 4.5:1 small text needs. */
.site-header-who span {
  color: var(--bs-navbar-color);
  font-size: 0.85rem;
}

.site-header .dropdown-item {
  min-height: 44px;
}

/* Below lg: a full-width list under the bar. Rows are 48px and the whole width of
   the screen, so a thumb cannot miss. */
.site-header-menu {
  border-top: 1px solid var(--bs-navbar-toggler-border-color);
  padding: 0.5rem 0 0.75rem;
}

.site-header-menu .nav-link {
  width: 100%;
  min-height: 48px;
  padding: 0 1.25rem;
  background: none;
  border: 0;
  text-align: left;
}

.site-header-menu .nav-link[aria-current="page"] {
  font-weight: 700;
}

.site-header-menu .nav-link[aria-current="page"]::before {
  content: "";
  position: absolute;
  left: 0;
  top: 10px;
  bottom: 10px;
  width: 4px;
  border-radius: 0 3px 3px 0;
  background: var(--brand-blue);
}

.site-header-menu-section {
  margin-top: 0.5rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--bs-navbar-toggler-border-color);
}

.site-header-menu .site-header-who {
  padding: 0.5rem 1.25rem;
}

/* Bootstrap's own ring is a 25% glow of its blue, which all but vanishes on this
   bar. White reads 13:1 against it, and against every holiday's colour too. */
.site-header a:focus-visible,
.site-header button:focus-visible,
.view-as-banner button:focus-visible,
.site-skip-link:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
  box-shadow: none;
}

.site-skip-link:focus {
  position: absolute;
  top: 0.5rem;
  left: 0.5rem;
  z-index: 1040;
  padding: 0.5rem 1rem;
  border-radius: 0.375rem;
  background: #fff;
  color: #000;
}

/* The sentence takes the spare width and wraps, so the button stays beside it until
   the screen is too narrow for both. */
.view-as-banner > span {
  flex: 1 1 20rem;
  min-width: 0;
}

.view-as-banner .btn {
  min-height: 44px;
}


/* ─── Cards ──────────────────────────────────────────────── */

/* Shared card shell used by both internal and client views */
.section-card {
  background: var(--bg-card);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-card);
  overflow: hidden;
}

.section-card + .section-card {
  margin-top: 0;
}

/* Section header strip inside a card */
.section-header {
  padding: 0.85rem 1.25rem;
  border-bottom: 1px solid var(--border-default);
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* Large metric card (client stat cards + internal summary bar) */
.stat-card {
  background: var(--bg-card);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-card);
  padding: 1.25rem 1.5rem;
  height: 100%;
}

.stat-label {
  font-size: 0.72rem;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: 0.4rem;
}

.stat-value {
  font-size: 2rem;
  font-weight: 700;
  color: var(--text-primary);
  line-height: 1;
}

.stat-unit {
  font-size: 0.9rem;
  color: var(--text-secondary);
  margin-left: 0.2rem;
  font-weight: 400;
}

.stat-sub {
  font-size: 0.78rem;
  color: var(--text-secondary);
  margin-top: 0.5rem;
}


/* ─── Health / status badges ─────────────────────────────── */

.health-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.3rem 0.8rem;
  border-radius: var(--radius-badge);
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  white-space: nowrap;
}

.health-ok   { background: var(--color-ok-bg);   color: var(--color-ok);   border: 1px solid var(--color-ok-border); }
.health-warn { background: var(--color-warn-bg);  color: var(--color-warn); border: 1px solid var(--color-warn-border); }
.health-crit { background: var(--color-crit-bg);  color: var(--color-crit); border: 1px solid var(--color-crit-border); }
.health-none { background: var(--bg-subtle);      color: var(--text-secondary); border: 1px solid var(--border-default); }

/* Compact inline variant for table cells */
.status-pill {
  display: inline-block;
  padding: 0.2rem 0.6rem;
  border-radius: var(--radius-badge);
  font-size: 0.75rem;
  font-weight: 600;
}

.status-ok   { background: var(--color-ok-bg);   color: var(--color-ok); }
.status-warn { background: var(--color-warn-bg);  color: var(--color-warn); }
.status-crit { background: var(--color-crit-bg);  color: var(--color-crit); }
.status-none { background: var(--bg-subtle);      color: var(--text-secondary); }


/* ─── Battery bar ────────────────────────────────────────── */

.battery-bar {
  height: 4px;
  background: rgba(255, 255, 255, 0.08);
  border-radius: 2px;
  margin-top: 0.4rem;
  overflow: hidden;
}

.battery-fill {
  height: 100%;
  border-radius: 2px;
}


/* ─── Tables ─────────────────────────────────────────────── */

.readings-table {
  width: 100%;
  border-collapse: collapse;
}

.readings-table th {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-secondary);
  padding: 0.65rem 1.25rem;
  border-bottom: 1px solid var(--border-default);
  font-weight: 600;
}

.readings-table td {
  padding: 0.65rem 1.25rem;
  font-size: 0.88rem;
  color: #c8d0de;
  border-bottom: 1px solid rgba(255, 255, 255, 0.04);
}

.readings-table tr:last-child td { border-bottom: none; }
.readings-table tr:hover td { background: rgba(255, 255, 255, 0.02); }

/* Bootstrap table overrides to match the design */
.table th {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}


/* ─── Charts ─────────────────────────────────────────────── */

.dashboard-chart {
  min-height: 220px;
}


/* ─── Map ────────────────────────────────────────────────── */

#mapid {
  border-radius: 0 0 var(--radius-card) var(--radius-card);
}


/* ─── Scrollbar (webkit) ─────────────────────────────────── */

::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: var(--bg-page); }
::-webkit-scrollbar-thumb { background: #444; border-radius: 3px; }
