/* doug.exe.here.now
   the desktop renders at every width (SITE-SPEC §2, revised 2026-08-21).
   `.shell` below is the pre-js/no-js fallback only — every real load
   replaces it with `#desktop` before first paint.

   98.css supplies the bevels; this file supplies the era. 98.css is a
   win98 recreation, and win98 chrome is win95 chrome except in two
   places — the title bar carries a left-to-right gradient and the
   inactive one carries a second — so the WINDOWS 95 block further down
   flattens exactly those and leaves every border 98.css draws alone.
   theme decision: DECISIONS.md, "LE THÈME"; target: SITE-SPEC §5. */

/* Perfect DOS VGA 437 — the terminal's and the boot screen's raster
   face. the old xp chrome used to declare this @font-face; 98.css
   does not carry
   it, so it is declared here against the same two vendored files. */
@font-face {
  font-family: "Perfect DOS VGA 437 Win";
  src: url("PerfectDOSVGA437Win.woff2") format("woff2"),
       url("PerfectDOSVGA437Win.woff") format("woff");
  font-weight: 400;
  font-style: normal;
}

/* Lucida Console does not exist outside Windows: on macOS, iOS and most
   Android builds the --mono stack below silently fell through to Courier
   New, a typewriter serif that reads as "unstyled" everywhere the site's
   three hero numbers and every log line are set. Cousine is vendored to
   close that gap — an open-license (Apache 2.0), metric-compatible
   understudy for Consolas: plain, humanist, no "developer tool" branding
   (ruling out Fira Code / JetBrains Mono, which read as IDE, not OS).
   Latin subset only, regular weight only — no mono text on this site is
   ever bold. font-display: swap so the font never blocks first paint;
   the fallback chain renders instantly and swaps in without reflow. */
@font-face {
  font-family: "Cousine";
  src: url("Cousine.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* ---------- WINDOWS 95 palette ----------
   SITE-SPEC §5: grey #c0c0c0 surfaces, #fff / #808080 bevels, one flat
   #000080 title bar, and no gradient anywhere in the chrome. the old
   rule was "no gradients beyond authentic XP ones"; the 95 theme
   retires the exception rather than widening it.

   the five bevel tones are 98.css's own, named here so this file can
   draw a raised or a sunken edge on something 98.css has no component
   for (the taskbar, the start menu, the context menu) and land on the
   same pixels the library does. */
:root {
  --face:        #c0c0c0;   /* button face — every chrome surface */
  --face-lit:    #dfdfdf;   /* the soft inner highlight of a raised edge */
  --hi:          #ffffff;   /* outer highlight */
  --sh:          #808080;   /* outer shadow */
  --dk:          #0a0a0a;   /* inner shadow */
  --nav:         #000080;   /* active caption. flat, never a gradient */
  --nav-off:     #808080;   /* inactive caption */
  --sel:         #000080;   /* selection / menu highlight */
  --ink:         #000000;
  --ink-soft:    #404040;
  --ink-dis:     #808080;   /* the greyed half of a disabled item */
  --rule:        #808080;   /* a stated rule, on paper or on the face */
  --rule-lite:   #c0c0c0;   /* the hairline between rows inside a white well */
  /* MS Sans Serif first, the way a 95 machine had it. the vendored
     bitmap face is 98.css's and is drawn for 11px — every ui size in
     this file is 10-13px, which is the range it was cut for. */
  --ui:          "Pixelated MS Sans Serif", "MS Sans Serif", Tahoma, "Segoe UI", Arial, sans-serif;
  /* Cousine FIRST, and that is the fix, not a preference (2026-09-05).
     The comment on its @font-face above says Cousine was vendored so the
     mono text stops depending on the visitor's system fonts. It could not
     do that from second place: any machine that resolves "Lucida Console"
     — every Windows box, and every mac that has ever had Office installed,
     which is where this was caught — never reaches the vendored face, so
     the three hero numbers and every pre.plain block rendered in whatever
     that machine happened to have. Measured on the deployed site: 38px
     hero numbers coming out in Lucida Console next to an 11px bitmap ui
     font. Vendoring an asset and then ranking a system font ahead of it
     is the failure DECISIONS.md ("Chrome vendoré en local, jamais un
     CDN") exists to prevent, applied to type instead of to chrome. */
  --mono:        Cousine, "Lucida Console", "DejaVu Sans Mono", Consolas, "Courier New", monospace;
  /* widest published ascii block is 50 columns. keep it on one line. */
  --mono-block:  max(9px, min(12px, calc((100vw - 36px) / 30)));
  --install-fill:#000080;
  --install-bed: #ffffff;

  /* the one colour on this site that is not grey, navy or ink. it is the
     same value the icon generator calls `"P": bright phosphor` and
     already paints on the glass of the TERMINAL.EXE icon — the well and
     the icon share it so the icon does not promise a screen the
     application does not open. it belongs only where a screen is
     DEPICTED (SITE-SPEC §5): never a bevel, a button, a title bar or a
     status bar. a green that leaves the depicted screen is a theme
     colour, and this site does not have one. */
  --phosphor:    #2fd033;

  /* the two edges, written once. raised = light top-left; sunken is its
     mirror. both are 98.css's four-stop bevel, so a hand-drawn control
     and a library one sit at the same depth. */
  --bevel-out:   inset -1px -1px var(--dk), inset 1px 1px var(--hi),
                 inset -2px -2px var(--sh), inset 2px 2px var(--face-lit);
  --bevel-in:    inset -1px -1px var(--hi), inset 1px 1px var(--sh),
                 inset -2px -2px var(--face-lit), inset 2px 2px var(--dk);
  /* the shallow one-pixel pair, for dividers and small wells */
  --edge-out:    inset -1px -1px var(--sh), inset 1px 1px var(--hi);
  --edge-in:     inset -1px -1px var(--hi), inset 1px 1px var(--sh);
}

* { box-sizing: border-box; }

html, body {
  height: 100%;
  margin: 0;
  padding: 0;
  overflow: hidden;
  /* the same ground #desktop paints, so the swap from the no-js shell
     to the real desktop never flashes a different colour. */
  background: #16233f;
  color: var(--ink);
  font-family: var(--ui);
  font-size: 11px;
  -webkit-text-size-adjust: 100%;
  /* aliased type, everywhere, not only where 98.css asks for it.

     the library switches font smoothing off on its own list — `.window`,
     `.title-bar`, `button`, `input`, `ul.tree-view` — which covered the
     window chrome and the panels but not the taskbar, the start menu,
     the context menu, the boot screen, or any control this file builds
     with `all: unset` (that resets the inherited value back to `auto`:
     `.start-btn`, `.dtask`, `.dicon`, `.sm-item`, `.ctx-item`,
     `.cpl-item`, `.sound-btn`).

     so half the site was drawing a bitmap face with grey fringes on it
     while the other half drew it hard. one declaration on the root
     settles it: this site has no antialiased text anywhere, which is
     the whole point of vendoring a pixel face and a raster dos face.

     AMENDED 2026-09-08. that reasoning holds for a face drawn ON the
     pixel grid — Pixelated MS Sans Serif and Perfect DOS VGA 437, whose
     every stroke is a whole pixel by construction. Cousine is not one of
     those. it was vendored later (see its @font-face above) as an
     ORDINARY OUTLINE face, and this root declaration swept it up with
     the rest. with smoothing off, an outline stroke thinner than one
     device pixel is not drawn at all: at 11px Cousine's `t` crossbar is
     about 0.8px, so on a 1x display every `t` lost its bar and the log
     read `insLruction nol implemenLed`. measured 2026-09-08 by rendering
     the live site headless at 1x and 2x — 2x was perfect, 1x was not,
     which is why it survived a retina-only review.

     so: the bitmap faces keep `none` — the chrome, the labels, the
     taskbar, the title bars, the terminal, the boot screen, which is
     where the era actually lives. every rule that sets `var(--mono)` at
     11-12px sets `auto` back. the one mono rule that keeps `none` is
     `.readout dd` at 34px, where the crossbar is ~2px and survives: the
     three hero numbers stay hard-edged. */
  -webkit-font-smoothing: antialiased;
}

/* ---------- AMENDED AGAIN 2026-09-10, and this one is a defect fix ----------

   `none` was the wrong default and the 2026-09-08 amendment only caught
   half of it. Turning antialiasing off assumes the page is drawn on a
   whole-pixel grid. On a Retina display running a SCALED resolution —
   the factory default on most MacBooks — macOS renders at 2x and then
   resamples the entire framebuffer to a fractional factor. The page
   cannot see this and cannot opt out: `window.devicePixelRatio` still
   reports 2.

   Aliased type is what suffers most, because it has hard edges and no
   antialiasing to fall back on. Measured 2026-09-10 by rendering the
   live site at --force-device-scale-factor=1.5, which produces the same
   class of artifact: `returned` drew as `reLurned`, `FLIP.EXE` read as
   `FLIF.EXE`, and word spacing collapsed. Gee reported exactly that from
   his own screen, twice, before it was believed.

   So the era is bought back a different way: the vendored pixel and
   raster faces still supply every letterform, the palette and the bevels
   are untouched, and the site loses only the hard edge on the glyphs —
   on the displays where that edge survived at all. A site whose letters
   are wrong on a default MacBook is not a stylistic choice.

   98.css sets `none` on its own list, which is more specific than the
   root, so the override has to name those selectors and the ones this
   file builds with `all: unset`. To go back, this whole block is the
   only thing to delete. */
html, body,
.window, .title-bar, button, input, label, option, select, table,
textarea, ul.tree-view,
.start-btn, .dtask, .dicon, .sm-item, .ctx-item, .cpl-item, .sound-btn {
  -webkit-font-smoothing: antialiased;
}

/* the bitmap face is drawn for 11px. these two set it at 10px, which
   scales it off its own grid — the exact thing the face exists to avoid.
   found 2026-09-10 while auditing the type. 11px, and the letter-spacing
   that was compensating for the squeeze comes off with it. */
.log-day, .log-kind { font-size: 11px; letter-spacing: 0; }

/* ---------- the window itself ---------- */

.shell {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  border-radius: 0;              /* maximized: no rounded corners */
  padding-top: env(safe-area-inset-top);
  padding-bottom: env(safe-area-inset-bottom);
  padding-left: env(safe-area-inset-left);
  padding-right: env(safe-area-inset-right);
}

/* ---------- title bar: flat navy, square controls ----------
   98.css draws win98's left-to-right caption gradient. win95 has none:
   one flat #000080, and #808080 when the window is not the front one.
   this is the single place the two eras actually differ in the chrome,
   so it is the only thing overridden here — every border 98.css draws
   is left exactly as it is. */

.title-bar {
  background: var(--nav);
  padding: 2px 2px 2px 3px;
}

.title-bar.inactive { background: var(--nav-off); }

.shell > .title-bar {
  flex: 0 0 auto;
  border-radius: 0;
  height: 20px;
}

.title-bar-text {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-right: 8px;
  font-size: 11px;
}

.title-bar-controls.inert { pointer-events: none; }

/* 95's caption buttons are square, 16x14, raised on the face colour.
   98.css already draws them that way; only the leading gap is ours. */
.title-bar-controls button + button { margin-left: 2px; }
.title-bar-controls button[aria-label="Close"] { margin-left: 4px; }

/* 98.css switches the focus ring off on these (`:focus { outline: none }`)
   and they are real tab stops on every window on this desktop — nine
   windows, up to three buttons each. a keyboard visitor was moving
   through two dozen controls with nothing on screen saying where they
   were. the mark is 95's own: the dotted rectangle drawn inside a
   focused button's face, drawn just inside the bevel rather than at the
   library's four pixels in — on a 16x14 button four pixels lands on the
   glyph and the ring stops being a rectangle. */
.title-bar-controls button:focus-visible {
  outline: 1px dotted var(--ink);
  outline-offset: -2px;
}

/* the shell's title-bar icon is DOUG.EXE at 16px — the same Track A
   drawing .pxi-doug uses, so the two can never drift apart. */
.exe-icon {
  width: 16px;
  height: 16px;
  flex: 0 0 16px;
  background-repeat: no-repeat;
  background-size: 16px 16px;
  image-rendering: pixelated;
  background-image: url("../assets/icons/svg/doug-16.svg");
}

/* ---------- body: tabs + scrolling panel ---------- */

.shell-body {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  margin: 6px 3px 3px;
}

menu[role="tablist"] {
  flex: 0 0 auto;
  margin: 0 0 -2px;
  padding-left: 3px;
  /* seven tabs: on a phone they wrap to a second row, the way xp
     property sheets always stacked tabs, rather than shrinking labels
     below legibility. */
  flex-wrap: wrap;
}

menu[role="tablist"] li { display: contents; }

menu[role="tablist"] button {
  font-family: var(--ui);
  font-size: 11px;
  letter-spacing: -0.2px;
  padding: 3px 4px 5px;
  white-space: nowrap;
  min-width: 0;
}

/* keyed on the class, not the role: on the desktop the panels move into
   four windows and drop their tabpanel role, but keep these styles. */
.panel {
  container-type: inline-size;   /* see --mono-block override below */
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  margin-bottom: 0;
  padding: 16px 14px 22px;
}

.panel[hidden] { display: none; }

/* the panel is a scroll region and a real tab stop — the tabpanel of the
   no-js shell, and still focusable inside every desktop window so a
   keyboard can scroll it. it carried no focus style at all, which left
   the browser's own ring: the one mark on this page drawn by this decade
   instead of by 1995. */
.panel:focus-visible { outline: 1px dotted var(--ink); outline-offset: -3px; }

/* --mono-block above is sized off 100vw, which only equals a panel's
   real width in the maximized mobile shell. every desktop window is
   narrower than the viewport, so on desktop this always saturates to
   its 12px ceiling — correct today only because no window is currently
   user-resizable below that width. cqw measures the panel itself, so
   this stays correct even if that changes. guarded by @supports: browsers
   without container query units keep the vw-based value untouched. */
@supports (width: 1cqw) {
  .panel { --mono-block: max(9px, min(12px, calc((100cqw - 28px) / 30))); }
}

/* ---------- the three numbers ---------- */

.readout { margin: 0 0 22px; }

.readout-row + .readout-row {
  margin-top: 11px;
  padding-top: 11px;
  /* the etched divider 95 drew everywhere: one shadow line, one
     highlight line under it. never a single flat rule. */
  border-top: 1px solid var(--sh);
  box-shadow: 0 -1px var(--hi);
}

.readout dt {
  font-family: var(--ui);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.9px;
  text-transform: uppercase;
  color: var(--ink);
  margin: 0 0 3px;
}

.readout dd {
  margin: 0;
  font-family: var(--mono);
  font-size: 34px;
  line-height: 1.05;
  color: var(--ink);
  word-break: break-word;
}

/* an unknown value must never read as a real one */
.is-empty,
.readout dd.is-empty,
pre.plain .is-empty { color: var(--ink-dis); }

/* windows installer bar: segmented blocks on a sunken bed.
   **only the boot screen fills one now.** DOUG.EXE had one under the tier
   ladder until 2026-09-05; the ladder is gone and nothing on this site
   fills toward anything any more (DECISIONS.md, "PAS D'ÉCHELLE"). The
   component stays because the boot sequence is still a real progress
   bar with a real end. */
.installer-bar {
  height: 18px;
  padding: 2px;
  background: var(--install-bed);
  box-shadow: var(--bevel-in);
}

.installer-blocks {
  display: flex;
  gap: 2px;
  height: 100%;
  align-items: stretch;
}

.installer-blocks i {
  flex: 0 0 7px;
  background: var(--install-fill);
}


/* ---------- flat text blocks ---------- */

pre.plain {
  margin: 0;
  padding: 0;
  background: none;
  box-shadow: none;   /* 98.css gives every <pre> a sunken well; these are not wells */
  color: var(--ink);
  font-size: var(--mono-block);
  line-height: 1.55;
  white-space: pre;
  overflow-x: auto;
}

pre.plain, pre.plain * {
  font-family: var(--mono);
  -webkit-font-smoothing: auto;   /* outline face at 9-12px — see body */
}

/* on DOUG.EXE the $DOUG holdings line is the panel's last element, and at
   default window size everything below it was bare face colour — the
   same unread margin as INVOICE.TXT, fixed the same way: the panel
   becomes a column, this block grows to take the rest of it, and gets
   the identical sunken-white treatment as .invoice-sheet so the value
   reads as a field being reported, not a caption trailing off into
   empty space. text and layout inside are unchanged. */
/* :not([hidden]), not the bare id — an id selector outranks .panel[hidden]
   (0,2,0) on specificity alone, so display:flex here would have forced a
   hidden mobile-shell panel visible underneath whichever tab is showing. */
#panel-doug:not([hidden]) {
  display: flex;
  flex-direction: column;
}

#panel-doug pre.plain {
  flex: 1 1 auto;
  min-height: 84px;
  margin-top: 4px;
  padding: 14px 12px;
  background: #fff;
  box-shadow: var(--bevel-in);
}

/* ---------- status bar ---------- */

.shell > .status-bar {
  flex: 0 0 auto;
  margin: 0 3px 0;
}

.status-bar-field {
  font-family: var(--ui);
  font-size: 11px;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* 98.css grows every field equally. here the two fixed-width segments take
   only what they need and the sync line absorbs the rest, because it is the
   one that carries a variable note (retrying / account not found). */
.sb-host,
.sb-uptime,
.sb-wallet { flex: 0 0 auto; }

/* CONFIG.DEPLOYED_AT is unset until launch, so this field reads a
   permanent em dash — dead weight competing with sb-host for the same
   narrow width it loses at 439px. hide it while empty; the instant
   DEPLOYED_AT is set at launch, renderUptime stops adding .is-empty and
   the field reappears with a real value, no further change needed here. */
.sb-uptime.is-empty { display: none; }

.sb-sync {
  flex: 1 1 auto;
  min-width: 0;
  text-align: right;
}

.sb-wallet a {
  font-family: var(--mono);
  -webkit-font-smoothing: auto;   /* outline face at 11-12px — see body */
  font-size: 11px;
}

.sb-wallet a:focus-visible { outline: 1px dotted var(--ink); outline-offset: 1px; }

/* ---------- narrow phones ---------- */

@media (max-width: 359px) {
  menu[role="tablist"] button { font-size: 10px; padding: 3px 2px 5px; }
  .readout dd { font-size: 29px; }
}

/* ---------- .shell's no-js/pre-js fallback, tablet and up ----------
   real loads never see this at rest: the desktop module below replaces
   #shell before first paint. kept only so a page that never runs js
   still centers its one window sanely above a phone width. */

@media (min-width: 768px) {
  body { padding: 0; }
  .shell {
    inset: auto;
    position: relative;
    margin: 28px auto;
    width: min(560px, calc(100% - 40px));
    height: calc(100dvh - 56px);
    border-radius: 8px 8px 0 0;
  }
  .shell > .title-bar { border-radius: 8px 8px 0 0; }
  html, body { overflow: auto; }
  .readout dd { font-size: 38px; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
}

/* ---------- TRADES.LOG ----------
   no colour carries meaning here. a gain and a loss are the same ink,
   the same weight and the same size, so the page cannot flatter. */

/* the line above the list: what the log last read, and — only where the
   column headings are not available — how it is ordered. */
.log-bar {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin: 0 0 8px;
}

.log-status {
  margin: 0;
  font-family: var(--mono);
  -webkit-font-smoothing: auto;   /* outline face at 11-12px — see body */
  font-size: 11px;
  color: var(--ink-soft);
}

/* the narrow-width sort. hidden wherever the column headings are on
   screen: two controls for one sort, both visible, would be two places a
   reader could look for it. it is the SAME sort either way — both call
   setLogSort(). */
.log-sort {
  display: flex;
  align-items: baseline;
  gap: 5px;
  flex: 0 0 auto;
  font-family: var(--ui);
  font-size: 11px;
  color: var(--ink-soft);
}

.log-sort select {
  font-family: var(--ui);
  font-size: 11px;
}

/* ---------- the column headings ----------
   a 95 details view: raised heading buttons, labels hard left, the sorted
   one held down. no colour and no weight change — a heading is furniture,
   and the sort is stated by the bevel and one caret, the way the era did
   it. hidden under 560px with the grid they head. */
.log-cols {
  display: none;
  gap: 0;
  margin: 0 0 -2px;
  padding: 0;
}

.log-col {
  all: unset;
  box-sizing: border-box;
  display: block;
  min-width: 0;
  padding: 2px 6px 3px;
  font-family: var(--ui);
  font-size: 11px;
  color: var(--ink);
  background: var(--face);
  box-shadow: var(--bevel-out);
  cursor: var(--cur-arrow), default;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.log-col:not(:disabled):active,
.log-col.is-sorted {
  box-shadow: var(--bevel-in);
  padding: 3px 5px 2px 7px;   /* the 95 one-pixel shove of a pressed face */
}

/* the sorted column names its direction. a caret, not an arrow glyph:
   drawn in css so it carries no font dependency and no vendor mark. */
.log-col.is-sorted::after {
  content: "";
  display: inline-block;
  margin-left: 5px;
  border: 3px solid transparent;
  border-top-color: var(--ink);
  transform: translateY(2px);
}

.log-col.is-sorted.is-asc::after {
  border-top-color: transparent;
  border-bottom-color: var(--ink);
  transform: translateY(-2px);
}

/* present, and genuinely not offered — the same "greyed with no handler"
   pattern as `Delete` in the context menu and `OK` in ENDINGS.TXT. the
   engraved grey is 98.css's disabled text, drawn by hand here because
   `all: unset` dropped the library's rule with everything else. */
.log-col:disabled {
  color: var(--ink-dis);
  text-shadow: 1px 1px 0 var(--hi);
  cursor: var(--cur-arrow), default;
}

.log-col:focus-visible {
  outline: 1px dotted var(--ink);
  outline-offset: -4px;
}

/* the list is the window's document, so it fills the window — the same
   fix DOUG.EXE's holdings well and the invoice/readme sheets already
   carry, and the last panel that was still leaving several hundred
   pixels of bare face colour under a short log.

   `flex: 1 0 auto`, not `1 1 auto`: grow into the space the status line
   and the footer leave, never shrink below the rows actually in it. a
   log longer than the window spills past the paper and `.panel` scrolls
   it, which is the one scroller this window has. */
ul.tree-view.log {
  flex: 1 0 auto;
  margin: 0;
  padding: 3px;
  max-height: none;
}

/* THE ROW, STACKED — this is the phone, and the base. the four cells of
   the details grid wrap into the card the log has always shown here:
   `time … chain tx` on one line, the type on the next, the deltas under
   both. above 560px the same four cells become the grid (SITE-SPEC §3.2).
   `flex: 1 0 100%` is what forces the break: it is a line, not a column. */
.log-row {
  margin: 0;
  padding: 7px 5px 8px;
  border-bottom: 1px solid var(--rule-lite);
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: 8px;
}

.log-kind,
.log-deltas { flex: 1 0 100%; }

.log-deltas { display: block; }

.log-row:last-child { border-bottom: none; }

/* the day heading. tahoma rather than the log's mono: it is furniture,
   not a reading from the chain, and the distinction is worth one
   typeface. the rule under it is what the eye actually scans by. */
.log-day {
  list-style: none;
  margin: 0;
  padding: 12px 5px 3px;
  font-family: var(--ui);
  font-size: 10px;
  letter-spacing: 0.6px;
  color: var(--ink-soft);
  border-bottom: 1px solid var(--sh);
}

.log-day:first-child { padding-top: 3px; }

/* no double rule where a day ends: the row above a heading drops its own
   border and lets the heading's carry the break. */
.log-row:has(+ .log-day) { border-bottom: none; }

/* a faint row highlight — helps a reader track one row across its two
   lines without introducing any colour that could read as a gain/loss
   signal. neutral grey now the era is 95: a tint would be a signal. */
.log-row:hover { background: var(--face-lit); }

.log-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}

.log-time {
  font-family: var(--mono);
  -webkit-font-smoothing: auto;   /* outline face at 11-12px — see body */
  font-size: 11px;
  color: var(--ink);
  white-space: nowrap;
}

/* the chain the row happened on. it sits next to the explorer link and
   not next to the time, because the two belong together: the label says
   where, the link proves it (SITE-SPEC §3.2). `margin-left: auto` pushes
   the pair right and keeps the time hard left, so a row reads
   time … chain tx at every width.

   deliberately quiet — same size and colour as the time. it is a fact
   about the row, not a badge, and a coloured chip per chain would turn
   a log into a scoreboard. */
.log-chain {
  margin-left: auto;
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
  font-family: var(--mono);
  -webkit-font-smoothing: auto;   /* outline face at 11-12px — see body */
  font-size: 11px;
  color: var(--ink);
  white-space: nowrap;
}

.log-chain.is-empty { color: var(--ink-dis); }

/* the library's .tree-view a rule (color:#000, no underline — built for
   an Explorer tree, not a link list) was flattening every solscan link to
   plain black text: 277 of the darkest, most repeated marks on the page
   carrying the least information, with no way to tell they're tappable.
   this restores an affordance without competing with the log's own ink:
   soft grey + dotted underline reads as "secondary but clickable" at
   rest, and works with no :hover on mobile; full link-blue only appears
   on hover/focus, matching .sb-wallet a's treatment elsewhere on the
   site. still no colour that could be mistaken for gain/loss coding.
   selector is ".tree-view a.log-link", not ".log-link" alone: the
   library's ".tree-view a" is itself class+type (0,1,1), which outranks
   a bare single-class selector (0,1,0) — the first cut of this fix
   compiled but never painted, silently losing the cascade. 98.css
   carries the same rule xp.css did, so this stays load-bearing. */
.tree-view a.log-link {
  font-family: var(--ui);
  font-size: 11px;
  flex: 0 0 auto;
  color: var(--ink-soft);
  text-decoration: underline dotted;
  text-underline-offset: 2px;
}

.tree-view a.log-link:hover {
  color: #00f;
  text-decoration: underline solid;
}

/* 98.css paints `ul.tree-view a:focus` navy-on-white — an Explorer row
   selection — and the rule above then repainted the label #00f on top of
   it, so a keyboard focus landed blue ink on a navy bar and read as
   nothing at all. this is a link inside a log, not a selected row: the
   library's fill goes, and the mark becomes the dotted rectangle 95 drew
   round a focused item. the library's own blue ring on plain `:focus`
   goes with it, so a mouse click leaves no ring behind. */
.tree-view a.log-link:focus {
  background: none;
  color: var(--ink-soft);
  outline: none;
}

.tree-view a.log-link:focus-visible {
  color: #00f;
  text-decoration: underline solid;
  outline: 1px dotted var(--ink);
  outline-offset: 1px;
}

.log-kind {
  font-family: var(--ui);
  font-size: 10px;
  letter-spacing: 0.5px;
  color: var(--ink-soft);
  margin: 1px 0 5px;
  word-break: break-word;
}

.log-delta {
  font-family: var(--mono);
  -webkit-font-smoothing: auto;   /* outline face at 11-12px — see body */
  font-size: 12px;
  line-height: 1.45;
  color: var(--ink);
  padding-left: 10px;
  display: flex;
  gap: 6px;
}

/* the details grid, from 560px up. the tracks live in ONE custom property
   that the headings and every row both read, so a column cannot drift
   from the heading above it. the time track is the only one that moves:
   it holds a clock under a day heading and a whole stamp when the sort is
   not chronological and there is no heading to carry the date. */
#panel-trades {
  --log-t: 72px;
  --log-cols: var(--log-t) 92px 150px minmax(0, 1fr);
}

#panel-trades.is-stamped { --log-t: 132px; }

@media (min-width: 560px) {
  /* 8px on the left: the list's own 3px of padding plus the 5px a row
     carries, so a heading sits exactly over its column and not one pixel
     beside it. nothing on the right — the last heading runs to the edge
     of the bar, the way a details view's last column always did. */
  .log-cols {
    display: grid;
    grid-template-columns: var(--log-cols);
    padding: 0 0 0 8px;
  }

  .log-sort { display: none; }

  .log-row {
    display: grid;
    grid-template-columns: var(--log-cols);
    align-items: baseline;
    column-gap: 0;
  }

  /* in the grid the column supplies the offset, so the cells drop the
     margins and indents they need when they are stacked lines. */
  .log-chain { margin-left: 0; }
  .log-kind  { margin: 0; padding-right: 8px; }
  .log-delta { padding-left: 0; }
}

/* identical treatment for both directions. this is the point. */
.log-amt {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.log-mint {
  color: var(--ink-soft);
  word-break: break-all;
}

.log-none,
.log-empty {
  font-family: var(--mono);
  -webkit-font-smoothing: auto;   /* outline face at 11-12px — see body */
  font-size: 11px;
  color: var(--ink-soft);
  list-style: none;
  padding: 10px 5px;
  line-height: 1.5;
}

.log-empty.is-empty { font-size: 16px; }

.log-foot {
  margin-top: 10px;
  display: flex;
  align-items: center;
  gap: 10px;
}

.log-foot button { font-family: var(--ui); font-size: 11px; }

.log-note {
  margin: 0;
  font-family: var(--mono);
  -webkit-font-smoothing: auto;   /* outline face at 11-12px — see body */
  font-size: 11px;
  color: var(--ink-soft);
}

@media (max-width: 359px) {
  .log-delta { font-size: 11px; }
  .log-time  { font-size: 10px; }
}

/* ---------- ENDINGS.TXT ----------
   the xp "shut down windows" dialog. both options are described, neither is
   offered: nothing here is clickable and nothing here is live. */

.shutdown {
  background: var(--face);
  box-shadow: var(--bevel-out);
  padding: 3px;
}

/* the same flat caption every other window on this desktop wears. the
   xp version painted a nine-stop luna gradient here; 95 has one navy. */
.shutdown-bar {
  display: flex;
  align-items: center;
  gap: 4px;
  font-family: var(--ui);
  font-size: 11px;
  font-weight: 700;
  color: #fff;
  padding: 2px 3px;
  background: var(--nav);
}

.shutdown-body {
  /* 95's dialog body is the face colour and nothing else — the pale
     blue banner behind the options was an xp invention. */
  background: var(--face);
  padding: 14px 12px 12px;
}

.shutdown-prompt {
  margin: 0 0 14px;
  font-family: var(--ui);
  font-size: 12px;
  color: var(--ink);
}

/* each option sits in a 95 group box: face colour, one etched edge.
   nothing here is clickable and nothing here is offered — the box is a
   grouping, never a control. */
.ending {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 11px 10px;
  margin-bottom: 10px;
  background: var(--face);
  box-shadow: var(--edge-in);
}

/* 32px, which is the size `.dlg-lead` and `.prop-head` already draw a
   dialog's lead icon at — these two were the only ones at 24, and 24 put
   the drawing on a 1.5x scale. the art below is now drawn at 32, so the
   box asks for exactly the grid the file carries and every art pixel
   lands on whole device pixels with nothing resampled. */
.ending-icon {
  flex: 0 0 32px;
  width: 32px;
  height: 32px;
  margin-top: 1px;
  background-repeat: no-repeat;
  background-size: 32px 32px;
  image-rendering: pixelated;
}

/* original pixel art — no microsoft assets anywhere on this site.

   native 32s from tools/make-icons.py, not a 16px drawing shown at 32.
   both are the SAME machine as the ENDINGS.TXT window icon, pixel for
   pixel, with the same lit screen; only the glyph on the glass differs,
   and both glyphs are the same phosphor. one line is flat, one line
   rises, and that is the whole difference between them — no power glyph,
   no dark screen, and no colour marking one ending as the good one.
   PROGRESS.md E4: neither ending is a death. */
.ending-icon-up {
  background-image: url("../assets/icons/svg/ending-up.svg");
}

.ending-icon-flat {
  background-image: url("../assets/icons/svg/ending-flat.svg");
}

.ending-text { min-width: 0; }

.ending-text h3 {
  margin: 0 0 5px;
  font-family: var(--ui);
  font-size: 11px;
  font-weight: 700;
  color: var(--ink);
}

.ending-text p {
  margin: 0 0 6px;
  font-family: var(--mono);
  -webkit-font-smoothing: auto;   /* outline face at 11-12px — see body */
  font-size: 11px;
  line-height: 1.55;
  color: var(--ink);
  overflow-wrap: break-word;
}

.ending-text p:last-child { margin-bottom: 0; }

.shutdown-close {
  margin: 14px 0 2px;
  font-family: var(--mono);
  -webkit-font-smoothing: auto;   /* outline face at 11-12px — see body */
  font-size: 12px;
  color: var(--ink);
}

.shutdown-buttons {
  display: flex;
  justify-content: flex-end;
  gap: 6px;
  /* 12px on the sides, so the row's right edge lands on the same line as
     the two group boxes above it — `.shutdown-body` insets its content
     by 12 and this row was insetting by 8, which read as a button row
     hanging four pixels past the dialog's own margin. 8 above and 12
     below balances the 14 the body leaves under the caption. */
  padding: 8px 12px 12px;
}

/* real buttons in the authentic 95 disabled state — greyed and
   unfocusable come from the attribute, the engraved grey text (grey
   with a white shadow one pixel down and right) comes from 98.css.

   size is the library's and stays the library's: 98.css draws 95's
   standard push button at 75x23 with 12px of side padding, and every
   button row on this site used to override that with a different
   number (62 here, 74 in the dialogs, 88 in the log). one button size,
   set in one place. */
.shutdown-buttons button {
  font-family: var(--ui);
  font-size: 11px;
}

@media (max-width: 359px) {
  .ending { padding: 9px 7px; gap: 8px; }
  .ending-text p { font-size: 10px; }
}

/* the row on this site that stands three buttons side by side. below
   360px three 75px buttons and their gaps no longer fit the sheet they
   sit on, so the floor drops. everything above 360px keeps the
   library's size. (this was two rows until 2026-09-05 — PAINT.EXE's
   save / share / clear was the other.) */
@media (max-width: 359px) {
  .shutdown-buttons button { min-width: 62px; padding: 0 8px; }
}

/* ---------- status bar: what survives a narrow screen ----------
   measured worst case: host 73px + uptime 83px + wallet 60px + sync 201px
   (sync carries a variable note) + chrome ≈ 439px.

   drop order, least critical first:
     1. doug.exe.here.now — the only segment telling the reader something they
        already know: the domain they are currently on. pure chrome.
     2. uptime — a status figure, not a verification affordance.

   the wallet link and last sync survive every width. those two are the pair
   that lets a reader check the site is not lying: one goes to the chain,
   the other says how old the numbers are. */

@media (max-width: 439px) { .sb-host   { display: none; } }
@media (max-width: 359px) { .sb-uptime { display: none; } }

/* ---------- INVOICE.TXT ----------
   a notepad sheet: white, sunken, fixed-width. static text only. */

/* at default window size the sheet was shorter than the panel around it,
   leaving bare face colour below — an unread margin, not a document. this
   makes the panel a column and lets the sheet grow to fill it: the empty
   space becomes the inside of the paper instead of dead air outside it.
   no content added, nothing invented — same fix as #panel-doug below. */
/* :not([hidden]) for the same reason as #panel-doug above: a bare id
   selector would outrank .panel[hidden] and force this panel visible
   even while another tab is showing. */
#panel-invoice:not([hidden]),
#panel-readme:not([hidden]),
#panel-trades:not([hidden]) {
  display: flex;
  flex-direction: column;
}

/* README.TXT is the same object as INVOICE.TXT — a sheet of fixed-width
   text on notepad paper — so it is the same component, not a second one
   that has to be kept in sync by hand. */
.invoice-sheet,
.readme-sheet {
  /* 1 0 auto, not 1 1 auto: an explicit min-height of 100% replaces the
     flex default of min-height:auto, so a shrinkable item is allowed to
     collapse to exactly the panel's height and let anything longer spill
     out past the paper. README.TXT is the first sheet on this site taller
     than its window, which is what surfaced it. no shrink, no spill. */
  flex: 1 0 auto;
  min-height: 100%;
  background: #fff;
  box-shadow: var(--bevel-in);
  padding: 16px 14px;
}

/* the same dashed rule INVOICE.TXT puts under its header block.

   written as pre.plain.readme-block, not .readme-block: `pre.plain`
   above carries `margin: 0; padding: 0` at specificity (0,1,1), which
   outranks a bare single class whatever the source order. .invoice-notes
   had exactly this bug — its rule and its dashed border painted, its
   18px of air above and below never did, so the note sat flush against
   "status: OPEN". both are fixed here. */
pre.plain.readme-block,
pre.plain.invoice-notes {
  margin-top: 18px;
  padding-top: 18px;
  border-top: 1px dashed var(--rule);
  color: var(--ink-soft);
}

/* ---------- scrollbar arrows ----------
   a 95 scrollbar has ONE arrow at each end. 98.css sets display:block on
   the two that point outward and leaves the other two alone, but current
   chrome shows all four pieces once ::-webkit-scrollbar is styled at all,
   and its `:vertical:start` / `:vertical:end` background rules match the
   inner pair too — so every scrollbar was drawing a doubled arrow at each
   end. the vendored file is not edited; the two extras are hidden here.
   (xp.css carried the identical rules, so this predates the theme swap.) */
::-webkit-scrollbar-button:vertical:start:increment,
::-webkit-scrollbar-button:vertical:end:decrement,
::-webkit-scrollbar-button:horizontal:start:increment,
::-webkit-scrollbar-button:horizontal:end:decrement { display: none; }

/* ---------- cursors ----------
   Redrawn from `Icone Pack/win95 cursor.jpg`: original bitmaps, plotted
   pixel by pixel here, nothing traced or cut from a Microsoft file
   (DECISIONS.md "Attention IP"). Same ink as every other drawn mark on
   this site, white fill so each one reads on the near-black wallpaper
   and on the terminal's black well alike.

   Two sizes per cursor and no scaling between them: the 1x is the art at
   its own size, the 2x is the same grid at two device pixels per art
   pixel, so a hidpi screen gets crisp edges instead of a blurred
   upscale. The plain `url()` value is declared first and image-set only
   inside @supports, so a browser that cannot parse image-set keeps a
   working cursor rather than falling back to the system one.

   None of them animates, so there is nothing for prefers-reduced-motion
   to turn off — the Windows 95 hourglass did not animate either (the
   spinning one was a later, different cursor).

   THE FIFTH CURSOR OF THE REFERENCE SHEET, THE DIAGONAL RESIZE, IS NOT
   HERE. Nothing on this desktop resizes: windows open at their own rect
   and can be dragged, maximised and restored, never resized
   (SITE-SPEC §2). A resize cursor on a window edge would offer a grip
   that is not there, which is the one thing this site does not do. It
   is left out rather than drawn and pointed at nothing; see
   grok-review/TRACKS.md. */

:root {
  --cur-arrow: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAATCAYAAACk9eypAAAAfUlEQVR42q2QwQ3FMAhDXatTmP1HgzX4p1RtQtJU+pxixLMhkJT4UASALxABwN23IbbHLsS72IHYN94gVs0VxJnTDOJq3wri26/00DkbNLOHlpQRcZz9kLtfOiKOwUlSZma22KbvveEGM6vdqqpcVincdt5JrlKIf5ak4YYfOaBcid2xiy4AAAAASUVORK5CYII=") 0 0;
  --cur-ibeam: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAARCAYAAAAR3bZVAAAAOUlEQVR42mOUkpL6z4ALSElJ/YcBdDYjss6nT58ySEtL4zYBWTETAx4wKsnAwMCCLVbgYkTHCjoAANZRN+H1JDChAAAAAElFTkSuQmCC") 3 8;
  --cur-wait: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAUCAYAAAC58NwRAAAAdElEQVR42q2TXQrAIAyDY/EU8f5H6zncwyh0rm7+BQQRyZdqm0hWTCgDgKoOXS6l3BuS9U+WJIcOjXwCwaosFsnH8nH2CBGldd8ntE8cfaocc+9R5Fj2Xi3TBDF36xffT7ZXVRhljfDVra+zkVnwxafZEb0A7I+uEfE7ogEAAAAASUVORK5CYII=") 6 10;
  --cur-hand: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAUCAYAAACEYr13AAAAb0lEQVR42uWTSQrAMAwDldBXyP9/mv0N91QoWXA26KFzy0WMkAM0IOkkHSuQ9IeRkIxN/hAQLXJFAaoKABARBwAzS8sVVBXlvPn44bzfPSqDsu+WxQiVgZklEfnmkKarlGudNYgsWreybdD8CzOL3Hugv6UYciyKAAAAAElFTkSuQmCC") 5 0;
}

/* the 2x art. declared second so it wins wherever image-set parses, with
   the plain url() above as the standing value. `CSS.supports('cursor',
   'image-set(…)')` reports false in browsers that in fact accept it, so
   an @supports guard was tried and removed: it suppressed the 2x art on
   every browser that can use it. A browser too old to parse image-set at
   all falls back to the system arrow, which is what it would have shown
   anyway. */
:root {
  --cur-arrow: image-set(url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAATCAYAAACk9eypAAAAfUlEQVR42q2QwQ3FMAhDXatTmP1HgzX4p1RtQtJU+pxixLMhkJT4UASALxABwN23IbbHLsS72IHYN94gVs0VxJnTDOJq3wri26/00DkbNLOHlpQRcZz9kLtfOiKOwUlSZma22KbvveEGM6vdqqpcVincdt5JrlKIf5ak4YYfOaBcid2xiy4AAAAASUVORK5CYII=") 1x, url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAmCAYAAADeB1slAAAAoUlEQVR42uXXSw6AIAwE0MF4ivb+R4Nr4GpcdCGiFGrsysQY+5jiByJSRaTCqTY413kDL4m7YOdBzhkAoKoVAEop6VsCL8l8wWjJOsEoyXrBW0kcwVNJPEGvJK7griSeQFUvz/OtSMk6ATvlGtuKu5PZOTvkdFASdyfbzj/zXZTs3Lbm205VS+6fweg1n59B7wW9Wcz7P/hPBjaL1tPVXXAApiFulsAxnjsAAAAASUVORK5CYII=") 2x) 0 0;
  --cur-ibeam: image-set(url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAARCAYAAAAR3bZVAAAAOUlEQVR42mOUkpL6z4ALSElJ/YcBdDYjss6nT58ySEtL4zYBWTETAx4wKsnAwMCCLVbgYkTHCjoAANZRN+H1JDChAAAAAElFTkSuQmCC") 1x, url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAiCAYAAABvJuicAAAAUklEQVR42mOUkpL6z0AGYGIgE7DAGE+fPkWRkJaWxitOto2MuPwIswlmA/X8+OzZM0ZkAVwuQFdHto2jGkc1jmoc1UjXkpzYugNd3XCoO2gWqgBd8Rx+XwboKgAAAABJRU5ErkJggg==") 2x) 3 8;
  --cur-wait: image-set(url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAUCAYAAAC58NwRAAAAdElEQVR42q2TXQrAIAyDY/EU8f5H6zncwyh0rm7+BQQRyZdqm0hWTCgDgKoOXS6l3BuS9U+WJIcOjXwCwaosFsnH8nH2CBGldd8ntE8cfaocc+9R5Fj2Xi3TBDF36xffT7ZXVRhljfDVra+zkVnwxafZEb0A7I+uEfE7ogEAAAAASUVORK5CYII=") 1x, url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAoCAYAAADkDTpVAAAAlElEQVR42u2XQQoAIQhFc5hT5P2PlteYWbkJREktAl1FRGYv+wq9968l2tOS7eXBGCN0Y0TcEwHwgFl4I+GTExHsZSCdxGpS5OkR3O8A5on5NWks5nX8eorBOgMrC+3ui4GfgfbLandfDOLzwKpgxSBeDySNtuZFMfBXdlZNPlbZ3e/AXZvyumO1KUT1Bec6nOu7zB+Jc02FEKQEBAAAAABJRU5ErkJggg==") 2x) 6 10;
  --cur-hand: image-set(url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAUCAYAAACEYr13AAAAb0lEQVR42uWTSQrAMAwDldBXyP9/mv0N91QoWXA26KFzy0WMkAM0IOkkHSuQ9IeRkIxN/hAQLXJFAaoKABARBwAzS8sVVBXlvPn44bzfPSqDsu+WxQiVgZklEfnmkKarlGudNYgsWreybdD8CzOL3Hugv6UYciyKAAAAAElFTkSuQmCC") 1x, url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAoCAYAAACfKfiZAAAAnElEQVR42u1YSQ6AIAwE4yvg/09rv4EnEk2UJa3SmukNDmSY6TIQw2CklMp5zcwxKMQWFkccvTkRXfZzzipMLGcAAAAAAABglx4gnRH+GbiZEVOM+GdggJnSmp52GHjL8divgobjKTPZ39v314qJaPo2vl3xUy5ohf0+UJHV7P9CfxgS229DrarovSEhgd//Aan2kMCfK66a/o6BAwPWTMlYqGNUAAAAAElFTkSuQmCC") 2x) 5 0;
}

body { cursor: var(--cur-arrow), default; }

/* a link is the one thing on this desktop that is not a 95 widget, and
   the hand is what a browser puts there. every 95 control keeps the
   arrow, because 95 never used a hand for a button. */
a[href] { cursor: var(--cur-hand), pointer; }

/* text: fields, and the wells whose content is there to be selected —
   the CA line in INVOICE.TXT exists to be copied. */
input[type="text"],
textarea,
.plain,
.term-out,
.log,
.bsod-text { cursor: var(--cur-ibeam), text; }

/* the hourglass has exactly one true home on this site: the moment the
   drawing is being encoded to a PNG, which is the only user-started
   asynchronous operation here. it is set when the encode starts and
   cleared when it settles — never left on, and never used to decorate a
   read from the chain, which does not block anything. */
body.is-busy,
body.is-busy * { cursor: var(--cur-wait), wait; }

/* ---------- pixel icons ----------
   the eight window icons are Track A's, delivered 2026-09-01 and
   specified in site/assets/README.md. original pixel art: nothing is
   traced or cut from a microsoft bitmap (DECISIONS.md "Attention IP").

   each icon is TWO drawings, not one asset scaled — a 32 and a 16 drawn
   separately, because a 32 reduced to 16 turns to mush and 16 is where
   the title bar, the taskbar and the start menu live. so the rule is
   pick by size, never by scale factor: below 24px the 16, at 24px and
   above the 32.

   the four glyphs below the set (run, stop, x, ext) are still drawn
   here — they belong to dialogs and menu rows, not to windows, and
   Track A's brief covered the eight windows only. */

.pxi {
  display: inline-block;
  background-repeat: no-repeat;
  background-size: 100% 100%;
  image-rendering: pixelated;
}

/* the 16px drawings — title bars, taskbar buttons, start-menu rows */
.pxi-doug { background-image: url("../assets/icons/svg/doug-16.svg"); }
.pxi-trades { background-image: url("../assets/icons/svg/trades-16.svg"); }
.pxi-invoice { background-image: url("../assets/icons/svg/invoice-16.svg"); }
.pxi-readme { background-image: url("../assets/icons/svg/readme-16.svg"); }
.pxi-endings { background-image: url("../assets/icons/svg/endings-16.svg"); }
.pxi-terminal { background-image: url("../assets/icons/svg/terminal-16.svg"); }
.pxi-flip { background-image: url("../assets/icons/svg/flip-16.svg"); }
.pxi-recycle { background-image: url("../assets/icons/svg/recycle-16.svg"); }

/* the 32px drawings — desktop icons, dialog leads, properties heads.
   a different picture, carrying marks the 16 grid cannot hold. */
.dicon-img.pxi-doug,
.dlg-lead .pxi-doug,
.prop-head .pxi-doug { background-image: url("../assets/icons/svg/doug.svg"); }
.dicon-img.pxi-trades,
.dlg-lead .pxi-trades,
.prop-head .pxi-trades { background-image: url("../assets/icons/svg/trades.svg"); }
.dicon-img.pxi-invoice,
.dlg-lead .pxi-invoice,
.prop-head .pxi-invoice { background-image: url("../assets/icons/svg/invoice.svg"); }
.dicon-img.pxi-readme,
.dlg-lead .pxi-readme,
.prop-head .pxi-readme { background-image: url("../assets/icons/svg/readme.svg"); }
.dicon-img.pxi-endings,
.dlg-lead .pxi-endings,
.prop-head .pxi-endings { background-image: url("../assets/icons/svg/endings.svg"); }
.dicon-img.pxi-terminal,
.dlg-lead .pxi-terminal,
.prop-head .pxi-terminal { background-image: url("../assets/icons/svg/terminal.svg"); }

.dicon-img.pxi-flip,
.dlg-lead .pxi-flip,
.prop-head .pxi-flip { background-image: url("../assets/icons/svg/flip.svg"); }
.dicon-img.pxi-recycle,
.dlg-lead .pxi-recycle,
.prop-head .pxi-recycle { background-image: url("../assets/icons/svg/recycle.svg"); }

/* the control panel's own icon, drawn here rather than in Track A's set:
   Track A's brief covered the eight windows, and this is a ninth object
   that arrived after it. two drawings, not one scaled — the 16 for title
   bars, taskbar buttons and the start-menu row, the 32 for the desktop
   icon and the properties head. same rule as every other icon on this
   site. a panel of controls: a machine face with two recessed sliders
   and one knob. */
.pxi-control {
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' shape-rendering='crispEdges'%3E%3Crect x='2' y='1' width='12' height='1' fill='%23413f38'/%3E%3Crect x='2' y='2' width='1' height='13' fill='%23413f38'/%3E%3Crect x='3' y='2' width='10' height='1' fill='%23eceade'/%3E%3Crect x='13' y='2' width='1' height='3' fill='%23413f38'/%3E%3Crect x='3' y='3' width='1' height='11' fill='%23eceade'/%3E%3Crect x='4' y='3' width='8' height='1' fill='%23d9d3c0'/%3E%3Crect x='12' y='3' width='1' height='2' fill='%23eceade'/%3E%3Crect x='4' y='4' width='1' height='3' fill='%23d9d3c0'/%3E%3Crect x='5' y='4' width='6' height='1' fill='%23413f38'/%3E%3Crect x='11' y='4' width='1' height='1' fill='%23d9d3c0'/%3E%3Crect x='5' y='5' width='1' height='1' fill='%23413f38'/%3E%3Crect x='6' y='5' width='2' height='1' fill='%23808080'/%3E%3Crect x='8' y='5' width='1' height='1' fill='%23413f38'/%3E%3Crect x='9' y='5' width='2' height='1' fill='%23808080'/%3E%3Crect x='11' y='5' width='1' height='1' fill='%23413f38'/%3E%3Crect x='12' y='5' width='1' height='1' fill='%23d9d3c0'/%3E%3Crect x='13' y='5' width='1' height='1' fill='%23eceade'/%3E%3Crect x='14' y='5' width='1' height='1' fill='%23413f38'/%3E%3Crect x='5' y='6' width='6' height='1' fill='%23413f38'/%3E%3Crect x='11' y='6' width='1' height='1' fill='%23d9d3c0'/%3E%3Crect x='12' y='6' width='1' height='3' fill='%23eceade'/%3E%3Crect x='13' y='6' width='1' height='3' fill='%23413f38'/%3E%3Crect x='4' y='7' width='8' height='1' fill='%23d9d3c0'/%3E%3Crect x='4' y='8' width='1' height='3' fill='%23d9d3c0'/%3E%3Crect x='5' y='8' width='6' height='1' fill='%23413f38'/%3E%3Crect x='11' y='8' width='1' height='1' fill='%23d9d3c0'/%3E%3Crect x='5' y='9' width='1' height='1' fill='%23413f38'/%3E%3Crect x='6' y='9' width='1' height='1' fill='%23808080'/%3E%3Crect x='7' y='9' width='1' height='1' fill='%23413f38'/%3E%3Crect x='8' y='9' width='3' height='1' fill='%23808080'/%3E%3Crect x='11' y='9' width='1' height='1' fill='%23413f38'/%3E%3Crect x='12' y='9' width='1' height='1' fill='%23d9d3c0'/%3E%3Crect x='13' y='9' width='1' height='1' fill='%23eceade'/%3E%3Crect x='14' y='9' width='1' height='1' fill='%23413f38'/%3E%3Crect x='5' y='10' width='6' height='1' fill='%23413f38'/%3E%3Crect x='11' y='10' width='1' height='1' fill='%23d9d3c0'/%3E%3Crect x='12' y='10' width='1' height='4' fill='%23eceade'/%3E%3Crect x='13' y='10' width='1' height='5' fill='%23413f38'/%3E%3Crect x='4' y='11' width='8' height='1' fill='%23d9d3c0'/%3E%3Crect x='4' y='12' width='2' height='2' fill='%23d9d3c0'/%3E%3Crect x='6' y='12' width='3' height='1' fill='%23413f38'/%3E%3Crect x='9' y='12' width='3' height='2' fill='%23d9d3c0'/%3E%3Crect x='6' y='13' width='1' height='1' fill='%23413f38'/%3E%3Crect x='7' y='13' width='1' height='1' fill='%23e2a33a'/%3E%3Crect x='8' y='13' width='1' height='1' fill='%23413f38'/%3E%3Crect x='3' y='14' width='10' height='1' fill='%238d8880'/%3E%3Crect x='2' y='15' width='12' height='1' fill='%23413f38'/%3E%3C/svg%3E");
}
.dicon-img.pxi-control,
.dlg-lead .pxi-control,
.prop-head .pxi-control { background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' shape-rendering='crispEdges'%3E%3Crect x='4' y='2' width='24' height='1' fill='%23413f38'/%3E%3Crect x='4' y='3' width='1' height='23' fill='%23413f38'/%3E%3Crect x='5' y='3' width='22' height='1' fill='%23eceade'/%3E%3Crect x='27' y='3' width='1' height='11' fill='%23413f38'/%3E%3Crect x='5' y='4' width='1' height='21' fill='%23eceade'/%3E%3Crect x='6' y='4' width='20' height='2' fill='%23d9d3c0'/%3E%3Crect x='26' y='4' width='1' height='10' fill='%238d8880'/%3E%3Crect x='6' y='6' width='2' height='6' fill='%23d9d3c0'/%3E%3Crect x='8' y='6' width='14' height='1' fill='%23413f38'/%3E%3Crect x='22' y='6' width='4' height='6' fill='%23d9d3c0'/%3E%3Crect x='8' y='7' width='1' height='4' fill='%23413f38'/%3E%3Crect x='9' y='7' width='12' height='1' fill='%23808080'/%3E%3Crect x='21' y='7' width='1' height='4' fill='%23413f38'/%3E%3Crect x='9' y='8' width='2' height='2' fill='%23808080'/%3E%3Crect x='11' y='8' width='2' height='2' fill='%23ffffff'/%3E%3Crect x='13' y='8' width='8' height='2' fill='%23808080'/%3E%3Crect x='9' y='10' width='12' height='1' fill='%23808080'/%3E%3Crect x='8' y='11' width='14' height='1' fill='%23413f38'/%3E%3Crect x='6' y='12' width='20' height='1' fill='%23d9d3c0'/%3E%3Crect x='6' y='13' width='2' height='4' fill='%23d9d3c0'/%3E%3Crect x='8' y='13' width='14' height='1' fill='%23413f38'/%3E%3Crect x='22' y='13' width='4' height='1' fill='%23d9d3c0'/%3E%3Crect x='8' y='14' width='1' height='2' fill='%23413f38'/%3E%3Crect x='9' y='14' width='9' height='2' fill='%23808080'/%3E%3Crect x='18' y='14' width='2' height='2' fill='%23ffffff'/%3E%3Crect x='20' y='14' width='2' height='2' fill='%23808080'/%3E%3Crect x='22' y='14' width='1' height='2' fill='%23413f38'/%3E%3Crect x='23' y='14' width='4' height='2' fill='%23d9d3c0'/%3E%3Crect x='27' y='14' width='1' height='2' fill='%238d8880'/%3E%3Crect x='28' y='14' width='1' height='2' fill='%23413f38'/%3E%3Crect x='8' y='16' width='14' height='1' fill='%23413f38'/%3E%3Crect x='22' y='16' width='4' height='1' fill='%23d9d3c0'/%3E%3Crect x='26' y='16' width='1' height='9' fill='%238d8880'/%3E%3Crect x='27' y='16' width='1' height='10' fill='%23413f38'/%3E%3Crect x='6' y='17' width='20' height='2' fill='%23d9d3c0'/%3E%3Crect x='6' y='19' width='4' height='1' fill='%23d9d3c0'/%3E%3Crect x='10' y='19' width='4' height='1' fill='%23413f38'/%3E%3Crect x='14' y='19' width='12' height='1' fill='%23d9d3c0'/%3E%3Crect x='6' y='20' width='3' height='3' fill='%23d9d3c0'/%3E%3Crect x='9' y='20' width='1' height='3' fill='%23413f38'/%3E%3Crect x='10' y='20' width='4' height='1' fill='%23e2a33a'/%3E%3Crect x='14' y='20' width='1' height='3' fill='%23413f38'/%3E%3Crect x='15' y='20' width='11' height='3' fill='%23d9d3c0'/%3E%3Crect x='10' y='21' width='1' height='1' fill='%23e2a33a'/%3E%3Crect x='11' y='21' width='2' height='1' fill='%23413f38'/%3E%3Crect x='13' y='21' width='1' height='1' fill='%23e2a33a'/%3E%3Crect x='10' y='22' width='4' height='1' fill='%23e2a33a'/%3E%3Crect x='6' y='23' width='4' height='1' fill='%23d9d3c0'/%3E%3Crect x='10' y='23' width='4' height='1' fill='%23413f38'/%3E%3Crect x='14' y='23' width='12' height='1' fill='%23d9d3c0'/%3E%3Crect x='6' y='24' width='20' height='1' fill='%23d9d3c0'/%3E%3Crect x='5' y='25' width='22' height='1' fill='%238d8880'/%3E%3Crect x='4' y='26' width='24' height='1' fill='%23413f38'/%3E%3C/svg%3E"); }

/* ---------- control panel applets ----------
   five 32px drawings, same pixel family as the rest. Date/Time's face
   is a DRAWING of a clock, not a reading of one: nothing on this site
   derives from where those hands point, and the only live clock here is
   the tray's, labelled as the visitor's own. */
.cpa {
  display: inline-block;
  width: 32px;
  height: 32px;
  flex: 0 0 32px;
  background-repeat: no-repeat;
  background-size: 100% 100%;
  image-rendering: pixelated;
}
.cpa-display { background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' shape-rendering='crispEdges'%3E%3Crect x='3' y='2' width='24' height='1' fill='%23413f38'/%3E%3Crect x='3' y='3' width='1' height='17' fill='%23413f38'/%3E%3Crect x='4' y='3' width='22' height='1' fill='%23eceade'/%3E%3Crect x='26' y='3' width='1' height='17' fill='%23413f38'/%3E%3Crect x='4' y='4' width='1' height='15' fill='%23eceade'/%3E%3Crect x='5' y='4' width='20' height='1' fill='%23d9d3c0'/%3E%3Crect x='25' y='4' width='1' height='15' fill='%238d8880'/%3E%3Crect x='5' y='5' width='1' height='12' fill='%23d9d3c0'/%3E%3Crect x='6' y='5' width='18' height='1' fill='%23413f38'/%3E%3Crect x='24' y='5' width='1' height='12' fill='%23d9d3c0'/%3E%3Crect x='6' y='6' width='1' height='10' fill='%23413f38'/%3E%3Crect x='7' y='6' width='16' height='1' fill='%2316389b'/%3E%3Crect x='23' y='6' width='1' height='10' fill='%23413f38'/%3E%3Crect x='7' y='7' width='1' height='8' fill='%2316389b'/%3E%3Crect x='8' y='7' width='14' height='1' fill='%232b6acb'/%3E%3Crect x='22' y='7' width='1' height='8' fill='%2316389b'/%3E%3Crect x='8' y='8' width='1' height='6' fill='%232b6acb'/%3E%3Crect x='9' y='8' width='12' height='6' fill='%2316389b'/%3E%3Crect x='21' y='8' width='1' height='6' fill='%232b6acb'/%3E%3Crect x='8' y='14' width='14' height='1' fill='%232b6acb'/%3E%3Crect x='7' y='15' width='16' height='1' fill='%2316389b'/%3E%3Crect x='6' y='16' width='18' height='1' fill='%23413f38'/%3E%3Crect x='5' y='17' width='20' height='2' fill='%23d9d3c0'/%3E%3Crect x='4' y='19' width='22' height='1' fill='%238d8880'/%3E%3Crect x='3' y='20' width='24' height='1' fill='%23413f38'/%3E%3Crect x='9' y='21' width='12' height='1' fill='%23413f38'/%3E%3Crect x='9' y='22' width='1' height='2' fill='%23413f38'/%3E%3Crect x='10' y='22' width='10' height='1' fill='%23d9d3c0'/%3E%3Crect x='20' y='22' width='1' height='2' fill='%23413f38'/%3E%3Crect x='10' y='23' width='10' height='1' fill='%238d8880'/%3E%3Crect x='7' y='24' width='16' height='1' fill='%23413f38'/%3E%3Crect x='7' y='25' width='1' height='3' fill='%23413f38'/%3E%3Crect x='8' y='25' width='14' height='1' fill='%23eceade'/%3E%3Crect x='22' y='25' width='1' height='3' fill='%23413f38'/%3E%3Crect x='8' y='26' width='14' height='1' fill='%23d9d3c0'/%3E%3Crect x='8' y='27' width='14' height='1' fill='%238d8880'/%3E%3Crect x='7' y='28' width='16' height='1' fill='%23413f38'/%3E%3C/svg%3E"); }
.cpa-sounds { background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' shape-rendering='crispEdges'%3E%3Crect x='14' y='3' width='2' height='1' fill='%23413f38'/%3E%3Crect x='13' y='4' width='1' height='1' fill='%23413f38'/%3E%3Crect x='14' y='4' width='1' height='1' fill='%23eceade'/%3E%3Crect x='15' y='4' width='1' height='7' fill='%23413f38'/%3E%3Crect x='23' y='4' width='1' height='5' fill='%23413f38'/%3E%3Crect x='12' y='5' width='1' height='1' fill='%23413f38'/%3E%3Crect x='13' y='5' width='1' height='1' fill='%23eceade'/%3E%3Crect x='14' y='5' width='1' height='1' fill='%23d9d3c0'/%3E%3Crect x='11' y='6' width='1' height='1' fill='%23413f38'/%3E%3Crect x='12' y='6' width='1' height='1' fill='%23eceade'/%3E%3Crect x='13' y='6' width='2' height='1' fill='%23d9d3c0'/%3E%3Crect x='18' y='6' width='1' height='2' fill='%23413f38'/%3E%3Crect x='28' y='6' width='1' height='2' fill='%23413f38'/%3E%3Crect x='10' y='7' width='1' height='1' fill='%23413f38'/%3E%3Crect x='11' y='7' width='1' height='1' fill='%23eceade'/%3E%3Crect x='12' y='7' width='3' height='1' fill='%23d9d3c0'/%3E%3Crect x='9' y='8' width='1' height='1' fill='%23413f38'/%3E%3Crect x='10' y='8' width='1' height='1' fill='%23eceade'/%3E%3Crect x='11' y='8' width='4' height='1' fill='%23d9d3c0'/%3E%3Crect x='17' y='8' width='1' height='3' fill='%23413f38'/%3E%3Crect x='19' y='8' width='1' height='11' fill='%23413f38'/%3E%3Crect x='27' y='8' width='1' height='11' fill='%23413f38'/%3E%3Crect x='2' y='9' width='7' height='1' fill='%23413f38'/%3E%3Crect x='9' y='9' width='1' height='1' fill='%23eceade'/%3E%3Crect x='10' y='9' width='5' height='2' fill='%23d9d3c0'/%3E%3Crect x='22' y='9' width='1' height='9' fill='%23413f38'/%3E%3Crect x='24' y='9' width='1' height='9' fill='%23413f38'/%3E%3Crect x='2' y='10' width='1' height='8' fill='%23413f38'/%3E%3Crect x='3' y='10' width='7' height='1' fill='%23eceade'/%3E%3Crect x='29' y='10' width='1' height='9' fill='%23413f38'/%3E%3Crect x='3' y='11' width='1' height='5' fill='%23eceade'/%3E%3Crect x='4' y='11' width='11' height='6' fill='%23d9d3c0'/%3E%3Crect x='15' y='11' width='2' height='6' fill='%23413f38'/%3E%3Crect x='3' y='16' width='1' height='1' fill='%238d8880'/%3E%3Crect x='3' y='17' width='7' height='1' fill='%238d8880'/%3E%3Crect x='10' y='17' width='5' height='2' fill='%23d9d3c0'/%3E%3Crect x='15' y='17' width='1' height='7' fill='%23413f38'/%3E%3Crect x='17' y='17' width='1' height='2' fill='%23413f38'/%3E%3Crect x='2' y='18' width='7' height='1' fill='%23413f38'/%3E%3Crect x='9' y='18' width='1' height='1' fill='%238d8880'/%3E%3Crect x='23' y='18' width='1' height='5' fill='%23413f38'/%3E%3Crect x='9' y='19' width='1' height='1' fill='%23413f38'/%3E%3Crect x='10' y='19' width='1' height='1' fill='%238d8880'/%3E%3Crect x='11' y='19' width='4' height='1' fill='%23d9d3c0'/%3E%3Crect x='18' y='19' width='1' height='2' fill='%23413f38'/%3E%3Crect x='28' y='19' width='1' height='3' fill='%23413f38'/%3E%3Crect x='10' y='20' width='1' height='1' fill='%23413f38'/%3E%3Crect x='11' y='20' width='1' height='1' fill='%238d8880'/%3E%3Crect x='12' y='20' width='3' height='1' fill='%23d9d3c0'/%3E%3Crect x='11' y='21' width='1' height='1' fill='%23413f38'/%3E%3Crect x='12' y='21' width='1' height='1' fill='%238d8880'/%3E%3Crect x='13' y='21' width='2' height='1' fill='%23d9d3c0'/%3E%3Crect x='12' y='22' width='1' height='1' fill='%23413f38'/%3E%3Crect x='13' y='22' width='1' height='1' fill='%238d8880'/%3E%3Crect x='14' y='22' width='1' height='1' fill='%23d9d3c0'/%3E%3Crect x='13' y='23' width='1' height='1' fill='%23413f38'/%3E%3Crect x='14' y='23' width='1' height='1' fill='%238d8880'/%3E%3Crect x='14' y='24' width='2' height='1' fill='%23413f38'/%3E%3C/svg%3E"); }
.cpa-network { background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' shape-rendering='crispEdges'%3E%3Crect x='2' y='2' width='13' height='1' fill='%23413f38'/%3E%3Crect x='2' y='3' width='1' height='8' fill='%23413f38'/%3E%3Crect x='3' y='3' width='11' height='1' fill='%23eceade'/%3E%3Crect x='14' y='3' width='1' height='2' fill='%23413f38'/%3E%3Crect x='3' y='4' width='1' height='6' fill='%23eceade'/%3E%3Crect x='4' y='4' width='1' height='5' fill='%23d9d3c0'/%3E%3Crect x='5' y='4' width='7' height='1' fill='%23413f38'/%3E%3Crect x='12' y='4' width='1' height='1' fill='%23d9d3c0'/%3E%3Crect x='13' y='4' width='1' height='1' fill='%238d8880'/%3E%3Crect x='5' y='5' width='1' height='3' fill='%23413f38'/%3E%3Crect x='6' y='5' width='1' height='3' fill='%2316389b'/%3E%3Crect x='7' y='5' width='4' height='3' fill='%232b6acb'/%3E%3Crect x='11' y='5' width='1' height='3' fill='%2316389b'/%3E%3Crect x='12' y='5' width='1' height='3' fill='%23413f38'/%3E%3Crect x='13' y='5' width='1' height='3' fill='%23d9d3c0'/%3E%3Crect x='14' y='5' width='1' height='3' fill='%238d8880'/%3E%3Crect x='15' y='5' width='1' height='3' fill='%23413f38'/%3E%3Crect x='5' y='8' width='7' height='1' fill='%23413f38'/%3E%3Crect x='12' y='8' width='1' height='1' fill='%23d9d3c0'/%3E%3Crect x='13' y='8' width='1' height='2' fill='%238d8880'/%3E%3Crect x='14' y='8' width='1' height='3' fill='%23413f38'/%3E%3Crect x='4' y='9' width='9' height='1' fill='%23d9d3c0'/%3E%3Crect x='3' y='10' width='11' height='1' fill='%238d8880'/%3E%3Crect x='2' y='11' width='13' height='1' fill='%23413f38'/%3E%3Crect x='2' y='12' width='1' height='3' fill='%23413f38'/%3E%3Crect x='3' y='12' width='11' height='1' fill='%23eceade'/%3E%3Crect x='14' y='12' width='1' height='3' fill='%23413f38'/%3E%3Crect x='3' y='13' width='1' height='1' fill='%23eceade'/%3E%3Crect x='4' y='13' width='3' height='1' fill='%23d9d3c0'/%3E%3Crect x='7' y='13' width='1' height='1' fill='%23c0392b'/%3E%3Crect x='8' y='13' width='1' height='1' fill='%23d9d3c0'/%3E%3Crect x='9' y='13' width='1' height='1' fill='%232b6acb'/%3E%3Crect x='10' y='13' width='4' height='1' fill='%23d9d3c0'/%3E%3Crect x='3' y='14' width='11' height='1' fill='%238d8880'/%3E%3Crect x='2' y='15' width='13' height='1' fill='%23413f38'/%3E%3Crect x='7' y='16' width='1' height='1' fill='%23413f38'/%3E%3Crect x='7' y='17' width='11' height='1' fill='%23413f38'/%3E%3Crect x='17' y='18' width='13' height='1' fill='%23413f38'/%3E%3Crect x='17' y='19' width='1' height='8' fill='%23413f38'/%3E%3Crect x='18' y='19' width='11' height='1' fill='%23eceade'/%3E%3Crect x='29' y='19' width='1' height='2' fill='%23413f38'/%3E%3Crect x='18' y='20' width='1' height='6' fill='%23eceade'/%3E%3Crect x='19' y='20' width='1' height='5' fill='%23d9d3c0'/%3E%3Crect x='20' y='20' width='7' height='1' fill='%23413f38'/%3E%3Crect x='27' y='20' width='1' height='1' fill='%23d9d3c0'/%3E%3Crect x='28' y='20' width='1' height='1' fill='%238d8880'/%3E%3Crect x='20' y='21' width='1' height='3' fill='%23413f38'/%3E%3Crect x='21' y='21' width='1' height='3' fill='%2316389b'/%3E%3Crect x='22' y='21' width='4' height='3' fill='%232b6acb'/%3E%3Crect x='26' y='21' width='1' height='3' fill='%2316389b'/%3E%3Crect x='27' y='21' width='1' height='3' fill='%23413f38'/%3E%3Crect x='28' y='21' width='1' height='3' fill='%23d9d3c0'/%3E%3Crect x='29' y='21' width='1' height='3' fill='%238d8880'/%3E%3Crect x='30' y='21' width='1' height='3' fill='%23413f38'/%3E%3Crect x='20' y='24' width='7' height='1' fill='%23413f38'/%3E%3Crect x='27' y='24' width='1' height='1' fill='%23d9d3c0'/%3E%3Crect x='28' y='24' width='1' height='2' fill='%238d8880'/%3E%3Crect x='29' y='24' width='1' height='3' fill='%23413f38'/%3E%3Crect x='19' y='25' width='9' height='1' fill='%23d9d3c0'/%3E%3Crect x='18' y='26' width='11' height='1' fill='%238d8880'/%3E%3Crect x='17' y='27' width='13' height='1' fill='%23413f38'/%3E%3Crect x='17' y='28' width='1' height='3' fill='%23413f38'/%3E%3Crect x='18' y='28' width='11' height='1' fill='%23eceade'/%3E%3Crect x='29' y='28' width='1' height='3' fill='%23413f38'/%3E%3Crect x='18' y='29' width='1' height='1' fill='%23eceade'/%3E%3Crect x='19' y='29' width='3' height='1' fill='%23d9d3c0'/%3E%3Crect x='22' y='29' width='1' height='1' fill='%23c0392b'/%3E%3Crect x='23' y='29' width='1' height='1' fill='%23d9d3c0'/%3E%3Crect x='24' y='29' width='1' height='1' fill='%232b6acb'/%3E%3Crect x='25' y='29' width='4' height='1' fill='%23d9d3c0'/%3E%3Crect x='18' y='30' width='11' height='1' fill='%238d8880'/%3E%3Crect x='17' y='31' width='13' height='1' fill='%23413f38'/%3E%3C/svg%3E"); }
.cpa-datetime { background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' shape-rendering='crispEdges'%3E%3Crect x='10' y='3' width='10' height='1' fill='%23413f38'/%3E%3Crect x='8' y='4' width='2' height='1' fill='%23413f38'/%3E%3Crect x='10' y='4' width='10' height='1' fill='%23eceade'/%3E%3Crect x='20' y='4' width='2' height='1' fill='%23413f38'/%3E%3Crect x='7' y='5' width='1' height='1' fill='%23413f38'/%3E%3Crect x='8' y='5' width='1' height='1' fill='%23eceade'/%3E%3Crect x='9' y='5' width='6' height='1' fill='%23fdfdf5'/%3E%3Crect x='15' y='5' width='1' height='2' fill='%23413f38'/%3E%3Crect x='16' y='5' width='5' height='1' fill='%23fdfdf5'/%3E%3Crect x='21' y='5' width='1' height='1' fill='%23eceade'/%3E%3Crect x='22' y='5' width='1' height='1' fill='%23413f38'/%3E%3Crect x='6' y='6' width='1' height='1' fill='%23413f38'/%3E%3Crect x='7' y='6' width='1' height='1' fill='%23eceade'/%3E%3Crect x='8' y='6' width='7' height='1' fill='%23fdfdf5'/%3E%3Crect x='16' y='6' width='6' height='1' fill='%23fdfdf5'/%3E%3Crect x='22' y='6' width='1' height='1' fill='%23eceade'/%3E%3Crect x='23' y='6' width='1' height='1' fill='%23413f38'/%3E%3Crect x='5' y='7' width='1' height='1' fill='%23413f38'/%3E%3Crect x='6' y='7' width='1' height='1' fill='%23eceade'/%3E%3Crect x='7' y='7' width='16' height='1' fill='%23fdfdf5'/%3E%3Crect x='23' y='7' width='1' height='1' fill='%23eceade'/%3E%3Crect x='24' y='7' width='1' height='1' fill='%23413f38'/%3E%3Crect x='4' y='8' width='1' height='2' fill='%23413f38'/%3E%3Crect x='5' y='8' width='1' height='2' fill='%23eceade'/%3E%3Crect x='6' y='8' width='18' height='2' fill='%23fdfdf5'/%3E%3Crect x='24' y='8' width='1' height='2' fill='%23eceade'/%3E%3Crect x='25' y='8' width='1' height='2' fill='%23413f38'/%3E%3Crect x='3' y='10' width='1' height='9' fill='%23413f38'/%3E%3Crect x='4' y='10' width='1' height='9' fill='%23eceade'/%3E%3Crect x='5' y='10' width='20' height='1' fill='%23fdfdf5'/%3E%3Crect x='25' y='10' width='1' height='5' fill='%23eceade'/%3E%3Crect x='26' y='10' width='1' height='5' fill='%23413f38'/%3E%3Crect x='5' y='11' width='8' height='1' fill='%23fdfdf5'/%3E%3Crect x='13' y='11' width='2' height='1' fill='%23413f38'/%3E%3Crect x='15' y='11' width='10' height='1' fill='%23fdfdf5'/%3E%3Crect x='5' y='12' width='9' height='1' fill='%23fdfdf5'/%3E%3Crect x='14' y='12' width='2' height='1' fill='%23413f38'/%3E%3Crect x='16' y='12' width='9' height='1' fill='%23fdfdf5'/%3E%3Crect x='5' y='13' width='10' height='1' fill='%23fdfdf5'/%3E%3Crect x='15' y='13' width='2' height='1' fill='%23413f38'/%3E%3Crect x='17' y='13' width='8' height='1' fill='%23fdfdf5'/%3E%3Crect x='5' y='14' width='1' height='2' fill='%23fdfdf5'/%3E%3Crect x='6' y='14' width='1' height='2' fill='%23413f38'/%3E%3Crect x='7' y='14' width='9' height='1' fill='%23fdfdf5'/%3E%3Crect x='16' y='14' width='2' height='1' fill='%23413f38'/%3E%3Crect x='18' y='14' width='5' height='1' fill='%23fdfdf5'/%3E%3Crect x='23' y='14' width='1' height='1' fill='%23413f38'/%3E%3Crect x='24' y='14' width='1' height='1' fill='%23fdfdf5'/%3E%3Crect x='7' y='15' width='10' height='1' fill='%23fdfdf5'/%3E%3Crect x='17' y='15' width='5' height='1' fill='%23413f38'/%3E%3Crect x='22' y='15' width='2' height='1' fill='%23fdfdf5'/%3E%3Crect x='24' y='15' width='1' height='1' fill='%23413f38'/%3E%3Crect x='25' y='15' width='1' height='1' fill='%23fdfdf5'/%3E%3Crect x='26' y='15' width='1' height='1' fill='%23eceade'/%3E%3Crect x='27' y='15' width='1' height='1' fill='%23413f38'/%3E%3Crect x='5' y='16' width='20' height='3' fill='%23fdfdf5'/%3E%3Crect x='25' y='16' width='1' height='3' fill='%23eceade'/%3E%3Crect x='26' y='16' width='1' height='3' fill='%23413f38'/%3E%3Crect x='4' y='19' width='1' height='2' fill='%23413f38'/%3E%3Crect x='5' y='19' width='1' height='2' fill='%23eceade'/%3E%3Crect x='6' y='19' width='18' height='2' fill='%23fdfdf5'/%3E%3Crect x='24' y='19' width='1' height='2' fill='%23eceade'/%3E%3Crect x='25' y='19' width='1' height='2' fill='%23413f38'/%3E%3Crect x='5' y='21' width='1' height='1' fill='%23413f38'/%3E%3Crect x='6' y='21' width='1' height='1' fill='%23eceade'/%3E%3Crect x='7' y='21' width='16' height='1' fill='%23fdfdf5'/%3E%3Crect x='23' y='21' width='1' height='1' fill='%23eceade'/%3E%3Crect x='24' y='21' width='1' height='1' fill='%23413f38'/%3E%3Crect x='6' y='22' width='1' height='1' fill='%23413f38'/%3E%3Crect x='7' y='22' width='1' height='1' fill='%23eceade'/%3E%3Crect x='8' y='22' width='6' height='1' fill='%23fdfdf5'/%3E%3Crect x='14' y='22' width='1' height='2' fill='%23413f38'/%3E%3Crect x='15' y='22' width='7' height='1' fill='%23fdfdf5'/%3E%3Crect x='22' y='22' width='1' height='1' fill='%23eceade'/%3E%3Crect x='23' y='22' width='1' height='1' fill='%23413f38'/%3E%3Crect x='7' y='23' width='1' height='1' fill='%23413f38'/%3E%3Crect x='8' y='23' width='1' height='1' fill='%23eceade'/%3E%3Crect x='9' y='23' width='5' height='1' fill='%23fdfdf5'/%3E%3Crect x='15' y='23' width='6' height='1' fill='%23fdfdf5'/%3E%3Crect x='21' y='23' width='1' height='1' fill='%23eceade'/%3E%3Crect x='22' y='23' width='1' height='1' fill='%23413f38'/%3E%3Crect x='8' y='24' width='2' height='1' fill='%23413f38'/%3E%3Crect x='10' y='24' width='10' height='1' fill='%23eceade'/%3E%3Crect x='20' y='24' width='2' height='1' fill='%23413f38'/%3E%3Crect x='10' y='25' width='10' height='1' fill='%23413f38'/%3E%3C/svg%3E"); }
.cpa-system { background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' shape-rendering='crispEdges'%3E%3Crect x='4' y='2' width='20' height='1' fill='%23413f38'/%3E%3Crect x='4' y='3' width='1' height='13' fill='%23413f38'/%3E%3Crect x='5' y='3' width='18' height='1' fill='%23eceade'/%3E%3Crect x='23' y='3' width='1' height='13' fill='%23413f38'/%3E%3Crect x='5' y='4' width='1' height='11' fill='%23eceade'/%3E%3Crect x='6' y='4' width='16' height='1' fill='%23d9d3c0'/%3E%3Crect x='22' y='4' width='1' height='11' fill='%238d8880'/%3E%3Crect x='6' y='5' width='1' height='9' fill='%23d9d3c0'/%3E%3Crect x='7' y='5' width='14' height='1' fill='%23413f38'/%3E%3Crect x='21' y='5' width='1' height='9' fill='%23d9d3c0'/%3E%3Crect x='7' y='6' width='1' height='7' fill='%23413f38'/%3E%3Crect x='8' y='6' width='12' height='1' fill='%2316389b'/%3E%3Crect x='20' y='6' width='1' height='7' fill='%23413f38'/%3E%3Crect x='8' y='7' width='1' height='5' fill='%2316389b'/%3E%3Crect x='9' y='7' width='10' height='5' fill='%232b6acb'/%3E%3Crect x='19' y='7' width='1' height='5' fill='%2316389b'/%3E%3Crect x='8' y='12' width='12' height='1' fill='%2316389b'/%3E%3Crect x='7' y='13' width='14' height='1' fill='%23413f38'/%3E%3Crect x='6' y='14' width='16' height='1' fill='%23d9d3c0'/%3E%3Crect x='5' y='15' width='18' height='1' fill='%238d8880'/%3E%3Crect x='4' y='16' width='20' height='1' fill='%23413f38'/%3E%3Crect x='2' y='17' width='26' height='1' fill='%23413f38'/%3E%3Crect x='2' y='18' width='1' height='11' fill='%23413f38'/%3E%3Crect x='3' y='18' width='24' height='1' fill='%23eceade'/%3E%3Crect x='27' y='18' width='1' height='11' fill='%23413f38'/%3E%3Crect x='3' y='19' width='1' height='9' fill='%23eceade'/%3E%3Crect x='4' y='19' width='22' height='1' fill='%23d9d3c0'/%3E%3Crect x='26' y='19' width='1' height='9' fill='%238d8880'/%3E%3Crect x='4' y='20' width='2' height='3' fill='%23d9d3c0'/%3E%3Crect x='6' y='20' width='12' height='1' fill='%23413f38'/%3E%3Crect x='18' y='20' width='8' height='3' fill='%23d9d3c0'/%3E%3Crect x='6' y='21' width='1' height='1' fill='%23413f38'/%3E%3Crect x='7' y='21' width='10' height='1' fill='%23808080'/%3E%3Crect x='17' y='21' width='1' height='1' fill='%23413f38'/%3E%3Crect x='6' y='22' width='12' height='1' fill='%23413f38'/%3E%3Crect x='4' y='23' width='22' height='1' fill='%23d9d3c0'/%3E%3Crect x='4' y='24' width='2' height='3' fill='%23d9d3c0'/%3E%3Crect x='6' y='24' width='12' height='1' fill='%23413f38'/%3E%3Crect x='18' y='24' width='4' height='3' fill='%23d9d3c0'/%3E%3Crect x='22' y='24' width='1' height='2' fill='%23413f38'/%3E%3Crect x='23' y='24' width='2' height='2' fill='%23e2a33a'/%3E%3Crect x='25' y='24' width='1' height='2' fill='%23413f38'/%3E%3Crect x='6' y='25' width='1' height='1' fill='%23413f38'/%3E%3Crect x='7' y='25' width='10' height='1' fill='%23808080'/%3E%3Crect x='17' y='25' width='1' height='1' fill='%23413f38'/%3E%3Crect x='6' y='26' width='12' height='1' fill='%23413f38'/%3E%3Crect x='22' y='26' width='4' height='1' fill='%23413f38'/%3E%3Crect x='4' y='27' width='22' height='1' fill='%23d9d3c0'/%3E%3Crect x='3' y='28' width='24' height='1' fill='%238d8880'/%3E%3Crect x='2' y='29' width='26' height='1' fill='%23413f38'/%3E%3C/svg%3E"); }

/* run: a window with a prompt caret in it. the caret is what the dialog
   actually is — a place to type a name — so the icon says the same thing
   the dialog says, which is nothing at all. */
.pxi-run {
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' shape-rendering='crispEdges'%3E%3Crect x='2' y='3' width='12' height='10' fill='%23413f38'/%3E%3Crect x='3' y='4' width='10' height='8' fill='%23fdfdf5'/%3E%3Crect x='3' y='4' width='10' height='2' fill='%232f6ba8'/%3E%3Crect x='5' y='7' width='1' height='1' fill='%23163d6b'/%3E%3Crect x='6' y='8' width='1' height='1' fill='%23163d6b'/%3E%3Crect x='5' y='9' width='1' height='1' fill='%23163d6b'/%3E%3Crect x='8' y='9' width='3' height='1' fill='%23163d6b'/%3E%3C/svg%3E");
}

/* the "cannot find" dialog's icon. a plain stop mark: no red alarm
   colour, since nothing on this site failed — a name was typed and it
   does not exist. */
.pxi-stop {
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' shape-rendering='crispEdges'%3E%3Crect x='5' y='2' width='6' height='1' fill='%23413f38'/%3E%3Crect x='3' y='3' width='2' height='1' fill='%23413f38'/%3E%3Crect x='11' y='3' width='2' height='1' fill='%23413f38'/%3E%3Crect x='2' y='4' width='1' height='8' fill='%23413f38'/%3E%3Crect x='13' y='4' width='1' height='8' fill='%23413f38'/%3E%3Crect x='3' y='12' width='2' height='1' fill='%23413f38'/%3E%3Crect x='11' y='12' width='2' height='1' fill='%23413f38'/%3E%3Crect x='5' y='13' width='6' height='1' fill='%23413f38'/%3E%3Crect x='5' y='3' width='6' height='1' fill='%238d8d86'/%3E%3Crect x='3' y='4' width='10' height='8' fill='%238d8d86'/%3E%3Crect x='5' y='12' width='6' height='1' fill='%238d8d86'/%3E%3Crect x='5' y='5' width='1' height='1' fill='%23fdfdf5'/%3E%3Crect x='6' y='6' width='1' height='1' fill='%23fdfdf5'/%3E%3Crect x='7' y='7' width='2' height='2' fill='%23fdfdf5'/%3E%3Crect x='9' y='9' width='1' height='1' fill='%23fdfdf5'/%3E%3Crect x='10' y='10' width='1' height='1' fill='%23fdfdf5'/%3E%3Crect x='10' y='5' width='1' height='1' fill='%23fdfdf5'/%3E%3Crect x='9' y='6' width='1' height='1' fill='%23fdfdf5'/%3E%3Crect x='6' y='9' width='1' height='1' fill='%23fdfdf5'/%3E%3Crect x='5' y='10' width='1' height='1' fill='%23fdfdf5'/%3E%3C/svg%3E");
}

/* the letter x, drawn — a letter is nobody's mark. used for the profile
   row in the start menu. */
.pxi-x {
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' shape-rendering='crispEdges'%3E%3Crect x='3' y='3' width='2' height='2' fill='%23413f38'/%3E%3Crect x='11' y='3' width='2' height='2' fill='%23413f38'/%3E%3Crect x='4' y='4' width='2' height='2' fill='%23413f38'/%3E%3Crect x='10' y='4' width='2' height='2' fill='%23413f38'/%3E%3Crect x='5' y='5' width='2' height='2' fill='%23413f38'/%3E%3Crect x='9' y='5' width='2' height='2' fill='%23413f38'/%3E%3Crect x='6' y='6' width='4' height='4' fill='%23413f38'/%3E%3Crect x='5' y='9' width='2' height='2' fill='%23413f38'/%3E%3Crect x='9' y='9' width='2' height='2' fill='%23413f38'/%3E%3Crect x='4' y='10' width='2' height='2' fill='%23413f38'/%3E%3Crect x='10' y='10' width='2' height='2' fill='%23413f38'/%3E%3Crect x='3' y='11' width='2' height='2' fill='%23413f38'/%3E%3Crect x='11' y='11' width='2' height='2' fill='%23413f38'/%3E%3C/svg%3E");
}

/* an external destination: a box being left by an arrow. used for the
   navigation rows (solscan, pump.fun) — a place, not a claim. */
.pxi-ext {
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' shape-rendering='crispEdges'%3E%3Crect x='2' y='5' width='1' height='9' fill='%23413f38'/%3E%3Crect x='2' y='5' width='7' height='1' fill='%23413f38'/%3E%3Crect x='2' y='13' width='9' height='1' fill='%23413f38'/%3E%3Crect x='10' y='9' width='1' height='4' fill='%23413f38'/%3E%3Crect x='8' y='2' width='6' height='1' fill='%23413f38'/%3E%3Crect x='13' y='2' width='1' height='6' fill='%23413f38'/%3E%3Crect x='12' y='3' width='1' height='1' fill='%23413f38'/%3E%3Crect x='11' y='4' width='1' height='1' fill='%23413f38'/%3E%3Crect x='10' y='5' width='1' height='1' fill='%23413f38'/%3E%3Crect x='9' y='6' width='1' height='1' fill='%23413f38'/%3E%3Crect x='8' y='7' width='1' height='1' fill='%23413f38'/%3E%3C/svg%3E");
}

/* title-bar icon: the 5px gap comes from .title-bar-text's flex gap */
.tbi {
  width: 16px;
  height: 16px;
  flex: 0 0 16px;
}

/* ============================================================
   DESKTOP — present at every width once js adds body.is-desktop,
   which now happens on every real load, immediately (SITE-SPEC §2).
   `body.is-compact-desktop` (< 1024px) is layered on top of this,
   further down, for the mobile-only rules: hiding maximize/restore
   and shrinking the taskbar buttons to fit.
   ============================================================ */

body.is-desktop { overflow: hidden; }
body.is-desktop #shell { display: none; }

#desktop {
  position: fixed;
  inset: 0 0 28px 0;   /* clear of the taskbar, which is 28px in 95 */
  overflow: hidden;
  /* the wallpaper. Track A's `doug-crt-scanline.svg`, calibrated against
     `reference-images/Wallpaper/crt scanline wallpaper.jpg` and kept by
     PLAN-DE-MATCH §7.3. adopted 2026-09-01 (Track F) over the
     hand-rolled css it replaces, which is preserved below.

     compared side by side in the browser at 700x480 and at 375px: the
     asset wins on the one thing that matters here, which is that it
     reads as a lit tube rather than as graph paper. the css version's
     26px grid is even and everywhere, which is exactly the failure its
     own comment warned about; the asset's grid is 48px at 5% and the
     glow does the work.

     no vendor bitmap: this is an original file Track A drew, and the
     "Attention IP" rule is untouched (DECISIONS.md). a wallpaper is not
     chrome — the flat grey rule governs the window frame, not the
     ground behind it, which is why a glow is allowed here and nowhere
     else (SITE-SPEC §5).

     the background-color stays as the fallback: if the file ever fails
     to load, the ground is the same navy the asset is built on, never
     a white flash.

     what was NOT done, against site/assets/README.md's suggestion:
     `#desktop::after` is KEPT, not zeroed. Measured rather than assumed
     — the svg's scanline is a 1px line in a 3px pattern at 1920 user
     units, so `cover` resamples it to well under a pixel at every real
     viewport and it stops being a scanline at all, becoming a uniform
     ~3% darkening. The ::after layer is the only one that lands on exact
     device pixels, and it is also the only one that reaches the windows
     (z-index 1900), which is the CRT behaviour Track D chose
     deliberately. A/B'd with it on and off: no visible doubling. */
  background-color: #16233f;
  background-image: url("../assets/wallpaper/doug-crt-scanline.svg");
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

/* the hand-rolled ground the asset replaced, kept readable rather than
   deleted: it is the css `doug-crt-scanline.svg` was drawn from, and it
   is the one-line fallback if the file is ever pulled.

.no-wallpaper-asset #desktop {
  background-image:
    linear-gradient(rgba(60, 110, 180, 0.26) 1px, transparent 1px),
    linear-gradient(90deg, rgba(60, 110, 180, 0.26) 1px, transparent 1px),
    radial-gradient(circle at 78% 68%, rgba(120, 180, 255, 0.28), transparent 45%),
    radial-gradient(circle at 15% 25%, rgba(120, 180, 255, 0.16), transparent 40%);
  background-size: 26px 26px, 26px 26px, 100% 100%, 100% 100%;
}
*/

/* scanlines. z-index puts them over the windows as well as the wallpaper,
   which is what a crt would do; the taskbar sits outside #desktop and so
   stays clean. windows are raised from z-index 20 upward, one step per
   raise, so 1900 is well clear of any real session.

   3%, up from the 1.5% trial. measured off a 1:1 capture of the bare
   wallpaper, which is the only surface where a white overlay this faint
   has room to register: at 1.5% a lit line moved the ground by +3 of 255
   per channel, under the threshold where a display's own dithering is
   louder than the effect — a paint layer that returned nothing. at 3% it
   is +6/+7, which reads as crt texture at 1:1. 5% is +11 and starts to
   look like a filter over the picture rather than a property of it.

   over a window face (#c0c0c0) the same 3% is worth +1, because the
   overlay is white and the face nearly is. that asymmetry is the reason
   this is safe: the texture lands on the wallpaper, where there is
   nothing to read, and effectively skips the mono log text, which is the
   one thing on this site that must stay legible. */
#desktop::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1900;
  pointer-events: none;
  background: repeating-linear-gradient(0deg,
              rgba(255, 255, 255, 0.03) 0 1px, transparent 1px 3px);
}

.desk-area { position: absolute; inset: 0; }

/* ---------- desktop icons ---------- */

.desk-icons {
  position: absolute;
  top: 16px;
  left: 12px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  z-index: 1;
}

.dicon {
  all: unset;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  width: 92px;
  padding: 6px 2px;
  cursor: var(--cur-arrow), default;
  text-align: center;
}

.dicon-img { width: 32px; height: 32px; }

.dicon-label {
  font-family: var(--ui);
  font-size: 11px;
  color: #fff;
  /* one hard pixel, no blur. 95 drew no shadow under a desktop label at
     all — the soft halo is an xp mark, and on an 11px bitmap face it
     costs the type its edges. the shadow stays because this wallpaper is
     lit in the middle and white alone would not hold there; it just
     stops being a glow. */
  text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.9);
  padding: 1px 3px;
}

.dicon.is-sel .dicon-label { background: var(--sel); }
.dicon:focus-visible .dicon-label { outline: 1px dotted #fff; outline-offset: 1px; }

/* the icon's focus mark is the dotted rectangle on its label, below —
   which is where 95 drew it. 98.css's `button:focus` would put a second,
   black one round the whole 96x64 cell, invisible against the wallpaper
   and wrong even where it showed. */
.dicon:focus { outline: none; }

/* 95 explorer did not wash an icon on hover — the hot-tracking highlight
   arrived with the desktop update, and 95's own feedback was the solid
   selection fill on click and nothing before it. so the hover state is a
   dotted focus rectangle, which is what the era actually drew, and the
   solid navy fill stays reserved for a real selection. */
.dicon:hover:not(.is-sel) .dicon-label {
  outline: 1px dotted rgba(255, 255, 255, 0.75);
  outline-offset: 0;
}

/* ---------- windows ---------- */

.dwin {
  position: absolute;
  display: flex;
  flex-direction: column;
  min-width: 300px;
  min-height: 180px;
  /* 95 drew no drop shadow at all. one tight, hard-edged offset stays,
     and only because the wallpaper is near-black: without it a grey
     window's bottom-right bevel is the same value as the ground behind
     it and the frame stops reading as a frame. no blur, no spread —
     a soft halo is the glow SITE-SPEC §5 rules out. */
  box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.35);
}

/* compact (< 1024px, SITE-SPEC §2): every window is full-area by
   construction (doug.js's layoutWin sets width/height/left/top inline),
   so the 300px floor above exists only to protect the freeform desktop
   from an accidental too-small rect — it has nothing to guard against
   here and could only ever fight the inline size on a genuinely tiny
   viewport. dropped, not raised: there is no drag to lose either. */
body.is-compact-desktop .dwin { min-width: 0; min-height: 0; }

/* the maximize/restore control has nothing to mean in compact — every
   window already fills the screen, and there is no smaller rect to
   restore to. hidden rather than removed, so the close/minimize buttons
   keep their exact freeform positions if the viewport ever crosses back. */
body.is-compact-desktop .dwin .title-bar-controls button[aria-label="Maximize"],
body.is-compact-desktop .dwin .title-bar-controls button[aria-label="Restore"] {
  display: none;
}

/* the front window sits visibly above the rest — the same hierarchy the
   inactive title-bar colour (below) already carries, one pixel deeper. */
.dwin.is-front {
  box-shadow: 3px 3px 0 rgba(0, 0, 0, 0.45);
}

.dwin > .title-bar {
  flex: 0 0 auto;
  user-select: none;
  -webkit-user-select: none;
}

/* while a window is being dragged, nothing on the page is selectable —
   a drag must not smear a text selection across the desktop. */
body.is-dragging, body.is-dragging * {
  user-select: none !important;
  -webkit-user-select: none !important;
}

.dwin .title-bar-text {
  display: flex;
  align-items: center;
  font-size: 11px;
}

/* inactive chrome. the xp version drained a gradient with a filter;
   95 has no gradient to drain — an unfocused caption is flat #808080
   with the pale grey text the era used, and that is the whole change. */
.dwin:not(.is-front) .title-bar { background: var(--nav-off); }
.dwin:not(.is-front) .title-bar-text { color: var(--face); }

.dwin-body {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  margin: 4px 3px 3px;
}

.dwin > .status-bar { flex: 0 0 auto; margin: 0 3px 3px; }

/* ---------- taskbar ---------- */

/* 95's taskbar: the face colour, one raised edge along the top, and
   nothing else. the xp bar painted a seven-stop blue gradient here. */
#taskbar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  height: 28px;
  z-index: 2000;
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 2px;
  background: var(--face);
  box-shadow: inset 0 1px var(--hi), inset 0 2px var(--face-lit);
}

/* 95's start button: an ordinary raised grey button with a mark and a
   bold lowercase word. no orb, no green pill, no italics — those are
   2001. the mark is the doug os head from Track A, drawn as the site's
   own art (site/assets/logo/doug-os-mark-16.svg). */
.start-btn {
  all: unset;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  gap: 4px;
  height: 22px;
  padding: 0 6px 0 4px;
  cursor: var(--cur-arrow), default;
  font-family: var(--ui);
  font-size: 11px;
  font-weight: 700;
  color: var(--ink);
  background: var(--face);
  box-shadow: var(--bevel-out);
}

.start-btn::before {
  content: '';
  width: 16px;
  height: 16px;
  flex: 0 0 16px;
  /* the 16-grid drawing, not the 26x30 one. `contain` on the 26x30 fitted
     it to 13.87x16 css px — 1.067 screen pixels per drawn pixel at DPR 2,
     so its pixels alternated one and two wide and the mark read blocky
     beside the crisp 16px icons on the taskbar next to it. this file is
     drawn on the grid it is displayed at, so one drawn pixel is exactly
     two screen pixels and `contain` has nothing left to resample. */
  background: url("../assets/logo/doug-os-mark-16.svg") center / contain no-repeat;
  image-rendering: pixelated;
}

.start-btn:active,
.start-btn[aria-expanded="true"] {
  box-shadow: var(--bevel-in);
  /* a pressed 95 button nudges its label down-right by one pixel */
  padding: 1px 5px 0 5px;
}

.start-btn:focus-visible { outline: 1px dotted var(--ink); outline-offset: -4px; }

/* the strip scrolls; it does not clip. measured with all nine windows
   open: at 375px four buttons fell off the end of the bar and at 1280px
   one did, and `overflow: hidden` meant they were not merely narrow,
   they were gone. below 1024px the taskbar is the only way to reach a
   window at all (SITE-SPEC §2), so a button off the end is a window
   that cannot be reached. the buttons still shrink first, exactly as 95
   shrank them; the strip only starts scrolling once they are at their
   floor, and the half-button at the right edge is what says so.

   no visible scrollbar: a 17px one inside a 24px strip would eat the
   bar. tabbing to a button off-screen still scrolls it into view. */
.task-btns {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 3px;
  padding: 0 2px;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
}

.task-btns::-webkit-scrollbar { display: none; }

/* a 95 task button is the same raised grey button as everything else,
   with the window's own 16px icon and its title in black. */
.dtask {
  all: unset;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  gap: 4px;
  height: 22px;
  padding: 0 5px;
  min-width: 130px;
  max-width: 190px;
  cursor: var(--cur-arrow), default;
  font-family: var(--ui);
  font-size: 11px;
  color: var(--ink);
  background: var(--face);
  box-shadow: var(--bevel-out);
}

.dtask .pxi { width: 16px; height: 16px; flex: 0 0 16px; }

/* below 1024px the taskbar is the only way to switch windows (SITE-SPEC
   §2) and the bar itself is narrower than the desktop it borrowed its
   130px floor from. real xp shrank buttons to fit rather than clip them;
   this is that, with the ellipsis .dtask-label already had doing the
   rest — a button never drops below icon-plus-a-few-characters wide. */
/* below 1024px the taskbar is the window switcher, so a button has to
   still read as a name. the floor was 40px — icon, one character and an
   ellipsis, which tells a visitor nothing — and is now 64, which is
   about five characters. past four windows the strip scrolls rather
   than squeezing the sixth name into three pixels. */
@media (max-width: 1023px) {
  .task-btns { gap: 3px; padding: 0 3px; }
  .dtask { flex: 1 1 0; min-width: 64px; max-width: 150px; padding: 0 6px; }
}

.dtask-label {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* the pressed state 95 used for the front window's button: sunken, and
   the face dithered one shade darker with a 50% checker — a real 95
   detail, drawn here rather than faked with a flat tint. */
.dtask.is-on {
  box-shadow: var(--bevel-in);
  padding: 1px 4px 0 6px;
  background-color: var(--face);
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2' height='2' shape-rendering='crispEdges'%3E%3Crect width='1' height='1' fill='%23ffffff'/%3E%3Crect x='1' y='1' width='1' height='1' fill='%23ffffff'/%3E%3C/svg%3E");
}

/* a raised 95 control has exactly one pointer state: pressed. no hover
   brightening — 95 had none, and the button already reads as raised. */
.dtask:active {
  box-shadow: var(--bevel-in);
  padding: 1px 4px 0 6px;
}

.dtask:focus-visible { outline: 1px dotted var(--ink); outline-offset: -4px; }

/* the 95 tray: a sunken well on the face colour, black text. */
.tray {
  flex: 0 0 auto;
  align-self: stretch;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 6px;
  color: var(--ink);
  font-family: var(--ui);
  font-size: 11px;
  background: var(--face);
  box-shadow: var(--edge-in);
}

.tray-clock { min-width: 52px; text-align: right; }

.sound-btn {
  all: unset;
  width: 16px;
  height: 16px;
  cursor: var(--cur-arrow), default;
  background-repeat: no-repeat;
  background-size: 100% 100%;
  image-rendering: pixelated;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' shape-rendering='crispEdges'%3E%3Crect x='2' y='6' width='3' height='4' fill='%23ffffff'/%3E%3Crect x='5' y='5' width='1' height='6' fill='%23ffffff'/%3E%3Crect x='6' y='4' width='1' height='8' fill='%23ffffff'/%3E%3Crect x='7' y='3' width='1' height='10' fill='%23ffffff'/%3E%3Crect x='10' y='6' width='1' height='4' fill='%23ffffff'/%3E%3Crect x='12' y='4' width='1' height='8' fill='%23ffffff'/%3E%3C/svg%3E");
}

.sound-btn.is-off {
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' shape-rendering='crispEdges'%3E%3Crect x='2' y='6' width='3' height='4' fill='%23ffffff'/%3E%3Crect x='5' y='5' width='1' height='6' fill='%23ffffff'/%3E%3Crect x='6' y='4' width='1' height='8' fill='%23ffffff'/%3E%3Crect x='7' y='3' width='1' height='10' fill='%23ffffff'/%3E%3Crect x='10' y='5' width='1' height='1' fill='%23ffffff'/%3E%3Crect x='11' y='6' width='1' height='1' fill='%23ffffff'/%3E%3Crect x='12' y='7' width='1' height='2' fill='%23ffffff'/%3E%3Crect x='11' y='9' width='1' height='1' fill='%23ffffff'/%3E%3Crect x='10' y='10' width='1' height='1' fill='%23ffffff'/%3E%3Crect x='12' y='5' width='1' height='1' fill='%23ffffff'/%3E%3Crect x='13' y='6' width='1' height='1' fill='%23ffffff'/%3E%3Crect x='13' y='9' width='1' height='1' fill='%23ffffff'/%3E%3Crect x='12' y='10' width='1' height='1' fill='%23ffffff'/%3E%3C/svg%3E");
}

.sound-btn:focus-visible { outline: 1px dotted var(--ink); outline-offset: 2px; }

/* ---------- start menu ----------
   the authentic 95 layout: ONE column with a vertical banner down the
   left edge, and no identity strip at all. windows 95 had no account
   picture and no username in a start menu — the two-column strip built
   on 2026-08-21 was a 2001 invention and it is gone with the theme.
   SITE-SPEC §5.5 (rewritten 2026-09-01), DECISIONS.md "Le piège du
   menu Démarrer". */

.startmenu {
  position: fixed;
  left: 2px;
  bottom: 28px;
  z-index: 2100;
  display: flex;
  align-items: stretch;
  width: 258px;
  background: var(--face);
  box-shadow: var(--bevel-out);
}

.startmenu[hidden] { display: none; }

/* the banner. flat navy, not the vertical ramp the real one carried and
   the mockup draws: SITE-SPEC §5's "no gradients at all in the chrome"
   retires that exception rather than widening it, and one flat navy is
   the same navy every caption on this desktop already wears. */
.sm-banner {
  flex: 0 0 22px;
  background: var(--nav);
  color: #fff;
  font-family: var(--ui);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.4px;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: 6px 0 8px;
  /* bottom-to-top, the way 95 set it */
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  user-select: none;
  -webkit-user-select: none;
}

.sm-list {
  flex: 1 1 auto;
  min-width: 0;
  list-style: none;
  margin: 0;
  padding: 2px;
}

.sm-item {
  all: unset;
  display: flex;
  align-items: center;
  gap: 7px;
  box-sizing: border-box;
  width: 100%;
  padding: 5px 14px 5px 6px;
  cursor: var(--cur-arrow), default;
  font-family: var(--ui);
  font-size: 11px;
  color: var(--ink);
  text-decoration: none;
}

.sm-item .pxi { width: 16px; height: 16px; flex: 0 0 16px; }

/* 95's menu highlight: a solid navy bar, white text, no border and no
   rounding. the same --sel every other menu on this site uses. */
.sm-item:hover,
.sm-item:focus-visible { background: var(--sel); color: #fff; outline: none; }

/* the etched separator, drawn the same way as every other rule in the
   95 chrome: one shadow line with one highlight line under it. */
.sm-sep {
  height: 2px;
  margin: 3px 2px;
  background: linear-gradient(var(--sh) 0 1px, var(--hi) 1px 2px);
}

/* ---------- context menu ----------
   right-click on a desktop icon or a taskbar button. same chrome as
   every other menu on this site: a raised grey box, a navy highlight,
   etched separators. text only — 95's own file context menu carried no
   icons, and the default item is bold, which is how 95 said which row
   Enter runs.

   FIVE OF THE NINE ROWS ARE DISABLED and look identical while disabled:
   Open with…, Cut, Create Shortcut, Delete, Rename. that is the point of
   the menu (SITE-SPEC §5.5, decision C7) and the greying must stay
   uniform — Delete singled out with any treatment of its own would turn
   a limitation into a punchline. the engraved grey-with-white-shadow is
   the same disabled state 98.css gives a disabled button, which is the
   same state ENDINGS.TXT's OK / Cancel / Help already wear. */

.ctxmenu {
  position: fixed;
  z-index: 2500;
  min-width: 150px;
  padding: 2px;
  background: var(--face);
  box-shadow: var(--bevel-out), 2px 2px 0 rgba(0, 0, 0, 0.35);
}

.ctx-item {
  all: unset;
  box-sizing: border-box;
  display: block;
  width: 100%;
  padding: 4px 22px 4px 20px;
  cursor: var(--cur-arrow), default;
  font-family: var(--ui);
  font-size: 11px;
  color: var(--ink);
  white-space: nowrap;
}

.ctx-item.is-default { font-weight: 700; }

.ctx-item:hover:not(:disabled),
.ctx-item:focus-visible { background: var(--sel); color: #fff; outline: none; }

/* the engraved disabled label 95 drew: grey with a white shadow one
   pixel down and right. it says "not available" and nothing else. */
.ctx-item:disabled {
  color: var(--ink-dis);
  text-shadow: 1px 1px var(--hi);
}

.ctx-sep {
  height: 2px;
  margin: 3px 2px;
  background: linear-gradient(var(--sh) 0 1px, var(--hi) 1px 2px);
}

/* ---------- recycle bin ----------
   an explorer pane with nothing in it. no placeholder text, no "this
   folder is empty" line: the emptiness is the object, and a caption
   explaining it would be the site telling a joke instead of showing one.
   the two status-bar figures are true by construction — there is no
   code path on this site that puts anything in here. */

.bin-view {
  flex: 1 1 auto;
  min-height: 0;
  background: #fff;
  box-shadow: var(--bevel-in);
}

/* ---------- dialogs: run, properties, "cannot find" ----------
   real 95 dialogs: face-coloured, one close button, buttons bottom-right.
   they sit above the windows and the taskbar but below the screensaver,
   the boot screen and the bsod, each of which is a whole-screen state. */

.dlg {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -55%);
  z-index: 2600;
  width: min(390px, calc(100vw - 32px));
  box-shadow: 3px 3px 0 rgba(0, 0, 0, 0.45);
}

.dlg .title-bar-text { display: flex; align-items: center; gap: 4px; font-size: 11px; }

.dlg-body { padding: 14px 12px 4px; }

/* the icon-beside-prose row every xp dialog opens with */
.dlg-lead { display: flex; gap: 12px; align-items: flex-start; }

.dlg-lead .pxi { width: 32px; height: 32px; flex: 0 0 32px; }

.dlg-lead p {
  margin: 0;
  font-family: var(--ui);
  font-size: 11px;
  line-height: 1.55;
  color: var(--ink);
}

.dlg-field {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 14px;
}

.dlg-field label {
  flex: 0 0 auto;
  font-family: var(--ui);
  font-size: 11px;
  color: var(--ink);
}

.dlg-field input {
  flex: 1 1 auto;
  min-width: 0;
  font-family: var(--mono);
  -webkit-font-smoothing: auto;   /* outline face at 11-12px — see body */
  font-size: 12px;
  padding: 3px 4px;
}

.dlg-buttons {
  display: flex;
  justify-content: flex-end;
  gap: 6px;
  /* the same 8px `.window-body` puts either side of `.dlg-body`, because
     this row is that body's sibling and not inside it: without it the
     buttons ended eight pixels right of the prose and the field above
     them. measured on the run dialog — field right edge 336, Cancel's
     344. one content edge for the whole sheet now. */
  margin: 0 8px;
  padding: 12px 12px 12px;
}

.dlg-buttons button {
  font-family: var(--ui);
  font-size: 11px;
}

/* ---------- properties ----------
   every row here is measured or trivially true. nothing is filled in to
   complete the form: a field with no true value renders the same em dash
   the rest of the site uses. */

.prop-head {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 4px 2px 12px;
  /* the etched separator 95 drew between a sheet's head and its rows */
  border-bottom: 1px solid var(--sh);
  box-shadow: 0 1px var(--hi);
}

.prop-head .pxi { width: 32px; height: 32px; flex: 0 0 32px; }

.prop-head b {
  font-family: var(--ui);
  font-size: 11px;
  font-weight: 700;
  color: var(--ink);
  word-break: break-all;
}

.prop-rows { margin: 0; padding: 10px 0 4px; }

/* the 2px inset lives on the row, not on the list: `.prop-sep` and the
   etched rule under `.prop-head` are the same rule drawn twice and have
   to be the same width. the text does not move. */
.prop-row { display: flex; gap: 10px; padding: 3px 2px; }

.prop-row dt {
  flex: 0 0 104px;
  font-family: var(--ui);
  font-size: 11px;
  color: var(--ink-soft);
}

.prop-row dd {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  font-family: var(--mono);
  -webkit-font-smoothing: auto;   /* outline face at 11-12px — see body */
  font-size: 11px;
  color: var(--ink);
  word-break: break-word;
}

.prop-row dd.is-empty { color: var(--ink-dis); }

.prop-sep {
  height: 2px;
  margin: 9px 0;
  background: linear-gradient(var(--sh) 0 1px, var(--hi) 1px 2px);
}

.prop-attrs { display: flex; gap: 18px; }

.prop-attrs span {
  display: flex;
  align-items: center;
  gap: 5px;
  font-family: var(--ui);
  font-size: 11px;
  color: var(--ink-soft);
}


/* ---------- control panel: the folder of applets ----------
   a 95 folder view: icons on a grid inside the window's list pane, a
   caption under each. the pane is white and sunken because that is what
   an explorer client area is — the recycle bin two icons away on this
   same desktop is already drawn that way, and this window's own status
   bar counts "5 objects" in the same explorer language. it used to sit
   straight on the face colour, which made two folders of the same kind
   look like two different kinds of window.

   the three disabled applets are greyed by the `disabled` attribute
   alone — no handler to remove, no tab stop, no message. they read as
   one family of things this machine cannot do rather than as three
   separate jokes. */

.cpl {
  /* fills the window, exactly like `.bin-view` does */
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  gap: 10px 4px;
  padding: 10px 6px;
  background: #fff;
  box-shadow: var(--bevel-in);
}

.cpl-item {
  all: unset;
  box-sizing: border-box;
  width: 96px;
  padding: 5px 2px 4px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  cursor: var(--cur-arrow), default;
  text-align: center;
  font-family: var(--ui);
  font-size: 11px;
  color: var(--ink);
}

.cpl-label { display: block; line-height: 1.25; }

.cpl-item.is-sel .cpl-label {
  background: var(--sel);
  color: #fff;
}

.cpl-item.is-sel .cpl-img { filter: brightness(0.82) saturate(1.35); }

.cpl-item:focus-visible { outline: 1px dotted var(--ink); outline-offset: -2px; }

/* grey ink, and the icon loses its colour with it the way 95 dithered a
   disabled glyph. no engraved white shadow here, unlike the disabled
   menu rows: that shadow only reads against the face colour, and this
   pane is white paper. explorer greyed a disabled item flat too. */
.cpl-item:disabled .cpl-label {
  color: var(--ink-dis);
}

.cpl-item:disabled .cpl-img {
  filter: grayscale(1) opacity(0.55);
}

/* the sounds sheet: one checkbox, no prose. */
.cpl-check {
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: var(--ui);
  font-size: 11px;
  color: var(--ink);
}


/* ---------- about doug os ----------
   PARKED-DECISIONS §2. the wordmark Track A delivered, over the same
   sunken group box 95 put a machine's facts in. no row here states a
   number this site cannot check: `interpreted` comes from osStatus(),
   the build seed is the wallet truncated the way the status bar
   truncates it, and an unset wallet renders the same em dash it
   renders everywhere else. */

.about-mark {
  width: 144px;
  height: 40px;
  margin: 2px auto 14px;
  background: url("../assets/logo/doug-os.svg") center/contain no-repeat;
  image-rendering: pixelated;
}

/* the group box the mockup draws the rows inside. `--edge-in`, not
   `--bevel-in`: the deep two-pixel well is what a *white* text area wears
   on this site (the invoice sheet, the bin). a
   face-coloured group box is etched with one pixel, which is what
   ENDINGS.TXT's `.ending` boxes already are — the same construct had two
   different depths until now. */
.about-rows {
  padding: 10px 12px;
  box-shadow: var(--edge-in);
}

.about-rows .prop-row dt { flex: 0 0 88px; }

/* ---------- screensaver ----------
   pure motion. it states nothing, carries no number, and shows only in
   freeform (DESK.compact false, SITE-SPEC §2/§5.5) — a device narrow
   enough to run compact already has its own lock screen. see SAVER in
   doug.js. */

#saver {
  position: fixed;
  inset: 0;
  z-index: 2900;
  background: #000;
  cursor: none;
}

#saver[hidden] { display: none; }

#saver canvas { display: block; width: 100%; height: 100%; }

/* ============================================================
   BOOT — black, vga, skippable. a preview, never a gate.

   restyled 2026-09-01 against `doug os bootup.jpg`
   (PLAN-DE-MATCH §7.4): centred column, the post log, then
   "Doug OS is starting…" with a block cursor, then the bar,
   with the copyright pinned at the foot. no login screen —
   the mockups show one and it is explicitly out. no new
   state: same overlay, same skip, same reduced-motion path.
   ============================================================ */

#boot {
  position: fixed;
  inset: 0;
  z-index: 3000;
  background: #000;
  cursor: var(--cur-hand), pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

#boot[hidden] { display: none; }

#boot::after {
  /* faint scanlines. texture, not decoration. */
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: repeating-linear-gradient(0deg,
              rgba(255, 255, 255, 0.025) 0 1px, transparent 1px 3px);
}

#boot.boot-out { opacity: 0; transition: opacity 0.24s linear; }

.boot-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: max(30px, env(safe-area-inset-top)) 26px 30px;
  max-width: 680px;
}

.boot-log {
  /* the post block stays left-aligned inside a centred column: a machine
     printing checks down the page, not a paragraph. */
  align-self: center;
  text-align: left;
  /* and it is the size of the finished log from the first frame. without
     this the block grew as it typed and the centred column slid under
     the reader — measured at 375px, eighty pixels left over the first
     second and a line's worth down on every line after it. 43ch is the
     longest line ("sell instruction .......... not implemented") and
     14.4em is nine lines at this line-height: both track LINES in
     doug.js's bootSequence, and move if that list does. */
  width: 43ch;
  max-width: 100%;
  min-height: 14.4em;
  margin: 0;
  padding: 0;
  background: none;
  box-shadow: none;
  color: #c0c0c0;
  font-size: 15px;
  line-height: 1.6;
  white-space: pre-wrap;
  word-break: break-word;
}

.boot-log, .boot-log *, .boot-title, .boot-enter, .boot-foot,
.bsod-text, .bsod-text * {
  font-family: "Perfect DOS VGA 437 Win", var(--mono);
}

/* the block cursor rides the log while it is still typing, then hands
   over to the title's own one. */
.boot-log::after {
  content: '█';
  color: #c0c0c0;
  animation: boot-blink 1s steps(1) infinite;
}

/* once the post log is done, the title's cursor is the only one on the
   screen — two blinking blocks would be two machines. `boot-typed` is
   set by ready(), the same call that unhides the title. */
#boot.boot-typed .boot-log::after { content: none; }

/* "Doug OS is starting…" — the machine naming itself. it is chrome, not
   doug speaking: no number, no claim, and it takes no input. */
.boot-title {
  margin: 26px 0 0;
  color: #fff;
  font-size: 28px;
  letter-spacing: 1px;
  white-space: nowrap;
}

/* the title, the bar and the skip line hold their places from the first
   frame rather than appearing into the column and shoving the finished
   log up 74px at the moment it is being read. `visibility`, not
   `display`, so the geometry is the finished one throughout and each
   part simply arrives; hidden from assistive tech either way, and
   `fillBar()` measures the bar after unhiding it, so its block count is
   unchanged. */
#boot .boot-title[hidden],
#boot .boot-bar[hidden],
#boot .boot-enter[hidden] {
  display: block;
  visibility: hidden;
}

/* the solid block cursor the reference screen parks after the ellipsis */
.boot-cursor {
  display: inline-block;
  width: 0.55em;
  height: 0.95em;
  margin-left: 0.12em;
  vertical-align: -0.12em;
  background: #fff;
  animation: boot-blink 1s steps(1) infinite;
}

/* on the boot screen the bar is a black trough with a white keyline and
   a bright fill — a white bed and a navy fill would vanish into each
   other on black. same segmented blocks the tier bar used to use; only
   the two colours differ, and they are set on the element, not on the
   shared component. */
.boot-bar {
  width: 340px;
  max-width: 100%;
  margin: 26px 0 0;
  height: 26px;
  padding: 3px;
  background: #000;
  box-shadow: none;
  border: 2px solid #fff;
  --install-fill: #1f4fe8;
}

.boot-enter {
  margin: 22px 0 0;
  color: #fff;
  font-size: 15px;
  animation: boot-blink 1.4s steps(1) infinite;
}

/* pinned at the foot, the way a splash screen carried its notice.
   period flavour: no operator, no claim, no number. */
.boot-foot {
  position: absolute;
  left: 0;
  right: 0;
  bottom: max(26px, env(safe-area-inset-bottom));
  margin: 0;
  text-align: center;
  color: #c0c0c0;
  font-size: 15px;
}

@keyframes boot-blink { 50% { opacity: 0; } }

@media (prefers-reduced-motion: reduce) {
  .boot-log::after { animation: none; }
  .boot-cursor { animation: none; }
  .boot-enter { animation: none; }
  #boot.boot-out { transition: none; }
}

@media (max-width: 480px) {
  .boot-log, .boot-enter, .boot-foot { font-size: 12px; }
  .boot-title { font-size: 19px; }
  .boot-bar { width: 260px; height: 22px; }
}

/* ============================================================
   BSOD — cosmetic by admission. an overlay, nothing more.
   the crt treatment is note 01's, minus two things: no
   phosphor glow (SITE-SPEC §5 rules glow out) and no reboot.
   ============================================================ */

.bsod {
  position: fixed;
  inset: 0;
  z-index: 4000;
  background: #0000aa;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: var(--cur-hand), pointer;
  overflow: hidden;
  /* the vignette a curved tube put on a flat field of colour */
  box-shadow: inset 0 0 90px rgba(0, 0, 0, 0.55);
}

/* scanlines, the same texture #desktop and #boot already carry —
   stronger here because there is nothing on this screen to keep
   legible except eleven lines of large raster type. */
.bsod::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: repeating-linear-gradient(0deg,
              transparent 0 2px, rgba(0, 0, 0, 0.22) 2px 4px);
}

.bsod-text {
  position: relative;
  z-index: 2;
  margin: 0;
  padding: 0 28px;
  max-width: 640px;
  background: none;
  box-shadow: none;
  color: #fff;
  font-size: 16px;
  line-height: 1.65;
  white-space: pre-wrap;
}

/* the underscore a stopped machine parked under its last line */
.bsod-cursor {
  display: inline-block;
  margin-left: 2px;
  animation: bsod-blink 1.1s steps(1) infinite;
}

@keyframes bsod-blink { 50% { opacity: 0; } }

@media (prefers-reduced-motion: reduce) {
  .bsod-cursor { animation: none; }
}

@media (max-width: 480px) {
  .bsod-text { font-size: 13px; padding: 0 18px; }
}

/* ============================================================
   FLIP.EXE — the same dialog ENDINGS.TXT is, one turn crueller.

   it reuses .shutdown / .shutdown-bar / .shutdown-body deliberately:
   the two windows are the same object, and a reader who has seen one
   should recognise the other before reading a word of it. what differs
   is what cannot be chosen — there, the ending; here, where the money
   goes. SITE-SPEC §3.9.
   ============================================================ */

.panel-flip { overflow-y: auto; }

.flip-q {
  font-family: var(--ui);
  font-size: 11px;
  margin: 0 0 12px;
}

.flip-opt {
  display: flex;
  gap: 10px;
  margin-bottom: 12px;
  align-items: flex-start;
}

/* a radio nobody can check. same "present but genuinely unavailable"
   construction as the context menu's Delete and ENDINGS.TXT's buttons:
   drawn faithfully, greyed, no handler. removing it would hide the
   fact; enabling it would be a lie. */
.flip-radio {
  flex: 0 0 auto;
  width: 12px;
  height: 12px;
  margin-top: 2px;
  border-radius: 50%;
  background: var(--face);
  box-shadow: var(--bevel-in);
}

.flip-opt-text { min-width: 0; font-family: var(--ui); font-size: 11px; }

.flip-opt-text h3 {
  margin: 0 0 3px;
  font-size: 11px;
  font-weight: 700;
  color: var(--ink-dis);
}

.flip-opt-text p { margin: 0; color: var(--ink-dis); line-height: 1.5; }

/* the pending well. it is not a suspense animation — it states the slot
   the flip resolves on, which is a real interval during which the
   answer does not exist anywhere. never animate a resolved result. */
.flip-pending {
  font-family: var(--mono);
  -webkit-font-smoothing: auto;   /* outline face at 11-12px — see body */
  font-size: 12px;
  text-align: center;
  padding: 8px;
  margin: 12px 0 0;
  box-shadow: var(--edge-in);
}

.flip-btns {
  display: flex;
  gap: 6px;
  justify-content: center;
  margin-top: 14px;
}

.flip-log-title {
  font-family: var(--ui);
  font-size: 11px;
  margin: 16px 0 4px;
}

/* ============================================================
   TERMINAL.EXE — green phosphor on a black well, dos raster
   face, the prompt sitting under the backlog inside one
   scrolling buffer.

   SITE-SPEC §3.8, revised 2026-09-01 (DECISIONS.md, "LE
   TERMINAL"): the ink is `--phosphor`, and this window carries
   the shared status bar like every other panelled window.
   ============================================================ */

.panel-terminal {
  /* the grey the well is sunk into. a 95 console was a black rectangle
     inside a window, not a window painted black edge to edge — and the
     panel needs a face colour for that gap to be a colour at all. */
  padding: 2px;
  background: var(--face);
  overflow: hidden;      /* the well scrolls, the panel does not */
  display: flex;
  flex-direction: column;
}

.panel-terminal[hidden] { display: none; }

.term {
  flex: 1 1 auto;
  min-height: 0;
  /* the whole well is the scroll container, backlog and prompt together —
     which is what a console buffer is, and what puts one full-height
     scrollbar down the right edge instead of a short one beside the
     backlog only. `scroll`, not `auto`: a console showed its scrollbar
     whether or not it had scrolled, and a bar that appears on the fourth
     command would reflow the text under the reader's hands. */
  overflow-y: scroll;
  overflow-x: hidden;
  padding: 4px 6px;
  background: #000;
  color: var(--phosphor);
  /* the deep sunken edge every white text well on this site wears
     (the invoice sheet, the bin). the well is
     black here; the frame around it is the same frame. */
  box-shadow: var(--bevel-in);
  font-family: "Perfect DOS VGA 437 Win", var(--mono);
  /* 16px, and the size is measured rather than chosen. this face draws
     its glyphs as rectangles on a fixed grid, so it is only truly sharp
     where one drawn pixel lands on a whole screen pixel — the same "pick
     by size, not by scale factor" rule the icons follow. its advance is
     0.5625em, so 16px is the ONLY size at or below it that gives a whole
     -pixel advance (9.0000px). measured, rendering one `help` row to a
     canvas and counting the antialiased fringe as a share of the ink:
     12px .757 · 13px .718 · 14px .686 · 15px .652 · **16px .520** · 24px
     .529. Every step from 12 to 15 shaves a little; 16 drops off a
     cliff, and 24 (advance 13.5) climbs back. 14px, the old value, was
     costing a fringe on every glyph for nothing. */
  font-size: 16px;
  line-height: 1.45;
  cursor: var(--cur-ibeam), text;
}

.term-out {
  /* 0 0 auto: the backlog is exactly as tall as its own text, so the
     prompt sits on the line after the last line of output — where a real
     command window puts the cursor — and the black simply continues
     below it. it does not scroll on its own any more; `.term` above is
     the one scroll container, so a long backlog scrolls the prompt with
     it the way a console buffer does, instead of sliding under a prompt
     pinned to the frame. */
  flex: 0 0 auto;
  margin: 0;
  /* 98.css's `pre` well brings padding: 12px 8px with it. the backlog and
     the prompt line below it are one column of text and have to share one
     left edge — this is the last <pre> on the site that was still paying
     the library's padding. */
  padding: 0;
  background: none;
  box-shadow: none;
  font: inherit;
  color: inherit;
  white-space: pre-wrap;
  word-break: break-word;
}

.term-line {
  flex: 0 0 auto;
  display: flex;
  align-items: baseline;
  padding-top: 2px;
}

.term-prompt { white-space: pre; }

/* doubled selector: 98.css styles input[type=text] with a white well
   and a sunken border, and wins on specificity against one class. */
.term-line input.term-in {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  padding: 0 0 0 1px;
  border: none;
  outline: none;
  background: transparent;
  color: inherit;
  font: inherit;
  line-height: inherit;
  caret-color: var(--phosphor);
  /* a console cursor was a filled block, not a hairline. browsers that
     do not know `caret-shape` keep the thin green caret above, which is
     a smaller cursor and not a wrong one — so this is added plain, with
     no @supports guard and nothing to fall back to. */
  caret-shape: block;
  border-radius: 0;
  box-shadow: none;
  height: auto;
}

/* narrow screens drop to 12px, and here the grid loses to the column
   count on purpose. the widest line this terminal prints is 47 columns
   (README.TXT's "a transaction counts as a trade when it did not",
   printed by `type readme.txt`; `dir` peaks at 42 and `help` at 43).
   The well is the viewport less 44px of window chrome and scrollbar,
   so 47 columns of 16px type need a 467px viewport — and 12px is the
   LARGEST size that still fits 47 columns at 375px (49 fit; 13px fits
   45 and wraps the readme, 14px fits 42 and wraps help as well).

   So this is not a timid value, it is a ceiling: above it the primary
   target starts wrapping console output. Where the two goals collide,
   the phone keeps whole lines and gives up the whole-pixel advance;
   the desktop, with room for both, keeps both.

   520px, not the 467px the arithmetic allows: that widest line is
   README.TXT prose, which is copy and may be re-edited, and a
   breakpoint sitting one character from wrapping would turn a comma
   into a layout bug. 520px leaves five columns of margin. */
@media (max-width: 520px) {
  .term { font-size: 12px; }
}
