/* HOPIUM LABS 98
 *
 * The chrome is the design here, so it has to be right. Windows 98 drew every
 * raised edge with a four-tone bevel: white and light grey on the top-left,
 * dark grey and black on the bottom-right. Faking it with a single border looks
 * flat and immediately wrong, so every panel here uses the real four-tone
 * bevel, built from stacked inset shadows.
 *
 * The one deliberate break from 1998 is the desktop itself. Instead of teal it
 * carries the lab, because the art is the reason anyone stays.
 */

/* --------------------------------------------------------------- tokens --- */

:root {
  /* The actual 3D object colours from the era. */
  --face: #c0c0c0;
  --light: #dfdfdf;
  --white: #ffffff;
  --shadow: #808080;
  --dark: #000000;

  --title: #000080;
  --title-2: #1084d0;
  --title-off: #808080;
  --title-off-2: #b5b5b5;
  --title-text: #ffffff;

  /* The lab's own palette, sampled from the art. */
  --lab: #39ff14;
  --lab-dim: #1f8c10;
  --lab-deep: #061007;
  --lab-black: #050805;

  --taskbar-h: 30px;

  /* Tahoma is metrically close to MS Sans Serif and is on every Windows box.
   * The pixel-font stack ahead of it is for anyone who has one installed. */
  --ui: "Pixelated MS Sans Serif", "MS Sans Serif", Tahoma, Geneva, Verdana, sans-serif;
  --mono: "Lucida Console", "Courier New", monospace;
}

/* The two bevels everything is built from. */
.raised {
  box-shadow:
    inset -1px -1px 0 0 var(--dark),
    inset 1px 1px 0 0 var(--white),
    inset -2px -2px 0 0 var(--shadow),
    inset 2px 2px 0 0 var(--light);
}

.sunken {
  box-shadow:
    inset 1px 1px 0 0 var(--shadow),
    inset -1px -1px 0 0 var(--white),
    inset 2px 2px 0 0 var(--dark),
    inset -2px -2px 0 0 var(--light);
}

/* A single-step bevel, for grouping rather than for objects you press. */
.groove {
  box-shadow:
    inset -1px -1px 0 0 var(--white),
    inset 1px 1px 0 0 var(--shadow);
}

/* ----------------------------------------------------------------- base --- */

* { box-sizing: border-box; }

html, body {
  height: 100%;
  margin: 0;
  overflow: hidden;
  font-family: var(--ui);
  font-size: 11px;
  /* 98 never antialiased its UI text. Turning off smoothing is most of why
   * this reads as the era rather than as a modern page in grey. */
  -webkit-font-smoothing: none;
  -moz-osx-font-smoothing: grayscale;
  color: var(--dark);
  background: var(--lab-black);
  /* Nothing on a desktop is text you drag-select, and accidental selection
   * while dragging windows looks broken. Text inside documents opts back in. */
  user-select: none;
  -webkit-user-select: none;
  cursor: default;
  touch-action: manipulation;
}

img { image-rendering: auto; }

/* ---------------------------------------------------------------- boot --- */

#boot {
  position: fixed;
  inset: 0;
  z-index: 9000;
  background: #000;
  color: #c8c8c8;
  font-family: var(--mono);
  font-size: 13px;
  line-height: 1.45;
  padding: 26px 22px;
  overflow: hidden;
  white-space: pre-wrap;
}

#boot.done { display: none; }
#boot b { color: #fff; font-weight: normal; }
#boot .g { color: var(--lab); }
#boot .amber { color: #ffb000; }

#boot .cursor {
  display: inline-block;
  width: 8px;
  height: 14px;
  background: #c8c8c8;
  vertical-align: -2px;
  animation: blink 1s steps(1) infinite;
}

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

/* --------------------------------------------------------------- screen --- */

#screen {
  position: fixed;
  inset: 0 0 var(--taskbar-h) 0;
  overflow: hidden;

  /* The lab, dimmed, with a green wash pooling out of the centre where the
   * flask is, so the wallpaper lights the desktop instead of just sitting
   * behind it.
   *
   * wall.webp, not the banner: the banner is a 3:1 strip, so covering a 16:9
   * screen with it meant a 2.5x upscale and losing 44% of the width, frogs
   * included. The wallpaper is the same art composed to 16:9 offline, which
   * makes this a downscale on any normal desktop. See ops/prep_hopium_wall.py.
   *
   * Held in a variable so the phone breakpoint can swap in the small version
   * without restating the whole layer stack. */
  --wall: url("art/wall.webp");
  background:
    radial-gradient(ellipse 65% 55% at 50% 46%,
      rgba(57, 255, 20, .15) 0%, rgba(57, 255, 20, 0) 70%),
    linear-gradient(rgba(5, 8, 5, .42), rgba(5, 8, 5, .68)),
    var(--wall) center center / cover no-repeat,
    var(--lab-black);
}

/* Scanlines and a vignette. Kept faint: the point is a slight unease, not a
 * novelty filter, and it must never fight the art. */
#crt {
  position: fixed;
  inset: 0;
  z-index: 8000;
  pointer-events: none;
  opacity: .5;
  background:
    repeating-linear-gradient(
      to bottom,
      rgba(0, 0, 0, .16) 0px, rgba(0, 0, 0, .16) 1px,
      rgba(0, 0, 0, 0) 1px, rgba(0, 0, 0, 0) 3px),
    radial-gradient(ellipse 90% 80% at 50% 50%,
      rgba(0, 0, 0, 0) 55%, rgba(0, 0, 0, .40) 100%);
}

body.no-crt #crt { display: none; }

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

/* Icons fill a column, then start a second one, the way a real desktop does.
 * Capping the height is what makes the wrap happen, and it also keeps the last
 * icons clear of the start menu instead of hidden behind it. */
#icons {
  position: absolute;
  top: 8px;
  left: 8px;
  max-height: calc(100% - 16px);
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
  align-content: flex-start;
  gap: 2px 6px;
}

.dicon {
  width: 92px;
  padding: 4px 2px 5px;
  text-align: center;
  cursor: default;
}

.dicon .glyph {
  display: block;
  width: 32px;
  height: 32px;
  margin: 0 auto 3px;
  font-size: 26px;
  line-height: 32px;
  text-align: center;
  /* Icons sit on a dark wallpaper, so they need their own light to read. */
  filter: drop-shadow(0 0 6px rgba(57, 255, 20, .55));
}

.dicon img.glyph {
  object-fit: contain;
  filter: drop-shadow(0 0 7px rgba(57, 255, 20, .6));
}

.dicon .cap {
  display: inline-block;
  max-width: 88px;
  color: #fff;
  font-size: 11px;
  line-height: 1.25;
  padding: 1px 3px;
  text-shadow: 1px 1px 1px #000, 0 0 4px #000;
  /* Filenames have no spaces, so the default would strand single letters on
   * their own line. Let a long name run to the edge of its cell instead. */
  overflow-wrap: break-word;
  word-break: normal;
  hyphens: none;
}

.dicon.sel .cap {
  background: var(--title);
  text-shadow: none;
  outline: 1px dotted #fff;
  outline-offset: -1px;
}

.dicon.sel .glyph {
  /* 98 tinted the selected icon rather than boxing it. */
  filter: drop-shadow(0 0 6px rgba(57, 255, 20, .55)) brightness(.72) saturate(1.6);
}

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

.win {
  position: absolute;
  min-width: 200px;
  background: var(--face);
  padding: 3px;
  display: flex;
  flex-direction: column;
  /* Windows on a black desktop with no drop shadow look pasted on. This is the
   * one modern affordance kept, because it costs nothing and helps depth. */
  filter: drop-shadow(3px 3px 0 rgba(0, 0, 0, .45));
}

.win.min { display: none; }

.win.max {
  left: 0 !important;
  top: 0 !important;
  width: 100% !important;
  height: 100% !important;
}

.titlebar {
  display: flex;
  align-items: center;
  gap: 4px;
  height: 20px;
  padding: 0 2px 0 3px;
  background: linear-gradient(90deg, var(--title), var(--title-2));
  color: var(--title-text);
  font-weight: bold;
  font-size: 11px;
  cursor: default;
  flex: 0 0 auto;
}

.win.blur .titlebar {
  background: linear-gradient(90deg, var(--title-off), var(--title-off-2));
}

.titlebar .tico {
  width: 16px;
  height: 16px;
  font-size: 13px;
  line-height: 16px;
  text-align: center;
  flex: 0 0 auto;
}

.titlebar .tico img { width: 16px; height: 16px; object-fit: contain; }

.titlebar .ttext {
  flex: 1 1 auto;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  /* The era's title bars had a hard 1px shadow, not a soft one. */
  text-shadow: 1px 1px 0 rgba(0, 0, 0, .45);
}

.titlebar .tbtns { display: flex; gap: 2px; flex: 0 0 auto; }

.tbtn {
  width: 16px;
  height: 14px;
  background: var(--face);
  border: 0;
  padding: 0;
  font-family: var(--ui);
  font-size: 9px;
  font-weight: bold;
  line-height: 1;
  color: var(--dark);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: default;
}

.tbtn:active { box-shadow: inset 1px 1px 0 0 var(--shadow), inset -1px -1px 0 0 var(--white), inset 2px 2px 0 0 var(--dark); }
.tbtn svg { display: block; }

/* The menu strip under a title bar. */
.menubar {
  display: flex;
  gap: 0;
  padding: 1px 0 2px;
  flex: 0 0 auto;
}

.menubar span {
  padding: 1px 6px;
  cursor: default;
}

.menubar span:hover {
  background: var(--title);
  color: #fff;
}

.wbody {
  flex: 1 1 auto;
  overflow: auto;
  background: var(--face);
  padding: 8px;
}

/* A document surface: white, sunken, and selectable, unlike the chrome. */
.paper {
  background: #fff;
  padding: 8px 10px;
  overflow: auto;
  user-select: text;
  -webkit-user-select: text;
  cursor: text;
}

.statusbar {
  flex: 0 0 auto;
  display: flex;
  gap: 3px;
  padding: 2px 0 0;
  font-size: 11px;
}

.statusbar > span {
  padding: 2px 5px;
  background: var(--face);
}

.statusbar > span:first-child { flex: 1 1 auto; }

/* --------------------------------------------------------------- widgets --- */

/* Not element-qualified, because half the buttons on this page are anchors
 * that leave the site. A `button.b98` selector silently leaves those looking
 * like plain blue links, which is exactly the sort of thing that makes a
 * pastiche fall apart. */
.b98 {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 75px;
  height: 23px;
  padding: 0 12px;
  background: var(--face);
  border: 0;
  font-family: var(--ui);
  font-size: 11px;
  line-height: 1;
  color: var(--dark);
  text-align: center;
  text-decoration: none;
  cursor: default;
}

.b98:visited { color: var(--dark); }
.b98:focus-visible { outline: 1px dotted var(--dark); outline-offset: -4px; }

.b98:active:not(:disabled) {
  box-shadow:
    inset 1px 1px 0 0 var(--shadow),
    inset -1px -1px 0 0 var(--white),
    inset 2px 2px 0 0 var(--dark),
    inset -2px -2px 0 0 var(--light);
  /* The label shifts down and right on press, as every 98 button did. */
  padding: 2px 11px 0 13px;
}

.b98:disabled {
  color: var(--shadow);
  text-shadow: 1px 1px 0 var(--white);
}

.b98.wide { min-width: 0; width: 100%; }

.field {
  background: #fff;
  padding: 3px 4px;
  font-family: var(--mono);
  font-size: 11px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  user-select: text;
  -webkit-user-select: text;
}

fieldset.fs {
  border: 0;
  padding: 10px 9px 9px;
  margin: 0 0 9px;
  position: relative;
}

fieldset.fs legend {
  padding: 0 4px;
  font-size: 11px;
}

.row { display: flex; gap: 6px; align-items: center; }
.row.wrap { flex-wrap: wrap; }
.grow { flex: 1 1 auto; min-width: 0; }
.stack { display: flex; flex-direction: column; gap: 7px; }

/* The sunken progress trough with the classic segmented fill. */
.prog {
  height: 18px;
  background: var(--face);
  padding: 2px;
  overflow: hidden;
}

.prog i {
  display: block;
  height: 100%;
  width: 0;
  background:
    repeating-linear-gradient(90deg,
      var(--title) 0 8px, var(--face) 8px 10px);
  transition: width .18s linear;
}

.prog.lab i {
  background:
    repeating-linear-gradient(90deg,
      var(--lab-dim) 0 8px, var(--face) 8px 10px);
}

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

#taskbar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  height: var(--taskbar-h);
  z-index: 7000;
  background: var(--face);
  display: flex;
  align-items: center;
  gap: 3px;
  padding: 2px 2px;
  box-shadow: inset 0 1px 0 0 var(--white), inset 0 2px 0 0 var(--light);
}

#start {
  height: 24px;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 0 7px 0 4px;
  background: var(--face);
  border: 0;
  font-family: var(--ui);
  font-size: 11px;
  font-weight: bold;
  cursor: default;
}

#start img { width: 17px; height: 17px; object-fit: contain; }

#start.on {
  box-shadow:
    inset 1px 1px 0 0 var(--shadow),
    inset -1px -1px 0 0 var(--white),
    inset 2px 2px 0 0 var(--dark),
    inset -2px -2px 0 0 var(--light);
}

.tdiv {
  width: 2px;
  height: 20px;
  flex: 0 0 auto;
  box-shadow: inset -1px 0 0 var(--white), inset 1px 0 0 var(--shadow);
}

#tasks {
  flex: 1 1 auto;
  display: flex;
  gap: 3px;
  overflow: hidden;
  min-width: 0;
}

.task {
  flex: 0 1 154px;
  min-width: 40px;
  height: 24px;
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 0 6px;
  background: var(--face);
  border: 0;
  font-family: var(--ui);
  font-size: 11px;
  overflow: hidden;
  cursor: default;
}

.task .tl {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.task img, .task .em { width: 15px; height: 15px; flex: 0 0 auto; font-size: 12px; line-height: 15px; text-align: center; object-fit: contain; }

.task.on {
  font-weight: bold;
  box-shadow:
    inset 1px 1px 0 0 var(--shadow),
    inset -1px -1px 0 0 var(--white),
    inset 2px 2px 0 0 var(--dark),
    inset -2px -2px 0 0 var(--light);
  /* The pressed taskbar button was stippled, which is the detail that sells it. */
  background-image:
    repeating-conic-gradient(from 0deg at 0 0,
      rgba(255,255,255,.55) 0 25%, transparent 0 50%);
  background-size: 2px 2px;
}

#tray {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 5px;
  height: 24px;
  padding: 0 7px;
  background: var(--face);
}

#tray .ticon { font-size: 12px; cursor: default; }
#clock { font-size: 11px; min-width: 52px; text-align: center; }

/* ---------------------------------------------------------- start menu --- */

#startmenu {
  position: fixed;
  left: 2px;
  bottom: var(--taskbar-h);
  z-index: 7100;
  width: 200px;
  background: var(--face);
  padding: 3px;
  display: none;
  filter: drop-shadow(2px 2px 0 rgba(0, 0, 0, .4));
}

#startmenu.open { display: flex; }

/* The vertical "Windows 98" spine down the left of the menu. */
#startmenu .spine {
  width: 21px;
  flex: 0 0 auto;
  background: linear-gradient(var(--title), #4a1d7a);
  color: #fff;
  font-weight: bold;
  font-size: 15px;
  letter-spacing: .06em;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  text-align: right;
  padding: 8px 2px;
}

#startmenu .items { flex: 1 1 auto; }

.mitem {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 4px 6px;
  cursor: default;
  font-size: 11px;
}

.mitem .mi {
  width: 20px;
  font-size: 15px;
  text-align: center;
  flex: 0 0 auto;
}

.mitem .mi img { width: 18px; height: 18px; object-fit: contain; vertical-align: -3px; }
.mitem:hover { background: var(--title); color: #fff; }
.mitem.sep { padding: 0; margin: 3px 1px; height: 2px; pointer-events: none; box-shadow: inset 0 1px 0 var(--shadow), inset 0 -1px 0 var(--white); }
.mitem b { font-weight: bold; }

/* ------------------------------------------------------------- content --- */

h1.ht {
  margin: 0 0 3px;
  font-size: 20px;
  letter-spacing: -.02em;
}

h2.hs {
  margin: 0 0 6px;
  font-size: 12px;
}

p.pp { margin: 0 0 9px; line-height: 1.5; }
p.pp:last-child { margin-bottom: 0; }

.banner {
  display: block;
  width: 100%;
  height: auto;
  background: var(--lab-black);
}

.flask {
  display: block;
  width: 96px;
  height: 96px;
  margin: 0 auto;
  background: var(--lab-black);
}

/* Text that belongs to the lab rather than to the operating system. */
.lab-text {
  color: var(--lab-dim);
  font-weight: bold;
}

.blink { animation: blink 1.1s steps(1) infinite; }

.marquee {
  overflow: hidden;
  white-space: nowrap;
  background: var(--lab-black);
  color: var(--lab);
  font-family: var(--mono);
  font-size: 11px;
  padding: 3px 0;
}

.marquee i {
  display: inline-block;
  padding-left: 100%;
  animation: slide 26s linear infinite;
  font-style: normal;
}

@keyframes slide {
  to { transform: translateX(-100%); }
}

/* The spreadsheet. */
table.sheet {
  border-collapse: collapse;
  background: #fff;
  font-size: 11px;
  width: 100%;
}

table.sheet th, table.sheet td {
  border: 1px solid #d0d0d0;
  padding: 2px 5px;
  text-align: left;
  white-space: nowrap;
}

table.sheet thead th, table.sheet tbody th {
  background: var(--face);
  box-shadow: inset -1px -1px 0 var(--shadow), inset 1px 1px 0 var(--white);
  text-align: center;
  font-weight: normal;
  color: #222;
}

table.sheet td.n { text-align: right; font-family: var(--mono); }
table.sheet tr.tot td, table.sheet tr.tot th { font-weight: bold; background: #f0f0c8; }

/* Defrag: the block grid that hypnotised a generation. */
#defrag-grid {
  display: grid;
  grid-template-columns: repeat(40, 1fr);
  gap: 1px;
  background: #fff;
  padding: 3px;
  height: 150px;
}

#defrag-grid i {
  background: #c8c8c8;
  display: block;
}

#defrag-grid i.a { background: var(--title); }
#defrag-grid i.b { background: var(--lab-dim); }
#defrag-grid i.c { background: #d02020; }
#defrag-grid i.r { background: var(--lab); }

.legend { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 7px; font-size: 11px; }
.legend span { display: flex; align-items: center; gap: 4px; }
.legend b { width: 10px; height: 10px; display: block; }

/* Paint. */
#paint-canvas { display: block; background: #fff; cursor: crosshair; touch-action: none; }

.swatches { display: grid; grid-template-columns: repeat(8, 15px); gap: 2px; }
.swatches i { width: 15px; height: 15px; display: block; cursor: default; }
.swatches i.on { outline: 2px solid var(--title); outline-offset: 1px; }

/* The meter's dial, drawn as a real gauge.
 *
 * A CSS-only version needs the needle pivoted at the bottom of a wide box,
 * which leaves it lying almost flat at rest and crossing the readout on its
 * way up. In SVG the geometry is stated once and everything lands where a
 * dial should: the sweep is 160 degrees about a fixed pivot, the readout sits
 * below the pivot and out of the needle's path, and the arc fills as it climbs.
 */
.dial {
  width: 100%;
  height: 128px;
  background: var(--lab-black);
  padding: 4px;
}

.gauge { display: block; width: 100%; height: 100%; }

.gauge-track {
  fill: none;
  stroke: rgba(57, 255, 20, .22);
  stroke-width: 7;
  stroke-linecap: butt;
}

.gauge-fill {
  fill: none;
  stroke: var(--lab);
  stroke-width: 7;
  stroke-linecap: butt;
  opacity: .8;
  transition: stroke-dashoffset .35s ease-out;
  filter: drop-shadow(0 0 5px rgba(57, 255, 20, .8));
}

.gauge-ticks line { stroke: rgba(57, 255, 20, .45); stroke-width: 2; }

.gauge-needle {
  /* Without an explicit box the origin resolves against the bounding box of
   * the group itself, which moves as the needle turns. */
  transform-box: view-box;
  transform-origin: 100px 100px;
  transition: transform .4s cubic-bezier(.3, 1.5, .5, 1);
}

.gauge-needle line {
  stroke: #fff;
  stroke-width: 3;
  stroke-linecap: round;
  filter: drop-shadow(0 0 4px var(--lab));
}

.gauge-needle circle { fill: #fff; }

.gauge-read {
  fill: var(--lab);
  font-family: var(--mono);
  font-size: 19px;
  font-weight: bold;
  text-anchor: middle;
}

.gauge-lab {
  fill: rgba(57, 255, 20, .5);
  font-family: var(--mono);
  font-size: 9px;
  text-anchor: middle;
}

/* ------------------------------------------------------------- dialogs --- */

.dlg-icon {
  width: 32px;
  height: 32px;
  flex: 0 0 auto;
  font-size: 27px;
  line-height: 32px;
  text-align: center;
}

/* ---------------------------------------------------------- screensaver --- */

#saver {
  position: fixed;
  inset: 0;
  z-index: 8500;
  background: #000;
  display: none;
  overflow: hidden;
  cursor: none;
}

#saver.on { display: block; }

#saver img {
  position: absolute;
  width: 74px;
  height: 74px;
  will-change: transform;
}

#saver .sstext {
  position: absolute;
  color: var(--lab);
  font-family: var(--mono);
  font-size: 13px;
  white-space: nowrap;
  text-shadow: 0 0 10px var(--lab);
}

/* ---------------------------------------------------------------- bsod --- */

#bsod {
  position: fixed;
  inset: 0;
  z-index: 9500;
  display: none;
  background: #0000aa;
  color: #fff;
  font-family: var(--mono);
  font-size: 14px;
  line-height: 1.6;
  padding: 8vh 8vw;
}

#bsod.on { display: block; }
#bsod .hd { background: #aaa; color: #0000aa; display: inline-block; padding: 0 8px; margin-bottom: 22px; }
#bsod .ct { text-align: center; margin-top: 26px; }

/* -------------------------------------------------------------- mobile --- */

/* A desktop metaphor on a phone cannot keep overlapping draggable windows, so
 * below the breakpoint the windows stack and fill the screen. The chrome, the
 * taskbar and the art all stay, because they are the reason to be here. */
@media (max-width: 720px) {
  :root { --taskbar-h: 34px; }

  html, body { font-size: 12px; }

  /* A phone crops the wallpaper down to a slice around the flask anyway, so it
   * has no use for the 2048px version and should not pay for it. */
  #screen { --wall: url("art/wall-sm.webp"); }

  /* A window fills a phone screen, so a grid of icons underneath it would be
   * unreachable and the desktop would look like it had one program on it.
   * Instead the icons become a single scrollable strip pinned above the
   * windows, which stays visible whatever is open. */
  #icons {
    top: 0;
    left: 0;
    right: 0;
    max-height: none;
    flex-direction: row;
    flex-wrap: nowrap;
    align-content: initial;
    gap: 0;
    padding: 4px 4px 6px;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    background: linear-gradient(rgba(5, 8, 5, .82), rgba(5, 8, 5, .34));
  }

  #icons::-webkit-scrollbar { display: none; }

  .dicon {
    width: 84px;
    flex: 0 0 auto;
  }

  .dicon .glyph { width: 28px; height: 28px; font-size: 23px; line-height: 28px; }
  .dicon .cap { max-width: 82px; font-size: 10px; }

  .win {
    left: 2vw !important;
    /* Clear of the icon strip, which measures 77px with its padding. Anything
     * tighter overlaps the captions by a few pixels. */
    top: 84px !important;
    width: 96vw !important;
    max-height: calc(100% - 92px);
  }

  .win:not(.max) { height: auto !important; }

  /* Maximised still means the whole screen, icon strip included. */
  .win.max { top: 0 !important; max-height: 100%; }

  .titlebar { height: 24px; }
  .tbtn { width: 20px; height: 18px; }

  #startmenu { width: min(260px, 94vw); }
  .task { flex-basis: 44px; }
  .task .tl { display: none; }

  #defrag-grid { grid-template-columns: repeat(20, 1fr); height: 120px; }
}

@media (prefers-reduced-motion: reduce) {
  .blink, .marquee i, #boot .cursor { animation: none; }
  .prog i, .dial .needle { transition: none; }
}
