/* ==========================================================================
   energylog — the drawing library's stylesheet

   Extracted from the previous app's stylesheet by .tools/extract_viz_css.php,
   which keeps only the rules viz.js and symbols.js actually draw with and
   drops everything belonging to the old shell.

   Loading the whole of the old stylesheet was the shortcut that broke the
   new layout: both files defined .card, .topbar, .tabbar and .shell, and the
   navigation ended up spread across the top of the page. This file shares no
   class names with the new system, so it cannot collide with it.

   Colours come from the new tokens through the aliases in ui.css, so the
   diagrams change appearance with the look like everything else.

   Do not edit by hand — regenerate it.
   ========================================================================== */

:is(.field input, .btn, .icon-btn, .site-row, .tabbar a, .segmented button, .panel-row):focus-visible {
  outline: 2px solid var(--brand); outline-offset: 2px;
}

/* ------------------------------------------------------- status chips/pills */

/*
 * A band is always icon + number + word. Two of the four status colours are
 * below 3:1 on the light surface by design, so the glyph and the word are what
 * actually carry the meaning; the colour only reinforces it.
 */
.band { display: inline-flex; align-items: center; gap: 5px; font-weight: 650; }

.band .ic { font-size: .85em; }

.band-ok       { color: var(--ok); }

.band-warm     { color: var(--warm); }

.band-high     { color: var(--high); }

.band-critical { color: var(--critical); }

.status { font-size: .72rem; font-weight: 600; }

.status::before {
  content: ''; display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  margin-right: 4px; vertical-align: middle; background: currentColor;
}

.status-online  { color: var(--ok); }

.status-stale   { color: var(--warm); }

.status-offline { color: var(--critical); }

.status-unknown { color: var(--ink-muted); }

.panel-list {
  display: flex; flex-direction: column; gap: 1px;
  background: var(--border); border: 1px solid var(--border);
  border-radius: var(--radius); overflow: hidden;
}

.panel-row {
  display: flex; align-items: center; gap: 12px; padding: 11px 14px;
  background: var(--surface); width: 100%; border: 0; text-align: left;
  font: inherit; color: inherit; cursor: pointer;
  transition: background .12s;
}

.panel-name { flex: 1; min-width: 0; font-size: .9rem; font-weight: 560; }

.panel-meter {
  display: block; font-size: .71rem; font-weight: 400;
  color: var(--ink-muted); margin-top: 2px;
}

.panel-temp { text-align: right; flex: none; }

.panel-temp strong { display: block; font-size: 1.08rem; font-weight: 670; }

.panel-temp .u { font-size: .68rem; font-weight: 600; color: var(--ink-muted); }

.panel-row.band-ok       { box-shadow: inset 3px 0 0 var(--ok); }

.panel-row.band-warm     { box-shadow: inset 3px 0 0 var(--warm); }

.panel-row.band-high     { box-shadow: inset 3px 0 0 var(--high); }

.panel-row.band-critical { box-shadow: inset 3px 0 0 var(--critical); }

.sld-stage { position: relative; padding: 0 0 26px; }

.sld-stage:last-child { padding-bottom: 4px; }

.sld-stage::after {
  content: ''; position: absolute; left: 50%; bottom: 6px;
  width: 2px; height: 20px; background: var(--border); transform: translateX(-50%);
}

.sld-stage:last-child::after { display: none; }

.sld-title {
  display: flex; align-items: center; gap: 8px; margin-bottom: 8px;
  font-size: .72rem; font-weight: 680; text-transform: uppercase; letter-spacing: .07em;
  color: var(--ink-muted);
}

.sld-title::after { content: ''; flex: 1; height: 1px; background: var(--border); }

.sld-row { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; }

.sld-node {
  flex: 1 1 150px; max-width: 240px; min-width: 140px;
  padding: 10px 12px; text-align: left; cursor: pointer;
  background: var(--surface); border: 1px solid var(--border);
  border-top: 3px solid var(--border);
  border-radius: var(--radius-sm); font: inherit; color: inherit;
}

.sld-node .n {
  display: block; font-size: .8rem; font-weight: 620; line-height: 1.25;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.sld-node .v { display: flex; align-items: baseline; gap: 3px; margin-top: 5px; }

.sld-node .v strong { font-size: 1.15rem; font-weight: 690; letter-spacing: -.02em; }

.sld-node .v .u { font-size: .66rem; color: var(--ink-muted); font-weight: 600; }

.sld-node .w { margin-left: auto; font-size: .68rem; font-weight: 650; }

.sld-node.band-ok       { border-top-color: var(--ok); }

.sld-node.band-warm     { border-top-color: var(--warm); }

.sld-node.band-high     { border-top-color: var(--high); }

.sld-node.band-critical { border-top-color: var(--critical); }

.sld-node.band-ok .v strong,       .sld-node.band-ok .w       { color: var(--ok); }

.sld-node.band-warm .v strong,     .sld-node.band-warm .w     { color: var(--warm); }

.sld-node.band-high .v strong,     .sld-node.band-high .w     { color: var(--high); }

.sld-node.band-critical .v strong, .sld-node.band-critical .w { color: var(--critical); }

/* ------------------------------------------------- heatmap & single line */

/*
 * Wide content scrolls inside its own box. A single-line diagram for 27 outgoing
 * ways is genuinely wide — that is what an SLD looks like on paper too — and the
 * page body must never scroll sideways because of it.
 */
.hm-scroll, .sld-scroll {
  overflow-x: auto; overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  padding-bottom: 4px;
}

.hm-scroll svg, .sld-scroll svg { display: block; }

/*
 * The heatmap fills the card. Its own inline min-width holds the drawing at a
 * legible size, so on a narrow screen this resolves to a scroll and on a wide
 * one the grid opens out instead of ending in dead space.
 */
.hm-scroll svg.hm { width: 100%; height: auto; }

/* ------------------------------------------------- temperature rise (ΔT) */

.dt-head {
  display: flex; align-items: baseline; justify-content: space-between;
  flex-wrap: wrap; gap: 8px; margin-bottom: 12px;
}

.dt-verdict { font-size: 1rem; font-weight: 640; }

.dt-verdict b { font-weight: 760; }

.dt-verdict.ok { color: var(--ok); font-weight: 600; }

.dt-ref { font-size: .74rem; color: var(--ink-muted); }

.dt-ref b { color: var(--ink-2); font-weight: 620; }

.dt-note {
  margin: 12px 2px 0; font-size: .72rem; line-height: 1.5; color: var(--ink-muted);
}

.hm-legend {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-top: 10px; font-size: .72rem; color: var(--ink-muted);
}

.hm-scale {
  flex: 0 0 130px; height: 9px; border-radius: 999px;
  border: 1px solid var(--border);
}

.hm-note { margin-left: auto; }

.hc { cursor: crosshair; }

.hc:hover { stroke: var(--ink); stroke-width: 1.5; }

.sld-dev, .cub { cursor: pointer; }

.sld-dev:hover rect, .cub:hover > rect:first-of-type { filter: brightness(1.05); }

.spark { vertical-align: middle; flex: none; }

/*
 * A wide diagram is scrollable, and on a touch screen that is not obvious.
 * A soft fade at the right edge says there is more without adding furniture,
 * and it is drawn from the card's own surface so it disappears in both themes.
 */
.sld-scroll, .hm-scroll { position: relative; }

/*
 * This block never rendered until 2026-08-14.
 *
 * It read `.chart-card > .sld-scroll::after,` — a selector list left open on a
 * trailing comma — and then, after a comment, an @media rule. An at-rule cannot
 * complete a selector list, so the parser threw the whole thing away under error
 * recovery, taking the @media block with it. The result was NO fade on either
 * the diagram or the heatmap, on any screen, ever. Nothing looked broken; the
 * affordance simply was not there, which is the hard kind of bug to notice.
 *
 * Split into two rules, which is what the two comments always described.
 *
 * There was a SECOND reason it could never have worked, found once the parse
 * error was fixed and the fade still did not appear: both selectors were
 * `.chart-card > …`, and this app has no `.chart-card` at all. The scroller
 * sits in `.viz` inside `.card`. That class came from the previous design, and
 * viz.css was extracted from its stylesheet — so the rule was written against
 * markup that no longer exists. Dropping the parent qualifier entirely, since
 * `.sld-scroll` and `.hm-scroll` are only ever used for this.
 *
 * The diagram fades at every width on purpose: a single-line diagram is sized
 * by how many meters a site has, not by the window. D S Group Greater Noida
 * draws 2948px of diagram into a 954px card on a 1280px desktop — barely a
 * third of it visible, with nothing to say so.
 */
.sld-scroll::after {
  content: ''; position: sticky; float: right; top: 0; right: 0;
  width: 34px; height: 100%; pointer-events: none;
  background: linear-gradient(90deg, transparent, var(--surface));
}

/*
 * The heatmap only overflows on a narrow screen, now that it stretches to fill
 * its card — on a desktop this was fading the last column of a chart that fitted.
 */
@media (max-width: 900px) {
  .hm-scroll::after {
    content: ''; position: sticky; float: right; top: 0; right: 0;
    width: 34px; height: 100%; pointer-events: none;
    background: linear-gradient(90deg, transparent, var(--surface));
  }
}

.chart-head h3 { margin: 0; font-size: .92rem; font-weight: 650; }

/* The unit belongs in the heading, once, rather than repeated on every axis
   label — and having it there is what stops a reader assuming °C. */
.chart-unit {
  margin-left: 6px; padding: 1px 7px; border-radius: 999px;
  background: var(--surface-sunk); border: 1px solid var(--border);
  font-size: .7rem; font-weight: 600; color: var(--ink-muted);
}

.chart-head .meta { font-size: .74rem; color: var(--ink-muted); }

.chart-wrap svg { display: block; width: 100%; height: auto; touch-action: pan-y; }

/*
 * The hover readout.
 *
 * It clears the cell it describes rather than covering it: a percentage offset
 * scaled with the tooltip's own height, so a two-line label drifted several
 * rows up the grid and hid the readings either side of the one being read. The
 * offset is now a fixed 10px gap above the cell, and `.flip` swaps it below for
 * cells near the top edge, where there is no room above.
 */
.tip {
  position: absolute; pointer-events: none; z-index: 5;
  padding: 7px 10px; border-radius: 8px; font-size: .76rem; line-height: 1.4;
  white-space: nowrap;
  background: var(--ink); color: var(--page);
  border: 1px solid var(--surface); box-shadow: var(--shadow-lift);
  transform: translate(-50%, calc(-100% - 10px));
  opacity: 0; transition: opacity .1s;
}

.tip.flip { transform: translate(-50%, 10px); }

.tip.on { opacity: 1; }

.tip b { font-weight: 680; }

.empty .big { display: block; font-size: 1.8rem; margin-bottom: 6px; }

.table-wrap, .panel-list { border: 0; }

/* ==========================================================================
   Equipment symbols

   Motion is information here, not decoration: a part only moves while its
   machine is drawing current, so a glance says what is running. Every machine
   also prints RUN / IDLE / NO DATA as a word, so nothing depends on seeing it.
   ========================================================================== */

.sym { display: block; color: var(--ink-2); flex: none; }

.sym .sym-spin, .sym .sym-belt, .sym .sym-pulse, .sym .sym-flow,
.sym .sym-glow, .sym .sym-heat, .sym .sym-shake, .sym .sym-lift,
.sym .sym-level, .sym .sym-trace, .sym .sym-press { animation-play-state: paused; }

.sym.is-running .sym-spin  { animation: sym-spin 2.4s linear infinite; }

.sym.is-running .sym-belt  { animation: sym-belt 1.1s linear infinite; }

.sym.is-running .sym-pulse { animation: sym-pulse 1.6s ease-in-out infinite; }

.sym.is-running .sym-flow  { animation: sym-flow 1.8s ease-in-out infinite; }

.sym.is-running .sym-glow  { animation: sym-glow 2.6s ease-in-out infinite; }

.sym.is-running .sym-heat  { animation: sym-heat 2s ease-in-out infinite; }

.sym.is-running .sym-shake { animation: sym-shake .35s ease-in-out infinite; }

.sym.is-running .sym-lift  { animation: sym-lift 2.4s ease-in-out infinite; }

.sym.is-running .sym-level { animation: sym-level 3.4s ease-in-out infinite; }

.sym.is-running .sym-trace { animation: sym-trace 2.2s linear infinite; }

.sym.is-running .sym-press { animation: sym-press 2.8s ease-in-out infinite; }

.sym.is-running :is(.sym-spin,.sym-belt,.sym-pulse,.sym-flow,.sym-glow,.sym-heat,
  .sym-shake,.sym-lift,.sym-level,.sym-trace,.sym-press) { animation-play-state: running; }

/* A machine that is off is drawn quieter, so a still fan reads as stopped
   rather than as a fan that failed to animate. */
.sym:not(.is-running) { opacity: .55; }

.sym.is-running .sym-trace path { stroke-dasharray: 60; }

/* ==========================================================================
   Device grids

   Laid out by CSS rather than by a fixed count baked into an SVG. The old
   version drew four columns whatever the screen, which left a third of a
   desktop empty and cramped a phone.
   ========================================================================== */

.dev-grid {
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
}

.dev-grid.wide { grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); }

.dev {
  display: flex; flex-direction: column; gap: 8px; padding: 12px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); text-align: left; width: 100%;
  font: inherit; color: inherit; cursor: pointer;
  transition: border-color .12s, transform .12s;
}

.dev:hover { border-color: var(--brand); }

.dev:active { transform: scale(.99); }

/* A device with no reading has no trend to open, so it does not offer one. */
.dev[disabled] { cursor: default; opacity: .7; }

.dev[disabled]:hover { border-color: var(--border); }

.dev[disabled]:active { transform: none; }

.dev.alarm { border-width: 2px; padding: 11px; }

.dev.alarm.band-warm     { border-color: var(--warm); }

.dev.alarm.band-high     { border-color: var(--high); }

.dev.alarm.band-critical { border-color: var(--critical); }

.dev-top { display: flex; align-items: flex-start; gap: 10px; }

.dev-name {
  flex: 1; min-width: 0; font-size: .84rem; font-weight: 650; line-height: 1.3;
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}

.dev-state {
  font-size: .62rem; font-weight: 700; letter-spacing: .06em;
  padding: 2px 6px; border-radius: 999px; flex: none;
  background: var(--surface-sunk); color: var(--ink-muted);
}

.dev-state.run { background: color-mix(in srgb, var(--ok) 16%, transparent); color: var(--ok); }

.dev-read {
  display: flex; align-items: baseline; gap: 4px;
  padding: 7px 9px; border-radius: var(--radius-sm); background: var(--meter-bg);
}

.dev-read strong {
  font-family: var(--mono); font-size: 1.32rem; font-weight: 700;
  letter-spacing: -.02em; color: var(--meter-ink);
}

.dev-read .u { font-size: .68rem; font-weight: 650; color: var(--meter-ink); opacity: .65; }

.dev.alarm .dev-read strong { color: inherit; }

.dev.alarm.band-warm .dev-read strong     { color: var(--warm); }

.dev.alarm.band-high .dev-read strong     { color: var(--high); }

.dev.alarm.band-critical .dev-read strong { color: var(--critical); }

.dev-sub { display: flex; justify-content: space-between; gap: 6px; font-size: .7rem; }

.dev-sub span { color: var(--ink-muted); }

.dev-sub b { font-weight: 650; color: var(--ink-2); }

/* Headroom bar: where the reading sits between comfortable and the alarm. */
.dev-bar { height: 5px; border-radius: 3px; background: var(--surface-sunk); overflow: hidden; }

.dev-bar i { display: block; height: 100%; background: var(--ink-2); opacity: .5; }

.dev.alarm.band-warm     .dev-bar i { background: var(--warm); opacity: 1; }

.dev.alarm.band-high     .dev-bar i { background: var(--high); opacity: 1; }

.dev.alarm.band-critical .dev-bar i { background: var(--critical); opacity: 1; }

/* Dial cards: the gauge fills the card, its name sits under it. */
.gauge-card { align-items: center; gap: 4px; padding: 10px; }

.gauge { width: 100%; height: auto; max-width: 150px; }

.gauge-name {
  font-size: .78rem; font-weight: 620; text-align: center; line-height: 1.3;
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
