/* ── Design tokens ───────────────────────────────────────────────────────
   Ebsher Platform to Monitor Solar Systems: solar telemetry for Jordanian schools.
   Palette pairs deep "ink" navy (structure/trust) with "teal" (the brand,
   already tied to the edge product) and "solar" amber reserved for energy /
   generation data specifically — so color itself tells you whether a number
   is about the system (teal) or about what the sun produced (solar).
   Every text/background pairing below is verified >= 4.5:1 contrast. */
:root {
  /* Palette */
  --c-ink: #0b1f33;
  --c-teal: #0e7c86;
  --c-teal-700: #0a5f68;
  --c-teal-100: #e3f2f1;
  --c-solar: #93590a;         /* text-safe amber (labels, values, badges) */
  --c-solar-bright: #c97c0a;  /* decorative-only: icon fills, chart strokes */
  --c-solar-100: #fbedd6;
  --c-success: #0f6b45;
  --c-success-100: #dff3e9;
  --c-warning: #8f5e0a;
  --c-warning-100: #fbeeda;
  --c-danger: #b23122;
  --c-danger-100: #fbe7e4;
  /* Maintenance mode — the same yellow as its dot on the Overview map. */
  --c-maint: #facc15;
  --c-maint-100: #fef9c3;
  --c-maint-ink: #713f12;

  /* Surfaces & text */
  --bg: #f4f6f9;
  --panel: #ffffff;
  --surface-sunken: #f7f9fb;
  --border: #e1e7ed;
  --border-strong: #c9d2db;
  --text: #16232f;
  --muted: #58697b;
  --accent: var(--c-teal);
  --accent-hover: var(--c-teal-700);
  --ok: var(--c-success);
  --warn: var(--c-warning);
  --danger: var(--c-danger);

  --sidebar-bg: var(--c-ink);
  --sidebar-text: #a9bbcc;
  --sidebar-text-active: #ffffff;
  --sidebar-icon: #7c90a4;
  --sidebar-icon-active: #6be3d2;

  --font: "Cairo", "Segoe UI", Tahoma, Arial, sans-serif;

  /* Spacing scale (4px base) */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 20px;
  --sp-6: 24px;
  --sp-8: 32px;

  /* Radius scale */
  --r-sm: 6px;
  --r-md: 10px;
  --r-lg: 14px;
  --r-pill: 999px;

  /* Elevation */
  --shadow-xs: 0 1px 2px rgba(11, 31, 51, 0.06);
  --shadow-sm: 0 2px 10px rgba(11, 31, 51, 0.07);
  --shadow-md: 0 12px 28px rgba(11, 31, 51, 0.12);
  --shadow-lg: 0 24px 56px rgba(11, 31, 51, 0.18);

  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --dur-fast: 0.15s;
  --dur-base: 0.22s;
}

@media (prefers-color-scheme: dark) {
  /* Reserved: this product ships light-only today (office/desktop use).
     Token names are dark-mode-ready if that becomes a requirement later. */
}

* {
  box-sizing: border-box;
}

html {
  color-scheme: light;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 15px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, p {
  margin: 0;
}

h2 {
  font: 800 19px var(--font);
  color: var(--text);
}

a {
  color: var(--accent);
}

a:hover {
  color: var(--accent-hover);
}

:focus-visible {
  outline: 2px solid var(--c-teal);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

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

.error {
  background: var(--c-danger-100);
  color: var(--danger);
  border: 1px solid #f0c6c0;
  border-radius: var(--r-sm);
  padding: 0.55rem 0.75rem;
  font-size: 0.85rem;
  margin-bottom: 0.9rem;
}

.success {
  background: var(--c-success-100);
  color: var(--ok);
  border: 1px solid var(--c-success-100);
  border-radius: var(--r-sm);
  padding: 0.55rem 0.75rem;
  font-size: 0.85rem;
  margin-bottom: 0.9rem;
}

/* ── Layout containers ───────────────────────────────────────────────── */

.container {
  max-width: 1100px;
  margin: 0 auto;
  padding: 0;
}

.container--fluid { max-width: none; }
.container--md { max-width: 1000px; }
.container--sm { max-width: 600px; }

.layout {
  display: grid;
  grid-template-columns: 280px 1fr;
  gap: var(--sp-5);
  align-items: start;
}

@media (max-width: 800px) {
  .layout { grid-template-columns: 1fr; }
}

/* Before a school is picked, let the schools panel take the full page
   instead of sitting cramped in a 280px sidebar — matters once a region
   has hundreds of schools to scan. Once one is selected, the layout goes
   back to the normal sidebar + detail split. */
.layout--picker {
  grid-template-columns: 1fr;
}

.layout--picker > div:last-child {
  display: none;
}

.section {
  margin-bottom: var(--sp-5);
}

/* Small inline flex rows, used for compact toolbars/notes that used to be
   ad hoc `style="display:flex; ..."` scattered across every template. */
.row {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-wrap: wrap;
}

.row--between {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  flex-wrap: wrap;
}

.mt-sm { margin-top: var(--sp-3); }
.mb-sm { margin-bottom: var(--sp-3); }

/* ── Cards & panels ──────────────────────────────────────────────────── */

.card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--sp-5);
  box-shadow: var(--shadow-xs);
}

.panel-title {
  font: 700 12px var(--font);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
  margin: 0 0 var(--sp-3);
}

.panel-card-title-row .panel-title {
  margin: 0;
}

.panel-subtitle {
  color: var(--muted);
  font-size: 0.85em;
  margin: 0 0 var(--sp-3);
}

.panel-subtitle:last-child {
  margin-bottom: 0;
}

.panel-title-suffix {
  text-transform: none;
  font-weight: 400;
  letter-spacing: normal;
}

.note {
  color: var(--muted);
  font-size: 0.85em;
  margin: var(--sp-2) 0 0;
}

.note:first-child {
  margin-top: 0;
}

.text-xs {
  font-size: 0.8em;
}

.text-center {
  text-align: center;
}

.form-narrow {
  max-width: 320px;
}

.form-md {
  max-width: 420px;
  margin-top: var(--sp-4);
}

.settings-form-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--sp-4);
  align-items: start;
}

.settings-form-grid > div {
  min-width: 0;
  display: flex;
  flex-direction: column;
}

/* Same trap as .report-field: this rule's `display: flex` outranks the
   browser default `[hidden] { display: none }`, so JS hiding #regionField
   / #schoolField by role would otherwise leave the dropdowns visible. */
.settings-form-grid > div[hidden] {
  display: none;
}

.settings-form-grid label {
  margin-bottom: 0.3rem;
  min-height: 1.35em;
}

.settings-form-grid input,
.settings-form-grid select,
.settings-form-grid button {
  margin-bottom: 0;
  width: 100%;
}

.settings-add-submit button {
  min-height: 2.5rem;
}

@media (max-width: 800px) {
  .settings-form-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 520px) {
  .settings-form-grid {
    grid-template-columns: 1fr;
  }
}

.mfa-qr {
  /* Content box must be exactly 220x220 to match the SVG's own width/height
     attributes (see ui.py's _mfa_qr_svg) — box-sizing: border-box (global
     reset above) would otherwise shrink the content area by the padding,
     making the 220x220 SVG overflow the box instead of fitting inside it. */
  box-sizing: content-box;
  width: 220px;
  height: 220px;
  padding: var(--sp-3);
  background: #fff;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  display: flex;
  align-items: center;
  justify-content: center;
  /* Centers the (fixed-width) box itself within its wider parent card,
     instead of sitting flush against the start edge. */
  margin-inline: auto;
}

.mfa-qr svg {
  max-width: 100%;
  height: auto;
}

.code-block {
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: var(--sp-4);
  margin: var(--sp-4) 0;
  word-break: break-all;
}

.code-block code {
  font-family: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", monospace;
  font-size: 0.95rem;
}

.code-block-line {
  font-family: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", monospace;
  font-size: 1rem;
  padding: 0.2rem 0;
}

.code-block + .code-block {
  margin-top: -0.5rem;
}

.table-scroll {
  overflow-x: auto;
}

/* ── Forms ───────────────────────────────────────────────────────────── */

label {
  display: block;
  font-size: 0.85rem;
  color: var(--muted);
  margin-bottom: 0.3rem;
}

input[type="text"],
input[type="password"],
input[type="email"],
input[type="tel"],
input[type="number"],
input[type="date"],
input[type="search"],
select,
textarea {
  width: 100%;
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  font-size: 0.95rem;
  font-family: var(--font);
  background: #fff;
  color: var(--text);
  margin-bottom: 0.9rem;
  transition: border-color var(--dur-fast, 0.15s) var(--ease);
}

textarea {
  resize: vertical;
  min-height: 4.5em;
}

/* Native select arrows render flush against the border in most browsers —
   swap in a custom chevron with real breathing room instead of relying on
   the browser's own (inconsistent, edge-hugging) rendering. */
select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  padding-inline-end: 2.25rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6' fill='none'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%2358697b' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.9rem center;
  background-size: 10px 6px;
}

input:hover, select:hover, textarea:hover {
  border-color: var(--muted);
}

input:focus-visible, select:focus-visible, textarea:focus-visible {
  border-color: var(--c-teal);
}

table input[type="email"],
table input[type="tel"] {
  min-width: 140px;
  padding: 0.35rem 0.5rem;
  font-size: 0.85rem;
  margin-bottom: 0;
}

/* Settings > Users: one line per person, edit controls folded away.
   The card-per-user layout repeated every label in every card and stood the
   role/scope selects open on every row, so two super admins already filled
   a screen — and school/regional accounts, which also carry a region and a
   school, are the ones that come in dozens. The summary line carries
   everything a reader looks for (who, contact, role, scope, 2FA, alarms);
   the <details> body holds what an admin changes. Header labels are printed
   once above the list, and the summary grid and .user-list-head share one
   column template so they cannot drift apart. */
.user-filter {
  max-width: 440px;
  margin-bottom: var(--sp-3);
}

.user-list-head,
.user-row-summary {
  display: grid;
  grid-template-columns:
    minmax(0, 2.7fr) minmax(0, 1fr) minmax(0, 1.4fr) minmax(0, 1.5fr) 5rem;
  gap: var(--sp-4);
  align-items: center;
}

.user-list-head {
  padding: 0 calc(var(--sp-4) + 1px) var(--sp-2);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}

.user-list {
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--panel);
}

.user-row + .user-row {
  border-top: 1px solid var(--border);
}

.user-row[hidden] {
  display: none;
}

.user-row-summary {
  padding: var(--sp-3) var(--sp-4);
  cursor: pointer;
  list-style: none;
  transition: background-color var(--dur-fast) var(--ease);
}

.user-row-summary::-webkit-details-marker {
  display: none;
}

.user-row-summary:hover,
.user-row[open] > .user-row-summary {
  background: var(--surface-sunken);
}

.user-row-summary:focus-visible {
  outline: 2px solid var(--c-teal);
  outline-offset: -2px;
}

.user-row-who {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-width: 0;
}

.user-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--c-teal-100);
  color: var(--c-teal-700);
  font-weight: 700;
  font-size: 0.9rem;
}

.user-row-id {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
}

.user-row-name {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.2rem 0.5rem;
  font-weight: 700;
  color: var(--text);
}

.user-row-contact {
  display: flex;
  flex-wrap: wrap;
  gap: 0 0.4rem;
  font-size: 0.8rem;
  color: var(--muted);
  overflow-wrap: anywhere;
}

.user-row--inactive .user-avatar {
  background: var(--surface-sunken);
  color: var(--muted);
}

.user-row--inactive .user-row-name {
  color: var(--muted);
}

.user-row-cell {
  min-width: 0;
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--text);
  overflow-wrap: anywhere;
}

.user-row-sub {
  display: block;
  font-size: 0.78rem;
  font-weight: 400;
  color: var(--muted);
}

.user-row-status {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.3rem;
  min-width: 0;
}

.user-chip {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.2rem 0.4rem;
  font-size: 0.75rem;
  color: var(--muted);
}

.user-row-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.4rem;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--c-teal-700);
}

.user-row-toggle::after {
  content: "";
  width: 0.45rem;
  height: 0.45rem;
  /* Physical, not inline-end: up/down does not mirror in Arabic. */
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform var(--dur-fast) var(--ease);
}

.user-row[open] .user-row-toggle::after {
  transform: translateY(2px) rotate(-135deg);
}

.user-row-body {
  padding: var(--sp-4);
  padding-inline-start: calc(var(--sp-4) + 34px + var(--sp-3));
  border-top: 1px solid var(--border);
  background: var(--surface-sunken);
}

.user-edit-grid {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--sp-3) var(--sp-4);
  margin-bottom: var(--sp-4);
}

.user-edit-field {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  flex: 1 1 190px;
  max-width: 280px;
  margin: 0;
  font-size: 0.8rem;
  color: var(--muted);
}

.user-edit-field[hidden] {
  display: none;
}

.user-edit-field select {
  margin-bottom: 0;
  padding-top: 0.45rem;
  padding-bottom: 0.45rem;
  font-size: 0.9rem;
}

.user-active {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-height: 2.35rem;
  margin: 0;
  font-size: 0.85rem;
  color: var(--text);
  cursor: pointer;
  white-space: nowrap;
}

.user-active input[type="checkbox"] {
  width: 1.05rem;
  height: 1.05rem;
  margin: 0;
  flex: none;
}

.users-row-actions {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  gap: var(--sp-2);
  flex: 0 0 auto;
}

.users-row-actions .btn-sm,
.users-row-actions .btn-sm.btn-danger {
  margin: 0;
  width: auto;
}

/* Manage panel: one titled section per concern — the account itself, your
   sign-in, your alarm messages — each with its own action beside what it
   changes. They used to share one flex row, where the WhatsApp label-over-
   select stretched every button to its height and two "Save" buttons saved
   different things. */
.manage-section {
  display: grid;
  grid-template-columns: 9.5rem minmax(0, 1fr);
  gap: var(--sp-2) var(--sp-6);
  padding-block: var(--sp-4);
}

.manage-section:first-child {
  padding-top: 0;
}

.manage-section + .manage-section {
  border-top: 1px solid var(--border);
}

.manage-section-title {
  margin: 0;
  padding-top: 0.3rem;
  font-size: 0.85rem;
  font-weight: 700;
  color: var(--text);
}

.manage-section-body {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  min-width: 0;
}

.manage-section .user-edit-grid {
  margin-bottom: 0;
}

/* A status on one side, its action on the other. */
.manage-line {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2) var(--sp-4);
}

.manage-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
}

/* A section's own action always sits at the line's end, wherever it is. */
.manage-section-body > .manage-actions {
  justify-content: flex-end;
}

.manage-actions .btn-sm,
.manage-danger .btn-sm.btn-danger {
  margin: 0;
}

/* Delete sits apart from every button that changes the account — below a
   rule and at the opposite end of the line from Save — so it is never the one
   a hand lands on after Save. */
.manage-danger {
  display: flex;
  justify-content: flex-start;
  padding-top: var(--sp-4);
  border-top: 1px solid var(--border);
}

/* WhatsApp alarms: three options side by side, each saying what it means. */
.choice-group {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.choice-group-legend {
  padding: 0;
  margin-bottom: var(--sp-2);
  font-size: 0.8rem;
  color: var(--muted);
}

.choice-options {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: var(--sp-2);
}

.choice {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  margin: 0;
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  background: var(--panel);
  color: var(--text);
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease);
}

.choice:hover {
  border-color: var(--muted);
}

.choice:has(input:checked) {
  border-color: var(--c-teal-700);
  background: var(--c-teal-100);
}

.choice input[type="radio"] {
  flex: none;
  width: 1rem;
  height: 1rem;
  margin: 0.2rem 0 0;
  accent-color: var(--c-teal-700);
}

.choice:has(input:focus-visible) {
  outline: 2px solid var(--c-teal-700);
  outline-offset: 2px;
}

.choice-text {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
}

.choice-title {
  font-size: 0.85rem;
  font-weight: 600;
  line-height: 1.3;
}

.choice-hint {
  font-size: 0.75rem;
  line-height: 1.35;
  color: var(--muted);
}

.choice-note {
  margin: 0;
  font-size: 0.78rem;
  color: var(--muted);
}

@media (max-width: 760px) {
  .user-list-head {
    display: none;
  }

  .user-row-summary {
    grid-template-columns: minmax(0, 1fr) auto;
    row-gap: var(--sp-2);
  }

  .user-row-cell,
  .user-row-status {
    grid-column: 1 / -1;
    padding-inline-start: calc(34px + var(--sp-3));
  }

  .user-row-toggle {
    grid-column: 2;
    grid-row: 1;
  }

  .user-row-cell::before {
    content: attr(data-label) ": ";
    font-weight: 400;
    color: var(--muted);
  }

  .user-row-sub {
    display: inline;
    margin-inline-start: 0.4rem;
  }

  .user-row-status {
    flex-direction: row;
    flex-wrap: wrap;
    gap: 0.3rem var(--sp-4);
  }

  .user-row-body {
    padding-inline-start: var(--sp-4);
  }

  .user-edit-field {
    max-width: none;
  }

  .manage-section {
    grid-template-columns: minmax(0, 1fr);
  }

  .manage-section-title {
    padding-top: 0;
  }
}

@media (max-width: 560px) {
  .users-row-actions {
    flex-direction: column;
    align-items: stretch;
  }

  .users-row-actions .btn-sm {
    width: 100%;
  }
}

/* ── Buttons ─────────────────────────────────────────────────────────
   Auto-width by default — a button is exactly as wide as its label unless
   it opts into .btn-block. (The previous default was full-width, which is
   why almost every button in the templates carried a `width:auto` inline
   override; this flips the default to the common case.) */

button,
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4em;
  width: auto;
  background: var(--accent);
  color: #fff;
  border: 1px solid transparent;
  padding: 0.55rem 1.1rem;
  border-radius: var(--r-sm);
  font-family: var(--font);
  font-weight: 600;
  font-size: 0.9rem;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--dur-fast, 0.15s) var(--ease), border-color var(--dur-fast, 0.15s) var(--ease);
}

button:hover, .btn:hover {
  background: var(--accent-hover);
  color: #fff;
}

button:disabled, .btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.btn-block {
  width: 100%;
}

.btn-secondary {
  background: transparent;
  color: var(--text);
  border-color: var(--border-strong);
}

.btn-secondary:hover {
  background: var(--surface-sunken);
  color: var(--text);
  border-color: var(--muted);
}

.btn-danger {
  background: var(--danger);
}

.btn-danger:hover {
  background: #94281c;
}

.btn-sm {
  padding: 0.35rem 0.75rem;
  font-size: 0.8rem;
}

.btn-sm.btn-danger {
  margin-inline-start: 0.4rem;
}

/* ── Badges ──────────────────────────────────────────────────────────── */

.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  padding: 0.2rem 0.65rem;
  border-radius: var(--r-pill);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.01em;
}

.badge.active { background: var(--c-success-100); color: var(--ok); }
.badge.pending { background: var(--c-warning-100); color: var(--warn); }
.badge.inactive { background: var(--surface-sunken); color: var(--muted); }
/* "No answer to be had" — not a state the site is in, so it gets no chip at
   all. .inactive's filled grey would read as a reading that came back. */
.badge.unknown { background: none; color: var(--muted); padding-inline: 0; }
.badge.offline { background: var(--c-danger-100); color: var(--danger); }
.badge.info { background: var(--c-teal-100); color: var(--c-teal-700); }
.badge.warning { background: var(--c-warning-100); color: var(--warn); }
.badge.error, .badge.critical { background: var(--c-danger-100); color: var(--danger); }

.badge.offline::before,
.school-row-grid .badge.active::before,
.school-list:not(.school-list--rows) .badge.active::before,
.kpi-tile .badge.active::before {
  content: "";
  width: 0.45em;
  height: 0.45em;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
}

/* Badge reduced to just its status dot, for rows too narrow to spell the
   verdict out (the 280px schools sidebar). The label is still in the markup,
   visually hidden, and in the badge's title — so this drops the width, not
   the meaning. Deliberately sized above the 0.45em decorative dot above:
   here the dot is the whole control, not an accent on a word. */
.badge--dot {
  padding: 0;
  background: none;
}

.badge--dot::before {
  content: "";
  width: 0.6em;
  height: 0.6em;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
}

/* Hollow, so "no answer" is not a second grey dot indistinguishable from
   "answered, and the answer is idle" — the two sit side by side here. */
.badge--dot.unknown::before {
  background: none;
  box-shadow: inset 0 0 0 1.5px currentColor;
}

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

table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9rem;
}

th, td {
  text-align: start;
  padding: 0.65rem 0.7rem;
  border-bottom: 1px solid var(--border);
}

thead th {
  color: var(--muted);
  font-weight: 700;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

tbody tr:hover {
  background: var(--surface-sunken);
}

/* Label/value stat tables (Performance, Economic, Reliability).
   table-layout:fixed keeps every row on the same tracks so a long Arabic
   label or a fallback sentence cannot shove one row's numbers into the
   middle of the card. Labels stay on the inline-start edge (right in
   Arabic, left in English); numeric cells and their headers sit on the
   inline-end edge — so the Benchmark/المرجع column is flush left in RTL
   and flush right in LTR, matching its header. */
.metrics-table {
  table-layout: fixed;
  width: 100%;
}

.metrics-table tbody th {
  width: 52%;
  font-weight: 600;
  color: var(--text);
  text-align: start;
  vertical-align: middle;
}

.metrics-table td,
.metrics-table thead th:not(:first-child) {
  text-align: end;
  vertical-align: middle;
  font-variant-numeric: tabular-nums;
}

.metrics-table thead th:first-child {
  text-align: start;
}

.metrics-table td [dir="ltr"] {
  display: inline-block;
  white-space: nowrap;
}

.metrics-table .metrics-fallback {
  display: inline-block;
  max-width: 100%;
  text-align: start;
  white-space: normal;
  font-weight: 500;
  color: var(--muted);
  font-size: 0.85em;
}

.metrics-table--compare tbody th {
  width: auto;
}

.metrics-table--compare col.metrics-col-num {
  width: 10.75rem;
}

@media (max-width: 640px) {
  .metrics-table--compare col.metrics-col-num {
    width: 8.25rem;
  }
}

/* The five rows under this heading are one inverter, not the whole site.
   A filled teal banner read as a selected-row highlight, so the grouping is
   a quiet kicker plus a start-edge accent on the rows themselves. */
.metrics-table tbody tr.metrics-section th {
  padding: 0.9rem 0 0.45rem;
  background: transparent;
  border: none;
  font-weight: 700;
  letter-spacing: 0;
  text-transform: none;
  color: var(--text);
}

.metrics-section-kicker {
  display: block;
  margin-bottom: 2px;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}

.metrics-section-name {
  display: block;
  font-size: 0.92rem;
  font-weight: 800;
  color: var(--text);
}

.metrics-table tbody tr.metrics-section:hover {
  background: transparent;
}

.metrics-table tbody tr.metrics-inverter th,
.metrics-table tbody tr.metrics-inverter td {
  background: var(--surface-sunken);
}

.metrics-table tbody tr.metrics-inverter th {
  border-inline-start: 3px solid var(--c-teal);
}

/* The "?" beside a Performance row label, and the definition it opens.
   The <th> is the positioning context so the panel hangs under its own row
   rather than being trapped inside a 52%-wide fixed-layout cell; it is wider
   than that cell on purpose, since a definition is a sentence and a label is
   two words. inset-inline-start pins it to the label edge, which flips with
   the document in Arabic. */
#performanceTable tbody th {
  position: relative;
}

.metric-info {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  margin-inline-start: var(--sp-1);
  padding: 0;
  border: 1px solid var(--c-teal);
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--c-teal);
  font: 700 11px var(--font);
  line-height: 1;
  cursor: pointer;
  vertical-align: middle;
}

.metric-info:hover,
.metric-info[aria-expanded="true"] {
  background: var(--c-teal);
  color: #fff;
}

.metric-info:focus-visible {
  outline: 2px solid var(--c-teal);
  outline-offset: 2px;
}

.metric-info-panel {
  position: absolute;
  z-index: 5;
  top: calc(100% + var(--sp-1));
  inset-inline-start: 0;
  width: max(100%, 25rem);
  max-width: calc(100vw - 5rem);
  /* An open definition overlays the rows beneath it, so without this it
     swallows the click meant for the next row's "?" and reading two in a
     row takes three clicks. Passing pointer events through costs the
     ability to select the text, which is the cheaper of the two. */
  pointer-events: none;
  padding: var(--sp-3);
  border-radius: var(--r-sm);
  background: var(--c-ink);
  color: #fff;
  font: 500 12px var(--font);
  line-height: 1.55;
  text-align: start;
  white-space: normal;
  box-shadow: var(--shadow-md);
}

.report-links {
  font-size: 0.78rem;
  font-weight: 400;
  text-transform: none;
  letter-spacing: normal;
  color: var(--muted);
}

.panel-title > .report-links {
  float: right;
}

.report-links a {
  text-decoration: none;
}

/* ── Lists ───────────────────────────────────────────────────────────── */

.school-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.school-list li a {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0.6rem 0.7rem;
  border-radius: var(--r-sm);
  text-decoration: none;
  color: var(--text);
  font-size: 0.92rem;
  font-weight: 500;
}

.school-list:not(.school-list--rows) li a > span:first-child {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.school-list li a:hover {
  background: var(--surface-sunken);
}

.school-list li a.active {
  background: var(--c-ink);
  color: #fff;
}

/* Full-width search row, stacked below the "Schools" title (see
   .panel-card-title-row--split, which keeps just the "+" button) instead
   of sharing that row — the schools panel is only ~280px wide once a
   school is selected (layout--picker drops), nowhere near enough to fit
   a search box next to the title without overflowing. */
.schools-search-input {
  display: block;
  width: 100%;
  padding: 0.4rem 0.7rem;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  font-size: 0.85rem;
  font-family: var(--font);
  color: var(--text);
  background: var(--panel);
  margin-bottom: var(--sp-3);
  -webkit-appearance: none;
  appearance: none;
}

input[type="search"],
input[type="search"]::placeholder,
input[type="search"]::-webkit-input-placeholder,
.schools-search-input::placeholder {
  font-family: var(--font);
}

/* Region tab bar (All/North/Central/South) — filters which schools render
   below via ?region=, server-side. Replaces per-region section headers:
   with up to 350 schools, browsing one region at a time beats scrolling
   past groups you don't care about. */
.region-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin-bottom: var(--sp-4);
  padding-bottom: var(--sp-3);
  border-bottom: 1px solid var(--border);
}

.region-tab {
  padding: 0.35rem 0.9rem;
  border-radius: 999px;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--muted);
  text-decoration: none;
  background: var(--surface-sunken);
}

.region-tab:hover {
  color: var(--text);
}

.region-tab.active {
  background: var(--c-ink);
  color: #fff;
}

/* Table-like school picker (pre-selection, .layout--picker): one header
   row plus data rows share the same 8-column template so the two status
   columns/panels/inverters sit in a real column, not under a second
   per-cell label that the badge padding then offset. minmax(0, …) stops a
   long Arabic name from blowing a track (the original reason the header was
   dropped). Per-cell labels stay in the markup for screen readers and for
   the stacked 2-column layout under 800px.

   Floors, and who gets one: the two status tracks, because a badge is one
   unwrappable inline-flex box holding a whole phrase ("Not generating 1/2");
   and the name, because it is the column the row is unreadable without, and
   as the widest track it was otherwise the one that absorbed every squeeze.
   The numeric tracks have none — they hold two or three characters, and
   their headings wrap instead (see .school-table-head > span).

   The second selector below (scoped under .school-list--rows li >) is not
   redundant: .school-list li a earlier in this file (display:flex, gap,
   padding) has higher specificity than a bare .school-row-grid class, so
   without it display never became grid at all. */
.school-table {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.school-row-grid,
.school-list--rows li > a.school-row-grid,
.school-table > .school-table-head {
  display: grid;
  grid-template-columns:
    minmax(7.5rem, 1.5fr)
    minmax(8.5rem, 1fr)
    minmax(5.75rem, 0.8fr)
    minmax(0, 0.6fr)
    minmax(0, 0.5fr)
    minmax(0, 0.65fr)
    minmax(0, 0.75fr)
    minmax(0, 0.65fr);
  align-items: center;
  column-gap: var(--sp-3);
  padding: 0 var(--sp-4);
}

.school-table-head {
  padding-bottom: var(--sp-2);
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  align-items: end;
}

/* Headings wrap rather than ellipsis. "Inverter count" is two words, and
   reserving enough track to keep it on one line took that width from the
   school name — the one column nobody can read the row without. The header
   row is bottom-aligned, so a two-line heading still shares a baseline with
   its neighbours. */
.school-table-head > span {
  overflow-wrap: break-word;
}

.school-list--rows {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.school-list--rows li > a.school-row-grid {
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  color: var(--text);
  text-decoration: none;
}

.school-list--rows li > a.school-row-grid:hover {
  border-color: var(--c-ink);
  box-shadow: var(--shadow-xs);
}

.school-field {
  display: flex;
  flex-direction: column;
  align-items: start;
  justify-content: center;
  text-align: start;
  gap: 4px;
  min-width: 0;
}

.school-field-label {
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--muted);
}

.school-field > :not(.school-field-label) {
  text-align: start;
  font-variant-numeric: tabular-nums;
}

.school-row-name,
.wo-row-title {
  display: block;
  min-width: 0;
  font-size: 0.95rem;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

@media (min-width: 801px) {
  /* Shared header row owns the column titles; keep per-cell labels for
     screen readers only so values sit in the same tracks as the header
     (badge padding no longer fights a second "Status" in the cell). */
  .school-list--rows .school-field-label {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }

  .school-list--rows .school-field {
    display: block;
    position: relative;
    gap: 0;
  }

  .school-table-head > span:not(.school-col-name),
  .school-list--rows .school-field:not(.school-col-name),
  .school-list--rows .school-field:not(.school-col-name) [dir="ltr"] {
    text-align: center;
  }
}

@media (max-width: 800px) {
  .school-table > .school-table-head {
    display: none;
  }

  .school-list--rows li > a.school-row-grid {
    grid-template-columns: 1fr 1fr;
    align-items: start;
  }
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Reports page row grid — its own list/row classes rather than reusing
   .school-list/.school-row-grid: each row needs three separate download
   links plus the name link, but .school-list li a (above) applies flex
   layout to *every* <a> under .school-list li, which is only correct for
   that list's one-link-per-row rows and would otherwise squash these
   rows' three report buttons into that same full-width flex line. */
.report-list {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  list-style: none;
  margin: 0;
  padding: 0;
}

.report-row-grid {
  display: grid;
  grid-template-columns: 2fr 0.8fr 2fr;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
}

.report-table-head {
  padding-bottom: var(--sp-2);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.report-table-head > span:not(:first-child),
.report-list > .report-row-grid > :not(:first-child) {
  text-align: center;
}

li.report-row-grid {
  border: 1px solid var(--border);
  border-radius: var(--r-md);
}

li.report-row-grid:hover {
  border-color: var(--c-ink);
  box-shadow: var(--shadow-xs);
}

.report-row-name {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--text);
  text-decoration: none;
  overflow: hidden;
}

.report-row-name span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.report-quick-actions {
  display: flex;
  justify-content: center;
  gap: var(--sp-2);
  flex-wrap: wrap;
}

.report-quick-btn {
  padding: 0.3rem 0.85rem;
  border-radius: 999px;
  font-family: inherit;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--text);
  text-decoration: none;
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  white-space: nowrap;
  cursor: pointer;
}

.report-quick-btn:hover {
  border-color: var(--c-ink);
  color: var(--c-ink);
}

.alerts-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0 var(--sp-2);
  table-layout: fixed;
}

.alerts-col-school { width: 46%; }
.alerts-col-region { width: 22%; }
.alerts-col-num { width: 16%; }

.alerts-table th {
  padding: 0 var(--sp-4) var(--sp-2);
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
  text-align: start;
}

.alerts-table td {
  padding: var(--sp-3) var(--sp-4);
  text-align: start;
  vertical-align: middle;
  background: var(--panel);
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}

.alerts-table th:not(:first-child),
.alerts-table td:not(:first-child) {
  text-align: center;
}

.alerts-table td:first-child {
  border-inline-start: 1px solid var(--border);
  border-start-start-radius: var(--r-md);
  border-end-start-radius: var(--r-md);
}

.alerts-table td:last-child {
  border-inline-end: 1px solid var(--border);
  border-start-end-radius: var(--r-md);
  border-end-end-radius: var(--r-md);
}

.alerts-table tbody tr:hover td {
  border-color: var(--c-ink);
}

.alerts-count {
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  color: var(--muted);
}

.alerts-count--hot {
  color: var(--danger);
}

.alerts-count--warn {
  color: var(--warn);
}

/* ── Maintenance inbox ──────────────────────────────────────────────────
   Full-width ticket list stays on screen; logging is a dialog; reviewing
   and updating happen in a slide-over so the inbox never collapses into
   a 280px sidebar. The inline-start colour rail is priority (critical /
   high / medium / low) — the one thing a regional admin scans first. */
.wo-toolbar {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-4);
  margin-bottom: var(--sp-4);
}

.wo-page-title {
  font: 800 1.35rem var(--font);
  color: var(--c-ink);
  margin: 0 0 var(--sp-1);
}

.wo-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: var(--sp-3);
  margin-bottom: var(--sp-3);
}

input.wo-search,
.wo-school-filter select {
  height: 40px;
  margin: 0;
  padding: 0 0.85rem;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background-color: var(--panel);
  font-size: 0.85rem;
  line-height: 38px;
  color: var(--text);
}

input.wo-search {
  flex: 1 1 16rem;
  width: auto;
  min-width: 12rem;
}

.wo-school-filter {
  display: flex;
  flex: 0 1 16rem;
  min-width: 12rem;
}

.wo-school-filter select {
  width: 100%;
  padding-inline-end: 2.4rem;
  cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1.5 1.5L6 6.5 10.5 1.5' stroke='%230b1f33' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.85rem center;
  background-size: 12px 8px;
}

.wo-status-tabs {
  margin-bottom: var(--sp-4);
}

.wo-tab-count {
  display: inline-flex;
  min-width: 1.25rem;
  justify-content: center;
  margin-inline-start: 0.35rem;
  padding: 0 0.35rem;
  border-radius: var(--r-pill);
  background: var(--surface-sunken);
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  font-size: 0.75rem;
}

.region-tab.active .wo-tab-count {
  background: var(--c-teal-100);
  color: var(--c-teal-700);
}

.wo-inbox {
  padding: var(--sp-4);
}

.wo-row-grid {
  display: grid;
  grid-template-columns: minmax(0, 2.2fr) minmax(7rem, 1.1fr) 7.5rem minmax(6rem, 0.9fr) 6.5rem;
  align-items: center;
  gap: var(--sp-3);
}

.wo-row-grid--head {
  padding: 0 var(--sp-4) var(--sp-2);
  padding-inline-start: calc(var(--sp-4) + 4px);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.wo-ticket-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.wo-ticket {
  display: grid;
  grid-template-columns: minmax(0, 2.2fr) minmax(7rem, 1.1fr) 7.5rem minmax(6rem, 0.9fr) 6.5rem;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--border);
  border-inline-start-width: 4px;
  border-inline-start-color: var(--wo-rail, var(--border-strong));
  border-radius: var(--r-md);
  color: var(--text);
  text-decoration: none;
  cursor: pointer;
  background: var(--panel);
  transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}

.wo-ticket--low { --wo-rail: var(--muted); }
.wo-ticket--medium { --wo-rail: var(--c-teal); }
.wo-ticket--high { --wo-rail: var(--warn); }
.wo-ticket--critical { --wo-rail: var(--danger); }

.wo-ticket:hover {
  border-color: var(--c-ink);
  box-shadow: var(--shadow-xs);
  color: var(--text);
}

.wo-ticket.is-open {
  border-color: var(--c-teal);
  background: var(--c-teal-100);
}

.wo-ticket-main {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
}

.wo-ticket-main .wo-row-title {
  flex: 1 1 auto;
}

.wo-ticket-school,
.wo-ticket .muted {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.wo-empty {
  text-align: center;
  padding: var(--sp-8) var(--sp-4);
}

.wo-empty-title {
  font: 700 1.05rem var(--font);
  margin-bottom: var(--sp-2);
}

.wo-search-empty {
  margin-top: var(--sp-3);
}

.wo-page--drawer {
  padding-inline-end: min(28rem, 100%);
}

.wo-drawer-backdrop {
  position: fixed;
  inset: 0;
  z-index: 1400;
  background: rgba(11, 31, 51, 0.28);
  text-decoration: none;
}

.wo-drawer-head .report-dialog-close {
  color: var(--muted);
  text-decoration: none;
  background: transparent;
  border: none;
}

.wo-drawer {
  position: fixed;
  inset-block: 0;
  inset-inline-end: 0;
  z-index: 1500;
  width: min(28rem, 100%);
  background: var(--panel);
  box-shadow: var(--shadow-lg);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.wo-drawer-head {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  padding: var(--sp-5) var(--sp-5) var(--sp-3);
  border-bottom: 1px solid var(--border);
}

.wo-drawer-title {
  font: 800 1.05rem var(--font);
  line-height: 1.35;
  margin: 0 0 var(--sp-1);
}

.wo-drawer-body {
  padding: var(--sp-4) var(--sp-5) var(--sp-4);
  overflow: auto;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.wo-field-label {
  font-weight: 600;
  font-size: 0.8rem;
  color: var(--muted);
  margin: var(--sp-4) 0 var(--sp-2);
}

.wo-next-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

.wo-next-actions form {
  margin: 0;
}

.wo-drawer-fields {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-3);
  margin-top: var(--sp-4);
}

.wo-inline-field {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  margin: 0;
}

.wo-inline-field label {
  font-weight: 600;
  font-size: 0.8rem;
  color: var(--muted);
}

.wo-inline-field select {
  margin: 0;
  width: 100%;
}

.priority-pill {
  position: relative;
  cursor: pointer;
}

.priority-pill input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
}

.priority-pill span {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0.45rem 1rem;
  border-radius: 999px;
  font-size: 0.85rem;
  font-weight: 600;
  background: var(--surface-sunken);
  color: var(--muted);
}

.priority-pill input:focus-visible + span {
  outline: 2px solid var(--c-teal);
  outline-offset: 2px;
}

.priority-pill--high input:checked + span {
  background: var(--c-warning-100);
  color: var(--warn);
}

.wo-urgent-toggle {
  justify-self: start;
}

.wo-meta-line {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-wrap: wrap;
}

.wo-waiting {
  margin: var(--sp-4) 0 0;
  padding: var(--sp-2) var(--sp-3);
  border-inline-start: 3px solid var(--border-strong);
  background: var(--surface-sunken);
  border-radius: var(--r-sm);
}

/* The maintenance log, drawn like a messaging app: the reader's own messages
   on the end side, everyone else's on the start side (so RTL mirrors it the
   way Arabic WhatsApp does), status changes as centred markers between them. */
.wo-chat {
  flex: 1 1 auto;
  min-height: 14rem;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-3);
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
}

.wo-chat-empty {
  margin: auto;
}

.wo-chat-marker {
  align-self: center;
  text-align: center;
  font-size: 0.75rem;
  color: var(--muted);
}

.wo-chat-marker > span {
  display: inline-block;
  padding: 2px var(--sp-3);
  border-radius: var(--r-pill);
  background: var(--panel);
  box-shadow: var(--shadow-xs);
}

.wo-chat-marker--status > span {
  background: var(--c-teal-100);
  color: var(--c-teal-700);
  font-weight: 600;
}

.wo-bubble {
  align-self: flex-start;
  max-width: 85%;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--sp-2) var(--sp-3);
  background: var(--panel);
  border-radius: var(--r-md);
  border-start-start-radius: 2px;
  box-shadow: var(--shadow-xs);
}

.wo-bubble--mine {
  align-self: flex-end;
  background: var(--c-teal-100);
  border-start-start-radius: var(--r-md);
  border-start-end-radius: 2px;
}

.wo-bubble-author {
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--c-teal-700);
}

.wo-bubble-text {
  margin: 0;
  line-height: 1.5;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.wo-bubble-time {
  align-self: flex-end;
  font-size: 0.7rem;
  color: var(--muted);
}

.wo-chat-composer {
  display: flex;
  align-items: flex-end;
  gap: var(--sp-2);
  margin: 0;
  padding: var(--sp-3) var(--sp-5);
  border-top: 1px solid var(--border);
  background: var(--panel);
}

.wo-chat-composer textarea {
  flex: 1 1 auto;
  margin: 0;
  min-height: 44px;
  max-height: 9.5em;
  padding: 10px var(--sp-4);
  border: 1px solid var(--border-strong);
  border-radius: 22px;
  font: 400 15px var(--font);
  line-height: 1.5;
  resize: none;
  background: var(--surface-sunken);
  color: var(--text);
}

.wo-chat-send {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease);
}

.wo-chat-send:hover {
  background: var(--accent-hover);
}

.wo-chat-send:focus-visible {
  outline: 2px solid var(--c-teal);
  outline-offset: 2px;
}

.wo-chat-readonly {
  margin: 0;
  padding: var(--sp-3) var(--sp-5);
  border-top: 1px solid var(--border);
}

.wo-timestamps {
  margin: var(--sp-3) 0 0;
}

.wo-composer-card {
  width: min(32rem, 100%);
}

.report-field textarea {
  font: 400 15px var(--font);
  padding: 8px 10px;
  margin-bottom: 0;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  background: #fff;
  color: var(--text);
  width: 100%;
  min-height: 8em;
  line-height: 1.5;
  resize: vertical;
}

@media (min-width: 901px) {
  .wo-drawer-backdrop {
    display: none;
  }
}

@media (max-width: 900px) {
  .wo-page--drawer {
    padding-inline-end: 0;
  }

  .wo-row-grid--head {
    display: none;
  }

  .wo-ticket {
    grid-template-columns: 1fr auto;
    grid-template-areas:
      "title status"
      "school date"
      "assignee assignee";
  }

  .wo-ticket-main { grid-area: title; }
  .wo-ticket-school { grid-area: school; }
  .wo-ticket > span:nth-child(3) { grid-area: status; justify-self: end; }
  .wo-ticket > span:nth-child(4) { grid-area: assignee; }
  .wo-ticket > span:nth-child(5) { grid-area: date; justify-self: end; }

  .wo-drawer-fields {
    grid-template-columns: 1fr;
  }
}

@media (prefers-reduced-motion: reduce) {
  .wo-ticket {
    transition: none;
  }
}

.event-log {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.event-log li {
  padding: var(--sp-2) var(--sp-3);
  background: var(--surface-sunken);
  border-radius: var(--r-sm);
  font-size: 0.88rem;
}

/* ── Login ─────────────────────────────────────────────────────────────
   The solar-panel loop is the page. A vignette holds the edges in ink so
   the glass card reads; the panel cells stay visible through the centre. */

.login-wrap {
  position: relative;
  overflow: hidden;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-5);
  background: var(--c-ink);
}

.login-stage {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: var(--c-ink) url("/static/video/login-bg.jpg") center / cover no-repeat;
}

.login-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 60%;
  transform: scale(1.04);
}

.login-scrim {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse 70% 60% at 50% 48%, rgba(11, 31, 51, 0.18) 0%, rgba(11, 31, 51, 0.55) 72%, rgba(11, 31, 51, 0.78) 100%),
    linear-gradient(180deg, rgba(14, 124, 134, 0.18) 0%, transparent 38%, rgba(11, 31, 51, 0.22) 100%);
  pointer-events: none;
}

.login-card-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-bottom: var(--sp-4);
}

.login-made-in {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  padding: 0;
  color: var(--muted);
  font: 600 11.5px var(--font);
  line-height: 1;
  flex: none;
}

.login-jordan-flag {
  display: block;
  width: 24px;
  height: 12px;
  border-radius: 2px;
  box-shadow: 0 0 0 1px var(--border);
  flex: none;
}

.login-card {
  position: relative;
  z-index: 1;
  width: 360px;
  max-width: 100%;
  background: rgba(255, 255, 255, 0.9);
  border: 1px solid rgba(255, 255, 255, 0.55);
  box-shadow: 0 24px 64px rgba(11, 31, 51, 0.38);
  backdrop-filter: blur(18px) saturate(1.15);
  -webkit-backdrop-filter: blur(18px) saturate(1.15);
  animation: login-card-in 0.55s var(--ease) both;
}

@keyframes login-card-in {
  from { opacity: 0; transform: translateY(14px); }
  to { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .login-video {
    display: none;
  }

  .login-card {
    animation: none;
  }
}

.login-lang-switch {
  margin: 0;
  flex: none;
}

.login-logo {
  display: block;
  width: 64px;
  height: 64px;
  margin: 0 auto var(--sp-3);
}

.login-card h1 {
  font: 800 19px var(--font);
  margin: 0 0 var(--sp-5);
  text-align: center;
  color: var(--c-ink);
}

/* First-login setup (/welcome) sits in the same card as login, so the
   whole first sign-in reads as one flow; a title needs a subtitle under it,
   so the h1's bottom margin gives way to the paragraph's own. */
.login-card .panel-subtitle {
  margin-top: calc(-1 * var(--sp-4));
  margin-bottom: var(--sp-4);
}

.onboarding-step {
  margin: 0 0 var(--sp-2);
  text-align: center;
  font: 600 11.5px var(--font);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--c-teal-700);
}

.onboarding-note {
  font-size: 0.82rem;
  margin: var(--sp-2) 0 var(--sp-4);
}

.login-card .mfa-qr {
  margin-bottom: var(--sp-3);
}

.onboarding-actions {
  display: flex;
  gap: var(--sp-2);
  margin-top: var(--sp-3);
}

/* Two equal halves whatever the labels do: the forms stretch to the row's
   height and each button fills its form, so a label that wraps in one
   language cannot leave the other button shorter. */
.onboarding-actions form {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
}

.onboarding-actions button {
  flex: 1;
  font-size: 0.85rem;
  padding-inline: var(--sp-2);
}

/* ── App shell (sidebar + topbar) ───────────────────────────────────── */

.app-shell {
  display: flex;
  min-height: 100vh;
}

.sidebar {
  width: 250px;
  flex: none;
  background: var(--sidebar-bg);
  display: flex;
  flex-direction: column;
  padding: var(--sp-5) var(--sp-4);
}

.sidebar-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 4px 22px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
  margin-bottom: var(--sp-2);
}

.sidebar-brand-icon {
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
}

.sidebar-brand-icon img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.sidebar-brand-name {
  font: 800 15px var(--font);
  color: #fff;
}

.nav-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.nav-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  border-radius: var(--r-sm);
  text-decoration: none;
  transition: background-color var(--dur-fast, 0.15s) var(--ease);
}

.nav-item:hover {
  background: rgba(255, 255, 255, 0.07);
}

.nav-item.active {
  background: rgba(255, 255, 255, 0.12);
}

.nav-item .nav-label {
  font: 600 13.5px var(--font);
  color: var(--sidebar-text);
}

.nav-item.active .nav-label {
  color: var(--sidebar-text-active);
}

.nav-item svg {
  flex: none;
}

.sidebar-user {
  margin-top: auto;
  padding: 12px;
  border-radius: var(--r-sm);
  background: rgba(255, 255, 255, 0.06);
  display: flex;
  align-items: center;
  gap: 10px;
}

.avatar {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--c-teal);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font: 700 13px var(--font);
  flex: none;
}

.sidebar-user-name {
  font: 600 12.5px var(--font);
  color: #fff;
}

.sidebar-user-role {
  font: 500 11px var(--font);
  color: var(--sidebar-icon);
}

.main-area {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.app-topbar {
  height: 64px;
  flex: none;
  background: #fff;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 28px;
  gap: 16px;
}

.topbar-left {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}

.breadcrumb {
  font: 600 13.5px var(--font);
  color: var(--text);
}

.topbar-right {
  display: flex;
  align-items: center;
  gap: 18px;
}

.topbar-right > a {
  text-decoration: none;
}

.search-input {
  /* Wide enough that its own placeholder text ("Search schools or
     regions…") doesn't get clipped — 230px cut it off mid-word, and 260px
     still wasn't enough on real rendering. There's plenty of free space in
     the topbar for this. Disabled on purpose (search itself isn't built
     yet, see title=/disabled below); this only fixes visual truncation. */
  width: 300px;
  /* Fixed height (border-box, matches .topbar-logout's 32px) instead of
     padding + inherited body line-height (1.55) — the old box worked out
     ~37px tall, visibly taller than every other topbar-right element, so
     its placeholder text sat noticeably higher/lower than the AR/EN pills
     and avatar instead of sitting level with them on the same line. */
  height: 32px;
  padding: 0 12px;
  /* Explicit, not inherited from body (1.55) — line-height set to exactly
     the content-box height (32px - 2px border) is what actually centers
     the placeholder text inside the box; without this, the browser's own
     default input line-height left the text sitting off-center even
     though the box itself was the right height. */
  line-height: 30px;
  border-radius: var(--r-md);
  border: 1px solid var(--border);
  background: var(--surface-sunken);
  font: 400 12.5px var(--font);
  color: var(--text);
  margin-bottom: 0;
}

.search-input:focus-visible {
  outline: 2px solid var(--c-teal);
  outline-offset: 1px;
}

.sidebar-toggle {
  display: none;
  width: 36px;
  height: 36px;
  flex: none;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 0;
  cursor: pointer;
}

.sidebar-toggle:hover {
  background: var(--surface-sunken);
}

.sidebar-backdrop {
  display: none;
}

.notif-bell {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  flex: none;
  border-radius: 50%;
  color: var(--muted);
}

.notif-bell:hover {
  background: var(--surface-sunken);
  color: var(--text);
}

.notif-bell svg {
  display: block;
  fill: currentColor;
}

.notif-count {
  position: absolute;
  top: -2px;
  inset-inline-end: -2px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--danger);
  color: #fff;
  font: 700 9px/1 var(--font);
  border: 2px solid #fff;
  border-radius: var(--r-pill);
  box-sizing: border-box;
  pointer-events: none;
}

.lang-switch {
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  gap: 4px;
  flex-shrink: 0;
  white-space: nowrap;
}

.lang-switch a {
  display: inline-block;
  text-decoration: none;
  padding: 0.2rem 0.55rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  color: var(--text);
  font: 700 11px var(--font);
  line-height: 1.3;
}

.lang-switch a.active {
  background: var(--c-ink);
  color: #fff;
  border-color: var(--c-ink);
}

/* Logout link — was previously a circle with the user's initial, which
   looked identical to (and got confused with) a plain profile avatar. A
   real exit icon (door frame + outward arrow) actually signals "log out". */
.topbar-logout {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--c-ink);
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
}

.topbar-logout:hover {
  background: var(--accent-hover);
}

.content-area {
  flex: 1;
  padding: var(--sp-6);
  overflow: auto;
}

@media (max-width: 900px) {
  .sidebar-toggle {
    display: flex;
  }

  .sidebar {
    position: fixed;
    top: 0;
    bottom: 0;
    inset-inline-start: -260px;
    z-index: 70;
    transition: inset-inline-start 0.25s ease;
  }

  .sidebar.open {
    inset-inline-start: 0;
    box-shadow: var(--shadow-lg);
  }

  .sidebar-backdrop {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 65;
    background: rgba(11, 31, 51, 0.5);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s ease;
  }

  .sidebar-backdrop.open {
    opacity: 1;
    pointer-events: auto;
  }

  .app-topbar {
    padding: 0 16px;
  }

  .content-area {
    padding: var(--sp-4);
  }
}

@media (max-width: 640px) {
  .search-input {
    display: none;
  }

  .topbar-right {
    gap: 12px;
  }
}

/* ── Overview page components ─────────────────────────────────────────── */

.overview-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  margin-bottom: var(--sp-5);
  flex-wrap: wrap;
  gap: var(--sp-3);
}

.overview-title {
  font: 800 23px var(--font);
  color: var(--text);
}

.overview-subtitle {
  font: 500 13px var(--font);
  color: var(--muted);
  margin-top: 4px;
}

.kpi-grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: var(--sp-3);
  margin-bottom: var(--sp-5);
}

.kpi-grid--4 {
  grid-template-columns: repeat(4, 1fr);
}

@media (max-width: 1100px) {
  .kpi-grid { grid-template-columns: repeat(3, 1fr); }
  .kpi-grid--4 { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 640px) {
  .kpi-grid { grid-template-columns: repeat(2, 1fr); }
}

.kpi-tile {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: var(--sp-4);
  display: flex;
  flex-direction: column;
  gap: 9px;
  transition: box-shadow var(--dur-fast, 0.15s) var(--ease), border-color var(--dur-fast, 0.15s) var(--ease);
}

.kpi-tile:hover {
  box-shadow: var(--shadow-sm);
  border-color: var(--border-strong);
}

a.kpi-tile--link {
  text-decoration: none;
  color: inherit;
}

a.kpi-tile--link:hover {
  border-color: var(--c-ink);
}

.kpi-tile-head {
  display: flex;
  align-items: center;
  gap: 8px;
}

.kpi-tile-label {
  font: 600 11px var(--font);
  color: var(--muted);
}

.kpi-tile-value {
  font: 800 21px var(--font);
  color: var(--text);
}

.kpi-tile-delta {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  font: 700 11px var(--font);
}

.delta-good { color: var(--ok); }
.delta-bad { color: var(--danger); }
.delta-sub { font: 500 11px var(--font); color: #8b98a6; }

.grid-main {
  display: grid;
  grid-template-columns: 1.7fr 1fr;
  gap: var(--sp-4);
  margin-bottom: var(--sp-4);
  align-items: stretch;
}

.grid-16-10 {
  display: grid;
  grid-template-columns: 1.6fr 1fr;
  gap: var(--sp-4);
  margin-bottom: var(--sp-4);
}

.grid-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-4);
}

@media (max-width: 1000px) {
  .grid-main, .grid-16-10 { grid-template-columns: 1fr; }
}

@media (max-width: 800px) {
  .grid-2 { grid-template-columns: 1fr; }
}

.panel-card {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--sp-5);
}

.panel-card--flush {
  display: flex;
  flex-direction: column;
}

.panel-card-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: var(--sp-4);
  flex-wrap: wrap;
  gap: 10px;
}

.panel-card-head--tight {
  margin-bottom: 0;
}

.panel-card-actions {
  display: flex;
  align-items: center;
  gap: 14px;
}

/* A <button> that reads as one of the head's links, for actions that change
   nothing on the server and so must not look like a form submit. */
.link-btn {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: var(--accent);
  cursor: pointer;
}

.link-btn:hover {
  color: var(--accent-hover);
  text-decoration: underline;
}

.panel-card-title-row {
  display: flex;
  align-items: center;
  gap: 9px;
}

.panel-card-title-row--split {
  justify-content: space-between;
  margin-bottom: var(--sp-2);
}

.panel-card-title {
  font: 700 14.5px var(--font);
  color: var(--text);
}

.panel-card-title--spaced {
  margin-bottom: var(--sp-3);
}

.panel-card-toolbar {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-wrap: wrap;
}

/* The "+" is drawn as two CSS bars, not the literal text glyph — a "+"
   character's visual weight sits above true center in most fonts (worse
   here since Cairo, this site's only font, doesn't cover this glyph well,
   so it silently falls back to a system font with different metrics),
   which is why it never looked centered no matter how the button's own
   padding/line-height were tuned. The bars are centered by geometry, not
   font metrics, so this is exact regardless of font/rendering engine.
   `aria-label` (already set in the template) covers accessibility — the
   text node is still present, just visually hidden via font-size: 0. */
.icon-btn {
  width: 26px;
  height: 26px;
  padding: 0;
  font-size: 0;
  line-height: 0;
  position: relative;
  flex: none;
}

.icon-btn::before,
.icon-btn::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  background: currentColor;
  transform: translate(-50%, -50%);
}

.icon-btn::before {
  width: 12px;
  height: 2px;
}

.icon-btn::after {
  width: 2px;
  height: 12px;
}

.live-pill {
  display: flex;
  align-items: center;
  gap: 6px;
  background: var(--c-success-100);
  color: var(--ok);
  font: 700 10.5px var(--font);
  padding: 3px 9px;
  border-radius: var(--r-pill);
}

.live-dot {
  position: relative;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--ok);
  flex: none;
}

.live-pill:not(.stale) .live-dot::after {
  content: "";
  position: absolute;
  inset: -4px;
  border-radius: 50%;
  background: var(--ok);
  opacity: 0.55;
  animation: live-pulse 2.2s var(--ease) infinite;
}

@media (prefers-reduced-motion: reduce) {
  .live-pill:not(.stale) .live-dot::after {
    animation: none;
    display: none;
  }
}

@keyframes live-pulse {
  0% { transform: scale(0.6); opacity: 0.55; }
  70% { transform: scale(2.2); opacity: 0; }
  100% { transform: scale(2.2); opacity: 0; }
}

.live-pill.stale {
  background: var(--c-warning-100);
  color: var(--warn);
}

.live-pill.stale .live-dot {
  background: var(--warn);
}

.mode-toggle {
  display: flex;
  gap: var(--sp-2);
  flex-wrap: wrap;
}

.mode-btn {
  padding: 6px 14px;
  border-radius: var(--r-pill);
  border: 1px solid var(--border);
  background: #fff;
  color: var(--text);
  font: 600 11.5px var(--font);
  font-family: var(--font);
  cursor: pointer;
  text-decoration: none;
  display: inline-block;
  width: auto;
  transition: background-color var(--dur-fast, 0.15s) var(--ease), color var(--dur-fast, 0.15s) var(--ease), border-color var(--dur-fast, 0.15s) var(--ease);
}

.mode-btn:hover {
  border-color: var(--border-strong);
  background: var(--surface-sunken);
  color: var(--text);
}

.mode-btn.active {
  background: var(--c-ink);
  border-color: var(--c-ink);
  color: #fff;
}

.mode-btn.active:hover {
  background: var(--c-ink);
  color: #fff;
}

.inverter-tab-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-6);
}

.inverter-tab-group {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  min-width: 0;
}

.inverter-tab-group--brand {
  align-items: center;
}

.inverter-tab-caption {
  font: 700 12px var(--font);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
  margin: 0;
  line-height: 1.2;
}

.inverter-brand-logo {
  display: block;
  height: 44px;
  width: auto;
  max-width: 160px;
  object-fit: contain;
}

.overview-map {
  position: relative;
  width: 100%;
  flex: 1 1 auto;
  min-height: 420px;
  border-radius: var(--r-md);
  overflow: hidden;
  border: 1px solid var(--border);
}

/* Hover label on a map marker. Leaflet's own tooltip, restyled to the
   platform's font and squared off so it reads as a name tag, not a speech
   bubble. */
.leaflet-tooltip.school-tip {
  /* Leaflet positions the tooltip with a transform from its static position
     and never sets left/top. Under dir="rtl" an absolutely-positioned box's
     static position hangs its right edge on the (zero-width) pane origin, so
     the label landed one full width to the left of the marker in Arabic.
     Pinning the origin is a no-op in LTR and puts both languages in the same
     place — leaflet.css does exactly this for .leaflet-marker-icon. */
  left: 0;
  top: 0;
  font: 600 12px var(--font);
  color: var(--text);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 4px 8px;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12);
  white-space: nowrap;
}

.leaflet-tooltip.school-tip::before {
  display: none;
}

.map-legend {
  display: flex;
  gap: 16px;
  margin-top: var(--sp-3);
  flex-wrap: wrap;
}

.legend-item {
  display: flex;
  align-items: center;
  gap: 6px;
  font: 500 11px var(--font);
  color: var(--muted);
}

.legend-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  display: inline-block;
}

.alert-list {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

/* Author `display: flex` beats the UA's `[hidden] { display: none }`, so
   Overview's Clear all — which sets `row.hidden` — needs this to take effect. */
.alert-row[hidden] {
  display: none;
}

.alert-row {
  display: flex;
  gap: 10px;
  padding: var(--sp-3);
  border-radius: var(--r-sm);
  background: var(--surface-sunken);
  border: 1px solid var(--border);
}

.alert-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-top: 5px;
  flex: none;
}

.alert-body {
  min-width: 0;
}

.alert-school {
  font: 600 12.5px var(--font);
  color: var(--text);
}

.alert-msg {
  font: 500 11.5px var(--font);
  color: var(--muted);
  margin-top: 2px;
}

.alert-time {
  font: 500 10.5px var(--font);
  color: #9ca9b6;
  margin-top: 3px;
}

.rank-pill {
  font: 700 12.5px var(--font);
  padding: 4px 10px;
  border-radius: var(--r-pill);
}

.rank-pill.good { color: var(--ok); background: var(--c-success-100); }
.rank-pill.bad { color: var(--danger); background: var(--c-danger-100); }
/* Not yet enough observed days to rank fairly — neither good nor bad, still
   accumulating evidence. Same token as .badge.pending so it reads as one
   "in progress" language across the app. */
.rank-pill.building { color: var(--warn); background: var(--c-warning-100); }

/* School Performance Comparison table (Overview page) */
#schoolBenchmarkTable thead th {
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}

#schoolBenchmarkTable thead th:hover {
  color: var(--text);
}

#schoolBenchmarkTable thead th.sorted-asc::after { content: " \25B2"; }
#schoolBenchmarkTable thead th.sorted-desc::after { content: " \25BC"; }

.row-attention {
  background: var(--c-danger-100);
}

/* A school under maintenance (app/maintenance_mode.py): its figures stay on
   screen but blurred behind one notice, so they read as withheld while a
   worker may have the site switched off, not as a site failing. */
.maint-pill {
  display: inline-flex;
  align-items: center;
  padding: 2px 10px;
  border: 1px solid var(--c-maint);
  border-radius: var(--r-pill);
  background: var(--c-maint-100);
  color: var(--c-maint-ink);
  font-size: 0.8rem;
  font-weight: 700;
  white-space: nowrap;
}

.maint-pill--compact {
  padding: 1px 8px;
  font-size: 0.7rem;
}

.maint-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}

.school-list--rows li > a.school-row-grid.is-maintenance {
  position: relative;
  border-color: var(--c-maint);
}

.school-row-grid.is-maintenance > .school-field:not(.school-col-name),
.maint-blur {
  filter: blur(3px);
  opacity: 0.55;
  user-select: none;
}

.row-maintenance td {
  background: var(--c-maint-100);
}

.maint-cell {
  position: relative;
}

.maint-blur {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--sp-3);
}

.maint-banner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  margin: var(--sp-2) 0 0;
  padding: var(--sp-2) var(--sp-3);
  border-inline-start: 3px solid var(--c-maint);
  border-radius: var(--r-sm);
  background: var(--c-maint-100);
  color: var(--c-maint-ink);
}

.coming-soon {
  height: 100%;
  min-height: 500px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.coming-soon-inner {
  max-width: 420px;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-3);
}

.coming-soon-icon {
  width: 56px;
  height: 56px;
  border-radius: var(--r-lg);
  background: var(--surface-sunken);
  display: flex;
  align-items: center;
  justify-content: center;
}

.coming-soon-title {
  font: 700 17px var(--font);
  color: var(--text);
}

.coming-soon-sub {
  font: 500 13px var(--font);
  color: var(--muted);
  line-height: 1.6;
}

/* ── School dashboard: live readings schematic (signature element) ─────
   The literal path energy takes — PV strings → inverter → energy/grid —
   rendered as a connected pipeline rather than a row of generic bordered
   boxes, since that flow is the one thing genuinely specific to this
   product. */

.solar-flow {
  display: flex;
  align-items: stretch;
  gap: 0;
  margin-top: var(--sp-3);
  overflow-x: auto;
  padding-bottom: 4px;
}

.flow-block {
  flex: 1 1 220px;
  min-width: 200px;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: var(--sp-3) var(--sp-4);
  position: relative;
}

.flow-block::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  inset-block: 0;
  width: 3px;
  border-start-start-radius: var(--r-md);
  border-end-start-radius: var(--r-md);
  background: var(--flow-color, var(--c-teal));
}

.flow-pv_string { --flow-color: var(--c-solar-bright); }
.flow-inverter { --flow-color: var(--c-teal); }
.flow-energy { --flow-color: var(--c-success); }
.flow-device_info { --flow-color: var(--muted); }
.flow-other { --flow-color: var(--muted); }

.flow-block-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: var(--sp-3);
}

.flow-block-icon {
  width: 26px;
  height: 26px;
  border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--flow-color, var(--c-teal)) 14%, white);
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
}

.flow-block-title {
  font: 700 12.5px var(--font);
  color: var(--text);
}

.flow-metrics {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.flow-metric {
  display: flex;
  flex-direction: column;
  padding-bottom: 7px;
  border-bottom: 1px solid var(--border);
}

.flow-metric:last-child {
  border-bottom: none;
  padding-bottom: 0;
}

.flow-metric-label {
  font: 500 11px var(--font);
  color: var(--muted);
}

.flow-metric-value-row {
  display: inline-flex;
  align-items: baseline;
  align-self: start;
  width: max-content;
  gap: 6px;
}

.flow-metric-value {
  font: 700 15px var(--font);
  color: var(--text);
}

.flow-metric-unit {
  font: 600 11px var(--font);
  color: var(--muted);
}

.flow-metric-time {
  font: 500 10px var(--font);
  color: #9ca9b6;
  margin-top: 1px;
}

.flow-arrow {
  display: flex;
  align-items: center;
  justify-content: center;
  align-self: center;
  flex: none;
  width: 28px;
  height: 28px;
  margin-inline: 2px;
  padding: 0;
  line-height: 0;
  border-radius: 50%;
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  color: var(--muted);
}

.flow-arrow svg {
  display: block;
}

[dir="rtl"] .flow-arrow svg {
  transform: scaleX(-1);
}

@media (max-width: 800px) {
  .solar-flow { flex-direction: column; overflow-x: visible; gap: var(--sp-2); }
  .flow-block::before {
    inset-inline: 0;
    inset-block-start: 0;
    width: auto;
    height: 3px;
    border-radius: var(--r-md) var(--r-md) 0 0;
  }
  .flow-arrow { align-self: center; transform: rotate(90deg); }
  [dir="rtl"] .flow-arrow svg { transform: none; }
}

.summary-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--sp-3);
}

@media (max-width: 560px) {
  .summary-grid { grid-template-columns: repeat(2, 1fr); }
}

.school-map {
  width: 100%;
  height: 280px;
  border-radius: var(--r-md);
  border: 1px solid var(--border);
}

.weather-range {
  margin: 0 0 var(--sp-6);
}

.weather-kpi-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-3);
  margin-bottom: var(--sp-4);
}

.weather-charts {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-3);
}

.weather-chart {
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: var(--sp-3) var(--sp-4);
  position: relative;
}

.weather-chart-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-2);
  margin-bottom: var(--sp-2);
}

.weather-chart-title {
  font: 600 12px var(--font);
  color: var(--muted);
  min-width: 0;
}

.weather-chart-period {
  font: 600 11px var(--font);
  color: var(--muted);
  flex: none;
  white-space: nowrap;
}

.weather-chart-canvas {
  width: 100%;
}

.weather-svg {
  display: block;
  border-radius: var(--r-sm);
  background: #fff;
  width: 100%;
  height: auto;
}

.weather-axis-label {
  font: 500 10px var(--font);
  fill: #7a8b9a;
}

.weather-axis-unit {
  font: 600 10px var(--font);
  fill: var(--muted);
}

.weather-tooltip {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 0.55rem 1.75rem;
  margin-top: var(--sp-3);
  padding: 14px 20px;
  min-height: 3.4rem;
  border-radius: var(--r-md);
  background: var(--c-ink);
  color: #fff;
  font: 600 16px/1.2 var(--font);
}

.weather-tooltip[hidden] {
  display: none;
}

.weather-tooltip-item {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
}

.weather-tooltip-label {
  font: 600 13px var(--font);
  color: var(--sidebar-icon-active);
}

.weather-tooltip-val {
  font: 800 1.2rem var(--font);
  font-variant-numeric: tabular-nums;
  color: #fff;
}

.weather-tooltip-sep {
  width: 1px;
  height: 1.35em;
  background: rgba(255, 255, 255, 0.22);
  flex: none;
}

/* Weather cards are a third of the row — the school-chart readout size
   wraps Date/Value onto two lines. Keep that size for inverter charts;
   shrink only this bar so the pair stays on one line. */
.weather-chart .weather-tooltip {
  flex-wrap: nowrap;
  gap: 0.25rem 0.5rem;
  padding: 8px 10px;
  min-height: 0;
  overflow: hidden;
}

.weather-chart .weather-tooltip-item {
  flex: none;
  flex-wrap: nowrap;
  gap: 0.28rem;
  white-space: nowrap;
}

.weather-chart .weather-tooltip-label {
  font-size: 10px;
  flex: none;
}

.weather-chart .weather-tooltip-val {
  font: 700 0.72rem/1.2 var(--font);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.weather-chart .weather-tooltip-sep {
  height: 0.9em;
}

.weather-tooltip strong {
  font-weight: 600;
  color: var(--sidebar-icon-active);
}

@media (max-width: 900px) {
  .weather-kpi-grid,
  .weather-charts { grid-template-columns: 1fr; }
}

/* System Overview → Chart view */
.chart-period-toggle {
  margin-top: var(--sp-3);
}

.chart-day-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: var(--sp-3);
  padding: 10px 0 4px;
  border-top: 1px solid var(--border);
}

.chart-day-center {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  justify-content: center;
}

.chart-day-input {
  width: auto;
  font: 600 13px var(--font);
  font-family: var(--font);
  padding: 6px 10px;
  margin-bottom: 0;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  background: #fff;
  color: var(--text);
}

.chart-nav-btn {
  padding: 0.45rem 0.9rem;
  font-family: var(--font);
  font-weight: 600;
  font-size: 0.85rem;
}

.chart-nav-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

/* Data update frequency slider — ends labels sit under the track only */
.push-interval-form {
  max-width: 420px;
}

.push-interval-row {
  display: flex;
  align-items: flex-start;
  gap: 14px;
}

.push-interval-slider-col {
  flex: 1;
  min-width: 0;
}

.push-interval-slider-col input[type="range"] {
  width: 100%;
  display: block;
  accent-color: var(--c-teal);
}

.push-interval-ends {
  display: flex;
  justify-content: space-between;
  font-size: 0.78em;
  color: var(--muted);
  margin-top: 2px;
}

.push-interval-value {
  display: flex;
  align-items: baseline;
  gap: 6px;
  padding-top: 2px;
  flex-shrink: 0;
}

.push-interval-value #pushIntervalValue {
  min-width: 1.5em;
  text-align: end;
  font-weight: 700;
  font-family: var(--font);
}

.push-interval-save {
  margin-top: var(--sp-3);
}

.overview-charts-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-3);
  margin-top: var(--sp-3);
}

.overview-chart {
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: var(--sp-3) var(--sp-4);
  position: relative;
}

.overview-chart.wide {
  grid-column: 1 / -1;
}

.overview-chart-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  flex-wrap: wrap;
  margin-bottom: var(--sp-2);
}

.overview-chart-title {
  font: 600 12px var(--font);
  color: var(--muted);
}

/* Tabs inside a chart card (the grid lines) — same pills as the period
   toggle above the grid, a size down so they read as part of the card. */
.chart-series-tabs {
  gap: var(--sp-1);
}

.chart-series-tabs:empty {
  display: none;
}

.chart-series-tabs .mode-btn {
  padding: 3px 10px;
  font-size: 11px;
}

.overview-chart-canvas {
  width: 100%;
}

@media (max-width: 900px) {
  .overview-charts-grid { grid-template-columns: 1fr; }
  .overview-chart.wide { grid-column: auto; }
}

/* While any report-dialog-style modal is open, the page behind it (which
   can include the Leaflet map on the Overview page) must not scroll —
   otherwise the fixed-position dialog and the scrolling map behind it
   visibly intersect/overlap as the user scrolls. */
body.modal-open {
  overflow: hidden;
}

/* Add-school / period report dialogs. z-index must clear Leaflet's own
   internal chrome (its zoom control / attribution panes render at z-index
   800-1000 in Leaflet's own stylesheet) — otherwise the school map behind
   this dialog visibly punches through it, controls and all. */
.report-dialog {
  position: fixed;
  inset: 0;
  z-index: 2000;
  background: rgba(11, 31, 51, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}

.report-dialog[hidden] {
  display: none !important;
}

.report-dialog-card {
  width: min(440px, 100%);
  background: #fff;
  border-radius: var(--r-lg);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
  padding: 18px 18px 16px;
}

.report-dialog-head {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin-bottom: 6px;
}

.report-dialog-title {
  flex: 1;
  min-width: 0;
  margin: 0;
  font: 700 14px var(--font);
  color: var(--text);
  text-transform: none;
  letter-spacing: 0;
  line-height: 1.35;
}

.report-dialog-close {
  border: none;
  background: transparent;
  font-family: var(--font);
  font-size: 1.5rem;
  line-height: 1;
  color: var(--muted);
  cursor: pointer;
  padding: 0;
  width: auto;
  flex: 0 0 auto;
  align-self: flex-start;
  margin-inline-start: auto;
}

.report-dialog-close:hover {
  color: var(--text);
}

.report-dialog-fields {
  display: grid;
  gap: 12px;
}

/* From/To pair shown for weekly/monthly/yearly instead of the single-day
   field — side by side so the range reads as one unit. */
.report-field-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}

.report-field-row[hidden] {
  display: none;
}

/* "To" is computed from "From" (calendar-aligned period end), never typed
   directly — grey it out so it reads as derived, not editable. */
.report-field input[type="date"]:disabled {
  background: var(--surface-sunken);
  color: var(--muted);
}

.report-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font: 600 12px var(--font);
  color: var(--muted);
}

/* This class's own `display: flex` above outranks the browser's default
   `[hidden] { display: none }` (author rules beat UA rules regardless of
   specificity) — without this, JS setting .hidden on #reportDayField does
   nothing and the Day field stays visible alongside From/To. */
.report-field[hidden] {
  display: none;
}

.report-field select,
.report-field input,
.report-field input[type="date"] {
  font: 600 13px var(--font);
  font-family: var(--font);
  padding: 8px 10px;
  margin-bottom: 0;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  background-color: #fff;
  color: var(--text);
  width: 100%;
  box-sizing: border-box;
}

/* Same edge-hugging-arrow fix as the base `select` rule — this dialog's
   compact 8px/10px padding above would otherwise overwrite the chevron's
   breathing room from that rule. background: shorthand on the rule above
   used to wipe the arrow entirely. */
.report-field select {
  padding-inline-end: 2.4rem;
  cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1.5 1.5L6 6.5 10.5 1.5' stroke='%230b1f33' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.85rem center;
  background-size: 12px 8px;
}

/* Keep the typed date beside the calendar icon. Native date inputs are
   LTR chrome; right-align the value in RTL so it sits next to the icon. */
.report-field input[type="date"] {
  direction: ltr;
  text-align: left;
}

.report-dialog-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: var(--sp-4);
}

/* Settings > Delete a School — searchable combobox, deliberately not a
   table: this list is meant to scale to hundreds of schools. */
.school-delete-picker {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  max-width: 420px;
}

/* Full-size button (not .btn-sm) so its height actually matches the search
   input beside it — .btn-sm's much smaller padding/font-size made the
   button look visibly shorter than the box next to it. flex: none keeps it
   from ever being squeezed narrower than its (longer, in Arabic) label. */
/* Outstanding WhatsApp confirmation for a delete/swap: sits above both
   controls, edged in the danger colour because whatever is typed here
   goes straight through. */
.confirm-action {
  border-color: var(--danger);
}

#confirmActionCode {
  flex: none;
  width: 9ch;
  text-align: center;
  letter-spacing: 0.15em;
}

#schoolDeleteBtn,
#deviceSwapBtn,
.confirm-action .btn-danger {
  flex: none;
  white-space: nowrap;
}

/* The device-number box sits in its own row so a 6-digit field is not
   stretched to the width of a school name. */
#deviceSwapCode {
  flex: none;
  width: 9ch;
  text-align: center;
  letter-spacing: 0.15em;
}

.school-delete-field {
  position: relative;
  flex: 1;
}

.school-delete-search {
  margin-bottom: 0;
}

.school-delete-options {
  position: absolute;
  top: calc(100% + 4px);
  inset-inline-start: 0;
  inset-inline-end: 0;
  max-height: 260px;
  overflow-y: auto;
  background: var(--panel);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg, 0 8px 24px rgba(11, 31, 51, 0.16));
  z-index: 20;
}

.school-delete-options[hidden] {
  display: none;
}

.school-delete-option {
  padding: 0.5rem 0.7rem;
  font-size: 0.9rem;
  cursor: pointer;
}

.school-delete-option:hover {
  background: var(--surface-sunken);
}

.school-delete-option[hidden] {
  display: none;
}

.school-delete-empty {
  padding: 0.5rem 0.7rem;
  font-size: 0.85rem;
  color: var(--muted);
}

.school-delete-empty[hidden] {
  display: none;
}

/* Audit log feed — one card per event so action/school/details stay in the
   UI language instead of a raw snake_case table. */
.audit-toolbar {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-4);
  margin-bottom: var(--sp-4);
}

.audit-feed {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.audit-item {
  display: grid;
  grid-template-columns: 9.5rem minmax(0, 1fr);
  gap: var(--sp-4);
  align-items: start;
  padding: var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--panel);
}

.audit-time {
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.audit-action {
  margin: 0 0 var(--sp-1);
  font-weight: 700;
  font-size: 0.98rem;
}

.audit-meta {
  margin: 0;
  font-size: 0.85rem;
  color: var(--muted);
}

.audit-dot {
  padding-inline: 0.25rem;
}

.audit-details {
  margin: var(--sp-2) 0 0;
  font-size: 0.9rem;
  line-height: 1.5;
}

@media (max-width: 640px) {
  .audit-item {
    grid-template-columns: 1fr;
    gap: var(--sp-2);
  }

  .audit-toolbar {
    flex-direction: column;
  }
}
