/* Light is the default theme; the dark one is opt-in via data-theme="dark" on
   <html>, which an inline script in the page head sets before first paint.
   Everything below draws from these variables — including the chart colours,
   which app.js reads back out with getComputedStyle.

   Type weights are variables too, shared by both themes: running text sits at
   500 rather than the usual 400, figures a step above that, headings and
   labels above those. This is a dense numeric table read at a glance, often
   on a phone, and 400 was reported as hard to read. */
:root {
  --w-body: 500;
  --w-num: 600;
  --w-strong: 700;

  color-scheme: light;
  --bg: #eef1f5;
  --panel: #ffffff;
  --text: #0d151e;
  --muted: #3f4e5d;
  --accent: #12897f;
  --on-accent: #ffffff;
  --border: #c3ccd6;
  --zebra: rgba(16, 32, 48, 0.04);
  --row-tint: rgba(18, 137, 127, 0.08);
  --now-tint: rgba(18, 137, 127, 0.15);
  --now-line: rgba(18, 137, 127, 0.5);
  --danger: #c53030;
  --danger-bg: rgba(197, 48, 48, 0.1);
  --notice-bg: rgba(176, 108, 20, 0.1);
  --notice-border: rgba(176, 108, 20, 0.35);
  --notice-text: #8a5510;
  --modal-backdrop: rgba(20, 28, 38, 0.45);
  --diff-good: #237a4a;
  --diff-warn: #a76a12;
  --diff-bad: #c53030;
  --chart-forecast: #12897f;
  --chart-official: #c47f1a;
  --chart-actual: #d64545;
  --chart-prev: #7f8c9b;
  --chart-today: #7c5cd6;
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: #0f1620;
  --panel: #17202b;
  --text: #f3f7fa;
  --muted: #b3c1cd;
  --accent: #4fd1c5;
  --on-accent: #0f1620;
  --border: #33414f;
  --zebra: rgba(255, 255, 255, 0.03);
  --row-tint: rgba(79, 209, 197, 0.06);
  --now-tint: rgba(79, 209, 197, 0.13);
  --now-line: rgba(79, 209, 197, 0.45);
  --danger: #f56565;
  --danger-bg: rgba(245, 101, 101, 0.14);
  --notice-bg: rgba(246, 173, 85, 0.12);
  --notice-border: rgba(246, 173, 85, 0.4);
  --notice-text: #f6ad55;
  --modal-backdrop: rgba(0, 0, 0, 0.55);
  --diff-good: #2f855a;
  --diff-warn: #f6ad55;
  --diff-bad: #c53030;
  --chart-forecast: #4fd1c5;
  --chart-official: #f6ad55;
  --chart-actual: #f56565;
  --chart-prev: #a0aec0;
  --chart-today: #9f7aea;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif;
  font-weight: var(--w-body);
  /* Fixed-width digits, so decimal points line up down a column of MWh
     figures instead of drifting row to row. */
  font-variant-numeric: tabular-nums;
  background: var(--bg);
  color: var(--text);
  /* Stops iOS from inflating text when a phone is turned to landscape. */
  -webkit-text-size-adjust: 100%;
}

header {
  padding: 24px 32px 8px;
}

h1 { margin: 0; font-size: 1.5rem; }
/* Still used by users.html and ibex-history.html, which keep their own
   descriptive subtitle; the dashboard dropped its own. */
.subtitle { color: var(--muted); margin: 4px 0 0; }

/* The dashboard header reads top to bottom: title, figures, controls,
   account. Left-aligned rather than stretched, so each row is only as wide as
   what it holds. */
.header-stack {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
}

.dashboard-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
}

.stat-tile {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.stat-label {
  color: var(--muted);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

.stat-value {
  font-weight: 700;
  font-size: 0.95rem;
  font-family: monospace;
}

main {
  padding: 16px 32px 48px;
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.logged-out-notice {
  max-width: 480px;
  margin: 80px auto;
  text-align: center;
  padding: 32px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
}

.logged-out-notice h2 { margin-top: 0; }

.logged-out-notice button {
  background: var(--accent);
  color: var(--on-accent);
  border: none;
  border-radius: 6px;
  padding: 10px 24px;
  font-weight: var(--w-strong);
  cursor: pointer;
  margin-top: 8px;
}

.panel {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 20px;
}

.panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}

.panel-header h2 { margin: 0; font-size: 1.1rem; }

.hint {
  color: var(--muted);
  font-size: 0.85rem;
  margin: 6px 0 14px;
}

select, input[type="date"] {
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 6px 10px;
}

.day-nav {
  display: flex;
  align-items: center;
  gap: 6px;
}

.date-picker {
  position: relative;
  display: inline-flex;
  align-items: center;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 6px 10px;
}

.bg-date-label {
  white-space: nowrap;
  pointer-events: none;
}

.native-date-input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  cursor: pointer;
  border: none;
  padding: 0;
}

.day-nav button {
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 6px 10px;
  cursor: pointer;
}

table {
  width: 100%;
  border-collapse: collapse;
  margin-bottom: 18px;
}

th, td {
  text-align: left;
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
  font-size: 0.9rem;
}

th { color: var(--muted); font-weight: var(--w-strong); }

/* The figures are what actually gets read here, so table cells sit a step
   heavier than running text. Kept at element specificity so the totals row
   and the diff column can still override it. */
table tbody td { font-weight: var(--w-num); }

tbody tr:hover { background: var(--row-tint); }

#last7Table tbody tr:nth-child(even),
#dayEditTable tbody tr:nth-child(even),
#usersTable tbody tr:nth-child(even) { background: var(--zebra); }
#last7Table tbody tr:nth-child(even):hover,
#dayEditTable tbody tr:nth-child(even):hover,
#usersTable tbody tr:nth-child(even):hover { background: var(--row-tint); }

.chart-box {
  position: relative;
  height: 320px;
  width: 100%;
}

canvas { max-width: 100%; }

.header-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}

.header-controls {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

#forecastView, #monthView {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.calendar-weekdays {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 6px;
  margin-bottom: 6px;
  color: var(--muted);
  font-size: 0.8rem;
  font-weight: var(--w-strong);
  text-align: center;
}

.calendar-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 6px;
}

.cal-cell {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 8px;
  min-height: 88px;
  font-size: 0.78rem;
  cursor: pointer;
}

.cal-cell:hover {
  border-color: var(--accent);
}

.cal-cell.empty {
  background: transparent;
  border: none;
  cursor: default;
}

.cal-cell.empty:hover {
  border-color: transparent;
}

.cal-daynum {
  font-weight: 700;
  margin-bottom: 4px;
}

.cal-forecaster {
  color: var(--muted);
  font-size: 0.72rem;
  margin-bottom: 6px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.cal-row {
  display: flex;
  justify-content: space-between;
  gap: 4px;
}

.cal-diff {
  font-weight: 700;
  margin-top: 4px;
}

.cal-revenue {
  margin-top: 4px;
  padding-top: 4px;
  border-top: 1px solid var(--border);
  color: var(--muted);
}

.table-scroll {
  overflow-x: auto;
  margin-bottom: 24px;
}

#last7Table {
  border-collapse: collapse;
  white-space: nowrap;
}

#last7Table th, #last7Table td {
  text-align: center;
  padding: 6px 10px;
  border-bottom: 1px solid var(--border);
  font-size: 0.85rem;
}

#last7Table thead th {
  color: var(--muted);
  font-weight: var(--w-strong);
  border-bottom: 1px solid var(--border);
}

#last7Table .hour-col {
  text-align: left;
}

/* Only the leading Hour column pins in place while scrolling; the trailing
   one is a plain column so it sits at the true right edge and picks up
   zebra striping like every other column. */
#last7Table .hour-col-sticky {
  position: sticky;
  left: 0;
  background: var(--panel);
}

#last7Table tbody tr:nth-child(even) .hour-col-sticky {
  background: linear-gradient(var(--zebra), var(--zebra)), var(--panel);
}

/* The hour now in progress. The grid is wider than the screen and gets scrolled
   sideways, so the band is carried by hairlines above and below the row as well
   as by the tint — those stay in view whichever day you have scrolled to. Drawn
   as insets rather than borders so marking a row costs no extra pixel of height
   and nothing below it shifts on the hour.

   Must stay after the zebra rule above: identical specificity, so source order
   is what decides the sticky Hour cell's background. */
#last7Table tbody tr.current-hour td {
  background: var(--now-tint);
  box-shadow: inset 0 1px 0 var(--now-line), inset 0 -1px 0 var(--now-line);
}

#last7Table tbody tr.current-hour .hour-col-sticky {
  background: linear-gradient(var(--now-tint), var(--now-tint)), var(--panel);
}

#last7Table tbody tr.current-hour .hour-col {
  font-weight: var(--w-strong);
}

#last7Table .day-group-start {
  border-left: 1px solid var(--border);
}

#last7Table .th-forecaster {
  color: var(--muted);
  font-weight: var(--w-body);
  font-size: 0.8rem;
  margin-top: 2px;
}

.auth-box {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 0.9rem;
  color: var(--muted);
}

.auth-box button {
  background: var(--accent);
  color: var(--on-accent);
  border: none;
  border-radius: 6px;
  padding: 7px 14px;
  font-weight: var(--w-strong);
  cursor: pointer;
}

.auth-box .logout-link {
  color: var(--muted);
  text-decoration: underline;
  cursor: pointer;
  background: none;
  border: none;
  padding: 0;
  font: inherit;
}

.modal {
  position: fixed;
  inset: 0;
  background: var(--modal-backdrop);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 50;
}

.modal.hidden, .hidden { display: none !important; }

.modal-card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 24px;
  width: min(300px, calc(100vw - 28px));
}

.modal-card h3 { margin-top: 0; }

.modal-card-wide {
  width: min(700px, 90vw);
  max-height: 85vh;
  overflow-y: auto;
}

/* Six fields plus hint/error/actions runs taller than the login-style modals
   this class was designed for, so it needs the wide modal's scroll escape
   hatch even though it stays narrow. */
#addUserModal .modal-card {
  max-height: 85vh;
  overflow-y: auto;
}

.modal-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.modal-close {
  background: none;
  border: none;
  color: var(--muted);
  font-size: 1.1rem;
  cursor: pointer;
  padding: 4px;
}

.modal-card form { display: flex; flex-direction: column; gap: 12px; }

.modal-card label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 0.85rem;
  color: var(--muted);
}

.modal-card input {
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 8px 10px;
  font-size: 0.95rem;
}

.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 4px;
}

.modal-actions button {
  padding: 7px 14px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text);
  cursor: pointer;
}

.modal-actions button[type="submit"] {
  background: var(--accent);
  color: var(--on-accent);
  border: none;
  font-weight: var(--w-strong);
}

.error {
  color: var(--danger);
  font-size: 0.85rem;
}

.tab-nav {
  display: flex;
  gap: 4px;
}

.tab-btn {
  background: transparent;
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 6px 14px;
  cursor: pointer;
  font-weight: var(--w-strong);
  font-size: 0.9rem;
}

.tab-btn.active {
  background: var(--accent);
  color: var(--on-accent);
  border-color: var(--accent);
}

/* Icon-only buttons, so they need less horizontal padding than the BG/EN
   pair they sit next to. */
.theme-toggle .tab-btn {
  padding: 6px 9px;
  font-size: 0.95rem;
  line-height: 1.2;
}

.edit-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 24px;
}

.edit-header h3 { margin: 0; font-size: 1rem; }

#adminForecasterPicker select {
  margin-left: 6px;
}

.notice {
  background: var(--notice-bg);
  border: 1px solid var(--notice-border);
  color: var(--notice-text);
  padding: 8px 12px;
  border-radius: 6px;
  font-size: 0.85rem;
  margin: 10px 0;
}

/* Left to the browser's default form font until now, which made the typed
   figures lighter than the saved ones sitting right next to them. */
#dayEditTable input {
  width: 80px;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 4px 6px;
  font-family: inherit;
  font-weight: var(--w-num);
  font-variant-numeric: tabular-nums;
}

#dayEditTable input:disabled {
  opacity: 0.5;
}

/* The entry cells take free text so that a typed comma survives long enough to
   be read as a decimal point. That also lets a typo sit there looking fine, so
   anything unusable — not a number, or past the plant's hourly ceiling — says
   so in the cell, and Save names the hours rather than dropping them. */
#dayEditTable input.input-invalid {
  border-color: var(--danger);
  background: var(--danger-bg);
}

#saveStatus.status-error {
  color: var(--danger);
  font-weight: var(--w-strong);
}

.diff-cell { font-weight: var(--w-strong); }

.totals-row td {
  font-weight: 700;
  border-top: 2px solid var(--border);
  background: var(--row-tint);
}

.badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: var(--w-strong);
  white-space: nowrap;
}

.badge-on { background: var(--row-tint); color: var(--diff-good); }
.badge-off { background: var(--danger-bg); color: var(--danger); }
.badge-pending { background: var(--notice-bg); color: var(--notice-text); }

.row-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.row-actions button {
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 5px 10px;
  font-size: 0.8rem;
  cursor: pointer;
}

.row-actions button:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.row-actions button.btn-danger {
  background: var(--danger-bg);
  color: var(--danger);
  border-color: var(--danger);
}

/* ---- Панчарево planned release grid ----
   Hours down, five days across. Set apart from the forecast table above it
   with a rule, because it is a different kind of thing: not what we predict,
   but what the dam upstream has told us it intends to do. */
.pancharevo-section {
  margin-top: 32px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
}

#pancharevoTable input {
  width: 76px;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 4px 6px;
  font-family: inherit;
  font-weight: var(--w-num);
  font-variant-numeric: tabular-nums;
}

#pancharevoTable input:disabled { opacity: 0.5; }

#pancharevoTable input.input-invalid {
  border-color: var(--danger);
  background: var(--danger-bg);
}

/* A high figure is flagged, not refused: during a flood it is the real
   reading, and the operator is better placed than the app to judge. */
#pancharevoTable input.input-warn {
  border-color: var(--diff-warn);
}

/* The blank-vs-zero rule is the one thing in this panel that changes what gets
   stored, so it carries the app's own strong weight rather than the browser's
   default bold. */
.pancharevo-section .hint strong {
  font-weight: var(--w-strong);
}

/* The fill button sits immediately after its own date. It used to be pushed to
   the cell's right edge, which put it closer to the NEXT column's date than to
   the one it actually fills — an easy way to fill the wrong day. */
.pancharevo-day-head {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 6px;
  white-space: nowrap;
}

.pancharevo-day-name { font-weight: var(--w-strong); }

.pancharevo-day-note {
  display: block;
  font-weight: 400;
  font-size: 0.75rem;
  color: var(--muted);
}

.pancharevo-day-locked { opacity: 0.65; }

.pancharevo-fill {
  background: none;
  border: 1px solid var(--border);
  color: var(--muted);
  border-radius: 4px;
  padding: 0 5px;
  line-height: 1.4;
  cursor: pointer;
  font-size: 0.85rem;
}

.pancharevo-fill:hover {
  border-color: var(--accent);
  color: var(--accent);
}

#pancharevoSaveStatus.status-error {
  color: var(--danger);
  font-weight: var(--w-strong);
}

.link-btn {
  background: none;
  border: none;
  color: var(--accent);
  cursor: pointer;
  font: inherit;
  padding: 0 4px;
  text-decoration: underline;
}

.edit-actions {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 14px;
}

.edit-actions button {
  background: var(--accent);
  color: var(--on-accent);
  border: none;
  border-radius: 6px;
  padding: 8px 18px;
  font-weight: var(--w-strong);
  cursor: pointer;
}

.edit-actions button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* ---- phone / tablet ----
   Wide content (data tables, the month calendar) scrolls sideways inside its
   own container rather than being squeezed until columns get clipped — the
   admin views carry values (revenue, prices) that are worth swiping for. */

.table-wrap { overflow-x: auto; }
.calendar-scroll { overflow-x: auto; }

@media (max-width: 820px) {
  header { padding: 16px 16px 8px; }
  main { padding: 12px 16px 32px; gap: 18px; }
  .panel { padding: 16px 14px; }
}

@media (max-width: 600px) {
  header { padding: 14px 12px 6px; }
  main { padding: 10px 12px 28px; gap: 14px; }

  h1 { font-size: 1.15rem; line-height: 1.25; }
  .subtitle { font-size: 0.82rem; }

  .panel { padding: 14px 12px; border-radius: 8px; }
  .panel-header h2 { font-size: 1rem; }
  .hint { font-size: 0.8rem; margin: 6px 0 10px; }

  /* Title block and controls stack; controls stretch to the full width so
     they stay comfortably tappable instead of wrapping into slivers. */
  .header-row { flex-direction: column; align-items: stretch; gap: 10px; }
  .header-controls { width: 100%; gap: 8px; }
  #headerAuthedControls select { flex: 1 1 auto; min-width: 0; }
  .auth-box { width: 100%; flex-wrap: wrap; gap: 10px; font-size: 0.8rem; }

  /* Admin header stats: 2x2 grid rather than one row that wraps raggedly. */
  .header-stack { align-items: stretch; gap: 10px; }
  .dashboard-stats {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px 12px;
    width: 100%;
  }
  .stat-label { font-size: 0.66rem; }
  .stat-value { font-size: 0.9rem; }

  /* iOS zooms the whole page when focusing an input smaller than 16px. */
  input, select { font-size: 16px; }

  .day-nav button, .tab-btn { padding: 8px 12px; }
  .chart-box { height: 240px; }

  /* Keeps 7 real weekday columns (~88px each) instead of 40px slivers; the
     weekday header sits in the same scroller so it stays aligned. */
  .calendar-weekdays, .calendar-grid { min-width: 620px; }

  th, td { padding: 6px 8px; font-size: 0.82rem; }
  #last7Table th, #last7Table td { padding: 5px 7px; font-size: 0.78rem; }
  #dayEditTable input { width: 68px; }
  #leaderboardTable, #histTable { white-space: nowrap; }

  .edit-header { flex-wrap: wrap; gap: 10px; margin-top: 18px; }
  .logged-out-notice { margin: 40px auto; padding: 24px 18px; }
  .modal-card { padding: 18px; }
  .modal-card-wide { width: min(700px, 94vw); }
}

/* Phone held upright: drop Official (col 3) and Diff (col 5) from the hourly
   entry table so the columns you actually read and type into fit without
   swiping. The inputs stay in the DOM, so saving still submits Official
   exactly as before — this only hides them. */
@media (max-width: 600px) and (orientation: portrait) {
  #dayEditTable th:nth-child(3), #dayEditTable td:nth-child(3),
  #dayEditTable th:nth-child(5), #dayEditTable td:nth-child(5) {
    display: none;
  }
}

/* The 25th row: the next day's first hour. Set below the total and tinted so
   it never reads as one of this day's 24 - it is a promise about tomorrow. */
.nextday-row td {
  border-top: 1px dashed var(--border);
  color: var(--muted);
}

.nextday-row td:first-child {
  font-style: italic;
}

/* Hour 0 when it came from yesterday's 25th row. Distinct from a plain
   disabled cell, which reads as "not yours to edit" rather than "already
   decided". */
#dayEditTable input.input-inherited {
  border-style: dashed;
  opacity: 0.85;
  cursor: not-allowed;
}

/* A second button beside Save must not compete with it. Save is the committing
   action and keeps the accent fill; this one only fills the boxes in, so it
   reads as the quieter of the two. */
.edit-actions button.btn-secondary {
  background: transparent;
  color: var(--accent);
  border: 1px solid var(--border);
}

.edit-actions button.btn-secondary:hover:not(:disabled) {
  border-color: var(--accent);
}
