/* GameRoom, one stylesheet, back in the year it belongs to.

   This is 2001: Arial, lavender section bars, cream panels, beveled gray
   buttons, the applet field, blue strip headers over the button groups, links
   that turn purple once visited. Nothing is soft, nothing has a radius, and
   nothing fades.

   What it keeps from the modern pass is everything that was not a look:
   uploadable pictures, a real account page, boards drawn at device resolution,
   panes that stack rather than scrolling sideways, and a scrollbar that
   belongs to the page instead of to the operating system.

   The component class names are deliberately unchanged from that pass. A card
   is still .card and a button is still .btn, so the pages and the JavaScript
   did not have to be rewritten to move the whole thing back in time. */

:root {
  --lav: #ccccff;
  --cream: #ffffcc;
  --field: #efefce;
  --face: #d4d0c8;
  --face-2: #c3bfb7;
  --edge: #808080;
  --strip: #0a246a;
  --rule: #999999;
  --hair: #dddddd;
  --link: #0000cc;
  --seen: #551a8b;
  --ink: #000000;
  --ink-2: #444444;
  --ink-3: #777777;
  --paper: #ffffff;
  --good: #007000;
  --warn: #a06000;
  --bad: #cc0000;
  --felt: #1f7a3d;

  --font: Arial, Helvetica, sans-serif;
  --max: 1180px;

  /* The page behind the panels. The same white as a panel here, and a
     different shade in every theme that puts its windows on a desktop. */
  --page: var(--paper);

  /* A playing card is white with a red suit in every theme, including the dark
     ones. Cards are the one thing on screen that is a picture of a real
     object, and a dark grey four of hearts is not a four of hearts. */
  --card-face: #ffffff;
  --card-ink: #111111;
  --card-red: #cc0000;

  /* Text that sits on top of --strip: the blue strip headers, the modal title
     bar, a menu row under the pointer. White here, and not white in a theme
     whose accent is pale. */
  --on-accent: #ffffff;

  /* ---- shape ----

     The palette above is what a theme mostly changes. These are what it needs
     to change as well, because a look is not only its colors: 2001 is a two
     pixel outset bevel and a hard corner, Aqua is a soft corner and a shadow,
     and Windows 11 is a rounded rectangle with a hairline. Every component
     below is written in terms of these rather than in terms of the bevel, so
     a theme is one block of variables and never a second stylesheet. */
  --radius: 0;
  --radius-panel: 0;
  --btn-border: 2px outset var(--face);
  --btn-border-active: 2px inset var(--face);
  --btn-bg: var(--face);
  --btn-bg-hover: #dcd8d0;
  --btn-shadow: none;
  --in-border: 2px inset var(--face);
  --panel-shadow: none;
  /* Laid over --lav on panel headers and over --strip on the strips. A theme
     with gradients puts one here; the period had none. */
  --head-image: none;
  --strip-image: none;
  /* Nothing in 2001 eased. */
  --knob-anim: transform .12s steps(3);

  /* ---- type and density ----

     The layer that makes a theme more than a repaint. Every size and every
     space in this stylesheet was a 2001 number typed in place, which is why a
     theme could only ever recolor the app: twelve pixel body text and two
     pixel padding inside a button are the look, as much as the beveled gray
     is. The values here are exactly those numbers, so the period theme is
     unmoved, and a modern theme is the same components at a modern size. */
  --fs: 12px;
  --fs-sm: 11px;
  --fs-xs: 10px;
  --fs-ctl: 11px;
  --lh: 1.45;

  --pad-ctl: 2px 10px;
  --pad-ctl-sm: 1px 7px;
  --pad-head: 2px 6px;
  --pad-body: 8px;
  --pad-cell: 4px 6px;
  --pad-in: 2px 3px;

  /* A primary button in 2001 was the same button with bold text on it. */
  --btn-primary-bg: var(--btn-bg);
  --btn-primary-hover: var(--btn-bg-hover);
  --btn-primary-fg: var(--ink);

  /* The switch: a square knob stepping along a sunken rail, or a round one
     gliding in a pill. A round knob is a different width, so it travels a
     different distance. */
  --track-radius: 0;
  --knob-radius: 0;
  --knob-w: 16px;
  --knob-x: 14px;

  /* The accent, when it has to carry ten pixel white text: the strip headers,
     the modal title bar, the little suit chip on the front page. A theme whose
     accent is a bright mid blue reads fine as a fill and fails as a background
     for small text, so those places get their own darker shade of it. */
  --accent-ink: var(--strip);

  /* The strip: the little bar over a group of rail buttons and over a section
     of a form. A period one is a navy band with white text on it. A modern one
     is a quiet label, because a full width block of accent every few inches is
     what a modern interface stopped doing. */
  --strip-bg: var(--accent-ink);
  --strip-fg: var(--on-accent);

  /* The two narrow columns either side of the front page. Wider type needs
     wider columns, or Room Classes wraps every other word. */
  --col-l: 150px;
  --col-r: 170px;

  /* Red, on the two backgrounds that are not the page: the selection tint under
     the seat whose turn it is, and the face of a button. A theme's --bad is
     chosen to work on paper, and neither of those is paper. */
  --alert-fg: var(--bad);
  /* A touch darker than --bad, because the period red on the period button
     face is the one pairing in the default theme that is genuinely hard to
     read. Everything else about it is left alone. */
  --danger-fg: #a91616;

  /* The SOON chip. It is --bad on --cream, and --cream is a pale yellow tint in
     one theme and a selection blue in the next, which is where red on blue came
     from. A theme with a selection blue points this at its neutral instead. */
  --badge-bg: var(--cream);
  --badge-fg: var(--bad);

  --head-weight: bold;
  --focus: 1px dotted var(--ink);
  --link-underline: underline;

  /* The masthead, measured by hand, and subtracted from the viewport to size
     the lobby and the table. A theme with bigger type has a taller masthead,
     and a stale number here is a table page that runs off the bottom of the
     screen. */
  --chrome: 108px;

  /* Aliases, not a second palette. The period had one look; these exist only
     because the board renderers read tokens for their colors. */
  --bg: var(--paper);
  --bg-2: var(--paper);
  --bg-3: var(--field);
  --bg-4: var(--face);
  --line: var(--rule);
  --line-2: var(--edge);
  --accent: var(--strip);
  --accent-2: var(--link);
  --accent-soft: var(--cream);
}

*,
*::before,
*::after { box-sizing: border-box; }

/* The hidden attribute only sets display:none at the very bottom of the
   cascade, so any class that sets display at all silently beats it. */
[hidden] { display: none !important; }

html, body { height: 100%; }

body {
  margin: 0;
  background: var(--page);
  color: var(--ink);
  font: var(--fs)/var(--lh) var(--font);
  overflow-x: hidden;
}

h1 { font-size: 18px; margin: 0; }
h2 { font-size: 14px; margin: 0; }
h3, h4 { font-size: var(--fs); margin: 0; }
p { margin: 0 0 8px; }
a { color: var(--link); text-decoration: var(--link-underline); }
a:visited { color: var(--seen); }
a:hover { color: var(--bad); }
img { max-width: 100%; }

.num { font-variant-numeric: tabular-nums; }
.muted { color: var(--ink-2); }
.small { font-size: var(--fs-sm); }
.tiny { font-size: var(--fs-xs); }
.center { text-align: center; }
.spacer { flex: 1 1 auto; }
.row { display: flex; align-items: center; gap: 8px; }
.row.wrap-row { flex-wrap: wrap; }
.stack > * + * { margin-top: 10px; }
.sep { height: 1px; background: var(--rule); margin: 10px 0; }
.hidden { display: none !important; }

:focus-visible { outline: var(--focus); outline-offset: 1px; }

/* ---------- the scrollbar ----------

   Chromium and Firefox are told separately and never both, because the moment
   scrollbar-color is set Chromium abandons the pseudo-element path and draws
   the native widget instead, stepper arrows and all, silently ignoring every
   rule below it. Gated on a fine pointer, since a touch browser draws a
   transient overlay that costs no layout, and styling that parks a permanent
   rail down the side of the page. */
@media (pointer: fine) {
  @supports not selector(::-webkit-scrollbar) {
    * { scrollbar-width: thin; scrollbar-color: var(--face-2) var(--field); }
  }
  ::-webkit-scrollbar { width: 15px; height: 15px; }
  ::-webkit-scrollbar-track { background: var(--field); }
  ::-webkit-scrollbar-thumb {
    background: var(--face);
    border: 1px solid var(--edge);
    border-top-color: var(--paper);
    border-left-color: var(--paper);
  }
  ::-webkit-scrollbar-thumb:hover { background: var(--btn-bg-hover); }
  ::-webkit-scrollbar-corner { background: var(--field); }
  ::-webkit-scrollbar-button { display: none; width: 0; height: 0; }
}

/* ---------- the masthead ---------- */

.wrap { width: 100%; max-width: var(--max); margin: 0 auto; padding: 0 8px; }

.topbar { border-bottom: 1px solid var(--rule); background: var(--paper); }
.topbar .inner { display: flex; align-items: flex-end; gap: 10px; padding: 6px 0 4px; flex-wrap: wrap; }

.brand { display: flex; align-items: baseline; gap: 4px; text-decoration: none; white-space: nowrap; }
.brand:hover { text-decoration: none; }
.brand .mark {
  font: italic bold 26px Georgia, "Times New Roman", serif;
  color: var(--bad);
  letter-spacing: -1px;
}
.brand .word { font: bold 26px var(--font); color: var(--ink); letter-spacing: -1px; }

.navlinks { display: flex; align-items: baseline; gap: 10px; font-size: var(--fs-sm); padding-bottom: 4px; }
.navlinks a.on { background: var(--cream); padding: 1px 4px; font-weight: bold; text-decoration: none; color: var(--ink); }

.topbar #me { padding-bottom: 3px; font-size: var(--fs-sm); }

/* The page's own title bar. A full border rather than a rule above and below:
   with open ends it was a band running off both sides of the page while every
   panel under it was a closed box. */
.titlebar {
  background: var(--lav); background-image: var(--head-image);
  border: 1px solid var(--rule);
  border-radius: var(--radius-panel);
  font-weight: var(--head-weight);
  padding: var(--pad-head);
  margin: 4px 0 8px;
}

.crumb { font-size: var(--fs-sm); margin: 6px 0; }

/* ---------- panels ----------

   Header, body, footer. The header is lavender, and cream when the panel is
   the main one on the page, which is what the original did with its "Select a
   Game to Play" box. */

.card {
  border: 1px solid var(--rule); background: var(--paper); margin-bottom: 10px;
  border-radius: var(--radius-panel); box-shadow: var(--panel-shadow);
}
.card-head {
  /* Wraps on purpose: the lobby's header carries a switch, two dropdowns and a
     button, and on a phone that is wider than the phone. Wrapping is what
     stops it becoming the one thing in the app that scrolls sideways. */
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  background: var(--lav); background-image: var(--head-image);
  border-bottom: 1px solid var(--rule);
  /* The panel's own corners, less its one pixel border. Without this the
     header is a square block painted over the top of a rounded card, which is
     only invisible in the themes whose radius is zero. max() rather than a
     bare subtraction because a negative radius is not a radius. */
  border-radius: max(0px, calc(var(--radius-panel) - 1px)) max(0px, calc(var(--radius-panel) - 1px)) 0 0;
  padding: var(--pad-head);
  font-weight: var(--head-weight);
}
.card.feature > .card-head { background: var(--cream); }
.card-body { padding: var(--pad-body); }
.card-body.flush { padding: 0; }
.card-foot {
  display: flex; align-items: center; gap: 6px;
  border-top: 1px solid var(--rule);
  background: var(--field);
  border-radius: 0 0 max(0px, calc(var(--radius-panel) - 1px)) max(0px, calc(var(--radius-panel) - 1px));
  padding: var(--pad-head);
}

.grid { display: grid; gap: 8px; }
.grid.cards { grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); }
.cols-2 { display: grid; grid-template-columns: minmax(0, 1fr) 210px; gap: 10px; align-items: start; }
.cols3 { display: grid; grid-template-columns: var(--col-l) minmax(0, 1fr) var(--col-r); gap: 10px; align-items: start; }
@media (max-width: 760px) {
  .cols-2, .cols3 { grid-template-columns: minmax(0, 1fr); }
}

.side .card-head { font-size: var(--fs); }
.side ul { list-style: none; margin: 0; padding: 0; }
.side li { padding: 1px 0; }
.side ul.bullets { list-style: disc; padding-left: 16px; }

/* ---------- the game wall ---------- */

.cat { margin-bottom: 12px; }
.cat h4 { display: flex; align-items: center; gap: 6px; margin-bottom: 4px; }
.cat h4 .line { flex: 1; border-bottom: 1px solid var(--rule); }
.cat .icon {
  width: 16px; height: 16px; flex: none;
  display: grid; place-items: center;
  font-size: 10px; color: var(--on-accent); font-weight: bold;
  background: var(--accent-ink);
}
/* Two columns of games in the width the applet had, three now that every page
   is the wide one, because at 1180 a two column list is a long thin ribbon
   down the middle of a lot of nothing. */
.games { columns: 3; column-gap: 20px; }
@media (max-width: 900px) { .games { columns: 2; } }
@media (max-width: 560px) { .games { columns: 1; } }
.games div { break-inside: avoid; padding: 1px 0; }
.games .n { color: var(--ink-2); }
.games .soon a, .games .soon .nm { color: var(--ink-3); }
.badge-new { color: var(--badge-fg); font-weight: bold; font-size: 9px; background: var(--badge-bg); padding: 0 2px; }

/* ---------- buttons ---------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 5px;
  padding: var(--pad-ctl);
  background: var(--btn-bg);
  border: var(--btn-border);
  border-radius: var(--radius);
  box-shadow: var(--btn-shadow);
  color: var(--ink);
  font: var(--fs-ctl) var(--font);
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
}
.btn:hover { background: var(--btn-bg-hover); text-decoration: none; color: var(--ink); }
.btn:active { border: var(--btn-border-active); }
/* A disabled button is a disabled button, whatever it was before. Without the
   second line a primary in a theme that fills it with the accent goes grey on
   blue, which is the worst contrast in the app. */
.btn[disabled] { color: var(--ink-3); text-shadow: 1px 1px 0 var(--paper); cursor: default; pointer-events: none; }
.btn-primary[disabled] { background: var(--btn-bg); border: var(--btn-border); }
.btn.sm { padding: var(--pad-ctl-sm); }
.btn.block { width: 100%; }
.btn-primary { font-weight: bold; background: var(--btn-primary-bg); color: var(--btn-primary-fg); }
.btn-primary:hover { background: var(--btn-primary-hover); color: var(--btn-primary-fg); }
.btn-ghost { background: transparent; border-color: transparent; }
.btn-ghost:hover { background: var(--btn-bg); border: var(--btn-border); }
.btn-danger { color: var(--danger-fg); font-weight: bold; }

/* ---------- fields ---------- */

.field { display: block; margin-bottom: 8px; }
.field > label { display: block; font-weight: bold; margin-bottom: 2px; }
.field .hint { color: var(--ink-2); font-size: 11px; margin-top: 2px; }
.field .err { color: var(--bad); font-size: 11px; margin-top: 2px; }
/* Every page is the wide one now, and a text field that is eleven hundred
   pixels wide for a display name is a form nobody can read the shape of. */
.field input, .field select, .field textarea { max-width: 420px; }

input[type=text], input[type=email], input[type=password], input[type=number], textarea, select {
  width: 100%;
  padding: var(--pad-in);
  background: var(--paper);
  color: var(--ink);
  border: var(--in-border);
  border-radius: var(--radius);
  font: var(--fs) var(--font);
}
input:disabled { background: var(--field); color: var(--ink-2); }

/* The chevron is drawn rather than native, with enough room that it can never
   sit on top of the last letter of the longest option. */
select {
  appearance: none;
  padding-right: 22px;
  background-image: linear-gradient(45deg, transparent 50%, var(--ink) 50%),
                    linear-gradient(135deg, var(--ink) 50%, transparent 50%);
  background-position: calc(100% - 13px) calc(50% + 1px), calc(100% - 8px) calc(50% + 1px);
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}

/* ---------- switches ----------

   There are no bare checkboxes anywhere in this app. Anything that is on or
   off is a switch, drawn here as a period one: a sunken rail with a beveled
   gray knob that slides across it, and the rail goes title bar blue when it is
   on. It steps rather than glides, because nothing in 2001 eased. */

.switch { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; padding: 2px 0; user-select: none; }
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.switch .track {
  width: 34px; height: 16px; flex: none; position: relative;
  background: var(--field);
  border: var(--in-border);
  border-radius: var(--track-radius);
}
.switch .track::after {
  content: "";
  position: absolute; left: 0;
  /* Full height of the rail whatever its border is, rather than a number that
     only lines up with a two pixel bevel. */
  width: var(--knob-w); top: 0; bottom: 0;
  background: var(--btn-bg);
  border: var(--btn-border);
  border-radius: var(--knob-radius);
  transition: var(--knob-anim);
}
.switch input:checked + .track { background: var(--accent-ink); }
.switch input:checked + .track::after { transform: translateX(var(--knob-x)); }
.switch input:disabled + .track { opacity: .5; }
.switch .lbl { font-size: var(--fs); }

/* ---------- segmented control ---------- */

.tabs { display: inline-flex; }
.tabs button {
  padding: var(--pad-ctl);
  background: var(--btn-bg);
  border: var(--btn-border);
  border-radius: var(--radius);
  font: var(--fs-ctl) var(--font);
  cursor: pointer;
}
.tabs button.on { border: var(--btn-border-active); background: var(--cream); font-weight: bold; }
.tabs-select { display: none; }
@media (max-width: 640px) { .tabs { display: none; } .tabs-select { display: block; } }

/* ---------- pills ---------- */

.pill {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 0 4px;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--field);
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.pill.live { background: var(--cream); font-weight: bold; }
.pill.quiet { color: var(--ink-3); }
.pill.good { color: var(--good); }
.pill.bad { color: var(--bad); }

/* The licence line an admin sees, and only an admin. Warn rather than bad: a
   server that is running perfectly well and needs paperwork is not an error. */
.licence-note { border-color: var(--warn); }
.licence-note .card-body { color: var(--warn); }
.dot { width: 7px; height: 7px; background: var(--good); flex: none; }
.dot.off { background: var(--ink-3); }

/* ---------- tables ----------

   Flush inside a panel, lavender header, hairline rules. Below the breakpoint
   each row becomes a block of its own, so nothing scrolls sideways. */

table.list { width: 100%; border-collapse: collapse; }
table.list th {
  background: var(--lav);
  border-bottom: 1px solid var(--rule);
  text-align: left;
  padding: var(--pad-cell);
  font-size: var(--fs-sm);
  white-space: nowrap;
}
table.list td { padding: var(--pad-cell); border-bottom: 1px solid var(--hair); vertical-align: middle; }
table.list tbody tr:last-child td { border-bottom: 0; }
table.list tbody tr:hover td { background: var(--cream); }
table.list td.right, table.list th.right { text-align: right; }

@media (max-width: 720px) {
  table.list thead { display: none; }
  table.list, table.list tbody, table.list tr, table.list td { display: block; width: 100%; }
  table.list tr { border: 1px solid var(--rule); margin: 6px; padding: 2px 0; }
  table.list td { border: 0; padding: 3px 6px; display: flex; justify-content: space-between; gap: 10px; }
  table.list td::before { content: attr(data-label); color: var(--ink-3); font-size: 10px; }
  table.list td:empty { display: none; }
}

/* ---------- avatars ---------- */

/* A border, because a picture with a pale edge on a pale panel has no edge at
   all, and half of these are drawings with a light background. */
.av {
  border-radius: 50%; background: var(--field); flex: none; display: block;
  object-fit: cover;
  border: 1px solid var(--rule);
}
.av.lg, .av.xl { border-width: 2px; }
.av.xs { width: 16px; height: 16px; }
.av.sm { width: 22px; height: 22px; }
.av.md { width: 32px; height: 32px; }
.av.lg { width: 72px; height: 72px; }
.av.xl { width: 96px; height: 96px; }

.avpick { display: grid; grid-template-columns: repeat(auto-fill, minmax(46px, 1fr)); gap: 4px; }
.avpick button { padding: 2px; background: transparent; border: 2px solid transparent; cursor: pointer; line-height: 0; }
.avpick button:hover { border-color: var(--edge); }
.avpick button.on { border-color: var(--bad); background: var(--cream); }
.avpick img { width: 100%; height: auto; border-radius: 50%; display: block; }

/* ---------- tooltip ----------

   Mounted on the body and positioned fixed, so a panel with overflow can never
   clip it, and shown only for a real pointer: a tap fires mouseenter and never
   fires the matching mouseleave, which would leave one stuck on the screen. */

.tip {
  position: fixed; z-index: 200; pointer-events: none;
  max-width: 240px; padding: 2px 5px;
  background: var(--cream);
  border: 1px solid var(--ink);
  font-size: var(--fs-sm); line-height: 1.35;
}

/* ---------- modal ----------

   Nothing in this app calls confirm() or alert(). */

.scrim { position: fixed; inset: 0; z-index: 150; background: rgba(0, 0, 0, .35); display: grid; place-items: center; padding: 14px; }
.modal {
  width: 100%; max-width: 400px;
  background: var(--face); border: var(--btn-border);
  border-radius: var(--radius-panel); box-shadow: var(--panel-shadow);
}
.modal > .card-head {
  background: var(--accent-ink); background-image: var(--strip-image);
  color: var(--on-accent); border-bottom: 0; padding: 3px 6px;
}
.modal > .card-body, .modal > .card-foot { background: var(--face); }
.modal > .card-foot { border-top: 0; }
.modal input, .modal select { background: var(--paper); }

/* ---------- menus ---------- */

.menu {
  position: fixed; z-index: 160; min-width: 150px;
  background: var(--face);
  border: var(--btn-border);
  border-radius: var(--radius-panel);
  box-shadow: var(--panel-shadow);
  padding: 2px;
}
.menu .mhead {
  display: flex; align-items: center; gap: 5px;
  padding: 2px 6px 3px; margin-bottom: 2px;
  border-bottom: 1px solid var(--edge);
  font-weight: bold;
}
.menu button {
  display: flex; width: 100%; align-items: center; gap: 6px;
  padding: 2px 8px; border: 0; background: transparent;
  color: var(--ink); font: var(--fs-ctl) var(--font); cursor: pointer; text-align: left;
}
.menu button:hover { background: var(--accent-ink); color: var(--on-accent); }
.menu button.danger:hover { background: var(--bad); color: var(--on-accent); }

/* ---------- toasts ---------- */

.toasts { position: fixed; right: 8px; bottom: 8px; z-index: 180; display: grid; gap: 5px; justify-items: end; }
.toast {
  background: var(--cream);
  border: 1px solid var(--ink);
  border-left: 4px solid var(--strip);
  padding: 4px 8px; font-size: var(--fs-sm); max-width: 300px;
}
.toast.bad { border-left-color: var(--bad); }
.toast.good { border-left-color: var(--good); }

/* ---------- chat ---------- */

.chat { display: flex; flex-direction: column; min-height: 0; min-width: 0; }
.chat .log {
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
  margin: 4px; padding: 3px 5px;
  background: var(--paper);
  border: var(--in-border);
  border-radius: var(--radius);
  line-height: 1.4;
}
.chat .log .ln { word-wrap: break-word; }
.chat .log .sys { color: var(--link); }
.chat .log .who { font-weight: bold; cursor: pointer; }
.chat .say { padding: 0 4px 4px; }

/* ---------- the lobby and the table ----------

   Three panes on a screen with room, and a stack on one without, which is the
   one thing the applet never had to worry about. */

.lobby, .tablepage {
  display: grid;
  gap: 6px;
  height: calc(100dvh - var(--chrome));
  padding: 4px 0 8px;
}
.lobby {
  grid-template-columns: minmax(0, 1fr) 220px;
  grid-template-rows: minmax(200px, 1fr) minmax(150px, 220px);
  grid-template-areas: "tables people" "chat people";
}
.tablepage {
  grid-template-columns: 116px minmax(0, 1fr) 210px;
  grid-template-rows: minmax(240px, 1fr) minmax(130px, 190px);
  grid-template-areas: "rail board side" "rail chat chat";
}
.lobby > .card, .tablepage > .card {
  display: flex; flex-direction: column; min-height: 0; min-width: 0; margin: 0;
}
/* flex:1 and not just min-height:0. A flex column stretches its children
   across, never down, so without this the body is only as tall as whatever is
   already in it, and a board that measures its pane comes out half size and
   then never changes, because nothing ever resizes to tell it otherwise. */
.lobby > .card > .card-body, .tablepage > .card > .card-body {
  flex: 1 1 auto; overflow-y: auto; min-height: 0;
}

/* The left rail on a table: the stack of beveled buttons, with the blue strip
   headers over each group, exactly as the applet had it. */
.rail {
  grid-area: rail; background: var(--field);
  border: 1px solid var(--rule); border-radius: var(--radius-panel);
  padding: 4px; overflow-y: auto;
}
.rail .btn { width: 100%; margin-bottom: 3px; }
.strip {
  background: var(--strip-bg); background-image: var(--strip-image);
  color: var(--strip-fg);
  border-radius: var(--radius);
  font-size: var(--fs-xs); padding: 1px 4px; margin: 6px 0 3px;
}
.strip:first-child { margin-top: 0; }
/* A gap between two groups of rail buttons. It used to be an empty strip,
   which was invisible when the accent was navy and a bright blue brick in
   every theme whose accent is not. */
.railgap { height: 10px; }
.rail .switch { display: flex; }
.rail select { font-size: var(--fs-sm); }

@media (max-width: 940px) {
  .lobby, .tablepage {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: none;
    grid-template-areas: none;
    height: auto;
  }
  .lobby > .card, .tablepage > .card, .rail { grid-area: auto !important; }
  .lobby > .card > .card-body, .tablepage > .card > .card-body { max-height: 55vh; }
  .lobby .chat .log, .tablepage .chat .log { max-height: 34vh; }
  .rail { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; }
  .rail .btn { width: auto; margin: 0; }
  .rail .strip { width: 100%; margin: 2px 0; }
}

/* The live tables list and the online list on the front page: one line each,
   truncated rather than wrapped, because three wrapped lines per person turns
   a summary into a wall. */
#whosonline .person .tiny, #whosonline .person .nm {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* ---------- how to play ----------

   The rules were a stack of paragraphs, which is accurate and is not something
   anybody reads. So: a row of facts you can take in without reading at all, the
   object of the game set apart, and the rest in two columns at a readable
   measure rather than one ribbon down the middle of a wide page. */
.helpfacts {
  display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
  margin-bottom: 10px;
}
.helpfacts .glyph {
  width: 26px; height: 26px; flex: none;
  display: grid; place-items: center;
  background: var(--accent-ink); color: var(--on-accent);
  border-radius: var(--radius);
  font-size: 15px; line-height: 1;
}
.helplead {
  font-size: calc(var(--fs) + 1px);
  border-left: 3px solid var(--accent-ink);
  background: var(--field);
  padding: 8px 10px;
  margin: 0 0 10px;
}
.helpbody { columns: 2; column-gap: 22px; }
.helpbody p { break-inside: avoid; margin: 0 0 8px; }
@media (max-width: 780px) { .helpbody { columns: 1; } }
/* In the modal there is no room for two columns of anything. */
.modal .helpbody { columns: 1; }
.modal .helplead { font-size: var(--fs); }
/* The live tables list on the front page: one line each, truncated rather than
   wrapped, because three wrapped lines per table turns a summary into a wall. */
#livetables .person { grid-template-columns: 8px minmax(0, 1fr) auto; align-items: center; }
#livetables .person .nm { font-weight: bold; }
#livetables .person .tiny { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---------- people ---------- */

.people { display: flex; flex-direction: column; }
.person {
  display: grid; grid-template-columns: 22px minmax(0, 1fr) auto;
  gap: 6px; align-items: center;
  padding: 1px 4px;
  border: 1px solid transparent;
  cursor: pointer; width: 100%; background: transparent; color: inherit;
  font: var(--fs) var(--font); text-align: left;
}
.person:hover { background: var(--cream); border-color: var(--rule); }
.person .nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.person .rt { color: var(--ink-2); font-size: var(--fs-sm); font-variant-numeric: tabular-nums; }
.person.seated .nm { color: var(--good); font-weight: bold; }

/* ---------- seats ---------- */

.seats { display: grid; gap: 3px; }
.seat {
  display: grid; grid-template-columns: 32px minmax(0, 1fr) auto;
  gap: 7px; align-items: center;
  padding: 3px 4px;
  border: 1px solid transparent;
  background: var(--field);
}
.seat.turn { background: var(--cream); border-color: var(--rule); }
.seat.open { background: transparent; border: 1px dashed var(--edge); cursor: pointer; }
.seat.open:hover { border-color: var(--strip); background: var(--cream); }
.seat .nm { font-weight: bold; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.seat .side { font-size: var(--fs-sm); color: var(--ink-2); }
.seat .turnmark { color: var(--alert-fg); font-weight: bold; font-size: var(--fs-sm); }

/* ---------- boards ---------- */

.board-area {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 8px; padding: 6px; min-height: 100%;
  background: var(--field);
}
canvas.board { display: block; border: 1px solid var(--edge); touch-action: none; max-width: 100%; }
.turnline { font-weight: bold; }
.scoreline { display: flex; gap: 8px; align-items: center; }
.controls { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; justify-content: center; font-size: var(--fs-sm); }
.controls label { display: flex; align-items: center; gap: 4px; }
.controls input[type=range] { width: 110px; }
.controls select { width: auto; }

.dice { display: flex; gap: 4px; align-items: center; justify-content: center; flex-wrap: wrap; }
.die {
  width: 22px; height: 22px;
  background: var(--paper); border: 1px solid var(--ink);
  display: grid; place-items: center;
  font: bold 13px var(--font); font-variant-numeric: tabular-nums;
}
.cube { padding: 1px 5px; background: var(--paper); border: 1px solid var(--ink); font-size: 11px; }

/* ---------- empty states ---------- */

.empty { padding: 20px 12px; text-align: center; color: var(--ink-2); }
.empty h3 { color: var(--ink); margin-bottom: 3px; }

.foot { margin-top: 16px; border-top: 1px solid var(--rule); padding: 5px 0 20px; font-size: var(--fs-sm); color: var(--ink-2); }

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}

/* ---------- card games ----------

   A playing card is .pcard, not .card: .card is the panel every page is built
   out of, and giving playing cards that name made every panel in the app forty
   pixels wide and fifty six tall.

   A card has to be readable at a glance, clickable, and legible on a phone, so
   these are elements rather than something drawn on a canvas. The look is the
   one every card game has: white, a rank in the corner, a suit under it, red
   for the red suits. */

.cardtable { display: flex; flex-direction: column; gap: 8px; width: 100%; align-items: center; }

.pcard {
  display: inline-grid;
  place-items: center;
  width: 40px; height: 56px;
  padding: 2px;
  background: var(--card-face);
  color: var(--card-ink);
  border: 1px solid var(--edge);
  font: 12px var(--font);
  line-height: 1.1;
  cursor: default;
}
.pcard .r { font-weight: bold; font-size: 14px; }
.pcard .s { font-size: 16px; }
.pcard.red { color: var(--card-red); }
/* Trump, in Euchre. A tint rather than a border, because the border width is
   what marks a card as playable and two of them fight. The left bower is trump
   while still being printed as another suit, so this is the only thing on the
   table that says which cards are actually good. */
.pcard.trump { background: #fff3c4; box-shadow: inset 0 -3px 0 var(--strip); }
.pcard.playable { cursor: pointer; border-color: var(--strip); border-width: 2px; }
.pcard.playable:hover { background: #fbfbe8; transform: translateY(-4px); }
.pcard[disabled] { opacity: .85; }
/* A card chosen for the Hearts pass. It stays lifted so three of them read as
   a set at a glance, and keeps the .playable border width so picking one does
   not shove the rest of the hand sideways. */
.pcard.picked {
  background: #fbfbe8;
  border-color: var(--strip); border-width: 2px;
  transform: translateY(-8px);
  box-shadow: 0 2px 0 rgba(0, 0, 0, .25);
}
.pcard.back {
  width: 12px; height: 18px; padding: 0;
  background: repeating-linear-gradient(45deg, var(--strip) 0 3px, #16357f 3px 6px);
  border-color: var(--strip);
}

.sp-score { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; justify-content: center; }

.ring {
  display: grid;
  grid-template-columns: minmax(90px, 1fr) minmax(150px, 2fr) minmax(90px, 1fr);
  grid-template-rows: auto auto auto;
  grid-template-areas: ". north ." "west middle east" ". . .";
  gap: 6px;
  width: 100%;
  align-items: center;
  justify-items: center;
}
.sp-seat { text-align: center; padding: 3px 5px; border: 1px solid transparent; min-width: 0; }
.sp-seat.turn { border-color: var(--rule); background: var(--cream); }
.sp-seat.north { grid-area: north; }
.sp-seat.west { grid-area: west; }
.sp-seat.east { grid-area: east; }

/* Six and eight round the table, for Hold'em, Chinese Checkers and Bingo. The
   four seat ring puts one player on each side; these put two or three down each
   side, so the middle stays the middle however many are sitting at it. */
.ring.six {
  grid-template-columns: minmax(90px, 1fr) minmax(150px, 2fr) minmax(90px, 1fr);
  grid-template-rows: auto auto auto;
  grid-template-areas:
    "nw north ne"
    "west middle east"
    ". . .";
}
.ring.eight {
  grid-template-columns: minmax(80px, 1fr) minmax(80px, 1fr) minmax(150px, 2fr) minmax(80px, 1fr) minmax(80px, 1fr);
  grid-template-rows: auto auto auto;
  grid-template-areas:
    "nw north north north ne"
    "west west middle east east"
    "sw . . . se";
}
.sp-seat.nw { grid-area: nw; }
.sp-seat.ne { grid-area: ne; }
.sp-seat.sw { grid-area: sw; }
.sp-seat.se { grid-area: se; }
@media (max-width: 620px) {
  .ring.six, .ring.eight {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-rows: none;
    grid-template-areas: none;
  }
  .ring.six > *, .ring.eight > * { grid-area: auto !important; }
  .ring.six .sp-middle, .ring.eight .sp-middle { grid-column: 1 / -1; }
}
.sp-seat .nm { font-weight: bold; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sp-seat .backs { display: flex; justify-content: center; margin-top: 2px; }
.sp-seat .backs .pcard.back { margin-left: -7px; }
.sp-seat .backs .pcard.back:first-child { margin-left: 0; }

.sp-middle {
  grid-area: middle;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, auto);
  grid-template-areas: ". n ." "w . e" ". s .";
  gap: 2px;
  place-items: center;
  min-height: 130px;
  background: var(--field);
  border: 1px solid var(--rule);
  padding: 4px;
  width: 100%;
}
.played.north { grid-area: n; }
.played.west { grid-area: w; }
.played.east { grid-area: e; }
.played.south { grid-area: s; }

.sp-bid { display: flex; flex-wrap: wrap; gap: 3px; align-items: center; justify-content: center; }
.sp-hand { display: flex; flex-wrap: wrap; gap: 3px; justify-content: center; padding-top: 4px; }

@media (max-width: 620px) {
  .pcard { width: 32px; height: 46px; }
  .pcard .r { font-size: 12px; }
  .pcard .s { font-size: 13px; }
}

/* ---------- themes ----------

   The look above is the default and the one this program is for: 2001, hard
   corners, beveled gray. Everything below is the same app wearing somebody
   else's desktop, and each one is a block of variables rather than a second
   stylesheet, which is the whole reason the components were written in terms
   of --btn-border and --radius instead of in terms of the bevel.

   A theme sets three kinds of thing. The palette, which is most of it. The
   shape: corner radius, whether a control is beveled or hairlined, whether
   anything casts a shadow. And the type, because Tahoma is as much of Windows
   XP as the blue is.

   What no theme touches: the layout, the class names, and a playing card. */

/* Windows XP, Luna blue. Gradient title bars, silver controls, Tahoma. */
[data-theme="xp"] {
  --lav: #d6e5f5;
  --cream: #fffbcc;
  --field: #f1efe2;
  --face: #ece9d8;
  --face-2: #d4d0c8;
  --edge: #aca899;
  --strip: #0a246a;
  --rule: #919b9c;
  --hair: #e3e3db;
  --link: #0000ee;
  --seen: #551a8b;
  --ink: #000000;
  --ink-2: #3f3f3f;
  --ink-3: #6f6f66;
  --paper: #ffffff;
  --page: #ece9d8;
  --good: #007000;
  --warn: #a06000;
  --bad: #cc0000;
  --felt: #1f7a3d;
  --font: Tahoma, Verdana, Arial, sans-serif;

  --radius: 3px;
  --radius-panel: 3px;
  --btn-border: 1px solid #003c74;
  --btn-border-active: 1px solid #003c74;
  --btn-bg: linear-gradient(180deg, #ffffff 0%, #f3f2ea 45%, #e4e1d2 46%, #f6f5eb 100%);
  --btn-bg-hover: linear-gradient(180deg, #ffffff 0%, #fdf6d8 45%, #f6e7a8 46%, #fdf9e4 100%);
  --btn-shadow: none;
  --in-border: 1px solid #7f9db9;
  --panel-shadow: none;
  --head-image: linear-gradient(180deg, rgba(255, 255, 255, .75), rgba(0, 0, 0, .07));
  --strip-image: linear-gradient(180deg, #3a6ea5, #0a246a);
  --knob-anim: transform .12s ease;
}

/* Windows 7, Aero. Softer, glassier, and the first one with a real shadow. */
[data-theme="win7"] {
  --alert-fg: #cc0000;
  --badge-bg: var(--field);
  --lav: #dbe9f7;
  --cream: #cce8ff;
  --field: #f7f9fc;
  --face: #f0f0f0;
  --face-2: #dcdcdc;
  --edge: #8e8f8f;
  --strip: #1f5c99;
  --rule: #b6c4d2;
  --hair: #e6ecf2;
  --link: #0645ad;
  --seen: #6b4f9e;
  --ink: #101010;
  --ink-2: #444444;
  --ink-3: #6b7683;
  --paper: #ffffff;
  --page: #eef3f9;
  --good: #1a7a2e;
  --warn: #a06000;
  --bad: #c62828;
  --felt: #1f7a3d;
  --font: "Segoe UI", Tahoma, Arial, sans-serif;

  --radius: 3px;
  --radius-panel: 4px;
  --btn-border: 1px solid #8e9ba8;
  --btn-border-active: 1px solid #5a7a99;
  --btn-bg: linear-gradient(180deg, #fdfdfd 0%, #eff0f1 50%, #e2e5e8 51%, #f5f6f7 100%);
  --btn-bg-hover: linear-gradient(180deg, #f6fbff 0%, #e7f5fd 50%, #d3ecfc 51%, #eaf7ff 100%);
  --btn-shadow: 0 1px 0 rgba(255, 255, 255, .7) inset;
  --in-border: 1px solid #abadb3;
  --panel-shadow: 0 1px 3px rgba(20, 40, 70, .10);
  --head-image: linear-gradient(180deg, rgba(255, 255, 255, .8), rgba(0, 0, 0, .05));
  --strip-image: linear-gradient(180deg, #3a86c8, #1f5c99);
  --knob-anim: transform .16s ease;
}

/* Windows 10. The flat one: no gradient anywhere, one blue, square corners. */
[data-theme="win10"] {
  --alert-fg: #b91c1c;
  --accent-ink: #005a9e;
  --lav: #e8e8e8;
  --cream: #cce4f7;
  --field: #f3f3f3;
  --face: #e1e1e1;
  --face-2: #cccccc;
  --edge: #adadad;
  --strip: #0078d7;
  --rule: #d1d1d1;
  --hair: #ebebeb;
  --link: #0067c0;
  --seen: #68217a;
  --ink: #1b1b1b;
  --ink-2: #444444;
  --ink-3: #767676;
  --paper: #ffffff;
  --page: #f3f3f3;
  --good: #107c10;
  --warn: #9d5d00;
  --bad: #c50f1f;
  --felt: #1f7a3d;
  --font: "Segoe UI", Tahoma, Arial, sans-serif;

  --radius: 0;
  --radius-panel: 0;
  --btn-border: 1px solid var(--edge);
  --btn-border-active: 1px solid var(--strip);
  --btn-bg: #e1e1e1;
  --btn-bg-hover: #e5f1fb;
  --in-border: 1px solid #767676;
  --panel-shadow: none;
  --knob-anim: transform .14s ease;
}

/* Windows 11. Rounded, quiet, and everything floats slightly. */
[data-theme="win11"] {
  --alert-fg: #cc0000;
  --badge-bg: var(--field);
  --lav: #eef0f3;
  --cream: #cfe4fa;
  --field: #f3f3f3;
  --face: #fbfbfb;
  --face-2: #e5e5e5;
  --edge: #d1d1d1;
  --strip: #0067c0;
  --rule: #e2e2e2;
  --hair: #f0f0f0;
  --link: #0067c0;
  --seen: #7a4f9e;
  --ink: #1a1a1a;
  --ink-2: #4a4a4a;
  --ink-3: #707070;
  --paper: #ffffff;
  --page: #f3f3f3;
  --good: #0f7b0f;
  --warn: #9d5d00;
  --bad: #c42b1c;
  --felt: #1f7a3d;
  --font: "Segoe UI Variable Text", "Segoe UI", system-ui, sans-serif;

  --radius: 6px;
  --radius-panel: 8px;
  --btn-border: 1px solid #d8d8d8;
  --btn-border-active: 1px solid #c4c4c4;
  --btn-bg: #fbfbfb;
  --btn-bg-hover: #f0f0f0;
  --btn-shadow: 0 1px 0 rgba(0, 0, 0, .04);
  --in-border: 1px solid #d8d8d8;
  --panel-shadow: 0 2px 6px rgba(0, 0, 0, .06);
  --knob-anim: transform .18s cubic-bezier(.2, .9, .3, 1);
}

/* macOS. Rounded, soft shadows, system blue. */
[data-theme="macos"] {
  --alert-fg: #cc0000;
  --badge-bg: var(--field);
  --accent-ink: #0057b8;
  --lav: #eceaf0;
  --cream: #d7e9ff;
  --field: #f2f2f7;
  --face: #ffffff;
  --face-2: #e5e5ea;
  --edge: #d0d0d5;
  --strip: #007aff;
  --rule: #d8d8dc;
  --hair: #ebebef;
  --link: #0066cc;
  --seen: #8e5bd0;
  --ink: #1d1d1f;
  --ink-2: #4b4b50;
  --ink-3: #71717a;
  --paper: #ffffff;
  --page: #f5f5f7;
  --good: #248a3d;
  --warn: #b25000;
  --bad: #d70015;
  --felt: #1f7a3d;
  --font: -apple-system, "SF Pro Text", "Helvetica Neue", system-ui, sans-serif;

  --radius: 6px;
  --radius-panel: 10px;
  --btn-border: 1px solid #d0d0d5;
  --btn-border-active: 1px solid #b8b8bd;
  --btn-bg: #ffffff;
  --btn-bg-hover: #f0f0f4;
  --btn-shadow: 0 1px 1px rgba(0, 0, 0, .05);
  --in-border: 1px solid #c9c9ce;
  --panel-shadow: 0 1px 4px rgba(0, 0, 0, .08);
  --knob-anim: transform .2s cubic-bezier(.2, .9, .3, 1);
}

/* macOS, dark. */
[data-theme="macos-dark"] {
  --danger-fg: #ff9c9c;
  --alert-fg: #ff9c9c;
  --badge-bg: var(--field);
  --accent-ink: #0a63c9;
  --lav: #3a3a3c;
  --cream: #14406e;
  --field: #232326;
  --face: #3a3a3c;
  --face-2: #48484a;
  --edge: #48484a;
  --strip: #0a84ff;
  --rule: #3f3f42;
  --hair: #333336;
  --link: #6cb0ff;
  --seen: #bf9bea;
  --ink: #f5f5f7;
  --ink-2: #b4b4ba;
  --ink-3: #9a9aa0;
  --paper: #2c2c2e;
  --page: #1c1c1e;
  --good: #32d74b;
  --warn: #ff9f0a;
  --bad: #ff453a;
  --felt: #1a6b3c;
  --on-accent: #ffffff;
  --font: -apple-system, "SF Pro Text", "Helvetica Neue", system-ui, sans-serif;

  --radius: 6px;
  --radius-panel: 10px;
  --btn-border: 1px solid #55555a;
  --btn-border-active: 1px solid #6a6a70;
  --btn-bg: #3a3a3c;
  --btn-bg-hover: #47474a;
  --btn-shadow: none;
  --in-border: 1px solid #55555a;
  --panel-shadow: 0 1px 4px rgba(0, 0, 0, .4);
  --knob-anim: transform .2s cubic-bezier(.2, .9, .3, 1);
}

/* Linux Mint, Mint-Y. Grey, with the green. */
[data-theme="mint"] {
  --alert-fg: #cc0000;
  --badge-bg: var(--field);
  --accent-ink: #496e2f;
  --lav: #e4e4e2;
  --cream: #d9ecd0;
  --field: #f2f2f0;
  --face: #fbfbfa;
  --face-2: #dededc;
  --edge: #c6c6c2;
  --strip: #5c8a3c;
  --rule: #d3d3d0;
  --hair: #eaeae7;
  --link: #3d7a1f;
  --seen: #6b5b8e;
  --ink: #1f1f1c;
  --ink-2: #4a4a45;
  --ink-3: #71716c;
  --paper: #ffffff;
  --page: #f0f0ee;
  --good: #3d7a1f;
  --warn: #a06000;
  --bad: #c0392b;
  --felt: #2a7a45;
  --font: Ubuntu, Cantarell, "Noto Sans", system-ui, sans-serif;

  --radius: 4px;
  --radius-panel: 6px;
  --btn-border: 1px solid #c6c6c2;
  --btn-border-active: 1px solid #a9a9a4;
  --btn-bg: #fbfbfa;
  --btn-bg-hover: #efefec;
  --btn-shadow: 0 1px 0 rgba(0, 0, 0, .04);
  --in-border: 1px solid #c6c6c2;
  --panel-shadow: 0 1px 3px rgba(0, 0, 0, .06);
  --knob-anim: transform .16s ease;
}

/* Ubuntu, Yaru. Aubergine and orange. */
[data-theme="ubuntu"] {
  --lav: #ece7ea;
  --cream: #fbe3d7;
  --field: #f6f2f4;
  --face: #ffffff;
  --face-2: #e3dade;
  --edge: #cfc4ca;
  --strip: #772953;
  --rule: #d8cdd3;
  --hair: #efe8ec;
  --link: #19647e;
  --seen: #772953;
  --ink: #1f1a1d;
  --ink-2: #4c4348;
  --ink-3: #756a70;
  --paper: #ffffff;
  --page: #f7f4f5;
  --good: #0e8420;
  --warn: #c7802b;
  --bad: #c7162b;
  --felt: #2a7a45;
  --font: Ubuntu, "Noto Sans", system-ui, sans-serif;

  --radius: 4px;
  --radius-panel: 6px;
  --btn-border: 1px solid #cfc4ca;
  --btn-border-active: 1px solid #e95420;
  --btn-bg: #ffffff;
  --btn-bg-hover: #fdeee7;
  --btn-shadow: 0 1px 0 rgba(0, 0, 0, .04);
  --in-border: 1px solid #cfc4ca;
  --panel-shadow: 0 1px 3px rgba(0, 0, 0, .06);
  --knob-anim: transform .16s ease;
}

/* Plain light. No desktop in mind, just a quiet modern one. */
[data-theme="light"] {
  --alert-fg: #cc0000;
  --badge-bg: var(--field);
  --badge-fg: #b91c1c;
  --lav: #f0f0f2;
  --cream: #e8f0ff;
  --field: #f4f4f5;
  --face: #ffffff;
  --face-2: #e4e4e7;
  --edge: #d4d4d8;
  --strip: #2563eb;
  --rule: #e4e4e7;
  --hair: #f0f0f1;
  --link: #2563eb;
  --seen: #7c3aed;
  --ink: #18181b;
  --ink-2: #52525b;
  --ink-3: #71717a;
  --paper: #ffffff;
  --page: #fafafa;
  --good: #16803c;
  --warn: #b45309;
  --bad: #dc2626;
  --felt: #1f7a3d;
  --font: system-ui, -apple-system, "Segoe UI", Arial, sans-serif;

  --radius: 4px;
  --radius-panel: 6px;
  --btn-border: 1px solid #d4d4d8;
  --btn-border-active: 1px solid #a1a1aa;
  --btn-bg: #ffffff;
  --btn-bg-hover: #f4f4f5;
  --btn-shadow: 0 1px 0 rgba(0, 0, 0, .04);
  --in-border: 1px solid #d4d4d8;
  --panel-shadow: 0 1px 2px rgba(0, 0, 0, .05);
  --knob-anim: transform .16s ease;
}

/* Plain dark. */
[data-theme="dark"] {
  --danger-fg: #f87171;
  --alert-fg: #ff9c9c;
  --badge-bg: var(--field);
  --accent-ink: #1d4ed8;
  --lav: #2a2a30;
  --cream: #2b3550;
  --field: #1c1c20;
  --face: #2a2a30;
  --face-2: #3a3a42;
  --edge: #3f3f47;
  --strip: #3b82f6;
  --rule: #35353b;
  --hair: #2a2a30;
  --link: #7ab7ff;
  --seen: #c4a4f5;
  --ink: #f4f4f5;
  --ink-2: #a1a1aa;
  --ink-3: #8b8b95;
  --paper: #202024;
  --page: #161619;
  --good: #4ade80;
  --warn: #fbbf24;
  --bad: #f87171;
  --felt: #17603a;
  --on-accent: #ffffff;
  --font: system-ui, -apple-system, "Segoe UI", Arial, sans-serif;

  --radius: 4px;
  --radius-panel: 6px;
  --btn-border: 1px solid #3f3f47;
  --btn-border-active: 1px solid #52525b;
  --btn-bg: #2a2a30;
  --btn-bg-hover: #34343c;
  --btn-shadow: none;
  --in-border: 1px solid #3f3f47;
  --panel-shadow: 0 1px 3px rgba(0, 0, 0, .5);
  --knob-anim: transform .16s ease;
}

/* Modern, and Modern Dark.

   Not another desktop: this is what a web application looks like now. Near
   black on white, one blue, hairline rules, a filled primary button, six pixel
   corners and a single soft shadow. Nothing decorative and nothing period.

   It is also the theme the density layer above was added for. The other twelve
   are the same sizes in different paint, because 2001 and Windows 11 really do
   put a button at the same height. A modern interface does not: thirteen pixel
   text, twelve pixels of padding in a panel header, and a control you could hit
   with a thumb. That is most of what makes this feel like a different program
   rather than the same one repainted. */
[data-theme="modern"] {
  --strip-bg: var(--field);
  --strip-fg: var(--ink-2);
  --col-l: 182px;
  --col-r: 196px;
  --alert-fg: #cc0000;
  --badge-bg: var(--field);
  --badge-fg: #b91c1c;
  --accent-ink: #1d4ed8;
  --lav: #ffffff;
  --cream: #eff4ff;
  --field: #f4f4f5;
  --face: #ffffff;
  --face-2: #e4e4e7;
  --edge: #d4d4d8;
  --strip: #2563eb;
  --rule: #e4e4e7;
  --hair: #f1f1f3;
  --link: #2563eb;
  --seen: #6d28d9;
  --ink: #09090b;
  --ink-2: #52525b;
  --ink-3: #71717a;
  --paper: #ffffff;
  --page: #f7f7f8;
  --good: #15803d;
  --warn: #b45309;
  --bad: #dc2626;
  --felt: #15803d;
  --on-accent: #ffffff;
  --font: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

  --radius: 6px;
  --radius-panel: 10px;
  --btn-border: 1px solid #e4e4e7;
  --btn-border-active: 1px solid #d4d4d8;
  --btn-bg: #ffffff;
  --btn-bg-hover: #f4f4f5;
  --btn-shadow: 0 1px 2px rgba(9, 9, 11, .05);
  --btn-primary-bg: #2563eb;
  --btn-primary-hover: #1d4ed8;
  --btn-primary-fg: #ffffff;
  --in-border: 1px solid #d4d4d8;
  --panel-shadow: 0 1px 2px rgba(9, 9, 11, .06);
  --knob-anim: transform .18s cubic-bezier(.2, .9, .3, 1);

  --fs: 13px;
  --fs-sm: 12px;
  --fs-xs: 11px;
  --fs-ctl: 13px;
  --lh: 1.5;
  --pad-ctl: 6px 12px;
  --pad-ctl-sm: 4px 10px;
  --pad-head: 8px 12px;
  --pad-body: 12px;
  --pad-cell: 8px 12px;
  --pad-in: 6px 8px;

  --track-radius: 999px;
  --knob-radius: 999px;
  --knob-w: 14px;
  --knob-x: 18px;
  --head-weight: 600;
  --focus: 2px solid #2563eb;
  --link-underline: none;
  --chrome: 116px;
}

[data-theme="modern-dark"] {
  --strip-bg: var(--field);
  --strip-fg: var(--ink-2);
  --col-l: 182px;
  --col-r: 196px;
  --danger-fg: #f87171;
  --badge-bg: var(--field);
  --accent-ink: #1d4ed8;
  --lav: #131317;
  --cream: #1e293b;
  --field: #17171c;
  --face: #1b1b21;
  --face-2: #27272e;
  --edge: #2f2f37;
  --strip: #3b82f6;
  --rule: #27272e;
  --hair: #1f1f25;
  --link: #93b8ff;
  --seen: #c4b5fd;
  --ink: #fafafa;
  --ink-2: #a1a1aa;
  --ink-3: #8b8b93;
  --paper: #131317;
  --page: #0b0b0e;
  --good: #4ade80;
  --warn: #fbbf24;
  --bad: #f87171;
  --felt: #14532d;
  --on-accent: #ffffff;
  --font: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

  --radius: 6px;
  --radius-panel: 10px;
  --btn-border: 1px solid #2f2f37;
  --btn-border-active: 1px solid #3f3f47;
  --btn-bg: #1b1b21;
  --btn-bg-hover: #26262e;
  --btn-shadow: none;
  --btn-primary-bg: #2563eb;
  --btn-primary-hover: #1d4ed8;
  --btn-primary-fg: #ffffff;
  --in-border: 1px solid #2f2f37;
  --panel-shadow: 0 1px 3px rgba(0, 0, 0, .5);
  --knob-anim: transform .18s cubic-bezier(.2, .9, .3, 1);

  --fs: 13px;
  --fs-sm: 12px;
  --fs-xs: 11px;
  --fs-ctl: 13px;
  --lh: 1.5;
  --pad-ctl: 6px 12px;
  --pad-ctl-sm: 4px 10px;
  --pad-head: 8px 12px;
  --pad-body: 12px;
  --pad-cell: 8px 12px;
  --pad-in: 6px 8px;

  --track-radius: 999px;
  --knob-radius: 999px;
  --knob-w: 14px;
  --knob-x: 18px;
  --head-weight: 600;
  --focus: 2px solid #3b82f6;
  --link-underline: none;
  --chrome: 116px;
}

/* The picker itself, up in the masthead beside the account. */
.themepick { width: auto; font-size: var(--fs-sm); padding: 1px 20px 1px 4px; }
