/* ==========================================================================
   Platinum
   ==========================================================================
   Mac OS 8, transcribed from Classicy (robbiebyrd/classicy, Unlicense) into
   this site's own tokens and markup. Classicy is React with a stylesheet per
   component; none of it can be linked. What is here is its design, written
   again against .card_styles / .sidebar2_group-title / .button.

   ---- Why this is a small file ----
   The bevel block in index.html is already token-driven: every edge on the
   desk is var(--gs-frame), var(--gs-well) or var(--gs-bevel), and every stop
   in those is a var too. So most of Platinum arrives by REDEFINING those
   seven tokens rather than by writing the cards again. What is left is the
   handful of things Win95 has no equivalent for: the hard black border and
   its unblurred drop, the striped title bar, and a button with a corner.

   Loaded AFTER <style id="gs-bevel">, which is what lets a redefinition here
   reach rules declared there -- a <link> and a <style> cascade in document
   order, so later wins the ties.

   ---- The two ramps ----
   Classicy carries --color-system-01..07 (the grey the chrome is made of) and
   --color-theme-01..07 (the same seven steps in the accent colour), and its
   Appearance control panel swaps the second. This site already has that
   second ramp: --primary--50..950 is color-mix() off --primary--base, and the
   swatches in the menu card repoint --primary--base. So the theme ramp is
   bridged to what is already there and the colour swapping works untouched --
   eight primaries, both themes, no new machinery.
   ========================================================================== */

:root {
  /* ---- The chrome's own grey ----
     Classicy's default theme, verbatim: themes.json system[0..6]. Seven steps
     from near-white to near-black, and every edge in Platinum is two of them
     against each other. */
  --color-system-01: #eeeeee;
  --color-system-02: #dddddd;
  --color-system-03: #cccccc;
  --color-system-04: #aaaaaa;
  --color-system-05: #808080;
  --color-system-06: #393939;
  --color-system-07: #202020;

  /* ---- The accent, which is Sean's ----
     Classicy ships twenty-one of these (azul, bondi, copper, crimson...); this
     site has eight and already computes the ramp. Straight across. */
  --color-theme-01: var(--primary--50);
  --color-theme-02: var(--primary--100);
  --color-theme-03: var(--primary--300);
  --color-theme-04: var(--primary--500);
  --color-theme-05: var(--primary--700);
  --color-theme-06: var(--primary--800);
  --color-theme-07: var(--primary--900);

  /* ---- The window's own colours ----
     theme.color.window in themes.json. The border is BLACK, not a grey -- that
     single hard line is most of the difference between a Platinum window and a
     Win95 one, which has no black anywhere on its outside. */
  --color-window-border: #000000;
  --color-window-border-outset: #ffffff;
  --color-window-border-inset: #cccccc;
  --color-window-frame: #cccccc;
  --color-window-title: #000000;
  --color-window-document: #ffffff;
  --color-outline: var(--color-theme-05);
  --color-highlight: var(--color-theme-03);

  /* ---- Measurements ----
     theme.measurements.window, verbatim. controlSize 12 is the close/zoom box,
     and the title bar is one and a half of them -- 18px, which is the real
     height and less than half the 34px band this desk wore under Win95. */
  --window-border-size: 1px;
  --window-control-size: 12px;
  --window-padding-size: 6px;
  --window-scrollbar-size: 17px;
  /* ---- 34px, and not Classicy's own number ----
     Its 1.5 control boxes is 18px, which is the real Mac OS 8 height. Three
     things in this site are measured off the band instead: the folded card is
     the band plus its 4px of face, and the three keyframes that fold and
     unfold it travel to the same number -- calc(2.125rem + 4px), where the
     2.125rem IS this. Take the band to 18 and the fold still stops at 38, so
     20px of .card_styles_inner shows under it with the well's top edge on it.
     That seam is the one this desk has already been taken apart for twice.

     So the band keeps the height everything else was built against, and what
     Platinum changes is what is drawn in it. */
  --pl-title-h: 2.125rem;

  /* Mac OS 8 HIG, chapter 3. Classicy exposes these as tokens so controls lay
     out to the guidelines instead of to whatever looked right. */
  --hig-button-height: 20px;
  --hig-button-min-width: 58px;
  --hig-button-text-padding: 8px;
  --hig-button-default-ring: 3px;

  /* ---- The faces ----
     theme.typography. Charcoal is the 8.5 system font and Chicago the one
     before it; Geneva is what small text was set in. */
  --pl-ui: "Charcoal", "ChicagoFLF", "Geneva", sans-serif;
  --pl-body: "Geneva", "Charcoal", sans-serif;
  --pl-mono: "Monaco", "Courier New", monospace;
}

/* ==========================================================================
   The bevel tokens become Platinum
   ==========================================================================
   Win95 lights a plate from the upper left with white and shades the lower
   right with grey, and the whole plate floats free. Platinum does the same two
   lines but draws a BLACK rule around the outside of the object and drops a
   hard, unblurred shadow off it. So the light and shade stops keep their jobs
   and only their values change; the black and the drop are added below, where
   the shape of the rule is known.

   The tile pair moves with them. A tile on this desk is a card and takes the
   same treatment -- that was settled when the tiles were rebuilt as cards, and
   nothing about changing systems reopens it. */
:root {
  --gs-lit: var(--color-window-border-outset);
  --gs-lit-2: var(--color-system-02);
  --gs-shade: var(--color-system-05);
  --gs-shade-2: var(--color-system-04);

  /* A well in Platinum is shallower than a Win95 one: one dark line in, one
     light line out, and the document white inside it. */
  --gs-sink: var(--color-system-05);
  --gs-sink-2: var(--color-system-04);
  --gs-rise: var(--color-window-border-outset);
  --gs-rise-2: var(--color-system-02);

  --gs-tile-lit: var(--color-window-border-outset);
  --gs-tile-lit-2: var(--color-system-02);
  --gs-tile-dk: var(--color-window-border);
  --gs-tile-dk-2: var(--color-system-05);
  --gs-tile-edge: var(--color-system-05);
  --gs-tile-edge-2: var(--color-system-04);
}

/* ==========================================================================
   Dark
   ==========================================================================
   Platinum never had one. The ramp is turned end for end rather than invented:
   the chrome stays the same seven steps and reads them from the dark end, so
   an edge that was white-on-grey becomes grey-on-black and every rule written
   against a stop still points at the right side of the object.

   ---- :not([data-theme="light"]), and there is no "dark" to match ----
   This site says LIGHT with an attribute and says dark by taking it off again
   -- js/site.js apply(): setAttribute('data-theme','light') or
   removeAttribute. Dark is the default and has no name. So every block here
   was written against html[data-theme="dark"], which nothing on this site ever
   sets, and the whole of Platinum's dark theme was dead: the chrome kept the
   light grey ramp on a dark desk, and the only reason it ever LOOKED right was
   a test harness setting the attribute by hand.

   Same specificity as the selector it replaces, so nothing else moves. */
html:not([data-theme="light"]) {
  --color-system-01: #202020;
  --color-system-02: #2c2c2c;
  --color-system-03: #393939;
  --color-system-04: #555555;
  --color-system-05: #808080;
  --color-system-06: #aaaaaa;
  --color-system-07: #cccccc;
  --color-window-border: #000000;
  --color-window-border-outset: #6e6e6e;
  --color-window-frame: #393939;
  --color-window-document: #1a1a1a;
  --color-window-title: #f0f0f0;
}

/* ==========================================================================
   The window
   ==========================================================================
   A hard black rule all the way round and a one-pixel drop with no blur on it,
   which is the shadow a 1997 machine could afford and the reason these windows
   sit ON the desktop rather than floating above it.

   The drop is the only part of --gs-frame that was an OUTER shadow; the rest
   were insets. Written here in full rather than as a token because the black
   border changes the box and the inset stops have to start inside it. */
.main-content .card_styles,
.gs-icon .card_styles,
.gs-menu .card_styles {
  border: var(--window-border-size) solid var(--color-window-border);
  border-radius: 0;
  background-color: var(--color-window-frame);
  color: var(--color-window-title);
  box-shadow:
    inset calc(var(--window-border-size) * -1) calc(var(--window-border-size) * -1) var(--color-system-05),
    inset var(--window-border-size) var(--window-border-size) var(--color-window-border-outset),
    var(--window-border-size) var(--window-border-size) 0 0 var(--color-window-border);
}

/* The lift on hover was a Win95 idea -- a plate coming off the table. A
   Platinum window is on the desktop and stays there; what a pointer over it
   earns is nothing at all. */
.main-content .card_styles.is-hover:hover {
  box-shadow:
    inset calc(var(--window-border-size) * -1) calc(var(--window-border-size) * -1) var(--color-system-05),
    inset var(--window-border-size) var(--window-border-size) var(--color-window-border-outset),
    var(--window-border-size) var(--window-border-size) 0 0 var(--color-window-border);
}

/* ==========================================================================
   The title bar is striped
   ==========================================================================
   Classicy ships this as three base64 SVGs -- a left cap, a repeating centre
   and a right cap. Decoded, the centre is a 12px tile of alternating one-pixel
   rows, #fff and #787878, and nothing else. So it is a gradient here instead:
   no assets, no cap images, sharp at any zoom, and -- the reason it matters --
   the dim stripe is a var, which is where the primary lands.

   The stripes run edge to edge and the title sits ON them with the frame's own
   colour behind it, which is how the real thing keeps a long name legible
   without breaking the run. */
.main-content .card_styles > .sidebar2_group-title,
.gs-friend .gs-friend_head > .sidebar2_group-title {
  height: var(--pl-title-h);
  min-height: var(--pl-title-h);
  padding: 0 var(--window-padding-size);
  border: var(--window-border-size) solid var(--color-system-07);
  border-bottom: var(--window-border-size) solid var(--color-system-05);
  border-radius: 0;
  background-color: var(--color-system-03);
  background-image: repeating-linear-gradient(
    to bottom,
    var(--pl-stripe-lit) 0 1px,
    var(--pl-stripe-dim) 1px 2px
  );
  box-shadow: inset var(--window-border-size) var(--window-border-size) var(--color-window-border-outset);
  color: var(--color-window-title);
  font-family: var(--pl-ui);
  font-size: calc(var(--pl-title-h) * 0.4);
  gap: var(--window-padding-size);
}

:root {
  /* The stripe pair. White over the accent's own dark step, so a bar reads as
     the theme's colour at a glance and as stripes up close -- which is the
     whole of what the Appearance control panel did. */
  --pl-stripe-lit: var(--color-window-border-outset);
  --pl-stripe-dim: var(--color-theme-03);
}
html:not([data-theme="light"]) {
  --pl-stripe-lit: var(--color-system-04);
  --pl-stripe-dim: var(--color-theme-07);
}

/* The name sits ON the stripes with nothing behind it. The accidental version
   of this was the friend card -- its header is a level deeper than the old
   selector reached, so it never got the plate, and it is the one that reads
   right. What makes it work is the stripe pair, not a ground. */
.main-content .card_styles > .sidebar2_group-title .pre-heading,
.gs-friend .gs-friend_head > .sidebar2_group-title .pre-heading {
  background-color: transparent;
  font-family: var(--pl-ui);
  text-transform: none;
  letter-spacing: 0;
}

/* ==========================================================================
   The document well
   ==========================================================================
   What a window holds is a document, and a document is white and set INTO the
   frame -- one dark line at the top and left, one light line at the bottom and
   right, and no second ring. Win95's well was two stops deep on all four
   sides; this is the shallower Mac one. */
.main-content .card_styles > .card_styles_inner {
  border-radius: 0;
  background-color: var(--color-window-document);
  box-shadow:
    inset var(--window-border-size) var(--window-border-size) var(--color-system-05),
    inset calc(var(--window-border-size) * -1) calc(var(--window-border-size) * -1) var(--color-window-border-outset);
}

/* ==========================================================================
   Buttons
   ==========================================================================
   platinumWindowDepressable, flattened. Four stops rather than Win95's two:
   the outer pair is the plate's edge and the inner pair is the roll on its
   face, which is what makes a Platinum button look moulded instead of folded.
   A real corner on it, too -- the first rounded button in this lineage. */
/* ---- The plate is the theme's, not the system's ----
   Classicy builds a button out of --color-system-02 and keeps the accent for
   selection only, which is what Apple did. Here the accent IS the site, so the
   face is the theme's lightest step and the roll is cut from the steps above
   and below it. The type stays black: at step 01 the face is light enough on
   all eight primaries that reversing it would cost more than it bought. */
/* ---- Which END of the accent a face comes from ----
   The grey ramp is turned end for end in the dark (see the Dark block) but the
   accent's is NOT, and cannot be: --primary--50 is a mix toward white at both
   themes, because the eight swatches and everything in the site that reads
   them expect it to be. So a button's face was step 01 -- the palest -- under
   a title colour that goes near-white in the dark, which is white on white.
   What turns is which end of the accent a CHROME SURFACE takes, and that is
   one token rather than a second set of button rules. Everything that is a
   plate on this desk reads it, so the phone's bar and the buttons in the cards
   fix together or not at all. */
:root {
  --pl-face: var(--color-theme-01);
  --pl-face-hover: var(--color-theme-02);
  --pl-face-on: var(--color-theme-05);
  --pl-face-on-text: var(--color-window-border-outset);
  /* ---- Black, at both themes, and that is not an oversight ----
     A chip is not chrome. It keeps its accent face in the dark the way it
     always has, and because the accent ramp does not turn, that face is light
     at both themes -- so the ink on it is black at both themes. Written as a
     token rather than as #000 in three rules so the next accent-faced thing
     does not have to work it out again. --color-window-title cannot do this
     job: it is near-white in the dark, which is what put white type on a pale
     green chip. */
  --pl-ink-on-accent: #000000;
}
html:not([data-theme="light"]) {
  --pl-face: var(--color-theme-07);
  --pl-face-hover: var(--color-theme-06);
  --pl-face-on: var(--color-theme-04);
  --pl-face-on-text: #000000;
}
.button {
  border: var(--window-border-size) solid var(--color-window-border);
  border-radius: var(--window-padding-size);
  background-color: var(--pl-face);
  color: var(--color-window-title);
  font-family: var(--pl-ui);
  min-height: var(--hig-button-height);
  box-shadow:
    inset calc(var(--window-border-size) * -1) calc(var(--window-border-size) * -1) var(--color-system-05),
    inset calc(var(--window-border-size) * -2) calc(var(--window-border-size) * -2) var(--color-system-04),
    inset var(--window-border-size) var(--window-border-size) var(--color-theme-03),
    inset calc(var(--window-border-size) * 2) calc(var(--window-border-size) * 2) var(--color-window-border-outset);
}

/* HIG: an OK/Cancel-shaped button is 58px at its narrowest. Icon-only and
   small ones are excused, the same exceptions Classicy makes. */
.button:not(.is-icon_only):not(.is-small):not(.is-ghost) {
  min-width: var(--hig-button-min-width);
}

.button:hover {
  background-color: var(--pl-face-hover);
  box-shadow:
    inset calc(var(--window-border-size) * -1) calc(var(--window-border-size) * -1) var(--color-theme-05),
    inset calc(var(--window-border-size) * -2) calc(var(--window-border-size) * -2) var(--color-theme-04),
    inset var(--window-border-size) var(--window-border-size) var(--color-theme-03),
    inset calc(var(--window-border-size) * 2) calc(var(--window-border-size) * 2) var(--color-window-border-outset);
}

/* Pressed inverts the roll and fills with the accent's dark step, which is
   where Classicy puts --color-system-05 and where this site's own colour
   belongs instead. */
.button:active,
.button.w--current:active {
  background-color: var(--pl-face-on);
  color: var(--pl-face-on-text);
  box-shadow:
    inset calc(var(--window-border-size) * -1) calc(var(--window-border-size) * -1) var(--color-system-05),
    inset calc(var(--window-border-size) * -2) calc(var(--window-border-size) * -2) var(--color-system-06),
    inset var(--window-border-size) var(--window-border-size) var(--color-system-07),
    inset calc(var(--window-border-size) * 2) calc(var(--window-border-size) * 2) var(--color-system-06);
}

/* ---- The default button's ring ----
   Three rings outside the button rather than a thicker edge on it: grey, the
   face colour, then black. Nothing else in this interface says "this is the
   one Return presses", and it is the most recognisable control Apple drew. */
.button.is-primary,
.button.w--current {
  box-shadow:
    0 0 0 calc(var(--hig-button-default-ring) / 3) var(--color-system-04),
    0 0 0 calc(var(--hig-button-default-ring) / 3 * 2) var(--color-system-02),
    0 0 0 var(--hig-button-default-ring) var(--color-window-border),
    inset calc(var(--window-border-size) * -1) calc(var(--window-border-size) * -1) 0 0 var(--color-system-05),
    inset var(--window-border-size) var(--window-border-size) 0 0 var(--color-system-06);
}

/* A ghost button is flat until it is wanted, which is the toolbar behaviour
   the desk already uses; Platinum only changes what "wanted" looks like. */
.button.is-ghost { box-shadow: none; background-color: transparent; border-color: transparent; }
.button.is-ghost:hover {
  border-color: var(--color-window-border);
  background-color: var(--pl-face);
  box-shadow:
    inset calc(var(--window-border-size) * -1) calc(var(--window-border-size) * -1) var(--color-system-05),
    inset var(--window-border-size) var(--window-border-size) var(--color-window-border-outset);
}

.button:focus-visible {
  outline: calc(var(--window-border-size) * 2) solid var(--color-outline);
  outline-offset: var(--window-border-size);
}

/* ==========================================================================
   Type
   ==========================================================================
   The interface's own voice only -- title bars, buttons, the small labels.
   The dictionary entry, the case studies and everything else a visitor came to
   READ keep the faces they were set in: this is a change of chrome, not a
   change of what the site says. */
.pre-heading,
.gs-taskbar_item,
.gs-taskbar_label,
.file_explorer-row,
.badge {
  font-family: var(--pl-ui);
}

/* ==========================================================================
   The menu card's strip
   ==========================================================================
   The menu card wears its title bar turned ninety degrees down its left edge,
   so it takes the same stripes turned with it. to right rather than to bottom
   is the whole change -- the rules run along the bar in both cases, which is
   what makes the two read as one object rotated rather than two patterns. */
.card_styles.is-menu .sidebar2_group-title.is-vertical {
  border: var(--window-border-size) solid var(--color-system-07);
  border-right: var(--window-border-size) solid var(--color-system-05);
  border-radius: 0;
  background-color: var(--color-system-03);
  background-image: repeating-linear-gradient(
    to right,
    var(--pl-stripe-lit) 0 1px,
    var(--pl-stripe-dim) 1px 2px
  );
  box-shadow: inset var(--window-border-size) var(--window-border-size) var(--color-window-border-outset);
  color: var(--color-window-title);
}
/* The word and the marks down it sit on the stripes, the same as the name in a
   horizontal bar does. */
.card_styles.is-menu .sidebar2_group-title.is-vertical .pre-heading {
  background-color: transparent;
  font-family: var(--pl-ui);
}

/* ==========================================================================
   The desktop is the mark, embossed
   ==========================================================================
   Mac OS 8 shipped desktop patterns that were a mark tiled and pressed into
   the ground -- the same drawing twice, a hair apart, one lighter than the
   surface and one darker. Classicy defaults to the Finder face done that way.
   This is the moveRectangles mark done that way, generated by make-emboss.mjs.

   The tile has no colour of its own: it is low-alpha white and low-alpha black
   over whatever is behind it, so it tints to the desktop under it and follows
   all eight primaries and both themes without ever being regenerated.

   AND THE GRID GOES. Two patterns on one surface is one too many, and the
   point of trying this was to see the mark carry the desk the way the Finder
   face carries Classicy's. The grid is still in the markup and one rule
   away -- see .gs-gridfill below.
*/
/* html on the front, and it has to be. .background-overlay is set to
   --surface--grid-background again in a <style> inside the BODY, which is
   later in the document than this file is -- so a bare .background-overlay
   here ties at (0,1,0) and loses, and the light desk stayed pure white while
   the dark one tinted. The dark rule below already carried html:not(...) and
   was the only reason that half ever worked. Measured: white in light, green
   in dark, from the same pair of declarations. */
html .background-overlay {
  /* ---- The startup screen's own green, and for a reason ----
     Platinum's desktop was never the paper colour: it was a COLOUR with the
     pattern pressed into it, and the pattern has no colour of its own, so this
     is the only place the desk gets any.

     It was --color-theme-02, a tint 80% of the way to white, and at that
     lightness the emboss is not there. The tile is two offset copies of the
     mark -- white up-left, black down-right -- and a white highlight on a
     near-white ground has nothing to show, so half the pattern vanished and
     what was left read as a faint grey smudge rather than something pressed
     in. Side by side with the boot screen it looked like the desk had no
     pattern at all.

     So it takes the ground the startup screen already uses. Both tones carry
     on it, the desk and the boot are visibly the same machine, and the one
     surface that had a strong colour stops being the odd one out. */
  background-color: var(--color-theme-05);
  background-image: url("../img/site/emboss-tile.png");
  background-size: 128px 128px;
  background-repeat: repeat;
}
/* Dark keeps its own end of the ramp and does NOT follow the boot. The
   accent ramp does not turn, so the startup screen is this same bright green
   at both themes -- fine for four seconds of full-screen machine, wrong for
   the thing a dark desk of dark windows sits on all evening. And the emboss
   has no trouble here: on a dark ground it is the white copy that carries and
   the black one that disappears, which is the same pattern read from the other
   side rather than half of one. */
html:not([data-theme="light"]) .background-overlay { background-color: var(--color-theme-07); }

/* ---- The grid is gone, and that means the MEASURE, not just its entrance ----
   There are two things here and I only turned off the second one. The measure
   itself -- the dashed rules, the ticks, the plus and the eight dots of the
   64px cell -- is drawn by .page-wrapper::before, a flat colour behind an SVG
   mask. .gs-gridfill is only the entrance: a box per cell that paints the same
   lattice in one at a time on the way in and then hands back. Hiding the
   entrance leaves the thing it was an entrance TO, which is why the desk still
   had a grid on it under the embossed mark.

   Both, then. The mask is what draws it, so the mask is what goes. */
.page-wrapper::before { display: none !important; }
.gs-gridfill,
.gs-gridfill > i { display: none !important; }

/* ==========================================================================
   Chips
   ==========================================================================
   A pill is not a shape this system has. Platinum's small label is a plate
   with the same corner its buttons wear and the same one-pixel rule round it,
   and the accent belongs in its face rather than as a fill that shouts over
   the grey. They stay FLAT -- a chip is a label and nothing about it can be
   pressed, which was settled before this system arrived and is still true. */
.badge {
  border: var(--window-border-size) solid var(--color-window-border);
  border-radius: var(--window-padding-size);
  background-color: var(--color-theme-02);
  color: var(--pl-ink-on-accent);
  font-family: var(--pl-ui);
  box-shadow: none;
}
/* The filled chip keeps its weight -- it is the one that is saying something
   rather than labelling something -- but takes the corner and the rule. */
.badge.is-dark {
  background-color: var(--color-theme-04);
  color: var(--pl-ink-on-accent);
}
/* A chip that is a dot and a word (Online, A_Friend.exe) reads as a readout,
   so it goes in a well rather than on a plate. */
.badge.is-icon {
  background-color: var(--color-window-document);
  box-shadow:
    inset var(--window-border-size) var(--window-border-size) var(--color-system-05),
    inset calc(var(--window-border-size) * -1) calc(var(--window-border-size) * -1) var(--color-window-border-outset);
}

/* ==========================================================================
   The menu bar
   ==========================================================================
   A Mac without one is not a Mac, so the bar comes off the bottom of the
   screen and goes across the top of it at every width -- not just the phone's,
   where it used to be the only navigation. Twenty pixels, white, with one
   black rule under it: that is the whole of the Mac OS 8 menu bar and it has
   not changed since 1984.

   Nothing moves in the markup. js/taskbar.js already builds it in the right
   order for this -- the mark, then the readout, then the group at the far end
   -- which is the Apple menu, the menu titles, and the Application menu of a
   real bar in that order. What changes is where the strip sits and what it is
   made of.

   ---- ON THE DESK ONLY ----
   A twenty-pixel white strip is the right answer on a desk and the wrong one
   on a phone. On a phone that bar is not chrome, it is the NAVIGATION -- the
   wordmark, the menu and the only route to anything -- and the desk's menu bar
   made the one thing you actually press the smallest thing on the screen, at
   the end of the screen your thumb does not reach. So above 1025px the strip
   goes to the top and behaves like a menu bar; below it the bar stays on the
   floor where it was, at its old three cells, wearing the title bar's stripes.
   See the phone block at the end of this section.

   ---- --gs-bar follows the bar ----
   Three scrims inset themselves off the bottom by it, the consent bar parks
   above it and the lightbox sits on it. With the bar at the top there is
   nothing down there to avoid, so it is nought on the desk and stays at three
   cells on the phone, which is what it always was.

   ---- The two type tokens ----
   The strip is 20px in one place and 48px in the other, and type that is a
   fraction of the bar would be 29px on the phone. So the sizes are their own
   tokens rather than a multiple of the height: the bar grows, the words grow
   a little, and nothing has to be talked out of scaling. */
:root {
  --pl-menubar: 20px;
  --pl-bar-type: 12px;
  --pl-bar-icon: 12px;
  --gs-bar: 0px;
}

.gs-taskbar {
  top: 0;
  bottom: auto;
  display: flex !important;
  height: var(--pl-menubar);
  min-height: var(--pl-menubar);
  padding: 0;
  border-top: 0;
  border-bottom: var(--window-border-size) solid var(--color-window-border);
  background-color: var(--color-window-document);
  background-image: none;
  color: var(--color-window-title);
  font-family: var(--pl-ui);
  font-size: var(--pl-bar-type);
  box-shadow: none;
  overflow: visible;
}

/* The desk clears the bar at the top instead of at the bottom. The fitter
   reads padding-bottom to find the desk's floor (gsDeskBottom), so moving the
   room rather than adding to it is what keeps a dragged window able to reach
   the bottom of the screen. */
/* The bar's height and NOT a cell on top of it. 1rem + 20px was 36 where the
   desk used to have 16, and those twenty pixels came off the bottom of the
   field: the page started scrolling, the packer had a taller column to fill
   and the tiles stopped sweeping and started stacking. On a Mac an icon sits
   directly under the menu bar with no air between, which is both the faithful
   answer and the one that gives the packer its old field back. */
.main-content.is-homepage { padding-top: var(--pl-menubar); padding-bottom: 1rem; }

/* It arrives from above now. The old keyframe slid it up off the bottom edge,
   which with the bar at the top is a slide out of the middle of the screen. */
@keyframes gs-bar-down { from { transform: translateY(-100%); } to { transform: none; } }
.gs-taskbar { animation-name: gs-bar-down; }

/* The fades at the ends of the run belonged to a scrolling strip of window
   buttons. A menu bar does not scroll. */
.gs-taskbar::before,
.gs-taskbar::after { display: none !important; }

/* ---- The mark is the Apple menu ----
   First thing in the bar, its own height, and it highlights like a menu title
   because that is what it is. */
.gs-taskbar_brand {
  align-self: stretch;
  gap: 0;
  padding: 0 calc(var(--window-padding-size) * 0.75);
}
.gs-taskbar_mark {
  height: calc(var(--pl-menubar) - 4px);
  width: auto;
}
/* The wordmark was the brand shouting beside the mark. In a menu bar the thing
   next to the apple is a menu title, at the bar's own size and weight. */
.gs-taskbar_name {
  font-family: var(--pl-ui);
  font-size: var(--pl-bar-type);
  font-weight: 400;
  line-height: 1;
}

/* ---- Menu titles ----
   Everything in the bar that can be pressed reads as a title: flat until the
   pointer is on it, then the whole box inverts. Apple inverted; it did not
   tint, did not round and did not lift, and the invert is the reason a menu
   bar never needed a hover colour of its own. */
.gs-taskbar_brand,
.gs-bartrack_viz,
.gs-taskbar_menu,
.gs-bartrack_btn {
  border: 0 !important;
  border-radius: 0 !important;
  background-color: transparent !important;
  background-image: none !important;
  box-shadow: none !important;
  color: var(--color-window-title) !important;
  height: var(--pl-menubar) !important;
  min-height: 0 !important;
  align-self: stretch;
}
.gs-taskbar_brand:hover,
.gs-bartrack_viz:hover,
.gs-taskbar_menu:hover,
.gs-bartrack_btn:hover,
.gs-bartrack_viz[aria-pressed="true"],
.gs-taskbar_menu[aria-expanded="true"] {
  background-color: var(--color-window-border) !important;
  color: var(--color-window-document) !important;
}

/* ---- The readout in the middle ----
   The wordmark and what is playing keep the middle of the bar. No well round
   it any more: a menu bar has no wells, and the thing that tells you it is a
   readout rather than a menu is that it does not highlight. */
.gs-bartrack {
  align-self: stretch;
  padding: 0 var(--window-padding-size);
  gap: var(--window-padding-size);
}
.gs-bartrack_swap {
  box-shadow: none !important;
  margin: 0 !important;
  padding: 0 !important;
  align-self: center;
}
.gs-bartrack_word,
.gs-bartrack_np {
  font-family: var(--pl-ui);
  font-size: var(--pl-bar-type);
}
/* The strapline under the wordmark does not fit a twenty-pixel bar and is not
   a thing a menu bar says. */
.gs-bartrack_word p,
.gs-bartrack_word .text-size-tiny { display: none; }

/* ---- The Application menu ----
   Far right, which is where the running program's name and icon sat, and the
   one place in the bar this site already had something in. */
.gs-taskbar_end {
  align-self: stretch;
  gap: 0;
  padding: 0;
  margin-left: auto;
}
.gs-bartrack_viz,
.gs-taskbar_menu {
  width: auto !important;
  padding: 0 calc(var(--window-padding-size) * 0.75) !important;
  gap: calc(var(--window-padding-size) * 0.5);
}
.gs-taskbar_menu svg,
.gs-bartrack_viz svg { width: var(--pl-bar-icon); height: var(--pl-bar-icon); }

/* ---- The run of windows is a row of menu titles ----
   This is the one part of the old bar that only ever showed on the DESKTOP --
   .gs-taskbar_scroll is display:none below 1025px, which is where the bar used
   to live, so the run had never been drawn until the bar moved up here.

   It was stacked, icon over label, at the size a 48px strip could carry. In a
   twenty-pixel menu bar it is a row, and it takes the title treatment: flat,
   inverted under the pointer. The frontmost window stays inverted, which is
   how the Application menu says which one you are in and is the same sentence
   the taskbar was making with a filled chip. */
.gs-taskbar_scroll { overflow: visible; padding: 0; }
.gs-taskbar_items { gap: 0; align-items: stretch; }
.gs-taskbar_item {
  flex-direction: row;
  align-items: center;
  gap: calc(var(--window-padding-size) * 0.5);
  height: var(--pl-menubar);
  padding: 0 calc(var(--window-padding-size) * 0.75);
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  color: var(--color-window-title);
  font-family: var(--pl-ui);
  font-size: var(--pl-bar-type);
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
}
.gs-taskbar_item:hover,
.gs-taskbar_item.is-on {
  background-color: var(--color-window-border);
  color: var(--color-window-document);
}
.gs-taskbar_icon svg { width: var(--pl-bar-icon); height: var(--pl-bar-icon); }

/* ==========================================================================
   The phone's bar is a title bar, and it is on the floor
   ==========================================================================
   Everything above this describes a menu bar on a desk. A phone has no desk
   and no pointer, and the bar down there is not chrome -- it is the wordmark,
   the menu, the window switcher and the transport, which is to say it is the
   whole of the navigation. Twenty pixels at the top made the one strip you
   actually press the smallest thing on the screen and put it at the end your
   thumb does not reach. So it goes back to the bottom at its old three cells.

   ---- Why three cells and not "whatever looks right" ----
   48px, exactly, because the background grid is anchored to the viewport
   origin and every card snaps to it. A bar that is not a whole number of cells
   tall puts every card edge half a cell off the lines behind them. That was
   the original reason for 3rem and it has not changed.

   ---- It wears the title bar, because it IS one ----
   The same stripes, the same pair of tokens, the same Chicago. A bar across
   the bottom holding the name of the thing you are in and the windows you have
   open is a title bar for the whole machine, so it is drawn as one rather than
   as a fifth kind of surface. The one difference is which edge carries the
   black rule: a title bar is lit along its top, and a strip on the floor is
   lit along its top too -- so the rule goes on top and the highlight sits just
   under it, which is what makes it read as the floor rather than as a window
   that slid off the bottom of the screen. */
@media (max-width: 1024px) {
  :root {
    --pl-menubar: 3rem;
    --pl-bar-type: 15px;
    --pl-bar-icon: 1.125rem;
    --gs-bar: 3rem;
  }

  .gs-taskbar {
    top: auto;
    bottom: 0;
    border-top: var(--window-border-size) solid var(--color-window-border);
    border-bottom: 0;
    background-color: var(--color-system-03);
    background-image: repeating-linear-gradient(
      to bottom,
      var(--pl-stripe-lit) 0 1px,
      var(--pl-stripe-dim) 1px 2px
    );
    box-shadow: inset 0 var(--window-border-size) var(--color-window-border-outset);
    overflow: hidden;
    animation-name: gs-bar-up;
  }
  /* Slides up off the floor again, the way it always did. */
  @keyframes gs-bar-up { from { transform: translateY(100%); } to { transform: none; } }

  /* The room goes back to the bottom of the desk, and the desk's top edge gets
     its own cell of air back now that nothing is hanging over it. */
  .main-content.is-homepage { padding-top: 1rem; padding-bottom: 4rem; }

  /* The mark is taller than the bar and clipped by it, which is what it was
     before: the face runs to both edges instead of sitting inside them with
     air above and below. The artwork reaches every edge of its own file -- the
     marquee frame is part of the drawing -- so height alone, width follows. */
  .gs-taskbar_brand { padding: 0 calc(var(--window-padding-size) * 1.25) 0 0; }
  .gs-taskbar_mark { height: calc(var(--pl-menubar) + .5rem); }
  /* ---- The wordmark keeps its own face ----
     The base block above sets this in Chicago, because in a MENU bar the thing
     beside the apple is a menu title. Down here it is not a menu title, it is
     the wordmark -- the same lockup the welcome card and the menu card set in
     Instrument Serif -- and this file's own rule for type says the interface's
     voice is title bars, buttons and small labels, not the brand's name.

     It also measures better, which is a consequence and not the reason:
     Chicago is a bitmap face drawn to be read across a room and wants 142px
     for "moveRectangles" where the serif wants 109, against a box that is
     154px at 430 and 84 at 360. Putting it back means nothing else has to give
     up room for it, so the Visualizer button keeps its word at every width.

     The ellipsis stays. The serif fits, but the box it shares with the track
     title is overflow: hidden with no ellipsis of its own, so anything that
     ever does run out stops at a character rather than halfway through one. */
  .gs-taskbar_name {
    font-family: "Instrument Serif", serif;
    font-size: 1.25rem;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  /* ---- What sits ON the stripes ----
     Flat text on a striped ground is the one thing the menu bar above can do
     and this cannot: up there the ground is white. Here every pressable thing
     takes a plate, the same bevel the header's own controls wear, so it reads
     against the rules behind it. Nothing new is invented for the phone -- it
     is the button that is already in this file at the bar's size, reading the
     same --pl-face pair, so the dark theme is handled once for both. */
  .gs-taskbar_item,
  .gs-taskbar_menu,
  .gs-bartrack_viz,
  .gs-bartrack_btn {
    border: var(--window-border-size) solid var(--color-window-border) !important;
    background-color: var(--pl-face) !important;
    color: var(--color-window-title) !important;
    box-shadow:
      inset calc(var(--window-border-size) * -1) calc(var(--window-border-size) * -1) var(--color-system-05),
      inset var(--window-border-size) var(--window-border-size) var(--color-window-border-outset) !important;
  }
  .gs-taskbar_item:hover,
  .gs-taskbar_menu:hover,
  .gs-bartrack_viz:hover,
  .gs-bartrack_btn:hover { background-color: var(--pl-face-hover) !important; }
  /* Pressed, and the one you are in, are the same picture: the roll inverts
     and the plate fills with the accent's loud step. */
  .gs-taskbar_item.is-on,
  .gs-taskbar_item:active,
  .gs-taskbar_menu[aria-expanded="true"],
  .gs-bartrack_viz[aria-pressed="true"],
  .gs-bartrack_btn:active {
    background-color: var(--pl-face-on) !important;
    color: var(--pl-face-on-text) !important;
    box-shadow:
      inset calc(var(--window-border-size) * -1) calc(var(--window-border-size) * -1) var(--color-window-border-outset),
      inset var(--window-border-size) var(--window-border-size) var(--color-system-06) !important;
  }

  /* The run of windows is a row of plates with air between them and a cell of
     air off the top and bottom of the bar, rather than the edge-to-edge run of
     menu titles a menu bar wants. */
  .gs-taskbar_scroll { overflow-x: auto; padding: .375rem 0 .375rem .5rem; }
  .gs-taskbar_items { gap: .375rem; align-items: center; }
  .gs-taskbar_item {
    height: auto;
    align-self: stretch;
    padding: 0 .5rem;
    font-size: calc(var(--pl-bar-type) * 0.8);
  }
  .gs-taskbar_end { padding: .375rem .5rem; gap: .375rem; }
  /* ---- Every plate in the bar is one plate ----
     Play, Visualizer and the menu handle are the same kind of object and are
     drawn the same size. They were not: the two in .gs-taskbar_end take their
     height from that group's .375rem inset and came out 36 tall, while play
     lives in .gs-bartrack, which has no inset, so it stretched the full 48 and
     read as a different control that happened to be next to them.

     So the height is stated once here instead of being inherited from whichever
     group a button happens to sit in -- the bar less the inset the end group
     puts round its own -- and the two icon-only ones take the same .5rem of
     side padding, which lands both on 36 square. The Visualizer keeps its word
     and hugs it. */
  .gs-taskbar_menu,
  .gs-bartrack_viz,
  .gs-bartrack_btn {
    height: calc(var(--pl-menubar) - .75rem) !important;
    min-height: 0 !important;
    align-self: center;
    padding: 0 .5rem !important;
  }

  /* The readout keeps the middle, still with no plate -- it is the one thing
     up there that is telling you something rather than waiting to be pressed,
     and that is exactly the distinction a plate draws. On the stripes it needs
     the contrast the plates get for free, so it takes the title's own colour
     and the weight a name on a title bar has. */
  .gs-bartrack_word,
  .gs-bartrack_np,
  .gs-taskbar_np-text { color: var(--color-window-title); }
}

/* ---- The zoom rectangle ----
   The same dither the drag outline used, for the same reason: XOR against
   whatever is under it, so one rectangle reads over the desk, over a card and
   over a photograph with no colour of its own. Four bars rather than a border,
   because a border cannot be dithered. See js/zoom.js. */
.gs-zoombox {
  position: fixed;
  z-index: 10000;
  pointer-events: none;
  mix-blend-mode: difference;
}
.gs-zoombox > i {
  position: absolute;
  background-color: #fff;
  background-image:
    linear-gradient(45deg, #000 25%, transparent 25%, transparent 75%, #000 75%),
    linear-gradient(45deg, #000 25%, transparent 25%, transparent 75%, #000 75%);
  background-size: 2px 2px;
  background-position: 0 0, 1px 1px;
}
.gs-zoombox > i:nth-child(1) { left: 0; right: 0; top: 0; height: 2px; }
.gs-zoombox > i:nth-child(2) { left: 0; right: 0; bottom: 0; height: 2px; }
.gs-zoombox > i:nth-child(3) { top: 2px; bottom: 2px; left: 0; width: 2px; }
.gs-zoombox > i:nth-child(4) { top: 2px; bottom: 2px; right: 0; width: 2px; }

/* ==========================================================================
   Starting up
   ==========================================================================
   Classicy's startup screen, part for part: the desktop pattern behind, a grey
   panel on it, a white plate inside the panel holding the mark and the
   wordmark, and under the plate -- on the grey, not in the white -- the status
   line and the progress bar. The parade of icons sits at the bottom left of
   the screen.

   Before it, the power key on the same ground, because a browser will not play
   a sound until something is pressed and the chime is the first thing this
   sequence is for. See js/boot.js. */
.gs-boot {
  position: fixed;
  inset: 0;
  z-index: 10500;
  display: flex;
  align-items: center;
  justify-content: center;
  /* The desk's own pattern and colour -- this is the same machine starting up,
     not a screen borrowed from another one. */
  background-color: var(--color-theme-05);
  background-image: url("../img/site/emboss-tile.png");
  background-size: 128px 128px;
  color: var(--color-window-border);
  font-family: var(--pl-ui);
}
.gs-boot.is-going { opacity: 0; transition: opacity .32s linear; }
html.gs-booting, html.gs-booting body { overflow: hidden; }

/* ---- The ground is on screen before the script that draws the boot is ----
   .gs-boot is BUILT by js/boot.js, and a script cannot run until the document
   has parsed -- so for a frame or two the desk paints first and you see the
   desk's own pale ground before the startup screen covers it. Nothing about
   boot.js can fix that: by the time it exists, the wrong thing has been shown.

   So the ground is a rule instead, on a box that is in the document from the
   first frame, keyed off a class the HEAD puts on <html> before anything
   paints -- the same trick the theme resolver two scripts above it uses, and
   for the same reason. Identical colour and tile to .gs-boot, so when the real
   screen lands on top there is nothing to see; and it leaves when the class
   does, one frame before .gs-boot begins its own fade, which is invisible for
   the same reason.

   Under .gs-boot rather than over it: 10500 is the screen, this is 10499. */
html.gs-booting body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 10499;
  pointer-events: none;
  background-color: var(--color-theme-05);
  background-image: url("../img/site/emboss-tile.png");
  background-size: 128px 128px;
}

.gs-boot_power,
.gs-boot_startup { display: flex; flex-direction: column; align-items: center; }

/* ---- The panel ----
   A Platinum plate with no title bar on it. Classicy's has none either: this
   is not a window somebody opened, it is the machine talking. */
.gs-boot_panel {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(var(--window-padding-size) * 1.5);
  padding: calc(var(--window-padding-size) * 3);
  border: var(--window-border-size) solid var(--color-window-border);
  background-color: var(--color-system-03);
  box-shadow:
    inset calc(var(--window-border-size) * -1) calc(var(--window-border-size) * -1) var(--color-system-05),
    inset var(--window-border-size) var(--window-border-size) var(--color-window-border-outset),
    calc(var(--window-border-size) * 2) calc(var(--window-border-size) * 2) 0 0 var(--color-window-border);
}
.gs-boot_startup .gs-boot_panel { opacity: 0; }
.gs-boot.is-welcome .gs-boot_panel { opacity: 1; transition: opacity .25s linear; }

/* The white plate the mark sits on, sunk into the panel. */
.gs-boot_plate {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  min-width: 26rem;
  padding: 2.5rem 3.5rem;
  border: var(--window-border-size) solid var(--color-window-border);
  background-color: var(--color-window-document);
}
.gs-boot_logo { width: 7rem; height: auto; border: 0; }
.gs-boot_wordmark {
  font-family: "Instrument Serif", Georgia, serif;
  font-size: 2.75rem;
  line-height: 1;
  color: var(--color-window-border);
  user-select: none;
}
.gs-boot_progress { font-size: 13px; font-weight: 700; color: var(--color-window-border); }

/* ---- The progress bar ----
   Sunken track, theme fill, one pixel of black round it. Driven from
   js/boot.js so it arrives at the end exactly when the boot does -- a looping
   animation under a thing that stops is not a progress bar, it is a barber's
   pole. */
.gs-boot_track {
  width: 14rem;
  height: 12px;
  border: var(--window-border-size) solid var(--color-window-border);
  background-color: var(--color-window-document);
  box-shadow:
    inset var(--window-border-size) var(--window-border-size) var(--color-system-05),
    inset calc(var(--window-border-size) * -1) calc(var(--window-border-size) * -1) var(--color-window-border-outset);
}
.gs-boot_track > i {
  display: block;
  width: 0;
  height: 100%;
  background-color: var(--color-theme-05);
  box-shadow: inset 0 var(--window-border-size) 0 var(--color-theme-03);
}

/* ---- The power key ---- */
.gs-boot_key {
  display: inline-flex; align-items: center; justify-content: center;
  width: 3.25rem; height: 3.25rem; padding: 0; cursor: pointer;
  margin-top: .5rem;
  border: var(--window-border-size) solid var(--color-window-border);
  border-radius: 50%;
  background-color: var(--color-theme-01);
  color: var(--color-window-border);
  box-shadow:
    inset calc(var(--window-border-size) * -1) calc(var(--window-border-size) * -1) var(--color-system-05),
    inset calc(var(--window-border-size) * -2) calc(var(--window-border-size) * -2) var(--color-theme-04),
    inset var(--window-border-size) var(--window-border-size) var(--color-theme-03),
    inset calc(var(--window-border-size) * 2) calc(var(--window-border-size) * 2) var(--color-window-border-outset);
}
.gs-boot_key svg { width: 1.6rem; height: 1.6rem; display: block; }
.gs-boot_key:hover { background-color: var(--color-theme-02); }
.gs-boot_key:active {
  background-color: var(--color-theme-05);
  color: var(--color-window-document);
}

/* ---- The parade ----
   Bottom left, wrap-reverse so a full row pushes the next one UPWARD, which is
   the direction the real one grew. One icon per piece on the desk, each
   carrying that piece's own picture. */
.gs-boot_exts {
  position: absolute;
  inset: auto auto calc(var(--window-padding-size) * 2) calc(var(--window-padding-size) * 2);
  display: flex;
  flex-wrap: wrap-reverse;
  gap: calc(var(--window-padding-size) * 1.2);
  max-width: min(72rem, calc(100vw - 4rem));
}
.gs-boot_ext {
  opacity: 0;
  overflow: hidden;
  width: 32px;
  height: 32px;
  border: var(--window-border-size) solid var(--color-window-border);
  background-color: var(--color-window-document);
  box-shadow: var(--window-border-size) var(--window-border-size) 0 0 var(--color-window-border);
}
.gs-boot_ext.is-in { opacity: 1; }
.gs-boot_ext img { display: block; width: 100%; height: 100%; object-fit: cover; border: 0; }
