/* =========================================================================
   Everything's Computer — holding page
   A pseudo-OS installer dialog, randomly skinned as one of fourteen
   1980s/90s operating systems.

   Everything is authored at 1:1 native OS pixels inside .stage, then scaled
   by --zoom, which is chosen so one stage pixel covers a whole number of
   DEVICE pixels — that is what keeps bitmap fonts and 1px bevels crisp.
   Usually that means an integer, but on a screen reporting a fractional DPR
   (Android, commonly 2.75) app.js nudges it off the integer to land back on
   the device grid. See the device-pixels note in app.js.

   Section map
     1. Reset + page
     2. Scaling + layout
     3. Shared dialog structure
     4. Progress motion
     5. Fonts
     6. Skins  (search for "SKIN —" to jump between them)
   ========================================================================= */


/* ---- 1. Reset + page --------------------------------------------------- */

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

html, body {
  height: 100%;
  margin: 0;
  padding: 0;
}

body {
  overflow: hidden;
  background: #000;
  -webkit-text-size-adjust: 100%;
  -webkit-font-smoothing: antialiased;
}

button { font: inherit; color: inherit; }


/* ---- 2. Scaling + layout ---------------------------------------------- */

/* The page sits at 1:1 native operating-system pixels — the size these dialogs
   actually were. Zoom is a hidden key command rather than a breakpoint:

     z         cycle  1x -> 2x -> 3x -> 1x
     1 2 3     jump straight to that zoom

   app.js sets --zoom and data-zoom on <html>, skips any level that would not
   fit the window, and remembers the choice for that visitor. With JavaScript
   off the page stays at 1x, which is the intended size anyway.

   The two are not always the same number. data-zoom is the level, 1/2/3, and
   cursors.css uses it to pick the 1x/2x/3x pointer artwork. --zoom is the
   level times a device-pixel correction, so on a screen at DPR 2.75 a
   data-zoom of 1 comes with a --zoom of 1.0909. Anything picking artwork
   wants data-zoom; anything measuring wants --zoom. */
:root {
  --zoom: 1;
  --dither: calc(2px * var(--zoom));   /* backdrop dither cell, viewport-space */
}

.screen {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  overflow: hidden;
}

/* transform doesn't affect layout, so the untransformed box is centred by the
   grid and scale() grows it symmetrically about that centre.

   Every bitmap on this page is native OS pixels — lifted chrome, dither tiles,
   pattern swatches. The zoom is an integer scale, so those want nearest
   neighbour, and without saying so the browser smooths them: at 3x a one-pixel
   black rule lifted out of a capture arrives as a three-pixel grey smear on a
   skin that has no grey in it. Vectors and text are unaffected — they are
   re-rasterised at the scaled size either way. */
.screen, .stage { image-rendering: pixelated; }

.stage {
  transform: scale(var(--zoom));
  transform-origin: center center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
}


/* ---- 3. Shared dialog structure --------------------------------------- */

/* The dialog and the web button under it share one grid cell — both are
   placed in 1/1, so the cell takes the dialog's size and the button sits
   centred inside it, covered. Nothing hides the button: it is underneath,
   and dragging the window off it is what finds it. */
.deck { display: grid; }
.deck > * { grid-area: 1 / 1; }

.dialog {
  /* Above the button it covers, and above the address below it — the window
     can be dragged over both once the title bar moves it, and without this it
     would go UNDER them, since they are static and painted after it. */
  position: relative;
  z-index: 2;
  width: var(--dlg-w, 330px);
  background: var(--face, #c0c0c0);
  color: var(--text, #000);
  font-family: var(--font);
  font-size: var(--fsize, 11px);
  line-height: var(--lh, 1.35);
  text-align: left;
}

.titlebar {
  display: flex;
  align-items: center;
  height: var(--title-h, 18px);
  color: var(--title-fg, #fff);
  background: var(--title-bg, #000080);
  font-size: var(--title-fsize, var(--fsize, 11px));
  overflow: hidden;
}

.tb-l, .tb-r { display: flex; align-items: center; flex: none; gap: 2px; }
.tb-c        { display: flex; align-items: center; flex: 1 1 auto; min-width: 0; overflow: hidden; }

.title {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: clip;
}

/* Title-bar widgets are opt-in: a skin shows only the ones that OS had. */
.w { display: none; flex: none; font-style: normal; }

.content { padding: var(--pad, 12px); }

.message { margin: 0 0 var(--gap, 12px); }

.progress { margin: 0 0 var(--gap, 12px); min-width: 0; }

.track {
  position: relative;
  height: var(--bar-h, 16px);
  overflow: hidden;
}

/* app.js sets an explicit px width; max-width is the belt-and-braces cap so a
   mis-measured track can never paint a fill past the end of its own bar. */
.fill {
  height: 100%;
  width: 0;             /* driven by js/app.js */
  max-width: 100%;
  will-change: width;
}

.actions { display: flex; justify-content: flex-end; }

.btn {
  min-width: var(--btn-w, 75px);
  height: var(--btn-h, 23px);
  padding: 0 12px;
  border: 0;
  border-radius: 0;
  background: var(--face, #c0c0c0);
  font-family: inherit;
  font-size: inherit;
  line-height: 1;
  text-align: center;
  -webkit-appearance: none;
  appearance: none;
}

/* The mnemonic letter of the button's label. Nothing is drawn here: a skin
   whose buttons showed accelerator underlines opts in and the rest inherit
   an ordinary span. */
.mn { font: inherit; }

.btn:focus-visible { outline: 1px dotted currentColor; outline-offset: -4px; }

/* Measured in native px, so the width budget is the viewport divided by the
   zoom — that keeps it from being clipped by .screen's overflow on a phone. */
.notice {
  margin: 0;
  max-width: calc((100vw - 40px) / var(--zoom));
  text-align: center;
  font-family: var(--font);
  font-size: var(--notice-fsize, var(--fsize, 11px));
  line-height: 1.4;
  color: var(--notice-fg, #fff);
}

/* THE WEB BUTTON, 88x31 and animated, under the dialog. Native size at 1x and
   scaled with the stage like everything else, so it wants the same
   nearest-neighbour treatment .screen and .stage already get.

   Which one shows is a RARITY TIER, and it is keyed to the odds the draw
   actually runs at rather than to a taste about which skins look precious:

     dark       common      the twenty-four skins in the ordinary bag, and
                            Mac OS 8 & 9 on the Lavender desktop it boots
                            into eight visits in ten
     silver     uncommon    one of the twenty-one colour desktops — a third
                            of Mac OS 8 & 9's draws
     gold       rare        Newton and Bob, held out of the main bag; about
                            one draw in a hundred and thirty
     holo-edge  legendary   an 8.5b6 appearance theme, one Mac OS 8 & 9 draw
                            in a hundred

   Mac OS Default is excluded from silver by name because it is the common
   case wearing a colour, and the appearance themes are excluded explicitly
   rather than by specificity — the silver selector is the more specific of
   the two, so left to a tie it would win over the one that should. */
/* A link, and reachable only once the window has been moved off it — while
   it is covered the dialog takes the clicks, which is what makes finding it
   worth something. No cursor rule: cursors.css already gives every element
   inside .screen that skin's own pointer, and a link is not worth breaking
   that for. */
.badge {
  display: block;
  width: 88px;
  height: 31px;
  place-self: center;          /* centred under the window that covers it */
  background: none 0 0 / 88px 31px no-repeat;
}
/* The image is attached only once data-badge is set, which app.js does in an
   idle callback. Without that the gold and holographic ones — 22 frame GIFs
   at 23-29 KB — are fetched on every first paint for something no visitor can
   see until they drag the window off it. Bob's first visit was 59.5 KB, of
   which 23,504 was a picture underneath an opaque dialog. */
[data-badge] .badge { background-image: url("../img/made-with-claude-dark.gif"); }
[data-badge][data-badge][data-os="bob"] .badge,
[data-badge][data-os="newton"] .badge {
  background-image: url("../img/made-with-claude-gold.gif");
}
[data-badge][data-os="macos89"][data-desk]:not([data-desk="Mac OS Default"]):not([data-theme]) .badge {
  background-image: url("../img/made-with-claude-silver.gif");
}
[data-os="macos89"][data-theme] .badge {
  background-image: url("../img/made-with-claude-holo-edge.gif");
}

.notice a { color: inherit; text-decoration: none; }
.notice a:hover, .notice a:focus-visible { text-decoration: underline; }

/* The name of the operating system, under the address. It sits in the flow
   permanently at opacity 0, so revealing it moves nothing — a line that
   appeared would shove the whole stage upward.

   Double-click the dialog to show it, again to hide it. It used to come up on
   hover, which meant it was on screen for anyone who happened to be pointing
   at the thing and never for anyone on a touchscreen; asking for it is the
   point. app.js sets data-osname-shown on the root and writes the text when
   the skin changes — the reveal itself is still only this one rule. */
.osname {
  display: block;
  margin-top: 4px;
  opacity: 0;
  transition: opacity .5s ease;
}
[data-osname-shown] .osname { opacity: .5; }

/* With the name showing, the title bar is a drag handle (js/app.js). Both are
   off the same double-click. touch-action keeps a drag on a phone from
   scrolling the page instead, and the two user-selects stop the title
   highlighting blue under the pointer halfway through a drag. */
[data-osname-shown] .titlebar {
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
}

@media (prefers-reduced-motion: reduce) { .osname { transition: none; } }


/* ---- 4. Progress motion ------------------------------------------------ */
/* The bar never completes: app.js walks it forward, stalls, slips back.
   Barber-pole stripes on the skins that had them animate independently. */

@keyframes barber   { to { background-position-x: 11.3137085px; } }  /* 8px / cos45 */
@keyframes barber-r { to { background-position-x: -11.3137085px; } }

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


/* ---- 5. Fonts ---------------------------------------------------------- */
/* All subset to the ~75 characters this page uses, which is why they are
   1.4-6 KB each. Only the font belonging to the skin that loaded is ever
   fetched — the rest are never referenced by any rule that matches.

   CREDITS (two of these carry attribution requirements — see README.md):
     Geneva 9        © Kelsey Higham, FontStruct — CC BY 3.0
     MS Sans Serif   © lou 2017, FontStruct      — CC BY-SA 3.0
     ChiKareGo2      Giles Booth — Chicago recreation, freely distributed
     Liberation Sans SIL Open Font License 1.1
     GNU FreeSans   GNU GPL v3 with the font exception
     DejaVu Sans     Bitstream Vera / DejaVu licence
     Topaz A500/A1200  generated from AnsiLove's MIT-licensed bitmap tables;
                       the underlying design is © Commodore-Amiga            */

@font-face {                             /* System 6/7, Mac OS 8/9 */
  font-family: "Chicago";
  src: url("../fonts/chicago.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: block;
}
@font-face {                             /* Mac small text; Newton stand-in */
  font-family: "Geneva";
  src: url("../fonts/geneva.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: block;
}
@font-face {                             /* Windows 3.1 / 95 */
  font-family: "MS Sans Serif";
  src: url("../fonts/mssans.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: block;
}
@font-face {
  font-family: "MS Sans Serif";
  src: url("../fonts/mssans-bold.woff2") format("woff2");
  font-weight: bold; font-style: normal; font-display: block;
}
@font-face {                             /* Windows XP — Tahoma stand-in */
  font-family: "Tahoma Alt";
  src: url("../fonts/tahoma-alt.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: swap;
}
/* BeOS — Swis721 BT, Bitstream's Helvetica, which is not free. This is GNU
   FreeSans, drawn from URW's Nimbus Sans L, so it is the same Helvetica and not
   an Arial standing in for one.

   It is a stand-in all the same, and it has to be: BeOS drew its titles with
   anti-aliasing, and the five 8x tab captures prove it is outline text and not
   a strike — the same letter comes out as a DIFFERENT set of pixels in
   different tabs, because each one lands on a different fraction of a pixel.
   No threshold reconciles them (every one from 60 to 195 either splits a letter
   or makes two 'a's disagree), so there is nothing here to harvest the way the
   QNX and RISC OS faces were.

   Which face, then, is measured rather than argued. Each of the 23 letters the
   captures carry, compared against its best-matching appearance at its best
   1px alignment, disagreeing pixels as a share of the union:

       FreeSans 12px        28.3%          FreeSans 13px        25.6%
       Nimbus Sans 12px     32.3%          Liberation 13px      27.5%
       Liberation 12px      34.9%          Nimbus Sans 13px     30.4%

   13px fits the letterforms better and the SPACING worse — it runs the five
   titles 9 to 11px long, where 12px lands every one of them within 2px — so
   12px it is, and FreeSans over the Liberation the skin used to use.        */
/* And the same face at the size R3 uses for everything that is NOT a window
   title — cap 7, x-height 5, one pixel of stem. That one IS a strike: every
   letter that repeats across the two Installer captures comes out as the same
   bitmap every time, which is the test the tab titles fail, so it is lifted
   whole rather than approximated; see build/beos-harvest.py. Glyphs the captures
   never showed are FreeSans struck at 9ppem, which has the same cap height and
   x-height, and struck in GREY so they do not sit hard-edged among soft ones.

   The anti-aliasing is reproduced as MEASURED, level for level — no floor
   under it, no contrast curve over it. A tenth of a pixel stays a tenth. That
   modulation, from a tenth at the end of a curve to six tenths where two
   strokes meet, is the whole character of the face, and lifting the light end
   of it flattens every grey into the same one.

   One glyph is redrawn rather than lifted, and only one: the 's'. Why is in
   build/beos-harvest.py. */
@font-face {
  font-family: "BeSwiss";
  src: url("../fonts/beswiss.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: block;
}
@font-face {
  font-family: "Swis721Alt";
  src: url("../fonts/swis721-alt.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Swis721Alt";
  src: url("../fonts/swis721-alt-bold.woff2") format("woff2");
  font-weight: bold; font-style: normal; font-display: swap;
}
/* NeXTSTEP set its interface in Helvetica, and the Power Off panel shows three
   sizes of it at once: a bold cap-14 heading, a cap-11 body and a cap-9 button
   label. All three are ONE BIT — not a grey pixel anywhere on a machine whose
   screen was two bits deep — so unlike the BeOS faces there is no coverage to
   carry here.

   They are Adobe's hand-tuned Helvetica bitmaps rather than an outline
   rasterised small, and that is measured, not assumed: a Nimbus Sans strike —
   the same Helvetica, at the ppem that lands on the same cap height AND the
   same x-height — reproduces only 4 of the 21 body letters the panel shows.
   So the letters are lifted; see build/next-harvest.py. What the panel does
   not show is that Nimbus Sans strike underneath, which is why the sizes below
   are the ppem that matches each face's cap and x-height exactly. */
@font-face {
  font-family: "NXBody";
  src: url("../fonts/nxbody.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: block;
}
@font-face {
  font-family: "NXBtn";
  src: url("../fonts/nxbtn.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: block;
}
@font-face {
  font-family: "NXMenu";
  src: url("../fonts/nxmenu.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: block;
}
/* The smallest of the five — cap 7, x-height 5 — off the two legal-notice
   panels NeXTSTEP shows at install time, recovered to native 375x72 and 374x81
   in two colours flat. Ten lines of boilerplate repeat every letter many times
   over, so each glyph arrives with its own consistency check and 48 of them
   agree with themselves across 216 instances; the backing strike is Nimbus
   Sans at 9ppem, which lands on this face's cap AND x-height exactly. Only two
   characters are not the panels' own: the capital P, derived from the R by
   taking its leg off (a rule checked against the strike's own R and P at this
   size), and the '@', which appears nowhere in either panel and is drawn —
   Helvetica's own outline fills its ring solid at 9ppem, so the strike put a
   black blob in the middle of the address. */
/* Apple II DeskTop's screen face, lifted whole off three 560x192 captures —
   45 characters, 205 instances, zero spacing residual. Its rows are DOUBLED
   in the font file: double hi-res pixels are twice as tall as they are wide,
   so a face built on the raw framebuffer grid would come out squat. Doubled,
   it sits 1:1 at 16px on a square-pixel grid and looks like the machine did.
   There is no strike underneath it — no outline rasterised at a 2:1 aspect
   would be anything but wrong — so what the captures do not show, this does
   not have, and the stack falls through to Geneva. */
@font-face {
  font-family: "A2Sys";
  src: url("../fonts/a2sys.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: block;
}
@font-face {
  font-family: "NXLegal";
  src: url("../fonts/nxlegal.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: block;
}
@font-face {
  font-family: "NXTitle";
  src: url("../fonts/nxtitle.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: block;
}
@font-face {
  font-family: "NXHead";
  src: url("../fonts/nxhead.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: block;
}
@font-face {                             /* RISC OS */
  font-family: "Helv";
  src: url("../fonts/helv.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Helv";
  src: url("../fonts/helv-bold.woff2") format("woff2");
  font-weight: bold; font-style: normal; font-display: swap;
}
@font-face {                             /* AmigaOS 1.3 — Topaz (A500) */
  font-family: "Topaz13";
  src: url("../fonts/topaz13.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: block;
}
@font-face {                             /* AmigaOS 2.0 — Topaz (A1200) */
  font-family: "Topaz20";
  src: url("../fonts/topaz20.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: block;
}
@font-face {                             /* Windows 1.01 — harvested system font */
  font-family: "Win1System";
  src: url("../fonts/win1.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: block;
}
/* RISC OS 3 — the Wimp's System font, built by build/riscos-font.py from
   bitmaps harvested out of the 640x480 captures. 8px advance, 16px tall. */
/* Xerox GlobalView 2 — a stand-in for Xerox's own Modern, which has no free
   recreation. DejaVu Sans at 11ppem, as its own 1-bit strike: cap height 8
   against the capture's 8, and the measured strings land within a pixel. */
@font-face {
  font-family: "GVSans";
  src: url("../fonts/gvsans.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: block;
}
/* Microsoft Bob — Times New Roman, which is what Rover actually spoke in.
   Three 1-bit strikes of Liberation Serif, which is metric-compatible with it:
   11px for body text, 13px regular for option rows and buttons, 13px bold for
   what Rover says. See the skin's note in skins.css for the measurements. */
@font-face {
  font-family: "BobSerif";
  src: url("../fonts/bobserif11.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: block;
}
@font-face {
  font-family: "BobSerifL";
  src: url("../fonts/bobserif13.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: block;
}
@font-face {
  font-family: "BobSerifL";
  src: url("../fonts/bobserif13b.woff2") format("woff2");
  font-weight: bold; font-style: normal; font-display: block;
}
@font-face {                             /* Mac OS 8.5b6 Gizmo — its own
                                            large system font */
  font-family: "Gadget";
  src: url("../fonts/gadget.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: block;
}
@font-face {                             /* Mac OS 8.5b6 Hi-Tech — its own
                                            large system font, harvested */
  font-family: "Techno";
  src: url("../fonts/techno.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: block;
}
/* Solaris 8 / CDE — DtStandard itself, for the 36 characters Hami's captures
   contain, over DejaVu Sans at 14ppem for the rest.

   The strike started as DejaVu alone, picked on metrics: cap 10 against the
   capture's 10, x-height 8 against 8, "Cancel" in an identical 45x11 ink box.
   Close enough to pass at a glance and not close enough to keep — Hami named
   the spur on 'a' the first time he saw it. build/cde-harvest.py now cuts the
   real glyphs out of four captures and build/prop-font.py lays them over the
   strike, so what is DejaVu's is only what no capture shows: mostly capitals
   nothing follows, and the six characters the page needs that none of them
   contains at all (v, I, comma, @, 8, and a lone digit or two).

   Advances are solved rather than assumed — a cut gives ink boxes, not
   origins — and the fit is exact: 216 spacing equations, worst residual 0.000
   px, word space 4.00. Rendered back against the captures, 16 of 17 lines come
   out pixel for pixel, the exception being "OK", two glyphs whose one equation
   cannot be split. One bit deep throughout, because CDE drew type that way and
   an antialiased outline is the wrong texture whatever the shapes are. */
@font-face {
  font-family: "DtSans";
  src: url("../fonts/dtsans.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: block;
}
/* RISC OS 4's desktop face: Homerton, which is Acorn's Helvetica, so URW's
   Nimbus Sans is the same design rather than a stand-in. Regular weight, at
   14px.

   This took three passes and the middle one was wrong, which is worth
   recording. Hami's Task Manager sample shows a BOLD face with a single-storey
   'a' and hooked descenders — not Helvetica at all — so this pointed at
   Poppins for a while. His About-the-Operating-System capture then shows plain
   Helvetica: double-storey 'a', regular weight. The two disagree because they
   are not the same machine — the Task Manager sheet's greys are #dedede and
   #737373, the RISC OS palette, while the About window's are #dddddd and
   #777777, and RISC OS lets the desktop font be configured. Hami picked the
   About window as the reference, so that is what this is.

   Sized on the Display-manager and shutdown captures, which are the ones the
   chrome came from: eight measured strings land within 2px each, six of them
   within 1, for 8px of error in total. */
/* Photon's UI face, at the one size QNX 4 drew it: cap 9, x-height 7, 1px
   stems regular and 2px bold. It is a hand-tuned X11 bitmap font and no outline
   rasterises to it — of six candidates at five sizes the best, Liberation Sans
   at 12ppem, reproduces three of the nine glyphs Hami's Font/cour14 field
   carries exactly. So the ground under both of these is a strike: Liberation
   Sans and Liberation Sans Bold rendered 1-bit at 12ppem with their own hints,
   which gets the size and the hard edge right. The bold strike is then SMEARED
   — OR'd with itself a pixel right, the way QuickDraw and X11 both made a bold
   out of a strike — because Liberation Bold's stems come out 1px at 12ppem and
   Photon's are 2.

   Over that go the real bitmaps: nine glyphs in the regular, off the Font
   field, and twenty-one in the bold, cut out of two caption captures by
   build/qnx-harvest.py. "Everything's Computer" is all Photon's own except v,
   m and the apostrophe; "Cancel" except the c.

   The two cells differ (13 rows against 14, Liberation Bold's descender is
   deeper) but both cap heights are 9, so the regular sits 1:1 at 13px and the
   bold at 14px and they line up. */
@font-face {
  font-family: "PhotonHelv";
  src: url("../fonts/phelv.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "PhotonHelvBold";
  src: url("../fonts/phelvb.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: swap;
}
/* And a third, which is where the message line and the buttons both end up: the
   small bold Netscape's group-box labels and tab captions are set in — cap 8
   against the caption's 9, two-pixel stems, the same size as the body text
   beside it. Twenty-eight of its glyphs are harvested off six captures and one,
   the capital I, is the harvested 'l' — in the caption face, where both are
   harvested, they are the same nine rows and the same advance.

   Every string I have a reference for reproduces exactly: Cancel, Memory Cache
   Options, Point Sizes and Connection all lay out 0 pixels from their captures.

   The three cells differ — 13 rows, 14 and 12 — but the regular sits 1:1 at
   13px, the caption bold at 14px and this at 12px, and their baselines line up.
   The big cap-14 heading face that was here briefly is gone: its long heading
   is the one string in this skin that no fixed set of advances reproduces. */
@font-face {
  font-family: "PhotonHelvBtn";
  src: url("../fonts/phelvbtn.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "RO4Desk";
  src: url("../fonts/ro4desk.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "RiscOS";
  src: url("../fonts/riscos.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: block;
}

/* Bitmap faces must never be smoothed or synthetically emboldened. */
[data-os="system6"] .stage, [data-os="system7"] .stage,
[data-os="macos89"]  .stage, [data-os="newton"]  .stage,
[data-os="win1"]    .stage, [data-os="win30"]   .stage,
[data-os="win31"]   .stage, [data-os="win95"]   .stage,
[data-os="win98"]   .stage, [data-os="amiga13"] .stage,
[data-os="amiga20"] .stage, [data-os="a2desk"]  .stage,
[data-os="geosa2"]  .stage, [data-os="geosc64"] .stage,
[data-os="win2"]    .stage, [data-os="bob"]     .stage,
[data-os="riscos3"] .stage, [data-os="riscosnew"] .stage,
[data-os="gv2"]     .stage,
[data-os="solaris8"] .stage {
  -webkit-font-smoothing: none;
  -moz-osx-font-smoothing: unset;
  font-smooth: never;
}
