/* Buildability validator — same design tokens and the same tab mechanism as
   planner/, deliberately self-contained: both pages are standalone, and a
   shared stylesheet between two standalone pages is a coupling that buys
   nothing and breaks one of them the first time the other is restyled. */

:root{--ink:#17201d;--muted:#65706b;--paper:#f4f1e9;--panel:#fffdfa;--line:#d9d5ca;--green:#1e604c;--lime:#b9d96b;--orange:#e87842;--red:#9c3527;--blue:#3b4a75;--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{padding:20px 4vw;display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;background:var(--ink);color:#fff}
h1,h2,p{margin-top:0}
h1{font:700 33px/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}

/* The tabs. `.tab-hide` rather than the hidden attribute — several panels here
   own their own `hidden`, and the two mechanisms must not fight. */
nav.tabs{padding:0 4vw;background:var(--ink);display:flex;gap:5px;flex-wrap:wrap;position:sticky;top:0;z-index:20}
.tab{border:0;background:transparent;color:#bfc7c2;padding:13px 18px;font-weight:700;font-size:14px;cursor:pointer;border-bottom:3px solid transparent}
.tab.active{color:#fff;border-color:var(--lime)}
.tab:disabled{color:#6d7873;cursor:not-allowed}
.tab-hide{display:none!important}
[hidden]{display:none!important}

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}
.panel h2{font:700 24px/1.25 Georgia,serif}
.panel-head{display:flex;justify-content:space-between;align-items:start;gap:12px;flex-wrap:wrap}
.setup[hidden]{display:none}
.table-hint{margin:8px 0 14px;color:var(--muted);font-size:13px}
.rates-head{margin:18px 0 10px;font-size:12px;color:var(--muted);font-weight:700}
.level-count{padding:7px 11px;border-radius:16px;background:#edf2e5;color:var(--green);font-size:12px;font-weight:800;white-space:nowrap}

button,.button{cursor:pointer}
.primary,.button{border:0;border-radius:8px;background:var(--green);color:#fff;padding:12px 18px;font-weight:800;text-align:center}
.primary:disabled{opacity:.65;cursor:wait}
.link-button{border:0;background:none;padding:0;color:var(--green);font-weight:800;font-size:13px;text-decoration:underline;cursor:pointer}

/* ------------------------------- the start tab ---------------------------- */
.setup-head{margin-bottom:20px}
.setup-head h2{margin-bottom:10px}
.lede-plain{margin-bottom:0}
.grid-form{display:grid;grid-template-columns:repeat(3,1fr);gap:18px 26px;margin-top:26px;padding-top:22px;border-top:1px solid var(--line);align-items:start}
.grid-form label{font-size:12px;font-weight:800;color:var(--muted);text-transform:uppercase;letter-spacing:.05em}
.grid-form label small{display:block;font-weight:600;text-transform:none;letter-spacing:0;color:var(--muted)}
.grid-form input,.grid-form select{display:block;width:100%;margin-top:6px;padding:11px 12px;border:1px solid var(--line);border-radius:8px;background:#fff;color:var(--ink)}
.form-wide{grid-column:1/-1}
/* One picker, two buttons — see app/ui/picker.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}
.setup-actions{display:flex;flex-wrap:wrap;align-items:center;gap:10px 26px;margin-top:4px}
.setup-actions .or-demo{margin:0}
.setup-actions .or-demo small{display:block;color:var(--muted);font-size:12px}
.import-message{grid-column:1/-1;margin:0;color:var(--green);font-weight:700}
.import-message.error{color:var(--red)}
.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)}
.plain-list{columns:2;column-gap:44px;margin:0 0 8px;padding-left:19px}
.plain-list li{break-inside:avoid;margin-bottom:9px}

/* ------------------------------- the toolbar ------------------------------ */
.toolbar{padding:16px 22px}
.controls-head{display:flex;align-items:center;gap:14px;flex-wrap:wrap}
.status{padding:10px 14px;border-radius:8px;background:#edf2e5;color:var(--green);font-weight:800}
.status.bad{background:#f9e3d8;color:#963f26}
.controls-head .button{margin-left:auto}
#scope-note{margin:12px 0 0}
.demo-note{color:#963f26;font-weight:700}

/* ------------------------------ the verdicts ------------------------------ */
.verdict-lede{font:400 17px/1.65 Georgia,serif;max-width:88ch;margin:8px 0 18px}
.metric-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:14px;margin-bottom:20px}
.metric-grid article{background:#fbfaf6;border:1px solid var(--line);border-top:4px solid var(--ink);padding:16px;border-radius:12px}
.metric-grid span,.metric-grid small{display:block;color:var(--muted);font-size:12px}
.metric-grid strong{display:block;font:700 30px/1.1 Georgia,serif;margin:12px 0 5px}
.metric-grid article.tone-ok{border-top-color:var(--green)}
.metric-grid article.tone-bad{border-top-color:var(--red)}
.metric-grid article.tone-warn{border-top-color:var(--orange)}
.metric-grid article.tone-info{border-top-color:var(--blue)}
.callout{border-left:4px solid var(--orange);background:#fff1e8;padding:12px 15px;font-weight:700}

.verdict-pill{display:inline-block;padding:3px 9px;border-radius:12px;font:800 11px/1.5 Inter,Segoe UI,sans-serif;white-space:nowrap}
.verdict-pill.ok{background:#dcebdc;color:#24633f}
.verdict-pill.bad{background:#f7dcd6;color:var(--red)}
.verdict-pill.warn{background:#f9e3d8;color:#963f26}
.verdict-pill.info{background:#e4e7f2;color:var(--blue)}

/* One finding, as a card. The report tab reads these; the checks tab reads the
   same rows as a table, because a table is for scanning and a card is for
   reading, and the two tabs are doing those two different things. */
.finding{border:1px solid var(--line);border-left:4px solid var(--muted);border-radius:0 10px 10px 0;padding:14px 16px;margin-bottom:10px;background:#fbfaf6}
.finding.tone-ok{border-left-color:var(--green)}
.finding.tone-bad{border-left-color:var(--red)}
.finding.tone-warn{border-left-color:var(--orange)}
.finding.tone-info{border-left-color:var(--blue)}
.finding-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:7px}
.finding-head b{font-size:15px}
.finding-id{color:var(--muted);font:600 11px Consolas,monospace}
.finding-body{margin:0 0 6px;font-size:14px}
.finding-evidence{margin:0 0 6px;font-size:13px;color:var(--ink)}
.finding-why{margin:0;font-size:12.5px;color:var(--muted);font-style:italic}

/* -------------------------------- the tables ------------------------------ */
.check-group{margin-bottom:26px}
.check-group .kicker{margin-bottom:2px}
.table-wrap{overflow:auto}
table{width:100%;border-collapse:collapse;font-size:13px}
th,td{text-align:left;border-bottom:1px solid var(--line);padding:10px 9px;vertical-align:top}
th{position:sticky;top:0;background:var(--panel);color:var(--muted);font-size:11px;text-transform:uppercase;white-space:nowrap}
.check-table td small{display:block;color:var(--muted);font:600 11px Consolas,monospace;margin-top:3px}
.check-table td:nth-child(5),.check-table td:nth-child(6){color:var(--muted);font-size:12.5px}
code{background:#eef0ea;border-radius:4px;padding:1px 5px;font:600 12px Consolas,monospace}

dl.glossary{display:grid;grid-template-columns:120px 1fr;gap:10px 16px;margin:0 0 14px}
dl.glossary dt{font-weight:800}
dl.glossary dd{margin:0;color:var(--muted);font-size:13px}
.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 ul{margin:12px 0 0;padding-left:19px}
.provenance li{margin-bottom:9px}

#toast{position:fixed;right:25px;bottom:25px;background:var(--ink);color:#fff;padding:14px 18px;border-radius:9px;box-shadow:var(--shadow);display:none;max-width:460px;z-index:40}
#toast.error{background:var(--red)}


/* ------------------------ the parameter schedule -------------------------- */
/* The three columns that carry the new work: where a value belongs, what reads
   it, and what was found in it. They are lists rather than prose because a
   reader scans them for one path and stops. */
.graph-controls{gap:14px;margin:14px 0 12px;font-size:12px;color:var(--muted);font-weight:700}
.graph-controls label{display:flex;align-items:center;gap:7px;text-transform:uppercase;letter-spacing:.05em}
.graph-controls select,.graph-controls input{max-width:100%;padding:7px 9px;border:1px solid var(--line);border-radius:7px;background:#fff;color:var(--ink);font-weight:700}
.graph-controls input[type=number]{width:88px}
.graph-controls .button{padding:8px 13px;font-size:12px}

.carriers{margin:0;padding:0;list-style:none}
.carriers li{margin-bottom:6px;padding-left:11px;border-left:2px solid var(--line)}
.carriers li.inferred{border-left-color:var(--orange)}
.carriers li.answered{border-left-color:var(--green)}
.carriers li small{display:block;color:var(--muted);font-size:11px;margin-top:2px}
/* Paths are long, and on a phone the tables become cards with no scroller of
   their own — so a path that cannot wrap scrolls the whole page sideways. */
.carriers code{font-size:11.5px;display:inline-block;max-width:100%;overflow-wrap:anywhere}
.param-table code,.param-table .val,.param-table small{overflow-wrap:anywhere}
.param-table td{font-size:12.5px}
.param-table td:nth-child(3),.param-table td:nth-child(5){width:22%}
.param-table td small{display:block;color:var(--muted);font:600 11px Consolas,monospace;margin-top:3px}
.param-table td small.if-absent{font:italic 11.5px/1.5 Inter,Segoe UI,sans-serif;color:#963f26;margin-top:6px}
.param-table td small.uri{font-size:10.5px;opacity:.75;margin-top:6px}
.feeds{margin-bottom:5px}
.feeds small{display:block!important;font:italic 11px/1.45 Inter,Segoe UI,sans-serif!important;color:var(--muted)}
.classes code{margin-right:4px;font-size:11px}
.vals{margin-top:6px}
.val{display:inline-flex;align-items:center;gap:5px;margin:0 5px 4px 0;padding:2px 7px;border-radius:6px;background:#eef0ea;font-size:11.5px}
.val b{color:var(--muted);font:700 10.5px Inter,sans-serif}
/* A value the Code publishes, and one it does not. The mark is on the value
   itself because that is what a reader copies into the model to fix it. */
.val.on{background:#dcebdc;color:#24633f}
.val.off{background:#f7dcd6;color:var(--red);font-weight:700}
.val.off b{color:var(--red)}
.more-values{margin-top:4px}
.more-values>summary{cursor:pointer;font-size:11px;color:var(--green);font-weight:700}
.more-values .vals{margin-top:5px}
.value-check{margin-top:8px;padding-top:7px;border-top:1px dashed var(--line);font-size:12px}
.value-check small{display:block;color:var(--muted);font:600 11px Consolas,monospace;margin-top:3px}
.value-check .muted{color:var(--muted);font-style:italic}
.callout+.callout{margin-top:10px}
.vals.derived{margin-top:6px}
.callout.ok{border-left-color:var(--green);background:#eef5ee}
.callout.info{border-left-color:var(--blue);background:#eef0f6}
.check-group .kicker .verdict-pill{margin-left:8px;text-transform:none;letter-spacing:0}

/* ------------------------- the start tab, several files -------------------- */
.file-plan{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:6px}
.plan-file{display:block;padding:8px 12px;border:1px solid var(--line);border-left:3px solid var(--green);border-radius:0 8px 8px 0;background:#fbfaf6;font-size:12.5px}
.plan-file.unknown{border-left-color:var(--orange)}
.plan-file b{display:block}
.plan-file small{color:var(--muted)}

/* -------------------------------- title block ------------------------------ */
/* What the submission says about itself, beside what the model turned out to
   hold. The only sentence in an IFC that can be checked rather than described. */
#title-block{margin:2px 0 12px}
.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}

/* Which files the model draws. A ten-file submission is nine disciplines the
   officer does not want in the way of the one they are looking at. */
.massing-files{display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px}
.massing-files button{border:1px solid var(--line);background:#fff;color:var(--muted);border-radius:14px;padding:3px 9px;font:700 11px Inter,Segoe UI,sans-serif;cursor:pointer;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.massing-files button.on{background:var(--green);border-color:var(--green);color:#fff}

/* --------------------------- the graph and the model ----------------------- */
/* Side by side on a wide screen: the graph says what is true and the boxes say
   where. Stacked below 1460px, because the graph now divides whatever width it
   is given between EIGHT columns rather than scrolling sideways, and 400px of
   model taken off the side of a 1300px panel is the difference between a
   column that holds a name and one that holds eight characters. Wide enough
   for both, both; otherwise the graph takes the width and the model sits under
   it, where it is still beside the thing it is answering. */
.graph-and-view{display:grid;grid-template-columns:minmax(0,1fr) 400px;gap:14px;align-items:start}
.massing{border:1px solid var(--line);border-radius:12px;background:#fbfaf6;padding:10px 12px 12px}
.massing-head{display:flex;align-items:baseline;gap:10px;margin-bottom:8px;font-size:13px}
.massing-tools{margin-left:auto;display:flex;gap:10px}
.massing-tools .link-button{font-size:11px;text-decoration:none;border-bottom:1px solid transparent}
.massing-tools .link-button:hover{border-bottom-color:var(--green)}
.massing-tools .isolate{border:1px solid var(--line);border-radius:12px;padding:1px 8px}
.massing-tools .isolate.on{background:var(--green);border-color:var(--green);color:#fff}
#massing-canvas{display:block;width:100%;height:420px;border-radius:8px;background:#fbfaf6;cursor:grab;touch-action:none}
#massing-canvas:active{cursor:grabbing}
.massing .table-hint{margin:8px 0 0;font-size:11.5px}
@media(max-width:1460px){
  .graph-and-view{grid-template-columns:1fr}
  #massing-canvas{height:340px}
}

/* ---------------------------- the knowledge graph ------------------------- */
/* Copied in rather than shared with the federation page on purpose: both pages
   are standalone, and one stylesheet across two standalone pages breaks one of
   them the first time the other is restyled. */
/* The elements behind a selection: the file, the GlobalId and where it is. */
.inspector-elements{font-size:12.5px}
.inspector-elements th{font-size:10.5px}
.inspector-elements td{vertical-align:top}
.inspector-elements td small{display:block;color:var(--muted);font-size:11px;margin-top:2px}
.inspector-elements .guid{font-size:11.5px;overflow-wrap:anywhere}
/* A row that will do something when clicked has to look like one, and the row
   currently lit in the model has to be findable again after the reader has
   spent a minute orbiting it. */
.inspector-elements tr.pickable{cursor:pointer}
.inspector-elements tr.pickable:hover{background:#f2f1ea}
.inspector-elements tr.pinned{background:#fdf0e8;box-shadow:inset 3px 0 0 #e87842}

/* ------------------------- the parameter list ----------------------------- */
/* Every other stacked table on this page gives its `small` a line of its own.
   This one did not, so two adjacent ones ran together as "5,979 97%175 not
   carried" -- one string, three facts, none of them legible. */
#params-table td small{display:block;color:var(--muted);font-size:11px;margin-top:2px}
#params-table .param-row{cursor:pointer}
#params-table .param-row:hover{background:#eef0ea}
#params-table .param-row.on{background:#eef0ea;box-shadow:inset 3px 0 0 var(--green)}
#params-table .param-detail>td{background:#fbfaf6;padding:14px 16px}
#params-table .param-detail .inspector-table th{width:230px;vertical-align:top}

.canvas-wrap{border:1px solid var(--line);border-radius:12px;background:#fbfaf6;overflow-x:auto;overflow-y:hidden}
.legend{display:flex;gap:12px;flex-wrap:wrap;margin-left:auto;text-transform:none;letter-spacing:0}
.legend .key{display:flex;align-items:center;gap:5px;font-weight:700}
.legend i{width:10px;height:10px;border-radius:3px;display:inline-block}
.layer-band{fill:#00000006}
/* Title Case, not SHOUTED. All caps cost the column its word shapes -- the
   thing a reader recognises a heading by without reading it -- and cost it
   width, which is what put "Buildability item" into "Property" in the first
   place. Capitalising the source's sentence case gives "Building Block" and
   "Buildability Item" without a second list of labels to keep in step. */
.layer-title{font:800 10px Inter,Segoe UI,sans-serif;fill:var(--muted);letter-spacing:.045em;text-transform:capitalize}
.trace-link{fill:none;stroke:#b9c0ae;stroke-width:1;opacity:.45}
.trace-link.on{stroke:var(--green);stroke-width:2;opacity:1}
.trace-link.fail{stroke:var(--red);opacity:.8}
.trace-link.dim{opacity:.06}
.trace-node{cursor:pointer}
.trace-node rect{stroke:#fffdfa;stroke-width:1;rx:3}
.trace-node.dim{opacity:.18}
.trace-node.on rect{stroke:var(--ink);stroke-width:2}
.trace-label{font:600 10px Inter,Segoe UI,sans-serif;pointer-events:none}
.trace-count{font:600 9px Inter,Segoe UI,sans-serif;pointer-events:none;fill:var(--muted)}
.tooltip{position:fixed;z-index:60;max-width:300px;background:var(--ink);color:#fff;padding:9px 12px;border-radius:8px;font-size:12px;line-height:1.5;pointer-events:none;box-shadow:var(--shadow)}

.path-chain{display:flex;flex-wrap:wrap;gap:6px;align-items:center;margin-top:6px;font-size:12.5px}
.path-step{display:inline-flex;align-items:center;gap:6px;padding:5px 10px;border-radius:8px;background:#fbfaf6;border:1px solid var(--line)}
.path-step i{width:9px;height:9px;border-radius:2px;display:inline-block}
.path-step b{font-weight:800}
.path-step small{color:var(--muted)}
.path-arrow{color:var(--muted);font-weight:800}
.path-step.fail{border-color:var(--red);background:#f9e6e2}
.path-step.pass{border-color:var(--green);background:#eef5ee}

.inspector{margin-top:16px;padding-top:14px;border-top:1px solid var(--line)}
.inspector-empty{margin:0;color:var(--muted);font-size:13px;font-style:italic}
.inspector-head{display:flex;align-items:center;gap:9px;margin-bottom:10px}
.inspector-head i{width:12px;height:12px;border-radius:3px;display:inline-block}
.inspector-head b{font:700 17px/1.3 Georgia,serif}
.inspector-head span{padding:3px 9px;border-radius:12px;background:#edf2e5;color:var(--green);font:800 11px Inter,sans-serif}
.inspector-table th{width:190px;text-align:left;background:transparent;text-transform:none;font-size:12px;color:var(--muted);white-space:normal;position:static}
.inspector-table td{font-size:13px}
.inspector-table td small{display:block;color:var(--muted);font-size:11.5px;font-style:italic;margin-top:2px}

.metadata{margin-top:18px;padding-top:12px;border-top:1px solid var(--line)}
.metadata>summary{cursor:pointer;font-size:13px;color:var(--green)}
.metadata>summary small{margin-left:9px;color:var(--muted);font-weight:600}
.meta-group{margin-top:12px}
.meta-group .rates-head{margin-bottom:4px}
.meta-group .rates-head small{text-transform:none;letter-spacing:0;font-weight:600}
/* The property inventory under a selected node, and one element's own list. */
.inspector-props{font-size:12.5px}
.inspector-props th{font-size:10.5px}
.inspector-props td{vertical-align:top;padding:6px 9px}
.inspector-props td small{display:block;color:var(--muted);font-size:11px;margin-top:2px}
.inspector-props code{overflow-wrap:anywhere}
.inspector-props .val{margin-bottom:3px}
.inspector-props tr.superseded td{opacity:.55}

/* A row of the element table opens that element's metadata beneath it. */
.inspector-elements .element-row{cursor:pointer}
.inspector-elements .element-row:hover{background:#f3f5ef}
.inspector-elements .element-row.is-open{background:#edf2e5}
.inspector-elements .element-row.is-open.pinned{background:#fdf0e8}
.inspector-elements .element-row small.row-action{font-style:normal;color:var(--green);font-weight:700}
.inspector-elements .element-detail>td{background:#fafbf8;border-left:3px solid var(--green);padding:4px 12px 12px}
.element-meta .rates-head{margin:12px 0 4px}
.element-meta .rates-head code{text-transform:none;letter-spacing:0}

.meta-table td{padding:6px 9px;font-size:12.5px}
.meta-table td small{display:block;color:var(--muted);font-size:11px}
.meta-table .meta-num{text-align:right;white-space:nowrap;color:var(--muted);font-weight:700}

@media(max-width:1100px){.metric-grid{grid-template-columns:repeat(3,1fr)}}
@media(max-width:900px){
  .grid-form{grid-template-columns:1fr}
  .grid-form>*{grid-column:1/-1}
  .plain-list{columns:1}
  dl.glossary{grid-template-columns:1fr}
  dl.glossary dt{margin-bottom:-6px}
}
@media(max-width:700px){
  h1{font-size:26px}
  main{padding:18px 4vw 48px}
  .panel{padding:17px}
  nav.tabs{flex-wrap:nowrap;overflow-x:auto;gap:2px}
  .tab{white-space:nowrap;padding:12px 13px;font-size:13px}
  input,select{font-size:16px}
  .metric-grid{grid-template-columns:1fr 1fr}
  .verdict-lede{font-size:16px}
  #toast{left:16px;right:16px;bottom:16px;max-width:none}
  /* Six columns cannot be read on a phone, and a sideways scroller hides
     whichever column the reader wants. One card per row instead. */
  .param-table td:nth-child(3),.param-table td:nth-child(5){width:auto}
  /* A select is as wide as its widest option unless it is told otherwise, and
     "Only what is missing or partly carried" is wider than a phone. */
  .graph-controls{flex-direction:column;align-items:stretch}
  .graph-controls label{flex-wrap:wrap;min-width:0}
  .graph-controls select,.graph-controls input[type=number]{width:100%;min-width:0}
  .legend{margin-left:0}
  .inspector-table th{width:auto}
  .check-table thead{display:none}
  .check-table,.check-table tbody,.check-table tr,.check-table td{display:block;width:auto}
  .check-table tr{margin-bottom:10px;border:1px solid var(--line);border-radius:10px;background:#fbfaf6;padding:4px 0}
  .check-table td{border:0;padding:6px 12px}
  .check-table td::before{content:attr(data-label);display:block;font:800 10px/1.6 Inter,Segoe UI,sans-serif;letter-spacing:.08em;text-transform:uppercase;color:var(--muted)}
  .table-wrap{overflow:visible}
}

@media print{
  nav.tabs,#toast,.controls-head .button,.panel-head button,.setup-more{display:none!important}
  body{background:#fff}
  header{background:#fff;color:#000;border-bottom:2px solid #000}
  header .eyebrow{color:#000}
  main{max-width:none;padding:0}
  .panel,.finding{box-shadow:none;break-inside:avoid}
  .table-wrap{overflow:visible}
  tr,.finding{break-inside:avoid}
  thead{display:table-header-group}
}

/* ------------------------------------------------- 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 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 Buildability register ---
   One row per element per required property, coloured by the verdict on THAT
   element. Three rules hold it together.

   THE COLOUR IS A LEFT EDGE, not a background. A register of twenty-seven
   thousand rows with two-thirds of them washed in orange is unreadable at any
   density, and the thing a reader needs is to find the reds by scanning down
   one column. A 3px bar does that and leaves the text on paper.

   THE BAR IS FLEX, not a percentage. Each segment is `flex:<count>`, so the
   proportions are the counts themselves and nothing has to be computed in
   JavaScript or rounded to make a hundred.

   A GUID GETS ITS OWN TREATMENT. It is twenty-two characters of base64 nobody
   reads and everybody copies, so it is monospaced, selectable and allowed to
   be the one thing on the row that does not wrap. */
.legend-stacked{margin:0 0 10px;margin-left:0}
.legend .key[title]{cursor:help}

.tone-bar{display:flex;height:7px;border-radius:4px;overflow:hidden;margin-top:6px;
  min-width:90px;background:#e9e5db}
.tone-bar i{display:block;min-width:2px}
.tone-bar i.ok{background:var(--green)}
.tone-bar i.warn{background:var(--orange)}
.tone-bar i.bad{background:var(--red)}
.tone-bar i.info{background:var(--muted)}

#items-matrix .matrix-first td{border-top:2px solid var(--line)}
#items-matrix .matrix-row{cursor:pointer}
#items-matrix .matrix-row:hover td{background:#f0ede4}
#items-matrix td small{display:block;color:var(--muted);font-size:11px;margin-top:2px}
#items-matrix code{font-size:12px}

#items-register tbody tr{border-left:3px solid transparent}
#items-register tbody tr.tone-ok{border-left-color:var(--green)}
#items-register tbody tr.tone-warn{border-left-color:var(--orange)}
#items-register tbody tr.tone-bad{border-left-color:var(--red)}
#items-register tbody tr.tone-info{border-left-color:var(--muted)}
#items-register td{vertical-align:top;font-size:13px}
#items-register td small{display:block;color:var(--muted);font-size:11px;margin-top:2px}
#items-register .guid{font:600 12px/1.4 ui-monospace,Menlo,Consolas,monospace;
  white-space:nowrap;user-select:all}
#items-register .verdict-pill{margin-bottom:2px}

#items-summary b.tone-ok{color:var(--green)}
#items-summary b.tone-warn{color:#963f26}
#items-summary b.tone-bad{color:var(--red)}

#items-find{padding:7px 10px;border:1px solid var(--line);border-radius:7px;
  font:inherit;font-size:13px;min-width:190px}

/* On a phone, one card per row — the treatment `.check-table` already gets and
   for the same reason: eight columns cannot be read at 390px, and a sideways
   scroller hides whichever one the reader wants. Every cell carries a
   `data-label`, so the header row goes and each value is labelled where it sits.

   Without this the register laid out at 933px and pushed the whole PAGE
   sideways, because `.table-wrap` drops to `overflow:visible` at this width so
   that the stacked cards are not trapped in a scroller of their own.

   The GUID is the one value allowed to break mid-string rather than widen its
   card: it is base64 with no break opportunities in it, and half a GUID on
   screen is worse than an ugly wrap. */
@media (max-width:760px){
  #items-matrix thead,#items-register thead{display:none}
  #items-matrix,#items-matrix tbody,#items-matrix tr,#items-matrix td,
  #items-register,#items-register tbody,#items-register tr,#items-register td{
    display:block;width:auto}
  #items-matrix tr,#items-register tr{margin-bottom:10px;border:1px solid var(--line);
    border-radius:10px;background:#fbfaf6;padding:4px 0}
  #items-matrix td,#items-register td{border:0;padding:6px 12px}
  #items-matrix td::before,#items-register td::before{content:attr(data-label);display:block;
    font:800 10px/1.6 Inter,Segoe UI,sans-serif;letter-spacing:.08em;text-transform:uppercase;
    color:var(--muted)}
  /* An empty cell is the matrix's own way of saying "same item as the row
     above", which stops meaning anything once the rows are cards. */
  #items-matrix td:empty{display:none}
  #items-register tbody tr{border-left-width:4px}
  #items-register .guid{white-space:normal;word-break:break-all}
  #items-find{min-width:0;width:100%}
}
