/* ==========================================================================
   RioTech — design system
   Layered on top of Bootstrap 5.3. Brand teal #35A8C0 is taken from the
   RioNadi logo. Mobile-first: every rule here assumes small screens and
   scales up, never the reverse.
   ========================================================================== */

:root {
  /* Brand */
  --rt-teal:        #35A8C0;
  --rt-teal-600:    #2A8A9E;
  --rt-teal-700:    #226F80;
  --rt-teal-050:    #EAF7FA;

  /* Neutrals */
  --rt-ink:         #16232E;
  --rt-body:        #3D4E5C;
  --rt-muted:       #6B7C8A;
  --rt-line:        #E3E9ED;
  --rt-surface:     #FFFFFF;
  --rt-bg:          #F4F7F9;

  /* Status */
  --rt-ok:          #1F9254;
  --rt-ok-bg:       #E8F6EE;
  --rt-warn:        #A9700B;
  --rt-warn-bg:     #FDF3E0;
  --rt-err:         #C0392B;
  --rt-err-bg:      #FBEDEB;

  /* Height of the controls sitting in the navbar (search box, account
     button) so they always line up with each other. */
  --rt-navctl-h:    46px;

  /* Shape */
  --rt-radius:      12px;
  --rt-radius-sm:   8px;
  --rt-shadow:      0 1px 2px rgba(22, 35, 46, .05), 0 4px 16px rgba(22, 35, 46, .05);
  --rt-shadow-lg:   0 2px 6px rgba(22, 35, 46, .06), 0 16px 40px rgba(22, 35, 46, .10);

  /* Bootstrap overrides */
  --bs-primary:     #35A8C0;
  --bs-link-color:  #226F80;
  --bs-link-hover-color: #16232E;
  --bs-body-color:  #3D4E5C;
  --bs-body-bg:     #F4F7F9;
  --bs-border-color: #E3E9ED;
}

/* --------------------------------------------------------------------------
   Base
   -------------------------------------------------------------------------- */

body {
  background-color: var(--rt-bg);
  color: var(--rt-body);
  font-size: 0.9375rem;
  -webkit-font-smoothing: antialiased;
  /* Never let a wide table push the whole page sideways on a phone. */
  overflow-x: hidden;
}

h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
  color: var(--rt-ink);
  font-weight: 600;
  letter-spacing: -0.011em;
}

a { text-decoration: none; }
a:hover { text-decoration: underline; }

/* Anchors styled as buttons or menu items are controls, not links — the
   underline above must not follow them. Real links keep it. */
.btn:hover, .btn:focus,
.dropdown-item:hover, .dropdown-item:focus {
  text-decoration: none;
}

code, kbd, samp, pre { font-size: 0.875em; }

/* Bigger tap targets on touch devices — 44px is the accessible minimum. */
@media (hover: none) and (pointer: coarse) {
  .btn, .form-control, .form-select, .nav-link, .dropdown-item {
    min-height: 44px;
  }
  .btn { display: inline-flex; align-items: center; justify-content: center; }
}

/* Keyboard focus stays visible everywhere. */
:focus-visible {
  outline: 2px solid var(--rt-teal);
  outline-offset: 2px;
}

/* --------------------------------------------------------------------------
   Navbar
   -------------------------------------------------------------------------- */

.rt-navbar {
  background: var(--rt-surface);
  border-bottom: 1px solid var(--rt-line);
  padding-top: .5rem;
  padding-bottom: .5rem;
}

.rt-navbar .navbar-brand img { height: 30px; width: auto; }

.rt-navbar .nav-link {
  color: var(--rt-body);
  font-weight: 500;
  border-radius: var(--rt-radius-sm);
  padding: .5rem .75rem;
}

.rt-navbar .nav-link:hover,
.rt-navbar .nav-link:focus {
  color: var(--rt-teal-700);
  background: var(--rt-teal-050);
  text-decoration: none;
}

.rt-navbar .nav-link.active {
  color: var(--rt-teal-700);
  background: var(--rt-teal-050);
}

.navbar-toggler {
  border: 1px solid var(--rt-line);
  padding: .4rem .6rem;
}
.navbar-toggler:focus { box-shadow: none; outline: 2px solid var(--rt-teal); }

/* The slide-in panel used instead of a dropdown accordion on small screens. */
.rt-offcanvas { max-width: 84vw; background: var(--rt-surface); }
.rt-offcanvas .offcanvas-header { border-bottom: 1px solid var(--rt-line); }

/* Avatar chip */
.rt-avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--rt-teal);
  color: #fff;
  font-size: .8125rem;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
}

/* --------------------------------------------------------------------------
   Page shell
   -------------------------------------------------------------------------- */

.rt-main { padding-top: 1.25rem; padding-bottom: 3rem; }

/* Stop content sprawling across ultrawide monitors. */
.rt-main > .container-fluid { max-width: 1560px; }

/* --------------------------------------------------------------------------
   Desktop: the page itself does not scroll — the content area does.
   The scrollbar therefore sits *below* the menu, and the navbar keeps the full
   viewport width on every page. Without this, a short page (Dashboard) and a
   long one (Chargers) get different viewport widths and the menu jumps
   sideways between them.
   Phones keep normal page scrolling: a fixed-height scroll container breaks
   momentum scrolling and the browser's collapsing address bar, and mobile
   overlay scrollbars take no layout space so there is nothing to fix.
   -------------------------------------------------------------------------- */

@media (min-width: 992px) {
  html, body { height: 100%; }

  body {
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }

  .rt-navbar { flex: 0 0 auto; }

  .rt-main {
    flex: 1 1 auto;
    overflow-y: auto;
    /* Keeps the content column itself from shifting when the inner scrollbar
       appears — same reasoning, applied to the scroll container instead of
       the whole page. */
    scrollbar-gutter: stable;
  }
}

.rt-page-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: .75rem;
  margin-bottom: 1.25rem;
}

.rt-page-title {
  font-size: 1.375rem;
  margin: 0;
  line-height: 1.25;
}

@media (min-width: 768px) {
  .rt-page-title { font-size: 1.625rem; }
  .rt-main { padding-top: 1.75rem; }
}

.rt-page-sub {
  color: var(--rt-muted);
  font-size: .875rem;
  margin: .25rem 0 0;
}

/* --------------------------------------------------------------------------
   Cards
   -------------------------------------------------------------------------- */

.rt-card {
  background: var(--rt-surface);
  border: 1px solid var(--rt-line);
  border-radius: var(--rt-radius);
  box-shadow: var(--rt-shadow);
  height: 100%;
}

.rt-card-head {
  padding: .875rem 1.125rem;
  border-bottom: 1px solid var(--rt-line);
  font-weight: 600;
  color: var(--rt-ink);
  display: flex;
  align-items: center;
  gap: .5rem;
}

.rt-card-body { padding: 1.125rem; }

/* Tabs sitting in a card header (Bootstrap nav-tabs, restyled). */
.rt-tabs {
  border-bottom: 1px solid var(--rt-line);
  padding: 0 .5rem;
  /* Scroll sideways on a phone rather than wrapping to two rows. */
  flex-wrap: nowrap;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}

.rt-tabs::-webkit-scrollbar { display: none; }

.rt-tabs .nav-link {
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  color: var(--rt-muted);
  font-weight: 600;
  font-size: .875rem;
  padding: .75rem 1rem;
  white-space: nowrap;
}

.rt-tabs .nav-link:hover {
  color: var(--rt-teal-700);
  border-bottom-color: var(--rt-line);
}

.rt-tabs .nav-link.active {
  color: var(--rt-teal-700);
  background: transparent;
  border-bottom-color: var(--rt-teal);
}

/* Stat tile */
.rt-stat {
  background: var(--rt-surface);
  border: 1px solid var(--rt-line);
  border-radius: var(--rt-radius);
  box-shadow: var(--rt-shadow);
  padding: .875rem 1rem;
  height: 100%;
  display: flex;
  flex-direction: column;
  gap: .3rem;
}

@media (min-width: 768px) {
  .rt-stat { padding: 1rem 1.125rem; gap: .35rem; }
}

.rt-stat-label {
  font-size: .75rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--rt-muted);
}

.rt-stat-value {
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--rt-ink);
  line-height: 1.2;
  /* Long values (emails, ids) wrap instead of overflowing on a phone. */
  overflow-wrap: anywhere;
}

@media (min-width: 768px) {
  .rt-stat-value { font-size: 1.375rem; }
}

.rt-stat-icon { color: var(--rt-teal); flex: 0 0 auto; }

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */

.btn { font-weight: 500; border-radius: var(--rt-radius-sm); }

.btn-primary,
.btn-primary:disabled {
  background-color: var(--rt-teal);
  border-color: var(--rt-teal);
  color: #fff;
}
.btn-primary:hover,
.btn-primary:focus,
.btn-primary:active {
  background-color: var(--rt-teal-600) !important;
  border-color: var(--rt-teal-600) !important;
  color: #fff !important;
}

.btn-outline-secondary {
  border-color: var(--rt-line);
  color: var(--rt-body);
  background: var(--rt-surface);
}
.btn-outline-secondary:hover,
.btn-outline-secondary:focus {
  background: var(--rt-bg);
  border-color: var(--rt-muted);
  color: var(--rt-ink);
}

/* Full-width buttons on phones, natural width from sm up. */
.rt-actions {
  display: flex;
  flex-direction: column;
  gap: .5rem;
}
.rt-actions .btn { width: 100%; }

@media (min-width: 576px) {
  .rt-actions { flex-direction: row; }
  .rt-actions .btn { width: auto; min-width: 140px; }
}

/* --------------------------------------------------------------------------
   Forms
   -------------------------------------------------------------------------- */

.form-label {
  font-size: .8125rem;
  font-weight: 600;
  color: var(--rt-ink);
  margin-bottom: .3rem;
}

.form-control, .form-select {
  border-color: var(--rt-line);
  border-radius: var(--rt-radius-sm);
  /* 16px stops iOS Safari zooming the viewport when a field is focused. */
  font-size: 1rem;
  padding: .55rem .75rem;
}

@media (min-width: 768px) {
  .form-control, .form-select { font-size: .9375rem; }
}

.form-control:focus, .form-select:focus {
  border-color: var(--rt-teal);
  box-shadow: 0 0 0 3px rgba(53, 168, 192, .18);
}

.rt-fieldset { margin-bottom: 1.75rem; }

.rt-fieldset-legend {
  font-size: .75rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--rt-muted);
  padding-bottom: .5rem;
  margin-bottom: 1rem;
  border-bottom: 1px solid var(--rt-line);
}

/* --------------------------------------------------------------------------
   Token / copy field
   -------------------------------------------------------------------------- */

.rt-token {
  display: flex;
  align-items: center;
  gap: .5rem;
  background: var(--rt-bg);
  border: 1px solid var(--rt-line);
  border-radius: var(--rt-radius-sm);
  padding: .5rem .625rem;
}

.rt-token code {
  color: var(--rt-ink);
  font-size: .8125rem;
  /* A 40-char token must wrap on a phone, not scroll the page. */
  overflow-wrap: anywhere;
  min-width: 0;
  flex: 1 1 auto;
}

/* --------------------------------------------------------------------------
   Badges / alerts
   -------------------------------------------------------------------------- */

.rt-badge {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  font-size: .75rem;
  font-weight: 600;
  padding: .2rem .55rem;
  border-radius: 999px;
}
.rt-badge-ok   { background: var(--rt-ok-bg);   color: var(--rt-ok); }
.rt-badge-warn { background: var(--rt-warn-bg); color: var(--rt-warn); }
.rt-badge-info { background: var(--rt-teal-050); color: var(--rt-teal-700); }

.rt-messages {
  position: sticky;
  top: .75rem;
  z-index: 1030;
}

.rt-messages .alert {
  border: 1px solid var(--rt-line);
  border-radius: var(--rt-radius-sm);
  box-shadow: var(--rt-shadow);
}

/* --------------------------------------------------------------------------
   Tables — horizontal scroll is contained, never the page
   -------------------------------------------------------------------------- */

.rt-table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--rt-line);
  border-radius: var(--rt-radius);
  background: var(--rt-surface);
}

.rt-table-wrap > .table { margin-bottom: 0; }

/* Bootstrap paints every cell with --bs-table-bg, which defaults to
   --bs-body-bg — the grey page colour here. That grey then covers the white
   wrapper, so tables looked like they sat on the page rather than on a
   surface. Cells belong on the card surface. */
.table { --bs-table-bg: var(--rt-surface); }

.rt-table-wrap > .table > thead th {
  font-size: .75rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--rt-muted);
  font-weight: 600;
  border-bottom-color: var(--rt-line);
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   Auth (login) screen
   -------------------------------------------------------------------------- */

/* Column on phones so the brand panel hugs its content and the form gets the
   rest of the screen. Side-by-side halves from lg up. */
.rt-auth {
  min-height: 100vh;
  min-height: 100dvh;
  flex-direction: column;
  flex-wrap: nowrap;
}

@media (min-width: 992px) {
  .rt-auth { flex-direction: row; }
}

.rt-auth-brand {
  background: linear-gradient(150deg, var(--rt-teal) 0%, var(--rt-teal-700) 100%);
  color: #fff;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 1.5rem;
  flex: 0 0 auto;          /* mobile: only as tall as the logo */
}

@media (min-width: 992px) {
  .rt-auth-brand { flex: 0 0 50%; }
}

.rt-auth-brand img { max-width: 180px; width: 45%; }

.rt-auth-tagline {
  color: rgba(255, 255, 255, .88);
  max-width: 34ch;
  margin-top: 1rem;
}

.rt-auth-panel {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem 1.25rem;
  flex: 1 1 auto;          /* takes whatever the brand panel leaves */
}

.rt-auth-card {
  width: 100%;
  max-width: 400px;
  background: var(--rt-surface);
  border: 1px solid var(--rt-line);
  border-radius: var(--rt-radius);
  box-shadow: var(--rt-shadow-lg);
  padding: 1.75rem 1.5rem;
}

@media (min-width: 992px) {
  .rt-auth-brand { padding: 3rem; }
  .rt-auth-card { padding: 2.25rem 2rem; }
}

.rt-footnote {
  color: var(--rt-muted);
  font-size: .8125rem;
}

/* Respect reduced-motion preferences. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    transition-duration: .01ms !important;
  }
}

/* ── Charger live state ───────────────────────────────────────────────
   Online/offline dot. Colour alone never carries the meaning — the word
   "Online" or "Offline" is always next to it.                          */
.rt-dot {
  display: inline-block;
  width: .5rem;
  height: .5rem;
  border-radius: 50%;
  margin-right: .4rem;
  vertical-align: baseline;
}
.rt-dot-ok  { background: var(--rt-ok); }
.rt-dot-off { background: var(--rt-muted); }

/* ── Charger message log ──────────────────────────────────────────────
   Raw OCPP frames. Fixed-height scroll panel so a long log doesn't push
   the rest of the page away.                                           */
.rt-logs {
  /* Phones: a viewport-relative height, since the card is not stretched to
     anything there. Desktop overrides this to fill the card — see
     .rt-detail-card below. */
  height: calc(100vh - 19rem);
  min-height: 16rem;
  overflow-y: auto;
  border: 1px solid var(--rt-line);
  border-radius: var(--rt-radius);
  background: var(--rt-bg);
  padding: .5rem;
}
.rt-log-row {
  background: var(--rt-surface);
  border: 1px solid var(--rt-line);
  border-radius: 8px;
  padding: .4rem .6rem;
  margin-bottom: .4rem;
}
.rt-log-row:last-child { margin-bottom: 0; }
.rt-log-action {
  display: inline-block;
  font-size: .75rem;
  font-weight: 600;
  color: var(--rt-teal-700);
  margin-right: .5rem;
}
.rt-log-payload {
  font-size: .75rem;
  color: var(--rt-body);
  overflow-wrap: anywhere;
}

/* Print: QR code page only needs the code itself. */
@media print {
  .rt-navbar, .rt-footer { display: none !important; }
  .rt-card { border: none; box-shadow: none; }
}

/* ── Navbar charger search ────────────────────────────────────────────
   Sits left of the account dropdown on desktop; full width inside the
   offcanvas on phones.

   The search controls and the account button are locked to one height via
   --rt-navctl-h. The account button's natural height comes from the 32px
   avatar inside it, so without this the two sit at different heights.   */
.rt-navsearch { width: 100%; }

@media (min-width: 992px) {
  .rt-navsearch { width: auto; }
  .rt-navsearch .form-control { width: 11rem; }

  .rt-navsearch .form-control,
  .rt-navsearch .btn,
  .rt-navbar .dropdown > .btn {
    height: var(--rt-navctl-h);
  }
}

/* Pretty-printed JSON inside a log row keeps its line breaks but must not
   force the panel to scroll sideways. */
pre.rt-log-payload {
  white-space: pre-wrap;
  word-break: break-word;
  margin: 0;
}

/* ── Charger detail: left card fills the row ──────────────────────────
   The row's height is set by the taller column (the station detail cards
   on the right). Without this the tab body keeps its natural height and
   the log panel stops short, leaving dead white space under it.
   min-height:0 on each flex ancestor is what lets the log panel shrink
   and scroll internally instead of overflowing the card.               */
@media (min-width: 992px) {
  /* Taking the card out of flow means it contributes nothing to the row's
     height, so the row is sized by the station cards on the right. The
     column still stretches to that height, and the card fills it. The log
     panel then scrolls inside rather than running past the right column. */
  .rt-detail-col { position: relative; min-height: 34rem; }

  .rt-detail-col > .rt-detail-card {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
  }

  /* The tab strip must keep its natural height. Default flex items are
     shrinkable, so in a height-constrained column the browser squashes it
     to nothing and the tabs vanish. */
  .rt-detail-card > .rt-tabs { flex: 0 0 auto; }

  .rt-detail-card > .tab-content {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    min-height: 0;
    overflow: hidden;
  }

  /* Tabs without their own scroll area (Manage, Billing) scroll as a whole. */
  .rt-detail-card .tab-pane.active {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    min-height: 0;
    overflow-y: auto;
  }

  /* Flex children shrink by default, which silently squashes tables down to
     their header row. Only the log panel is allowed to flex. */
  .rt-detail-card .tab-pane.active > * { flex: 0 0 auto; }
  .rt-detail-card .tab-pane.active > .rt-logs { flex: 1 1 auto; }

  .rt-detail-card .rt-logs {
    flex: 1 1 auto;
    height: auto;
    min-height: 8rem;
  }
}

/* Loading / end-of-list line inside the log panel. */
.rt-log-status {
  padding: .5rem .25rem;
  text-align: center;
}

/* OCPP message id — the correlation key between a request and its response. */
.rt-log-id {
  display: inline-block;
  font-size: .7rem;
  font-family: var(--bs-font-monospace, monospace);
  color: var(--rt-muted);
  margin-right: .5rem;
}

/* ── Fault chart ──────────────────────────────────────────────────────
   90 thin bars, one per day, scaled to the busiest day. Plain divs — no
   charting library, nothing loaded from a CDN.                         */
.rt-chart {
  display: flex;
  align-items: flex-end;
  gap: 1px;
  height: 120px;
  padding: .25rem;
  border: 1px solid var(--rt-line);
  border-radius: var(--rt-radius-sm);
  background: var(--rt-bg);
  overflow-x: auto;
}
.rt-chart-col {
  flex: 1 1 0;
  min-width: 4px;
  height: 100%;
  display: flex;
  align-items: flex-end;
  cursor: default;
}
.rt-chart-col:hover .rt-chart-bar,
.rt-chart-col:focus .rt-chart-bar { background: var(--rt-teal-700); }
.rt-chart-col:focus { outline: 2px solid var(--rt-teal); outline-offset: 1px; }
/* A pinned bar stays highlighted after the pointer leaves, so it is obvious
   which day the code list below belongs to. */
.rt-chart-col { cursor: pointer; }
.rt-chart-col.is-pinned .rt-chart-bar { background: var(--rt-teal-700); }
.rt-chart-col.is-pinned { outline: 2px solid var(--rt-teal); outline-offset: 1px; }
.rt-chart-bar {
  width: 100%;
  background: var(--rt-teal);
  border-radius: 2px 2px 0 0;
  min-height: 2px;
}
/* A day with no faults still gets a hairline, so an empty chart reads as 90
   quiet days rather than a broken panel. --rt-line is too close to the panel
   background to be seen, hence the darker grey. */
.rt-chart-bar.is-empty { background: #C3CED6; height: 3px !important; }

/* A flex column stretches its children, which turns an inline button into a
   full-width bar. Buttons keep their natural width. */
@media (min-width: 992px) {
  .rt-detail-card .tab-pane.active > .btn { align-self: flex-start; }
}

/* Vendor codes act as links but read as data, so no underline — the colour
   and cursor already say they are clickable. */
.rt-code-link,
.rt-code-link:hover,
.rt-code-link:focus { text-decoration: none; }
/* Inline in a sentence, the link takes the sentence's size. */
.rt-footnote .rt-code-link { font-size: inherit; vertical-align: baseline; }


/* ── Fleet Health ────────────────────────────────────────────────────────
   Colour on this page means exactly one thing: connector state. Rankings use
   a single hue with the name as the label, because at hundreds of accounts a
   colour each is impossible and inventing one makes a chart unreadable.

   Faulted and Unavailable were originally the brand red and amber, which sit
   only ΔE 4.8 apart under deuteranopia — indistinguishable to a colourblind
   reader, and they are the two states most needing to be told apart. Re-stepped
   to a dark red and a light amber at ΔE 30+, and every state also carries its
   initial so nothing depends on colour at all.                              */

:root{
  --rt-rank:        #2a78d6;
  --rt-rank-soft:   #9ec5f4;
  --rt-st-charging: #1F9254;
  --rt-st-ready:    #8FA3AF;
  --rt-st-unavail:  #D9A441;
  --rt-st-faulted:  #96271C;
  --rt-st-silent:   #DDE3E7;
  --rt-st-other:    #B9C4CC;
}

.rt-fleet-kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(158px,1fr));
  gap:12px;margin-bottom:16px}
.rt-kpi{background:var(--rt-surface);border:1px solid var(--rt-line);border-radius:8px;
  padding:11px 14px}
.rt-kpi .n{font-size:28px;font-weight:600;color:var(--rt-ink);line-height:1.08;
  font-variant-numeric:tabular-nums}
.rt-kpi .l{font-size:12px;color:var(--rt-muted);margin-top:2px}
.rt-kpi .t{font-size:11.5px;color:var(--rt-muted);margin-top:4px}
.rt-kpi.alert{border-color:#D9A79F;background:#FDF6F5}
.rt-kpi.alert .n{color:var(--rt-st-faulted)}

.rt-stackbar{display:flex;height:28px;border-radius:5px;overflow:hidden;gap:2px;margin:2px 0 10px}
.rt-seg{display:flex;align-items:center;justify-content:center;font-size:11.5px;
  font-weight:600;color:#fff;min-width:0}
.rt-seg-charging{background:var(--rt-st-charging)}
.rt-seg-available{background:var(--rt-st-ready)}
.rt-seg-unavailable{background:var(--rt-st-unavail);color:var(--rt-ink)}
.rt-seg-faulted{background:var(--rt-st-faulted)}
.rt-seg-silent{background:var(--rt-st-silent);color:var(--rt-body)}
.rt-seg-other{background:var(--rt-st-other);color:var(--rt-body)}
.rt-statelegend{display:flex;flex-wrap:wrap;gap:13px;font-size:12.5px;color:var(--rt-body)}
.rt-sq{width:17px;height:17px;border-radius:4px;display:inline-flex;align-items:center;
  justify-content:center;font-size:10px;font-weight:700;color:#fff;margin-right:5px;
  vertical-align:-4px}

.rt-causes{display:grid;grid-template-columns:repeat(auto-fit,minmax(184px,1fr));gap:10px}
.rt-cause{border:1px solid var(--rt-line);border-radius:8px;padding:11px 13px;background:#fff}
.rt-cause .n{font-size:24px;font-weight:600;color:var(--rt-ink);line-height:1.1;
  font-variant-numeric:tabular-nums}
.rt-cause .l{font-size:12.5px;color:var(--rt-ink);font-weight:600;margin-top:1px}
.rt-cause .a{font-size:11.5px;color:var(--rt-muted);margin-top:3px}
.rt-cause .bar{height:3px;border-radius:2px;margin-top:8px;background:var(--rt-rank)}
.rt-cause-faulted .bar{background:var(--rt-st-faulted)}
.rt-cause-unavailable .bar{background:var(--rt-st-unavail)}
.rt-cause-silent .bar{background:var(--rt-muted)}

.rt-act{font-weight:600;font-size:12.5px;padding-left:9px;border-left:3px solid var(--rt-line);
  display:inline-block}
.rt-act-faulted{border-left-color:var(--rt-st-faulted);color:var(--rt-st-faulted)}
.rt-act-unavailable{border-left-color:var(--rt-st-unavail);color:#A9700B}
.rt-act-silent{border-left-color:var(--rt-muted)}
.rt-act-crashing{border-left-color:var(--rt-teal);color:var(--rt-teal-700)}
.rt-act-stuck{border-left-color:var(--rt-teal);color:var(--rt-teal-700)}

.rt-bars{display:flex;flex-direction:column;gap:8px}
.rt-brow{display:grid;grid-template-columns:minmax(140px,1fr) 2fr 54px;gap:10px;
  align-items:center;font-size:13px}
.rt-brow .lbl{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--rt-ink)}
.rt-btrack{background:#EEF2F5;border-radius:3px;height:15px;overflow:hidden}
.rt-bfill{height:100%;border-radius:0 3px 3px 0;background:var(--rt-rank)}
.rt-bfill.soft{background:var(--rt-rank-soft)}
.rt-brow .v{text-align:right;font-variant-numeric:tabular-nums;font-size:12.5px;color:var(--rt-ink)}

/* The bar needs a parent with a DEFINITE height or its percentage resolves
   against nothing — inside a flex column every bar collapses to min-height and
   the chart silently becomes a row of flat lines with correct numbers above
   them. `.rt-track` supplies that fixed height. */
/* Daily alert trend. One series, so no legend -- the card head names it.
   The SVG stretches to the card width, so strokes are pinned with
   non-scaling-stroke and the markers are HTML dots on top: an ellipse is
   what you get if you let a circle ride a distorted viewBox. */
.rt-trend{position:relative;height:150px;margin-top:2px}
.rt-trend svg{width:100%;height:100%;display:block;overflow:visible}
.rt-trend .ln{fill:none;stroke:var(--rt-rank);stroke-width:2;
  stroke-linejoin:round;stroke-linecap:round;vector-effect:non-scaling-stroke}
.rt-trend .fill{fill:var(--rt-rank);opacity:.09;stroke:none}
.rt-trend .base{stroke:var(--rt-line);stroke-width:1;vector-effect:non-scaling-stroke}
.rt-trend .shiftline{stroke:var(--rt-muted);stroke-width:1;stroke-dasharray:3 3;
  vector-effect:non-scaling-stroke;opacity:.75}
.rt-trend .dot{position:absolute;width:9px;height:9px;margin:-5px 0 0 -5px;
  border-radius:50%;background:var(--rt-surface);border:2px solid var(--rt-rank);
  opacity:0;transition:opacity .12s}
.rt-trend .dot.last{opacity:1}
.rt-trend .hit{position:absolute;top:0;bottom:0;width:26px;margin-left:-13px;cursor:default}
.rt-trend .hit:hover + .dot,.rt-trend .dot:hover{opacity:1}
.rt-trend-x{display:flex;justify-content:space-between;margin-top:6px;
  font-size:11px;color:var(--rt-muted)}
.rt-trend .peakline{stroke:var(--rt-line);stroke-width:1;vector-effect:non-scaling-stroke}
.rt-trend-peak{position:absolute;left:0;font-size:11px;color:var(--rt-muted);
  transform:translateY(-125%);background:var(--rt-surface);padding-right:4px}
.rt-trend-shift{position:absolute;top:2px;transform:translateX(-50%);font-size:11px;
  color:var(--rt-muted);white-space:nowrap;background:var(--rt-surface);padding:0 4px}
.rt-dist{display:flex;align-items:flex-end;gap:8px}
.rt-dist .col{flex:1;display:flex;flex-direction:column;align-items:center;gap:5px}
.rt-dist .rt-track{width:100%;height:96px;display:flex;align-items:flex-end}
.rt-dist .b{width:100%;background:var(--rt-rank);border-radius:3px 3px 0 0;min-height:4px}
.rt-dist .b.bad{background:var(--rt-st-faulted)}
.rt-dist .t{font-size:10.5px;color:var(--rt-muted)}
.rt-dist .v{font-size:12px;font-weight:600;color:var(--rt-ink)}

.rt-fleet-filters{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:14px}
.rt-fleet-filters .form-control,.rt-fleet-filters .form-select{width:auto;min-width:170px}
.rt-fleet-filters #rt-fleet-search{min-width:250px;flex:1;max-width:420px}
.rt-fault-window.active{background:var(--rt-teal);border-color:var(--rt-teal);color:#fff}
.rt-sevpill{display:inline-block;border-radius:999px;padding:1px 9px;font-size:11.5px;
  font-weight:600;white-space:nowrap}
.rt-sev-critical{background:#FBEDEB;color:var(--rt-st-faulted)}
.rt-sev-high{background:#FDF3E0;color:#A9700B}
.rt-sev-medium{background:#EFF3F6;color:var(--rt-body)}
.rt-sev-low{background:#EFF3F6;color:var(--rt-muted)}
.rt-sq.rt-sev-critical{background:var(--rt-st-faulted);color:#fff}
.rt-sq.rt-sev-high{background:#C4622C;color:#fff}
.rt-sq.rt-sev-medium{background:var(--rt-st-unavail);color:var(--rt-ink)}
.rt-sq.rt-sev-low{background:var(--rt-st-ready);color:#fff}

.rt-causebar{display:grid;text-decoration:none;color:inherit;padding:2px 0;border-radius:4px}
.rt-causebar:hover{background:#F7FAFB;color:inherit}
.rt-causebar:hover .lbl{color:var(--rt-teal-700)}
.rt-bfill.rt-cause-faulted{background:var(--rt-st-faulted)}
.rt-bfill.rt-cause-unavailable{background:var(--rt-st-unavail)}
.rt-bfill.rt-cause-silent{background:var(--rt-muted)}
.rt-bfill.rt-cause-crashing{background:var(--rt-rank)}
.rt-bfill.rt-cause-stuck{background:var(--rt-rank-soft)}

/* ── support dashboard ──────────────────────────────────────────────
   Blame palette. Validated with the dataviz validator against the light
   surface (lightness band, chroma floor, CVD separation, normal-vision
   floor, contrast) — all pass. Do not hand-tweak these without re-running
   it; "looks fine to me" is exactly what the check exists to replace.
   Grey is NOT one of the four: it means "the charger did not say", which is
   missing data rather than a fifth category. */
:root{
  --rt-blame-normal:  #1A7FA8;
  --rt-blame-car:     #C9782B;
  --rt-blame-payment: #8A5FB0;
  --rt-blame-charger: #B8453C;
  --rt-blame-unknown: #98A6B2;
}
.blame-normal{background:var(--rt-blame-normal)}
.blame-car{background:var(--rt-blame-car)}
.blame-payment{background:var(--rt-blame-payment)}
.blame-charger{background:var(--rt-blame-charger)}
.blame-unknown{background:var(--rt-blame-unknown)}

.rt-stackbar .seg{min-width:2px}
.rt-legend{display:flex;flex-wrap:wrap;gap:14px;font-size:12.5px;color:var(--rt-body)}
.rt-legend i{display:inline-block;width:11px;height:11px;border-radius:3px;
  margin-right:6px;vertical-align:-1px}
.rt-legend i.ok{background:var(--rt-blame-normal)}
.rt-legend i.bad{background:var(--rt-blame-charger)}

/* Hour and day columns. Same lesson as .rt-dist: the bar's percentage height
   needs a parent with a definite height, which is what .rt-track gives it. */
.rt-hours{display:flex;align-items:flex-end;gap:3px}
.rt-hours.tall .rt-track{height:120px}
.rt-hours .col{flex:1;display:flex;flex-direction:column;align-items:center;gap:4px;min-width:0}
.rt-hours .rt-track{width:100%;height:92px;display:flex;align-items:flex-end}
.rt-hours .b{width:100%;background:var(--rt-rank);border-radius:2px 2px 0 0;min-height:2px}
/* Paid/stalled must be the exact colours their legend swatches use — a
   legend that names a colour the chart does not draw is worse than none. */
.rt-hours .b.paid{background:var(--rt-blame-normal)}
.rt-hours .b.bad{background:var(--rt-blame-charger)}
.rt-hours .stack{width:100%;display:flex;flex-direction:column;justify-content:flex-end;height:100%}
.rt-hours .stack .b{border-radius:0}
.rt-hours .stack .b:first-child{border-radius:2px 2px 0 0}
.rt-hours .t{font-size:10.5px;color:var(--rt-muted);white-space:nowrap}

.rt-sym{display:inline-block;border-radius:999px;padding:1px 9px;font-size:11.5px;
  font-weight:600;white-space:nowrap}
.sym-silent{background:#EFF3F6;color:var(--rt-body)}
.sym-billing{background:#F4EEF9;color:#6B4590}
.sym-charging{background:#FBEDEB;color:var(--rt-st-faulted)}

.rt-conn{display:flex;gap:10px;flex-wrap:wrap}
.rt-conn-box{flex:1;min-width:150px;border:1px solid var(--rt-line);border-radius:var(--rt-radius-sm);
  padding:9px 12px;background:var(--rt-bg)}
.rt-conn-box .st{font-size:15px;font-weight:600;color:var(--rt-ink);margin:2px 0}
.rt-conn-box .st.ok{color:var(--rt-ok)}
.rt-conn-box .st.bad{color:var(--rt-err)}

.rt-say{border-left:3px solid var(--rt-teal-700);background:var(--rt-teal-050);
  border-radius:0 var(--rt-radius-sm) var(--rt-radius-sm) 0;
  padding:9px 13px;margin-bottom:9px;color:var(--rt-body);font-size:13.5px}
.rt-say .lab{display:block;font-size:11px;font-weight:700;letter-spacing:.03em;
  text-transform:uppercase;color:var(--rt-teal-700);margin-bottom:3px}
.rt-note-box{border:1px solid var(--rt-line);background:var(--rt-bg);border-radius:var(--rt-radius-sm);
  padding:9px 13px;font-size:13px;color:var(--rt-body)}

.rt-scroll{max-height:460px;overflow-y:auto}

/* A KPI tile that is a link must not look like body text turned blue: it keeps
   the tile's own colours and only gains a hover lift. */
a.rt-kpi{text-decoration:none;color:inherit;display:block;transition:border-color .12s,box-shadow .12s}
a.rt-kpi:hover{border-color:#B9C7D2;box-shadow:0 1px 4px rgba(22,35,46,.07)}
a.rt-kpi:hover .n{text-decoration:underline;text-underline-offset:3px}
a.rt-kpi.alert:hover{border-color:#C68F86}

/* Provenance tag on advice blocks. A sentence from the vendor knowledge base
   and a sentence written for this page must never look identical -- one is
   quotable to a customer, the other is a hint. */
.rt-say .rt-src{float:right;font-weight:600;font-size:10px;letter-spacing:0;
  text-transform:none;color:var(--rt-muted)}
.rt-say.ours{border-left-color:var(--rt-muted);background:var(--rt-bg)}
.rt-say.ours .lab{color:var(--rt-body)}

/* Drill-down triggers. These are <button> for keyboard and screen-reader
   reasons, but they must not look like buttons -- they are the chart. */
button.rt-kpi{width:100%;text-align:left;font:inherit;cursor:pointer}
.rt-drill{cursor:pointer}
button.rt-seg{border:0;padding:0;font:inherit;cursor:pointer}
button.rt-track{border:0;padding:0;background:none;cursor:pointer}
.rt-hours button.rt-track,.rt-dist button.rt-track{display:flex;align-items:flex-end}
button.hit{border:0;background:none;padding:0}
.rt-legend-btn{border:0;background:none;padding:0;font:inherit;color:var(--rt-body);
  cursor:pointer;display:inline-flex;align-items:center}
.rt-legend-btn:hover{color:var(--rt-ink);text-decoration:underline;text-underline-offset:3px}
.rt-seg:hover{filter:brightness(1.07)}
button.rt-track:hover .b{filter:brightness(1.07)}

/* The account bar is a button now, so it needs the row layout a div had. */
button.rt-brow{width:100%;border:0;background:none;padding:2px 0;font:inherit;
  text-align:left;cursor:pointer}
button.rt-brow:hover .lbl{color:var(--rt-ink)}
button.rt-brow:hover .rt-bfill{filter:brightness(1.07)}
