/* Tariff Studio -- house style: Spectral (display) + IBM Plex Sans (body) + IBM Plex Mono (numbers) */

:root {
  --bg: #faf8f4;
  --bg-panel: #ffffff;
  --bg-inset: #f2efe8;
  --border: #ddd6c8;
  --text: #23211d;
  --text-dim: #6b665a;
  --text-faint: #9b9585;
  --accent: #7a5c2e;
  --accent-strong: #4f3a1c;
  --solar: #d99a2b;
  --wind: #3f7d8c;
  --bess: #6a4c93;
  --good: #3f7d4e;
  --bad: #a8402f;
  --shadow: 0 1px 2px rgba(35,33,29,0.06), 0 4px 16px rgba(35,33,29,0.05);
  --radius: 10px;
  --mono: 'IBM Plex Mono', ui-monospace, Menlo, monospace;
  --sans: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, sans-serif;
  --display: 'Spectral', Georgia, serif;
  color-scheme: light;
  --rw-left-w: 300px;
  /* Height of the frozen ribbon, measured and written by app.js. 0 is the
     honest starting value: before the script runs there is no offset to apply,
     and a wrong guess would push the sticky controls column off screen. */
  --ribbon-h: 0px;
}

/* Jumping to an anchor must not land underneath the ribbon. */
html { scroll-padding-top: var(--ribbon-h); }

/* Perpetual light mode -- deliberate. This tool is looked at during
 * client-facing walkthroughs at all hours; a chart that silently flips
 * dark because the presenter's OS did is worse than no dark mode at all.
 * See app.js's chart-theme registration for the matching fix on the
 * ECharts side (it must NOT ask the browser for prefers-color-scheme
 * either, or the charts alone would flip while the rest of the page
 * stays light). If a real light/dark toggle is wanted later, reintroduce
 * a `@media (prefers-color-scheme: dark)` block guarded by
 * `:root:not([data-theme="light"])`, matching the pattern this file used
 * to have. */

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 14px;
  line-height: 1.5;
}

/* ---- header / tabs ------------------------------------------------- */

/* The frozen ribbon: the mark, the title, the sign-in control and the tab
 * strip. It stays at the top of the window as the page scrolls, so which tab
 * you are on — and whether you are signed in — stays visible however far down
 * you have gone.
 *
 * `--ribbon-h` is written by app.js from the ribbon's MEASURED height rather
 * than guessed, because the ribbon wraps onto more lines on a narrow window and
 * its height also changes when the banner appears inside it. Everything that
 * has to sit clear of the ribbon is offset by the variable, so it stays right
 * at every width; a hard-coded number here would be wrong on a laptop and worse
 * on a phone.
 *
 * z-index 60 sits above the sticky controls column (5) and below the help
 * popover (1000) and the report reader (9999), so an overlay still covers the
 * ribbon rather than the other way round. */
.rw-sticky {
  position: sticky;
  top: 0;
  z-index: 60;
  /* Opaque: content scrolls UNDER this, and a transparent ribbon would let the
     page show through it. */
  background: var(--bg-panel);
  box-shadow: 0 1px 0 var(--border), 0 4px 12px rgba(35, 33, 29, 0.05);
}
.rw-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding: 18px 28px 0;
  border-bottom: 1px solid var(--border);
  background: var(--bg-panel);
}
.rw-header h1 {
  font-family: var(--display);
  font-weight: 600;
  font-size: 22px;
  margin: 0 0 14px;
  color: var(--accent-strong);
}
.rw-header .rw-sub {
  font-size: 12px;
  color: var(--text-faint);
  margin: -8px 0 14px;
}

.rw-tabs {
  display: flex;
  gap: 2px;
}
.rw-tab {
  padding: 9px 18px;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-dim);
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  cursor: pointer;
  font-family: var(--sans);
}
.rw-tab:hover { color: var(--text); }
.rw-tab.active {
  color: var(--accent-strong);
  border-bottom-color: var(--accent);
}

.rw-body { display: none; padding: 20px 28px 40px; max-width: 1500px; margin: 0 auto; }
.rw-body.active { display: block; }

/* ---- layout ---------------------------------------------------------*/

.rw-grid {
  display: grid;
  grid-template-columns: var(--rw-left-w, 300px) 1fr;
  gap: 20px;
  align-items: start;
  position: relative;
}
@media (max-width: 980px) { .rw-grid { grid-template-columns: 1fr !important; } }

/* Left column stays pinned in the viewport while you scroll down to a
 * chart further down the page, so a parameter you're adjusting and the
 * chart it drives are never more than a glance apart. Each of its panels
 * is also individually collapsible (see .rw-collapse-summary below) for
 * when the pinned column itself gets taller than the viewport. */
.rw-controls-col {
  position: sticky;
  /* Clear of the frozen ribbon. This column used to stick at 20px, which was
     right while the ribbon scrolled away; with the ribbon pinned it would slide
     underneath it and the top of the panel — the collapse handle and the first
     field — would be hidden exactly when someone scrolled down to use it. */
  top: calc(var(--ribbon-h) + 20px);
  align-self: start;
  max-height: calc(100vh - var(--ribbon-h) - 40px);
  overflow-y: auto;
  overflow-x: hidden;
  padding-right: 6px;
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}
.rw-controls-col::-webkit-scrollbar { width: 8px; }
.rw-controls-col::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
.rw-controls-col::-webkit-scrollbar-track { background: transparent; }
@media (max-width: 980px) {
  .rw-controls-col { position: static; max-height: none; overflow: visible; padding-right: 0; }
}

/* Drag handle between the two columns -- adjusts --rw-left-w (app.js). */
.rw-col-resizer {
  position: absolute;
  top: 0; bottom: 0;
  left: var(--rw-left-w, 300px);
  width: 12px;
  margin-left: -6px;
  cursor: col-resize;
  z-index: 5;
  touch-action: none;
}
.rw-col-resizer::after {
  content: '';
  position: absolute;
  left: 50%; top: 8px; bottom: 8px;
  width: 3px;
  border-radius: 2px;
  background: var(--border);
  transform: translateX(-50%);
  transition: background 0.12s ease;
}
.rw-col-resizer:hover::after, .rw-col-resizer.dragging::after { background: var(--accent); }
@media (max-width: 980px) { .rw-col-resizer { display: none; } }

.rw-panel {
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 16px 18px;
}
.rw-panel + .rw-panel { margin-top: 16px; }

.rw-panel h2 {
  font-family: var(--display);
  font-size: 15px;
  font-weight: 600;
  margin: 0 0 12px;
  color: var(--accent-strong);
}
.rw-panel h3 {
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-faint);
  margin: 14px 0 8px;
}
.rw-panel h3:first-child { margin-top: 0; }

/* ---- controls --------------------------------------------------------*/

.rw-field { margin-bottom: 12px; }
.rw-field label {
  display: flex;
  justify-content: space-between;
  font-size: 12.5px;
  color: var(--text-dim);
  margin-bottom: 4px;
}
.rw-field label span.val {
  font-family: var(--mono);
  color: var(--text);
  font-weight: 500;
}
.rw-field input[type="range"] {
  width: 100%;
  accent-color: var(--accent);
}
.rw-field input[type="number"], .rw-field select, .rw-field input[type="text"] {
  width: 100%;
  padding: 5px 8px;
  font-family: var(--mono);
  font-size: 12.5px;
  background: var(--bg-inset);
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text);
}
.rw-field input[type="text"] { font-family: var(--sans); }
.rw-field input[type="file"] {
  width: 100%;
  padding: 6px 8px;
  font-size: 11.5px;
  font-family: var(--sans);
  background: var(--bg-inset);
  border: 1px dashed var(--border);
  border-radius: 6px;
  color: var(--text-dim);
}
.rw-field input[type="file"]::file-selector-button {
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 600;
  padding: 4px 9px;
  margin-right: 8px;
  border-radius: 5px;
  border: 1px solid var(--border);
  background: var(--bg-panel);
  color: var(--accent-strong);
  cursor: pointer;
}
.rw-field-row { display: flex; gap: 8px; }
.rw-field-row > div { flex: 1; }
.rw-hint { font-size: 11px; color: var(--text-faint); margin-top: 3px; }

.rw-dataset-badge {
  display: inline-block;
  font-size: 10.5px;
  padding: 2px 7px;
  border-radius: 4px;
  font-weight: 600;
  letter-spacing: 0.02em;
}
.badge-measured { background: rgba(63,125,78,0.15); color: var(--good); }
.badge-modelled { background: rgba(217,154,43,0.18); color: var(--solar); }

button.rw-btn {
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 600;
  padding: 9px 16px;
  border-radius: 7px;
  border: 1px solid var(--accent);
  background: var(--accent);
  color: #fff;
  cursor: pointer;
  width: 100%;
}
button.rw-btn:hover { filter: brightness(1.08); }
button.rw-btn:disabled { opacity: 0.5; cursor: not-allowed; }
button.rw-btn.secondary {
  background: transparent;
  color: var(--accent-strong);
}

/* ---- status / progress ----------------------------------------------*/

.rw-status {
  font-size: 12px;
  color: var(--text-dim);
  margin-top: 10px;
  min-height: 16px;
}
.rw-progress-outer {
  height: 6px;
  background: var(--bg-inset);
  border-radius: 3px;
  overflow: hidden;
  margin-top: 8px;
}
.rw-progress-inner {
  height: 100%;
  background: var(--accent);
  width: 0%;
  transition: width 0.15s ease;
}

/* ---- stage cards -------------------------------------------------- */

.rw-stage-card {
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 16px 20px;
  margin-bottom: 18px;
}
.rw-stage-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 16px;
}
.rw-stage-head h2 {
  font-family: var(--display);
  font-size: 16px;
  margin: 0;
  color: var(--accent-strong);
}
.rw-stage-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px; height: 22px;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  margin-right: 8px;
}
.rw-stage-desc { font-size: 12px; color: var(--text-dim); margin-bottom: 12px; }
.rw-substage-head {
  font-family: var(--display);
  font-size: 12px;
  font-weight: 600;
  color: var(--text-dim);
  margin: 18px 0 0;
  padding-top: 14px;
  border-top: 1px dashed var(--border);
}

/* Resizable chart containers -- native browser drag handle, bottom-right
 * corner. app.js pairs this with a ResizeObserver so ECharts actually
 * redraws to fill the new size instead of just clipping. */
.rw-chart {
  width: 100%;
  height: 320px;
  margin-top: 4px;
  resize: vertical;
  overflow: hidden;
  min-height: 200px;
  max-height: 900px;
}
.rw-chart.tall { height: 420px; }
.rw-chart.heatmap { height: 460px; } /* stage-2 heatmap: extra room for the visualMap slider under the axis labels */

.rw-optimum-row {
  display: flex;
  gap: 22px;
  flex-wrap: wrap;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px dashed var(--border);
}
.rw-stat { min-width: 100px; }
.rw-stat .l { font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.03em; color: var(--text-faint); }
.rw-stat .v { font-family: var(--mono); font-size: 15px; font-weight: 600; color: var(--text); }
.rw-stat .v.good { color: var(--good); }

/* Worthwhile? Yes/No -- a slow glow pulse rather than a hard blink, so it
 * still draws the eye without the rapid-flash accessibility problem a
 * literal blink carries. Respects prefers-reduced-motion. */
.rw-worthwhile {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-weight: 700;
}
.rw-worthwhile.yes { color: var(--good); animation: rw-pulse-good 1.8s ease-in-out infinite; }
.rw-worthwhile.no { color: var(--bad); animation: rw-pulse-bad 1.8s ease-in-out infinite; }
@keyframes rw-pulse-good {
  0%, 100% { text-shadow: 0 0 0 rgba(63,125,78,0); }
  50% { text-shadow: 0 0 9px rgba(63,125,78,0.75); }
}
@keyframes rw-pulse-bad {
  0%, 100% { text-shadow: 0 0 0 rgba(168,64,47,0); }
  50% { text-shadow: 0 0 9px rgba(168,64,47,0.75); }
}
@media (prefers-reduced-motion: reduce) {
  .rw-worthwhile.yes, .rw-worthwhile.no { animation: none; text-decoration: underline; }
}

.rw-warn {
  background: rgba(217,154,43,0.1);
  border: 1px solid rgba(217,154,43,0.35);
  border-radius: 7px;
  padding: 8px 12px;
  font-size: 12px;
  color: var(--accent-strong);
  margin-top: 10px;
}
.rw-warn + .rw-warn { margin-top: 6px; }

.rw-placeholder {
  text-align: center;
  padding: 80px 20px;
  color: var(--text-faint);
  font-family: var(--display);
  font-size: 16px;
}

.rw-mode-toggle {
  display: flex;
  gap: 6px;
  margin-bottom: 4px;
}
.rw-mode-toggle button {
  flex: 1;
  font-size: 11.5px;
  padding: 6px 4px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--bg-inset);
  color: var(--text-dim);
  cursor: pointer;
}
.rw-mode-toggle button.active {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

table.rw-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
  margin-top: 10px;
}
table.rw-table th, table.rw-table td {
  padding: 5px 8px;
  text-align: right;
  border-bottom: 1px solid var(--border);
  font-family: var(--mono);
}
table.rw-table th { text-align: right; color: var(--text-faint); font-family: var(--sans); font-weight: 600; font-size: 11px; }
table.rw-table td:first-child, table.rw-table th:first-child { text-align: left; font-family: var(--sans); }
table.rw-table td.pct, table.rw-table th.pct { color: var(--text-faint); }
table.rw-table tr.total td { border-top: 2px solid var(--border); border-bottom: none; font-weight: 700; color: var(--text); }

/* ---- collapsible panels/sections (details/summary) --------------------
 * One shared pattern for every collapsible block in the app: the three
 * left-column panels (Dataset / Parameters / Run), the bottom
 * assumptions/warnings sections, and the cost-line tables. Apply
 * class="rw-collapse-summary" to the <summary> in each case. */

.rw-collapse-summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 0;
}
.rw-collapse-summary::-webkit-details-marker { display: none; }
.rw-collapse-summary::before {
  content: '\25B8';
  font-size: 11px;
  color: var(--text-faint);
  display: inline-block;
  transition: transform 0.15s ease;
  width: 10px;
  flex: none;
}
details[open] > .rw-collapse-summary::before { transform: rotate(90deg); }
.rw-collapse-summary h2 { display: inline; margin: 0; }
details[open] > .rw-collapse-summary { margin-bottom: 16px; }
.rw-collapse-summary:hover h2 { color: var(--accent); }
details.rw-panel { padding: 0; }
details.rw-panel > .rw-collapse-summary { padding: 16px 18px; margin-bottom: 0; }
details.rw-panel[open] > .rw-collapse-summary { border-bottom: 1px solid var(--border); margin-bottom: 0; }
details.rw-panel > .rw-panel-body { padding: 16px 18px; }

/* ---- glossary tooltips ------------------------------------------------*/

.rw-help {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px; height: 14px;
  margin-left: 5px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--bg-inset);
  color: var(--text-faint);
  font-size: 10px;
  font-weight: 700;
  font-family: var(--sans);
  line-height: 1;
  cursor: help;
  position: relative;
  vertical-align: middle;
  flex: none;
}
.rw-help:hover, .rw-help:focus-visible, .rw-help.rw-help-open {
  color: var(--accent); border-color: var(--accent); outline: none;
}
.rw-help-pop {
  display: none;
  position: absolute;
  z-index: 30;
  bottom: calc(100% + 7px);
  left: 50%;
  transform: translateX(-50%);
  width: 240px;
  max-width: 62vw;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: var(--shadow);
  padding: 9px 11px;
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--text-dim);
  font-weight: 400;
  text-align: left;
  cursor: auto;
}
/* The in-icon box is only where the text lives in the markup. What the user
   sees is .rw-help-float, one box on the page body, positioned by app.js
   against the window so it is never cut off by a panel edge. */
.rw-help .rw-help-pop { display: none !important; }
.rw-help[aria-expanded="true"] { color: var(--accent); border-color: var(--accent); }
.rw-help-float {
  position: fixed;
  z-index: 1000;
  max-width: calc(100vw - 16px);
  max-height: 60vh;
  overflow-y: auto;
  background: var(--bg-panel);
  border: 1px solid var(--accent);
  border-radius: 8px;
  box-shadow: 0 6px 24px rgba(35,33,29,0.18);
  padding: 10px 12px;
  font-family: var(--sans);
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--text);
  font-weight: 400;
  text-align: left;
  white-space: normal;
}
.rw-help-float[hidden] { display: none; }
.rw-help-float.pinned::before {
  content: 'Click elsewhere or press Esc to close';
  display: block;
  font-size: 10.5px;
  color: var(--text-faint);
  margin-bottom: 4px;
}

/* ---- banner: connection, session and daily-limit notices --------------*/
.rw-banner {
  display: flex; align-items: flex-start; gap: 12px;
  margin: 0 16px 8px; padding: 10px 14px;
  border-radius: 8px; font-size: 13px; line-height: 1.45;
  /* NOT sticky itself any more. It lives inside .rw-sticky, so it freezes with
     the ribbon — stacked below it, the way it sits at rest. Two siblings both
     sticky at top:0 would have landed on top of each other, with the notice
     hidden behind the ribbon: the one place a "your session ended" message
     must not be. */
}
.rw-banner[hidden] { display: none; }
.rw-banner-warn { background: #fdf3e3; border: 1px solid #d99a2b; color: #4f3a1c; }
.rw-banner-stop { background: #fbeae6; border: 1px solid #a8402f; color: #5c2018; }
.rw-banner-ok { background: #e8f2ea; border: 1px solid #3f7d4e; color: #23402b; }
.rw-banner button {
  margin-left: auto; background: transparent; border: 0; font-size: 18px; line-height: 1;
  cursor: pointer; color: inherit;
}

/* ---- sign-in state: steady blue when signed in, blinking amber when not */
.rw-auth-dot { width: 10px; height: 10px; border-radius: 50%; display: inline-block; flex: none; }
.rw-auth[data-state="in"] .rw-auth-dot { background: #2b6ea3; box-shadow: 0 0 0 3px rgba(43,110,163,0.18); }
.rw-auth[data-state="out"] .rw-auth-dot { background: #d99a2b; animation: rw-blink 1.1s steps(2, start) infinite; }
.rw-auth[data-state="out"] .rw-auth-btn[type="submit"] { border-color: #d99a2b; background: #fdf3e3; font-weight: 600; }
.rw-auth[data-state="offline"] .rw-auth-dot { background: #9b9585; }
.rw-auth[data-state="offline"] .rw-auth-msg { color: var(--text-dim); }
@keyframes rw-blink { to { visibility: hidden; } }
@media (prefers-reduced-motion: reduce) {
  .rw-auth[data-state="out"] .rw-auth-dot { animation: none; }
}

/* ---- upload outcome ---------------------------------------------------*/
.rw-status { white-space: pre-line; }
.rw-cost-table td.rw-cl-how { font-size: 11px; color: var(--text-dim); max-width: 420px; line-height: 1.4; }
.rw-dim { color: var(--text-faint); }
.rw-vs-table tr.rw-vs-stage2 td { color: #2b6ea3; }
.rw-vs-table tr.rw-vs-stage2 td:first-child { border-left: 3px solid #2b6ea3; }
.rw-vs-table tr.rw-vs-edited td { color: #9a5b12; }
.rw-vs-table tr.rw-vs-edited td:first-child { border-left: 3px solid #d99a2b; }
.rw-guide-link { display: inline-block; margin-left: 8px; font-size: 12px; color: #2b6ea3; text-decoration: none; border-bottom: 1px solid currentColor; }
.rw-optional { font-weight: 400; font-style: italic; font-size: 11px; color: var(--text-faint); font-family: var(--sans); }
.rw-status.rw-status-ok { color: #2b6ea3; font-weight: 600; }
.rw-status.rw-status-error { color: var(--bad); }
button.rw-btn.secondary.loaded { background: #2b6ea3; border-color: #2b6ea3 !important; color: #fff; }
.rw-upload-warn { margin-top: 6px; }
.rw-stat .l { position: relative; }

/* ---- scenario rows (compare tab) -------------------------------------*/

.rw-scenario-row {
  display: grid;
  grid-template-columns: 1.4fr 0.8fr 0.8fr 0.8fr 0.7fr auto;
  gap: 8px;
  align-items: end;
  padding: 8px 0;
  border-bottom: 1px solid var(--border);
}
.rw-scenario-row:first-of-type { padding-top: 0; }
.rw-scenario-row label {
  display: block;
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--text-faint);
  margin-bottom: 3px;
}
.rw-scenario-row input, .rw-scenario-row select {
  width: 100%;
  padding: 5px 7px;
  font-family: var(--mono);
  font-size: 12.5px;
  background: var(--bg-inset);
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text);
}
.rw-scenario-row input[type="text"] { font-family: var(--sans); }
.rw-scenario-remove {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--bad);
  border-radius: 6px;
  width: 30px;
  height: 30px;
  cursor: pointer;
  font-size: 15px;
  line-height: 1;
}
.rw-scenario-remove:hover { background: rgba(168,64,47,0.1); }
@media (max-width: 780px) { .rw-scenario-row { grid-template-columns: 1fr 1fr; } }

/* =====================================================================
   Bill calculator tab (#tab-bill) -- "Tariff Studio" treatment.
   Scoped entirely to this one tab: a cooler ink/teal instrument-panel
   palette borrowed from the Tariff_Studio.html tool, layered on top of
   the SAME rw-* structure/spacing the rest of the app uses (so this is
   a re-skin, not a rebuild -- nothing here changes markup or behaviour).
   Reached by overriding the shared CSS custom properties locally, so
   every existing rule that already reads var(--accent), var(--border)
   etc. re-themes for free; a handful of structural rules below (panel
   headers, KPI tiles, warn banner, table borders) carry the rest of the
   "Tariff Studio" character that isn't just colour. Light-mode only,
   same as the rest of the app -- see the note at the top of this file.
   ===================================================================== */

#tab-bill.ts-bill {
  --bg-panel: #ffffff;
  --bg-inset: #eef5f5;
  --border: #cfe0e2;
  --text: #12222c;
  --text-dim: #33474f;
  --text-faint: #6c818b;
  --accent: #12565c;
  --accent-strong: #0d3f44;
  --good: #1baf7a;
  --bad: #b03a2e;
  --shadow: 0 1px 2px rgba(10,30,34,.08), 0 6px 18px -10px rgba(10,30,34,.16);
  --radius: 7px;
  --ts-amber: #b6790a;
  --ts-amber-bg: #fff8ec;
  --ts-amber-line: #f0dfc0;
}

/* panel / card headers: uppercase teal label with a rule, not the serif
   display face used elsewhere -- the single biggest "instrument panel"
   cue Tariff Studio has that a colour swap alone wouldn't capture. */
#tab-bill.ts-bill .rw-panel h2,
#tab-bill.ts-bill .rw-stage-head h2,
#tab-bill.ts-bill .rw-collapse-summary h2 {
  font-family: var(--sans);
  font-size: 11.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--accent);
  margin: 0 0 10px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
}
#tab-bill.ts-bill .rw-stage-head { border-bottom: none; margin-bottom: 4px; }
#tab-bill.ts-bill details[open] > .rw-collapse-summary h2 { margin-bottom: 0; padding-bottom: 8px; }
#tab-bill.ts-bill .rw-collapse-summary { align-items: baseline; }
#tab-bill.ts-bill details.rw-panel > .rw-collapse-summary h2 { border-bottom: none; padding-bottom: 0; margin-bottom: 0; }

/* KPI row: from a loose flex line into bordered tiles, auto-fit. */
#tab-bill.ts-bill .rw-optimum-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(126px, 1fr));
  gap: 10px;
  border-top: none;
  padding-top: 0;
  margin-top: 2px;
}
#tab-bill.ts-bill .rw-stat {
  min-width: 0;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg-inset);
  padding: 8px 10px 7px;
}
#tab-bill.ts-bill .rw-stat .l {
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: .05em;
}
#tab-bill.ts-bill .rw-stat .v {
  font-size: 17px;
  margin-top: 3px;
}

/* warn banner: amber wash + left accent bar, matching Tariff Studio's
   warnbox instead of the pale all-round-border chip used elsewhere. */
#tab-bill.ts-bill .rw-warn {
  background: var(--ts-amber-bg);
  border: 1px solid var(--ts-amber-line);
  border-left: 4px solid var(--ts-amber);
  border-radius: 4px;
  color: var(--text-dim);
}

/* dense, fully-bordered table with a shaded header row. */
#tab-bill.ts-bill table.rw-table {
  border: 1px solid var(--border);
  border-collapse: collapse;
  font-size: 11.5px;
}
#tab-bill.ts-bill table.rw-table th,
#tab-bill.ts-bill table.rw-table td {
  border: 1px solid var(--border);
  padding: 4px 8px;
}
#tab-bill.ts-bill table.rw-table th {
  background: var(--bg-inset);
  text-transform: uppercase;
  letter-spacing: .04em;
  font-size: 9.5px;
}
#tab-bill.ts-bill table.rw-table tbody tr:hover { background: var(--bg-inset); }

/* buttons pick up the teal accent automatically via --accent, but the
   "secondary" button's inline border also reads var(--border), which is
   scoped here too -- no HTML change needed. */
#tab-bill.ts-bill button.rw-btn.secondary { color: var(--accent-strong); }

/* recommended-mix reference line, shown when the overlay legend entry is
   on -- a dashed neutral line distinct from every solid series color. */
#tab-bill.ts-bill .rw-ref-note { font-size: 11px; color: var(--text-faint); margin-top: 4px; }

/* ---- Site names -------------------------------------------------------
   Which physical sites this case refers to. Shown under the dataset picker
   and at the top of the bill calculator so a number is never read without
   knowing which factory and which plant produced it. */
.rw-sites-line {
  margin: 0 0 10px;
  padding: 7px 9px;
  border-left: 2px solid var(--accent, #7A5C2E);
  background: rgba(122, 92, 46, 0.05);
  font-size: 12px;
  line-height: 1.5;
  color: var(--ink, #23211D);
}
.rw-sites-line:empty { display: none; }
.rw-sites-line .rw-site-role {
  color: var(--dim, #6B665A);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-size: 10px;
  margin-right: 5px;
}

/* ---- Branding ---------------------------------------------------------
   The mark sits beside the product name in the header; the company name,
   site and contact live in the footer, where they are available on every
   screen without competing with the working area for attention.

   Only the circular mark is used in the header: the supplied logo's own
   wordmark is 13px tall at source, so at header scale it would be a smudge.
   The company name is set in text instead, which stays legible and, unlike
   an image, is selectable and searchable. */
.rw-brand { display: flex; align-items: center; gap: 13px; }
.rw-mark {
  width: 40px; height: 40px;
  flex: 0 0 auto;
  display: block;
}
/* The header is a single flex row on a desktop. Adding the mark costs about
   53px on the left, which on a phone is enough to push the tab row past the
   right edge -- measured, not assumed. Below 820px the header wraps instead,
   so the tabs drop onto their own line rather than overflowing, and the mark
   steps down a size. Verified at 420px: no horizontal scroll. */
@media (max-width: 820px) {
  .rw-header { flex-wrap: wrap; }
  .rw-header .rw-tabs { width: 100%; margin-bottom: 10px; }
  .rw-tabs { flex-wrap: wrap; }
}
@media (max-width: 640px) {
  .rw-mark { width: 32px; height: 32px; }
  .rw-brand { gap: 10px; }
  .rw-tab { padding: 8px 12px; font-size: 12px; }
}

.rw-footer {
  margin-top: 26px;
  padding: 14px 22px 20px;
  border-top: 1px solid var(--border, #DDD6C8);
  font-size: 12px;
  color: var(--dim, #6B665A);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}
.rw-footer-co { font-weight: 600; color: var(--ink, #23211D); }
.rw-footer-sep { opacity: 0.45; }
.rw-footer-dim { opacity: 0.75; }
.rw-footer a { color: var(--accent, #7A5C2E); text-decoration: none; border-bottom: 1px solid transparent; }
.rw-footer a:hover, .rw-footer a:focus { border-bottom-color: currentColor; }

/* --------------------------------------------------------------- sign in --
   Hosted build only: app.js adds .rw-auth to the header when there are
   accounts. The offline build never creates it, so none of this applies. */
.rw-auth {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
}
.rw-auth-form { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }

/* Step 4's two extra ways in: the set-password link and the trial request.
   Both carry more fields than the sign-in strip, so they stack; the strip's
   own inputs, buttons and messages are reused rather than restyled, and the
   honeypot is off-screen rather than `display:none` because some bots skip
   fields a browser would not lay out. */
.rw-auth-wide { flex-direction: column; align-items: stretch; gap: 8px; }
.rw-auth-wide input { min-width: 220px; }
.rw-auth-wide .rw-auth-msg { max-width: 320px; }
.rw-auth-consent { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--rw-dim, #6b665a); }
.rw-auth-consent input { min-width: 0; }
.rw-linkbtn { background: none; border: 0; padding: 0; cursor: pointer; font: inherit; }
.rw-auth input {
  font: inherit;
  padding: 5px 8px;
  border: 1px solid var(--rw-border, #ccc);
  border-radius: 4px;
  min-width: 150px;
  background: #fff;
}
.rw-auth-btn {
  font: inherit;
  padding: 5px 12px;
  border: 1px solid var(--rw-border, #ccc);
  border-radius: 4px;
  background: #fff;
  cursor: pointer;
}
.rw-auth-btn:hover { background: #f3f3f3; }
.rw-auth-btn[disabled] { opacity: 0.6; cursor: default; }
.rw-auth-who { display: inline-flex; align-items: center; gap: 6px; }
.rw-auth-tier {
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-size: 10px;
  padding: 2px 6px;
  border-radius: 3px;
  background: #eef2f5;
  color: #445;
}
.rw-auth-msg { color: #a33; max-width: 320px; }

@media (max-width: 820px) {
  .rw-auth { width: 100%; margin-left: 0; margin-top: 8px; }
  .rw-auth input { min-width: 0; flex: 1 1 140px; }
}

/* --------------------------------------------------------------- reports --
   Hosted build only: reports.js adds the tab and this panel when there is an
   account. The offline build never creates them. */
.ts-form { display: grid; gap: 10px; margin: 0 0 12px; max-width: 560px; }
.ts-form label { display: grid; gap: 4px; font-size: 12px; color: var(--rw-dim, #6b665a); }
.ts-form input {
  font: inherit;
  padding: 6px 9px;
  border: 1px solid var(--rw-border, #ccc);
  border-radius: 4px;
  background: #fff;
  color: inherit;
}
.ts-opt { font-style: italic; opacity: 0.7; }
.ts-check { display: inline-flex; align-items: center; gap: 7px; margin: 0 0 12px; font-size: 13px; }
.ts-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 8px; }
.ts-msg { font-size: 12.5px; color: var(--rw-dim, #6b665a); margin-left: 8px; }
.ts-reports table { width: 100%; }
/* The action column cannot wrap, so on a narrow window the table scrolls
   sideways rather than breaking the buttons onto two lines. */
.ts-reports { overflow-x: auto; }
.ts-rev { font-size: 11px; opacity: 0.7; }
/* The project a group of reports belongs to, and how full it is against the
   per-project limit. A separator row rather than a heading so that the
   reference/type/date columns stay aligned across every group. */
.ts-reports tr.ts-case-row td {
  background: var(--bg-inset, #f6f4ef);
  border-top: 2px solid var(--border, #e2ded4);
  font-size: 12.5px;
  padding-top: 7px;
  padding-bottom: 7px;
}
/* The button style is scoped to <button>; a download is a link, and should
   look the same without pretending to be one. */
a.ts-dl {
  font-family: var(--sans);
  font-size: 12.5px;
  font-weight: 600;
  padding: 5px 12px;
  border-radius: 6px;
  border: 1px solid var(--accent);
  background: var(--accent);
  color: #fff;
  text-decoration: none;
  display: inline-block;
  white-space: nowrap;
}
a.ts-dl:hover { filter: brightness(1.08); }

/* The reports table's action cell holds two controls side by side: "Read on
   screen" and "Download". `button.rw-btn` is full width on purpose -- it is the
   primary action in the sweep panels, where a button spanning its column is
   what you want -- and that made Read fill the whole cell and shove Download
   onto the next line. The width is reset HERE rather than in the shared rule,
   which every panel depends on. */
.ts-reports td.ts-report-actions { white-space: nowrap; }
.ts-reports td.ts-report-actions button.rw-btn { width: auto; }
.ts-reports td.ts-report-actions .ts-dl { margin-left: 8px; }
/* The panel's own buttons sit inline, not full width like the sweep controls. */
.ts-actions button.rw-btn, #rpSaveProfile { width: auto; }

/* -------------------------------------------------------- projects tab --
   Step 3. The tab is greyed until a project is open, because every other tab
   works on a project. The disabled attribute does the work; this only makes it
   look unavailable rather than merely inert -- a tab that looks live and does
   nothing is worse than one that plainly says it cannot be used yet. Colours
   come from the light palette documented at the top of this file. */
.rw-tab:disabled {
  color: var(--text-faint);
  opacity: 0.5;
  cursor: not-allowed;
  border-bottom-color: transparent;
}
.rw-tab:disabled:hover { color: var(--text-faint); }

.pj-credits {
  font-family: var(--mono);
  font-size: 15px;
  font-weight: 600;
  color: var(--accent-strong);
  margin-bottom: 10px;
}
.pj-note {
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-dim);
  background: var(--bg-inset);
  border-left: 3px solid var(--border);
  border-radius: 4px;
  padding: 8px 11px;
  margin: 10px 0;
}
.pj-note a { color: var(--accent-strong); }
.pj-row-actions { display: flex; gap: 6px; justify-content: flex-end; flex-wrap: wrap; }

/* Findings. Errors and warnings are the same list shape with different edges,
   so a scan down the page tells the two apart before a word is read. */
.pj-findings { margin: 12px 0; }
.pj-findings-head {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-faint);
  margin: 14px 0 6px;
}
.pj-errors-head { color: var(--bad); }
.pj-warn-head { color: var(--accent-strong); }
.pj-findings-list { list-style: none; margin: 0; padding: 0; }
.pj-finding {
  font-size: 12.5px;
  line-height: 1.5;
  padding: 6px 10px;
  border-radius: 5px;
  border: 1px solid var(--border);
  margin-bottom: 5px;
}
.pj-finding.pj-error { border-color: var(--bad); background: rgba(168,64,47,0.07); color: var(--bad); }
.pj-finding.pj-warning { border-color: rgba(217,154,43,0.5); background: rgba(217,154,43,0.08); color: var(--accent-strong); }
.pj-finding.pj-none { border-style: dashed; color: var(--text-faint); }
.pj-finding-kind {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-faint);
  margin-right: 5px;
}
.pj-example-list { margin: 4px 0 0; padding-left: 18px; }
.pj-example-list code { font-family: var(--mono); font-size: 11px; }

/* One card per file: the figures a client reads before spending a credit. */
.pj-stat-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 12px;
  margin: 14px 0;
}
.pj-stat-card {
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px 14px;
}
.pj-stat-card-head {
  font-family: var(--display);
  font-size: 14px;
  font-weight: 600;
  color: var(--accent-strong);
  margin-bottom: 8px;
}
.pj-stat-list { margin: 0; }
.pj-stat-row { display: flex; justify-content: space-between; gap: 10px; padding: 2px 0; }
.pj-stat-row dt { font-size: 11.5px; color: var(--text-dim); }
.pj-stat-row dd { margin: 0; font-family: var(--mono); font-size: 12px; text-align: right; }
.pj-stat-note { font-size: 11px; color: var(--text-faint); margin-top: 6px; }

.pj-chart-head {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-faint);
  margin: 18px 0 4px;
}
.pj-chart-head select {
  font-size: 11.5px;
  padding: 3px 6px;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--bg-panel);
  color: var(--text);
}
.pj-charts { margin-top: 8px; }

/* The heat map is 365 x 96 pixels of real data, so it is scaled up rather than
   resampled: a blurred pixel would hide exactly the stripe the picture exists
   to show. */
.pj-heat-row { display: grid; gap: 12px; margin: 6px 0 4px; }
.pj-heat-block { background: var(--bg-panel); border: 1px solid var(--border); border-radius: 6px; padding: 8px 10px; }
.pj-heat-title { font-size: 11px; color: var(--text-dim); margin-bottom: 5px; }
.pj-heat {
  display: block;
  width: 100%;
  height: 96px;
  image-rendering: pixelated;
  image-rendering: crisp-edges;
  border: 1px solid var(--border);
  background: var(--bg-inset);
}

/* The four-stage loader. A stage in progress is outlined in the accent; a
   finished one steps back; one not yet reached is plainly waiting. */
.pj-stage { border-left: 4px solid var(--border); }
.pj-stage.pj-done { border-left-color: var(--good); }
.pj-stage.pj-current { border-left-color: var(--accent); }
.pj-stage.pj-todo { opacity: 0.72; }
.pj-stage-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.pj-stage-head h2 { font-family: var(--display); font-size: 16px; margin: 0; color: var(--accent-strong); }
.pj-stage-letter {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; border-radius: 50%;
  background: var(--accent); color: #fff;
  font-size: 12px; font-weight: 700; flex: none;
}
.pj-stage-state {
  margin-left: auto;
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-faint);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 2px 9px;
}
.pj-stage.pj-done .pj-stage-state { color: var(--good); border-color: var(--good); }
.pj-stage.pj-current .pj-stage-state { color: var(--accent-strong); border-color: var(--accent); }
.pj-stage-body { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 22px; align-items: start; }
@media (max-width: 980px) { .pj-stage-body { grid-template-columns: 1fr; } }

.pj-file-status { font-size: 11.5px; color: var(--text-dim); margin: -6px 0 10px; min-height: 15px; }
.pj-state-wrap { display: block; }
.pj-state-wrap select, .pj-state-wrap input { width: 100%; }

.pj-confirm {
  border: 1px solid var(--accent);
  border-left: 4px solid var(--accent);
  border-radius: 6px;
  background: rgba(122,92,46,0.05);
  padding: 12px 14px;
  margin-top: 10px;
}
.pj-confirm-text { font-size: 13px; line-height: 1.6; color: var(--text); margin: 0 0 10px; }

/* Step 4.4: the on-screen report reader. Deliberately plain -- the framed
   document carries the watermark, so this is only the frame around it. */
.ts-reader{position:fixed;inset:0;z-index:9999;background:rgba(20,18,14,.55);
  display:flex;align-items:center;justify-content:center;padding:24px}
.ts-reader-box{background:#fff;border-radius:6px;width:min(1100px,100%);height:min(90vh,100%);
  display:flex;flex-direction:column;overflow:hidden;box-shadow:0 12px 40px rgba(0,0,0,.3)}
.ts-reader-bar{display:flex;align-items:center;gap:10px;padding:8px 12px;
  border-bottom:1px solid var(--rw-border,#ccc);font-size:13px}
.ts-reader-bar .rw-auth-btn{margin-left:auto}
.ts-reader-frame{flex:1;width:100%;border:0;background:#fff}
