:root{--ink:#17201d;--muted:#65706b;--paper:#f4f1e9;--panel:#fffdfa;--line:#d9d5ca;--green:#1e604c;--lime:#b9d96b;--orange:#e87842;--shadow:0 14px 35px #1a292012}*{box-sizing:border-box}body{margin:0;background:var(--paper);color:var(--ink);font:15px/1.5 Inter,Segoe UI,sans-serif}header{height:98px;padding:20px 4vw;display:flex;align-items:center;justify-content:space-between;background:var(--ink);color:white}h1,h2,p{margin-top:0}h1{font:700 35px/1.1 Georgia,serif;margin:4px 0}.eyebrow,.kicker{font-size:11px;letter-spacing:.16em;font-weight:800;color:var(--green)}header .eyebrow{color:var(--lime)}.privacy{padding:9px 14px;border:1px solid #ffffff38;border-radius:20px;font-size:13px}.privacy span{display:inline-block;width:8px;height:8px;background:var(--lime);border-radius:50%;margin-right:7px}nav{padding:0 4vw;background:var(--ink);display:flex;gap:5px}.tab{border:0;background:transparent;color:#bfc7c2;padding:13px 18px;font-weight:700;cursor:pointer;border-bottom:3px solid transparent}.tab.active{color:white;border-color:var(--lime)}main{max-width:1480px;margin:auto;padding:28px 4vw 70px}.panel{background:var(--panel);border:1px solid var(--line);border-radius:14px;padding:24px;box-shadow:var(--shadow);margin-bottom:22px}.setup{display:block}.setup h2,.panel h2{font:700 24px/1.2 Georgia,serif}.grid-form{display:grid;grid-template-columns:repeat(3,1fr);gap:14px}.grid-form .wide{grid-column:span 2}.grid-form label,.toolbar label{font-size:12px;font-weight:800;color:var(--muted);text-transform:uppercase;letter-spacing:.05em}.grid-form input,.grid-form select,.toolbar select{display:block;width:100%;margin-top:6px;padding:11px 12px;border:1px solid var(--line);border-radius:8px;background:white;color:var(--ink)}button,.button{cursor:pointer}.primary,.button{border:0;border-radius:8px;background:var(--green);color:white;padding:12px 18px;font-weight:800;text-decoration:none;align-self:end;text-align:center}.toolbar{display:flex;gap:18px;align-items:end;padding:16px 22px}.toolbar label{min-width:220px}.status{margin-left:auto;padding:10px 14px;border-radius:8px;background:#edf2e5;color:var(--green);font-weight:700}.metric-grid{display:grid;grid-template-columns:repeat(6,1fr);gap:14px;margin-bottom:22px}.metric-grid article{background:var(--panel);border:1px solid var(--line);border-top:4px solid var(--ink);padding:18px;border-radius:12px;min-height:135px}.metric-grid article.accent{background:var(--green);color:white;border-color:var(--green)}.metric-grid span,.metric-grid small{display:block;color:var(--muted);font-size:12px}.metric-grid .accent span,.metric-grid .accent small{color:#d6e7df}.metric-grid strong{display:block;font:700 32px/1.1 Georgia,serif;margin:18px 0 5px}.two-col{display:grid;grid-template-columns:1fr 1fr;gap:22px}.util{display:flex;gap:45px;margin:24px 0}.util b{font:700 32px Georgia,serif;display:block}.util span{font-size:12px;color:var(--muted)}.callout{border-left:4px solid var(--orange);background:#fff1e8;padding:12px 15px;font-weight:700}.chart{height:240px;display:flex;align-items:end;gap:7px;padding-top:28px;border-bottom:1px solid var(--line)}.bar{flex:1;background:var(--green);min-width:12px;position:relative;border-radius:5px 5px 0 0;opacity:.72}.bar.recommended{background:var(--orange);opacity:1}.bar span{position:absolute;bottom:-24px;width:100%;font-size:10px;text-align:center}.bar b{position:absolute;top:-20px;width:100%;font-size:9px;text-align:center}.panel-head{display:flex;justify-content:space-between;align-items:start}.table-wrap{overflow:auto;max-height:480px}table{width:100%;border-collapse:collapse;font-size:13px}th,td{text-align:left;border-bottom:1px solid var(--line);padding:10px 9px}th{position:sticky;top:0;background:var(--panel);color:var(--muted);font-size:11px;text-transform:uppercase}#type-bars{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin:8px 0 22px}.type-card{padding:12px;background:#eef0ea;border-radius:8px}.type-card b{font:700 22px Georgia,serif}.type-card span{display:block;text-transform:capitalize;color:var(--muted)}.compact{grid-template-columns:1fr 1fr}.compact .primary{grid-column:span 2}.notice{background:#eef0ea;padding:16px;border-radius:10px}.quality-card{padding:16px 0;border-bottom:1px solid var(--line)}.quality-card b{font:700 30px Georgia,serif;display:block}dl{display:grid;grid-template-columns:150px 1fr;gap:12px}dt{font-weight:800}dd{margin:0;font-family:Consolas,monospace;font-size:13px}#toast{position:fixed;right:25px;bottom:25px;background:var(--ink);color:white;padding:14px 18px;border-radius:9px;box-shadow:var(--shadow);display:none;max-width:460px}#toast.error{background:#9c3527}@media(max-width:1000px){.metric-grid{grid-template-columns:repeat(3,1fr)}.setup,.two-col{grid-template-columns:1fr}}@media(max-width:650px){.metric-grid,.grid-form{grid-template-columns:1fr}.grid-form .wide{grid-column:auto}.toolbar{flex-wrap:wrap}.status{margin-left:0}.metric-grid{grid-template-columns:1fr 1fr}}
:root .primary:disabled{opacity:.65;cursor:wait}.import-message{grid-column:1/-1;margin:0;color:var(--green);font-weight:700}.import-message.error{color:#9c3527}
:root .workflow-step{margin:0 0 22px}.workflow-heading,.workflow-step summary{display:block;margin:0 0 16px;font-size:14px;font-weight:800;color:var(--ink);letter-spacing:.02em}.workflow-heading span,.workflow-step summary span{display:inline-grid;place-items:center;width:26px;height:26px;margin-right:9px;border-radius:50%;background:var(--green);color:#fff}.workflow-step summary{cursor:pointer;padding:16px 20px;border:1px solid var(--line);border-radius:12px;background:var(--panel);box-shadow:var(--shadow);list-style:none}.workflow-step summary::-webkit-details-marker{display:none}.workflow-step summary small{margin-left:10px;color:var(--muted);font-weight:600;letter-spacing:0}.workflow-step[open] summary{border-radius:12px 12px 0 0;border-bottom:0}.workflow-content{padding:22px 0 0}.estimate-step{margin-top:4px}
.level-summary-panel{padding-bottom:12px}.level-summary-panel h2{margin-bottom:0}.level-count{padding:7px 11px;border-radius:16px;background:#edf2e5;color:var(--green);font-size:12px;font-weight:800}.table-hint{margin:8px 0 14px;color:var(--muted);font-size:13px}.level-table-wrap{max-height:430px}.level-table th{white-space:nowrap}.level-table td{vertical-align:top}.level-table td small{display:block;color:var(--muted);white-space:nowrap}.level-summary-row{cursor:pointer}.level-summary-row:hover td{background:#f5f7ef}.level-summary-row.selected td{background:#edf2e5}.level-summary-row.selected td:first-child{box-shadow:inset 4px 0 var(--green)}.target-badge{display:inline-block;padding:4px 8px;border-radius:12px;font-size:11px;font-weight:800;white-space:nowrap}.target-badge.met{background:#dcebdc;color:#24633f}.target-badge.not-met{background:#f9e3d8;color:#963f26}

#model-warnings{margin:0 0 22px}#model-warnings ul{margin:6px 0 0;padding-left:20px;font-weight:600}

.method-note h3{font:800 12px/1.4 Inter,Segoe UI,sans-serif;letter-spacing:.06em;text-transform:uppercase;color:var(--green);margin:0 0 12px}.method-note .method-lede{color:var(--muted);margin-bottom:14px}.method-note ol,.method-note ul{margin:0 0 14px;padding-left:19px}.method-note li{margin-bottom:8px}.method-note code{background:#eef0ea;border-radius:4px;padding:1px 5px;font:600 12px Consolas,monospace}.method-note .formula{display:block;background:var(--ink);color:#e4eae6;border-radius:9px;padding:15px 17px;margin-bottom:14px;font:600 13px/1.8 Consolas,monospace;white-space:pre;overflow-x:auto}.method-note .callout{margin-top:4px}

.toolbar{flex-wrap:wrap;row-gap:12px}.toolbar label{min-width:0;flex:1 1 160px}.toolbar input{display:block;width:100%;margin-top:6px;padding:11px 12px;border:1px solid var(--line);border-radius:8px;background:white;color:var(--ink)}.toolbar input::placeholder{color:var(--muted);font-weight:700}.toolbar .button{flex:0 0 auto}

.rates{margin-top:18px;padding-top:16px;border-top:1px solid var(--line)}.rates-head{margin:0 0 12px;font-size:12px;color:var(--muted)}.rates-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:10px}.rates-grid label{font-size:11px;font-weight:800;color:var(--muted);text-transform:uppercase;letter-spacing:.05em}.rates-grid input{display:block;width:100%;margin-top:6px;padding:9px 10px;border:1px solid var(--line);border-radius:8px;background:white;color:var(--ink);font-weight:700}.rates-grid input.changed{border-color:var(--orange);background:#fff8f4}.link-button{margin-top:12px;border:0;background:none;padding:0;color:var(--green);font-weight:800;font-size:12px;text-decoration:underline}@media(max-width:650px){.rates-grid{grid-template-columns:1fr 1fr}}

.programme-panel .panel-head{margin-bottom:6px}.programme-metrics{display:grid;grid-template-columns:repeat(6,1fr);gap:12px;margin:16px 0 20px}.programme-metrics div{padding:14px;border:1px solid var(--line);border-top:4px solid var(--ink);border-radius:10px;background:#fbfaf6}.programme-metrics div.accent{background:var(--green);border-color:var(--green);color:#fff}.programme-metrics span,.programme-metrics small{display:block;color:var(--muted);font-size:11px}.programme-metrics .accent span,.programme-metrics .accent small{color:#d6e7df}.programme-metrics strong{display:block;font:700 26px/1.1 Georgia,serif;margin:12px 0 4px}.programme-table-wrap{max-height:none}.programme-table-wrap td small{display:block;color:var(--muted)}.programme-panel tr.current td{background:#edf2e5;font-weight:700}.programme-panel .note-flag{color:#963f26;font-weight:700}.toolbar label[hidden]{display:none}@media(max-width:1000px){.programme-metrics{grid-template-columns:repeat(3,1fr)}}@media(max-width:650px){.programme-metrics{grid-template-columns:1fr 1fr}}

.src{display:inline-block;margin-left:6px;padding:2px 5px;border-radius:4px;font:800 9px/1 Inter,Segoe UI,sans-serif;letter-spacing:.08em;vertical-align:middle}.src.ifc{background:#dcebdc;color:#24633f}.src.assumed{background:#f9e3d8;color:#963f26}.src.derived{background:#e4e7f2;color:#3b4a75}.table-hint .src{margin:0 2px}.provenance{margin-top:16px;border-top:1px solid var(--line);padding-top:12px}.provenance summary{cursor:pointer;font-size:12px;font-weight:800;color:var(--green);letter-spacing:.02em}.provenance table{margin-top:12px}.provenance td:first-child{font-weight:700;white-space:nowrap}.provenance td:nth-child(2){white-space:nowrap}.provenance th{position:static}

/* [hidden] loses to .setup's own display rule, so the panel never went away. */
.setup[hidden]{display:none}

.rates-table{font-size:13px}.rates-table th{position:static;white-space:nowrap;vertical-align:bottom}.rates-table thead small{display:block;font-weight:600;text-transform:none;letter-spacing:0;color:var(--muted)}.rates-table tbody th{text-align:left;font-weight:800;white-space:nowrap}.rates-table tbody th small{display:block;font-weight:600;color:var(--muted)}.rates-table input{width:100%;min-width:72px;padding:8px 9px;border:1px solid var(--line);border-radius:7px;background:white;color:var(--ink);font-weight:700}.rates-table input.changed,.rates-grid input.changed{border-color:var(--orange);background:#fff8f4}.conn-range{display:block;margin-top:4px;color:var(--muted);font-size:11px;cursor:help}.ref-minutes{font-weight:800;white-space:nowrap}.rates-grid label small{display:block;font-weight:600;text-transform:none;letter-spacing:0;color:var(--muted)}
.stage-block{margin-top:6px}.stage-split{display:grid;gap:7px;margin-bottom:6px}.stage-row{display:grid;grid-template-columns:110px 1fr 86px;align-items:center;gap:10px;font-size:12px}.stage-name{color:var(--muted);font-weight:700}.stage-bar{background:#eef0ea;border-radius:5px;height:14px;overflow:hidden}.stage-bar i{display:block;height:100%;border-radius:5px}.stage-handling{background:var(--green)}.stage-lifting{background:var(--orange)}.stage-grouting{background:#7a9a53}.stage-survey{background:#8d99a8}.stage-allowance{background:#c9cdbb}.stage-value{text-align:right;font-weight:800}.stage-value small{display:block;color:var(--muted);font-weight:600}

.bar.crane-bound{background:repeating-linear-gradient(45deg,#8d99a8,#8d99a8 5px,#7c8794 5px,#7c8794 10px);opacity:1}#curve-note{margin:26px 0 0}

/* ------------------------------------------------------------- on a phone ---
   This is a tool people open on site, so it has to survive a 390 px screen.
   Four things break there, and the layout grid is not one of them.

   1. A form control below 16px makes iOS Safari zoom the whole page the moment
      it is focused, and it does not zoom back out. The toolbar alone has eight
      number inputs. The controls are enlarged rather than the zoom suppressed:
      a `user-scalable=no` viewport would take pinch-zoom away from everyone to
      fix a problem caused by one CSS declaration.
   2. The header is a fixed 98px flex row holding a 35px serif title beside the
      privacy pill. Below about 700px they collide, and the pill is the part
      that must not be lost — it is the page's claim that the file stays here.
   3. The three result tables are the output. Nine columns cannot be read on a
      phone, and a sideways scroller hides whichever column the reader wants.
      They become one card per row, each cell printing its own column name from
      `data-label` — which is why every row template goes through `cell()`.
      `thead` is dropped in that mode, so the label has to be on the cell.
   4. #toast is 460px wide and pinned 25px from the right edge, which puts it
      off-screen on a narrow phone at the exact moment it carries the error
      message explaining why nothing happened.

   Reference tables — the provenance and rate tables — deliberately keep their
   sideways scroll: they are read, not scanned, and stacking a six-column rate
   editor would make it longer than the screen without making it clearer. */
@media (max-width: 700px) {
  header { height: auto; flex-wrap: wrap; gap: 10px; padding: 16px 4vw }
  h1 { font-size: 27px }
  .privacy { font-size: 12px; padding: 7px 11px }
  main { padding: 18px 4vw 48px }
  .panel { padding: 17px }
  .setup { gap: 18px }
  .panel-head { flex-wrap: wrap; gap: 8px }
  /* 16px is the threshold below which iOS zooms the page on focus. */
  input, select, textarea { font-size: 16px }
  .toolbar { padding: 14px 16px }
  .toolbar label { flex: 1 1 145px }
  .chart { overflow-x: auto }
  #type-bars { grid-template-columns: 1fr 1fr }
  #toast { left: 16px; right: 16px; bottom: 16px; max-width: none }
  .stage-row { grid-template-columns: 88px 1fr 62px; gap: 8px; font-size: 11px }
}

@media (max-width: 700px) {
  /* Row-per-card. The wrapper stops scrolling and stops clipping, because the
     cards are what is being scrolled now — the page, not a box inside it. */
  .level-table-wrap, .programme-table-wrap { max-height: none; overflow: visible }
  .stack-table thead { display: none }
  .stack-table, .stack-table tbody, .stack-table tr, .stack-table td { display: block; width: auto }
  .stack-table tr { margin-bottom: 10px; border: 1px solid var(--line); border-radius: 10px; background: #fbfaf6 }
  /* The label is positioned rather than laid out beside the value. A cell here
     holds arbitrary content — a number, a <small> beneath it, a badge — and in
     a grid or flex row each of those becomes its own item, so the second child
     of every cell would wrap under the label. Absolute positioning leaves the
     cell's own content untouched however many children it has. */
  .stack-table td {
    position: relative; padding: 9px 12px 9px 45%; min-height: 40px;
    text-align: right; border: 0; border-bottom: 1px solid var(--line)
  }
  .stack-table tr td:last-child { border-bottom: 0 }
  .stack-table td::before {
    content: attr(data-label); position: absolute; left: 12px; top: 10px;
    width: 40%; text-align: left;
    font: 800 11px/1.4 Inter, Segoe UI, sans-serif; letter-spacing: .05em;
    text-transform: uppercase; color: var(--muted)
  }
  .stack-table td small { display: block; white-space: normal }
  /* The whole card carries the state, since there is no first cell to mark. */
  .level-table td { vertical-align: baseline }
  .stack-table tr.current, .level-summary-row.selected {
    border-color: var(--green); box-shadow: inset 3px 0 var(--green)
  }
  .stack-table tr.current td, .level-summary-row.selected td,
  .level-summary-row:hover td { background: transparent }
  .level-summary-row.selected td:first-child { box-shadow: none }
}

/* A grid item's default `min-width: auto` refuses to shrink below its content's
   minimum, so one wide table or long word inside a stacked panel pushes the
   whole page wider than the phone and every row gets a sideways scroll it did
   not ask for. Grid children are told they may shrink; the scrollers inside
   them are what handles the wide content. */
.two-col > *, .setup > *, .metric-grid > *, .programme-metrics > *,
.grid-form > *, .rates-grid > *, .stage-row > * { min-width: 0 }
.table-wrap, .chart { max-width: 100% }

/* Two toolbar controls carry a unit under their name — "days / level", "% per
   doubling". <small> is inline, so without this the unit joins the label as one
   run of text: "CURE / PROP HOLDdays / level". */
.toolbar label small { display: block; font-weight: 600; text-transform: none; letter-spacing: 0; color: var(--muted) }
@media (max-width: 700px) { .toolbar select { padding-left: 9px; padding-right: 6px } }

.manpower-block{margin-top:20px;padding-top:16px;border-top:1px solid var(--line)}
.manpower-block .callout{margin-top:12px;font-weight:600}
#manpower-table td:nth-child(2){font-weight:800}
#manpower-table tr.subtotal td{background:#eef0ea;font-weight:800}
#manpower-table tr.not-modelled td{color:var(--muted)}

.work-panel .phase-strip{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin:14px 0 20px}
.phase-card{padding:14px;border:1px solid var(--line);border-radius:10px;background:#fbfaf6}
.phase-card.on-hook{border-color:var(--orange);background:#fff5ef}
.phase-card b{display:block;font:700 14px/1.3 Georgia,serif;margin-bottom:5px}
.phase-card small{display:block;color:var(--muted);font-size:11px}
.phase-card .phase-roles{margin-top:8px;font-size:11px;font-weight:700;color:var(--green)}
.task-block{margin-top:18px;padding-top:14px;border-top:1px solid var(--line)}
.task-block h4{margin:0 0 4px;font:700 15px/1.3 Georgia,serif}
.task-block .task-meta{margin:0 0 10px;font-size:12px;color:var(--muted)}
.task-list{margin:0;padding:0;list-style:none}
.task-list li{display:grid;grid-template-columns:120px 68px 1fr;gap:12px;padding:7px 0;border-bottom:1px solid var(--line);font-size:13px;align-items:baseline}
.task-list li:last-child{border-bottom:0}
.task-role{font-weight:800;font-size:11px;text-transform:uppercase;letter-spacing:.04em;color:var(--green)}
.task-role.appointed{color:#963f26}
.task-phase{font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.05em;color:var(--muted)}
#management-notes p{margin:0 0 12px;font-size:13px}
#management-notes b{display:block;color:var(--ink)}
@media (max-width:700px){.work-panel .phase-strip{grid-template-columns:1fr}.task-list li{grid-template-columns:1fr;gap:2px;padding:10px 0}}

.kind-badge{display:inline-block;padding:2px 7px;border-radius:4px;font:800 10px/1.5 Inter,Segoe UI,sans-serif;letter-spacing:.06em;text-transform:uppercase}
.kind-law{background:#e4e7f2;color:#3b4a75}
.kind-published{background:#dcebdc;color:#24633f}
.kind-derived{background:#eef0ea;color:var(--muted)}
.kind-assumed{background:#f9e3d8;color:#963f26}
.swing-bar{display:block;height:6px;border-radius:3px;background:#eef0ea;margin-top:5px;overflow:hidden}
.swing-bar i{display:block;height:100%;background:var(--orange);border-radius:3px}
#assumption-detail .assumption-note{padding:14px 0;border-bottom:1px solid var(--line)}
#assumption-detail .assumption-note:last-child{border-bottom:0}
#assumption-detail h4{margin:0 0 6px;font:700 14px/1.3 Georgia,serif}
#assumption-detail p{margin:0 0 6px;font-size:13px;color:var(--muted)}
#assumption-detail .no-source{color:#963f26;font-weight:700}

/* The label's unit sits under its name, not welded onto the end of it. */
.grid-form label small{display:block;margin-top:2px;font-weight:600;text-transform:none;letter-spacing:0;color:var(--muted)}
.lede-plain{font-size:15px;line-height:1.6;margin-bottom:12px}
.plain-list{margin:0 0 14px;padding-left:19px;font-size:14px;line-height:1.6}
.plain-list li{margin-bottom:7px}
.or-demo{grid-column:1/-1;margin:2px 0 0;display:flex;flex-wrap:wrap;align-items:baseline;gap:10px}
.or-demo small{color:var(--muted);font-size:12px}
.glossary{display:grid;grid-template-columns:max-content 1fr;gap:9px 20px;margin-top:14px;font-size:13px}
.glossary dt{font-weight:800;color:var(--green)}
.glossary dd{margin:0;font-family:inherit;font-size:13px;color:var(--ink)}
@media(max-width:700px){.glossary{grid-template-columns:1fr;gap:2px 0}.glossary dd{margin-bottom:10px}}

.what-back{grid-column:1/-1;margin-top:18px;padding-top:16px;border-top:1px solid var(--line)}
.what-back ol{margin:0;padding-left:20px;font-size:13px;line-height:1.6;color:var(--muted)}
.what-back ol li{margin-bottom:5px}
.what-back ol b{color:var(--ink)}
/* The glossary sits at the foot of the setup panel, so it keeps .provenance s
   own rule above it and needs no override of its own. */


/* --- Choosing a dataset, and the batch view ------------------------------- */
/* The batch reuses .metric-grid, .panel, .stack-table and .callout rather than
   growing a parallel set of styles. What is genuinely new is here and only
   here: the run's progress rail, the three severities a finding can carry, and
   the provenance line under the dataset picker. */
.rate-set-note{grid-column:1/-1;margin:0 0 4px;font-size:13px;line-height:1.6;color:var(--muted)}
.rate-set-note b{color:var(--ink)}
.rate-actions{grid-column:1/-1;display:flex;flex-wrap:wrap;gap:18px;margin:0 0 6px}
.rate-actions .link-button{margin-top:0}
#source-note{grid-column:1/-1;margin:0 0 4px}
.progress-rail{height:8px;border-radius:5px;background:#e6e9e2;overflow:hidden;margin:10px 0 14px}
.progress-fill{height:100%;width:0;background:var(--green);transition:width .2s linear}
/* Severity on a callout. The default callout is already the orange "read this"
   bar, so .warn is the unchanged case and only the two ends need saying. */
.callout.ok{border-left-color:var(--green);background:#eef4ef}
.callout.bad{border-left-color:#9c3527;background:#fbeeec}
#b-findings .callout{margin-bottom:10px;font-weight:600}
#b-findings .callout b{font-weight:800}
/* The same three lift verdicts the single-model panel prints, in the table. */
.stack-table .ok{color:var(--green);font-weight:800}
.stack-table .warn{color:var(--orange);font-weight:800}
.stack-table .bad{color:#9c3527;font-weight:800}
.stack-table tr.failed td{background:#fbeeec}
.stack-table td small{display:block;font-weight:600;color:var(--muted)}


/* --- The setup panel, one column ------------------------------------------ */
/*
 * Prose above the form rather than beside it. The two-column split fitted a
 * two-field form; it now carries a grouping choice, two pickers and three
 * dataset buttons, and a form column 1.4x the width of the explanation left a
 * tall band of dead space next to it (align-items:center made that worse by
 * floating the short column in the middle of it).
 *
 * One panel does NOT mean one field per row: the form is a two-column grid
 * across the full width, so the pair that belongs together — what you are
 * giving the page, and the file itself — sits on one line.
 */
/*
 * Heading and lede side by side, bullets across beneath them. Stacking the two
 * left a readable-measure paragraph against an empty right half of the panel;
 * neither wants to run the full 1200px, so they share the band instead.
 */
/* Title on its own line, description under it, one column. Side by side, the
   heading and the lede read as two panels rather than one question and its
   answer — and the heading was squeezed into a column narrow enough to wrap
   a 48-character sentence onto two lines. Full width fits it on one.
   The lede keeps a measure: a 1,200 px line of 15 px text is not readable,
   so the column is what changed, not the line length. */
.setup-head{display:block;margin-bottom:20px}
.setup-head h2{margin-bottom:10px}
/* The lede runs the full width of the panel. It was capped at 92ch, which
   left a third of the panel empty beside it on a desktop — and the cap was
   protecting a measure that is already past the comfortable one, so it was
   buying dead space rather than readability. Put max-width back on this rule
   to restore it. */
.setup-head .lede-plain{margin-bottom:0}
.plain-list{columns:2;column-gap:44px}
.plain-list li{break-inside:avoid;margin-bottom:9px}
.setup-form{grid-template-columns:1fr 1fr;gap:18px 26px;margin-top:26px;padding-top:22px;border-top:1px solid var(--line);align-items:start}
.setup-form > .wide, .setup-form > .source-note, .setup-form > .import-message,
.setup-form > .setup-actions{grid-column:1/-1}
/* What the page read the pick as, and — only when the pick is genuinely
   ambiguous — the other reading, one click away and on the same line. */
.source-note{margin:0;display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 12px}
/* The dataset note and its three buttons ride beside the picker they describe,
   so the provenance line is read with the set it is about. */
.rate-block{align-self:end}
.setup-actions{display:flex;flex-wrap:wrap;align-items:center;gap:10px 26px;margin-top:4px}
.setup-actions .primary{align-self:auto;padding:13px 26px}
.setup-actions .or-demo{margin:0}
/* At full width the four things you get read as a strip, not a tall list. */
.what-back{margin-top:24px;padding-top:18px;border-top:1px solid var(--line)}
.what-back ol{display:grid;grid-template-columns:repeat(4,1fr);gap:6px 24px;padding-left:18px}
/*
 * `hidden` must actually hide. `.grid-form input{display:block}` outranked the
 * user-agent's [hidden] rule, so the file input behind "Load your edited copy"
 * was drawn on the page as a stray, unexplained Choose File box. Global,
 * because the next element given `hidden` inside a form would hit this too.
 */
[hidden]{display:none!important}
@media(max-width:900px){
  .plain-list{columns:1}
  .setup-form{grid-template-columns:1fr}
  .setup-form > *{grid-column:1/-1!important}
  .what-back ol{grid-template-columns:1fr 1fr}
}
@media(max-width:650px){.what-back ol{grid-template-columns:1fr}}

/* --------------------------------------------------- the controls, in tiers --
   The results controls were one flat flex row of fourteen fields. The four
   that decide the answer now sit on the page and the eight that describe the
   site and the working week sit inside one <details>. The summary is not a
   plain "more" — it names how many of the eight are away from their default,
   because a control that is folded away and silently non-default is worse than
   a crowded row. `.controls-main` keeps the old flex behaviour verbatim so the
   phone rules below and `.toolbar label[hidden]` still apply unchanged. */
.controls{display:block;padding:16px 22px}
.controls-main{display:flex;flex-wrap:wrap;gap:18px;row-gap:12px;align-items:end}
.controls-more{margin-top:14px;border-top:1px solid var(--line);padding-top:12px}
.controls-more summary{cursor:pointer;display:flex;flex-wrap:wrap;align-items:baseline;gap:10px;font-size:12px;letter-spacing:.02em;list-style:none}
.controls-more summary::-webkit-details-marker{display:none}
.controls-more summary b{color:var(--green);font-weight:800;text-transform:uppercase;letter-spacing:.06em}
.controls-more summary b::before{content:"▸ ";font-size:11px}
.controls-more[open] summary b::before{content:"▾ "}
.controls-more summary small{color:var(--muted);font-weight:600}
.controls-more summary small.changed{color:var(--orange);font-weight:800}
.controls-groups{display:grid;grid-template-columns:1fr 1fr;gap:22px;margin-top:14px}
.controls-group-head{margin:0 0 8px;font-size:11px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
.controls-row{display:grid;grid-template-columns:1fr 1fr;gap:14px;align-items:end}
.controls-head{display:flex;align-items:center;gap:14px;margin-bottom:16px}
.controls-head .status{margin-left:0;margin-right:auto}
.controls-head .button{margin-left:0;padding:9px 14px}
.controls-more summary b::before{font-size:inherit}
@media(max-width:900px){.controls-groups{grid-template-columns:1fr;gap:16px}}
@media(max-width:650px){.controls-row{grid-template-columns:1fr}.controls-head{flex-wrap:wrap}}

/* ------------------------------------------------- the method note, folded --
   Reference material below the answer, one disclosure per section. The summary
   carries a second line saying what is inside, so folding costs the reader
   nothing they could have got from the heading alone. Every one of them ships
   closed: the caveats travel with the figures they qualify, on the tabs the
   reader is already on. */
.method-fold{padding:0;margin-bottom:12px}
.method-fold summary{cursor:pointer;list-style:none;padding:18px 24px;display:block}
.method-fold summary::-webkit-details-marker{display:none}
.method-fold summary b{font:700 19px/1.3 Georgia,serif;color:var(--ink)}
.method-fold summary b::before{content:"▸ ";color:var(--green);font-size:14px}
.method-fold[open] summary b::before{content:"▾ "}
.method-fold[open] summary{border-bottom:1px solid var(--line)}
.method-fold summary small{display:block;margin-top:5px;color:var(--muted);font-size:13px;font-weight:400;padding-left:19px}
.method-body{padding:20px 24px 4px}
.method-body > .two-col{margin-top:4px}
.method-body > .two-col > .panel{box-shadow:none;background:#fbfaf6}
@media(max-width:650px){.method-fold summary{padding:16px}.method-body{padding:16px 16px 2px}}

/* The per-type method statements fold. The summary carries whose sequence it is
   and how many steps, which is what decides whether you want to open it. */
/* `.workflow-step summary` gives every summary inside the results a card with a
   border and a shadow. That is right for a step, and wrong for eleven method
   statements in a row — they read as eleven panels rather than one list. */
.task-block summary{cursor:pointer;list-style:none;display:flex;flex-wrap:wrap;align-items:baseline;gap:10px;
  padding:11px 0;border:0;border-radius:0;background:none;box-shadow:none}
.task-block summary::-webkit-details-marker{display:none}
.task-block summary h4::before{content:"▸ ";color:var(--green);font-size:12px}
.task-block[open] summary h4::before{content:"▾ "}
.task-block summary h4{margin:0}
.task-block summary small{color:var(--muted);font-size:12px}
.task-block[open] .task-meta{margin-top:2px}
.task-block{margin-top:0;padding-top:0}
.task-block+.task-block{border-top:1px solid var(--line)}
#task-blocks{margin-top:14px;border-top:1px solid var(--line)}

/* ------------------------------------------------------- the take-off funnel --
   Four counts and two class breakdowns. The costed cell is the accent one
   because it is the only figure the crew estimate rests on; the other three are
   what it does not speak for. Deliberately not red — a genuinely 30% precast
   building SHOULD cost 30%, and a page that scolded it would be wrong. */
.funnel-strip{display:grid;grid-template-columns:repeat(5,1fr);gap:12px;margin:16px 0 20px}
.funnel-cell{padding:14px;border:1px solid var(--line);border-top:4px solid var(--ink);border-radius:10px;background:#fbfaf6}
.funnel-cell.accent{background:var(--green);border-color:var(--green);color:#fff}
.funnel-cell span,.funnel-cell small{display:block;color:var(--muted);font-size:11px}
.funnel-cell.accent span,.funnel-cell.accent small{color:#d6e7df}
.funnel-cell strong{display:block;font:700 26px/1.1 Georgia,serif;margin:12px 0 4px}
.funnel-detail{gap:22px}
.funnel-detail .rates-head{margin-bottom:6px;font-weight:800;color:var(--ink);text-transform:none;font-size:13px}
.funnel-bars{display:grid;gap:6px;margin-top:10px}
.funnel-bar{display:grid;grid-template-columns:190px 1fr 44px;align-items:center;gap:10px;font-size:12px}
.funnel-bar .mono{font:600 11px Consolas,monospace;color:var(--muted);overflow:hidden;text-overflow:ellipsis}
.funnel-bar i{display:block;height:13px;border-radius:4px;background:#c9cdbb}
.funnel-bar b{text-align:right;font-weight:800}
.funnel-panel .callout{margin-top:18px;font-weight:600}
@media(max-width:1000px){.funnel-strip{grid-template-columns:1fr 1fr}}
@media(max-width:650px){.funnel-strip{grid-template-columns:1fr 1fr}.funnel-bar{grid-template-columns:120px 1fr 38px;gap:8px}}

/* ------------------------------------------- the four named losses ----------
   The total is displayed, never typed into: two editable fields for one
   quantity is how a page starts disagreeing with itself. */
.derived-field{background:#eef0ea;color:var(--muted);cursor:not-allowed}
.loss-head{display:flex;align-items:baseline;gap:10px;margin-top:18px}
.loss-total{padding:3px 9px;border-radius:12px;background:#edf2e5;color:var(--green);font-size:11px;font-weight:800}
.loss-total.changed{background:#fff1e8;color:var(--orange)}
#loss-note{margin-top:0}

/* The one funnel bucket that is a decision rather than a limitation. */
.other-trade-block{margin-top:18px;padding-top:14px;border-top:1px solid var(--line)}
.other-trade-block[hidden]{display:none}
.trade-row{display:grid;grid-template-columns:180px 90px 1fr;gap:12px;align-items:baseline;padding:8px 0;border-bottom:1px solid var(--line);font-size:13px}
.trade-row:last-child{border-bottom:0}
.trade-row b{font-weight:800}
.trade-row span{color:var(--green);font-weight:800}
.trade-row small{color:var(--muted)}
@media(max-width:650px){.trade-row{grid-template-columns:1fr}}


/* ------------------------------------------------------------- the tabs ----
   The page used to be one column eleven panels tall, read by scrolling: the
   file picker sat under four hundred words of explanation, and the method note
   sat under the answer. It is now five tabs in the order the work is done, and
   the explanation lives on the last of them.

   `.tab-hide` rather than the `hidden` attribute, because half the panels here
   toggle `hidden` for their own reasons — see the note in main.js. The two
   mechanisms have to be able to disagree without fighting.

   The bar is sticky: on a thirty-storey model the report tab is several
   screens long, and a tab bar you have to scroll back up to is a tab bar
   nobody uses twice. */
nav.tabs{flex-wrap:wrap;position:sticky;top:0;z-index:20}
.tab{border-radius:0;font-size:14px}
.tab:disabled{color:#6d7873;cursor:not-allowed}
.tab-hide{display:none!important}

/* ------------------------------------------------------ the start panel ----
   One form, one privacy claim. Nothing else. */

.form-wide{grid-column:1/-1}
/* One picker, two buttons — see wirePicker() in main.js for why it is two
   inputs underneath. The dashed edge says "put something here" without
   promising a drop target the page does not implement. */
/* TWO COLUMNS, because one left two thirds of the panel empty.
   The instruction and the buttons are what a reader acts on; the note about
   what the browser will call it is what they read while deciding. Side by side
   they fill the width and sit where each is wanted -- stacked, the note pushed
   the buttons up the page and the panel was mostly blank to the right of both.
   Placement is explicit rather than by source order, so the hidden inputs
   between them cannot claim a cell. */
.picker{border:1px dashed var(--line);border-radius:12px;padding:18px 20px;background:#fbfaf6;
  display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:0 32px;align-items:start}
.picker-head{grid-column:1/-1;grid-row:1}
.picker-head{margin:0;font-weight:800;font-size:15px;color:var(--ink);text-transform:none;letter-spacing:0}
.picker-sub{margin:6px 0 14px;color:var(--muted);font-size:13px;font-weight:400;text-transform:none;letter-spacing:0;max-width:none;grid-column:1;grid-row:2}
/* The browser calls it an upload. Said where the button is, because the
   dialog appears the moment it is pressed and the privacy note is further
   down the page than a reader gets before deciding. */
.picker-upload{border-left:3px solid var(--green);padding-left:13px;margin:0;
  grid-column:2;grid-row:2/4;max-width:none;align-self:start}
@media(max-width:1000px){
  .picker{grid-template-columns:minmax(0,1fr)}
  .picker-head,.picker-sub,.picker-actions,.picker-upload{grid-column:1;grid-row:auto}
  .picker-upload{margin-top:14px}
}
.picker-actions{display:flex;flex-wrap:wrap;align-items:center;gap:10px;grid-column:1;grid-row:3}
.picker-actions .button{cursor:pointer}
.picker-actions .button{background:transparent;color:var(--green);border:1.5px solid var(--green);padding:10px 16px}
.picker-actions .button:hover{background:var(--green);color:#fff}
.picker-picked{color:var(--muted);font-size:13px;font-weight:600;text-transform:none;letter-spacing:0}
.picker-picked.has{color:var(--green);font-weight:800}

/* The rates dataset decides every hour on this page and has a working default,
   which is exactly the test for what belongs behind a disclosure: it must be
   reachable, and it must not stand between a stranger and the file picker. */
.advanced{grid-column:1/-1;margin-top:6px;padding-top:16px;border-top:1px solid var(--line)}
.advanced > summary{cursor:pointer;font-size:13px;font-weight:800;color:var(--green);letter-spacing:.02em}
.advanced > summary small{margin-left:9px;color:var(--muted);font-weight:600;text-transform:none;letter-spacing:0}
.advanced-body{display:grid;grid-template-columns:1fr 1fr;gap:14px 26px;align-items:start;padding-top:16px}

/* The claim the whole tool rests on, said once, in front of the reader rather
   than folded into a method note nobody opens. */
.privacy-note{margin:22px 0 0;padding:14px 17px;border-left:4px solid var(--green);background:#edf2e5;border-radius:0 10px 10px 0;font-size:13px;line-height:1.6}
.setup-more{margin:14px 0 0;font-size:13px;color:var(--muted)}
.have-results{margin:0;padding:11px 14px;border-radius:10px;background:#edf2e5;color:var(--green);font-size:13px;font-weight:700}
.have-results .link-button{margin-top:0}
.setup-more .link-button{margin-top:0}

/* ------------------------------------------------------------ the charts ---
   Rows, not columns: everything charted here is named, and a thirty-storey
   model puts thirty names on one axis. The vertical `.chart` survives for the
   crew response curve alone, where the axis is a number. */
.chart-block{margin-top:20px;padding-top:16px;border-top:1px solid var(--line)}
.chart-block:first-of-type{margin-top:6px;padding-top:0;border-top:0}
.chart-block .rates-head small{margin-left:9px;color:var(--muted);font-weight:600}
/* overflow-x:auto also clips vertically, and the crew size under each bar is
   drawn at bottom:-24px — so the room for it has to be padding inside the
   scroller, not margin outside it. */
.chart-block .chart{overflow-x:auto;height:284px;padding-bottom:26px;margin-bottom:8px}
.hbars{display:grid;gap:6px}
.hbar-row{display:grid;grid-template-columns:minmax(96px,180px) 1fr 108px;align-items:center;gap:12px;font-size:12px}
.hbar-name{font-weight:700;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hbar-track{height:16px;background:#eef0ea;border-radius:5px;overflow:hidden}
.hbar-track i{display:block;height:100%;border-radius:5px}
.tone-green{background:var(--green)}
.tone-orange{background:var(--orange)}
.hbar-value{text-align:right;font-weight:800;white-space:nowrap}
.hbar-value small{display:block;color:var(--muted);font-weight:600}
.hbar-row.current .hbar-name{color:var(--green)}
.hbar-row.current .hbar-track i{background:var(--orange)}

/* ------------------------------------------------------------ the report ---
   The paragraph at the top is the part that gets pasted into an email, so it
   is set to be read rather than scanned. The points under it are the
   qualifications that have to travel with it. */
.report-lede{font:400 17px/1.65 Georgia,serif;max-width:80ch;margin:8px 0 18px}
.report-points{list-style:none;margin:0 0 16px;padding:0;display:grid;grid-template-columns:1fr 1fr;gap:10px 22px}
.report-points li{padding:12px 15px;background:#fbfaf6;border:1px solid var(--line);border-left:3px solid var(--green);border-radius:0 10px 10px 0}
.report-points b{display:block;margin-bottom:3px}
.report-points span{display:block;color:var(--muted);font-size:13px;line-height:1.55}

@media(max-width:900px){
  .report-points{grid-template-columns:1fr}
  .advanced-body{grid-template-columns:1fr}
}
@media(max-width:700px){
  nav.tabs{flex-wrap:nowrap;overflow-x:auto;gap:2px}
  .tab{white-space:nowrap;padding:12px 13px;font-size:13px}
  .hbar-row{grid-template-columns:minmax(68px,104px) 1fr 78px;gap:8px;font-size:11px}
  .report-lede{font-size:16px}
}


/* ---------------------------------------------------------------- on paper --
   The report tab is a deliverable, and a deliverable gets printed. What comes
   out is whichever tab is open — .tab-hide is display:none, so the browser
   never sees the others — which is the behaviour you want and needs only the
   chrome taken off it.

   Tables keep their scroller on screen because the alternative is a page that
   scrolls sideways; on paper there is no scroller, so the cap has to come off
   or a thirty-storey table prints its first eight rows and stops. */
@media print {
  nav.tabs, #toast, .toolbar .button, .panel-head button, .setup-more,
  .rate-actions, #reset-rates, .have-results { display: none !important }
  body { background: #fff; color: #000; font-size: 11pt }
  header { background: #fff; color: #000; border-bottom: 2px solid #000; height: auto }
  header .eyebrow { color: #000 }
  .privacy { border-color: #000 }
  main { max-width: none; padding: 0 }
  .panel, .metric-grid article, .programme-metrics div { box-shadow: none; break-inside: avoid }
  .table-wrap, .level-table-wrap, .programme-table-wrap { max-height: none; overflow: visible }
  tr, .hbar-row, .report-points li { break-inside: avoid }
  thead { display: table-header-group }
  details { break-inside: avoid }
  /* A fold prints what it was left showing, so an unopened method note prints
     as its summary — which is the honest thing for it to do. */
}

/* ------------------------------------------------------- the arithmetic ----
   Each box carries the sum that produced it, with this model's numbers in it.
   These were `title` tooltips, which need a mouse, need the reader to suspect
   there is something under there, and print as nothing — a poor way to carry
   the one thing a reader of an estimate is entitled to ask for.

   Monospace and small, so it reads as working rather than as another claim,
   and pre-line because several of them are two or three steps. It sits under
   a border so the box still reads value-first: the number, its caption, then
   how it was made. */
.formula{display:block;margin-top:10px;padding-top:8px;border-top:1px dotted var(--line);white-space:pre-line;font:600 10.5px/1.55 Consolas,Menlo,monospace;color:var(--muted);overflow-wrap:anywhere}
.accent .formula{border-top-color:#ffffff33;color:#cfe3da}
.formula:empty{display:none}
.programme-metrics div,.metric-grid article{min-height:0}

/* The chain, folded under the boxes it produced. */
.derivation{margin:0 0 20px;padding:14px 18px;border:1px solid var(--line);border-radius:12px;background:#fbfaf6}
.derivation>summary{cursor:pointer;font-size:13px;color:var(--green);letter-spacing:.02em}
.derivation>summary b{font-size:14px}
.derivation>summary small{margin-left:9px;color:var(--muted);font-weight:600}
.derivation[open]>summary{margin-bottom:12px}
.derivation code{font:600 11.5px/1.6 Consolas,Menlo,monospace;color:var(--ink);overflow-wrap:anywhere}
.derivation td:first-child{white-space:nowrap}
.derivation .callout{margin-top:12px}
@media(max-width:700px){.formula{font-size:10px}.derivation{padding:12px 14px}}

/* ------------------------------------------------ trades and weeks (tab 5) ---
   The stacked weekly curve, and the two tables under it.

   Drawn in divs rather than in SVG or on a canvas, for the same reason every
   other chart on this page is: the CSP forbids external scripts, the shapes are
   rectangles, and a div stack is the one chart form that stays legible when the
   browser reflows it onto a phone. One column is one week — or one band of
   weeks on a long programme, which the note under the chart states rather than
   leaving to be inferred from a squashed axis.

   The column is a flex column in REVERSE, so the segments stack from the bottom
   up in the order the trades are declared. Reading order and paint order then
   agree, which is what lets the legend be a plain list. */
.stack-scroll{overflow-x:auto}
.stack-inner{min-width:100%}
.stack-chart{display:flex;align-items:flex-end;gap:2px;height:260px;padding:14px 0 0;border-bottom:1px solid var(--line)}
.stack-col{flex:1 1 0;min-width:5px;height:100%;display:flex;align-items:flex-end;cursor:pointer}
.stack-col:hover{background:#eef0ea}
.stack-col-inner{width:100%;display:flex;flex-direction:column-reverse;border-radius:3px 3px 0 0;overflow:hidden;min-height:1px}
.stack-col-inner i{display:block;width:100%;min-height:1px}
.stack-axis{display:flex;justify-content:space-between;margin-top:6px;color:var(--muted);font-size:11px;font-weight:800}
.stack-legend{display:flex;flex-wrap:wrap;gap:8px 16px;margin-top:16px;font-size:12px;color:var(--muted)}
.stack-key{display:inline-flex;align-items:center;gap:6px;white-space:nowrap}
.stack-key i{width:11px;height:11px;border-radius:3px;flex:0 0 auto}

/* The share column is an editable number in the middle of a reference table, so
   it is sized to the digits it holds rather than to the column, and it carries
   the same .changed treatment every other edited figure on this page does. */
.trade-table td small{display:block;color:var(--muted);font-weight:600;max-width:46ch}
.trade-table input.trade-share{width:88px;padding:7px 8px;border:1px solid var(--line);border-radius:7px;background:white;color:var(--ink);font-weight:800;text-align:right}
.trade-table input.trade-share.changed{border-color:var(--orange);background:#fff8f4}
.trade-table th,.trade-table td{vertical-align:top}

/* Eighteen columns of weekly headcount. A dot rather than a zero: a table of
   zeroes reads as noise, and the eye has to be able to find the weeks a trade
   is actually on site. */
#t-week-table th{white-space:nowrap;font-size:10px}
#t-week-table td{padding:7px 6px;text-align:right}
#t-week-table td:first-child,#t-week-table th:first-child{text-align:left}
#t-week-table tbody tr:hover td{background:#f5f7ef}

#t-warning{margin:14px 0}
#trades .controls-head{width:100%}
@media(max-width:700px){.stack-chart{height:190px}.stack-legend{font-size:11px}}

/* ------------------------------------------------- one left edge, always ---
   The header, the tabs and the panels all start at the same x, at every width.
   They did not: the two dark bars were padded 4vw from the viewport while
   `main` was a centred column, so on a wide screen the title sat far left of
   the content it names, and the distance between them changed as the window
   did. `max()` gives the bars the column's own left edge once the viewport is
   wider than the column, and the plain gutter below that.

   `scrollbar-gutter` is the other half of the same complaint. Switching to a
   short tab used to remove the scrollbar and move every centred thing on the
   page sideways by its width; the space is reserved now whether a tab needs it
   or not, so nothing moves when the content changes. */
:root{--page:1480px;--gutter:4vw}
html{scrollbar-gutter:stable}
header,nav.tabs{padding-left:max(var(--gutter),calc((100% - var(--page))/2 + var(--gutter)));
  padding-right:max(var(--gutter),calc((100% - var(--page))/2 + var(--gutter)))}
main{max-width:var(--page);padding-left:var(--gutter);padding-right:var(--gutter)}

/* ---------------------------------------------------- the answer, first ----
   One number, at the size of the answer to the question in the heading, with
   the sentence that qualifies it beside it. The boxes under it are evidence
   for this figure; before it existed they WERE the figure, eight of them, and
   the reader had to know which one to read. */
.answer{display:flex;gap:26px;align-items:center;margin:14px 0 20px;padding:18px 24px;
  background:#f1f5ec;border:1px solid var(--line);border-left:5px solid var(--green);border-radius:12px}
.answer-figure{min-width:132px;text-align:center}
.answer-figure strong{display:block;font:700 54px/1 Georgia,serif;color:var(--green)}
.answer-figure small{display:block;margin-top:2px;font-size:11px;font-weight:800;letter-spacing:.09em;
  text-transform:uppercase;color:var(--muted)}
.answer-text p{margin:0}
.answer-text #p-lede{font:400 17px/1.55 Georgia,serif}
.answer-text #answer-sub{margin-top:7px;font-size:13px;color:var(--muted)}
/* The per-box arithmetic is the derivation table said eight times over. It is
   in the disclosure below the boxes, once, with the steps in order. */
.programme-metrics .formula{display:none}
@media(max-width:700px){.answer{flex-direction:column;align-items:start;gap:12px}
  .answer-figure{text-align:left;min-width:0}.answer-figure strong{font-size:44px}}

/* ------------------------------------------------- a panel that is folded ---
   Same panel, closed until asked for. A tab whose answer is one chart should
   not open with four tables under it: the share editor, the week table, the
   crew matrix and the how-it-works all exist for a reader who has a question
   about the chart, and none of them for the reader looking at it. The summary
   keeps the kicker and the title, so the tab still reads as a list of what is
   there — it just is not all open at once. */
.fold-panel{padding:0}
.fold-panel > summary{list-style:none;cursor:pointer;padding:18px 24px;display:flex;flex-wrap:wrap;
  align-items:baseline;gap:4px 12px;border-radius:14px}
.fold-panel > summary::-webkit-details-marker{display:none}
.fold-panel > summary::before{content:'▸';color:var(--green);font-size:13px;margin-right:2px}
.fold-panel[open] > summary::before{content:'▾'}
.fold-panel > summary b{font:700 20px/1.25 Georgia,serif}
.fold-panel > summary .fold-kicker{flex-basis:100%;font-size:11px;letter-spacing:.16em;font-weight:800;
  color:var(--green);margin-left:16px}
.fold-panel > summary small{color:var(--muted);font-size:13px}
.fold-panel > summary:hover b{text-decoration:underline}
.fold-panel > *:not(summary){margin-left:24px;margin-right:24px}
.fold-panel > *:last-child{margin-bottom:22px}
.fold-actions{display:flex;justify-content:flex-end}

/* ------------------------------------------- what the submission says it is ---
   IfcProject.LongName, read beside the model. A claim and not a verdict: a
   sentence written by a person can say anything, so the declared figure and the
   parsed one sit side by side and the reader does the arithmetic. */
.title-block:empty{display:none}
.title-block{margin-top:14px;padding-top:12px;border-top:1px solid var(--line)}
.title-line{font:400 15px/1.5 Georgia,serif;margin:0 0 6px}
.title-meta{display:flex;flex-wrap:wrap;gap:6px 10px;font-size:12px;color:var(--muted)}
.title-meta b{color:var(--ink)}
.claim{display:inline-flex;align-items:baseline;gap:6px;padding:3px 10px;border-radius:12px;background:#eef0ea;font-size:12px}
.claim.agrees{background:#dcebdc;color:#24633f}
.claim.differs{background:#f9e3d8;color:#963f26}
.claim b{font-weight:800}

/* The line under the claim is the counted one. It is set apart from the claim
   pills above it because it is a different kind of fact: those are read out of
   a sentence a person wrote, this is counted from the file. */
.title-measured{margin:8px 0 0;font-size:12px;color:var(--muted)}
.title-measured b{color:var(--ink)}

/* The second answer, named on the way in. The precast crew is what this page
   computes; the whole site is what most people arrive wanting, and it was one
   unlabelled tab away with nothing in front of it saying so. */
.lede-second{margin-top:10px;font-size:14px;color:var(--muted)}
.lede-second b{color:var(--ink)}
/* The manpower tab's exports are switched off when it has no output, and have
   to look it: a button that looks live and does nothing reads as broken. */
.button:disabled{opacity:.45;cursor:not-allowed;filter:grayscale(1)}
/* No output, no empty chart frame standing where a curve would be. */
.stack-scroll.is-empty{display:none}
.src.measured{background:#dcebdc;color:#24633f}
.records-block{margin-top:10px;padding-top:10px;border-top:1px solid var(--line)}
.records-block ul{margin:6px 0 0 18px;padding:0}

/* The trades tab leads with five figures, not six. */
@media(min-width:1001px){.metric-grid.trade-metrics{grid-template-columns:repeat(5,1fr)}}

/* Which project the page is describing, read from the open IFC. */
.header-project{margin:3px 0 0;max-width:70vw;color:#bfc7c2;font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* A sentence with a box in it, not a toolbar field: the toolbar's uppercase,
   stacked label and full-width input are undone here. */
.toolbar .inline-field{display:inline;flex:none;min-width:0;font-size:13px;font-weight:400;text-transform:none;letter-spacing:0;color:var(--muted)}
.toolbar .inline-field input{display:inline-block;width:7em;margin:0 6px;padding:5px 8px;border:1px solid var(--line);border-radius:6px;background:white;color:var(--ink)}
#t-sizing .rate-actions{display:flex;flex-wrap:wrap;align-items:center;gap:8px}
/* Unit conversions only: a note, not a warning, and folded until asked for. */
#model-warnings.quiet{border-left-color:var(--line);background:transparent;padding:4px 15px;font-weight:400;color:var(--muted);font-size:13px}#model-warnings summary{cursor:pointer;font-weight:600}#model-warnings details ul{font-weight:400}
