/* The pages borrow from the drawings they process: sheets with a thick frame and thin inner lines,
   a title block of labelled cells, drafting lettering for headings, and red reserved for corrections.

   Routed Gothic draws the digit 1 as a plain stroke, like the lettering sets it copies, so it reads
   as a capital I. Anything that can hold a drawing number or a figure is set in the text face. */

@font-face {
  font-family: "Routed Gothic";
  src: url("fonts/routed-gothic.woff2") format("woff2");
  font-display: swap;
}
@font-face {
  font-family: "Sofia Sans";
  font-weight: 1 1000;
  src: url("fonts/sofia-sans-latin.woff2") format("woff2");
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Sofia Sans";
  font-weight: 1 1000;
  src: url("fonts/sofia-sans-latin-ext.woff2") format("woff2");
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
    U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Sofia Sans";
  font-weight: 1 1000;
  src: url("fonts/sofia-sans-cyrillic.woff2") format("woff2");
  font-display: swap;
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

:root {
  --film: #edf0ee;
  --sheet: #fbfcfb;
  --ink: #181b3d;
  --graphite: #595e7a;
  --blueline: #2c3187;
  --blueline-thin: #b5b9d6;
  --blueline-wash: #e6e8f3;
  --redline: #c9252d;
  --redline-wash: #fbeceb;
  --highlighter: #ffe873;
  --highlighter-wash: #fff4b8;

  --lettering: "Routed Gothic", "Sofia Sans", "Segoe UI", sans-serif;
  --text: "Sofia Sans", "Segoe UI", system-ui, sans-serif;
  --mono: ui-monospace, "Cascadia Mono", Consolas, "DejaVu Sans Mono", monospace;

  --frame: 2px solid var(--blueline);
  --rule: 1px solid var(--blueline);
  --page: 1180px;
  --pad: 24px;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font: 17px/1.5 var(--text);
  color: var(--ink);
  background: var(--film);
}

a { color: var(--blueline); text-underline-offset: 3px; }
a:hover { color: var(--ink); }
:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

h1, h2 { font-family: var(--lettering); font-weight: 400; font-synthesis: none; overflow-wrap: anywhere; }
h1 { font-size: clamp(1.75rem, 3.2vw, 2.25rem); line-height: 1.15; margin: 32px 0 12px; }
h2 { font-size: 1.5rem; line-height: 1.2; margin: 0 0 16px; }
h3 { font-size: 1rem; font-weight: 700; margin: 0 0 8px; }

/* Page frame */

.topbar, main { max-width: var(--page); margin: 0 auto; padding-inline: var(--pad); }
.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px 24px;
  padding-block: 18px;
}
.topbar nav { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 22px; }
.topbar form { margin: 0; }
.brand {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  font: 1.35rem/1 var(--lettering);
  color: var(--ink);
  text-decoration: none;
}
.brand svg { width: 46px; height: 24px; fill: none; stroke: var(--blueline); stroke-width: 1.6; stroke-linejoin: round; }
.brand svg .centre { stroke-width: 0.7; stroke-dasharray: 7 2 1.5 2; }
main { padding-bottom: 96px; }
.lead { max-width: 62ch; margin: 0 0 24px; }

.sheet { background: var(--sheet); border: var(--frame); padding: var(--pad); margin: 24px 0; }
.sheet > :last-child { margin-bottom: 0; }

.hint { color: var(--graphite); font-size: 0.9rem; margin: 6px 0 0; }

/* Controls */

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 42px;
  padding: 0 20px;
  border: var(--frame);
  border-radius: 3px;
  background: var(--blueline);
  color: #fff;
  font: 600 1rem/1 var(--text);
  text-decoration: none;
  cursor: pointer;
}
.button:hover { background: var(--ink); border-color: var(--ink); color: #fff; }
.button.secondary { background: none; color: var(--blueline); }
.button.secondary:hover { background: var(--blueline); border-color: var(--blueline); color: #fff; }
.button:disabled { border-color: var(--blueline-thin); background: var(--blueline-thin); cursor: default; }
button.link {
  border: 0;
  padding: 0;
  background: none;
  color: var(--blueline);
  font: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}
button.link:hover { color: var(--ink); }

.form { max-width: 620px; }
.field { margin-bottom: 20px; }
label { display: block; font-weight: 600; margin-bottom: 6px; }
input[type="text"], input[type="password"], input[type="number"], select, textarea {
  width: 100%;
  min-height: 44px;
  padding: 9px 12px;
  border: var(--rule);
  border-radius: 2px;
  background: #fff;
  color: var(--ink);
  font: inherit;
}
textarea { display: block; resize: vertical; }
input[type="file"] {
  width: 100%;
  padding: 22px 18px;
  /* Dashed like a hidden edge: the drawing is not on the sheet yet */
  border: 2px dashed var(--blueline);
  border-radius: 2px;
  background: var(--film);
  color: var(--ink);
  font: inherit;
  cursor: pointer;
}
input[type="file"]::file-selector-button {
  margin-right: 14px;
  min-height: 38px;
  padding: 0 16px;
  border: var(--frame);
  border-radius: 3px;
  background: var(--sheet);
  color: var(--blueline);
  font: 600 0.95rem/1 var(--text);
  cursor: pointer;
}
/* The file that will be uploaded, chosen or pasted from the clipboard */
.chosen { margin: 10px 0 0; }
.chosen img { display: block; max-width: 100%; max-height: 260px; border: var(--rule); background: #fff; }
/* A file name holds figures, so it is set in the text font, not in the lettering of the other captions */
.chosen figcaption { margin-top: 6px; font: 0.9rem var(--text); font-variant-numeric: tabular-nums; text-align: left; overflow-wrap: anywhere; }
.errorlist { color: var(--redline); font-weight: 600; list-style: none; padding: 0; margin: 6px 0 12px; }
.form > .hint { margin-bottom: 14px; }
/* The buttons that end a form, the main one first */
.form .actions { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 24px; }
.script-form { max-width: 860px; }
textarea.code { font: 0.85rem/1.5 var(--mono); tab-size: 4; white-space: pre; overflow: auto; }

/* The two ways to start a model: tabs standing on the frame of the form's sheet. The tab of the
   open form has no line under it, so it reads as part of the sheet. */

.modes { position: relative; z-index: 1; display: flex; flex-wrap: wrap; gap: 0 4px; margin-bottom: -2px; }
.modes a {
  padding: 9px 18px 8px;
  border: var(--frame);
  border-color: transparent transparent var(--blueline);
  color: var(--blueline);
  font-weight: 600;
  text-decoration: none;
}
.modes a:hover { background: var(--blueline-wash); color: var(--ink); }
.modes a[aria-current] { border-color: var(--blueline) var(--blueline) var(--sheet); background: var(--sheet); color: var(--ink); }
.modes + .sheet { margin-top: 0; }

/* Messages */

.notice { max-width: 80ch; margin: 16px 0; padding: 10px 14px; background: var(--blueline-wash); }
.notice.warning { background: var(--highlighter); }
.notice.error { background: var(--redline-wash); color: var(--redline); border-left: 3px solid var(--redline); font-weight: 600; }

/* Status: outlined while it is pending, inked in once it is final */

.status {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 3px 10px 2px;
  border: 1.5px dashed var(--graphite);
  border-radius: 2px;
  color: var(--graphite);
  font: 600 0.82rem/1.3 var(--text);
  white-space: nowrap;
}
.status.running { border-style: solid; border-color: var(--blueline); color: var(--blueline); }
.status.running::before {
  content: "";
  width: 14px;
  height: 2px;
  background: currentColor;
  transform-origin: left;
  animation: draw-line 1.6s ease-in-out infinite;
}
.status.done { border-style: solid; border-color: var(--blueline); background: var(--blueline); color: #fff; }
.status.failed { border-style: solid; border-color: var(--redline); background: var(--redline); color: #fff; }
.status.waiting { border-style: solid; border-color: var(--blueline); background: var(--highlighter); color: var(--ink); }

/* What the drawing calls for, chosen from before the model is built */
.checklist .lead { margin-bottom: 20px; }
.checklist-card { margin: 0 0 14px; padding: 14px 16px; border: var(--rule); border-radius: 3px; background: #fff; }
.checklist-card:has(.switch:not(:checked)) { border-style: dashed; background: var(--sheet); }
.checklist-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; cursor: pointer; }
.checklist-label { font: 600 1.05rem/1.3 var(--text); color: var(--ink); }
.checklist-state { margin-left: auto; padding: 2px 10px; border-radius: 2px; background: var(--blueline-wash); color: var(--blueline); font: 600 0.8rem/1.4 var(--text); }
.checklist-state::before { content: attr(data-on); }
.checklist-head:has(.switch:not(:checked)) .checklist-state { background: var(--highlighter-wash); color: var(--graphite); }
.checklist-head:has(.switch:not(:checked)) .checklist-state::before { content: attr(data-off); }
.switch { appearance: none; flex: none; position: relative; width: 40px; height: 22px; margin: 0; border: 1.5px solid var(--blueline); border-radius: 11px; background: var(--blueline); cursor: pointer; transition: background 0.15s; }
.switch::after { content: ""; position: absolute; top: 2px; left: 20px; width: 15px; height: 15px; border-radius: 50%; background: #fff; transition: left 0.15s; }
.switch:not(:checked) { background: var(--blueline-thin); border-color: var(--blueline-thin); }
.switch:not(:checked)::after { left: 2px; }
.switch:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.tags { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0 0; padding: 0; list-style: none; }
.tag { display: inline-flex; align-items: baseline; gap: 6px; max-width: 100%; padding: 3px 8px; border: 1px solid var(--blueline-thin); border-radius: 2px; background: var(--sheet); font: 0.92rem/1.35 var(--text); color: var(--ink); }
.tag-text { overflow-wrap: anywhere; }
.tag-count { font-weight: 700; color: var(--blueline); }
.tag-page { font-size: 0.78rem; color: var(--graphite); }
.tag.seen { border-style: dashed; }
.seen-mark { color: var(--blueline); font-size: 0.7rem; }
.tags.notes .tag { border-color: transparent; background: var(--film); font-size: 0.85rem; }
.checklist-notes { margin-top: 8px; }
.checklist-notes summary { cursor: pointer; color: var(--blueline); font: 600 0.85rem/1.4 var(--text); }
.checklist-other { margin: 22px 0 0; padding-top: 14px; border-top: var(--rule); }
.checklist-other h3 { margin: 0; font-size: 1.05rem; }
.checklist-row { margin-top: 12px; }
.checklist-row .checklist-label { font-size: 0.95rem; color: var(--graphite); }
.checklist-legend { margin-top: 14px; }
.checklist-go { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; margin-top: 22px; padding-top: 16px; border-top: var(--rule); }
.checklist-summary { flex: 1 1 100%; margin: 0; display: flex; flex-wrap: wrap; gap: 4px 20px; font: 0.95rem/1.4 var(--text); }
.checklist-go .hint { flex: 1 1 260px; margin: 0; }

@keyframes draw-line {
  0% { transform: scaleX(0); }
  60%, 100% { transform: scaleX(1); }
}
@keyframes march {
  to { background-position-x: 12px; }
}

/* Labelled cells, as in a title block */

.cells { display: flex; flex-wrap: wrap; margin: 0; }
.cells > div { padding: 10px 20px 12px; border-left: var(--rule); }
.cells dt { color: var(--graphite); font-size: 0.8rem; }
.cells dd { margin: 0; font-weight: 600; font-variant-numeric: tabular-nums; }

/* List of drawings */

table.jobs { width: 100%; border-collapse: collapse; background: var(--sheet); border: var(--frame); }
table.jobs th, table.jobs td { text-align: left; padding: 14px 20px; }
table.jobs th { padding-block: 8px; border-bottom: var(--rule); color: var(--graphite); font-size: 0.8rem; font-weight: 400; }
table.jobs tbody tr { position: relative; }
table.jobs tbody tr + tr td { border-top: 1px solid var(--blueline-thin); }
table.jobs tbody tr:hover { background: var(--blueline-wash); }
table.jobs .name { width: 100%; overflow-wrap: anywhere; }
table.jobs .name a { color: var(--ink); font-weight: 600; text-decoration: none; }
/* The whole row opens the drawing */
table.jobs .name a::after { content: ""; position: absolute; inset: 0; }
table.jobs .when { color: var(--graphite); font-variant-numeric: tabular-nums; white-space: nowrap; }
.empty p { margin: 0 0 16px; }

/* Sign-in */

.signin { display: grid; grid-template-columns: minmax(0, 3fr) minmax(300px, 2fr); padding: 0; margin-top: 32px; }
.signin-drawing { padding: 32px var(--pad) var(--pad); border-right: var(--rule); }
.signin-drawing p { max-width: 36ch; margin: 24px 0 0; font-size: 1.15rem; }
.signin-form { align-self: end; padding: var(--pad); }
.signin-form h1 { margin-top: 0; }

.drafting { display: block; width: 100%; height: auto; }
.drafting path, .drafting circle, .drafting ellipse { fill: none; stroke: var(--blueline); }
.drafting .edge > * { stroke-width: 2; stroke-linejoin: round; }
.drafting .hidden { stroke-width: 1; stroke-dasharray: 5 3; }
.drafting .centre { stroke-width: 0.8; stroke-dasharray: 12 3 2 3; }
.drafting .dimension path { stroke-width: 0.8; marker-start: url(#arrow); marker-end: url(#arrow); }
.drafting .dimension .extension { marker: none; }
.drafting .dimension .outside, .drafting .dimension .leader { marker-start: none; }
.drafting marker path { fill: var(--blueline); stroke: none; }
.drafting text { font: 500 16px var(--text); fill: var(--blueline); text-anchor: middle; }
.drafting .solid > * { fill: var(--sheet); }
.drafting .solid .front { fill: var(--blueline-wash); }
.drafting .solid .side { fill: var(--blueline-thin); }
.drafting .solid .bore { fill: var(--blueline); }

/* Job page: title block */

.titleblock { display: grid; grid-template-columns: minmax(0, 1fr) auto; padding: 0; }
.titleblock h1 { align-self: center; margin: 0; padding: 18px var(--pad); font-family: var(--text); font-weight: 700; }
.titleblock .cells { flex-wrap: nowrap; }
.titleblock .cells > div { display: flex; flex-direction: column; justify-content: center; }
.titleblock-notes { grid-column: 1 / -1; margin: 0; padding: 10px var(--pad) 12px; border-top: var(--rule); }
.titleblock-notes span { display: block; color: var(--graphite); font-size: 0.8rem; }

/* Job page: progress */

.stages { display: grid; grid-template-columns: repeat(4, 1fr); list-style: none; margin: 0 0 20px; padding: 0; }
.stages li { position: relative; padding: 26px 16px 0 0; color: var(--graphite); font-size: 0.95rem; line-height: 1.3; }
/* Each stage draws the line to the next one: dashed while ahead, moving while in work, solid when passed */
.stages li::before {
  content: "";
  position: absolute;
  top: 7px;
  left: 8px;
  right: -8px;
  height: 2px;
  background: linear-gradient(90deg, var(--blueline-thin) 50%, transparent 0) 0 0 / 12px 2px repeat-x;
}
.stages li:last-child::before { content: none; }
.stages li::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 16px;
  height: 16px;
  border: 2px solid var(--blueline-thin);
  border-radius: 50%;
  background: var(--sheet);
}
.stages li:has(~ [aria-current]) { color: var(--ink); }
.stages li:has(~ [aria-current])::before { background: var(--blueline); }
.stages li:has(~ [aria-current])::after { border-color: var(--blueline); background: var(--blueline); }
.stages [aria-current] { color: var(--ink); font-weight: 700; }
.stages [aria-current]::before {
  background-image: linear-gradient(90deg, var(--blueline) 50%, transparent 0);
  animation: march 0.9s linear infinite;
}
.stages [aria-current]::after { border-color: var(--blueline); box-shadow: inset 0 0 0 3px var(--sheet), inset 0 0 0 8px var(--blueline); }
/* The way of a job from the drawing to the hand-off, in the title block. Nothing is in work
   here, so the step in hand does not move; when every step is done there is none in hand. */
.steps { grid-column: 1 / -1; grid-template-columns: repeat(5, 1fr); margin: 0; padding: 14px var(--pad) 12px; border-top: var(--rule); }
.steps li.done { color: var(--ink); }
.steps li.done::before { background: var(--blueline); }
.steps li.done::after { border-color: var(--blueline); background: var(--blueline); }
.steps [aria-current]::before { animation: none; background: linear-gradient(90deg, var(--blueline-thin) 50%, transparent 0) 0 0 / 12px 2px repeat-x; }
.steps small { display: block; color: var(--graphite); font-size: 0.82rem; font-weight: 400; overflow-wrap: anywhere; }
.steps a { color: inherit; }

/* Overview: the figures of the service, and where each model stands */

.figures h2 { margin: 28px 0 10px; }
.figures h2:first-child { margin-top: 0; }
.figures .cells { border: var(--rule); border-left: 0; }
.figures .cells > div { flex: 1 1 150px; }
.figures .hint { max-width: 80ch; margin-top: 12px; }
table.standing { margin-top: 24px; }
table.standing .name { width: 46%; }

/* Hand-off of a validated model */

.handoff h2 { margin: 28px 0 10px; }
.handoff h2:first-child { margin-top: 0; }
.handoff .cells { border: var(--rule); border-left: 0; }
.handoff .cells > div { flex: auto; }
.handoff input[type="text"] { width: 100%; max-width: 420px; min-height: 40px; padding: 6px 10px; border: var(--rule); border-radius: 2px; font: inherit; }
.decided-list { display: grid; gap: 8px; max-width: 90ch; margin: 0; padding: 0; list-style: none; }
.decided-list li { padding-left: 14px; border-left: 2px solid var(--blueline-thin); overflow-wrap: anywhere; }
.decided-list strong { margin-right: 8px; }
.decided-list .about { margin-left: 8px; color: var(--graphite); font-size: 0.9rem; font-variant-numeric: tabular-nums; }

.log {
  max-height: 380px;
  overflow-y: auto;
  margin: 20px 0 0;
  padding: 10px 16px;
  list-style: none;
  background: var(--film);
  border: 1px solid var(--blueline-thin);
}
.log:empty { display: none; }
.log li { padding: 3px 0; white-space: pre-wrap; overflow-wrap: anywhere; }
.log li.agent { max-width: 80ch; padding-block: 8px; }
.log li.tool { color: var(--graphite); font: 0.78rem/1.5 var(--mono); }
.log li.stage { padding-top: 10px; color: var(--blueline); font-weight: 700; }
.log li.stage::first-letter { text-transform: uppercase; }

/* Job page: failure */

.sheet.failure { border-color: var(--redline); }
.failure h2, .failure h3 { color: var(--redline); }
pre.problem {
  max-width: 100ch;
  margin: 0 0 8px;
  padding: 10px 14px;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  background: var(--redline-wash);
  border-left: 3px solid var(--redline);
  color: var(--ink);
  font: 0.85rem/1.5 var(--mono);
}
.sheet.failure .button { margin-top: 12px; }

/* Job page: one revision */

.revision { padding: 0; }
.revision > summary {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 20px;
  padding: 12px var(--pad);
  list-style: none;
  cursor: pointer;
}
.revision > summary::-webkit-details-marker { display: none; }
.revision > summary h2 { display: flex; align-items: center; gap: 10px; margin: 0; font: 700 1.3rem/1.2 var(--text); }
.revision > summary .status { margin-right: auto; }
.revision > summary .fact { color: var(--graphite); font-size: 0.9rem; font-variant-numeric: tabular-nums; }
.revision > summary::after {
  content: "";
  width: 9px;
  height: 9px;
  margin: 0 4px 4px 8px;
  border: solid var(--blueline);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.revision[open] > summary { border-bottom: var(--rule); }
.revision[open] > summary::after { margin-bottom: -4px; transform: rotate(-135deg); }
.revision-mark { width: 30px; height: 26px; flex: none; }
.revision-mark path { fill: none; stroke: var(--blueline); stroke-width: 1.8; stroke-linejoin: round; }
.revision-mark text { font: 700 12px var(--text); fill: var(--blueline); text-anchor: middle; }

.revision-body { padding: var(--pad); }
.revision-body > * { margin-block: 0; }
.revision-body > * + * { margin-top: 24px; }

.redline { max-width: 80ch; padding-left: 14px; border-left: 2px solid var(--redline); color: var(--redline); }
.redline .change { display: inline-block; margin-left: 14px; font-variant-numeric: tabular-nums; }
.redline code { font: 0.85em var(--mono); }

.model { display: grid; gap: 24px; }
.model.with-viewer { grid-template-columns: minmax(0, 1fr) 330px; }
/* The 3D view. The stage shows a preview image until viewer.js marks the view as ready; the
   buttons and the canvas appear only then, and the preview stays if the view cannot start. */
.viewer { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
/* Groups of buttons: the views, what a click does, how the model is shown, and the frame */
.viewer-bar { display: none; flex-wrap: wrap; gap: 6px 16px; }
.viewer-bar > div, .viewer-section, .sheet-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.viewer-bar > div:last-child { margin-left: auto; }
.viewer button {
  min-height: 32px;
  padding: 0 12px;
  border: var(--rule);
  border-radius: 3px;
  background: var(--sheet);
  color: var(--blueline);
  font: 600 0.85rem/1 var(--text);
  cursor: pointer;
}
/* A button that is switched on is filled; hovering only tints, so the two are not mistaken */
.viewer button:hover { background: var(--blueline-wash); }
.viewer button[aria-pressed="true"] { background: var(--blueline); color: #fff; }
.viewer [hidden] { display: none; }
/* The section plane: its axis, its side, and where along the axis it stands */
.viewer-section { font-size: 0.85rem; }
.viewer-section input { flex: 1; min-width: 120px; max-width: 320px; accent-color: var(--blueline); }
.viewer-section output { min-width: 9em; font-weight: 600; font-variant-numeric: tabular-nums; }
/* One pane for the model; with the drawing switched on, a second one beside it */
.viewer-panes { display: grid; grid-template-columns: minmax(0, 1fr); gap: 8px; min-height: 0; }
.viewer[data-drawing="on"] .viewer-panes { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.viewer-stage, .sheet-stage { position: relative; height: 540px; background: #fff; border: 1px solid var(--blueline-thin); }
.viewer-stage canvas { display: none; position: absolute; inset: 0; width: 100%; height: 100%; cursor: grab; }
.viewer-stage canvas:active { cursor: grabbing; }
.viewer-stage canvas[data-tool="measure"] { cursor: crosshair; }
.viewer-poster { display: block; width: 100%; height: 100%; object-fit: contain; }
/* The drawing: a page on a layer that is moved and scaled as a whole. Its buttons lie over it. */
.sheet-view { display: none; position: relative; min-width: 0; }
.viewer[data-drawing="on"] .sheet-view { display: block; }
.sheet-bar { position: absolute; z-index: 1; top: 8px; left: 8px; right: 8px; pointer-events: none; }
.sheet-bar button { pointer-events: auto; }
.sheet-stage { overflow: hidden; cursor: grab; touch-action: pan-y; }
.sheet-stage:active { cursor: grabbing; }
.sheet-layer { position: absolute; top: 0; left: 0; transform-origin: 0 0; }
.sheet-layer img { display: block; width: 100%; height: 100%; user-select: none; -webkit-user-drag: none; }
/* Boxes over the dimensions the model was built from. A box whose place was estimated is dashed;
   the one that is selected is gone over with the highlighter. */
.sheet-marks { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.sheet-marks rect { fill: transparent; stroke: var(--blueline); stroke-width: var(--mark-line, 1.5px); cursor: pointer; }
.sheet-marks rect.estimate { stroke-dasharray: calc(4 * var(--mark-line, 1.5px)) calc(3 * var(--mark-line, 1.5px)); }
.sheet-marks rect:hover { fill: rgb(44 49 135 / 0.12); }
/* A printed number that no value names: dotted, in the colour of a doubt, and not to be clicked */
.sheet-marks rect.unnamed { stroke: var(--redline); stroke-dasharray: var(--mark-line, 1.5px) calc(2 * var(--mark-line, 1.5px)); cursor: default; pointer-events: none; }
.sheet-marks rect.selected { fill: rgb(255 232 115 / 0.45); stroke: var(--redline); stroke-width: calc(1.6 * var(--mark-line, 1.5px)); }
/* The dimension or feature that is selected, named under the views */
.viewer-selected { margin: 0; padding: 6px 10px; background: var(--highlighter-wash); border-left: 3px solid var(--highlighter); }
.viewer-selected span { display: inline-block; margin-right: 18px; font-variant-numeric: tabular-nums; }
.viewer-selected small { color: var(--graphite); }
/* What the tool in use has to say: the face that was picked, a distance */
.viewer-readout { display: none; min-height: 3em; margin: 0; font-variant-numeric: tabular-nums; }
.viewer-readout span { display: block; }
.viewer-readout[data-kind="finding"] span:first-child { font-weight: 600; }
.viewer-readout[data-kind="prompt"] { color: var(--graphite); }
.viewer-help, .viewer-failed { display: none; margin: 0; }
.viewer[data-state="ready"] .viewer-bar { display: flex; }
.viewer[data-state="ready"] canvas, .viewer[data-state="ready"] .viewer-help, .viewer[data-state="ready"] .viewer-readout { display: block; }
.viewer[data-state="ready"] .viewer-poster { display: none; }
.viewer[data-state="failed"] .viewer-failed { display: block; }
/* Without the 3D view the drawing can still be put beside the preview, and beside a draft that
   is still waited for */
.viewer:is([data-state="failed"], [data-state="waiting"]) .viewer-bar { display: flex; }
.viewer:is([data-state="failed"], [data-state="waiting"]) .viewer-bar > div:not(:has([data-toggle="drawing"])),
.viewer:is([data-state="failed"], [data-state="waiting"]) .viewer-bar button:not([data-toggle="drawing"]) { display: none; }
/* The draft of a model the agent is still writing, in the progress panel: the same view with
   fewer buttons and no tools. Until there is a first draft its stage says what is waited for. */
.viewer.draft { margin-top: 20px; }
.draft .viewer-stage, .draft .sheet-stage { height: 420px; }
.draft-waiting { display: none; position: absolute; inset: 0; place-content: center; margin: 0; padding: 24px; color: var(--graphite); text-align: center; }
.viewer[data-state="waiting"] .draft-waiting { display: grid; }
/* Its number and its size are figures, so they are set in the text face */
.draft-facts { margin: 0; font: 600 1rem var(--text); font-variant-numeric: tabular-nums; }
.draft-help { max-width: 80ch; margin: 0; }
.viewer:fullscreen { padding: 16px; background: var(--sheet); }
.viewer:fullscreen .viewer-panes { flex: 1; grid-template-rows: minmax(0, 1fr); }
.viewer:fullscreen .viewer-stage { height: auto; }
.viewer:fullscreen .sheet-stage { height: 100%; touch-action: none; }
/* With the drawing beside it the view takes the whole width, and the size and files go below.
   On a narrow screen they are below already. */
@media (min-width: 901px) {
  .model.with-viewer:has(.viewer[data-drawing="on"]) { grid-template-columns: minmax(0, 1fr); }
  .model.with-viewer:has(.viewer[data-drawing="on"]) .model-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .model.with-viewer:has(.viewer[data-drawing="on"]) .model-facts .parts { grid-column: 2; grid-row: 1 / span 2; }
}
/* Two columns: size and files, with the list of bodies beside them. One column next to the viewer. */
.model-facts {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-content: start;
  align-items: start;
  gap: 20px;
  min-width: 0;
}
.model-facts .parts { grid-column: 2; grid-row: 1 / span 2; }
.with-viewer .model-facts { grid-template-columns: minmax(0, 1fr); }
.with-viewer .model-facts .parts { grid-column: auto; grid-row: auto; }
.model-facts .cells { border: var(--rule); border-left: 0; }
.model-facts .cells > div { flex: auto; }

.parts { max-height: 296px; overflow-y: auto; border: var(--rule); }
.parts table { width: 100%; border-collapse: collapse; font-size: 0.88rem; }
.parts th, .parts td { text-align: left; padding: 5px 12px; }
.parts th { position: sticky; top: 0; background: var(--sheet); box-shadow: 0 1px var(--blueline); color: var(--graphite); font-size: 0.8rem; font-weight: 400; }
.parts tr + tr td { border-top: 1px solid var(--blueline-thin); }
.parts td:first-child { position: relative; padding: 5px 4px 5px 32px; overflow-wrap: anywhere; }
/* The colour the body has in the 3D view and in the previews; placed so that a long label wraps beside it */
.swatch { position: absolute; left: 12px; top: 0.8em; width: 0.8em; height: 0.8em; outline: 1px solid var(--graphite); }
.parts td:last-child { font-variant-numeric: tabular-nums; white-space: nowrap; }

.downloads { display: grid; gap: 8px; list-style: none; margin: 0; padding: 0; }
.downloads a {
  display: grid;
  grid-template-columns: 1fr auto 5.5em;
  align-items: baseline;
  gap: 12px;
  padding: 8px 14px;
  border: var(--rule);
  border-radius: 3px;
  color: var(--blueline);
  font-weight: 600;
  text-decoration: none;
}
.downloads a:hover { background: var(--blueline-wash); color: var(--ink); }
.downloads a.main { padding-block: 12px; border: var(--frame); background: var(--blueline); color: #fff; }
.downloads a.main:hover { background: var(--ink); border-color: var(--ink); }
.downloads .file { font-size: 0.85rem; font-weight: 400; font-variant-numeric: tabular-nums; text-align: right; }

/* Four pictures of a model built before the rear view, five since: each row is filled */
.views { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 16px; }
.views figure, .projections figure { margin: 0; }
.views a { display: block; aspect-ratio: 4 / 3; background: #fff; border: 1px solid var(--blueline-thin); }
.views img { display: block; width: 100%; height: 100%; object-fit: contain; }
figcaption { margin-top: 6px; font: 1rem var(--lettering); text-align: center; }
.projections { display: grid; gap: 20px; padding-bottom: 8px; }
.projections a { display: block; background: #fff; border: 1px solid var(--blueline-thin); }
.projections img { display: block; width: 100%; height: auto; }

.fold { border-top: var(--rule); padding-top: 4px; }
.fold > summary { padding: 10px 0; font: 1.25rem var(--lettering); cursor: pointer; }
.fold > summary::marker { color: var(--blueline); }

/* The report: plain text until report.js lays it out */

pre.report { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; font: 0.85rem/1.5 var(--mono); }
.report > * { max-width: 76ch; margin: 0 0 12px; }
.report h3 { margin: 4px 0 16px; font-size: 1.3rem; line-height: 1.25; font-weight: 700; }
.report h4 { margin: 28px 0 8px; font-size: 1.05rem; font-weight: 700; }
.report h5, .report h6 { margin: 20px 0 6px; font-size: 1rem; font-weight: 700; }
.report ul, .report ol { padding-left: 22px; }
.report li { margin-bottom: 6px; }
.report li > ul, .report li > ol { margin-top: 6px; }
.report hr { margin: 20px 0; border: 0; border-top: 1px solid var(--blueline-thin); }
.report code, .report pre { font: 0.88em var(--mono); background: var(--blueline-wash); }
.report code { padding: 1px 4px; }
.report pre { padding: 10px 14px; overflow-x: auto; }
.report .table { max-width: 100ch; overflow-x: auto; }
.report table { width: 100%; border-collapse: collapse; font-size: 0.92rem; font-variant-numeric: tabular-nums; }
.report th, .report td { text-align: left; padding: 6px 16px 6px 0; vertical-align: top; }
.report th { border-bottom: var(--rule); font-weight: 700; }
.report td { border-bottom: 1px solid var(--blueline-thin); }

/* Job page: the values the model is built from. A changed one is in the checker's red. */

.values-table { overflow-x: auto; border: var(--rule); }
.values-table table { width: 100%; border-collapse: collapse; }
.values-table th, .values-table td { text-align: left; padding: 8px 16px; vertical-align: baseline; }
.values-table thead th { border-bottom: var(--rule); color: var(--graphite); font-size: 0.8rem; font-weight: 400; }
.values-table tbody tr + tr > * { border-top: 1px solid var(--blueline-thin); }
.values-table tbody th { font-weight: 400; overflow-wrap: break-word; }
/* Without notes the table is as wide as its two columns need */
.values-table:not(:has(.notes)) { max-width: 620px; }
.values-table label { display: inline; margin: 0 8px 0 0; }
.values-table code { color: var(--graphite); font: 0.8rem var(--mono); }
.values-table .number { white-space: nowrap; font-variant-numeric: tabular-nums; }
.values-table input, .values-table output {
  display: inline-block;
  width: 8.5em;
  min-height: 36px;
  padding: 5px 10px;
  border: var(--rule);
  border-radius: 2px;
  background: #fff;
  color: var(--ink);
  font: inherit;
  font-variant-numeric: tabular-nums;
  text-align: right;
}
/* A value that cannot be changed has no field to type in */
.values-table output { border-color: transparent; background: none; }
.values-table input.changed { border-color: var(--redline); box-shadow: inset 0 0 0 1px var(--redline); color: var(--redline); font-weight: 600; }
.values-table .unit { display: inline-block; min-width: 2.5em; margin-left: 4px; color: var(--graphite); font-size: 0.9rem; }
.values-table .notes { color: var(--graphite); font-size: 0.9rem; }
.values-table .notes span + span::before { content: " · "; }
.values-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 12px 20px; margin-top: 16px; }
.values-actions .hint { margin: 0; }
/* The value that is selected, here or on the drawing or in the model, and one still in doubt */
.values-table tr.selected > * { background: var(--highlighter-wash); }
.values-table tr.in-doubt > th { box-shadow: inset 3px 0 var(--redline); }
.values-table .notes .doubt a { color: var(--redline); font-weight: 600; }
.values-table [data-show] { margin-left: 8px; font-size: 0.85rem; }
.values-table tbody th { cursor: default; }
/* The threads and what the drawing states about the whole part: text of the script, so the text font */
.stated .values-table + .cells { margin-top: 16px; }
.stated .cells { border: var(--rule); border-left: 0; }
.stated .cells > div { flex: auto; }
.stated .cells dd { overflow-wrap: anywhere; }

/* Job page: the review. Every point in doubt is a card; one that is decided steps back. */

.issues { display: grid; gap: 12px; list-style: none; margin: 0 0 24px; padding: 0; }
.issue { padding: 14px 18px; border: var(--rule); border-left: 5px solid var(--blueline); background: #fff; }
.issue.warning { border-left-color: var(--highlighter); }
.issue.critical { border-left-color: var(--redline); }
.issue.settled { background: none; border-color: var(--blueline-thin); border-left-color: var(--blueline-thin); }
.issue.selected { background: var(--highlighter-wash); }
.issue-head { display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px 12px; }
.issue h3 { margin: 0; font: 600 1.05rem/1.3 var(--text); overflow-wrap: anywhere; }
.issue .severity { padding: 1px 8px; border: var(--rule); border-radius: 2px; font-size: 0.78rem; white-space: nowrap; }
.issue.warning .severity { background: var(--highlighter); border-color: var(--highlighter); }
.issue.critical .severity { background: var(--redline); border-color: var(--redline); color: #fff; }
.issue.settled .severity { background: none; border-color: var(--blueline-thin); color: var(--graphite); }
.issue p { max-width: 80ch; margin: 8px 0 0; overflow-wrap: anywhere; }
.issue .about { color: var(--graphite); font-size: 0.9rem; font-variant-numeric: tabular-nums; }
.issue .about span + span::before { content: " · "; }
/* Points of one kind under one head, a line each: thirty of them must not bury the others */
.members { display: grid; gap: 4px; list-style: none; margin: 12px 0 0; padding: 0; }
.issue.compact { display: flex; align-items: baseline; flex-wrap: wrap; gap: 2px 18px; padding: 5px 12px; border-left-width: 3px; }
.issue.compact .member { flex: 1 1 320px; margin: 0; font-variant-numeric: tabular-nums; }
.issue.compact .member span + span { margin-left: 10px; color: var(--graphite); font-size: 0.9rem; }
.issue.compact .decided { margin-top: 0; font-size: 0.92rem; }
.decide-one[open] { flex-basis: 100%; }
.decide-one > summary { color: var(--blueline); font-size: 0.9rem; font-weight: 600; cursor: pointer; }
.issue.compact .decisions { margin-top: 8px; }
.decisions { display: flex; align-items: flex-start; flex-wrap: wrap; gap: 10px 12px; margin-top: 14px; }
/* A button that names a dimension can be long: it wraps instead of pushing the card wide */
.decisions .button { min-height: 36px; height: auto; padding: 6px 14px; font-size: 0.92rem; line-height: 1.3; white-space: normal; text-align: left; }
.issue .hint { margin-top: 10px; }
.send-back { flex: 1 1 280px; }
.send-back > summary { display: inline-block; padding: 7px 0; color: var(--blueline); font-weight: 600; cursor: pointer; }
.send-back form { display: grid; gap: 8px; max-width: 520px; margin-top: 6px; }
.send-back label { font-size: 0.9rem; }
.send-back textarea { width: 100%; padding: 8px 10px; border: var(--rule); border-radius: 2px; color: var(--redline); font: inherit; }
.send-back .button { justify-self: start; }
.decided { display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px 16px; margin-top: 12px; }
.decided .by { margin-left: 8px; color: var(--graphite); font-size: 0.88rem; }
.validation { padding-top: 20px; border-top: var(--rule); }
.validation .hint { max-width: 70ch; }
/* Whether anyone has checked the model the files hold */
.validated-mark { margin: 0 0 8px; padding: 6px 12px; border: 1px dashed var(--redline); color: var(--redline); font-size: 0.9rem; font-weight: 600; }
.validated-mark.validated { border: var(--rule); color: var(--blueline); }
.validation .validated-mark { display: inline-block; margin-right: 16px; }

/* Job page: asking for a correction, in the checker's red */

.correction textarea { color: var(--redline); }
.correction textarea::placeholder { color: var(--graphite); }

/* Narrow screens */

@media (max-width: 900px) {
  .model.with-viewer { grid-template-columns: minmax(0, 1fr); }
  .with-viewer .model-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .with-viewer .model-facts .parts { grid-column: 2; grid-row: 1 / span 2; }
  .viewer-stage, .sheet-stage { height: clamp(320px, 60vh, 540px); }
  .draft .viewer-stage, .draft .sheet-stage { height: clamp(280px, 50vh, 420px); }
  /* The drawing above the model, each as wide as the page */
  .viewer[data-drawing="on"] .viewer-panes { grid-template-columns: minmax(0, 1fr); }
  .titleblock { grid-template-columns: minmax(0, 1fr); }
  .titleblock .cells { border-top: var(--rule); }
  .titleblock .cells > div { flex: auto; }
  .titleblock .cells > div:first-child { border-left: 0; }
  .signin { grid-template-columns: minmax(0, 1fr); }
  .signin-drawing { order: 1; border-right: 0; border-top: var(--rule); }
}

@media (max-width: 640px) {
  :root { --pad: 16px; }
  body { font-size: 16px; }
  .brand { font-size: 1.15rem; }
  .views { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .titleblock .cells { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; }
  .titleblock .cells > div { padding-inline: 12px; }
  .titleblock .cells > div:first-child { padding-left: var(--pad); }
  .model .model-facts { grid-template-columns: minmax(0, 1fr); }
  .model .model-facts .parts { grid-column: auto; grid-row: auto; }
  .revision > summary .status { margin-right: 0; }
  .viewer-bar > div:last-child { margin-left: 0; }
  .revision > summary::after { margin-left: auto; }

  .stages { grid-template-columns: 1fr; gap: 0; }
  .stages li { padding: 0 0 14px 28px; }
  .stages li::before { top: 16px; bottom: 0; left: 7px; right: auto; width: 2px; height: auto; background-size: 2px 12px; background-repeat: repeat-y; background-image: linear-gradient(var(--blueline-thin) 50%, transparent 0); }
  .stages [aria-current]::before { background-image: linear-gradient(var(--blueline) 50%, transparent 0); animation: none; }
  .stages li::after { top: 2px; }
  .steps [aria-current]::before { background: linear-gradient(var(--blueline-thin) 50%, transparent 0) 0 0 / 2px 12px repeat-y; }
  .steps li:last-child { padding-bottom: 0; }

  /* The values of the model become one block per value: its name, then the field, then the notes */
  .values-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .values-table table, .values-table tbody, .values-table tr, .values-table th, .values-table td { display: block; }
  .values-table tbody tr { padding: 12px var(--pad); }
  .values-table tbody tr + tr { border-top: 1px solid var(--blueline-thin); }
  .values-table tbody th, .values-table td, .values-table tbody tr + tr > * { padding: 0; border: 0; }
  .values-table .number { margin: 6px 0; }
  .values-table input, .values-table output { width: 60%; }

  /* The list of drawings becomes one block per drawing */
  table.jobs thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  table.jobs, table.jobs tbody, table.jobs tr, table.jobs td { display: block; }
  table.jobs tbody tr { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; padding: 12px var(--pad); }
  table.jobs tbody tr + tr { border-top: 1px solid var(--blueline-thin); }
  table.jobs td, table.jobs tbody tr + tr td { padding: 0; border: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .status.running::before, .stages [aria-current]::before { animation: none; }
}
