/* A Simplified Energy Balance (RC) Model for DSF System -- GUI v1.4.0 */

:root {
  --bg: #eef0f3;
  --panel: #ffffff;
  --panel2: #f5f6f8;
  --head: #e8ebf0;
  /*  ITEM 2: the left column's panel headers, deepened so each reads as its
      own object against the column's ground rather than blending into it. */
  --head-strong: #ccd4e2;
  --fg: #14161a;
  --muted: #5d6673;
  --grid: #dfe3e9;
  --line: #d3d8e0;
  --accent: #17429c;
  --accent-soft: #dbe5f7;
  --accent-fg: #ffffff;
  --ok: #04603f;
  --okbg: #dcf5ea;
  --warn: #8a4b04;
  --warnbg: #fdefdb;
  --bad: #96130f;
  --badbg: #fbe3e2;
  --tip: rgba(15, 20, 28, 0.95);
  --noteBg: rgba(255, 255, 255, 0.95);

  /* Typography.  The interface runs on the platform's own text face -- SF on
     macOS, Segoe UI Variable on Windows, Roboto on Linux -- which are properly
     drawn faces with real optical sizing, hinted for the screen and already on
     the machine, so the app needs no web fonts and works offline.  Running text
     is regular weight; headings are the same family at 600, per the house rule.
     Every figure is set in Times New Roman with tabular lining numerals,
     so columns of results align on the decimal point. */
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI Variable Text",
          "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-head: -apple-system, BlinkMacSystemFont, "Segoe UI Variable Display",
               "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  /*  Every figure, unit and symbol in the interface.  Times New Roman is on
      every machine this runs on, and it carries LINING TABULAR figures, so
      columns of results still align on the decimal point even though the face
      itself is proportional -- which is why `font-variant-numeric: tabular-nums`
      stays on everything set in it.  The serif also suits the equation panel,
      where the terms are written out symbolically. */
  --font-num: "Times New Roman", Times, "Liberation Serif", "Nimbus Roman",
              serif;

  /*  THE HEADER'S HEIGHT IS A SHARED NUMBER.  The left column is sticky and
      has to start exactly where the header ends; before this it carried the
      literal 54px and the literal 118px (header + run bar), so adding the
      funding strip to the title bar would have tucked the inputs underneath
      it.  One variable, two consumers, no arithmetic left in two places. */
  --header-h: 76px;
  --runbar-h: 64px;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #0d0f13;
    --panel: #171a20;
    --panel2: #1d2027;
    --head: #232833;
    --head-strong: #39414f;
    --fg: #eceef2;
    --muted: #a3abb9;
    --grid: #2c313c;
    --line: #333947;
    --accent: #6ea2ff;
    --accent-soft: #1b2740;
    --accent-fg: #0d0f13;
    --ok: #4ade9f;
    --okbg: #06281d;
    --warn: #fbbf24;
    --warnbg: #2c2006;
    --bad: #ff8a84;
    --badbg: #2e0f0e;
    --tip: rgba(5, 7, 10, 0.96);
    --noteBg: rgba(23, 26, 32, 0.95);
  }
}

* { box-sizing: border-box; }

html, body {
  font-family: var(--font);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-synthesis-weight: none;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-size: 12px;
  line-height: 1.5;
  font-weight: normal;
  -webkit-font-smoothing: antialiased;
}

input, select, button, table, dl { font-family: var(--font); font-weight: normal; }

/* every figure in the interface is set in Times New Roman, lining and tabular */
input[type="number"],
table.data td.num,
dl.kv dd { font-family: var(--font-num); font-size-adjust: 0.52; font-variant-numeric: tabular-nums; }

.muted { color: var(--muted); }
.spacer { flex: 1 1 auto; }

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

/*  HOST LEFT, TITLE CENTRED, FUNDERS RIGHT.  Three credits in one bar: whose
    university built it, what it is, and who paid for it.  The title holds the
    centre and the two marks flank it. */
header.app {
  position: sticky;
  top: 0;
  z-index: 30;
  background: var(--panel);
  border-bottom: 2px solid var(--line);
  padding: 8px 14px;
  height: var(--header-h);
  box-sizing: border-box;
  /*  THREE TRACKS, AND THE OUTER TWO ARE EQUAL.  `1fr auto 1fr` is what puts
      the title on the PAGE's centre line rather than halfway between two
      logos of very different widths -- with the EU strip roughly seven times
      the width of the unibz mark, "centred between them" would sit visibly
      left of centre.  `minmax(0, 1fr)` lets the outer tracks fall below their
      content width so the bar never overflows the window; the funding strip
      scales inside its track (see below) instead of being clipped. */
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: 18px;
  text-align: left;
}

header.app .brand {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  min-width: 0;
  text-align: center;
}

/*  THE TWO MARKS, UNBOXED.
    They sat on bordered white plates; the plates are gone, so each mark meets
    the bar's own ground.  In the light theme that ground IS white and the
    plates were doing nothing but drawing a rectangle around artwork that
    already had one.  The EU strip keeps its supplied white background either
    way -- the emblem may not be placed on a ground that changes its colours --
    and carries a small radius of its own so it does not read as a hard-edged
    block in the dark theme. */
header.app .mark {
  line-height: 0;
  min-width: 0;
}
header.app .mark-unibz { justify-self: start; }
header.app .funding    { justify-self: end; }

/*  The unibz mark is narrow enough to keep its full height at every width, so
    it is what fixes the bar's content height -- which is why --header-h can
    stay an exact number while the strip opposite is free to scale. */
header.app .mark-unibz img {
  display: block;
  height: 58px;
  width: auto;
}

/*  THE FUNDING STRIP SCALES, IT DOES NOT STEP.
    At roughly 8.6:1 this artwork is about 500px wide at full height, so on
    anything narrower than a large desktop it has to give way to the title.
    `max-width: 100%` with `height: auto` lets it shrink to whatever its track
    allows and keep its proportions, capped at 58px so it never grows past the
    size asked for.  A ladder of fixed heights would have needed a breakpoint
    for every window width to avoid either clipping or a visible jump. */
header.app .funding img {
  display: block;
  width: auto;
  height: auto;
  max-height: 58px;
  max-width: 100%;
  border-radius: 3px;
}

/*  THE TITLE GIVES WAY BEFORE THE STRIP DOES.  Narrowing the window takes the
    same width off both outer tracks, so the strip opposite shrinks twice as
    fast as the window does.  Stepping the heading down first widens both
    tracks and buys the strip back most of that loss -- and a heading one size
    smaller is a far smaller loss than an acknowledgement too small to read. */
@media (max-width: 1220px) {
  header.app h1 { font-size: 16px; }
  header.app .projref { font-size: 13.5px; }
}
/*  BELOW THIS THE BAR WRAPS: title across the top, the two marks beneath it,
    host left and funders right.  Squeezing on would leave the strip around
    20px tall, which is not an acknowledgement any more.

    --header-h IS REDEFINED HERE, and it has to be: the left column is sticky
    at exactly that offset, so a bar that grew a second row while the column
    still believed in the old number would have the inputs tucked underneath.
    `height` stays fixed rather than `auto`, so the bar cannot drift away from
    the number the column is using -- 94 = 16 padding + 2 border + 34 title +
    8 row gap + 34 mark.  (Below 900 the column goes static and the height is
    released, so a title that wraps to two lines has room.) */
@media (max-width: 1020px) {
  :root { --header-h: 94px; }
  header.app h1 { font-size: 15px; }
  header.app .projref { font-size: 12.5px; }
}
@media (max-width: 1020px) {
  header.app {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
  }
  header.app .brand { order: 1; flex: 1 1 100%; }
  header.app .mark-unibz { order: 2; }
  header.app .funding { order: 3; margin-left: auto; }
  header.app .mark-unibz img { height: 34px; }
  header.app .funding img { max-height: 34px; }
}

/*  At the layout's own breakpoint the left column stops being sticky, so the
    bar no longer owes it an exact height and a wrapped title can take the
    room it needs. */
@media (max-width: 900px) {
  header.app { height: auto; }
}

/*  LINE ONE: the title, bold, in the accent blue.
    LINE TWO: the project reference, bold, in body colour, one step down.
    `--fg` rather than a literal black, so the line stays legible when the
    interface is in its dark theme -- "black" here means body text colour, and
    body text is what it has to read as. */
header.app h1 {
  font-size: 18px;
  margin: 0;
  font-family: var(--font-head);
  font-weight: 700;
  line-height: 1.15;
  color: var(--accent);
}
header.app .projref {
  font-size: 15px;
  font-weight: 700;
  line-height: 1.2;
  color: var(--fg);
  /*  the same face as the line above it: the two lines are one credit in two
      parts, so they are set as one thing in two sizes */
  font-family: var(--font-head);
}

/*  THE RUN BAR.  Solve belongs where it is always reachable rather than at the
    top of a column that scrolls away, so it is fixed to the foot of the window.
    The layout's bottom padding is what keeps the last card clear of it. */
footer.runbar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 40;
  background: var(--panel);
  border-top: 2px solid var(--line);
  padding: 8px 14px;
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  box-shadow: 0 -2px 10px rgba(16, 20, 28, 0.06);
}
footer.runbar .err { margin: 0; font-size: 11.5px; max-width: 70ch; }
footer.runbar .err:empty { display: none; }

/*  The verdict belongs where the eye already is when a run finishes, which is
    the button that started it -- not in a panel three columns away. */
.foot-status {
  display: flex;
  align-items: center;
  gap: 9px;
  flex-wrap: wrap;
  padding-left: 14px;
  border-left: 1px solid var(--line);
}
.foot-status:empty { display: none; }
.foot-status .figs {
  font-family: var(--font-num); font-size-adjust: 0.52;
  font-size: 10.5px;
  color: var(--muted);
}
.foot-status .figs b { color: var(--fg); font-weight: 500; }

/*  A substituted equation is not a converged one, so it does not get the
    quiet treatment a normal figure gets. */
p.warnnote {
  margin: 10px 0 0;
  padding: 9px 11px;
  border-left: 3px solid var(--bad);
  background: var(--badbg);
  border-radius: 0 4px 4px 0;
  font-size: 10.5px;
  line-height: 1.55;
  color: var(--fg);
}

/*  THE ZONE PICKER.  One zone's equations on screen at a time, and the move
    between zones a click rather than a scroll past five equations. */
.zonepick {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-wrap: wrap;
  margin: 0 0 12px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--line);
}
.zonepick .lbl, .zonepick .of {
  font-family: var(--font-head);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  margin-right: 3px;
}
.zonepick .of { margin: 0 0 0 5px; }
.zonepick .spacer { flex: 1; }
.zonepick button {
  font-family: var(--font-num); font-size-adjust: 0.52;
  font-size: 11px;
  min-width: 26px;
  padding: 3px 6px;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--panel);
  color: var(--muted);
  cursor: pointer;
  line-height: 1.5;
}
.zonepick button:hover:not(.on) { color: var(--fg); border-color: var(--fg); }
.zonepick button.on,
.zonepick button.on:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-fg);
}
.zonepick button:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.zonepick .zmeta { font-size: 10.5px; color: var(--muted); }
.zonepick .zmeta b { color: var(--fg); font-family: var(--font-num); font-size-adjust: 0.52; }

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

.layout {
  display: grid;
  /*  The left column holds labels and short number fields, nothing wide, so
      it can give ground to the results -- which carry the section drawing and
      a plot side by side and use every pixel they get. */
  grid-template-columns: 268px minmax(0, 1fr);
  gap: 12px;
  padding: 12px 14px 76px;
  align-items: start;
  max-width: 1760px;
  margin: 0 auto;
}

/*  Two columns now: inputs and output on the left, results on the right.
    The information bar's panels moved into the left column, under Output,
    where they sit beside the inputs that produced them. */
@media (max-width: 900px) {
  .layout { grid-template-columns: 1fr; }
}

/*  The left column is a fixed panel: it stays put while the results scroll, and
    scrolls within itself when its own contents are taller than the window.
    Otherwise the inputs walk off the top as soon as you read a long result. */
aside {
  position: sticky;
  top: var(--header-h);
  height: calc(100vh - var(--header-h) - var(--runbar-h));
  overflow-y: auto;
  overscroll-behavior: contain;
  padding-right: 4px;
}
@media (max-width: 900px) { aside { position: static; height: auto; } }

/*  Its panels sit on a slightly greyer ground than the results, so the two
    halves of the window read as two things rather than one long list. */
aside .card { background: var(--bg); }
aside .card > h2 { background: var(--head-strong); }
aside .card.collapsed > h2 { border-bottom-color: transparent; }
aside .card .body { background: var(--panel); }

/* --------------------------------------------------------- panel toolbar */

.panelbar {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0 2px 8px;
}

/*  ITEM 2.  INPUTS / OUTPUT / SINGLE POINT RUN are the MAJOR headings: bold,
    blue, and set apart from the panel headings under them, which are
    italicised on a dark ground.  Two levels, told apart by weight and colour
    rather than by size alone. */
.panelbar-title {
  font-size: 11.5px;
  font-family: var(--font-head); font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--accent);
}

/*  ITEM 2.  The sidebar has to show every panel at once.  The headings carry
    the whole column when everything is collapsed, so they are the thing to
    shrink: tighter padding, a smaller cap height, and less air between
    cards.  Nothing in the bodies changes, so an open panel reads as before. */
aside .card { margin-bottom: 5px; }
aside .card > h2 {
  padding: 5px 9px 5px 7px;
  font-size: 10.5px;
  font-style: italic;
  letter-spacing: 0.02em;
  gap: 5px;
}
aside .card > h2 .info { margin-left: 2px; }
aside .panelbar { padding: 0 2px 5px; }
aside .panelbar .small { padding: 2px 7px; font-size: 9.5px; }
aside .outputs { display: block; }

/* ---------------------------------------------------------------- panels */

.card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  margin-bottom: 10px;
  overflow: hidden;
}

.card > h2 {
  margin: 0;
  font-size: 11px;
  font-family: var(--font-head); font-weight: 600;
  text-transform: uppercase;
  color: var(--fg);
  padding: 9px 11px 9px 9px;
  border-bottom: 1px solid var(--line);
  background: var(--head);
  cursor: pointer;
  user-select: none;
  display: flex;
  align-items: center;
  gap: 7px;
}

.card > h2::before {
  content: "";
  width: 0;
  height: 0;
  flex: 0 0 auto;
  border-left: 5px solid currentColor;
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
  transform: rotate(90deg);
  transition: transform 0.13s ease;
  opacity: 0.75;
}
.card.collapsed > h2::before { transform: rotate(0deg); }
.card.collapsed > .body { display: none; }

.card > h2:hover { background: var(--accent-soft); }

.card > .body { padding: 10px 11px; }

/* ---------------------------------------------------------------- fields */

.field {
  display: grid;
  grid-template-columns: 1fr 84px;
  gap: 8px;
  align-items: center;
  margin-bottom: 7px;
}
.field:last-child { margin-bottom: 0; }

.field > label {
  font-size: 11px;
  line-height: 1.35;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px;
}
.field > label .u { color: var(--muted); font-size: 10px; }
.field > label .sym { font-size: 10px; color: var(--accent); }

.field.wide { grid-template-columns: 1fr; gap: 4px; }

/* small explanatory line under a field, e.g. the cavity zone count */
.field .hint {
  font-size: 10.5px;
  line-height: 1.4;
  color: var(--muted);
  margin-top: 2px;
}
.field .hint.warn { color: var(--warn, #9a5b16); }

input[type="number"], input[type="text"], select {
  width: 100%;
  padding: 5px 7px;
  border: 1px solid var(--line);
  border-radius: 5px;
  background: var(--panel2);
  color: var(--fg);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

input:focus, select:focus { outline: 2px solid var(--accent); outline-offset: -1px; }

.checkline { display: flex; gap: 7px; align-items: center; margin: 10px 0 2px; }
.checkline label { font-size: 11px; display: flex; align-items: center; gap: 5px; }

.inline-check { display: flex; align-items: center; gap: 6px; font-size: 11px; color: var(--muted); }

/* ----------------------------------------------------------- info button */

button.info {
  flex: 0 0 auto;
  width: 15px;
  height: 15px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--muted);
  background: transparent;
  color: var(--muted);
  font-size: 9px;
  line-height: 1;
  cursor: help;
  text-transform: none;
}
button.info:hover { background: var(--accent); border-color: var(--accent); color: var(--accent-fg); }

.infopop {
  position: absolute;
  z-index: 100;
  max-width: 300px;
  background: var(--tip);
  color: #fff;
  padding: 9px 11px;
  border-radius: 6px;
  font-size: 11px;
  line-height: 1.5;
  box-shadow: 0 6px 22px rgba(0, 0, 0, 0.3);
}

/* ---------------------------------------------------------------- buttons */

button {
  font-size: 11px;
  padding: 6px 11px;
  border-radius: 5px;
  border: 1px solid var(--line);
  background: var(--panel2);
  color: var(--fg);
  cursor: pointer;
}
button:hover:not(:disabled):not(.info) { border-color: var(--accent); color: var(--accent); }
button:disabled { opacity: 0.45; cursor: not-allowed; }

button.primary { background: var(--accent); color: var(--accent-fg); border-color: var(--accent); }
button.primary:hover:not(:disabled) { color: var(--accent-fg); filter: brightness(1.12); }

button.small { padding: 3px 8px; font-size: 10px; }
button.ghost { background: transparent; }

.btnrow { display: flex; gap: 7px; flex-wrap: wrap; align-items: center; }

/* ---------------------------------------------------------------- tables */

table.data { width: 100%; border-collapse: collapse; font-size: 11px; }
table.data th, table.data td { padding: 5px 7px; border-bottom: 1px solid var(--grid); text-align: left; }
table.data th {
  color: var(--muted);
  font-size: 10px;
  font-family: var(--font-head); font-weight: 600;
  text-transform: uppercase;
  background: var(--panel2);
}
table.data td.num, table.data th.num { text-align: right; font-variant-numeric: tabular-nums; }
table.data tr:last-child td { border-bottom: none; }
table.data td .sym { color: var(--accent); }
table.data tbody tr.total td { border-top: 1px solid var(--line); background: var(--panel2); font-family: var(--font-head); font-weight: 600; }
table.data tbody tr.group td { background: var(--head); font-size: 10px; font-family: var(--font-head); font-weight: 600; text-transform: uppercase; }

.tablewrap { overflow-x: auto; }

/* ---------------------------------------------------------------- charts */

.split { display: grid; grid-template-columns: minmax(240px, 0.9fr) minmax(300px, 1.1fr); gap: 14px; align-items: start; }
@media (max-width: 900px) { .split { grid-template-columns: 1fr; } }

.chartbox canvas { width: 100%; display: block; }
.chart-actions { display: flex; justify-content: flex-end; gap: 6px; margin: 6px 0 10px; }

/*  A segmented toggle sitting in a card heading.  Two states that are two
    views of one thing belong on one control, not on two panels the reader has
    to hold side by side in their head. */
.h2-actions { margin-left: auto; display: flex; align-items: center; gap: 8px; }
.seg {
  display: inline-flex;
  border: 1px solid var(--line);
  border-radius: 6px;
  overflow: hidden;
  background: var(--bg);
}
.seg button {
  font: inherit;
  font-size: 11px;
  font-weight: 500;
  font-family: var(--font-head);
  padding: 3px 11px;
  border: 0;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  line-height: 1.7;
}
.seg button + button { border-left: 1px solid var(--line); }
/*  The generic button:hover rule sets colour to the accent, which on an
    active segment is the same as its background -- the label disappears
    exactly while the pointer is on it. Both states are stated here. */
.seg button:hover:not(.on) { color: var(--fg); }
.seg button.on,
.seg button.on:hover { background: var(--accent); color: var(--accent-fg); }
.seg button:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/*  A fixed colour scale is what makes two runs comparable: an adaptive one
    re-normalises to each result, so the same colour means a different number
    every time you change an input. */
.rangebox {
  /*  The card heading is uppercased; these are units and numbers, and W/M2 is
      not a unit. */
  text-transform: none;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 11px;
  color: var(--muted);
}
.rangebox .inline-check { font-size: 11px; gap: 4px; }
.rangebox input[type="number"] {
  width: 58px;
  font-family: var(--font-num); font-size-adjust: 0.52;
  font-size: 11px;
  padding: 2px 5px;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--panel);
  color: var(--fg);
}
.rangebox input[type="number"]:disabled { opacity: 0.45; }
.rangebox .dash { color: var(--muted); }
.rangebox .ru { font-family: var(--font-num); font-size-adjust: 0.52; font-size: 10.5px; }

h3.subhead {
  font-family: var(--font-head);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 18px 0 7px;
  padding-bottom: 5px;
  border-bottom: 1px solid var(--line);
}

/* ---- the governing equations, written out ----------------------------- */
/*  Each term is a box: the symbolic form on top, the value it took at this
    solution underneath, in the order the equation writes them. The closure box
    at the end is the same shape, because it is the same kind of thing -- what
    the terms add up to. */
.eqlist { margin-top: 14px; }
.eqnode { margin: 0 0 15px; }
.eqnode:last-child { margin-bottom: 0; }
.eqnode > .hd {
  display: flex;
  align-items: baseline;
  gap: 9px;
  flex-wrap: wrap;
  margin-bottom: 6px;
}
.eqnode > .hd .eqno {
  font-family: var(--font-num); font-size-adjust: 0.52;
  font-size: 11px;
  font-weight: 500;
  color: var(--accent-fg);
  background: var(--fg);
  border-radius: 3px;
  padding: 1px 7px;
}
.eqnode > .hd .nm {
  font-family: var(--font-head);
  font-weight: 600;
  font-size: 12.5px;
}
.eqnode > .hd .sym {
  font-family: var(--font-num); font-size-adjust: 0.52;
  font-size: 11.5px;
  color: var(--accent);
}
.eqnode > .hd .un { font-size: 10.5px; color: var(--muted); margin-left: auto; }

.eqrow {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 5px;
}
.eqrow .tail { display: inline-flex; align-items: stretch; gap: 5px; }
.eqrow .op {
  align-self: center;
  font-family: var(--font-num); font-size-adjust: 0.52;
  font-size: 13px;
  color: var(--muted);
  padding: 0 1px;
}
.eqrow .term {
  border: 1px dashed;
  border-radius: 5px;
  padding: 4px 9px 5px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.eqrow .term .ex {
  font-family: var(--font-num); font-size-adjust: 0.52;
  font-size: 10.5px;
  line-height: 1.35;
  white-space: nowrap;
}
.eqrow .term .vl {
  font-family: var(--font-num); font-size-adjust: 0.52;
  font-variant-numeric: tabular-nums;
  font-size: 12.5px;
  font-weight: 500;
  text-align: right;
  color: var(--fg);
}
/*  Colour by mechanism, matching the legend on the matrix above and the
    stripe on the section drawing. */
.eqrow .k-conduction { border-color: #7c3aed; color: #7c3aed; }
.eqrow .k-radiation  { border-color: #c02626; color: #c02626; }
.eqrow .k-convection { border-color: #1d4ed8; color: #1d4ed8; }
.eqrow .k-solar      { border-color: #c27803; color: #c27803; }
.eqrow .k-flow       { border-color: #047857; color: #047857; }
.eqrow .term.closure {
  border-style: solid;
  border-color: var(--fg);
  color: var(--muted);
  background: var(--bg);
}
.eqrow .term.closure.ok .vl  { color: var(--ok); }
.eqrow .term.closure.bad .vl { color: var(--bad); }

/* ---- the closure matrix ----------------------------------------------- */
table.eqmat { width: 100%; border-collapse: collapse; font-size: 11.5px; }
table.eqmat th {
  font-family: var(--font-head);
  font-weight: 600;
  font-size: 10px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
  text-align: left;
  padding: 0 7px 5px;
  border-bottom: 1.5px solid var(--line);
  white-space: nowrap;
}
table.eqmat th.n { text-align: right; }
table.eqmat th i {
  display: inline-block;
  width: 7px; height: 7px;
  border-radius: 2px;
  margin-right: 5px;
}
table.eqmat td {
  padding: 5px 7px;
  border-bottom: 1px solid var(--line);
}
table.eqmat td.n {
  font-family: var(--font-num); font-size-adjust: 0.52;
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}
table.eqmat td.empty { color: var(--muted); opacity: 0.5; }
table.eqmat td .mut { color: var(--muted); font-size: 10.5px; }
table.eqmat th.cl, table.eqmat td.cl {
  border-left: 1.5px solid var(--line);
  font-weight: 600;
}
table.eqmat td.cl.ok  { color: var(--ok); }
table.eqmat td.cl.bad { color: var(--bad); background: var(--badbg); }
p.eqcap {
  margin: 8px 0 0;
  font-size: 11px;
  line-height: 1.5;
  color: var(--muted);
  max-width: 78ch;
}

.eqkey {
  margin-top: 18px;
  padding-top: 11px;
  border-top: 1px solid var(--line);
  font-size: 10.5px;
  line-height: 1.7;
  color: var(--muted);
  display: flex;
  flex-wrap: wrap;
  gap: 2px 16px;
}
.eqkey b {
  font-family: var(--font-head);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--fg);
  width: 100%;
}
.eqkey span { font-family: var(--font-num); font-size-adjust: 0.52; }

.eqzone {
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 11px 13px;
  margin: 0 0 10px;
  background: var(--bg);
}
.eqzone > .zh {
  font-family: var(--font-head);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 9px;
}
.eqzone > .zh b { color: var(--fg); }

.grid-flux { display: grid; grid-template-columns: repeat(auto-fit, minmax(270px, 1fr)); gap: 8px; }
.grid-flux .fluxcell {
  border: 1px solid var(--grid);
  border-radius: 6px;
  padding: 4px;
  background: var(--panel);
}
.grid-flux canvas { width: 100%; display: block; }

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

/*  ITEM 8.  A RECTANGLE, not a lozenge.  The verdict is a status field, and a
    pill shape reads as a soft badge; squared corners say "this is the
    result", which is what it is. */
.pill {
  display: inline-flex;
  align-items: center;
  padding: 3px 9px;
  border-radius: 3px;
  font-size: 10px;
  font-weight: 600;
  border: 1px solid transparent;
}
.pill.ok { background: var(--okbg); color: var(--ok); border-color: currentColor; }
.pill.warn { background: var(--warnbg); color: var(--warn); border-color: currentColor; }
.pill.bad { background: var(--badbg); color: var(--bad); border-color: currentColor; }

/* ---------------------------------------------------------------- kv list */

dl.kv { display: grid; grid-template-columns: auto 1fr; gap: 4px 10px; margin: 0; font-size: 11px; }
dl.kv dt { color: var(--muted); }
dl.kv dd { margin: 0; text-align: right; font-variant-numeric: tabular-nums; word-break: break-word; }
dl.kv dd.wrap { text-align: left; }

/* ---------------------------------------------------------------- misc */

.err { color: var(--bad); font-size: 11px; white-space: pre-wrap; margin-top: 8px; }
.err:empty { display: none; }

/* ------------------------------------------------------- weather file panel */

.filedrop {
  border: 1.5px dashed var(--line);
  border-radius: 6px;
  padding: 11px 9px;
  text-align: center;
  cursor: pointer;
  background: var(--panel2);
  font-size: 11px;
  color: var(--muted);
}
.filedrop:hover, .filedrop.over { border-color: var(--accent); color: var(--accent); }
.filedrop b { font-family: var(--font-head); font-weight: 600; color: var(--fg); display: block; }
.filedrop.loaded { border-style: solid; text-align: left; }

.wx-out {
  margin-top: 9px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--panel2);
  padding: 8px 9px;
}
.wx-out .wx-head {
  font-family: var(--font-head); font-weight: 600;
  font-size: 10px;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 5px;
}
.wx-out dl.kv dd { font-family: var(--font-head); font-weight: 600; }

.datetime { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 6px; }
.datetime > div { display: flex; flex-direction: column; gap: 3px; }
.datetime label { font-size: 10px; color: var(--muted); }

.stepper { display: flex; gap: 6px; margin-top: 7px; }
.stepper button { flex: 1 1 auto; }

.warnbox {
  margin-top: 8px;
  background: var(--warnbg);
  color: var(--warn);
  padding: 7px 9px;
  border-radius: 5px;
  font-size: 10px;
  line-height: 1.45;
}

input:disabled, select:disabled {
  opacity: 0.65;
  cursor: not-allowed;
  background: var(--head);
}

.field.locked > label { color: var(--muted); }
.field.locked > label::after {
  content: "from file";
  font-size: 9px;
  color: var(--accent);
  background: var(--accent-soft);
  border-radius: 3px;
  padding: 0 4px;
  white-space: nowrap;
}

/* -------------------------------------------------------- system diagram */

#diagram-wrap { overflow-x: auto; }
/*  The section now shares its row with the plot (item 7), so it has to be
    legible at about 520px rather than the full width it used to have.  Below
    that the wrapper scrolls rather than the drawing collapsing. */
#ch-diagram { width: 100%; min-width: 520px; display: block; cursor: crosshair; }

/* ==========================================================================
   SPLIT RESULTS PANE, PLOT BUILDER, RUN TABS AND RUN SETTINGS
   Added for the two-pane section (item 7) and the annual run (item 8).
   ========================================================================== */

/*  ITEM 7.  The section drawing and the plot share one row.  `minmax(0, 1fr)`
    rather than `1fr` because a canvas has an intrinsic width and would
    otherwise refuse to shrink below it and push the row wide. */
.split2 {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 12px;
  align-items: start;
}
.split2 > .pane { min-width: 0; }
@media (max-width: 1180px) {
  .split2 { grid-template-columns: minmax(0, 1fr); }
}

/* ------------------------------------------------------------ plot builder */

.plotbuilder { min-width: 0; }
.plotbuilder canvas { width: 100%; display: block; }

.plotctl {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 5px 8px;
  align-items: center;
  margin-bottom: 9px;
  padding: 8px 9px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 6px;
}
.plotrow { display: contents; }
.plotlab {
  font-size: 10px;
  font-family: var(--font-head);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--muted);
  white-space: nowrap;
}
.plotsel, .plotinp {
  width: 100%;
  min-width: 0;
  font-size: 11px;
  padding: 3px 5px;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--panel);
  color: var(--fg);
}
.plotinp { font-family: var(--font-num); font-size-adjust: 0.52; }
.plotrow-btns {
  display: flex;
  grid-column: 1 / -1;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
  margin-top: 2px;
}
.plotempty {
  font-size: 11px;
  padding: 26px 0;
  text-align: center;
}

/* --------------------------------------------------------------- run tabs */

.runtabs { display: inline-flex; gap: 3px; }
.runtabs button {
  font-size: 11.5px;
  font-family: var(--font-head);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
  background: transparent;
  border: 1px solid transparent;
  border-radius: 4px 4px 0 0;
  padding: 3px 9px;
  cursor: pointer;
}
.runtabs button.on {
  color: var(--accent);
  background: var(--panel);
  border-color: var(--line);
  border-bottom-color: var(--panel);
}
.runtabs button:disabled { opacity: 0.45; cursor: not-allowed; }

/* ---------------------------------------------------------- run settings */

.runsettings { position: relative; }

/*  Opens UPWARD: the run bar is pinned to the bottom of the window, so a
    popover that dropped down would be off screen. */
.runpop {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 0;
  z-index: 60;
  width: 310px;
  max-width: calc(100vw - 24px);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.18);
  padding: 10px 11px;
}
.runpop h4 {
  margin: 0 0 7px;
  font-size: 10px;
  font-family: var(--font-head);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}
.radioline {
  display: flex;
  gap: 7px;
  align-items: flex-start;
  padding: 5px 0;
  font-size: 11.5px;
  cursor: pointer;
}
.radioline input { margin-top: 2px; flex: 0 0 auto; }
.radioline span { display: flex; flex-direction: column; gap: 1px; }
.radioline small { color: var(--muted); font-size: 10px; line-height: 1.35; }
/*  A disabled option is shown, not hidden: the user needs to see that the
    mode exists and what it is waiting for. */
.radioline:has(input:disabled) { cursor: not-allowed; opacity: 0.55; }

.rangedates {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
  padding: 0 0 6px 22px;
}
.rangedates label {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 10px;
  color: var(--muted);
}
.rangedates input {
  font-size: 10.5px;
  padding: 3px 4px;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--panel);
  color: var(--fg);
  font-family: var(--font-num);
  font-size-adjust: 0.52;
}
.rangedates input:disabled { opacity: 0.5; }

.runpop-foot {
  border-top: 1px solid var(--line);
  margin-top: 6px;
  padding-top: 7px;
}

/* ----------------------------------------------------------- run progress */

/*  `hidden` must win over the flex display, or the progress bar shows at
    idle -- `[hidden]` is only `display:none` at the default specificity. */
.foot-prog[hidden] { display: none; }
.foot-prog {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 10.5px;
  color: var(--muted);
}
.foot-prog progress { width: 150px; height: 8px; }

/* ==========================================================================
   RESULTS VIEWER -- one card, four tabs
   ========================================================================== */

/*  The colour range sits UNDER the bar it scales now, so it is a row of its
    own inside the left pane rather than a cluster in the card's title bar. */
#view-field .rangebox {
  margin: 8px 0 0;
  justify-content: flex-start;
  flex-wrap: wrap;
}

/*  The equation table's own controls, where the card heading used to carry
    them. */
.eqhead {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 9px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--line);
}

.mut { color: var(--muted); }
dl.kv dd a { color: var(--accent); }

/*  A figure that can be clicked for the story behind it.  Styled as a number
    first and a control second: it sits in a column of plain values, so it
    must not shout, but it has to be discoverably clickable. */
button.linkish {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: var(--accent);
  cursor: pointer;
  text-decoration: underline dotted;
  text-underline-offset: 2px;
}
button.linkish:hover { text-decoration-style: solid; }

#reject-wrap {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--line);
}
#reject-detail h4.subhead {
  margin: 0 0 7px;
  font-size: 10px;
  font-family: var(--font-head);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}
#reject-detail table.data td.wrap { white-space: normal; line-height: 1.35; }

/*  A disabled control says so by looking it, not only by refusing clicks. */
.inline-check.is-disabled { opacity: 0.5; cursor: not-allowed; }


/* ==========================================================================
   A LONG FILE NAME MUST NOT ESCAPE ITS BOX
   `83200MS_BolzanoOspedale_TRY_HOT.xlsx` has no spaces, so nothing in it is a
   wrap opportunity and the default `white-space: nowrap` ran it straight out
   of the drop zone.  `overflow-wrap: anywhere` lets it break mid-token, which
   for a file name is the right trade: a name split across two lines is still
   readable, one that leaves the panel is not.
   ========================================================================== */
#wx-drop { overflow: hidden; }
#wx-drop b,
#wx-drop span {
  display: block;
  max-width: 100%;
  overflow-wrap: anywhere;
  word-break: break-word;
  white-space: normal;
}

/* ==========================================================================
   THE RUN BAR -- each fact in its own box
   The verdict, where the run came from and the solver's figures were one
   run-on line in caption grey.  They are three different kinds of fact and
   they are read at a glance, so each gets its own bordered chip at the body
   size and colour rather than a smaller, greyer one.
   ========================================================================== */
.foot-status {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}
.foot-status .figs {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 11.5px;
  color: var(--fg);
  padding: 3px 8px;
  border: 1px solid var(--line);
  border-radius: 3px;
  background: var(--bg);
  white-space: nowrap;
}
.foot-status .figs b {
  font-family: var(--font-num);
  font-size-adjust: 0.52;
  font-weight: 600;
}
.foot-status .figs .lab {
  color: var(--muted);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
footer.runbar .err { font-size: 11.5px; }


/*  A verdict that is also the way in to the detail behind it.  It has to keep
    reading as a status pill -- it is the run's result first -- so it inherits
    the pill's look and only picks up the affordances of a control. */
.pill-btn {
  cursor: pointer;
  font: inherit;
  font-size: 10px;
  font-weight: 600;
  text-decoration: underline dotted;
  text-underline-offset: 2px;
}
.pill-btn:hover { text-decoration-style: solid; }

.rejhead { display: flex; align-items: center; gap: 8px; }
.rejhead .subhead { margin: 0 !important; }

.closebtn {
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--muted);
  border-radius: 3px;
  width: 20px;
  height: 20px;
  line-height: 1;
  font-size: 14px;
  cursor: pointer;
  padding: 0;
}
.closebtn:hover { color: var(--fg); border-color: var(--muted); }

/* ==========================================================================
   `hidden` MUST ACTUALLY HIDE
   The `hidden` attribute is only `display: none` at the user-agent default
   specificity, so ANY class rule that sets `display` outranks it.  That is
   how `#view-field` (a `.split2`, `display: grid`) stayed on screen with the
   Energy balance tab selected: the attribute was set, the grid won, and the
   section drawing and the plot sat above a table that was meant to replace
   them.  This has now bitten twice -- `.foot-prog` was the first -- so it is
   settled once, globally, rather than patched per selector.
   ========================================================================== */
[hidden] { display: none !important; }

/* DeepSeeBit line under the title (2026-10-30) */
.brand .projref.dsb { display:block; margin-top:2px; font-size:12px; opacity:.85 }
.brand .projref.dsb a { color:inherit; text-decoration:none }
.brand .projref.dsb a:hover { text-decoration:underline }
