:root {
	--paper: #17171a; --ink: #e6e6e2; --mid: #8a8a86; --faint: #33333a;
	--field: #0f0f12;
	--red: #ff4a3d; --green: #57c26a; --warn: #e0a53a;
	--font-body: Barlow, "DIN 2014", "Segoe UI", Arial, sans-serif;
	--font-code: ui-monospace, Consolas, monospace;
	--page-width: 680px;
}
* { box-sizing: border-box; }
/* Class rules that set display outrank the UA stylesheet's [hidden] rule, so
   `<div class="row" hidden>` stayed visible. Anything using both needs this. */
[hidden] { display: none !important; }
body {
	margin: 0 auto; max-width: var(--page-width); padding: 0 16px 48px;
	background: var(--paper); color: var(--ink);
	font: 15px/1.55 var(--font-body);
	counter-reset: sec;
}
h1 {
	font-size: 1.3rem; font-weight: 700; text-transform: uppercase;
	letter-spacing: .14em; margin: 56px 0 2px;
}
h1::before {
	content: ""; display: inline-block; width: .72em; height: .72em;
	vertical-align: baseline; background: var(--red); margin-right: .55em;
	transition: background .4s ease;
}
/* Tracks section 03: the square goes green when something has actually been
   transferred, not merely when a device answered. */
body.complete h1::before { background: var(--green); }
.sub { color: var(--mid); font-size: .85rem; margin-bottom: 20px; }
/* The description and the credits are one block, so the description does not
   carry .sub's trailing margin into the gap between them. */
.lede { margin-bottom: 0; }
/* Sits between the description and the credits, so it reads as where to go
   rather than as another thing this is built on. Full ink, unlike .sub's grey,
   because it is the only thing on the page asking for something back. */
.discuss { margin: 10px 0 20px; }
.discuss a { color: var(--ink); }
/* One project per line, so no single credit reads as the footnote of another. */
.credits span { display: block; padding-left: 1.1em; }
.divider { border-top: 3px solid var(--ink); margin-bottom: 40px; }
.row { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin-bottom: 12px; }
/* Fixed columns so each write button sits under the read it mirrors; a flex row
   would let the second row slide left as soon as it held fewer buttons. */
.transfer-grid {
	display: grid; grid-template-columns: repeat(4, max-content);
	gap: 10px; margin-bottom: 12px;
}
@media (max-width: 34rem) { .transfer-grid { grid-template-columns: repeat(2, 1fr); } }

button {
	background: transparent; color: var(--ink); border: 1px solid var(--ink);
	border-radius: 0; padding: 8px 18px; min-width: 110px; cursor: pointer;
	font: inherit; font-size: .76rem; font-weight: 600;
	text-transform: uppercase; letter-spacing: .1em;
}
button:hover:not(:disabled) { background: var(--ink); color: var(--paper); }
button:disabled { opacity: .3; cursor: default; }
button.primary { background: var(--ink); color: var(--paper); }
button.primary:hover:not(:disabled) { background: var(--red); border-color: var(--red); }
#btn-cancel { border-color: var(--red); color: var(--red); }
#btn-cancel:hover:not(:disabled) { background: var(--red); color: var(--paper); }

/* The three transfers are peers, so none of them is "primary" — emphasis there
   would be arbitrary. What is worth marking is the one that WRITES to the
   cartridge, which is the only irreversible thing on the page. */
button.writes { border-color: var(--warn); color: var(--warn); }
button.writes:hover:not(:disabled) { background: var(--warn); color: var(--paper); }

label {
	color: var(--mid); text-transform: uppercase; font-size: .7rem;
	letter-spacing: .1em; font-weight: 600; min-width: 5.5rem;
}

fieldset { border: none; border-top: 1px solid var(--ink); margin: 0 0 30px; padding: 16px 0 0; }
legend {
	counter-increment: sec;
	font-weight: 600; text-transform: uppercase; letter-spacing: .16em;
	font-size: .72rem; padding: 0 12px 0 0;
}
legend::before {
	content: counter(sec, decimal-leading-zero);
	color: var(--red); margin-right: .8em; font-variant-numeric: tabular-nums;
}
/* Step states, after the reference loader: a locked step collapses to its
   header so the flow reads as a sequence rather than a wall of controls. */
fieldset.locked { border-top-color: var(--faint); margin-bottom: 18px; }
fieldset.locked legend, fieldset.locked legend::before { color: var(--mid); }
fieldset.locked > :not(legend) { display: none; }
fieldset.done legend::before { color: var(--green); }
fieldset.done legend::after {
	content: "\2713"; color: var(--green); font-weight: 700; margin-left: .6em;
}

.tag { margin-left: 1.4em; font-weight: 400; letter-spacing: .08em; }
.tag::before { content: "["; }
.tag::after  { content: "]"; }
.tag:empty::before, .tag:empty::after { content: none; }
.tag.on   { color: var(--green); }
.tag.off  { color: var(--mid); }
.tag.busy { color: var(--warn); }
.tag.bad  { color: var(--red); }

/* Boxed readouts, after the reference page's version fields. */
.curver {
	display: inline-block; color: var(--mid); border: 1px solid var(--faint);
	padding: .28rem .5rem; font-variant-numeric: tabular-nums; min-width: 14rem;
}
.curver.known { color: var(--ink); }

/* Two label/value pairs per line, so eleven fields read as six rows instead of
   eleven. dt/dd alternate in source order, so the grid fills them pairwise with
   no extra markup. Collapses to a single pair on narrow screens. */
.rows {
	display: grid;
	grid-template-columns: max-content 1fr max-content 1fr;
	column-gap: 1.25rem; row-gap: 0; margin: 0;
}
@media (max-width: 34rem) {
	.rows { grid-template-columns: max-content 1fr; }
}
.rows dt {
	color: var(--mid); text-transform: uppercase; font-size: .7rem;
	letter-spacing: .1em; font-weight: 600; padding: .3rem 0;
	border-bottom: 1px solid var(--faint);
}
.rows dd {
	margin: 0; padding: .3rem 0; font-variant-numeric: tabular-nums;
	border-bottom: 1px solid var(--faint);
}
/* Marks something this tool can write to. Same amber as the buttons that do the
   writing, so "you can change this" reads consistently wherever it appears. */
.wr {
	margin-left: .6em; color: var(--warn); cursor: help;
	font-size: .68rem; font-weight: 600; letter-spacing: .1em;
	border: 1px solid var(--warn); padding: 0 .35em;
}

/* Spans the value across both column pairs: 4 columns total, label takes one. */
.rows dd.wide { grid-column: span 3; }
@media (max-width: 34rem) { .rows dd.wide { grid-column: span 1; } }
.rows dd.bad { color: var(--red); }
.rows dd.good { color: var(--green); }

progress {
	appearance: none; -webkit-appearance: none;
	height: 12px; width: 16rem; border: 1px solid var(--ink);
	background: var(--field); padding: 2px;
}
progress::-webkit-progress-bar { background: var(--field); }
progress::-webkit-progress-value { background: var(--ink); }
progress::-moz-progress-bar { background: var(--ink); }

a { color: var(--ink); text-decoration: underline; text-decoration-color: var(--ink); }
a:hover { color: var(--red); text-decoration-color: var(--red); }
/* A title tooltip nobody can see is not documentation, so a link carrying one
   gets the help cursor. No second underline: with the rule above already drawn
   in ink, a dotted border under it just reads as a rendering fault. */
a[title] { cursor: help; }

.note { color: var(--mid); font-size: .8rem; margin-top: 8px; max-width: 34rem; }
.subnote { color: var(--mid); font-size: .78rem; }
.mono { font-family: var(--font-code); }

#logBox { margin-top: 8px; }
#logBox > summary, #tips > summary, #options > summary {
	cursor: pointer; color: var(--mid); font-size: .72rem; font-weight: 600;
	text-transform: uppercase; letter-spacing: .1em; padding: 4px 0;
	list-style-position: inside;
}
#logBox > summary:hover, #tips > summary:hover, #options > summary:hover { color: var(--ink); }
#log {
	background: var(--field); border: 1px solid var(--ink);
	padding: 12px 14px; height: 14rem; overflow-y: auto; white-space: pre-wrap;
	font-family: var(--font-code); font-size: .78rem; margin-top: 6px;
	scrollbar-width: thin; scrollbar-color: var(--faint) transparent;
}
.log-line { padding: .1rem 0; color: var(--mid); }
.log-line.ok   { color: var(--green); }
.log-line.warn { color: var(--warn); }
.log-line.err  { color: var(--red); }

/* Blocking status dialog, from the reference loader. Used for FPGA SRAM
   loading: it is the one operation where the console is mid-reconfiguration
   and clicking anything else would be a mistake, so the page says so. */
#modal, #confirm {
	position: fixed; inset: 0; z-index: 100; display: flex;
	align-items: center; justify-content: center; background: rgba(0, 0, 0, .6);
}
/* The confirm box warns, so its marker is the warning colour rather than the
   working-in-progress red of the status dialog. */
#confirm .modal-title::before { background: var(--warn); }
.modal-body { margin-top: 12px; font-size: .85rem; line-height: 1.6; max-width: 30rem; }
.modal-body dl { display: grid; grid-template-columns: max-content 1fr; gap: .2rem .9rem; margin: .6rem 0 0; }
.modal-body dt { color: var(--mid); text-transform: uppercase; font-size: .68rem; letter-spacing: .1em; font-weight: 600; }
.modal-body dd { margin: 0; font-family: var(--font-code); font-size: .78rem; }
.modal-actions { display: flex; gap: 10px; margin-top: 20px; justify-content: flex-end; }
.modal-box {
	background: var(--paper); border: 2px solid var(--ink);
	padding: 22px 26px; min-width: 20rem; max-width: 90vw;
}
.modal-title { font-weight: 700; text-transform: uppercase; letter-spacing: .12em; font-size: .85rem; }
.modal-title::before {
	content: ""; display: inline-block; width: .5em; height: .5em;
	background: var(--red); margin-right: .5em;
}
.modal-step {
	color: var(--mid); font-family: var(--font-code); font-size: .82rem;
	margin-top: 10px; min-height: 1.2em;
}
.modal-bar { margin-top: 16px; height: 4px; background: var(--faint); overflow: hidden; }
#modalFill { height: 100%; width: 0; background: var(--ink); }
#modalFill.indet { width: 40%; animation: modalslide 1.1s ease-in-out infinite; }
@keyframes modalslide { 0% { margin-left: -40%; } 100% { margin-left: 100%; } }

/* Nominative use: naming the hardware a tool works with is legitimate, and
   saying plainly that it is unofficial is the part that actually matters. */
.trademarks {
	margin-top: 36px; padding-top: 14px; border-top: 1px solid var(--faint);
	font-size: .72rem; line-height: 1.6; max-width: 44rem;
}

/* Options. The checkbox label is sentence case, not the uppercase tracking used
   for field labels: it is a sentence the user reads, not a column heading. */
.option { padding: 8px 0 4px 1.1em; }
.option label {
	color: var(--ink); text-transform: none; letter-spacing: normal;
	font-size: .85rem; font-weight: 400; min-width: 0; cursor: pointer;
	display: inline-flex; align-items: center; gap: .55em;
}
.option input[type="checkbox"] {
	appearance: none; -webkit-appearance: none; margin: 0;
	width: 1em; height: 1em; border: 1px solid var(--ink);
	background: var(--field); cursor: pointer; flex: none;
	display: inline-flex; align-items: center; justify-content: center;
	font: inherit; line-height: 1;
}
/* A cross rather than a filled block: a filled square reads as "greyed out" at
   this size, which is the opposite of what a ticked option means.

   Drawn as a background image, not ::after. <input> is a replaced element and
   Chrome does not reliably render pseudo-elements on one, which is why the
   first attempt showed an empty box. The stroke has to be a literal colour
   because a data: URI cannot see currentColor; it is --ink. */
.option input[type="checkbox"]:checked {
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Cpath d='M2.4 2.4 L7.6 7.6 M7.6 2.4 L2.4 7.6' stroke='%23e6e6e2' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E");
	background-size: 100%; background-repeat: no-repeat; background-position: center;
}
.option .subnote { padding-left: 1.5em; margin-top: .25em; font-family: var(--font-code); }

/* Slightly above the legal text in weight, because it is the one line down
   there anyone is meant to act on. */
.support { color: var(--ink); font-size: .8rem; margin: 0 0 14px; max-width: 42rem; }

/* The one warning above the fold. Amber, like every other "this writes" marker
   on the page, so the safety language and the buttons speak with one voice. */
.hazard {
	color: var(--warn); font-size: .8rem; line-height: 1.5;
	margin: 0; padding-left: .8em;
	border-left: 2px solid var(--warn); max-width: 44rem;
}
/* Spans the grid so it sits between the row that reads and the row that writes,
   which is the only place it is read at the moment it applies. */
.transfer-grid .hazard { grid-column: 1 / -1; margin: 6px 0 2px; }

.trademarks h2 { margin: 22px 0 10px; }
.trademarks p { margin: 0 0 10px; max-width: 46rem; }
.trademarks strong { color: var(--ink); font-weight: 600; }


/* Shown only when the loaded page is behind what is published. GitHub Pages
   sends max-age=600 on everything and honours no header override, so a stale
   copy is possible for ten minutes after a deploy and nothing can force a
   revalidate. Saying so is the whole remedy. */
.stale {
	border: 1px solid var(--warn); color: var(--warn);
	padding: .5rem .7rem; margin: 0 0 .8rem; border-radius: 3px;
	font-size: .8rem;
}

.stale { display: flex; align-items: center; gap: .7rem; }
/* Prose, not a line beside a button, so it stacks. The ID beats .stale's
   display:flex; [hidden] beats both. */
#boot-error { display: block; line-height: 1.55; }
#boot-error code { background: var(--faint); padding: 0 .25em; border-radius: 2px; }
#btn-force-reload { border-color: var(--warn); color: var(--warn); flex: none; }
#btn-force-reload:hover:not(:disabled) { background: var(--warn); color: var(--paper); }

/* Ordered: the steps are meant to be worked through in sequence. */
.checklist { margin: .5em 0 .8em; padding-left: 1.4em; }
.checklist li { margin: .25em 0; }
