/* The head of this stylesheet comes from `stylesheet_head` in
 * `bins/coder-serve/tests/html_golden.rs`, which reads the palette and the
 * four intensities from `crates/coder-ui-core`. The same test compares this
 * file with the generator, so edit the generator and run the tests rather
 * than these lines.
 */

:root,
[data-webtui-theme="coder"] {
  --amber: #ffb000;
  --amber-75: #c18600;
  --amber-50: #835b00;
  --amber-25: #463100;
  --near-black: #080600;
  --font-size: 14px;
  --line-height: 1.3;
}

pre.grid {
  font-size: var(--font-size);
  line-height: var(--line-height);
  margin: 0;
  white-space: pre;
}

pre.grid .quarter {
  color: var(--amber-25);
}

pre.grid .half {
  color: var(--amber-50);
}

pre.grid .three {
  color: var(--amber-75);
}

pre.grid .full {
  color: var(--amber);
}

pre.grid .pressed,
pre.grid button:active {
  opacity: 0.8;
}

/* A box that scrolls says so.
 *
 * Every scroller on this screen is a bounded box inside a page that never
 * scrolls itself, so the scrollbar is the only sign that there is more below
 * the last line you can see. It draws on the amber ladder like everything
 * else: a 25% thumb on the page's own ground, 50% under the pointer, one
 * character wide. The rule is global so a box added later gets the
 * affordance without anyone remembering to ask for it. */
::-webkit-scrollbar {
  width: 1ch;
  height: 1ch;
}

::-webkit-scrollbar-track {
  background: transparent;
}

::-webkit-scrollbar-thumb {
  background: var(--amber-25);
}

::-webkit-scrollbar-thumb:hover {
  background: var(--amber-50);
}

/* The same bar for an engine that has no `::-webkit-scrollbar`. Setting
 * `scrollbar-width` or `scrollbar-color` on an element makes Chrome and
 * Safari drop the rules above for it, and what they draw instead is the
 * platform's overlay bar, which fades out and is the thing this replaces. So
 * the standard properties go to the engines that need them and nowhere
 * else. */
@supports not selector(::-webkit-scrollbar) {
  * {
    scrollbar-width: thin;
    scrollbar-color: var(--amber-25) transparent;
  }
}

/* The marks a run carries beside its intensity. The renderer writes them as
 * classes in `bins/coder-serve/src/html.rs`. */
pre.grid .b {
  font-weight: bold;
}

pre.grid .it {
  font-style: italic;
}

pre.grid .u {
  text-decoration: underline;
}

pre.grid .s {
  text-decoration: line-through;
}

/* One amber on one near-black, ported from the CLI's theme
 * (`openagents/crates/openagents-cli/src/coder/markdown/theme.rs`). Elements
 * differ by intensity, the four opacities the TUI composites over the
 * background, and by effect, never by hue. A second hue would change what
 * Coder looks like, which is the one thing this stylesheet must not do. The
 * values themselves are in the generated head above.
 */
:root,
[data-webtui-theme="coder"] {
  --background0: var(--near-black);
  --background1: var(--near-black);
  --background2: var(--near-black);
  --background3: var(--near-black);
  --foreground0: var(--amber);
  --foreground1: var(--amber-50);
  --foreground2: var(--amber-25);

  --font-family: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas,
    "DejaVu Sans Mono", monospace;
  --box-border-width: 1px;
  --box-border-color: var(--amber);

  /* The two rail widths, in character cells. Dragging a rail's inner edge
   * writes these, and the page keeps what you set. */
  --rail: 32ch;
  --side: 64ch;
}

/* Every page: the palette, and the grid the text sits on. */
html,
body {
  background: var(--near-black);
  color: var(--amber);
  /* A ligature draws two cells as one glyph and moves the text off the
     grid the interface is laid out on, so the console turns them off. */
  font-variant-ligatures: none;
  font-feature-settings: "liga" 0, "calt" 0;
  word-break: normal;
  /* The palette is the terminal's, #ffb000 on #080600, and the browser
     still drew it heavier: macOS paints web text with subpixel
     antialiasing, which thickens every stroke and reads as a brighter,
     yellower amber than the same value in a terminal. Grayscale smoothing
     draws the strokes the weight the terminal draws them. */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  min-height: 100%;
  margin: 0;
}

/* The console's frame is the viewport: that page never scrolls, and neither
 * does it bounce past its ends, so the only thing that moves is the
 * transcript inside the window. A terminal does not rubber-band. Every other
 * page is a document and scrolls the way a document does, which is what the
 * blog and the product pages need. */
html:has(#screen),
body:has(#screen) {
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;
}

/* Selection is the palette too: the browser's default blue is the one hue this
 * stylesheet is not allowed to introduce. */
::selection {
  background: var(--amber-50);
  color: var(--near-black);
}

::-moz-selection {
  background: var(--amber-50);
  color: var(--near-black);
}

/* The screen is three columns filling the window: the Coders on the left, the
 * transcript in the middle, and what the current step is working on down the
 * right. Widths are character counts, not pixel counts, because the grid is
 * the unit: 20 columns holds `Coder 102 · $12.34`, and the side pane takes up
 * to 64 columns, which is a comfortable width for code.
 *
 * The window is the frame now, so nothing scrolls except the middle and the
 * side pane. */
#screen {
  display: grid;
  grid-template-columns: var(--rail) minmax(0, 1fr) minmax(0, var(--side));
  height: 100dvh;
  max-height: 100dvh;
  width: 100vw;
  gap: 0;
  overflow: hidden;
  overscroll-behavior: none;
}

/* The middle column: the transcript takes the space left over, the composer
 * sits on it, and the status row is the last line — the CLI's three-constraint
 * vertical layout, in the same order. */
#middle {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  padding: 0 1ch;
  overflow: hidden;
}

/* The composer is narrower than the view above it, the way a prompt is
 * narrower than the scrollback it sits under. */
#composer,
#status {
  width: min(88ch, 100%);
  margin: 0 auto;
  flex: 0 0 auto;
}

/* The rail down the left of the window: the row that starts a Coder at the top,
 * the Coders under it, and a foot naming who is signed in and what the Coders
 * cost. The Coders scroll; the row that starts one and the foot do not, so both
 * stay in reach however large the fleet gets.
 *
 * The selected row joins the transcript beside it — its right border is open,
 * the way a terminal draws the window you are in. */
#rail {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  min-height: 0;
  min-width: 0;
  overflow: hidden;
  border-right: 1px solid var(--amber-25);
  white-space: pre;
  /* One step smaller than the transcript beside it, so a row holds the name
   * and the money at the narrowest width a drag can set. */
  font-size: 12px;
  /* A row reads its own width from the rail, so a narrow rail can drop a
   * field the way a narrow window drops a column. */
  container-type: inline-size;
  container-name: rail;
}

.railtop,
.railfoot {
  flex: 0 0 auto;
}

/* The foot of the rail: who is signed in and what the Coders above have cost,
 * for this session. Settings sits above the line that separates them. */
.railset {
  display: flex;
  justify-content: space-between;
  padding: 0.5lh 1ch 0;
}

.railfoot {
  display: flex;
  flex-direction: column;
  gap: 0;
  padding: 0.5lh 1ch;
  border-top: 1px solid var(--amber-25);
  color: var(--amber-50);
}

.setlink {
  color: var(--amber-50);
  text-decoration: none;
}

.setlink:hover {
  color: var(--amber);
}

.railfoot .me {
  display: flex;
  justify-content: space-between;
  gap: 1ch;
  overflow: hidden;
}

.railfoot .name {
  color: var(--amber-75);
  overflow: hidden;
  text-overflow: ellipsis;
}

.railfoot .spend {
  color: var(--amber-50);
  flex: 0 0 auto;
}

/* The edge you drag to set a rail's width. It is one cell wide and sits inside
 * the pane it resizes, so it takes no column of the grid. */
.grip {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 1ch;
  cursor: col-resize;
  touch-action: none;
  z-index: 2;
}

#rail .grip {
  right: 0;
}

#sights .grip {
  left: 0;
}

.grip:hover {
  background: var(--amber-25);
}

/* The Coders scroll inside the rail. */
#tabs {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  min-height: 0;
  overflow: hidden;
}

#fleet {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
}

.tab {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 1ch;
  min-height: 2lh;
  padding: 0 1ch;
  border: 1px solid var(--amber-25);
  border-right: none;
  border-bottom: none;
  color: var(--amber-50);
  text-decoration: none;
  overflow: hidden;
}

.tab:last-of-type,
.tab.fresh {
  border-bottom: 1px solid var(--amber-25);
}

/* The row names the Coder and the stop control sits at its right end, so a
 * long row truncates its own text rather than pushing the control out of the
 * rail. The row is a flex line so the money keeps its cells however narrow the
 * rail gets: what the Coder is doing gives up its width first, the name gives
 * up its width next, and the number a person reads the rail for is the last
 * thing to go. */
.tab .face {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: baseline;
  overflow: hidden;
  color: inherit;
  text-decoration: none;
}

.tab .name,
.tab .state,
.tab .age {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* What the Coder is doing gives up its width long before the name does, so a
 * narrow rail reads `Coder 102 · … · $12.34` rather than losing the number. */
.tab .state,
.tab .age {
  flex-shrink: 200;
}

.tab .name {
  flex-shrink: 1;
}

/* A rail too narrow for the longest row drops what the Coder is doing and
 * keeps the name and the money whole. A working Coder still turns its spinner
 * at the right edge, so the row that matters most says so without the
 * field. */
@container rail (max-width: 34ch) {
  .tab .state,
  .tab .age,
  .tab .name + .sep {
    display: none;
  }
}

.tab .sep,
.tab .cost {
  flex: 0 0 auto;
}

.tab .sep,
.tab .cost,
.tab .state {
  color: inherit;
}

/* A working Coder's spinner, at the right edge of its row, so the rail reports
 * which Coder is going without the glyph moving as the text beside it grows. */
.tab .spin {
  flex: 0 0 auto;
  padding-left: 1ch;
  color: inherit;
}

/* A working Coder is the loud tab; a finished one recedes. Intensity carries
 * the state, so the strip reads at a glance without a second hue. */
.tab.working {
  color: var(--amber-75);
}

.tab.failed .state {
  color: var(--amber);
  font-weight: bold;
}

/* The Coder you are on: full intensity, and open on the right into the
 * transcript it is showing. */
.tab.here {
  color: var(--amber);
  border-color: var(--amber);
  margin-right: -1px;
  background: var(--near-black);
}

.tab:hover {
  color: var(--amber);
}

/* The tab that hires another Coder, kept plainly different from the ones that
 * are one. */
.tab.fresh {
  color: var(--amber-50);
  border-style: dashed;
}

/* The key that does the same thing, reported where the thing is. Smaller and
 * dimmer than the row it sits on, because it is a reminder rather than a
 * control. */
.hotkey {
  flex: 0 0 auto;
  font-size: 10px;
  color: var(--amber-25);
}

.tab.fresh:hover .hotkey {
  color: var(--amber-50);
}

/* A Coder's own key, shown only while you hold the control key, because the
 * right of the row already carries the spend. */
.tab .hotkey {
  display: none;
  padding-left: 1ch;
}

body[data-holding="1"] .tab .hotkey {
  display: inline;
}

/* The control that hides a Coder from the rail. It shows on hover, so a row
 * reads the same until you reach for it, and it never steals the click meant
 * for the row itself. */
.tab .archiver {
  display: none;
  flex: 0 0 auto;
}

.tab:hover .archiver {
  display: inline;
}

.tab .archiver button {
  all: unset;
  cursor: pointer;
  font-size: 10px;
  color: var(--amber-25);
}

.tab .archiver button:hover {
  color: var(--amber);
}

/* The one thing on the page that scrolls, and it keeps its overscroll to
 * itself so reaching the end of a transcript does not move the window.
 *
 * The transcript is one step smaller than the rest of the screen, so a long run
 * fits more lines. Its own cells stay square, because every line inside it
 * inherits the size. */
#transcript {
  font-size: 13px;
  flex: 1 1 0;
  min-height: 0;
  display: flex;
  overflow: hidden;
}

/* Every Coder's transcript is in the page, so the pane you are reading is the
 * thing that scrolls. The hidden ones keep their scroll position, which is what
 * makes switching tabs feel like switching windows. */
#panes {
  display: contents;
}

.pane {
  flex: 1 1 0;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 0.5lh 2ch 0;
}

.pane[hidden] {
  display: none;
}

.log {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* Protocol detail — the door's spec, the token mint, the clone path, turn
 * markers, token counts, the receipt — is in the page from the start and
 * hidden until you ask for it, so the default screen reports what Coder did to
 * your repository. */
#transcript:not([data-detail="on"]) .detail {
  display: none;
}

/* A tool's output, folded under the line that named it. The switch reports how
 * many lines it holds and floats to the right end of that line, so it costs no
 * row of its own. Open, the output is on the same rail the CLI prints it on. */
.fold {
  display: inline;
  white-space: normal;
}

.fold > summary {
  float: right;
  color: var(--amber-25);
  cursor: pointer;
  list-style: none;
  white-space: pre;
}

.fold > summary::-webkit-details-marker {
  display: none;
}

.fold > summary::before {
  content: "▸ ";
}

.fold[open] > summary::before {
  content: "▾ ";
}

.fold > summary:hover {
  color: var(--amber);
}

/* Output you opened is supporting material, so it sits a step below the line
 * that named it and two below the prose. The side pane is where output is meant
 * to be read; this is the copy kept in place. */
.folded {
  clear: both;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  color: var(--amber-25);
}

.folded * {
  color: var(--amber-25);
}

/* Rendered prose. The model writes markdown, so a finished block is real
 * elements rather than asterisks — still in the terminal's grid, still on the
 * amber ladder, so it reads as the CLI and not as a web page. Row rhythm is
 * kept in `lh` units, and nothing here changes the type size: a heading is
 * bold, not bigger, the way a TUI marks one. */
.md {
  white-space: normal;
}

/* Coder's own prose sits one step below the lines that report what it did, so a
 * screen of explanation does not shout as loudly as the work. Emphasis, code,
 * and headings stay at full intensity, which is what makes them emphasis. */
.md.agent,
.md.agent :is(p, li, blockquote, td) {
  color: var(--amber-75);
}

.md.agent :is(h1, h2, h3, h4, h5, h6, strong, th, code) {
  color: var(--amber);
}

.md > :first-child {
  margin-top: 0;
}

.md > :last-child {
  margin-bottom: 0;
}

.md p,
.md ul,
.md ol,
.md pre,
.md table,
.md blockquote {
  margin: 0 0 1lh;
}

.md h1,
.md h2,
.md h3,
.md h4,
.md h5,
.md h6 {
  font-size: inherit;
  font-weight: bold;
  margin: 1lh 0 0;
  color: var(--amber);
}

.md ul,
.md ol {
  padding-left: 3ch;
}

.md li {
  margin: 0;
}

/* A list item that holds a nested list keeps the paragraph the parser
 * wraps its text in. That paragraph is the item's own line, so it takes
 * no row of its own. */
.md li > p {
  margin: 0;
}

/* Inline code carries the 25% amber behind it, so a filename reads as one token
 * inside a sentence. A fenced block keeps its rail instead. */
.md code {
  font: inherit;
  color: var(--amber);
  background: var(--amber-25);
  padding-left: 0;
  padding-right: 0;
}

.md pre {
  white-space: pre-wrap;
  border-left: 1px solid var(--amber-50);
  padding-left: 1ch;
}

.md pre code {
  color: var(--amber-75);
  background: none;
}

.md strong {
  color: var(--amber);
  font-weight: bold;
}

.md em {
  font-style: italic;
}

.md blockquote {
  border-left: 1px solid var(--amber-50);
  padding-left: 1ch;
  color: var(--amber-50);
}

.md table {
  border-collapse: collapse;
}

.md th,
.md td {
  border: 1px solid var(--amber-25);
  padding: 0.2lh 1ch;
  text-align: left;
  vertical-align: top;
}

.md th {
  color: var(--amber);
  font-weight: bold;
}

/* The base sheet draws its own dividers on every table cell, as pseudo
 * elements standing at the cell's edges. A table in the transcript has the
 * border above, so a cell drew two lines and one of them crossed the text.
 * The rule is unlayered, so it wins over the layered one it turns off. */
.md table :is(th, td)::before,
.md table :is(th, td)::after {
  display: none;
}

.md hr {
  border: none;
  border-top: 1px solid var(--amber-25);
  margin: 1lh 0;
}

/* The dim lane keeps its 50% intensity even where markdown asks for emphasis:
 * reasoning is supporting text, and a bold word in it must not read louder
 * than the answer it supports. */
.md.dim,
.md.dim * {
  color: var(--amber-50);
}

/* What a step cost in time, at the right end of the line that named it, beside
 * the fold reporting how much the step printed. It runs while the step runs. */
.tick {
  float: right;
  color: var(--amber-25);
  white-space: pre;
  padding-left: 1ch;
}

.md .tick {
  color: var(--amber-25);
}

/* The agent's prose and the step headings read at full intensity. */
.agent,
.tool-head {
  color: var(--amber);
}

/* A third of a line above each step and each block of prose, so a run of them
 * reads as separate lines without a blank row between them. The step keeps its
 * own line, so the fold and the clock at its right end stay beside it. */
.tool-head {
  display: inline-block;
  padding-top: 0.35lh;
}

.md {
  margin-top: 0.35lh;
}

.you {
  color: var(--amber-75);
}
/* What the person typed, rendered as markdown, with the CLI's user marker in
   the margin of its first block. */
.md.you {
  position: relative;
  padding-left: 2ch;
}
.md.you::before {
  content: ">";
  position: absolute;
  left: 0;
  top: 0;
}
.dim,
.out,
.system,
.diff {
  color: var(--amber-50);
}
.rail {
  color: var(--amber);
}
.error {
  color: var(--amber);
  font-weight: bold;
}
.done {
  color: var(--amber-50);
}

/* The side pane: what the step in flight is working on. A read shows the lines
 * it read, an edit shows the passage it replaced against the one it wrote, a
 * search shows its matches, and a command shows its output. One step at a time,
 * replaced by the next, so the pane is the work going past rather than a log.
 *
 * It is one step smaller than the transcript, because code wants columns more
 * than the prose beside it does. */
#sights {
  position: relative;
  display: flex;
  min-width: 0;
  min-height: 0;
  border-left: 1px solid var(--amber-25);
  font-size: 12px;
  overflow: hidden;
}

.sight {
  flex: 1 1 0;
  min-width: 0;
  min-height: 0;
  display: flex;
  overflow: hidden;
}

/* A pane the page is not watching is out of the layout, not merely behind the
 * one it is watching. Without this the class's own `display` outranks the
 * `hidden` attribute, and every Coder's feed stands beside the others as a
 * column of its own. */
.sight[hidden] {
  display: none;
}

/* A step adds a box at the end of this feed, and the feed is what scrolls, so
 * the pane keeps the history of what the run looked at instead of showing only
 * the latest step. */
.seen {
  flex: 1 1 0;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5lh;
  padding: 0.5lh 1ch 1lh;
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
}

/* The thing being worked on is named in the border, so the lines inside start
 * at the top of the box. The box is drawn one shade down from the transcript's,
 * because the pane is what a step is looking at rather than the record. */
/* No one box takes the pane: a long file or log stops at half the window and
 * scrolls inside its own border. */
.seenbox {
  --box-border-color: var(--amber-50);
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  max-height: 50vh;
  min-height: 0;
  overflow: hidden;
}

.seenbox .boxtitle {
  color: var(--amber-50);
}

.seenbody {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  color: var(--amber-50);
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
}

.seenline {
  display: block;
}

/* Code in the side pane is colored on the same amber ladder as everything
 * else: a keyword at full intensity, strings and numbers below it, comments
 * further down, and punctuation at the bottom. */
.tone.key {
  color: var(--amber);
}

.tone.text,
.tone.num {
  color: var(--amber-75);
}

.tone.note {
  color: var(--amber-50);
}

.tone.mark {
  color: var(--amber-25);
}

/* A diff keeps its reading: what an edit wrote is at full intensity and what it
 * replaced recedes, so the coloring inside a diff line never outranks the
 * line's own side of the change. */
.seenline.added .tone {
  color: inherit;
}

.seenline.added .tone.mark,
.seenline.added .tone.note {
  color: var(--amber-50);
}

.seenline.removed .tone {
  color: inherit;
}

/* A diff, on the amber ladder rather than in red and green: what was written is
 * at full intensity, and what it replaced recedes. */
.seenline.added {
  color: var(--amber);
}

.seenline.removed {
  color: var(--amber-25);
}

/* The welcome card: the CLI's startup box at the top of the transcript, with
 * its title in the border and its labels at half intensity. */
#welcome {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 0 1ch;
}

/* The same width as the composer under it, so both boxes share their edges. */
#welcome > div {
  width: min(88ch, 100%);
}

/* A title in the top border, the way a ratatui block draws it. */
.boxtitle {
  display: flex;
  height: 1lh;
}

#welcome .boxtitle {
  justify-content: center;
}

.boxtitle [is-~="badge"] {
  color: var(--amber);
  padding: 0 1ch;
}

#welcome .label {
  color: var(--amber-50);
}

#welcome .value {
  color: var(--amber);
}

/* The composer: a bordered box holding the `>` marker and the caret, exactly
 * where the TUI puts it. */
#composer {
  display: flex;
  flex-direction: column;
  gap: 0;
  margin-top: 1lh;
}

#composer .draft {
  display: flex;
  align-items: flex-start;
  gap: 0;
}

/* Which repo the directive is for: a row above the caret, dim like a label
 * until you touch it, so the choice is visible without competing with the
 * prompt. */
#composer .picker {
  display: flex;
  align-items: baseline;
  gap: 1ch;
  color: var(--amber-50);
}

#composer .picker select {
  background: var(--near-black);
  color: var(--amber-75);
  border: none;
  font: inherit;
  line-height: inherit;
  padding: 0;
}

#composer .picker select:focus {
  color: var(--amber);
  outline: none;
}

#composer .marker {
  color: var(--amber);
  padding-right: 1ch;
  user-select: none;
}

#composer textarea {
  flex: 1 1 auto;
  background: transparent;
  color: var(--amber);
  border: none;
  font: inherit;
  line-height: inherit;
  resize: none;
  overflow: hidden;
  padding: 0;
  caret-color: var(--amber);
  caret-shape: block;
}

#composer textarea::placeholder {
  color: var(--amber-25);
}

/* The status row: supporting context under the composer, at the same 50%
 * intensity the CLI uses, credit-and-activity left, lane right. */
#status {
  display: flex;
  justify-content: space-between;
  gap: 1ch;
  color: var(--amber-50);
  padding: 0 1ch 0.4lh;
  white-space: pre;
  overflow: hidden;
}

#status .right {
  color: var(--amber-50);
  flex: 0 0 auto;
}

/* The character field behind a gate page. It sits under the gate box, ignores
 * the pointer, and refuses selection so the copy above it stays the only text
 * a person can grab. */
#gatebg {
  position: fixed;
  inset: 0;
  margin: 0;
  overflow: hidden;
  color: var(--amber-25);
  user-select: none;
  -webkit-user-select: none;
  pointer-events: none;
  z-index: 0;
}

#gatebg .mid {
  color: var(--amber-50);
}

/* Log-in, kept in the same frame so the first screen is already Coder. */
#gate {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100dvh;
  gap: 1lh;
  position: relative;
  z-index: 1;
}

#gate [box-] {
  background: var(--near-black);
}

#gate .boxtitle {
  justify-content: center;
}

#gate .label {
  color: var(--amber-50);
}

/* The component library. Admin-only, and the one page here that is allowed to
 * scroll the document: it is a reference rather than a terminal. */
#library {
  height: 100dvh;
  overflow-y: auto;
  overscroll-behavior: contain;
  width: min(100ch, calc(100vw - 2ch));
  margin: 0 auto;
  padding: 1lh 1ch;
}

#library > div,
#library .piece {
  margin-bottom: 2lh;
}

#library .label {
  color: var(--amber-50);
}

#library h2 {
  font-size: inherit;
  font-weight: bold;
  color: var(--amber);
  margin: 0;
}

#library h2::before {
  content: "⏺ ";
}

#library .variant {
  margin-bottom: 1lh;
}

#library .example {
  border: 1px solid var(--amber-25);
  padding: 1lh 1ch;
  margin: 0.5lh 0;
}

#library .code {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  color: var(--amber-75);
  border-left: 1px solid var(--amber-50);
  padding-left: 1ch;
  margin: 0.5lh 0 0;
}

#library .swatches {
  display: flex;
  gap: 1ch;
}

#library .swatch {
  color: var(--near-black);
  padding: 0 1ch;
}

button {
  background: transparent;
  color: var(--amber);
  border: none;
  font: inherit;
  cursor: pointer;
  padding: 0;
}

button:hover {
  color: var(--amber-75);
}

a,
a:visited {
  color: var(--amber);
  text-decoration: underline;
}

/* The strip that asks for an address, and then for the code mailed to it. One
 * line at the top of the middle column, on the composer's width, and nothing at
 * all once an address is verified. */
#mailbox {
  flex: 0 0 auto;
  width: min(88ch, 100%);
  margin: 0 auto;
}
.mailrow {
  display: flex;
  align-items: baseline;
  gap: 1ch;
  padding: 0.5lh 1ch 0;
}
.mailrow input {
  flex: 0 1 32ch;
  min-width: 0;
  background: transparent;
  color: var(--amber);
  border: 1px solid var(--amber-25);
  padding: 0 1ch;
  font: inherit;
}
.mailrow button {
  background: transparent;
  border: 0;
  color: var(--amber);
  font: inherit;
  cursor: pointer;
  padding: 0;
}

/* What the page has to say when a message did not arrive or the connection went
 * away: one line under the composer, above the status row. */
#trouble {
  width: min(88ch, 100%);
  margin: 0 auto;
  flex: 0 0 auto;
  padding: 0 1ch;
  white-space: pre-wrap;
}

/* On a narrow window the side pane has nowhere to go, so the transcript takes
 * the whole of what is left. These rules come last, because they override the
 * layout above rather than set it. */
@media (max-width: 1100px) {
  #screen {
    grid-template-columns: var(--rail) minmax(0, 1fr);
  }

  #sights {
    display: none;
  }
}

/* The settings page borrows the console's frame: the rail keeps its column and
 * the preferences take the room the transcript and the side pane had. */
#screen.plain {
  grid-template-columns: var(--rail) minmax(0, 1fr);
}

#preferences {
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 1lh 2ch;
}

#preferences > [box-] {
  width: min(88ch, 100%);
}

/* Stopping the Coder you are watching. The control sits in the composer's top
 * border at the right, opposite the label, and the page shows it only while
 * that Coder works. */
#stopper {
  margin-left: auto;
  padding: 0 1ch;
  border: none;
  background: var(--near-black);
  font: inherit;
  color: var(--amber-75);
  cursor: pointer;
}

#stopper[hidden] {
  display: none;
}

#stopper:hover {
  color: var(--amber);
}

/* The previous-Coders fold. It collapses a long history so the working and
   most recent Coders stay at the top of the rail. */
#previous {
  border-top: 1px solid rgba(255, 176, 0, 0.15);
}
#previous > summary {
  list-style: none;
  cursor: pointer;
  padding: 0.5rem 0.75rem;
}
#previous > summary::-webkit-details-marker { display: none; }
#previous > summary::before { content: "▸ "; }
#previous[open] > summary::before { content: "▾ "; }
#previous > summary:hover { color: rgba(255, 176, 0, 0.8); }

#screen.gym {
  /* Plain block stacking. The base #screen is the console's 3-column grid
   * (rail | transcript | side); reset the grid template so the dashboard's
   * sections stack in one column instead of auto-placing into those tracks. */
  display: block;
  grid-template-columns: none;
  height: auto;
  max-height: none;
  min-height: 100dvh;
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
  padding: 1lh 2ch;
  max-width: 110ch;
  margin: 0 auto;
  width: 100%;
}

#screen.gym > .gym-header,
#screen.gym > .gym-section {
  width: 100%;
  margin-bottom: 1.5lh;
}

/* A wide table (the optimization ladder) scrolls horizontally inside its own
 * section rather than overflowing the page or disturbing the column. */
#screen.gym > .gym-section {
  overflow-x: auto;
  max-width: 100%;
}

.gym-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-bottom: 1px solid var(--amber-25);
  padding-bottom: 0.5lh;
}

.gym-title {
  font-weight: bold;
  font-size: inherit;
  color: var(--amber);
  margin-right: 2ch;
}

.gym-asof {
  color: var(--amber-50);
}

.gym-badge {
  padding: 0 1ch;
  text-transform: lowercase;
}

.gym-verified {
  color: var(--amber);
  border: 1px solid var(--amber);
  background: var(--amber-25);
}

.gym-broken {
  color: var(--amber-50);
  border: 1px solid var(--amber-25);
  background: transparent;
}

.gym-section {
  display: flex;
  flex-direction: column;
  gap: 0.5lh;
}

/* A table draws one hairline under each row and none between cells, the
 * way the rail separates its rows: the header's rule at 50% amber, the body
 * rows' at 25%, and no rule under the last row, so the table ends on the
 * section's edge. Cell borders on top of row borders doubled into thick and
 * thin lines. */
.gym-table {
  width: 100%;
  border-collapse: collapse;
}

.gym-table th,
.gym-table td {
  border: 0;
  padding: 0.25lh 1ch;
  text-align: left;
  vertical-align: top;
}

/* WebTUI draws its own 2 px rules through `::before` and `::after` on the
 * cells of a table without a `divide-` attribute. The markup sets
 * `divide-="none"`, and this drops the pseudo-elements in case the
 * attribute is missing. */
.gym-table th::before,
.gym-table td::before,
.gym-table th::after,
.gym-table td::after {
  content: none;
}

.gym-table thead tr {
  border-bottom: 1px solid var(--amber-50);
}

.gym-table tbody tr {
  border-bottom: 1px solid var(--amber-25);
}

.gym-table tbody tr:last-child {
  border-bottom: 0;
}

.gym-table th {
  color: var(--amber);
  font-weight: bold;
}

.gym-table .num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.gym-table tr.kept td {
  color: var(--amber);
}

.gym-table tr.reverted td,
.gym-table tr.dim td {
  color: var(--amber-50);
}

.gym-status-strip {
  display: flex;
  gap: 3ch;
  padding: 0.5lh 1ch;
  border: 1px solid var(--amber-25);
  background: var(--near-black);
}

.gym-status-strip .active {
  color: var(--amber);
}

.gym-status-strip .dim {
  color: var(--amber-50);
}

.gym-summary {
  display: flex;
  gap: 3ch;
  color: var(--amber-75);
  margin-bottom: 0.25lh;
}

/* The homepage, which `/` shows a visitor without a session. One screen and
 * nothing under the fold: the bar across the top, and the rest centered in
 * what the bar leaves. The frame, the `[ ]` controls, and the intensities
 * are the console's own. */
#home {
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
  height: 100dvh;
  padding: 1lh 2ch;
}

#home .bar {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 2ch;
}

#home .wordmark {
  font-weight: bold;
}

#home .login {
  text-decoration: none;
  white-space: nowrap;
}

#home .login:hover {
  color: var(--amber-75);
}

/* The headline, the command, and the two notes sit a little above the
 * middle of the space, because a block at dead center reads as low. */
#home .hero {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding-bottom: 3lh;
  min-height: 0;
}

#home h1 {
  font-size: 2.6em;
  font-weight: bold;
  line-height: 1.2;
  margin: 0;
}

#home h1 .dim {
  color: var(--amber-50);
  font-weight: normal;
}

#home .tagline {
  font-size: 1.15em;
  color: var(--amber-75);
  margin: 0.5lh 0 1.5lh;
}

/* The framed row: the command on the left, the copy control on the right.
 * A command wider than the viewport scrolls inside the frame rather than
 * wrapping, so the row keeps one line at every width. */
#home #install {
  display: flex;
  align-items: center;
  gap: 2ch;
  /* The frame's own padding is one cell; the command wants room on both
   * sides so it does not touch the rule. */
  padding: 0.25lh 3ch;
  max-width: 100%;
  box-sizing: border-box;
  background: var(--near-black);
}

#home .command {
  font: inherit;
  white-space: nowrap;
  overflow-x: auto;
  min-width: 0;
}

#home .prompt {
  color: var(--amber-50);
  user-select: none;
  -webkit-user-select: none;
}

#home .copy {
  flex: 0 0 auto;
  white-space: nowrap;
  /* `[ Copied ]` is the wider of the two labels; the control keeps that
   * width in both states so the row does not shift when it is pressed. */
  min-width: 10ch;
  text-align: center;
}

#home .note {
  color: var(--amber-50);
  margin: 0;
}

#home .note:first-of-type {
  margin-top: 1.5lh;
}

@media (max-width: 60ch) {
  #home h1 {
    font-size: 1.9em;
  }

  #home .tagline {
    font-size: 1em;
  }
}

/* Blog pages: index and post screens sharing the amber terminal aesthetic. */
.blog-container {
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
  min-height: 100dvh;
  padding: 1lh 2ch;
  max-width: 90ch;
  margin: 0 auto;
}

.blog-container .bar {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 2ch;
  margin-bottom: 2lh;
}

.blog-container .wordmark {
  font-weight: bold;
  text-decoration: none;
}

.blog-nav {
  display: flex;
  gap: 2ch;
}

.blog-article {
  background: var(--near-black);
  padding: 2lh 3ch;
}

.blog-article h1 {
  font-size: 1.8em;
  font-weight: bold;
  margin: 0 0 1lh;
  color: var(--amber);
}

.blog-list {
  list-style: none;
  margin: 1.5lh 0;
  padding: 0;
}

.blog-list-item {
  margin-bottom: 1.5lh;
}

.blog-list-item:before {
  content: none !important;
}

.blog-item-title {
  font-weight: bold;
  font-size: 1.1em;
  text-decoration: underline;
  color: var(--amber);
}

.blog-item-desc {
  color: var(--amber-75);
  margin-top: 0.5lh;
}

.blog-footer {
  margin-top: 2lh;
  padding: 1lh 0 0;
  border-top: 1px dashed var(--amber-25);
  color: var(--amber-50);
}
