/* =========================================================
   Solar Dashboard — modern dark theme
   ========================================================= */
:root {
  --bg-0: #07090d;
  --bg-1: #0d1118;
  --bg-2: #11161f;
  --card: linear-gradient(180deg, rgba(255,255,255,0.025), rgba(255,255,255,0.01)) ,#11161f;
  --card-border: rgba(255,255,255,0.07);
  --card-border-hover: rgba(255,255,255,0.14);

  --text: #e6edf3;
  --muted: #8b94a3;
  --muted-2: #6b7280;
  --accent: #60a5fa;

  --pv: #fbbf24;       /* amber/yellow */
  --pv-glow: rgba(251,191,36,0.45);
  --house: #60a5fa;    /* blue */
  --house-glow: rgba(96,165,250,0.4);
  --grid: #f87171;     /* red */
  --grid-glow: rgba(248,113,113,0.45);
  --batt: #34d399;     /* green */
  --batt-glow: rgba(52,211,153,0.45);

  --good: #22c55e;
  --good-soft: rgba(34,197,94,0.15);
  --bad: #ef4444;
  --warn: #f59e0b;

  --shadow-sm: 0 1px 2px rgba(0,0,0,0.3);
  --shadow-md: 0 4px 16px rgba(0,0,0,0.35);
  --shadow-lg: 0 12px 40px rgba(0,0,0,0.45);

  --radius-sm: 10px;
  --radius:    14px;
  --radius-lg: 18px;
}

* { box-sizing: border-box; }

html, body {
  margin: 0; padding: 0;
  background:
    radial-gradient(ellipse 80% 60% at 20% -10%, rgba(96,165,250,0.10), transparent 60%),
    radial-gradient(ellipse 70% 50% at 110% 20%, rgba(251,191,36,0.08), transparent 60%),
    radial-gradient(ellipse 60% 50% at 50% 100%, rgba(52,211,153,0.05), transparent 70%),
    var(--bg-0);
  background-attachment: fixed;
  color: var(--text);
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto, sans-serif;
  font-size: 14px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Prevent the iPhone's "tap highlight" grey flash on every interactive
     element; we already have proper :hover/:active states. */
  -webkit-tap-highlight-color: transparent;
  /* Don't let iOS auto-zoom text when the device rotates to landscape. */
  -webkit-text-size-adjust: 100%;
          text-size-adjust: 100%;
  /* Avoid the rubber-band overscroll background bleed-through when the user
     pulls past the top/bottom — keeps the dark theme edge-to-edge. */
  overscroll-behavior-y: contain;
}

/* Most form fields scale fine, but Safari zooms the viewport whenever a
   focused input has font-size < 16px. Force 16px on text-like inputs only
   (date pickers, number, password, etc.) so a tap on a filter doesn't suddenly
   resize the layout. */
input[type="text"], input[type="number"], input[type="password"],
input[type="email"], input[type="search"], input[type="date"],
input[type="tel"], select, textarea {
  font-size: 16px;
}

/* Re-enable forwarding the iOS rubber-band on the body (we contained it on
   <html>); useful when long tab-panels need to scroll naturally. */
body { overscroll-behavior-y: auto; }

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

.muted { color: var(--muted); }
.small { font-size: 12px; }

/* =========================================================
   TOP BAR
   ========================================================= */
.topbar {
  width: 100%;
  box-sizing: border-box;
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 24px;
  background: #0d1118;
  border-bottom: 1px solid rgba(255,255,255,0.08);
}
.brand { display: flex; align-items: center; gap: 12px; }
.brand .logo {
  display: inline-flex;
  width: 34px; height: 34px;
  align-items: center; justify-content: center;
  border-radius: 10px;
  background: linear-gradient(135deg, #fbbf24, #f59e0b);
  color: #1c1300;
  font-size: 20px;
  box-shadow: 0 6px 20px rgba(251,191,36,0.35);
}
.brand h1 { margin: 0; font-size: 17px; font-weight: 700; letter-spacing: 0.2px; }

/* ----- Topbar action buttons (right side) -----
   Two pills: Definições (gear → /2fa.html) and Terminar sessão (power). Same
   shape as the legacy .tick chips so the visual rhythm of the bar stays. */
.topbar-actions { display: flex; align-items: center; gap: 10px; }
.topbar-btn {
  display: inline-flex; align-items: center; gap: 8px;
  background: rgba(255,255,255,0.04);
  border: 1px solid var(--card-border);
  padding: 8px 14px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  text-decoration: none;
  transition: background 150ms ease, border-color 150ms ease, color 150ms ease;
  cursor: pointer;
}
.topbar-btn:hover {
  background: rgba(255,255,255,0.08);
  border-color: var(--card-border-hover);
  text-decoration: none;
}
.topbar-btn-icon { font-size: 14px; line-height: 1; }
.topbar-btn-label { white-space: nowrap; }
.topbar-btn-logout {
  color: var(--bad);
  border-color: rgba(248,113,113,0.25);
}
.topbar-btn-logout:hover {
  background: rgba(248,113,113,0.12);
  border-color: rgba(248,113,113,0.45);
  color: var(--bad);
}

.dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; box-shadow: 0 0 0 0 currentColor; }
.dot-on   { background: var(--good); box-shadow: 0 0 12px var(--good); animation: pulse 1.6s ease-in-out infinite; }
.dot-off  { background: var(--bad);  box-shadow: 0 0 10px var(--bad); }
.dot-warn { background: var(--warn); box-shadow: 0 0 10px var(--warn); }

@keyframes pulse {
  0%,100% { opacity: 1; transform: scale(1); }
  50%     { opacity: 0.55; transform: scale(0.85); }
}

/* =========================================================
   LAYOUT
   ========================================================= */
main {
  max-width: 1380px;
  margin: 0 auto;
  padding: 22px;
  display: grid;
  gap: 20px;
}

.grid { display: grid; gap: 18px; }
.grid-live          { grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr); }
.grid-2             { grid-template-columns: 1fr 1fr; }
/* When grid-2 holds an odd number of direct cards (e.g. 5 charts on Tab 4),
   the last one would sit alone at half-width with empty space beside it.
   Span it across both columns so the last row reads as a full-width strip. */
.grid-2 > .card:last-child:nth-child(odd) { grid-column: 1 / -1; }
.grid-kpis          { grid-template-columns: repeat(4, 1fr); }
.grid-energy-kpis   { grid-template-columns: repeat(6, 1fr); }
.grid-omie          { grid-template-columns: repeat(4, minmax(0, 1fr)); }
/* On desktop the 4 OMIE cards sit in one row. Group them by DAY (Hoje on
   the left half, Amanhã on the right half) instead of by TYPE — easier to
   compare today vs tomorrow at a glance. Mobile keeps DOM order (2×2 grid
   reading: simples row first, bi-horário row second) because the user
   confirmed that's the layout they prefer at narrow widths. */
@media (min-width: 721px) {
  .grid-omie [data-omie="today-simples"]    { order: 1; }
  .grid-omie [data-omie="today-bi"]         { order: 2; }
  .grid-omie [data-omie="tomorrow-simples"] { order: 3; }
  .grid-omie [data-omie="tomorrow-bi"]      { order: 4; }
}

.card {
  background: var(--card);
  border: 1px solid var(--card-border);
  border-radius: var(--radius);
  padding: 18px 20px;
  box-shadow: var(--shadow-md);
  transition: border-color 200ms ease, transform 200ms ease;
}
.card:hover { border-color: var(--card-border-hover); }

.card-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 14px;
  gap: 12px;
}
.card-head h2 {
  margin: 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.7px;
}
.card-head h3 { margin: 0; font-size: 13px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.5px; font-weight: 600; }

/* =========================================================
   FLOW DIAGRAM (SVG)
   ========================================================= */
.card-flow { padding-bottom: 14px; }
.flow-wrap { width: 100%; }
.flow-svg  { width: 100%; height: auto; max-height: 420px; display: block; }

.flow-svg .track {
  stroke: rgba(255,255,255,0.05);
  stroke-width: 2;
  stroke-linecap: round;
}
/* "Dots flowing" animation: stroke-dasharray with a near-zero dash length
   combined with stroke-linecap:round renders as discrete circles travelling
   along the path. Way smoother than rectangular dashes. */
.flow-svg .flow {
  stroke: rgba(255,255,255,0.95);
  stroke-width: 5;
  stroke-linecap: round;
  stroke-dasharray: 0.01 18;
  animation: flow-dots 1.6s linear infinite;
  filter: drop-shadow(0 0 6px rgba(255,255,255,0.4));
  transition: stroke 220ms ease, opacity 220ms ease;
}
.flow-svg .flow.off    { opacity: 0; }
.flow-svg .flow.color-pv   { stroke: var(--pv);    filter: drop-shadow(0 0 6px var(--pv-glow)); }
.flow-svg .flow.color-grid { stroke: var(--grid);  filter: drop-shadow(0 0 6px var(--grid-glow)); }
.flow-svg .flow.color-batt { stroke: var(--batt);  filter: drop-shadow(0 0 6px var(--batt-glow)); }
.flow-svg .flow.reverse { animation-direction: reverse; }
@keyframes flow-dots { to { stroke-dashoffset: -36; } }

.flow-svg .node circle {
  fill: var(--bg-1);
  stroke: rgba(255,255,255,0.18);
  stroke-width: 2;
  transition: stroke 200ms ease, filter 200ms ease;
}
.flow-svg .node-pv   circle { stroke: var(--pv);   filter: drop-shadow(0 0 16px var(--pv-glow)); }
.flow-svg .node-house circle{ stroke: var(--house);filter: drop-shadow(0 0 16px var(--house-glow)); }
.flow-svg .node-grid circle { stroke: var(--grid); filter: drop-shadow(0 0 16px var(--grid-glow)); }
.flow-svg .node-batt circle { stroke: var(--batt); filter: drop-shadow(0 0 16px var(--batt-glow)); }

/* SVG icons inside each node — colour comes from the parent .node-* via currentColor */
.flow-svg .node-pv    { color: var(--pv); }
.flow-svg .node-house { color: var(--house); }
.flow-svg .node-grid  { color: var(--grid); }
.flow-svg .node-batt  { color: var(--batt); }

.flow-svg .node-label {
  font-size: 9px; text-anchor: middle; fill: var(--muted);
  text-transform: uppercase; letter-spacing: 1.6px; font-weight: 700;
}
.flow-svg .node-value {
  text-anchor: middle;
  font-family: 'JetBrains Mono', monospace;
  font-size: 17px;
  font-weight: 700;
  fill: var(--text);
}
.flow-svg .node-pv    .node-value { fill: var(--pv); }
.flow-svg .node-house .node-value { fill: var(--house); }
.flow-svg .node-grid  .node-value { fill: var(--grid); }
.flow-svg .node-batt  .node-value { fill: var(--batt); }

/* SoC% inside the battery icon. The text is rendered TWICE in two layers:
     • `.node-soc`     → green base, always visible everywhere
     • `.node-soc-inv` → dark overlay, clipped to the green-fill rect so it
       only shows on top of the fill, "punching out" the digits
   The visual result: characters over the fill appear in card-background
   dark, characters over the empty side stay battery-green — contrast is
   preserved at any SoC, character-by-character. */
.flow-svg .node-soc {
  text-anchor: middle;
  dominant-baseline: central;
  font-family: 'JetBrains Mono', monospace;
  font-size: 13px;
  font-weight: 800;
  fill: var(--batt);
}
.flow-svg .node-soc-inv {
  fill: var(--bg-2);
}

/* Smooth the battery fill animation. SVG `width` is a CSS geometry property
   in modern browsers, so a CSS transition tweens the attribute between
   updates (default WS push cadence) instead of snapping. Both the visible
   fill rect and its matching clip rect (used to mask the dark overlay text)
   transition together so the per-character contrast follows the bar edge
   smoothly. */
.flow-svg #bat-fill,
#bat-fill-clip-rect {
  transition: width 600ms cubic-bezier(0.25, 0.1, 0.25, 1);
}

/* Splits row under flow */
.splits {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 8px;
  margin-top: 14px;
}
.split {
  background: rgba(255,255,255,0.03);
  border: 1px solid var(--card-border);
  border-radius: var(--radius-sm);
  padding: 9px 10px;
  display: flex; flex-direction: column; gap: 3px;
  text-align: left;
  transition: border-color 200ms ease, background 200ms ease;
}
.split-label { font-size: 10px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.6px; font-weight: 600; }
.split-value { font-family: 'JetBrains Mono', monospace; font-size: 14px; font-weight: 700; }
.split-pv .split-value   { color: var(--pv); }
.split-batt .split-value { color: var(--batt); }
.split-grid .split-value { color: var(--grid); }
.split.dim { opacity: 0.4; }

/* =========================================================
   HERO CARDS
   ========================================================= */
.hero-stack { display: flex; flex-direction: column; gap: 18px; }
.hero { position: relative; overflow: hidden; padding: 22px 22px 8px; }
.hero-savings {
  background:
    radial-gradient(ellipse at top right, rgba(34,197,94,0.20), transparent 60%),
    var(--card);
  border-color: rgba(34,197,94,0.25);
}
.hero-spent {
  background:
    radial-gradient(ellipse at top right, rgba(245,158,11,0.20), transparent 60%),
    var(--card);
  border-color: rgba(245,158,11,0.25);
}
.hero-spent .hero-value { color: var(--warn); }
.hero-rates {
  background:
    radial-gradient(ellipse at top right, rgba(96,165,250,0.18), transparent 60%),
    var(--card);
}
.hero-label {
  font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.7px; font-weight: 600;
}
.hero-value {
  font-family: 'JetBrains Mono', monospace;
  font-size: 44px; font-weight: 800;
  margin: 6px 0 4px;
  color: var(--good);
  line-height: 1.1;
}
.hero-sub { font-size: 12px; color: var(--muted); }
.hero-spark { display: block; width: 100%; height: 60px; margin-top: 6px; }

.rates-row {
  display: grid; grid-template-columns: 1fr 1fr; gap: 16px;
  margin-bottom: 4px;
}
.rate-label { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.7px; font-weight: 600; }
.rate-value {
  font-family: 'JetBrains Mono', monospace;
  font-size: 26px; font-weight: 700; line-height: 1.1; margin-top: 6px;
}
.rate-value.cost { color: var(--grid); }
.rate-value.sale { color: var(--good); }

/* =========================================================
   KPI CARDS (today)
   ========================================================= */
.grid-kpis .kpi {
  background: var(--card);
  border: 1px solid var(--card-border);
  border-radius: var(--radius);
  padding: 16px 18px;
  display: flex; align-items: center; gap: 14px;
  box-shadow: var(--shadow-sm);
  transition: border-color 200ms ease;
}
.grid-kpis .kpi:hover { border-color: var(--card-border-hover); }
.kpi-icon {
  width: 42px; height: 42px;
  flex: 0 0 auto;
  border-radius: 12px;
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 18px;
  font-family: 'JetBrains Mono', monospace;
}
.kpi-icon-gross { background: rgba(248,113,113,0.15); color: var(--grid); }
.kpi-icon-real  { background: rgba(245,158,11,0.15); color: var(--warn); }
.kpi-icon-sale  { background: rgba(34,197,94,0.15);  color: var(--good); }
.kpi-icon-net   { background: rgba(96,165,250,0.15); color: var(--house); }
.kpi-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.kpi-label { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.7px; font-weight: 600; }
.kpi-value { font-family: 'JetBrains Mono', monospace; font-size: 22px; font-weight: 800; }
.kpi-sub   { font-size: 11px; color: var(--muted); }

/* Bigger variant for the Contas tab (where these cards are the headline row,
   not a strip squeezed under the live flow). Vertical spacing comes from the
   tab-panel's own `gap` — don't add margin here or it doubles up. */
.grid-kpis-lg { gap: 20px; }
.grid-kpis-lg .kpi {
  padding: 22px 26px;
  gap: 18px;
  border-radius: var(--radius-lg);
}
.grid-kpis-lg .kpi-icon { width: 56px; height: 56px; font-size: 22px; border-radius: 14px; }
.grid-kpis-lg .kpi-label { font-size: 12px; }
.grid-kpis-lg .kpi-value { font-size: 30px; }
.grid-kpis-lg .kpi-sub   { font-size: 12px; }

/* =========================================================
   OMIE QUICK CARDS (Tarifário tab header)
   Four cards in a row: simples-hoje, simples-amanhã, bi-hoje, bi-amanhã.
   Each card shows a type label, a day pill, and either one big value
   (simples) or two side-by-side values (bi-horário vazio/fora-vazio).
   ========================================================= */
.omie-card {
  padding: 16px 18px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
}
.omie-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.omie-type {
  font-size: 11px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.7px;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
  flex: 1 1 auto;
}
.omie-day { flex: 0 0 auto; }
.omie-day {
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  padding: 3px 9px;
  border-radius: 999px;
  background: rgba(96,165,250,0.15);
  color: var(--house);
  border: 1px solid rgba(96,165,250,0.25);
}
.omie-card.omie-bi .omie-day {
  background: rgba(52,211,153,0.15);
  color: var(--good);
  border-color: rgba(52,211,153,0.25);
}
/* Stacking order inside every OMIE card (top → bottom):
     head → date → value(s) → [min/max for simples]
   The date sits flush under the head so it lines up vertically across all
   four cards. `margin-top: auto` on the value (or the bi-values wrapper)
   pushes the main number(s) down to fill the remaining space, which keeps
   the visual rhythm consistent regardless of how much content sits below. */
.omie-value {
  font-family: 'JetBrains Mono', monospace;
  font-size: 26px;
  font-weight: 800;
  color: var(--text);
  line-height: 1.05;
  margin-top: auto;
}
.omie-date {
  font-size: 11px;
  color: var(--muted);
  /* Pull the date slightly closer to the head — the card's default flex gap
     leaves too much breathing room and the date felt disconnected from the
     OMIE title above. */
  margin-top: -6px;
}
.omie-bi-values {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: auto;
}
.omie-bi-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  min-width: 0;
}
.omie-bi-label {
  font-size: 11px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.7px;
  font-weight: 700;
}
.omie-bi-value {
  font-family: 'JetBrains Mono', monospace;
  font-size: 22px;
  font-weight: 800;
  color: var(--text);
  white-space: nowrap;
}

/* Max/Min strip below the simples value — two pills, label inline with value,
   colour-coded (red = max, green = min) to match Tiago Felícia's OMIE widget. */
.omie-minmax {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
  margin-top: 4px;
}
.omm {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 6px;
  padding: 5px 8px;
  border-radius: 8px;
  background: rgba(255,255,255,0.025);
  border: 1px solid var(--card-border);
  min-width: 0;
}
.omm-label {
  font-size: 9.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--muted);
}
.omm-value {
  font-family: 'JetBrains Mono', monospace;
  font-size: 12.5px;
  font-weight: 700;
  white-space: nowrap;
}
.omm-max .omm-value { color: var(--bad); }
.omm-min .omm-value { color: var(--good); }

/* "Aguarda publicação OMIE" hint shown when tomorrow's prices aren't out yet
   (before ~14:30 local time). When this is visible, hide the placeholder
   values so the user doesn't see two contradictory readouts. */
.omie-empty {
  font-size: 11px;
  color: var(--muted);
  text-align: center;
  padding: 8px 6px;
  border-radius: 8px;
  background: rgba(245,158,11,0.08);
  border: 1px dashed rgba(245,158,11,0.25);
  /* When `.omie-no-data` hides every other body element, this is the only
     visible content under the head — `margin: auto 0` centres it vertically
     in the remaining card space. */
  margin: auto 0;
}
.omie-card.omie-no-data .omie-value,
.omie-card.omie-no-data .omie-date,
.omie-card.omie-no-data .omie-minmax,
.omie-card.omie-no-data .omie-bi-values { display: none; }

/* =========================================================
   OMIP FUTUROS TABLE (Tarifário tab)
   Three side-by-side tables (Diários / Semanais / Mensais) showing the
   futures contracts from the OMIP MIBEL feed. Each row: descrição, valor
   in €/MWh, variação as an up/down arrow + signed delta. Stacks vertically
   on mobile.
   ========================================================= */
.omip-card .card-head { align-items: center; }
.omip-tables {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 18px;
}
.omip-section {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
}
.omip-section-head {
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--muted);
  padding: 0 0 6px;
  border-bottom: 1px solid var(--card-border);
}
.omip-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}
.omip-table th, .omip-table td {
  padding: 7px 8px;
  border-bottom: 1px solid rgba(255,255,255,0.04);
  text-align: left;
}
.omip-table thead th {
  font-size: 10.5px;
  font-weight: 700;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.4px;
  background: transparent;
  position: static;
}
.omip-table th.num, .omip-table td.num { text-align: right; }
.omip-unit { color: var(--muted); font-weight: 500; font-size: 10px; }
.omip-table tbody td { font-weight: 600; }
.omip-value { font-family: 'JetBrains Mono', monospace; }
.omip-var {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px;
}
.omip-var-up    { color: var(--good); }
.omip-var-down  { color: var(--bad); }
.omip-var-equal { color: var(--muted); }
.omip-arrow {
  display: inline-block;
  width: 0; height: 0;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
}
.omip-var-up .omip-arrow    { border-bottom: 7px solid var(--good); }
.omip-var-down .omip-arrow  { border-top:    7px solid var(--bad); }
.omip-var-equal .omip-arrow {
  border: none;
  width: 8px; height: 2px;
  background: var(--muted);
}
.omip-empty {
  padding: 14px;
  text-align: center;
  color: var(--muted);
  font-size: 13px;
}

/* =========================================================
   OMIE PERIOD AVERAGE CALCULATOR (Tarifário tab, bottom card)
   Date range + Calcular button on top, three result rows below
   (Simples / Bi-horário Vazio / Bi-horário Fora-vazio).
   ========================================================= */
.omie-avg-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 14px;
  margin-bottom: 16px;
}
.omie-avg-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.4px;
}
.omie-avg-field input[type="date"] {
  background: rgba(255,255,255,0.04);
  border: 1px solid var(--card-border);
  color: var(--text);
  border-radius: 10px;
  padding: 10px 12px;
  font-size: 14px;
  font-family: inherit;
  outline: none;
  transition: border-color 200ms ease;
  color-scheme: dark;
  min-width: 160px;
}
.omie-avg-field input[type="date"]:focus { border-color: var(--accent); }
.omie-avg-controls .btn { padding: 10px 18px; }

.omie-avg-results {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.omie-avg-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 10px 14px;
  background: rgba(255,255,255,0.03);
  border: 1px solid var(--card-border);
  border-radius: 10px;
}
.omie-avg-label {
  color: var(--muted);
  font-size: 13.5px;
}
.omie-avg-value {
  font-family: 'JetBrains Mono', monospace;
  font-weight: 700;
  font-size: 16px;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.omie-avg-meta { margin-top: 4px; }

/* energy KPI strip (kWh) */
.grid-energy-kpis .ek {
  background: rgba(255,255,255,0.03);
  border: 1px solid var(--card-border);
  border-radius: var(--radius-sm);
  padding: 12px 14px;
}
.ek-label { font-size: 10px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.7px; font-weight: 600; }
.ek-value { font-family: 'JetBrains Mono', monospace; font-size: 18px; font-weight: 700; margin-top: 4px; }

/* =========================================================
   CHART CARDS
   ========================================================= */
.chart-h300 { height: 300px; position: relative; }
.chart-h280 { height: 280px; position: relative; }

.mix-wrap { display: grid; grid-template-columns: 1fr 200px; gap: 16px; align-items: center; }
.mix-legend { display: flex; flex-direction: column; gap: 12px; }
.mix-row { display: flex; align-items: center; gap: 10px; }
.mix-swatch { width: 12px; height: 12px; border-radius: 3px; flex-shrink: 0; }
.mix-text { display: flex; flex-direction: column; gap: 2px; }
.mix-name { font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.5px; }
.mix-val  { font-family: 'JetBrains Mono', monospace; font-weight: 700; font-size: 14px; }

.chart-card {
  background: var(--card);
  border: 1px solid var(--card-border);
  border-radius: var(--radius);
  padding: 16px;
}
.chart-card h3 { margin: 0 0 10px; font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.6px; }

/* =========================================================
   PERIOD CARDS
   ========================================================= */
.period-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 14px;
}
.period-card {
  background: rgba(255,255,255,0.03);
  border: 1px solid var(--card-border);
  border-radius: var(--radius);
  padding: 16px;
  display: flex; flex-direction: column; gap: 10px;
  transition: border-color 200ms ease, transform 200ms ease;
}
.period-card:hover { border-color: var(--card-border-hover); transform: translateY(-2px); }
.period-title { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.7px; font-weight: 700; }

/* Big number = either net savings (green) or net cost (red). The label above
   changes in lockstep so the user sees instantly whether they're winning or paying. */
.period-big-label {
  font-size: 10px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.7px;
  font-weight: 700;
  margin-top: -2px;
}
.period-big {
  font-family: 'JetBrains Mono', monospace;
  font-size: 26px;
  font-weight: 800;
  line-height: 1.1;
}
.period-big-good { color: var(--good); }
.period-big-bad  { color: var(--grid); }
.period-rows { display: grid; grid-template-columns: 1fr auto; gap: 4px 10px; font-size: 12px; }
.period-rows .lbl { color: var(--muted); }
.period-rows .val { font-family: 'JetBrains Mono', monospace; font-weight: 600; text-align: right; }

/* =========================================================
   FILTERS / BUTTONS / TABLE
   ========================================================= */
.filters {
  display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end;
  margin-bottom: 18px;
}
.filters label {
  display: inline-flex; flex-direction: column;
  font-size: 10px; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.6px; font-weight: 600;
  gap: 6px;
}
.filters input, .filters select {
  background: rgba(255,255,255,0.04);
  border: 1px solid var(--card-border);
  color: var(--text);
  font-family: inherit;
  outline: none;
  transition: border-color 200ms ease;
}
.filters input:focus, .filters select:focus { border-color: var(--accent); }

/* Unified sizing for every interactive control inside .filters so the row reads
   as a single coherent strip — same height, same radius, same font size. */
.filters input,
.filters select,
.filters .btn {
  height: 38px;
  box-sizing: border-box;
  padding: 0 14px;
  font-size: 13px;
  line-height: 1;
  border-radius: 9px;
}
.filters .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 600;
}

.btn {
  background: rgba(255,255,255,0.06);
  color: var(--text);
  border: 1px solid var(--card-border);
  padding: 9px 14px;
  border-radius: 9px;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  transition: all 150ms ease;
  font-family: inherit;
}
.btn:hover { background: rgba(255,255,255,0.10); border-color: var(--card-border-hover); }
.btn-primary {
  background: linear-gradient(180deg, #3b82f6, #2563eb);
  border-color: rgba(96,165,250,0.4);
  color: #fff;
}
.btn-primary:hover { filter: brightness(1.1); }
.filters .quick { display: inline-flex; gap: 6px; margin-left: auto; flex-wrap: wrap; }

/* Read-only tariff label inside the price-history filter strip — matches the
   visual weight of the inputs without being editable. */
.ph-tariff-readout {
  display: inline-flex;
  align-items: center;
  height: 38px;
  padding: 0 14px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  background: rgba(255,255,255,0.04);
  border: 1px solid var(--card-border);
  border-radius: 9px;
  text-transform: none;
  letter-spacing: 0;
  max-width: 460px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.hist-totals {
  display: flex; gap: 18px; flex-wrap: wrap;
  margin: 14px 0 8px;
  padding: 12px 16px;
  background: rgba(255,255,255,0.03);
  border: 1px solid var(--card-border);
  border-radius: var(--radius-sm);
  font-size: 13px;
}
.hist-totals .ht { display: inline-flex; flex-direction: column; gap: 2px; }
.hist-totals .ht-label { font-size: 10px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.6px; font-weight: 700; }
.hist-totals .ht-value { font-family: 'JetBrains Mono', monospace; font-weight: 700; font-size: 16px; }
.hist-totals .ht.savings .ht-value { color: var(--good); }

.table-wrap { overflow-x: auto; border-radius: var(--radius-sm); border: 1px solid var(--card-border); }
table { width: 100%; border-collapse: collapse; font-size: 13px; }
/* fixed layout: every data column gets the same width regardless of header
   text length. Without this, "EXPORTADO (KWH)" eats space and "VENDA (€)"
   gets squashed. Scoped to the wide energy/cost tables — the tariff history
   on Tab 5 is a different shape, so it keeps natural sizing. */
#hist-table { table-layout: fixed; }
#hist-table th:first-child, #hist-table td:first-child { width: 110px; }
th, td {
  padding: 10px 12px;
  border-bottom: 1px solid var(--card-border);
  text-align: left;
}
th {
  color: var(--muted); font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.5px;
  font-size: 11px;
  background: rgba(255,255,255,0.03);
  position: sticky; top: 0;
}
tbody tr:hover { background: rgba(255,255,255,0.02); }
tbody tr:last-child td { border-bottom: none; }
td.num, th.num { text-align: right; font-family: 'JetBrains Mono', monospace; font-variant-numeric: tabular-nums; }

.foot {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0;
  color: var(--muted);
  font-size: 12px;
  padding: 16px;
}
.foot-conn { display: inline-flex; align-items: center; gap: 6px; }
.sep { opacity: 0.4; margin: 0 6px; }

/* =========================================================
   LOGIN PAGE
   ========================================================= */
.login-body {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}
.login-card {
  width: min(380px, 100%);
  background: var(--card);
  border: 1px solid var(--card-border);
  border-radius: var(--radius-lg);
  padding: 36px 32px 32px;
  box-shadow: var(--shadow-lg);
  text-align: center;
}
.login-logo {
  width: 56px; height: 56px;
  margin: 0 auto 18px;
  border-radius: 14px;
  background: linear-gradient(135deg, #fbbf24, #f59e0b);
  color: #1c1300;
  font-size: 28px;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 10px 28px rgba(251,191,36,0.35);
}
.login-card h1 {
  margin: 0 0 6px;
  font-size: 22px;
  font-weight: 700;
  letter-spacing: 0.1px;
}
.login-sub {
  margin: 0 0 26px;
  color: var(--muted);
  font-size: 13px;
}
.login-card form {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.login-card input[type="password"],
.login-card input[type="text"] {
  background: rgba(255,255,255,0.04);
  border: 1px solid var(--card-border);
  color: var(--text);
  border-radius: 10px;
  padding: 12px 14px;
  font-size: 16px;            /* 16px keeps iOS Safari from auto-zooming */
  font-family: inherit;
  text-align: center;
  outline: none;
  transition: border-color 200ms ease;
}
.login-card input[type="password"]:focus,
.login-card input[type="text"]:focus {
  border-color: var(--accent);
}
/* `:not([hidden])` so the `hidden` HTML attribute actually hides the group.
   Without it, the bare `display: flex` wins over the user-agent's
   `display: none` for `[hidden]`, leaving the TOTP field visible on every
   login page render — even when 2FA isn't configured at all. */
.login-totp:not([hidden]) { display: flex; flex-direction: column; gap: 6px; margin-top: 2px; }
.login-totp input {
  /* Inherit font + size + left alignment from the password input above —
     no overrides needed. Kept as an explicit empty rule for future tweaks. */
}

/* ===== Security / 2FA page (/2fa.html) =====
   Uses the dashboard's regular chrome (topbar + main + footer) instead of the
   login-card style. The card is centred in `main`, sized for comfortable
   reading on desktop but goes full-width on phones (via the existing mobile
   overrides for .card). */
.sec-card {
  max-width: 720px;
  margin: 0 auto;
  width: 100%;
}
/* Same trick as before: `display: flex` (or grid) on author CSS overrides the
   user-agent's `display: none` for `[hidden]`. Constrain the rule with
   `:not([hidden])` so hiding actually works. */
.sec-section:not([hidden]) {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.sec-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}
.sec-actions .btn { min-width: 140px; }
.sec-form {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.sec-form input[type="text"] {
  /* Match the login form: Inter font, centred text, no monospace +
     letter-spacing. Keeps both auth surfaces visually consistent. */
  background: rgba(255,255,255,0.04);
  border: 1px solid var(--card-border);
  color: var(--text);
  border-radius: 10px;
  padding: 12px 14px;
  font-size: 16px;
  font-family: inherit;
  text-align: center;
  outline: none;
  transition: border-color 200ms ease;
}
.sec-form input[type="text"]:focus { border-color: var(--accent); }

/* Backup codes block — shown ONCE after enrolment or regeneration. Two-column
   monospace grid; on mobile collapses to a single column. */
.backup-codes {
  list-style: none;
  padding: 12px 14px;
  margin: 0 0 14px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px 18px;
  background: rgba(255,255,255,0.04);
  border: 1px solid var(--card-border);
  border-radius: 10px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 14px;
}
.backup-codes li {
  margin: 0;
  padding: 4px 0;
  letter-spacing: 1px;
  color: var(--text);
  user-select: all;
}
.backup-codes code {
  font: inherit;
  background: transparent;
}
@media (max-width: 560px) {
  .backup-codes { grid-template-columns: 1fr; }
}

/* Enrolment block: two columns on desktop (instructions left, QR right);
   stacks vertically on phones via the existing .grid-2 mobile rule below. */
.sec-enrol {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 20px;
  align-items: start;
}
.sec-enrol-info { min-width: 0; }
@media (max-width: 560px) {
  .sec-enrol { grid-template-columns: 1fr; }
  .qr-wrap { justify-self: center; }
}

.setup-steps {
  margin: 0 0 14px;
  padding-left: 22px;
  color: var(--text);
  font-size: 14px;
  line-height: 1.6;
}
.setup-steps li { margin-bottom: 4px; }
.qr-wrap {
  background: #fff;
  border-radius: 12px;
  padding: 12px;
  display: flex;
  justify-content: center;
  align-items: center;
}
.qr-wrap svg { width: 240px; height: 240px; max-width: 100%; display: block; }
.setup-manual { font-size: 13px; }
.setup-manual summary { cursor: pointer; color: var(--accent); padding: 6px 0; }
.manual-secret {
  display: block;
  margin-top: 6px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 13px;
  letter-spacing: 0.15em;
  word-break: break-all;
  user-select: all;
  background: rgba(255,255,255,0.05);
  border: 1px solid var(--card-border);
  border-radius: 8px;
  padding: 10px;
}
.status-ok {
  margin: 0;
  padding: 12px 14px;
  background: rgba(34,197,94,0.10);
  border: 1px solid rgba(34,197,94,0.30);
  color: #86efac;
  border-radius: 10px;
  font-size: 14px;
}
.btn-danger {
  background: rgba(248,113,113,0.15);
  border: 1px solid rgba(248,113,113,0.40);
  color: #fca5a5;
}
.btn-danger:hover { background: rgba(248,113,113,0.22); }

.login-submit {
  height: 42px;
  padding: 0 14px;
  font-size: 14px;
  font-weight: 600;
  border-radius: 10px;
}
.login-error {
  margin: 14px 0 0;
  padding: 10px 12px;
  background: rgba(248,113,113,0.10);
  border: 1px solid rgba(248,113,113,0.30);
  color: #fca5a5;
  border-radius: 10px;
  font-size: 13px;
}

/* =========================================================
   TARIFÁRIO CARD
   ========================================================= */
.tariff-card { border-left: 3px solid var(--accent); }

.tariff-current {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 18px;
  align-items: center;
  padding: 8px 0 18px;
  border-bottom: 1px solid var(--card-border);
}
.tariff-current-label {
  font-size: 10px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.8px;
  font-weight: 700;
}
.tariff-current-name {
  font-size: 22px;
  font-weight: 700;
  margin: 4px 0 4px;
  letter-spacing: 0.1px;
}
.tariff-current-since { color: var(--muted); font-size: 13px; }

.tariff-current-prices {
  display: flex;
  gap: 14px;
}
.tprice {
  background: rgba(255,255,255,0.04);
  border: 1px solid var(--card-border);
  border-radius: var(--radius-sm);
  padding: 10px 14px;
  min-width: 130px;
}
.tprice-label { font-size: 10px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.6px; font-weight: 600; }
.tprice-value { font-family: 'JetBrains Mono', monospace; font-weight: 700; font-size: 16px; margin-top: 4px; }

.tariff-history { margin-top: 14px; }
.tariff-history summary {
  cursor: pointer;
  color: var(--muted);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  font-weight: 600;
  padding: 4px 0;
  list-style: none;
  user-select: none;
}
.tariff-history summary::-webkit-details-marker { display: none; }
.tariff-history summary::before { content: "▸ "; opacity: 0.6; }
.tariff-history[open] summary::before { content: "▾ "; }
.tariff-history summary:hover { color: var(--text); }

.kind-pill {
  display: inline-block;
  font-size: 10px;
  text-transform: uppercase;
  font-weight: 700;
  letter-spacing: 0.5px;
  padding: 3px 8px;
  border-radius: 999px;
}
.kind-pill.indexed             { background: rgba(96,165,250,0.18);  color: var(--house); }
.kind-pill.indexed_monthly_avg { background: rgba(52,211,153,0.18);  color: var(--batt); }
.kind-pill.indexed_avg_omie    { background: rgba(34,197,94,0.20);   color: var(--good); }
.kind-pill.fixed_simple        { background: rgba(245,158,11,0.18);  color: var(--warn); }
.kind-pill.fixed_bihorario     { background: rgba(167,139,250,0.20); color: #a78bfa; }

.btn-danger {
  background: rgba(248,113,113,0.15);
  color: var(--grid);
  border-color: rgba(248,113,113,0.3);
}
.btn-danger:hover { background: rgba(248,113,113,0.25); }
.btn-sm { padding: 5px 9px; font-size: 11px; }
.btn-current-active {
  background: rgba(34,197,94,0.15); color: var(--good);
  border-color: rgba(34,197,94,0.3); cursor: default;
}

/* =========================================================
   MODAL (HTML <dialog>)
   ========================================================= */
.modal {
  border: 0;
  padding: 0;
  border-radius: var(--radius-lg);
  background: var(--bg-1);
  color: var(--text);
  width: min(640px, 92vw);
  max-height: 92vh;
  box-shadow: 0 30px 80px rgba(0,0,0,0.6), 0 0 0 1px var(--card-border);
}
.modal::backdrop {
  background: rgba(0,0,0,0.62);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}
.modal[open] {
  animation: modal-in 200ms cubic-bezier(0.2, 0.8, 0.3, 1);
}
@keyframes modal-in {
  from { opacity: 0; transform: translateY(-12px) scale(0.98); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

.modal form { margin: 0; }

.modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px;
  border-bottom: 1px solid var(--card-border);
}
.modal-head h3 {
  margin: 0;
  font-size: 16px;
  font-weight: 700;
}
.modal-close {
  background: transparent;
  border: 0;
  color: var(--muted);
  font-size: 22px;
  cursor: pointer;
  width: 32px; height: 32px;
  border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
}
.modal-close:hover { background: rgba(255,255,255,0.06); color: var(--text); }

.modal-body {
  padding: 18px 20px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  max-height: 70vh;
  overflow-y: auto;
}

.modal-foot {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 14px 20px;
  border-top: 1px solid var(--card-border);
  background: rgba(0,0,0,0.18);
}

.form-group { display: flex; flex-direction: column; gap: 8px; }
.form-label {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 11px;
  color: var(--muted);
  /* Flex children default to `min-width: auto` which equals their intrinsic
     content width — for a <select> that's the longest option. Reset to 0 so
     the child select honours its parent's width instead of pushing past it. */
  min-width: 0;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  font-weight: 600;
}
.form-label input, .form-label select {
  background: rgba(255,255,255,0.05);
  border: 1px solid var(--card-border);
  color: var(--text);
  border-radius: 9px;
  padding: 9px 12px;
  font-size: 14px;
  font-family: inherit;
  outline: none;
  transition: border-color 200ms ease;
  /* `select` natively auto-sizes to its longest <option>. Catalog tariff names
     like "EDP | Eletricidade · Digital · Campanha -20% | DD + FE" easily blow
     past the modal width — force the element to honour its container and clip
     overflowing option text instead. */
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
  text-overflow: ellipsis;
}
.form-label input:focus, .form-label select:focus { border-color: var(--accent); }
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.form-hint { color: var(--muted); font-size: 12px; margin: 4px 0 0; line-height: 1.5; }
.form-hint-inline { color: var(--muted); font-size: 11px; margin-top: -4px; }
.form-divider { border: 0; border-top: 1px solid var(--card-border); margin: 4px 0; }
.form-error {
  background: rgba(248,113,113,0.15);
  color: #fca5a5;
  border: 1px solid rgba(248,113,113,0.3);
  padding: 10px 14px;
  border-radius: 9px;
  font-size: 13px;
}
/* Amber banner used in the tariff modal to surface new monthly-indexed
   tariffs detected in Tiago's XLSX that don't yet have a Python formula. */
.form-banner {
  background: rgba(251,191,36,0.12);
  color: #fbbf24;
  border: 1px solid rgba(251,191,36,0.3);
  padding: 10px 14px;
  border-radius: 9px;
  font-size: 13px;
  margin-bottom: 14px;
}
.form-banner code {
  background: rgba(255,255,255,0.08);
  padding: 1px 5px;
  border-radius: 4px;
  font-size: 12px;
}

.kind-options {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
}
/* When 5+ options, the last one wraps onto its own row — make it span both columns */
.kind-options .kind-option:nth-child(5):last-child {
  grid-column: 1 / -1;
}
.kind-option { cursor: pointer; }
.kind-option input { position: absolute; opacity: 0; pointer-events: none; }
.kind-card {
  border: 1.5px solid var(--card-border);
  border-radius: 10px;
  padding: 10px;
  transition: all 150ms ease;
  background: rgba(255,255,255,0.02);
}
.kind-option:hover .kind-card { border-color: var(--card-border-hover); }
.kind-option input:checked + .kind-card {
  border-color: var(--accent);
  background: rgba(96,165,250,0.10);
}
.kind-title { font-size: 13px; font-weight: 700; margin-bottom: 2px; }
.kind-desc  { font-size: 11px; color: var(--muted); line-height: 1.4; }

.when-options {
  display: flex;
  flex-direction: column;
  gap: 6px;
  background: rgba(255,255,255,0.03);
  border: 1px solid var(--card-border);
  border-radius: 9px;
  padding: 10px 14px;
}
.when-option {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  cursor: pointer;
  padding: 4px 0;
}
.when-option strong { color: var(--text); }
.when-option input[type="date"] {
  background: rgba(255,255,255,0.06);
  border: 1px solid var(--card-border);
  color: var(--text);
  border-radius: 7px;
  padding: 5px 8px;
  font-size: 12px;
  margin-left: 6px;
}

@media (max-width: 640px) {
  .tariff-current { grid-template-columns: 1fr; }
  .tariff-current-prices { flex-wrap: wrap; }
  .kind-options { grid-template-columns: 1fr; }
  .form-row { grid-template-columns: 1fr; }
}

/* =========================================================
   PRICE HISTORY (lookup)
   ========================================================= */
.price-history-card { border-left: 3px solid var(--pv); }

.ph-stats {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 10px;
  margin-bottom: 14px;
}
.ph-stat {
  background: rgba(255,255,255,0.03);
  border: 1px solid var(--card-border);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
}
.ph-stat-label {
  font-size: 10px; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.6px; font-weight: 700;
}
.ph-stat-value {
  font-family: 'JetBrains Mono', monospace;
  font-size: 16px; font-weight: 700; margin-top: 4px;
}

@media (max-width: 900px) {
  .ph-stats { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 540px) {
  /* Compact tile: label and value in the same row, less padding. Cuts the
     5-stat block from ~250 px tall to ~120 px on phones. `minmax(0, 1fr)`
     instead of `1fr` so tiles always render at equal widths — without it,
     "Início do dia + 0.1682 €/kWh" forces its column wider than its mate. */
  .ph-stats { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 6px; }
  .ph-stat {
    padding: 6px 8px;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 6px;
    min-width: 0;
    overflow: hidden;
  }
  .ph-stat-label { font-size: 9.5px; flex-shrink: 0; }
  .ph-stat-value { font-size: 11.5px; margin-top: 0; white-space: nowrap; }
}

/* =========================================================
   RESPONSIVE
   ========================================================= */
@media (max-width: 1100px) {
  .grid-live { grid-template-columns: 1fr; }
  .grid-kpis { grid-template-columns: repeat(2, 1fr); }
  .grid-energy-kpis { grid-template-columns: repeat(3, 1fr); }
  .grid-2 { grid-template-columns: 1fr; }
  .period-grid { grid-template-columns: repeat(2, 1fr); }
  .mix-wrap { grid-template-columns: 1fr; }
  .mix-legend { flex-direction: row; flex-wrap: wrap; }
}
@media (max-width: 640px) {
  main { padding: 14px; }
  .grid-kpis, .grid-energy-kpis { grid-template-columns: 1fr 1fr; }
  .splits { grid-template-columns: 1fr 1fr; }
  .period-grid { grid-template-columns: 1fr; }
  .hero-value { font-size: 36px; }
  .rate-value { font-size: 22px; }

  /* Mobile topbar: brand on the left, two icon-only buttons on the right.
     Labels collapse to icon-only via `.topbar-btn-label { display: none }`
     so the row stays single-line at 375 px. */
  .topbar {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 10px 14px;
  }
  .brand { gap: 10px; }
  .brand h1 { font-size: 15px; }
  .brand .logo { width: 28px; height: 28px; font-size: 16px; border-radius: 8px; }

  .topbar-actions { gap: 6px; }
  .topbar-btn {
    padding: 8px 10px;
    font-size: 13px;
  }
  .topbar-btn-label { display: none; }
  .topbar-btn-icon { font-size: 16px; }
}


/* =========================================================
   v2: TAB NAVIGATION
   ========================================================= */
.tabs {
  display: flex;
  gap: 4px;
  padding: 8px 24px 0;
  background: #0d1118;
  border-bottom: 1px solid rgba(255,255,255,0.08);
  overflow-x: auto;
  scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }

.tab-btn {
  appearance: none;
  background: transparent;
  border: 0;
  color: var(--muted);
  font: inherit;
  font-weight: 600;
  font-size: 14px;
  padding: 10px 18px;
  border-radius: 10px 10px 0 0;
  cursor: pointer;
  position: relative;
  white-space: nowrap;
  transition: color .15s, background .15s;
}
.tab-btn:hover { color: var(--text); background: rgba(255,255,255,0.03); }
.tab-btn.active {
  color: var(--text);
  background: linear-gradient(180deg, rgba(96,165,250,0.10), rgba(96,165,250,0));
}
.tab-btn.active::after {
  content: "";
  position: absolute;
  left: 12px; right: 12px;
  bottom: -1px;
  height: 2px;
  background: var(--accent);
  border-radius: 2px;
}

.tab-panel { display: none; }
/* The active panel is itself a grid container so every direct <section> child
   gets consistent vertical spacing — otherwise cards stack flush against the
   chart cards below them and the dashboard feels cramped. */
.tab-panel.active { display: grid; gap: 24px; }

@media (max-width: 720px) {
  .tabs { top: auto; padding: 6px 12px 0; gap: 2px; }
  .tab-btn { padding: 8px 12px; font-size: 13px; }
}


/* =========================================================
   v2: SYSTEM DETAIL CARDS (Inverter+Grid+Load / PV / Battery / Energy today)
   ========================================================= */
.grid-system-cards {
  display: grid;
  /* 4 cards on wide screens, gracefully wraps to 2 → 1 on narrow ones */
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 18px;
  /* Spacing between this section and its neighbours comes from .tab-panel's
     own gap — don't add margin here or it doubles up. */
}
.sys-card {
  padding: 18px 20px;
  display: flex;
  flex-direction: column;
}
.sys-card .card-head {
  margin-bottom: 14px;
}
.sys-card h2 {
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--muted);
}
.sys-card-pv h2     { color: var(--pv); }
.sys-card-batt h2   { color: var(--batt); }
.sys-card-energy h2 { color: var(--house); }

.sys-rows {
  display: flex;
  flex-direction: column;
  /* Tight vertical rhythm so the Solar PV card stays the same height with
     the extra MPPT peak rows. Applied to all 4 system cards for coherence. */
  gap: 8px;
  flex: 1;
}
.sys-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  font-size: 14px;
}
.sys-row-indent { padding-left: 18px; opacity: 0.85; }
.sys-label { color: var(--muted); }
.sys-val {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
}
.sys-mode {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 2px 10px;
  border-radius: 999px;
  background: rgba(96,165,250,0.15);
  color: #93c5fd;
  font-size: 12.5px;
  font-weight: 600;
}
.sys-sep {
  border: 0;
  border-top: 1px dashed rgba(255,255,255,0.10);
  margin: 6px 0 2px;
}
/* Sub-section header inside the merged "Inversor" card (Rede, Consumo) */
.sys-subhead {
  margin-top: 10px;
  padding-top: 8px;
  border-top: 1px dashed rgba(255,255,255,0.08);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--muted-2);
}


/* =========================================================
   v2: TOTALS TABLES (60d daily + 12m monthly)
   ========================================================= */
.totals-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  /* table-layout: fixed gives all data columns equal width regardless of
     header text length, so "EXPORTADO (KWH)" doesn't bloat its column. */
  table-layout: fixed;
}
.totals-table th:first-child, .totals-table td:first-child {
  width: 110px;
}
.totals-table thead th {
  position: sticky;
  top: 0;
  background: var(--bg-2);
  z-index: 1;
}
.totals-table th, .totals-table td {
  padding: 8px 10px;
  border-bottom: 1px solid rgba(255,255,255,0.04);
  white-space: nowrap;
}
.totals-table th {
  text-align: left;
  color: var(--muted);
  font-weight: 600;
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.4px;
}
.totals-table th.num, .totals-table td.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.totals-table tbody tr:hover { background: rgba(255,255,255,0.025); }
.totals-table tr.row-total {
  background: rgba(96,165,250,0.05);
  font-weight: 700;
}
.totals-table td.day-cell { font-weight: 600; }
.totals-table td.weekday {
  color: var(--muted);
  font-size: 11.5px;
  font-weight: 500;
}
/* Savings colour: green for poupança (positive), red for custo (negative),
   neutral white for ~zero. Applied to any <td> regardless of which table —
   the hist-table on the Contas tab uses these too. */
td.savings-pos { color: var(--good); }
td.savings-neg { color: var(--bad); }

/* Daily/monthly date label variants. Long form (e.g. "2026-05-13 qua") is the
   desktop default; short form ("13/05 qua" / "Mai 26") shows on phones via
   the mobile @media block, where every horizontal pixel matters. */
.lbl-short { display: none; }
/* Same toggle for the totals-table column headers: long ("Bat. descarga
   (kWh)") on desktop, short ("Bat. −") on mobile. */
.totals-table thead th .hd-short { display: none; }

/* Pager arrows for the totals tables (60d / 12m) */
.card-head-right {
  display: flex;
  align-items: center;
  gap: 12px;
}
.pager {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.btn-icon {
  width: 32px;
  height: 32px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  line-height: 1;
  font-weight: 600;
}
.btn-icon:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}


/* =========================================================
   v2: CHARTS TAB
   ========================================================= */
/* Date-range filter stays in its natural position at the top of the
   Gráficos tab and scrolls away with the content — no sticky/fixed
   behaviour. Same on desktop and mobile. */
.chart-h420 {
  height: 420px;
  position: relative;
}
@media (max-width: 720px) {
  .chart-h420 { height: 320px; }
}


/* =========================================================
   MOBILE (≤ 720px) — phones, narrow tablets in portrait
   =========================================================
   Everything below is purely overrides for handheld layouts so we don't
   touch desktop styles above. iOS-specific behaviours (safe-area insets,
   tap targets, prevent-zoom on inputs) are baked in here too. */

/* Safe-area insets so iPhone notch / home indicator don't overlap content
   when the dashboard is installed as a PWA. */
@supports (padding: env(safe-area-inset-top)) {
  .topbar {
    padding-top: max(14px, env(safe-area-inset-top));
    padding-left: max(24px, env(safe-area-inset-left));
    padding-right: max(24px, env(safe-area-inset-right));
  }
  main {
    padding-bottom: max(22px, calc(env(safe-area-inset-bottom) + 12px));
    padding-left: max(22px, env(safe-area-inset-left));
    padding-right: max(22px, env(safe-area-inset-right));
  }
  .foot { padding-bottom: max(12px, env(safe-area-inset-bottom)); }
}

@media (max-width: 720px) {
  /* ----- Base spacing: less generous margins, edge-to-edge cards ----- */
  main { padding: 12px; gap: 14px; }
  .grid { gap: 12px; }
  .tab-panel.active { gap: 14px; }
  .card { padding: 14px 14px; border-radius: 14px; }

  /* ----- Prevent horizontal page overflow on Totais / Custos -----
     Grid items default to min-width: auto, which lets them grow PAST the
     grid track when their content is wider than the track (e.g. the 7-col
     totals tables or the 10-col histórico). The card was expanding to fit
     the table, and since the card grew, .table-wrap's own overflow:auto
     never kicked in — the whole page ended up wider than the viewport
     (Safari then auto-zoomed-out to fit, which also visually compressed
     the topbar/tabs).
     Forcing min-width: 0 lets the card stay at track width; the table-wrap
     inside then provides the horizontal scroll, as intended. */
  /* No `overflow-x` rule on html/body — both `hidden` and `clip` have been
     observed to break `position: sticky` on the chart-controls-card on iOS
     Safari (the former defeats it everywhere, the latter is iOS 16-only and
     ships with quirks). Horizontal containment is enforced on the
     tab-panel children and cards below via `min-width: 0; max-width: 100%`,
     plus per-table `.table-wrap { overflow-x: auto }`. */
  .tab-panel.active > * { min-width: 0; max-width: 100%; }
  .card { min-width: 0; max-width: 100%; }
  .table-wrap { max-width: 100%; }

  /* Sticky top elements also need to be capped at the viewport width so they
     don't pick up the same auto-zoom-out the page used to suffer from. */
  .topbar, .tabs { max-width: 100vw; box-sizing: border-box; }

  /* ----- TOP BAR / HEADER -----
     Single tidy row on phones: brand on the left, two icon-only action
     buttons (Definições + Terminar sessão) on the right. Labels are
     collapsed to icons via .topbar-btn-label{display:none} in the
     `<= 720 px` overrides below. */
  .topbar {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 10px 14px;
  }
  .brand h1 { font-size: 16px; }
  .brand .logo { width: 30px; height: 30px; font-size: 18px; }

  /* ----- TABS -----
     Five tabs (Dashboard, Gráficos, Totais, Custos, Tarifário) need to fit a
     375 px viewport without horizontal scroll. `flex: 1` divides the row
     evenly; smaller padding + font-size keeps each label readable in its ~70 px
     slot. */
  .tabs {
    top: auto;
    padding: 4px 6px 0;
    gap: 2px;
    overflow-x: hidden;
  }
  .tab-btn {
    flex: 1 1 0;
    min-width: 0;
    padding: 10px 2px;
    font-size: 12px;
    min-height: 44px;
    border-radius: 10px 10px 0 0;
    text-align: center;
    letter-spacing: -0.1px;
  }
  /* Underline indicator hugs the inner edge of the tab so it doesn't visually
     touch the neighbour when tabs are tightly packed. */
  .tabs .tab-btn.active::after {
    left: 8px;
    right: 8px;
  }

  /* ----- FLOW + HEROES -----
     Stack flow card on top, heroes underneath. Each hero is full-width
     so the spark + label + value have room to breathe. */
  .grid-live { grid-template-columns: 1fr; gap: 12px; }
  /* Flow card on mobile: bleed edge-to-edge of the viewport so the diagram
     is the visual centerpiece. The card retains its outer chrome (head + splits
     with inner padding), but the SVG itself spans the full screen width. */
  .card-flow { padding: 12px 0 10px; overflow: hidden; }
  .card-flow .card-head { padding: 0 14px; }
  .card-flow .splits { padding: 0 12px; }
  /* Bleed almost edge-to-edge but leave a small inset (~3 % each side) so the
     diagram doesn't visually fight the screen bezel. `margin: calc(50% - 47vw)`
     walks the wrapper out to ~3 % from the viewport edge regardless of the
     parent's padding. */
  .flow-wrap {
    width: 94vw;
    margin-left: calc(50% - 47vw);
    margin-right: calc(50% - 47vw);
  }
  .flow-svg { width: 100%; height: auto; display: block; }
  /* Boost the in-SVG text on mobile so the kW values are readable even when
     the diagram is full-bleed (and the viewBox was tightened to remove the
     side dead space). */
  .flow-svg .node-value { font-size: 20px; }
  .flow-svg .node-label { font-size: 10px; }
  .flow-svg .node-soc   { font-size: 12.5px; }
  .hero-stack { gap: 12px; }
  .hero { padding: 14px 16px; }
  .hero-value { font-size: 26px; }
  .hero-spark { height: 36px; }
  /* Splits under the flow: 2 cols. Label inline with value (single-line
     each) cuts the splits block from ~250 px to ~120 px on phones, letting
     the flow diagram dominate as the user requested. */
  .splits {
    grid-template-columns: 1fr 1fr;
    gap: 6px;
    margin-top: 10px;
    padding: 0;
  }
  .split {
    flex-direction: row;
    align-items: baseline;
    justify-content: space-between;
    padding: 6px 9px;
    gap: 6px;
  }
  .split-label { font-size: 9.5px; letter-spacing: 0.4px; }
  .split-value { font-size: 12px; white-space: nowrap; }

  /* ----- OMIE CARDS (Tarifário tab header) -----
     4 cards collapse to a 2×2 grid on phones, with tighter padding and
     smaller values so each card stays scannable at half-width. */
  .grid-omie { grid-template-columns: 1fr 1fr; gap: 8px; }
  .omie-card { padding: 10px 12px; gap: 6px; }
  .omie-head { gap: 4px; }
  .omie-type { font-size: 9.5px; letter-spacing: 0.3px; }
  .omie-day  { font-size: 9px; padding: 2px 6px; letter-spacing: 0.3px; }
  .omie-value { font-size: 19px; }
  .omie-date  { font-size: 10px; margin-top: -2px; }
  .omie-bi-values { gap: 4px; margin-top: 2px; }
  .omie-bi-label { font-size: 9.5px; letter-spacing: 0.4px; }
  .omie-bi-value { font-size: 16px; }
  /* On phones each max/min pill becomes a tiny stacked tile (label above
     value) so a 6-char €-value doesn't fight the label on a ~80 px column. */
  .omie-minmax { gap: 4px; margin-top: 2px; }
  .omm {
    flex-direction: column;
    align-items: flex-start;
    padding: 4px 6px;
    border-radius: 6px;
    gap: 1px;
  }
  .omm-label { font-size: 8.5px; letter-spacing: 0.3px; }
  .omm-value { font-size: 11px; }
  .omie-empty { font-size: 10px; padding: 6px 4px; }

  /* ----- OMIP FUTUROS (Tarifário tab) -----
     Stack the 3 sub-tables vertically on phones; shrink fonts/padding so
     each tile reads cleanly at full width. */
  .omip-tables { grid-template-columns: 1fr; gap: 14px; }
  .omip-section-head { font-size: 11px; padding-bottom: 4px; }
  .omip-table { font-size: 12px; }
  .omip-table th, .omip-table td { padding: 5px 6px; }
  .omip-table thead th { font-size: 9.5px; letter-spacing: 0.3px; }
  .omip-unit { font-size: 9px; }
  .omip-var { font-size: 11px; gap: 3px; }

  /* ----- OMIE PERIOD AVERAGE CALCULATOR -----
     Mirrors the .filters layout used by the price-history card: 2-col grid
     with minmax(0, 1fr) so the cells can shrink below content min-width
     (otherwise a long date string like "30/04/2026" forces each cell wider
     than half the card on small phones, pushing the right input off-canvas).
     Button spans full width below. */
  .omie-avg-controls {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 8px;
    align-items: stretch;
  }
  .omie-avg-field {
    flex: initial;
    width: auto;
    min-width: 0;
    font-size: 11px;
    gap: 4px;
    margin: 0;
  }
  /* iOS Safari renders date inputs with a native height that ignores plain
     `height`; -webkit-appearance: none strips that so our box behaves. */
  .omie-avg-field input[type="date"] {
    -webkit-appearance: none;
    appearance: none;
    width: 100%;
    min-width: 0;
    height: 32px;
    padding: 0 8px;
    font-size: 13px;
    line-height: 32px;
    box-sizing: border-box;
  }
  .omie-avg-field input[type="date"]::-webkit-date-and-time-value {
    text-align: left;
    height: 32px;
    line-height: 32px;
  }
  .omie-avg-field input[type="date"]::-webkit-calendar-picker-indicator {
    padding: 0;
    margin: 0;
    opacity: 0.55;
  }
  .omie-avg-controls .btn {
    grid-column: 1 / -1;
    width: 100%;
    min-height: 40px;
    margin: 0;
  }
  .omie-avg-row { padding: 9px 12px; }
  .omie-avg-label { font-size: 12.5px; }
  .omie-avg-value { font-size: 14px; }

  /* ----- SYSTEM CARDS (Energia/PV/Bateria/Inversor) -----
     `auto-fit, minmax(260px, 1fr)` already collapses to 1 col on phones.
     Just tighten the inner padding so labels don't break-wrap. */
  .grid-system-cards { gap: 12px; }
  .sys-card { padding: 14px 16px; }
  .sys-card h2 { font-size: 14px; }
  .sys-rows { gap: 7px; }               /* proportionally tighter than the 8px desktop value */
  .sys-row { font-size: 13.5px; }
  .sys-label { white-space: normal; }   /* allow wrap on very long PT labels */

  /* ----- COST KPI CARDS (Custos tab) -----
     Full-width on phones so each card mirrors the hero style on Dashboard:
     icon + label + big value + sub all readable in one glance. 2x2 of dense
     170 px tiles felt cramped on the Custos tab against everything else. */
  .grid-kpis,
  .grid-kpis-lg { grid-template-columns: 1fr; gap: 10px; }
  .grid-kpis .kpi,
  .grid-kpis-lg .kpi { padding: 14px 16px; gap: 14px; border-radius: 14px; }
  .grid-kpis-lg .kpi-icon { width: 48px; height: 48px; font-size: 20px; }
  .grid-kpis-lg .kpi-value { font-size: 26px; }
  .grid-kpis-lg .kpi-label { font-size: 11px; }
  .grid-kpis-lg .kpi-sub { font-size: 12px; }

  /* ----- TABLES -----
     7-10 column tables don't physically fit on a 390px screen. We keep the
     existing horizontal scroll via .table-wrap but add a subtle inset shadow
     on the right edge so the user knows there's more content off-screen. */
  .table-wrap {
    /* Pinned shadow on right edge that fades when the user scrolls all the
       way across (background-attachment: local + scroll). */
    background:
      linear-gradient(to right, rgba(13,17,24,0) 0%, rgba(13,17,24,0) 90%, rgba(13,17,24,0.95) 100%) right center / 30px 100% no-repeat local,
      var(--bg-1);
  }
  table { font-size: 12px; }
  th, td { padding: 8px 10px; }
  /* ----- TOTALS TABLES (Tab Totais) -----
     Solar Assistant-style layout: rotated column headers + narrow numeric
     columns so the whole table fits the iPhone width without horizontal
     scrolling. Sticky-first-column / overflow-scroll approach is reserved
     for the hist-table on the Custos tab (10 cols, too wide to rotate). */
  .totals-table {
    table-layout: fixed;
    width: 100%;
    font-size: 11px;
  }
  /* Date column — first th + tds. Keep horizontal, narrow width, left-align. */
  .totals-table th:first-child,
  .totals-table td:first-child {
    width: 78px;
    text-align: left;
    padding: 6px 6px;
    white-space: nowrap;
  }
  /* Numeric columns share the remaining width evenly. With 6 .num columns
     on a 320 px-ish card, each gets ~40 px — enough for "12.34" at 10.5 px.
     Centre both the rotated header and the value so the column reads as a
     single vertical line: header on top, values stacked below, all on the
     same x-axis. Right-aligned numbers (the desktop default) looked off
     because the rotated header lived at the left edge. */
  .totals-table th.num, .totals-table td.num {
    padding: 6px 2px;
    font-size: 10.5px;
    text-align: center;
  }
  /* Rotate the short header label 90° (reads bottom→top). Doing it on a span
     keeps the <th>'s own width/height intact for table layout. The long
     header is hidden on phones so the column stays narrow. */
  .totals-table thead th.num {
    height: 70px;
    vertical-align: bottom;
  }
  .totals-table thead th.num .hd-long { display: none; }
  .totals-table thead th.num .hd-short {
    display: inline-block;
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    white-space: nowrap;
    font-size: 11px;
    letter-spacing: 0.3px;
    padding: 0 0 4px;
  }

  /* Switch from long date ("2026-05-13 qua") to short ("13/05 qua"). */
  .lbl-long  { display: none; }
  .lbl-short { display: inline; }
  /* Total row label wraps if needed (e.g. "Total 30 dias" at 11 px). */
  .totals-table tr.row-total td:first-child { white-space: normal; font-size: 10.5px; }
  .totals-table .weekday { font-size: 10px; }

  /* ----- HIST TABLE (Custos, 10 columns) -----
     Same SA-style rotated headers as .totals-table. With 9 numeric columns
     sharing the remaining width after the Período label, each cell is ~32 px
     — fits "12.3" (kWh @ 1 dp) and short €values without horizontal scroll.
     Slightly tighter padding + smaller font than the 6-column totals table. */
  #hist-table { table-layout: fixed; }
  #hist-table th:first-child,
  #hist-table td:first-child {
    width: 58px;
    font-size: 10.5px;
    padding: 6px 4px;
  }
  #hist-table th.num, #hist-table td.num {
    padding: 6px 2px;
    font-size: 10px;
  }
  /* Rotated header span: same vertical rotation as totals-table, but a touch
     smaller so 9 columns of headers don't visually fight each other. */
  #hist-table thead th.num .hd-short {
    font-size: 10.5px;
    letter-spacing: 0.2px;
  }

  /* ----- CHARTS -----
     Keep readable heights, shrink the legend so it doesn't dominate the tiny
     screen, and let the chart-controls-card filter row breathe. */
  .chart-h300 { height: 240px; }
  .chart-h280 { height: 220px; }
  .chart-h420 { height: 280px; }
  /* ----- FILTER ROWS (date inputs + apply + quick range) -----
     Switched from flex to a 2-col grid so we can pack the controls densely:
     row 1 = DE | ATÉ side-by-side
     row 2 = Resolução (full row)
     row 3 = Aplicar (full row)
     row 4 = quick-range buttons in a single flex row (5 buttons, 20% each)
     Total vertical footprint drops from ~370 px to ~220 px on a 393 px iPhone. */
  .chart-controls-card .filters { gap: 8px; }
  /* `minmax(0, 1fr)` (instead of plain `1fr`) lets each column shrink below
     its content's min-content width. Without it, a long readout like the
     tariff name on the Tarifário tab forces its column wider than the card,
     blowing the whole row past the card's right edge on a 375 px phone. */
  .filters {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 8px;
    align-items: stretch;
  }
  .filters label {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: 11px;
    color: var(--muted);
    margin: 0;
  }
  /* Resolução label appears 3rd among children, after DE and ATÉ — span full
     width so the dropdown isn't cramped to half. */
  .filters > label:nth-of-type(3) { grid-column: 1 / -1; }
  /* Force a single uniform height across every filter cell. The desktop rule
     bakes in `height: 38px` for inputs/selects/buttons; we need to override
     `height` (not just `min-height`) for the mobile cells to actually shrink.
     Date inputs and the tariff readout span use the same height so the two
     adjacent grid cells line up visually. */
  .filters input, .filters select {
    height: 32px;
    padding: 6px 8px;
    font-size: 14px;
    box-sizing: border-box;
  }
  /* iOS Safari has its own native height for date inputs that ignores plain
     `height` on the element — the calendar icon + tap target inflate the
     rendered box well past 32 px. `-webkit-appearance: none` strips the
     native widget so our height/padding actually apply. */
  .filters input[type="date"] {
    -webkit-appearance: none;
    appearance: none;
    padding: 0 8px;
    font-size: 13px;
    line-height: 32px;
  }
  /* The native calendar/clear icons sit on a pseudo-element; with appearance
     reset they shrink to icon size and align vertically inside our 32 px
     box. */
  .filters input[type="date"]::-webkit-date-and-time-value {
    text-align: left;
    height: 32px;
    line-height: 32px;
  }
  .filters input[type="date"]::-webkit-calendar-picker-indicator {
    padding: 0;
    margin: 0;
    opacity: 0.55;
  }
  .filters .ph-tariff-readout {
    width: 100%;
    max-width: 100%;
    height: 32px;
    padding: 0 8px;
    font-size: 13px;
    border-radius: 8px;
    box-sizing: border-box;
  }
  .filters > button.btn-primary {
    grid-column: 1 / -1;
    min-height: 40px;
    margin: 0;
  }
  /* `grid-auto-flow: column; grid-auto-columns: 1fr` produces N equal-width
     columns for N children — works for the 5-button Custos quick row AND
     the 3-button Tarifário quick row without per-card overrides. */
  .filters .quick,
  .quick {
    grid-column: 1 / -1;
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
    gap: 6px;
    margin: 0;
  }
  .filters .quick .btn,
  .quick .btn {
    padding: 8px 4px;
    font-size: 11.5px;
    min-height: 32px;
    height: 32px;
    white-space: nowrap;
    min-width: 0;
  }

  /* ----- PAGERS (totals tables) -----
     Bigger arrows so a thumb can tap them precisely. */
  .pager { gap: 6px; }
  /* Pager arrows in the totals card head — see the post-`.btn` override
     below for the actual sizing (cascade order matters there). */

  /* When the card-head has a right-side group (Totais 60d / 12m), stack the
     pieces so we don't squeeze "Totais diários — últimos 30 dias" + range
     summary + 3 pager arrows into a single squashed row. Title goes on top
     full-width; meta and pager sit on a second row, meta-left / pager-right. */
  .card-head:has(.card-head-right) {
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
  }
  .card-head-right {
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
  }

  /* ----- BUTTONS / TOUCH TARGETS ----- */
  .btn { min-height: 40px; padding: 10px 14px; font-size: 14px; }
  /* .btn-icon override placed AFTER `.btn` so it wins the cascade for
     `min-height` and `padding` (both share `.btn` class + selector specificity). */
  .btn-icon {
    width: 32px;
    height: 32px;
    min-height: 32px;
    padding: 0;
    font-size: 15px;
  }
  .btn-primary { min-height: 44px; }

  /* ----- MODAL (tariff change) -----
     Full-screen sheet on phones — easier to use than a tiny centred dialog. */
  .modal {
    width: 100vw;
    max-width: 100vw;
    height: 100vh;
    max-height: 100vh;
    margin: 0;
    border-radius: 0;
    inset: 0;
    padding: 0;
  }
  .modal::backdrop { background: rgba(0,0,0,0.85); }
  .modal form {
    height: 100%;
    display: flex;
    flex-direction: column;
    padding-top: max(0px, env(safe-area-inset-top));
    padding-bottom: max(0px, env(safe-area-inset-bottom));
  }
  .modal-head { position: sticky; top: 0; z-index: 2; background: var(--bg-2); }
  .modal-body { flex: 1; overflow-y: auto; -webkit-overflow-scrolling: touch; }
  .modal-foot {
    position: sticky;
    bottom: 0;
    z-index: 2;
    background: var(--bg-2);
    flex-direction: column-reverse;   /* "Aplicar" on top of "Cancelar" */
    gap: 8px;
  }
  .modal-foot .btn { width: 100%; }
  .kind-options { grid-template-columns: 1fr; gap: 8px; }
  .form-row { grid-template-columns: 1fr; gap: 10px; }

  /* ----- PERIOD CARDS (resumo por período, Custos tab) -----
     7 label/value rows + a big number in a 170 px tile doesn't read well; go
     full-width on phones so each period card is comfortable to scan. */
  .period-grid { grid-template-columns: 1fr; gap: 12px; }
  .period-card { padding: 14px 16px; }
  .period-big { font-size: 28px; }

  /* ----- HISTORY TOTALS STRIP ----- */
  .hist-totals { gap: 6px; }
  .ht { padding: 6px 10px; font-size: 12px; }

  /* ----- TARIFF CARD (Tarifário tab) ----- */
  .tariff-current { grid-template-columns: 1fr; }

  /* ----- LOGIN & SETUP ----- */
  .login-card { padding: 28px 22px; margin: 22px 14px; max-width: 100%; }
  .login-card h1 { font-size: 22px; }
  .login-card input { padding: 14px; }
  .setup-wrap { margin: 16px auto; padding: 16px; max-width: 100%; }

  /* ----- FOOTER ----- */
  .foot { padding: 14px 12px; font-size: 12px; }
}

/* Very narrow phones (iPhone SE, iPhone 12 mini portrait ~ 375px). */
@media (max-width: 400px) {
  .grid-kpis { grid-template-columns: 1fr; }
  .grid-kpis-lg .kpi-value { font-size: 20px; }
  .period-grid { grid-template-columns: 1fr; }
  /* Splits stay 2-col even on very narrow phones — the inline label/value
     layout from the 720 px block fits comfortably and keeps the splits block
     short so the flow diagram stays the headline of Tab 1. */
  /* Note: .filters now uses CSS grid (see the 720 px block), so the old
     flex-based 100%/50% overrides are no longer needed and would actually
     conflict with the grid layout. */
  .tab-btn { padding: 11px 12px; font-size: 13px; }
  table { font-size: 11.5px; }
  th, td { padding: 6px 8px; }
}

/* Standalone PWA (after "Add to Home Screen") — no Safari chrome means we
   own the whole viewport. Hide any "open in browser" affordances if we add
   them later, and tighten the top inset since the status bar is now ours. */
@media (display-mode: standalone) {
  .topbar { padding-top: max(10px, env(safe-area-inset-top)); }
}
