@import url('https://fonts.googleapis.com/css2?family=Quicksand:wght@400;500;600;700&display=swap');

/* Reserves the vertical scrollbar's width up front. Without this, a page
   that starts shorter than the viewport (e.g. dashboard.html before its
   cards/graph data has loaded in) has no scrollbar, then gets one once that
   content pushes the page past viewport height -- shifting the whole page,
   including the full-width header above it, left by the scrollbar's width.
   That's the "header jumps on load" effect; reserving the gutter always
   keeps the content width constant regardless of whether a scrollbar is
   actually showing. */
html {
  scrollbar-gutter: stable;
}

:root {
  --ink: #4a423c;
  --muted: #948a80;
  --accent: #c98a5e;
  --accent-dark: #b3744a;
  --link: #6b87a6;
  --panel-bg: rgba(255, 252, 247, 0.82);
  --panel-border: rgba(255, 255, 255, 0.45);
  --input-bg: rgba(255, 255, 255, 0.65);
  --input-border: rgba(74, 66, 60, 0.16);
  --error: #b45f4d;
}

body {
  font-family: 'Quicksand', system-ui, sans-serif;
  color: var(--ink);
}

h1 {
  font-weight: 700;
  letter-spacing: -0.01em;
}

a {
  color: var(--link);
  text-decoration: none;
}
a:hover { text-decoration: underline; }

/* Translucent glass wrapper used by the simple form pages (login,
   settings, admin) -- named .panel rather than .card since dashboard.html
   already has its own unrelated .card (metric tile) class. */
.panel {
  background: var(--panel-bg);
  border: 1px solid var(--panel-border);
  border-radius: 20px;
  box-shadow: 0 12px 40px rgba(70, 55, 40, 0.18);
  backdrop-filter: blur(14px) saturate(130%);
  -webkit-backdrop-filter: blur(14px) saturate(130%);
}

label {
  color: var(--ink);
  font-weight: 500;
}

input, textarea {
  font-family: inherit;
  color: var(--ink);
  background: var(--input-bg);
  border: 1px solid var(--input-border);
  border-radius: 10px;
  transition: border-color 0.15s, box-shadow 0.15s;
}
input:focus, textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(201, 138, 94, 0.18);
}

button {
  font-family: inherit;
  font-weight: 600;
  background: var(--accent);
  color: #fff;
  border: none;
  border-radius: 999px;
  padding: 0.6rem 1.4rem;
  cursor: pointer;
  transition: background 0.15s, transform 0.1s;
}
button:hover { background: var(--accent-dark); }
button:active { transform: scale(0.98); }

nav a {
  color: var(--muted);
  font-weight: 500;
}
nav a:hover { color: var(--ink); text-decoration: none; }

/* Top banner -- shared by every page behind requireKey() (dashboard,
   settings, data, preferences, admin, pair-usb), so it's the same full-width
   bar site-wide rather than each page's own nav sitting inline at whatever
   width that page's .panel/.container happens to use. */
header {
  background: rgba(255, 252, 247, 0.85);
  backdrop-filter: blur(14px) saturate(130%);
  -webkit-backdrop-filter: blur(14px) saturate(130%);
  border-bottom: 1px solid var(--input-border);
  padding: 0.75rem 1.5rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
header h1 { margin: 0; font-size: 1.1rem; }
header nav a { margin-left: 1.25rem; font-size: 0.9rem; }

.error { color: var(--error); }

/* Firmware-version mismatch banner -- every authenticated page carries an
   empty #firmwareWarning div right after its <header>, populated by
   renderFirmwareWarning() in app.js. Hidden (via the [hidden] attribute)
   until that check actually finds an outdated device. */
#firmwareWarning {
  background: #fef3c7;
  color: #92400e;
  border-bottom: 1px solid #f59e0b;
  padding: 0.6rem 1.5rem;
  font-size: 0.85rem;
  text-align: center;
}

/* SPA shell (shell.html) -- highlights the nav link for whichever view
   router.js just mounted. Pages that aren't part of the shell yet just
   never gain the "active" class, so this is a no-op there. */
header nav a.active { color: var(--ink); font-weight: 600; }

/* Cross-fade between chart redraws in the dashboard view (see
   crossfadeDraw() in views/dashboard-view.js), instead of the chart
   flashing to a blank "Loading…" state on every metric/window switch.
   #chart-wrap is already position:relative (dashboard styles); each drawn
   chart lives in its own absolutely-positioned slide so two can briefly
   overlap while fading. */
.chart-slide { position: absolute; inset: 0; opacity: 1; transition: opacity 0.18s ease; }
.chart-slide-entering, .chart-slide-leaving { opacity: 0; }

/* Brief pulse on a live card's value when refreshLive() updates it in place
   (see views/dashboard-view.js) rather than rebuilding the whole card grid
   every 15s -- a visual cue that something changed, without the value
   snapping into place unannounced. */
@keyframes aerostat-value-pulse { from { opacity: 0.35; } to { opacity: 1; } }
.card .value.pulse { animation: aerostat-value-pulse 0.5s ease-out; }
