  :root{
    --silver:#c0c0c0; --hi:#ffffff; --lo:#808080; --dark:#404040;
    --navy:#000080; --navy2:#1084d0;
    /* the ground the game is printed on, and the ink upon it. The Win9x
       chrome greys above are the frame; these are the page. Both themes are
       written in these terms, so a rule states what a colour is for and the
       theme says what colour that is (html.dark, at the foot of the sheet). */
    --paper:#fff; --ink:#000;             /* sunken fields, and their text */
    --plate:#fff;                          /* the ground a beast's plate is inked on */
    --desk:#3a6ea5;                        /* the desktop behind the window */
    --navyink:#000080;                     /* the navy where it is ink, not ground */
    --mute:#808080;                        /* disabled and locked text */
    --faint:#404040;                       /* the quieter ledger hands */
    --dim:#555; --dim2:#333; --dim3:#444; --dim4:#999;
    --rule:#eee; --rule2:#ddd; --rule3:#ccc;   /* hairlines within a list */
    --headrow:#e8e8e8;                     /* a ruled head inside a list */
    --tip:#ffffe1; --tipedge:#000;         /* the Win98 tooltip */
    --halo:#fff;                           /* the backing of figures over art */
    --scrim:rgba(0,0,0,.25);               /* a dialog's shade over the sheet */
    --chip:#e6f0ff; --chipill:#ffe6e6; --illink:#a00000;   /* the boon chips */
    --okink:#055405;                       /* a pass, read upon the grey of the chrome */
    --paleground:#e9e6f2; --paleink:#5a4a7a;               /* a pale beast's plate */
    --pressed:#b0b0b0;                     /* a titlebar button held down */
    --c-common:#333; --c-fine:#0a7d0a; --c-scarce:#0040c0;
    --c-prized:#8a00b0; --c-storied:#c06000; --c-fabled:#b00000;
    /* the three marks above the red one, kept off every rarity hue already
       spent: a deep teal, a slate, and the ink of the crown */
    --c-iron:#00606a; --c-silver:#465a72; --c-crowned:#6a5000;
    --forgegold:#c08000;                   /* the golden hammer in the forge's case */
    /* THE LOG'S OWN GOLD, AS A VARIABLE (v2.6.1). This is what the file marks a
       thing bought and kept with, and .lg-gold has carried a dark and a
       high-contrast reading of it for as long as the lamps have existed. The
       yard's stands copied the paper FIGURE instead of the class, so a star
       that says the same thing as a gold log line went unturned by both: on the
       dark ground #9a6a00 is a smudge. One name, four scopes, three readers. */
    --goldink:#9a6a00;
    /* THE THREE COLUMNS OF THE UPGRADE TREE. A talent stands in the ink until a
       point is spent in it, and takes its column's colour the moment one is:
       the grid is then read at a glance as three ladders of colour rather than
       as fifteen grey boxes. The -lit pair is the same hue carried one step
       brighter for a talent taken to its last rank. The first navy tried here
       was --c-scarce's own, and at 26px it could not be told from black. */
    --tree-weight:#0022b8; --tree-weight-lit:#0033dd;
    --tree-reach:#008a00;  --tree-reach-lit:#00a800;
    --tree-thrift:#b07c00; --tree-thrift-lit:#d09400;
    /* THE TWELVE TRADE INKS (v2.0.4). A calling had no colour of its own until
       now: the sheet knew rarity, the wall knew what a clause does, and the one
       thing a player picks at enrolment and carries for the whole chronicle was
       eleven pixels of plain text. One ink to a trade, and the mark beside it
       is drawn in currentColor, so the row hands the figure its colour exactly
       as the tree's columns hand theirs down.

       THE COLOUR NEVER CARRIES A MEANING ALONE. The mark and the name stand
       beside it everywhere it appears, which is what makes twelve hues safe in
       a sheet that has always spent colour on one thing at a time; under the
       high-contrast option they all drop to the ink and nothing is lost.

       Two of them are set off the Charter's own eight on purpose. The
       Barbarian's red was the family ink of the strike to the digit and the
       Cleric's gold was the crit's, and the adventurer's own seat is drawn in
       the trade ink upon that wall (chartDraw), so two trades would have signed
       in a colour that already means something else there. Both are carried a
       step deeper, which also reads as the heavier mark a seat wants.

       THE -lit PAIR IS THE SAME TRADE UPON A DARK GROUND, and it is needed in
       both themes rather than in the dark one alone: the title bar and the
       chosen row of the enrolment list are navy whichever theme is set, and
       measured on the light theme six of the twelve paper inks were all but
       gone the moment they stood on it -- the Rogue's charcoal on navy worst.
       So the dark theme does not restate twelve hexes, it points --t-* at the
       raised pair below, and anything drawn on navy asks for the raised pair
       by name. Twelve colours, twenty-four values, one place. */
    --t-fighter:#3f6080; --t-wizard:#3a2f9c;  --t-cleric:#856000;
    --t-rogue:#33373b;   --t-ranger:#157a45;  --t-barbarian:#8c1414;
    --t-paladin:#14499a; --t-bard:#96235c;    --t-druid:#6b7010;
    --t-sorcerer:#b34a00;--t-warlock:#6b2c8a; --t-monk:#0a6b6b;
    --t-fighter-lit:#8ab4d8; --t-wizard-lit:#9b93ee;  --t-cleric-lit:#f0c84a;
    --t-rogue-lit:#b4b8bc;   --t-ranger-lit:#58c689;  --t-barbarian-lit:#f07878;
    --t-paladin-lit:#7aa8f0; --t-bard-lit:#ee84b0;    --t-druid-lit:#ccd254;
    --t-sorcerer-lit:#ff9440;--t-warlock-lit:#c48ce4; --t-monk-lit:#3fbcbc;
    /* The measure: the figure the whole document is zoomed to (Options, the
       Legibility group). A length in this sheet is a local one and scales with
       it by itself; the viewport units below do not, for 100vw is the screen
       and the screen does not grow, so every one of them is read through this
       and lands where it did at 100%. */
    --ui-zoom:1;
  }
  /* Nothing in this game is wider than the sheet, so the page has no business
     scrolling sideways. A phone set to request the desktop site lays the page
     out at about 980px whatever the viewport meta asks for, and the whole
     sheet then drifts off the side of the screen under a thumb meant for the
     log. It is clipped rather than scrolled. */
  html, body{overflow-x:hidden;}
  *{box-sizing:border-box; margin:0; padding:0;}
  /* The document is pinned to the frame and the body does the scrolling.
     iOS Safari sizes an iframe to its content, and itch's page clips the
     rest, which left the bottom of the enrolment screen beyond reach on a
     phone; a scrolling body keeps every button reachable inside any frame. */
  html{height:100%; overflow:hidden;}
  body{
    background:var(--desk);
    font-family:Tahoma,"MS Sans Serif",Geneva,sans-serif;
    font-size:11px; color:var(--ink);
    display:flex; align-items:flex-start; justify-content:center;
    padding:16px; height:100%; overflow-y:auto;
    -webkit-overflow-scrolling:touch;
    overscroll-behavior-y:contain; /* the itch page holds still while the game scrolls */
    /* THE GUTTER IS ALWAYS THERE, WHETHER OR NOT THE BAR IS (v2.1.0).
       This is the page's scroller (html is clipped, the body scrolls), and the
       sheet is tuned to the pixel against the window's height: a boon coming
       into force, the log's room being opened, a window dragged one notch
       shorter -- any of them can put the page a hair over and bring the
       scrollbar out. Coming out, it used to take fifteen pixels of WIDTH with
       it, and the whole sheet re-laid itself sideways to suit: tables re-
       measured, prose re-wrapped, every list re-ruled. Going away again, it
       did it back. That is the flicker a player sees as the window breaking,
       and it is worst under the shake, which brings the bar out for a third of
       a second and puts it away again. The gutter is reserved once and for
       all, so the bar arrives into room already kept for it and nothing
       beside it moves at all. */
    scrollbar-gutter:stable;
  }
  .win{
    background:var(--silver);
    border:1px solid var(--dark);
    box-shadow:inset 1px 1px 0 var(--hi), inset -1px -1px 0 var(--lo), 2px 2px 6px rgba(0,0,0,.4);
    padding:2px; width:100%; max-width:960px;
  }
  .titlebar{
    background:linear-gradient(90deg,var(--navy),var(--navy2));
    color:#fff; font-weight:bold; padding:3px 4px 3px 6px;
    display:flex; align-items:center; gap:6px; user-select:none;
  }
  .titlebar .tglyph{width:14px;height:14px;flex:0 0 auto;}
  /* the game's own glyph is a span, so what stands in it may be swapped for
     the adventurer's trade once a chronicle is signed */
  .titlebar span.tglyph{display:block; line-height:0;}
  .titlebar span.tglyph svg{width:14px;height:14px;display:block;}
  .titlebar .tname{flex:1; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;}
  .tbtn{
    width:16px;height:14px; background:var(--silver); color:var(--ink);
    border:1px solid var(--dark);
    box-shadow:inset 1px 1px 0 var(--hi), inset -1px -1px 0 var(--lo);
    font-size:9px; line-height:12px; text-align:center; font-weight:bold; cursor:default;
  }
  /* The menu bar. Sixteen buttons stood in one row and the bar was the busiest
     thing on the window; a Win9x menu with four drops is both the tidier UI and
     the period-correct one. A menu whose every item is still gated hides
     itself, so a new adventurer meets Chronicle, Options and Help and nothing
     else, and the bar fills out as the Guild opens its books. */
  .menubar{padding:2px 4px; display:flex; gap:2px; user-select:none; align-items:stretch;}
  .menubar button{
    background:none; border:none; box-shadow:none; padding:2px 6px; font-size:11px; cursor:pointer;
    text-align:left; white-space:nowrap;
  }
  .menubar button:hover{background:var(--navy); color:#fff;}
  .menubar button:disabled{color:var(--mute); background:none;}
  .menubar button:disabled:hover{background:none; color:var(--mute);}
  .menu{position:relative;}
  .menu.open > .menutop{background:var(--navy); color:#fff;}
  .menudrop{
    display:none; position:absolute; top:100%; left:0; z-index:80; min-width:132px;
    background:var(--silver); padding:2px;
    border:1px solid var(--dark);
    box-shadow:inset 1px 1px 0 var(--hi), inset -1px -1px 0 var(--lo), 2px 2px 0 rgba(0,0,0,.35);
  }
  .menu.open > .menudrop{display:block;}
  .menudrop button{display:block; width:100%; padding:3px 14px 3px 8px;}
  .menusep{height:0; margin:3px 2px; border-top:1px solid var(--lo); border-bottom:1px solid var(--hi);}
  /* the fold, the version and the calendar are pushed to the far end where a
     status field belongs; the fold heads that group, being the one of the
     three that is a control */
  #m-fold{margin-left:auto;}
  /* the notices tray: a bell at the far end of the bar, with the count of the
     unread standing upon it, and the book itself a small window hung beneath */
  #noticetray{position:relative; display:flex;}
  #noticebtn{position:relative;}
  #noticebadge{
    position:absolute; top:-4px; right:-4px; min-width:12px; padding:0 2px;
    background:#a00000; color:#fff; border:1px solid var(--dark);
    font-size:9px; line-height:11px; text-align:center; font-weight:bold;
    pointer-events:none;
  }
  #noticepanel{
    position:absolute; top:100%; right:0; z-index:80; width:320px;
    background:var(--silver); padding:2px;
    border:1px solid var(--dark);
    box-shadow:inset 1px 1px 0 var(--hi), inset -1px -1px 0 var(--lo), 2px 2px 0 rgba(0,0,0,.35);
  }
  #noticeclear{
    background:var(--silver); color:var(--ink); border:1px solid var(--dark);
    box-shadow:inset 1px 1px 0 var(--hi), inset -1px -1px 0 var(--lo);
    font-size:10px; padding:0 6px; cursor:pointer;
  }
  #noticelist{max-height:264px; overflow-y:auto;}
  .noticerow{display:flex; align-items:flex-start; gap:6px; padding:3px 4px;}
  .noticerow + .noticerow{border-top:1px solid var(--lo);}
  .noticetext{flex:1;}
  .noticewhen{color:var(--dim3); white-space:nowrap; padding-top:1px;}
  .noticex{
    flex:0 0 auto; width:14px; padding:0; background:var(--silver); color:var(--ink);
    border:1px solid var(--dark);
    box-shadow:inset 1px 1px 0 var(--hi), inset -1px -1px 0 var(--lo);
    font-size:9px; line-height:11px; text-align:center; cursor:pointer;
  }
  .client{padding:6px;}

  /* A PANEL KEEPS TO ITS COLUMN (v1.6.5). The browser gives every fieldset a
     floor of min-content and nothing else on the sheet carries one, so a panel
     could not be squeezed below the width of the longest unbreakable line
     inside it: it grew instead, out of its own column and over the one beside
     it. The columns were guarded against exactly this and the guard held --
     .cols is minmax(0,1fr), a third is a third -- but the guard stops at the
     track, and the fieldset standing in that track walked straight out of it.

     The pet's card is where it showed. Its second line is a hireling's row
     (.hirerole), which is nowrap with an ellipsis, and that pair only works
     where something narrower is doing the squeezing; with the floor in place
     nothing ever was, so the ellipsis never fired and the line ran on. A
     hireling's trade is two words and stayed inside the column by luck; the
     pet's line is a whole sentence -- the count eaten, the growth, and what
     the growth pays -- and at 1280 it took the card 105 pixels past the
     column's edge and laid it over the plot. The floor comes off and the two
     rules the card already carried do the work they were written for. */
  fieldset{
    position:relative; padding:14px 6px 6px; margin-bottom:8px; min-inline-size:0;
    border-top:1px solid var(--lo); border-left:1px solid var(--lo);
    border-bottom:1px solid var(--hi); border-right:1px solid var(--hi);
  }
  .grouplabel{
    position:absolute; top:-7px; left:6px; background:var(--silver);
    padding:0 4px; font-weight:bold;
  }
  .sunken{
    background:var(--paper);
    border-top:1px solid var(--lo); border-left:1px solid var(--lo);
    border-bottom:1px solid var(--hi); border-right:1px solid var(--hi);
    box-shadow:inset 1px 1px 0 var(--dark);
  }
  .listview{overflow-y:auto;}
  /* The desktop lives inside itch's embed: content column 960px wide, the
     iframe 600-700 tall. Panel heights step down with the viewport instead
     of holding fixed pixels, so no size in that range grows a scrollbar.
     The ladder is written into variables upon the window rather than straight
     onto the lists, so a height the player sets by hand (--u-*, put on #game
     by the grip under the list) stands above every rung of it and no rung
     need know anything about it. Clear that figure and the ladder answers
     again, at whatever rung the window stands upon.
     All seven take one, the three slack-takers of the columns among them (the
     .grow rule below). A slack-taker holds whatever room its column has spare,
     so a height of its own would be a figure it ignored: given one, it stands
     its flex down and hands the office to the panel above it, which then holds
     the room instead. markSlack() does the handing over. */
  #game{
    /* THE TWO LISTS ON THE PAPERS EACH GAINED A ROW with the road pillar, and
       both boxes were cut to the row they held: the papers took the Dream the
       floor shows you, and the abilities took Spot and Footing, so each stood
       one line taller than its own box and clipped it. A row is eight pixels
       here, and only the BASE breakpoint moves -- the narrow sheets below scroll
       by design and were already scrolling at the old count. */
    --h-traits:126px; --h-stats:140px; --h-spells:122px;
    /* THE KIT FITS EXACTLY FOUR ROWS. It stood at 160px, which was nine slots'
       worth, and the four-slot table measures 76: eighty-four pixels of the
       column stood empty above an Inventory that scrolled. Every breakpoint that
       stood above the four rows comes down to 84 and gives the difference to the
       pack, which is the panel beneath it and the one a player reads most. */
    --h-kit:84px; --h-pack:222px; --h-chron:120px; --h-notice:120px;
  }
  .lv-traits{height:var(--u-traits, var(--h-traits));}
  .lv-stats{height:var(--u-stats, var(--h-stats));}
  .lv-spells{height:var(--u-spells, var(--h-spells));}
  .lv-kit{height:var(--u-kit, var(--h-kit));}
  .lv-pack{height:var(--u-pack, var(--h-pack));}
  .lv-chron{height:var(--u-chron, var(--h-chron));}
  .lv-notice{height:var(--u-notice, var(--h-notice));}
  /* The borders are separate because the headers float. Under border-collapse
     a border belongs to the table rather than to the cell, so a header that
     sticks leaves its bottom edge behind and the rows passing under it show
     through the header face. A separate border is the cell's own and travels
     with it. The padding gives back the pixel the collapsed model shared with
     the row below, which holds the header at 16px; grow it and the Equipment
     roster stops fitting its column. */
  table.lv{width:100%; border-collapse:separate; border-spacing:0;}
  table.lv th{
    background:var(--silver); text-align:left; font-weight:normal;
    border:1px solid; border-color:var(--hi) var(--lo) var(--lo) var(--hi);
    padding:1px 4px 0; position:sticky; top:0; z-index:2;
  }
  table.lv td{padding:1px 4px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:170px;}
  /* The kit's third column is the item's level, and it is paid for out of the
     Slot column, not the Item column: Slot ran to 123px for words like
     Breastplate that measure about 60, and the Item cell has clipped with an
     ellipsis since v1.0 and must not be made to clip sooner. A number is the
     one thing in the row that must never be cut, so it sits at the end and
     takes a fixed width. */
  /* the school's own hour, in the dim of a thing that is a condition rather
     than a figure: the eye goes to the school and to the odds, and the event
     between them is read when the eye asks what the odds are odds of */
  table.lv td.swhen{color:var(--dim);}
  table.lv th.kitslot, table.lv td.kitslot{width:78px;}
  table.lv th.kitlvl, table.lv td.kitlvl{width:34px; text-align:right; padding-right:6px;}
  /* the kit's own item level, beside the panel's name, which is the figure a
     player watches climb */
  /* The kit's item level climbs through five marks, and wears the deep's own
     colours for them. Its own classes rather than the r- ones: those mean the
     band a piece was assayed at, and the same colour must not mean two things
     in one panel. Two classes beat the one below, so the mark always wins. */
  .kitlevel{font-weight:normal; color:var(--dim);}
  .kitlevel.km1{color:var(--c-fine);    font-weight:bold;}
  .kitlevel.km2{color:var(--c-scarce);  font-weight:bold;}
  .kitlevel.km3{color:var(--c-prized);  font-weight:bold;}
  .kitlevel.km4{color:var(--c-storied); font-weight:bold;}
  .kitlevel.km5{color:var(--c-fabled);  font-weight:bold;}
  .kitlevel.km6{color:var(--c-iron);    font-weight:bold;}
  .kitlevel.km7{color:var(--c-silver);  font-weight:bold;}
  .kitlevel.km8{color:var(--c-crowned); font-weight:bold;}
  /* the same footnote marks the rarities climb, for eyes that keep no colour */
  body.rmarks .kitlevel.km1::after{content:" †"; font-weight:normal;}
  body.rmarks .kitlevel.km2::after{content:" ‡"; font-weight:normal;}
  body.rmarks .kitlevel.km3::after{content:" §"; font-weight:normal;}
  body.rmarks .kitlevel.km4::after{content:" ‖"; font-weight:normal;}
  body.rmarks .kitlevel.km5::after{content:" ¶"; font-weight:normal;}
  body.rmarks .kitlevel.km6::after{content:" ††"; font-weight:normal;}
  body.rmarks .kitlevel.km7::after{content:" ‡‡"; font-weight:normal;}
  body.rmarks .kitlevel.km8::after{content:" §§"; font-weight:normal;}
  table.lv tr.cur td{background:var(--navy); color:#fff;}
  table.lv tr.locked td{color:var(--mute);}

  button{
    font-family:inherit; font-size:11px;
    background:var(--silver); padding:4px 14px;
    border:1px solid var(--dark);
    box-shadow:inset 1px 1px 0 var(--hi), inset -1px -1px 0 var(--lo);
    cursor:pointer;
    touch-action:manipulation; /* a double tap on Roll must not zoom the page */
  }
  button:active{box-shadow:inset 1px 1px 0 var(--lo), inset -1px -1px 0 var(--hi);}
  button:focus-visible{outline:1px dotted var(--ink); outline-offset:-4px;}
  button:disabled{color:var(--mute); text-shadow:1px 1px 0 var(--hi); cursor:default;}
  input[type=text], textarea{
    font-family:inherit; font-size:11px; padding:2px 4px; width:100%;
    background:var(--paper); color:var(--ink); border:none;
    border-top:1px solid var(--lo); border-left:1px solid var(--lo);
    border-bottom:1px solid var(--hi); border-right:1px solid var(--hi);
    box-shadow:inset 1px 1px 0 var(--dark);
  }

  .pbar{
    height:16px; position:relative; background:var(--paper);
    border-top:1px solid var(--lo); border-left:1px solid var(--lo);
    border-bottom:1px solid var(--hi); border-right:1px solid var(--hi);
    box-shadow:inset 1px 1px 0 var(--dark);
    overflow:hidden;
    /* Two colours make a bar: the block, and the ink a figure takes where it
       crosses one. The groove between blocks stays a hole through to the
       paper: that gap is the whole of why the bar reads as a row of blocks
       rather than a band, and it is the oldest thing on the sheet. */
    --fillcol:var(--navy); --fillink:var(--paper);
  }
  .pbar .fill{
    position:absolute; left:1px; right:0; top:1px; bottom:1px;
    background:repeating-linear-gradient(90deg, var(--fillcol) 0 8px, transparent 8px 10px);
    /* The fill stands at its full span and is cut back to the figure. A clip
       is paint where a width is layout, and the work bar is redrawn on every
       frame: sizing it asked the whole column to be measured sixty times a
       second for a bar that is 200 pixels wide. */
    clip-path:inset(0 100% 0 0);
    transition:clip-path .12s linear;
  }
  /* And the work bar takes no ease whatever. The clock writes it on every
     frame, and a value rewritten mid-slide restarts the slide: the fill never
     arrived, ran a frame behind the truth all the way, and read as stutter.
     The frame is the animation here. The ease is kept for the bars that jump:
     a wound taken, a rank gained, a floor closed. */
  #bar-task .fill{transition:none;}
  /* And the beast's plate with it, for the same reason: renderFoe writes it
     off the same clock, every frame. Eased, it chased a figure it never
     caught, around a tenth of a second behind all the way down, and a fight
     shorter than that ran out before the fill did. At speed the beast died
     with its bar still standing near half, and the next beast's full bar took
     its place. The figure was right the whole time; only the blocks lied. */
  #foehp .fill{transition:none;}
  /* ---------- THE WORK BAR WEARS ITS KIND ----------
     Each errand tinted this bar from early on, but the tints were picked one at
     a time and answered to nothing: selling was gold, shopping was GREEN, and
     binding a wound was a surgeon's MAROON, so the two most opposite things in
     the loop wore each other's colour and the road, when it came, wore nothing
     at all and could not be told from a fight.

     They are the log's own seven kinds now, the same inks the latch filters on
     (LOG_CAT_INK). One colour means one thing across the whole sheet: what the
     bar is filling with is what the log will write in, and a reader who has
     learned that brown is the road has learned it everywhere. */
  .pbar.kill{--fillcol:#a00000;}                 /* combat */
  .pbar.boss{--fillcol:#7a0000;}                 /* combat, and the deepest of it */
  .pbar.sell{--fillcol:#9a6a00;}                 /* the counter */
  .pbar.buy{--fillcol:#9a6a00;}                  /* the counter, both ways across it */
  .pbar.road{--fillcol:#7a5230;}                 /* the road */
  .pbar.rest{--fillcol:#0a7d0a;}                 /* rest */
  .pbar.walk{--fillcol:#6a2d8a;}                 /* the descent */
  .pbar.plotcue{--fillcol:#6a2d8a;}              /* the descent */
  /* THE FIGURE ON THE BAR IS READ ACROSS A ROOM (v2.1.0). It was set at ten
     pixels of plain weight, laid over a groove pattern that breaks every glyph
     it crosses, and the bars that matter -- the descent, the quest, the work in
     hand -- are the ones a player checks with half an eye while reading the
     log. Bold and a pixel larger. The two pools and the beast's plate keep
     their own smaller settings below; those are read at a glance, not across a
     room, and they have no room to spare. */
  .pbar .ptext{
    position:absolute; inset:0; text-align:center; line-height:16px;
    font-size:11px; font-weight:bold; color:var(--ink); pointer-events:none;
  }
  /* The figure is written twice and read once. The plain copy lies on the
     trough in the trough's own ink and needs nothing behind it, the trough
     being one flat colour. The second copy sits inside the fill, cut off by
     the same clip, in the ink that carries on a block, and it is that copy,
     and only that copy, that wears an outline.

     The outline is the block's own colour, which is the whole of the fix. It
     used to be the paper's, so where a groove passed behind a glyph the
     outline was white upon white and the digits came apart; drawn in the
     block, it plugs the groove behind the glyph and leaves the groove itself
     showing everywhere else. The bar is the bar it always was. */
  .pbar .fill .ptext{
    inset:-1px 0 -1px -1px; color:var(--fillink);
    text-shadow:-1px 0 0 var(--fillcol), 1px 0 0 var(--fillcol), 0 -1px 0 var(--fillcol),
      0 1px 0 var(--fillcol), -1px -1px 0 var(--fillcol), 1px -1px 0 var(--fillcol),
      -1px 1px 0 var(--fillcol), 1px 1px 0 var(--fillcol);
  }
  .barlabel{font-weight:bold; margin:6px 0 2px;}

  /* THE FIGURE COMES OFF THE BLOCKS. A bar's figure was printed twice upon the
     trough itself -- once on the paper, once inside the fill -- and both copies
     were read across the grooves that make a bar a row of blocks: the digits of
     a wound were broken by white every eight pixels, and the longer the words
     the worse it read. So the sheet's own bars hand the figure to a cell of its
     own, set to the right of the trough on the panel's own ground where nothing
     crosses it, and the trough carries the blocks alone.

     The two copies inside stay in the markup and are only hidden. The folded
     strip stands these same bars in a row that has no room for a cell beside
     them, and there the inside figure is shown again (the mini block below):
     the bars are carried into the strip rather than copied, so what the strip
     borrows must still be able to speak for itself. */
  .barline{display:flex; align-items:center; gap:6px;}
  .barline .pbar{flex:1 1 auto; min-width:0;}
  .pbar.figout .ptext{display:none;}
  /* AND THE CELL IS A COLUMN, NOT A LABEL. Sized to what it holds, it would be
     a different width on every bar and a different width every time a figure
     shortened -- the descent counts itself down from "2h 5m of descent ahead"
     to "58m", and a trough that grew a dozen pixels each time it did would be
     the only thing on the sheet moving under a reader's eye. So the cell is
     held at the widest figure any of these bars prints, the figures hang right
     within it, and every trough on the sheet is the same length as every
     other. What that costs is the room between a short figure and its bar,
     which is what a column of figures has always cost. */
  .pfig{flex:0 0 auto; min-width:140px; white-space:nowrap; text-align:right;
    font-size:11px; font-weight:bold; color:var(--ink);}
  /* Encumbrance and Quest print compact figures with no changing sentence.
     Let their troughs run to the figure instead of reserving the Descent
     sentence's full column beside them. The barline gap keeps the two apart. */
  #fig-enc, #fig-quest{min-width:0;}

  /* HP and MP sit with the papers, just under the stat table that keeps
     their exact figures (Q6): a column-width pair standing one above the
     other, so a wound shows in the corner of the eye without a full-width
     band across the sheet. HP wears the wound-maroon and reddens to the
     danger tint (#a00000, the log's own bad-news red) at or below the
     bind-wounds quarter; MP keeps the navy of the default fill. */
  .poolrow{display:flex; flex-direction:column; gap:2px; margin:4px 0 0;}
  .poolrow .pbar{flex:1;}
  .poolrow .ptext{font-size:9px;}
  /* The pools keep the smaller ink they have always been read at, and their own
     narrower cell: the two of them are a pair, and a pair reads as one only
     while both troughs end level. */
  .poolrow .pfig{font-size:9px; min-width:94px;}
  /* AND THE SECOND ROW IS PAID FOR AT THE FLOOR. Standing the pools one above
     the other costs the papers eighteen pixels, and above 748 they are free:
     the trade's mark stands 30 in that row and the pair now stands 34, so the
     column grows by four and the grower in it has that and more. Below 748 the
     mark is hidden and the whole eighteen falls on a ladder that has been
     trading single pixels since the beginning; measured at 920x600 it put the
     sheet seven past the glass, which is a scrollbar in the embed.
     A trough that carries no words needs no height for words. The figures moved
     out to the cell beside them, so from 748 down the two troughs come to twelve
     pixels of plain blocks and hand eight of the eighteen back -- measured, that
     is the whole of what the sheet was over by at 748, at 678 and at the 600
     floor alike. It is the same step the mark stands down at, and for the same
     reason. Above 748 the pools are the sixteen they have always been. */
  @media (max-height:748px){
    .poolrow .pbar{height:12px;}
    .poolrow .ptext{line-height:12px;}
  }
  /* the adventurer's own plate, set beside the two pools in the line the
     hireling's portrait already keeps (.hirerow below): a 30px field, the
     ink at its own weight, and the pools take the rest of the row. */
  .heropool{display:flex; align-items:center; gap:6px; margin:4px 0 0;}
  .heropool .poolrow{flex:1 1 auto; min-width:0; margin:0;}
  .heroart{width:30px; height:30px; flex:0 0 30px;}
  .heroart svg{width:30px; height:30px; display:block;}
  /* The plate stands on the papers only where the column has room for it. From
     748px down the list heights are budgeted to the pixel (the embed steps
     below), and a 30px plate in the pools row spends 16 of them: the window
     then runs 5 to 12 pixels past three of itch's sizes, which is a scrollbar
     in the embed. The folded strip carries the plate at every size, and the
     strip is where it was drawn to be read. The selector reaches it only while
     it stands in the pools row, so the plate the strip has borrowed is not
     touched here (stripGather). */
  @media (max-height:748px){ .heropool .heroart{display:none;} }
  /* ---- THE TRADE'S MARK (v2.0.4) ----
     One figure to a calling, drawn in currentColor and carrying no fill of its
     own, so whatever box it stands in hands it the colour: the twelve inks
     above by default, the row's own ink where it sits on navy, and the plain
     ink under high contrast. It stands in five places -- the enrolment list,
     the Trade row of the papers, the title bar, the adventurer's plate and the
     Roll of Retired Names -- and the size is set by whichever of them it is in,
     never here.

     The trade names its own two inks and nothing else picks a colour: the
     element carrying data-trade sets --tmink and --tmink-lit, and the two
     rules below choose which of them the figure takes. Twelve declarations and
     two rules, rather than twelve rules twice over, and a thirteenth trade
     would be one line. */
  .tm{display:block; color:var(--tmink, var(--ink));}
  [data-trade="Fighter"]  {--tmink:var(--t-fighter);  --tmink-lit:var(--t-fighter-lit);}
  [data-trade="Wizard"]   {--tmink:var(--t-wizard);   --tmink-lit:var(--t-wizard-lit);}
  [data-trade="Cleric"]   {--tmink:var(--t-cleric);   --tmink-lit:var(--t-cleric-lit);}
  [data-trade="Rogue"]    {--tmink:var(--t-rogue);    --tmink-lit:var(--t-rogue-lit);}
  [data-trade="Ranger"]   {--tmink:var(--t-ranger);   --tmink-lit:var(--t-ranger-lit);}
  [data-trade="Barbarian"]{--tmink:var(--t-barbarian);--tmink-lit:var(--t-barbarian-lit);}
  [data-trade="Paladin"]  {--tmink:var(--t-paladin);  --tmink-lit:var(--t-paladin-lit);}
  [data-trade="Bard"]     {--tmink:var(--t-bard);     --tmink-lit:var(--t-bard-lit);}
  [data-trade="Druid"]    {--tmink:var(--t-druid);    --tmink-lit:var(--t-druid-lit);}
  [data-trade="Sorcerer"] {--tmink:var(--t-sorcerer); --tmink-lit:var(--t-sorcerer-lit);}
  [data-trade="Warlock"]  {--tmink:var(--t-warlock);  --tmink-lit:var(--t-warlock-lit);}
  [data-trade="Monk"]     {--tmink:var(--t-monk);     --tmink-lit:var(--t-monk-lit);}
  /* a figure standing on navy takes the raised ink of its trade, in either
     theme, since the navy is dark in both */
  .tm-navy .tm, .radio-list label:has(input:checked) .tm{color:var(--tmink-lit, #fff);}
  /* the mark is set into a line of text wherever it stands beside one, so it
     sits on the baseline rather than pushing the row taller */
  .tmin{display:inline-block; vertical-align:-3px; margin-right:3px; flex:0 0 auto;}
  .tmin .tm{width:100%; height:100%;}
  #bar-hp{--fillcol:#800000;}
  /* at the bind-wounds quarter the blocks close up into one solid band, which
     is the one place on the sheet where they do, and is the whole alarm */
  #bar-hp.alarm{--fillcol:#a00000;}
  #bar-hp.alarm .fill{background:#a00000;}
  /* and the figure beside it reddens with the blocks, now that it stands off
     the bar and would otherwise be the one part of the alarm that stayed calm */
  #bar-hp.alarm + .pfig{color:#a00000;}

  /* the hireling panel (F4): the hand at your side, a small framed card under
     the papers. Hidden until one is assigned, and foldable to the label so a
     player who wants the room can put it away. Its XP bar wears the green of a
     good deed, apart from the navy of your own rank. */
  #hirelingbox, #petbox{margin:0 0 8px; padding-top:11px;}
  /* THE CHEST'S SLOT, STANDING OPEN. The frame, the plate and the bar are the
     hireling's own, so the pet's card costs the stylesheet two rules and no
     new idiom. A slot nobody has filled yet draws its plate at a quarter
     weight: the frame then reads as a place kept rather than a picture shown,
     which is the whole of what an empty slot is for. */
  .hireart.vacant, .bestart.vacant{opacity:.28;}
  /* AND AN UNCLAIMED COMPANION COSTS THE SHEET ONE LINE, not a whole plate.
     The frame must stand open from the first hour, which is the whole of why
     the slot is drawn at all, but the empty state was taking a hireling's full
     66px out of the second column at every window: at 1100x760 there is no
     slack left to give and the log lost the room. So the plate and the bar are
     folded away until the chest is won, and the invitation is the two lines of
     words, which are the part that does the inviting. Winning it opens the
     frame to its full weight, and that is the moment worth the pixels. */
  #petbox.petvacant .hireart, #petbox.petvacant .hirebar{display:none;}
  #petbox.petvacant .hirerow{padding:2px 4px;}
  /* and the hand's own frame, standing open on the same terms and folded the
     same way: the plate and the bar are put away and the two lines of words do
     the inviting, which is the part that does it */
  #hirelingbox.hirevacant .hireart, #hirelingbox.hirevacant .hirebar{display:none;}
  #hirelingbox.hirevacant .hirerow{padding:2px 4px;}
  .hirerow{display:flex; align-items:center; gap:6px; padding:3px 4px;}
  /* THE HAND'S PLATE IS PAPER, like every other plate in the game. It was
     line-work standing directly on the panel's silver, and got a ground only
     at night so the ink would not be drawn in the dark upon the dark. That
     made it the one picture in the sheet without paper under it: the beasts,
     the pets and the foe are all inked on --plate, and the scanned plates
     carry their own white besides, so the hand alone read as a different kind
     of thing. Worse, --plate is AGED PAPER at night while every plate beside
     it is a scan, and a scan is an opaque png with its white baked in: the
     beasts stayed white in the dark and the hand alone came out brown.

     The drawing carries its own white now (hirelingGround), which is what
     fixes it in all three places the hand is drawn. This is the seam behind
     it, so a hair of ground at the edge of the box is white too and never the
     night's brown. The background is all it takes: a padding here would
     shrink the art inside a 30px box that column two's height is measured
     against. */
  .hireart{width:30px; height:30px; flex:0 0 30px; align-self:flex-start; margin-top:1px;
    background:#fff;}
  .hireart svg{width:30px; height:30px; display:block;}
  /* The basis is zero rather than the text's own width: at auto, a card asked
     the column for the whole of its longest line, which is what a trade like
     "apothecary's apprentice" made a column-wide demand of. The card takes the
     room the column gives it and cuts its own line to fit. */
  .hireinfo{flex:1 1 0; min-width:0;}
  /* Two hands take a line apiece. They stood side by side when the Barracks
     first boarded a second, to spare the sheet the height, and half a column
     is room enough for a name and a bar but not for a trade: two of the
     twenty-one wanted more than the whole half by themselves, and every one of
     them wanted more than the half the pair left. So the second hand wraps to
     its own line, where the widest trade on the roster reads out in full. The
     ladder below finds the height in the same list the panel has always taken
     it from. */
  .hirerow.pair{flex-wrap:wrap; align-items:flex-start;}
  /* the plate and the gap it stands off by are what the lines leave behind:
     at a hair more the card wraps off its own plate, at a hair less the
     second plate rides up onto the first hand's line */
  .hirerow.pair .hireinfo{flex:1 1 calc(100% - 36px);}
  .hirename{font-weight:bold; line-height:1.15; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;}
  /* the yard's stands beside the name, as one star and a figure. The colour is
     the log's own gold, which is what this file marks a thing bought and kept
     with everywhere else; nothing here is a second idiom. */
  .hirestar{color:var(--goldink); font-weight:bold; font-size:10px;}
  /* and the whole parade of stands, drawn in the yard's own window where
     there is room for ten of them. The unbought stands stand as open figures
     rather than being left off, for the reason the Profile draws an unearned
     badge: a row that shows what is left to buy is what makes a bought one
     worth having. */
  .handstars{color:var(--goldink); letter-spacing:1px;}
  .handstarsoff{color:var(--navyink); opacity:0.45;}
  .hirerole{font-size:10px; color:var(--navyink); line-height:1.15; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; margin:0 0 2px;}
  .pbar.hirebar{height:13px;}
  .pbar.hirebar{--fillcol:#0a7d0a;}
  .pbar.hirebar .ptext{line-height:13px; font-size:9px;}

  /* Folding a panel away, and sizing the list inside it. The hireling's panel
     folded to its label from the day it shipped; every panel on the sheet does
     it now, for a player who wants the room somewhere else. The mark before
     the name states which way it goes, and the whole body of the fieldset
     goes with it, the label excepted. */
  .grouplabel.foldable{cursor:pointer;}
  .grouplabel.foldable::before{content:"\25be\00a0"; font-size:9px;}
  .folded > .grouplabel.foldable::before{content:"\25b8\00a0";}
  fieldset.folded{padding-top:11px; padding-bottom:0;}
  fieldset.folded > *:not(.grouplabel){display:none;}
  /* The folded panel's own figure, and the blink that says it moved
     (v1.6.5): filled by renderFoldFigs, worn in the kit label's dim ink,
     and shown only while the panel stands folded, so the open sheet spends
     not a pixel on it. The blink is the label inverted twice over, the
     oldest attention idiom this chrome knows, and it stands down for a
     reader who has asked their machine for less motion. */
  .grouplabel .foldfig{display:none; font-weight:normal; color:var(--dim);}
  .folded > .grouplabel .foldfig{display:inline;}
  @keyframes figblink{
    0%,45%{background:var(--ink); color:var(--paper);}
    55%,100%{background:var(--silver); color:var(--ink);}
  }
  .grouplabel.figblink{animation:figblink 0.38s linear 3;}
  .grouplabel.figblink .foldfig{color:inherit;}
  @media (prefers-reduced-motion:reduce){ .grouplabel.figblink{animation:none;} }
  /* The grip beneath a list: the Win9x splitter nub, drawn in the gap that
     already stands under the list so it costs the sheet no height whatever.
     The strip that answers the pointer is wider than the nub, four pixels
     either side of the list's own edge, which is what a splitter gives the
     hand. Hidden to a finger: a drag upon six pixels is no gesture for a
     touch screen, and there the lists stand at full height regardless. */
  .lvgrip{position:relative; height:0;}
  .lvgrip::before{content:""; position:absolute; left:0; right:0; top:-4px; height:9px; cursor:ns-resize;}
  .lvgrip::after{
    content:""; position:absolute; left:50%; margin-left:-13px; width:26px; top:0; height:3px;
    background:var(--silver);
    box-shadow:inset 1px 1px 0 var(--hi), inset -1px -1px 0 var(--lo);
    pointer-events:none;
  }
  /* the nub is small at rest, as a splitter's is; under the hand it runs
     wider, which is the whole of telling a player that it is a control */
  .lvgrip:hover::after, body.sizing .lvgrip::after{margin-left:-21px; width:42px;}
  .lvgrip:focus-visible{outline:none;}
  .lvgrip:focus-visible::after{outline:1px dotted var(--ink); outline-offset:1px;}
  /* the whole page keeps the sizing cursor while a grip is held, or the
     pointer leaving the strip mid-drag turns it back into an arrow */
  body.sizing, body.sizing *{cursor:ns-resize !important; user-select:none;}
  @media (pointer:coarse){ .lvgrip{display:none;} }

  /* Three even columns, and minmax(0,1fr) rather than a bare 1fr because a
     bare fr has the column's own content for a floor: one long unbreakable
     line anywhere inside it (a hireling's trade, a fabled weapon's name) took
     the room from the two columns beside it, and the papers and the plot were
     squeezed to half their share to pay for it. A third is a third. */
  .cols{display:grid; grid-template-columns:repeat(3, minmax(0,1fr)); gap:8px;}
  @media (max-width:780px){ .cols{grid-template-columns:1fr;} }
  /* the grid stretches the three columns to one height; a grower list in each
     column then takes up the slack, so the foot bar (Knacks, Encumbrance,
     Quest) sits at the bottom of its column and no grey gap opens below it. */
  .cols > div{display:flex; flex-direction:column;}
  .cols fieldset.grow{flex:1 1 auto; display:flex; flex-direction:column; min-height:0;}
  .cols fieldset.grow > .listview{flex:1 1 auto; min-height:0;}
  /* Take the slack-taker out of the office, by folding it or by giving it a
     height of its own, and its column has nobody to hold the room: the empty
     fieldset would stretch to the foot, and under the last panel standing the
     grey would open that the rule above exists to shut. So a grower folded or
     pinned stands its flex down, and markSlack() hands the office to the last
     panel in that column that is neither, which gives it back the moment the
     grower is free again. A pinned list never stretches, wherever it stands;
     the one list left holding the room does, and keeps a floor of two rows so
     a hard drag above it cannot squeeze a panel out of sight. */
  .cols fieldset.grow.folded, .cols fieldset.grow.pinned{flex:0 0 auto;}
  .cols fieldset.slackee{flex:1 1 auto; display:flex; flex-direction:column; min-height:0;}
  .cols fieldset.slackee > .listview{flex:1 1 auto; min-height:36px;}
  .cols fieldset.grow > .listview.pinned,
  .cols fieldset.slackee > .listview.pinned{flex:0 0 auto; min-height:0;}
  /* THE MUSTER TAKES ROOM, IT DOES NOT MAKE IT (v2.1.0). The event's panel is
     the one thing on this sheet that arrives mid-chronicle: every other panel
     is standing from the first frame and the column heights are drawn around
     it, and this one appears the hour a player is posted and takes ninety-odd
     pixels of column three with it. Where the grower has slack it pays for it
     and nothing moves. Where it has none -- a short window, or a big one held
     at a large zoom, which is the same window as far as this sheet is
     concerned -- the column simply grew, the grid row grew with it, and the
     sheet went past the glass: a scrollbar, a foot folded away, and every
     figure in the height ladder wrong at once.

     Making the panel a flex column of its own was tried and measured worse:
     flex stops the children's margins collapsing, so the panel gained height
     in the act of being taught to give it up -- nothing at all to give on a
     tall window, and half again as much to find on a short one. The room comes
     out of the wall instead, which is a list with its own scroll and gives up
     rows the way every other list on this sheet does. */
  #musterbox > .listview{max-height:86px;}
  @media (max-height:748px){ #musterbox > .listview{max-height:56px;} }
  @media (max-height:678px){ #musterbox > .listview{max-height:38px;} }
  /* and the rest of it -- the two labelled troughs and the row that accepts an
     hour -- is paid for out of the two lists standing above it, which is the
     trade this sheet makes everywhere else: a row that arrives comes out of a
     neighbour, never out of the page. Only where the column has no slack of
     its own to give first, which is every step below 820: above it the
     noticeboard absorbs the whole panel and these rules would take room for
     nothing. A hand-set height (--u-) is trimmed with the rest; the room has
     to come from somewhere, and the list a player sized is still a list in
     this column. */
  @media (max-height:820px){
    #game.hasmuster .lv-chron{height:max(40px, calc(var(--u-chron, var(--h-chron)) - 34px));}
    #game.hasmuster .lv-notice{height:max(40px, calc(var(--u-notice, var(--h-notice)) - 34px));}
  }
  /* THE ROW BREATHES (v2.1.0). Every cell in this bar sat on two pixels of
     padding, which is the metric a 1995 status bar used at 96dpi and reads as
     a crease on a modern panel: the work in hand, the three controls beside it
     and the boons under it all ran together into one grey stripe. The padding
     is doubled and the gap opened a pixel, and the height that costs is paid
     back at the embed steps, where the old tight metrics come back (the
     max-height ladder below). */
  .statusbar{margin-top:6px; display:flex; gap:5px; align-items:stretch;}
  .statusbar .cell{
    flex:1; padding:4px 9px;
    border-top:1px solid var(--lo); border-left:1px solid var(--lo);
    border-bottom:1px solid var(--hi); border-right:1px solid var(--hi);
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  }
  .statusbar .cell.small{flex:0 0 auto; min-width:64px; text-align:center;}
  /* THE FOOT OF THE SHEET (v2.1.0). The pack's camps, the clock and the last
     save are not fight-work: none of the three changes on the stroke, and none
     of them wants the eye that the work in hand and the three controls beside
     it want. Standing in that row they crowded it, and the row that carries
     the only buttons on the sheet is the last one that should be crowded. So
     they come down here, under the log, in the corner a status bar has kept
     since Win95, and the row above is left to the work and its controls.
     Right-aligned and no wider than they need: a stretched cell would read as
     an empty field waiting to be filled. */
  /* AND IT NEVER GOES BELOW THE FOLD (v2.1.0). Standing last upon the sheet,
     the foot is the first thing a page that has outgrown its window loses: a
     panel opening mid-chronicle, a window zoomed a notch, anything that puts
     the sheet past the glass. What used to fall off the bottom there was the
     log's oldest line, which nobody misses. The foot is not that.
     It was tried as a sticky row first, and a sticky row holds the bottom of
     the WINDOW while the sheet goes on under it: what the player got was a
     status bar sitting on top of the last line of the log. So the answer is
     not to hold the row down but to stop spending it -- footPlace measures the
     room and folds the three cells back into the work row the moment the sheet
     will not fit, which is the same thing it does at the embed sizes and costs
     the page nothing at all.
     flex:0 0 auto because the desktop build makes this column a flex one and
     the foot is the only item in it with nothing to say about its own height:
     it would be the item chosen to be squeezed. */
  .footbar{justify-content:flex-end; flex:0 0 auto;}
  .footbar .cell{flex:0 0 auto;}
  /* the camps in the pack, drawn as fires: lit is one in hand, ashed is one
     spent. They live in the status row and not beside the HP bar because the
     sheet's height budget is the tightest thing in the game at 920x600 (three
     height steps apply at once there) and this row costs nothing at all. Not
     green: green is uncommon and lg-good, and a colour here means one thing. */
  /* The fires read as a COUNT, which means they need a word beside them and
     enough ink to be a fire rather than a smudge: at 7px they were three dots
     in a status row and a player could not tell what they were counting. */
  .firecell{min-width:0 !important; display:flex; align-items:center; gap:4px; padding:0 10px !important;}
  .firecell .firelab{font-size:10px; opacity:0.8; letter-spacing:0.2px;}
  .firecell .fire{width:10px; height:13px; flex:0 0 auto;}
  .firecell .fire.out{opacity:0.22;}
  /* past six in the pack the row would crowd the status bar, so the count is
     said in figures instead -- the same rule the Roll of Honour marks follow */
  .firecell .firenum{font-size:10px; font-weight:bold;}
  #game.mini .firecell{display:none;}   /* the strip says nothing it need not */
  /* A bar that cannot fit its cells should take a second line, not run the
     last of them off the edge. On a narrow phone the fixed cells alone come to
     more than the screen: measured at 360px, the calendar stood 10px past the
     edge once the Skill Tree cell was made to stand, and a waiting dispatch
     put the save cell 94px past it, which was so before the tree existed. The
     work in hand takes the whole of the first line and the rest follow under
     it. Wider than this nothing changes: the bar has always fitted on one. */
  @media (max-width:560px){
    .statusbar{flex-wrap:wrap;}
    .statusbar > #taskdesc{flex:1 1 100%; min-width:0;}
    .footbar{justify-content:flex-start;}
    /* a row that reads left to right has nothing to push the latch away from */
    .footbar #logfilter{margin-right:0;}
  }
  /* boons stand on their own row beneath the work in hand, so a full slate of
     them never crowds the task text into an ellipsis. The row is shown only
     while a boon is in force (renderBuffs toggles it), so it costs no height
     when there is none. */
  .buffrow{margin-top:5px;}
  .buffrow #buffcell{flex:1; padding:3px 7px;}

  .logwrap{position:relative;}
  #log{
    height:108px; overflow-y:auto; margin-top:6px; padding:2px 4px;
    font-size:11px; line-height:1.45;
    /* and the log keeps its own gutter for the same reason the page keeps one:
       the first line that fills it used to bring the bar out and re-wrap every
       line above it at once, which is a page of prose jumping under the eye
       that is reading it */
    scrollbar-gutter:stable;
  }
  /* the follow cue: a small raised button over the log's foot, shown only
     when fresh lines land while the reader has scrolled back. It inherits the
     standard button bevel; a click on it takes up the newest line again. */
  #logcue{
    position:absolute; right:16px; bottom:6px; z-index:2;
    font-size:10px; padding:2px 8px;
  }
  #logcue.hidden{display:none;}
  #log .t{color:var(--dim4); margin-right:4px;}
  /* the expand toggle (4G.1): the log takes its extra room from the pack
     lists, for players who watch the prose. Every column gives up the same
     108px the log gains, so the window keeps its height. */
  #game.logbig #log{height:216px;}
  #game.logbig{
    --h-traits:90px; --h-stats:96px; --h-spells:86px;
    --h-kit:84px; --h-pack:114px; --h-chron:66px; --h-notice:66px;
  }
  /* the hireling panel (F4) sits at the head of column two, above Equipment
     and Inventory. Column two carries slack the papers column does not, so in
     the normal view the panel costs nothing: the inventory (the growing list)
     simply yields it the room, and the spellbook in column one keeps its full
     height. Only the expanded log (logbig), whose big prose already crowds the
     smaller embeds, needs the pack and kit lists trimmed so a hand at your side
     leaves the window no taller than it stood without one. Scoped to the
     desktop grid; below 781px the columns stack and the lists go flat.
     That slack is spent now: the companion's frame stands in the same column
     from the first hour, and what the hands cost above 678 is stated in the
     block under this one rather than left to a list that has nothing spare. */
  @media (min-width:781px){
    #game.has-hireling.logbig{--h-pack:44px;}
  }
  /* WHAT THE COMPANION'S FRAME COSTS THE TALL WINDOWS. Every rung under this
     one was priced when column two ended at the Inventory, and the arithmetic
     the whole sheet stands on is that its height is the tallest of the three
     columns: the papers come to 537 above 748 and 529 below it, and column two
     had room under that for a hand at your side and a pair alike. The empty
     companion card is 59px of that column at every window, held for good, and
     the two hands no longer fit under the papers' figure: measured with the
     pair aboard, column two came to 581 against 537 at 1100x760 and against
     529 at 1280x720, which is the sheet 44 and 52 past the glass. A single
     hand came to 536, seven over the shorter of the two.
     So the Inventory states the figure here instead of yielding room it has
     not got: 222 less 7 for a hand, less 52 for a pair, which puts column two
     level with the papers at both steps and the sheet exactly where it stood
     before the frame was drawn. It is given straight back wherever the window
     is taller than the papers column, which is what a slack-taking list is
     for. The rungs below restate both figures at the embed sizes. */
  /* AND THE PET'S FRAME JOINED THE COLUMN AFTER THESE WERE MEASURED (v2.6.1).
     The figures above were taken with the companion card in the column and the
     pet's own frame not yet drawn, and the pet's frame is 73px of the same
     column at every window. So the pair ran 20 pixels past the glass at
     1100x760 and 6 past it at 864x594, and html carries overflow:hidden, so
     what runs over is not scrolled to but simply lost. Measured at every shape
     the hireling file drives and stated here rather than left to be yielded:
     the pair comes down 20 and the trio with it, the trio costing the same
     line again. 920x600 and 960x660 were already inside and are unmoved. */
  @media (min-width:781px){
    #game.has-hireling{--h-pack:215px;}
    #game.has-hirepair{--h-pack:150px;}
    /* and a third hand takes the same line again. The Barracks does not board
       it until its fourth stage, which is five hundred million gold and deeper
       than any chronicle inside a fortnight, so this rung is reached late and
       by few: it states the same 45px a second hand costs and leaves the rest
       to the slack-taking list, as every rung of this ladder does. */
    #game.has-hiretrio{--h-pack:105px;}
  }
  @media (min-width:781px) and (max-height:678px){
    #game.has-hireling{--h-pack:116px;}
    #game.has-hireling.logbig{--h-pack:40px; --h-kit:70px;}
  }
  @media (min-width:781px) and (max-height:628px){
    #game.has-hireling{--h-pack:96px;}
    #game.has-hireling.logbig{--h-pack:36px; --h-kit:60px;}
  }
  /* AND WHAT THE HAND'S EMPTY FRAME COSTS, which is a new charge and not a
     discount on the one above: the frame now stands from the first minute and
     the sheet carries it through the whole of a chronicle that never takes a
     hand on. It is 51px of column two, and column two has no 51px spare at any
     window the embed range covers: unpriced, the sheet ran 739 against 720 at
     1280x720 and 641 against 600 at 920x600, and html carries overflow:hidden,
     so what runs over is not scrolled to but simply lost.

     Every figure here was measured and none was reckoned. At each rung the
     Inventory was swept until column two came back to the height it stood at
     with the frame away: 170 of 222 at the tall windows, 120 of 136 at 678,
     70 of 126 at 628. The middle rung gives up only 16 because the column
     still has slack there, which is the whole reason these are measured. */
  @media (min-width:781px){
    #game.has-hirevacant{--h-pack:170px;}
    /* the expanded log takes column two's slack first, so the frame's rung has
       to be stated against it as well or it RAISES the pack back over what
       logbig had already cut it to: the two selectors carry the same weight
       and this one is written later, so it wins on order alone. */
    #game.has-hirevacant.logbig{--h-pack:70px;}
  }
  @media (min-width:781px) and (max-height:678px){
    #game.has-hirevacant{--h-pack:120px;}
    #game.has-hirevacant.logbig{--h-pack:44px; --h-kit:70px;}
  }
  @media (min-width:781px) and (max-height:628px){
    #game.has-hirevacant{--h-pack:70px;}
    #game.has-hirevacant.logbig{--h-pack:36px; --h-kit:60px;}
  }
  /* A second hand takes a line of its own, and that line is 45px the panel did
     not stand at before. The inventory pays it, as it pays for the first hand
     and for the expanded log: it is the growing list in that column, and the
     only list there whose rows are not a fixed count (Equipment's nine slots
     keep their 160px at every step, and a scrollbar on the kit is worse than a
     shorter pack). Above 678px of window the inventory used to have the slack
     in hand and yield it without being told; the companion's frame has that
     slack now, so the block above states the figure there as these two steps
     state it here. */
  @media (min-width:781px) and (max-height:678px){
    #game.has-hirepair{--h-pack:94px;}
    /* and the expanded log at this step stands eight pixels over since the
       frame joined the column: measured at 960x660 with the pair aboard,
       column two came to 385 against the papers' 377. The kit gives the
       eight, the inventory being down to 40 and having nothing to give. */
    #game.has-hirepair.logbig{--h-kit:62px;}
    /* the third hand's line at this step comes off the inventory to its floor
       and then off the kit, in that order, which is the order every rung of
       this ladder spends in */
    #game.has-hiretrio{--h-pack:49px;}
    #game.has-hiretrio.logbig{--h-kit:44px;}
  }
  @media (min-width:781px) and (max-height:628px){
    /* six pixels at this step, measured the same way */
    #game.has-hirepair{--h-pack:46px;}
    /* the expanded log at the smallest window has already taken the inventory
       down to the two-row floor a slack-taking list keeps, so the last dozen
       pixels come off the kit, which scrolls there in any case. The frame in
       the column asks for another twelve: measured at 864x594 with the pair
       aboard, column two came to 359 against the papers' 337, and the kit
       gives twelve of the twenty-two rather than the whole, since below a row
       and a half the list stops reading as a list at all. */
    #game.has-hirepair.logbig{--h-kit:36px;}
    /* and the last ten come out of the prose itself. This is the tightest
       corner the sheet has: the 594 floor, the log doubled, two hands standing
       and the companion's frame open beside them. Column two is spent, and the
       expanded log is 128 pixels of preference over the 46 it rests at here.
       Ten of them buy the foot of the sheet back, which is the trade this
       ladder has made from the beginning. The figure outranks the step's own
       #game.logbig #log by a class and answers wherever it stands. */
    /* AND THE EXPANDED LOG AT THE SMALLEST WINDOW pays its own sixty. The
       inventory is at its two-row floor here and the kit is at 36, so there is
       nothing left in the column to take it from: the log is the panel that is
       never finished, and at 864x594 with a pair aboard it stood 654 against
       594. It gives the sixty back and stands at 104, which is still six rows
       of prose and more than the trio's own figure below. */
    #game.has-hirepair.logbig #log{height:104px;}
    /* the third hand at the 594 floor: the inventory is at its two-row floor
       already, so the line comes off the kit and then off the prose, and both
       are stated rather than left to be found */
    #game.has-hiretrio{--h-pack:40px;}
    #game.has-hiretrio.logbig{--h-kit:24px;}
    #game.has-hiretrio.logbig #log{height:130px;}
    /* AND THE STANDING WEATHER CELL IS PAID HERE TOO (v1.6.4). The two figures
       above were measured with the boon row counted absent; the weather cell
       made it a fixture, and there is still nothing left in the column to take
       from, so the row's 21 come off the log's own figure the way the sixty
       did. Five rows of prose with a pair aboard, and the trio keeps its lead. */
    #game.hasboon.has-hirepair.logbig #log{height:83px;}
    #game.hasboon.has-hiretrio.logbig #log{height:109px;}
  }
  .r-common{color:var(--c-common);} .r-fine{color:var(--c-fine); font-weight:bold;}
  .r-scarce{color:var(--c-scarce); font-weight:bold;} .r-prized{color:var(--c-prized); font-weight:bold;}
  .r-storied{color:var(--c-storied); font-weight:bold;}
  .r-fabled{color:var(--c-fabled); font-weight:bold;}
  .lg-good{color:#0a7d0a;} .lg-gold{color:var(--goldink);} .lg-bad{color:#a00000;}
  .lg-sys{color:var(--navyink); font-weight:bold;} .lg-crit{color:#a00000; font-weight:bold;}
  /* the muster speaks in its own ink, so a line from the wall is picked out of
     the descent's own chatter at a glance */
  .lg-muster{color:#7a3a00;} .lg-muster b{color:var(--navyink);}
  html.dark .lg-muster{color:#d09a5c;} html.dark .lg-muster b{color:#b9c6ff;}
  body.hicontrast .lg-muster{color:#5c2b00;}
  html.dark body.hicontrast .lg-muster{color:#e8b070;}
  /* The three columns of the muster window, after the manner of a raid board:
     the campaign's stages on the left, word off the wall in the middle, and
     the roll of who is standing on the right. */
  /* the three wrap rather than crush: under about five hundred pixels of
     viewport the roll drops to its own line and the feed keeps a column wide
     enough to read a name in, instead of being squeezed to a strip */
  .musterrow{display:flex; flex-wrap:wrap; gap:6px; margin-top:6px; align-items:stretch;}
  .musterrow > .musterstages{flex:0 0 186px; height:146px; overflow-y:auto; padding:3px 5px;}
  .musterrow > .musterfeed{flex:1 1 200px; min-width:200px; height:146px; overflow-y:auto; padding:3px 5px;}
  .musterrow > .musterroll{flex:0 0 196px; height:146px; overflow-y:auto;}
  .musterfeed div{padding:1px 0;}
  .musterfeed div + div{border-top:1px solid var(--rule2);}
  /* the roll is a table in a narrow column, so nothing in it may wrap: a name
     that wrapped left its second line reading "(away)" and nothing else, and
     the hours were clipped mid-word */
  .musterroll td, .musterroll th{white-space:nowrap;}
  .musterroll td:first-child{max-width:120px; overflow:hidden; text-overflow:ellipsis;}
  .musterroll td:last-child, .musterroll th:last-child{text-align:right;}
  /* the plate hung over a reckoning: the board's own image, or the frame that
     stands in its place until the keeper hangs one */
  /* the plate shows whole and the frame scrolls, so nothing is ever cropped
     away: a tall plate is read by rolling it, as any list in the game is */
  .musterplate{border:1px solid var(--rule); background:var(--paper); margin-bottom:6px;
    text-align:center; max-height:240px; overflow-y:auto;}
  .musterplate img{display:block; width:100%; height:auto;}
  .musterplate.fetching span{animation:platewait 1.6s steps(2) infinite;}
  @keyframes platewait{0%,49%{opacity:1;} 50%,100%{opacity:0.45;}}
  @media (prefers-reduced-motion:reduce){ .musterplate.fetching span{animation:none;} }
  /* a plate still decoding says so over itself rather than sitting blank */
  .musterplate.loading{position:relative; min-height:60px;}
  .musterplate.loading img{visibility:hidden;}
  .musterplate.loading::after{content:"the plate is on its way"; position:absolute; inset:0;
    display:flex; align-items:center; justify-content:center;
    color:var(--dim4); font-style:italic;
    background:repeating-linear-gradient(45deg, var(--paper), var(--paper) 6px, var(--face) 6px, var(--face) 12px);}
  .musterplate.todo{height:96px; display:flex; align-items:center; justify-content:center;
    color:var(--dim4); font-style:italic;
    background:repeating-linear-gradient(45deg, var(--paper), var(--paper) 6px, var(--face) 6px, var(--face) 12px);}
  .mustershout{font-weight:bold; margin:0 0 4px;}
  /* the vote: two endings side by side, each a thing to pick up and turn over */
  .votegrid{display:flex; gap:6px; margin-top:6px; flex-wrap:wrap;}
  .votecard{flex:1 1 220px; min-width:200px; cursor:pointer; padding:4px;
    background:var(--face); border:2px solid; border-color:var(--hi) var(--lo) var(--lo) var(--hi);}
  .votecard:hover{background:var(--chip);}
  .votecard.mine{border-color:#0a7d0a; background:#dff3df;}
  html.dark .votecard.mine{background:#1d3320; border-color:#6ec96e;}
  .votecard .musterplate{margin-bottom:4px;}
  .votecard .musterplate{max-height:130px;}
  .votename{font-weight:bold;}
  .votetext{margin-top:2px;}
  .votenote{margin-top:3px; color:var(--dim); font-style:italic;}
  .votetally{padding:2px 0;}
  .votetally + .votetally{border-top:1px solid var(--rule2);}
  .votetally.won b{color:#0a7d0a;}
  html.dark .votetally.won b{color:#6ec96e;}
  body.hicontrast .votetally.won b, body.hicontrast .votecard.mine{border-color:#065e06;}
  .votetally .prov{color:var(--dim); font-style:italic;}
  .musterwait{font-weight:bold; text-align:center; padding:4px; margin-top:6px;
    background:var(--chip); border:1px solid var(--navyink); color:var(--navyink);}
  .musterstages .stage{padding:3px 2px;}
  .musterstages .stage + .stage{border-top:1px solid var(--rule2);}
  .musterstages .stagenote{display:block; color:var(--dim3); margin-left:12px;}
  .musterstages .done .stagenote, .musterstages .todo .stagenote{color:var(--dim4);}
  .musterstages .mark{display:inline-block; width:12px;}
  /* the stage standing is picked out in the green the game already uses for a
     good turn, and a stage behind you says so in one word */
  .musterstages .now{background:#dff3df; outline:1px solid #0a7d0a;}
  .musterstages .now > b{color:#0a7d0a;}
  html.dark .musterstages .now{background:#1d3320; outline-color:#6ec96e;}
  html.dark .musterstages .now > b{color:#6ec96e;}
  .stagetag{float:right; font-weight:bold; font-size:9px; padding:0 3px; letter-spacing:0.5px;}
  .done .stagetag{color:#0a7d0a; border:1px solid #0a7d0a;}
  .now  .stagetag{color:#0a7d0a; background:#0a7d0a; color:#fff;}
  .todo .stagetag{color:var(--dim4); border:1px solid var(--dim4);}
  html.dark .done .stagetag{color:#6ec96e; border-color:#6ec96e;}
  html.dark .now .stagetag{background:#6ec96e; color:#12210f;}
  /* a hand on the roll answers to a click with a note upon it, so the column
     is a thing to poke at and not only a thing to read */
  .musterroll tbody tr{cursor:pointer;}
  .musterroll tbody tr:hover{background:var(--chip);}
  /* the hour stood, waiting upon a word: the one moment the window shouts */
  .watchready{background:#dff3df; outline:1px solid #0a7d0a; padding:3px 5px; margin-top:6px; font-weight:bold; color:#0a7d0a;}
  html.dark .watchready{background:#1d3320; outline-color:#6ec96e; color:#6ec96e;}
  .lg-amb{color:#7a7a88; font-style:italic;}
  /* THE ROAD'S OWN ARITHMETIC, set behind its line rather than instead of it.
     Every other figure in the game is shown in one voice or the other by the
     Simplicity option; a stretch of road is a run of dice nobody saw thrown,
     so it prints the flavour and the working together and the working is set
     down a shade so the sentence still reads first. */
  .lg-fig{color:#8a8a96; font-size:.92em; letter-spacing:.01em;}
  /* THE SEVEN KINDS. These come after the tones on purpose, so a line that has
     a kind wears it and a line that has none keeps the tone it always had. The
     arithmetic is a nested span and keeps its own grey whatever the row wears,
     which is the whole of how the flavour is coloured and the working is not. */
  .lg-c-combat{color:#a00000;}
  .lg-c-trade{color:#9a6a00;}
  .lg-c-road{color:#7a5230;}
  .lg-c-rest{color:#0a7d0a;}
  .lg-c-descent{color:#6a2d8a;}
  .lg-c-guild{color:#000080;}
  .lg-c-town{color:#5a6a7a;}
  /* and the latch hides a kind outright, the reader's own business */
  #log.hide-combat  [data-cat="combat"],
  #log.hide-trade   [data-cat="trade"],
  #log.hide-road    [data-cat="road"],
  #log.hide-rest    [data-cat="rest"],
  #log.hide-descent [data-cat="descent"],
  #log.hide-guild   [data-cat="guild"],
  #log.hide-town    [data-cat="town"]{display:none;}
  /* THE LATCH COMES DOWN TO THE FOOT. It stood at the log's top shoulder as a
     floating knocker, which is the one corner of the window where a control
     has nothing to stand on: it sat over the oldest line in view, half faded so
     as not to bury it, and read as a smudge on the prose rather than a switch.
     The foot is where a Win9x window keeps the things that are the reader's own
     business, and that row already holds three of them and stands empty at its
     left end. So the latch takes that end, wears the same sunken cell as its
     neighbours, and carries its word now that it is out of the log's sight. */
  .logwrap{position:relative;}
  /* the three cells of the foot are right-aligned; the latch is not one of
     their kind and takes the far end of the row on its own */
  #logfilter{background:none; box-shadow:none; cursor:pointer;
    color:var(--dim); margin-right:auto;}
  #logfilter:hover, #logfilter:focus{color:var(--navyink);}
  #logfilter.on{color:var(--ink); font-weight:bold;}
  .lgfrow{display:flex; align-items:baseline; gap:6px; padding:2px 0;}
  .lgfrow label{cursor:pointer;}
  .lgfswatch{display:inline-block; width:9px; height:9px; flex:0 0 9px; border:1px solid rgba(0,0,0,.35);}
  .lgfhint{color:#6a6a76; font-size:.9em;}
  /* Quiet density (4G.1): system chatter prints dim and unbolded, ambient
     lines dimmer still; a lately repeated ambient is withheld in log() */
  #log.quiet .lg-sys{color:#66688a; font-weight:normal;}
  #log.quiet .lg-amb{opacity:.7;}
  /* a mark rides beside every rarity colour, for eyes that keep no colour
     (4H.5 / Q2); the rarity word still prints as ever. The switch lives in
     Options ("Mark rarities in print"); the classic footnote marks climb
     the ladder, distinct in print and in greyscale. */
  body.rmarks .r-fine::before{content:"† "; font-weight:normal;}
  body.rmarks .r-scarce::before{content:"‡ "; font-weight:normal;}
  body.rmarks .r-prized::before{content:"§ "; font-weight:normal;}
  body.rmarks .r-storied::before{content:"‖ "; font-weight:normal;}
  body.rmarks .r-fabled::before{content:"¶ "; font-weight:normal;}
  /* A piece that bears a brand takes the asterisk, which is the first mark of
     the same classic footnote sequence the rarities climb, and it says what
     every asterisk says: there is a note, and the note is in the appraisal.
     It is a span rather than a ::before because the rarity marks above already
     hold that pseudo-element, and it stands at the head of the cell so it
     survives the ellipsis that has always truncated a long kit name. */
  .bmark{font-weight:normal; font-style:normal;}
  /* High-contrast text (Q2): the ground greys darken and the rarity hues
     deepen against the silver, for readers who want more contrast. The
     chrome bevels keep their greys, so the Win9x look holds. */
  body.hicontrast{
    --c-common:#000; --c-fine:#065e06; --c-scarce:#002a8c;
    --c-prized:#61007e; --c-storied:#7a3c00; --c-fabled:#8a0000;
    --c-iron:#00464e; --c-silver:#2f4055; --c-crowned:#4c3900;
  }
  body.hicontrast{--goldink:#7a5400;}
  body.hicontrast .lg-good{color:#065e06;}
  /* the muster's greens take the same darkening as the log's good turn, so the
     stage standing and the hour waiting upon a word hold their contrast */
  body.hicontrast .musterstages .now{outline-color:#065e06;}
  body.hicontrast .musterstages .now > b{color:#065e06;}
  body.hicontrast .done .stagetag{color:#065e06; border-color:#065e06;}
  body.hicontrast .now  .stagetag{background:#065e06; color:#fff;}
  body.hicontrast .todo .stagetag{color:#5a5a5a; border-color:#5a5a5a;}
  body.hicontrast .watchready{outline-color:#065e06; color:#065e06;}
  /* AND THE SAME FOUR WITH THE LAMPS DOWN. High contrast darkens an ink to
     hold it against paper, and the two switches meet at dark ink upon a dark
     ground: the muster's stage, its tag and the hour waiting upon a word all
     went to #065e06 on navy, which is a green nobody can read. verify-theme
     names every rule this happens to and it named these four. */
  html.dark body.hicontrast .musterstages .now > b{color:#8ee88e;}
  html.dark body.hicontrast .done .stagetag{color:#8ee88e; border-color:#8ee88e;}
  html.dark body.hicontrast .todo .stagetag{color:#b0b2b6; border-color:#b0b2b6;}
  html.dark body.hicontrast .watchready{outline-color:#8ee88e; color:#8ee88e;}
  /* THE TWELVE TRADE INKS COME OFF UNDER HIGH CONTRAST, all of them, in one
     rule. A third value apiece would be thirty-six hexes and a palette nobody
     can hold in their head, and it would be answering the wrong question: the
     option is asked for by a player who wants ink against ground, and twelve
     mid-tone hues are the thing being complained about. The set was chosen so
     that every mark reads as a silhouette with the colour taken away -- that
     is the state it was drawn in -- so nothing is lost but the hue. */
  body.hicontrast .tm{color:var(--ink) !important;}
  body.hicontrast .radio-list label:has(input:checked) .tm{color:#fff !important;}
  body.hicontrast .lg-amb{color:#4c4c58;}
  body.hicontrast #log.quiet .lg-sys{color:#33355c;}
  body.hicontrast #log.quiet .lg-amb{opacity:1;}
  body.hicontrast table.lv tr.locked td{color:#5a5a5a;}
  body.hicontrast .optnote, body.hicontrast .barlabel .optnote{color:#555;}
  /* log art direction (4E.2): a crit or boss line lands with a one-frame
     background highlight, gone by the next glance */
  .lg-hit{animation:loghit .5s ease-out;}
  @keyframes loghit{from{background:#ffe9b0;} to{background:transparent;}}

  #creator .client{max-width:700px;}
  .cre-grid{display:grid; grid-template-columns:1fr 1fr 1fr 1fr; gap:8px;}
  @media (max-width:700px){ .cre-grid{grid-template-columns:1fr;} }
  /* 208px held the twelve rows the three columns shipped with exactly, and the
     thirteenth of the folk and the origins landed half-drawn under the fold. A
     row a player has to find by scrolling is a poor place for the only two rows
     the sheet ever withholds, so the box grows by one row and no more: thirteen
     rows of 16.5 plus the padding. */
  .radio-list{max-height:226px; overflow-y:auto; padding:2px;}
  .radio-list label{display:block; padding:1px 2px; white-space:nowrap; cursor:pointer;}
  .radio-list label:has(input:checked){background:var(--navy); color:#fff;}
  /* a row still under seal: greyed, and it does not take the pointer's finger,
     because a row that looks clickable and refuses the click reads as broken.
     The slip still rings for it, which is where the deed that opens it stands. */
  .radio-list label.crelock{color:var(--dim4); cursor:default;}
  /* the chosen row is navy, so the mark upon it takes its trade's raised ink;
     the rule lives with the other two beside .tm, where all three can be read
     against each other */
  .radio-list input{vertical-align:-1px; margin-right:4px;}
  .stat-table{width:100%; border-collapse:collapse;}
  .stat-table td{padding:2px 4px;}
  .stat-table td.v{text-align:right; width:42px; background:var(--paper);
    border-top:1px solid var(--lo); border-left:1px solid var(--lo);
    border-bottom:1px solid var(--hi); border-right:1px solid var(--hi);}
  .total-good{color:#a00; font-weight:bold;}
  .total-great{color:#a0a; font-weight:bold;}
  .namerow{display:flex; gap:4px; margin-bottom:8px;}
  .crebtns{display:flex; gap:6px; justify-content:space-between; margin-top:10px; flex-wrap:wrap;}
  .audiorow{display:flex; align-items:center; gap:6px; margin-top:10px; cursor:pointer; width:fit-content;}
  .audiorow input{margin:0;}
  /* the Options dialog (4H.4): the small switches, kept together */
  .optrow{display:block; padding:2px 0; cursor:pointer;}
  .optrow input{vertical-align:-1px; margin-right:4px;}
  .optrow input:disabled + span{color:var(--mute);}
  .optnote{color:var(--dim); font-style:italic;}
  .volrow{display:flex; align-items:center; gap:6px; padding-top:4px;}
  .volrow input[type=range]{flex:1; max-width:220px;}
  /* the first sheet: the Guild's three questions, asked once before
     enrolment. The greeting plate is the one raster the game ships, sunk
     like any other field */
  #setupdlg .setupart{display:block; width:100%;}
  #setupdlg .setupartbox{padding:2px; margin-bottom:8px;}
  /* the Music window (4F.3): the minstrel's book, one line to an air */
  .airlist{max-height:280px; overflow:auto; padding:4px 6px; background:var(--paper);}
  .airlist .airmod{color:var(--navyink); font-weight:bold; margin:9px 0 1px;
    border-bottom:1px solid var(--rule2); padding-bottom:1px;}
  .airlist .airmod:first-child{margin-top:0;}
  .airlist .airgrp{color:var(--dim); font-weight:bold; margin:6px 0 2px; padding-left:8px;}
  .airlist .airgrp:first-child{margin-top:0;}
  .airlist .airmod + .airgrp{margin-top:3px;}
  .airlist .optrow{padding-left:8px;}
  .airlist .optrow.playing span{font-weight:bold;}
  #airsnow{margin:0 0 6px;}
  .soldbtn{font-weight:bold; padding:4px 26px;}
  .hidden{display:none !important;}
  .hint{color:var(--dim3); margin-top:8px;}
  /* The Roll's standing, on the enrolment sheet. It was one run-on line of
     purple in the middle of a grey form, and at a dozen upgrades and a dozen
     retired names it was a wall nobody read. It is a panel now, in the shape
     of the three beside it: what you hold, then the upgrades ruled in a column
     with the figure to the right, then the names in one quiet line. */
  #legacystanding{margin-bottom:5px;}
  #legacystanding b{color:var(--navyink);}
  /* Two columns, because a veteran holds fourteen of these and a single column
     either scrolls half of them out of sight or makes the sheet twice as tall.
     The sheet is wide and the rows are short, so the pair fits with room over.
     One column on a narrow window, where two would break the figures off. */
  #legacyups{padding:1px 5px; column-count:2; column-gap:16px;}
  #legacyups .uprow{display:flex; gap:8px; align-items:baseline;
    padding:2px 0; border-bottom:1px solid var(--rule2);
    break-inside:avoid; -webkit-column-break-inside:avoid;}
  @media (max-width:760px){ #legacyups{column-count:1;} }
  #legacyups .upname{flex:1;}
  #legacyups .upfig{font-weight:bold; color:var(--navyink); text-align:right;}
  #legacynames{margin-top:5px; color:var(--dim3);}

  /* The card is asked for, never delivered unbidden, so it takes the middle of
     the screen. z-index above the .overlay band (70), because it is raised
     from the Story book and must be answerable over it. The veil is the same
     scrim every window in the game draws. */
  #fatecard{
    position:fixed; inset:0; z-index:76; background:var(--scrim);
    display:flex; align-items:center; justify-content:center;
    padding:14px; overflow-y:auto; -webkit-overflow-scrolling:touch;
  }
  #fatecard > .win{
    width:360px; margin:auto;
    max-width:calc(100vw / var(--ui-zoom,1) - 28px);
  }
  #fatecard .client{padding:8px;}
  .fatewarning{
    padding:4px 7px; background:#ffff80; color:#000; border-top:1px solid #fff;
    border-bottom:1px solid var(--dark); font-weight:bold;
  }
  #fatebtns{display:flex; flex-direction:column; gap:4px; margin-top:8px;}
  #fatebtns button{text-align:left;}
  #fatebtns button.aside{text-align:center; color:var(--dim2);}

  #toasts{position:fixed; top:14px; right:14px; z-index:60; display:flex; flex-direction:column; gap:6px; align-items:flex-end;}
  .toast{
    background:var(--silver); border:1px solid var(--dark);
    box-shadow:inset 1px 1px 0 var(--hi), inset -1px -1px 0 var(--lo), 2px 2px 5px rgba(0,0,0,.35);
    padding:6px 10px; max-width:280px;
    animation:toastin .25s ease-out;
  }
  /* --navyink and not --navy: the one is the ink of a heading, which comes up
     pale on a dark ground, the other is the ground of a title bar, which stays
     dark in both themes. A toast wearing the ground as ink is unreadable by
     lamplight, which is how it was reported. */
  .toast b{color:var(--navyink);}
  @keyframes toastin{from{transform:translateX(24px); opacity:0;} to{transform:none; opacity:1;}}

  .floater{
    position:fixed; z-index:55; font-weight:bold; pointer-events:none; font-size:12px;
    animation:floatup 1.15s cubic-bezier(.22,.61,.36,1) forwards; text-shadow:0 0 3px var(--halo),0 0 3px var(--halo);
  }
  .floater.big{font-size:17px;}
  /* and the figure that flies into its own counter: it fades in a little above
     the number, drops onto it and shrinks away as the counter takes up the
     count. Short, because it is an arrival and not an announcement. */
  .floater.merge{animation:mergein .6s cubic-bezier(.4,0,.2,1) forwards; font-size:12px;}
  /* the purse, found without hunting for it */
  .coin{width:10px; height:10px; vertical-align:-1px; margin-right:4px; color:#9a6a00;}
  .goldrow td{color:#9a6a00;}
  .goldrow #goldcell{font-size:1.25em; letter-spacing:.02em;}
  .stripgold #stripgold{color:#9a6a00; font-size:1.2em;}
  html.dark .coin{color:#d8a83c;}
  html.dark .goldrow td{color:#d8a83c;}
  html.dark .stripgold #stripgold{color:#d8a83c;}
  @keyframes mergein{
    0%{transform:translateY(-9px) scale(1.2); opacity:0;}
    30%{transform:translateY(-7px) scale(1.15); opacity:1;}
    100%{transform:translateY(15px) scale(.62); opacity:0;}
  }
  @keyframes floatup{
    0%{transform:translateY(8px) scale(.5); opacity:0;}
    16%{transform:translateY(-2px) scale(1.3); opacity:1;}
    30%{transform:translateY(-6px) scale(1);}
    100%{transform:translateY(-42px) scale(1); opacity:0;}
  }

  /* the heavy beats: a white flash, a shaken window, a banner between
     the kill and the paperwork. All of it idle under reduced motion. */
  #flash{position:fixed; inset:0; z-index:66; background:#fff; opacity:0; pointer-events:none;}
  #flash.on{animation:flashout .28s ease-out;}
  @keyframes flashout{from{opacity:var(--flashmax,.8);} to{opacity:0;}}
  /* THE BLOW NEVER FALLS DOWNWARD (v2.1.0). A transform counts toward the
     scroller's overflow, and the sheet is drawn to fit the window exactly: a
     jolt of two pixels DOWN put the page two pixels over its height, brought
     the page's scrollbar out for the length of the animation and put it away
     after, and the sheet was re-laid sideways twice for a hit that landed.
     Sideways the shake has the body's own padding to move in and costs
     nothing; upward it moves into the padding above and off the start edge,
     which no scroller counts. So the jolt keeps its whole force and spends it
     in the three directions that are free. The gutter reserved at body is the
     belt to this pair of braces: between them, a landed blow cannot move one
     pixel of the sheet it did not mean to. */
  .shake{animation:shake .28s linear;}
  @keyframes shake{
    20%{transform:translate(-4px,-2px);} 40%{transform:translate(3px,-3px);}
    60%{transform:translate(-2px,-1px);} 80%{transform:translate(2px,-2px);}
  }
  #banner{position:fixed; inset:0; z-index:68; display:flex; align-items:center; justify-content:center; pointer-events:none;}
  #banner .plate{
    background:var(--silver); border:1px solid var(--dark);
    box-shadow:inset 1px 1px 0 var(--hi), inset -1px -1px 0 var(--lo), 2px 2px 6px rgba(0,0,0,.4);
    padding:14px 34px; text-align:center;
    animation:bannerin .16s ease-out;
  }
  #banner .plate b{font-size:18px; letter-spacing:1px;}
  #banner .plate small{display:block; font-size:11px; margin-top:4px; color:var(--dim2);}
  @keyframes bannerin{from{transform:scale(.7); opacity:0;} to{transform:none; opacity:1;}}

  @media (prefers-reduced-motion: reduce){
    .floater, .toast{animation:none;}
    .pbar .fill{transition:none;}
    #flash.on, #banner .plate, .shake{animation:none;}
    .lg-hit, .creditroll{animation:none;}
    .creditbox{overflow-y:auto;}
    .chartcell.waiting{animation:none; background:var(--chip);}
    .guildplate.lit .lamp{animation:none;}
  }
  /* the same stilling, asked for in Options rather than by the machine */
  body.stillmotion .floater, body.stillmotion .toast{animation:none;}
  body.stillmotion .pbar .fill{transition:none;}
  body.stillmotion #flash.on, body.stillmotion #banner .plate, body.stillmotion .shake{animation:none;}
  body.stillmotion .lg-hit, body.stillmotion .creditroll{animation:none;}
  body.stillmotion .creditbox{overflow-y:auto;}
  body.stillmotion .chartcell.waiting{animation:none; background:var(--chip);}
  body.stillmotion .guildplate.lit .lamp{animation:none;}

  /* mini mode (4E.7 / 4H.3): the minimize button folds the window to a
     one-row strip: the work in hand, the last log line, the dispatch badge
     and the clock, sized to sit in the corner of a monitor. */
  #game.mini{max-width:560px;}
  #game.mini .menubar, #game.mini .cols{display:none;}
  /* The gutter comes off with the fold. body keeps scrollbar-gutter:stable for
     the unfolded sheet (v2.1.0), but a folded strip scrolls nothing, and under
     the wrapper the window is sized to the strip's own box: fifteen pixels
     held for a bar that cannot come would leave the strip fifteen narrower
     than its window on every exchange, each resize paying the toll again. */
  .folded body{scrollbar-gutter:auto;}
  /* And in a browser the strip goes to a corner and stays there. Folded, it
     used to sit in the flow where the whole window had stood, which on itch is
     a shrunk game at the top of the frame and no dock at all. The corner is the
     bottom left, where Win9x sent a minimized window. (It was chosen as the one
     corner the dispatch card did not hold; since v1.6.7 the card takes the
     middle of the screen and holds no corner at all, and the strip keeps this
     one because that is where Win9x put it.) The PC build is untouched: there
     the strip IS the window, and the wrapper docks it (desktop/window.js). */
  html:not(.app).folded #game.mini{
    position:fixed; left:10px; bottom:10px; right:auto; margin:0; z-index:50;
    max-width:min(560px, calc(100vw / var(--ui-zoom,1) - 20px));
  }
  /* Fold is one way. The square beside it unfolds, so a folded strip has no use
     for the underscore and does not show a button that would undo the fold
     under a slip that says it makes one. Under the wrapper it stays: there it
     is the window's own minimize and means the taskbar. */
  html:not(.app) #game.mini #minbtn{display:none;}
  /* One line of log in the strip, and the rules written for the unfolded window
     do not get a vote. #game.hasboon:not(.logbig) #log carries more weight than
     #game.mini #log does and sets the log taller so that a boon's row has
     somewhere to come from; in a strip the boon row is hidden and the window is
     sized to the strip, so all that arrived was six more pixels of window every
     time a boon came into force and went again. The three other uses of
     !important in this sheet are the same kind of case: a rule that has to win
     or the thing it holds up is broken. */
  #game.mini #log{height:24px !important; overflow:hidden;}
  #minbtn, #maxbtn{cursor:pointer;}
  /* Both of these are out of the flow in the unfolded window and carry nothing
     there: the sheet's own bars are only moved into them once the window folds
     (stripGather). So the full window draws exactly what it drew before. */
  #stripface, #stripbay{display:none;}
  #game.mini #stripface{display:block; flex:0 0 auto;}
  /* THE PLATE'S GROUND GOES WITH THE PLATE (v2.0.4). The field carried the
     bestiary's paper because it held an inked drawing and a drawing wants
     paper under it. It holds the trade's mark now, which is a figure in the
     trade's own ink with nothing behind it, and a slip of paper under it would
     read as a sticker on the chrome -- and worse in the dark, where the paper
     stays light and the marks are raised light to match the ground they have
     lost. The beast's plate and the hireling's are untouched: both still hold
     drawings. */
  #game.mini #stripface .heroart{width:38px; height:38px; flex:0 0 38px;}
  #game.mini #stripface .heroart svg{width:100%; height:100%;}
  /* the purse, the two pools, and the descent, which wraps to a rule across
     the whole foot: it is the one bar that moves at the pace of a glance
     taken every twenty minutes rather than every few seconds. */
  #game.mini #stripbay{display:flex; flex-wrap:wrap; align-items:center;
    gap:3px 6px; margin-top:3px;}
  #game.mini #stripbay .stripgold{font-size:10px; white-space:nowrap;}
  #game.mini #stripbay #bar-hp, #game.mini #stripbay #bar-mp{flex:1 1 60px; height:9px;}
  /* The sheet's bars keep their figure in a cell beside the trough (.pfig), and
     that cell stays behind on the sheet when the strip borrows the bar. In a
     strip there is no room for it either way, so here the figure goes back
     inside the blocks it came off, which is where a strip has always read it. */
  #game.mini #stripbay .pbar.figout .ptext{display:block;}
  #game.mini #stripbay .ptext{font-size:8px; line-height:7px;}
  #game.mini #stripbay #bar-plot{flex:0 0 100%; height:4px;}
  #game.mini #stripbay #bar-plot .ptext{display:none;}
  /* The strip is one height and stays there. At 560 wide the narrow step above
     gives the work in hand a line of its own and wraps the rest of the bar under
     it, which in a strip came to four rows that grew and shrank as a boon came
     into force or a letter arrived: in the PC build, where the window is sized to
     the strip, that is a window resizing itself under the player's hand every
     time the road changes. So the strip takes that rule back and keeps its bar on
     one line, and the cells that are not glance-work stand down: the skill tree,
     the time since the last save, and the boon row are the whole window's
     business. The log's new-lines cue goes too; the strip always follows the
     newest line (jumpLog), so it has nothing to cue. */
  #game.mini .statusbar{flex-wrap:nowrap; overflow:hidden;}
  #game.mini .statusbar > #taskdesc{flex:1 1 auto; min-width:0;}
  #game.mini #chartcell, #game.mini #savecell, #game.mini #logfilter,
  #game.mini #buffrow, #game.mini #logcue{display:none;}
  /* the foot of the sheet folds up into this row in the strip (footPlace), and
     the strip keeps only the clock of the three: the camps and the age of the
     last save are hidden by name above. display:contents, so the berth ranks
     what it holds among the row's own cells rather than nesting it in a box. */
  #footberth{display:none;}
  #footberth.on{display:contents;}
  #game.mini .statusbar .cell{padding:2px 7px;}
  #game.mini .dispatchbtn, #game.mini .campbtn{font-size:11px; padding:2px 8px;}
  #game.mini #bar-task{height:16px; margin-top:4px;}
  #game.mini #bar-task .ptext{line-height:16px; font-size:11px;}

  /* the About box earns its credits scroll (4E.7), in the old manner */
  .creditbox{height:72px; overflow:hidden; margin-bottom:6px;
    text-align:center; font-size:10px; line-height:1.7; padding:0 6px;}
  .creditroll{animation:creditscroll 28s linear infinite;}
  @keyframes creditscroll{from{transform:translateY(72px);} to{transform:translateY(-100%);}}
  @media (prefers-reduced-motion: reduce){ .creditroll{animation:none;} }

  /* WHAT THE ROOM COSTS, AND WHO PAYS FOR IT (v2.1.0). The doubled padding in
     the work row, the taller work bar and the row at the foot come to some
     forty pixels of chrome. A tall window has them; below 820 it does not, and
     below that the sheet is at the embed sizes, where it has fought for single
     pixels since the beginning and cannot spare a row for a status bar.

     So the ladder pays in two steps. Between 748 and 820 the chrome takes back
     its old tight metrics and the log gives up the foot's own row -- the log
     is the panel that is never finished, and that is the trade the whole
     ladder below already makes. Below 748 the foot folds up into the work row
     (footPlace), the sheet is exactly the shape it was, and every figure in
     the ladder under this holds unchanged. The typography stays put at every
     step: bold figures on the bars and bold names on the boons cost no height.

     This band is written closed at the bottom rather than open, so the step
     below may set the same figure without a fight over which rule was written
     last. The chrome's own scale-back is a plain max-height and stands at the
     very foot of this sheet, after every rule it takes back. */
  @media (max-height:820px) and (min-height:749px){
    #log{height:84px;}
    /* and a boon coming into force gives its row back out of the log here too,
       exactly as the steps below do: in this band the page has no slack, and a
       row arriving unpaid for is the page going over its height mid-fight */
    #game.hasboon:not(.logbig) #log{height:63px;}
    #game.logbig #log{height:192px;}
  }
  /* embed steps: 700-ish, 660-ish, and the 600 floor of itch's range.
     The expanded log keeps the same trade at every step: +108 of prose,
     paid for by the kit and pack lists in equal measure. */
  /* AND THE TWO EMBED STEPS PAID FOR THE PAPERS' SIXTH ROW AT LAST (v2.2.0).
     The row Mastery added was paid for at the 628 step when it arrived and
     nowhere above it, so 700 stood 24 pixels over its own gate and 660 stood 18
     -- the itch embed opened a page scrollbar at two of the three shapes it is
     measured at, and qa-itch had been saying so. The log gives the pixels back,
     which is the trade every step of this ladder already makes and the one the
     head of it is written around: the log is the panel that is never finished. */
  @media (max-height:748px){
    body{padding:6px 10px;}
    #log{height:48px;}
    #game.hasboon:not(.logbig) #log{height:27px;}
    #game.logbig #log{height:196px;}
  }
  /* ---------- THE GAP BETWEEN THE RUNGS (v2.6.1) ----------
     Below 678 the panels are trimmed and the log takes what they give up. Above
     748 there is room for everybody. Between the two nothing trimmed anything,
     so a window in that band carried the FULL panels on a short screen and the
     log -- the slack-taker of its column, and the panel that is never finished
     -- paid for all of it. MEASURED: 1024x700 stood the log at 66 pixels while
     960x660, a screen forty pixels SHORTER, stood it at 70. A taller window
     giving a shorter log is the ladder saying plainly that it has a rung
     missing, and the floor this file keeps for that band is 72.

     So the band gets a rung of its own, and a light one: the same panels the
     678 rung trims, trimmed about half as far, which is what the gap is worth.

     AND IT IS BOUNDED ON THREE SIDES. min-height:679 keeps it off the rung
     below, which already trims harder; max-height:748 stops it where the screen
     stops being short. The width bound is the one that took measuring: at 1280
     the sheet already stands the log at 86 and has slack to spare, and trimming
     there would hand the papers column a slack of its own that it is not
     supposed to have -- the drag checks in verify-panels read that column as
     the one with none, and it is. It is the NARROW short window that is
     squeezed, because narrow columns make tall panels: 1024x700 is the shape
     that stood at 66, and 1100 is the width above which the sheet is measured
     comfortable. Only --h-pack moves at width alone; the papers move only
     where the width is what is doing the squeezing. */
  @media (max-height:748px) and (min-height:679px){
    #game{--h-pack:179px;}
  }
  @media (max-width:1100px) and (max-height:748px) and (min-height:679px){
    #game{--h-stats:129px; --h-spells:111px;}
  }
  @media (max-height:678px){
    #game{--h-stats:118px; --h-spells:100px; --h-pack:136px;}
    #log{height:52px;}
    #game.hasboon:not(.logbig) #log{height:31px;}
    #game.logbig #log{height:186px;}
    #game.logbig{--h-stats:82px; --h-spells:64px; --h-kit:84px; --h-pack:94px;}
  }
  @media (max-height:628px){
    body{padding:4px 10px;}
    #game{
      /* THE PAPERS HOLD SIX ROWS since Mastery joined them, and the row is paid
         for out of the Knacks list rather than out of the page: measured at this
         size the Knacks box stood at 88 against 46 of content, forty-two pixels of
         slack, while the papers overflowed by six and the page went a pixel over
         920x600 with a boon standing. The Knacks give up ten and the papers take
         eight, which leaves the page two inside the gate rather than one outside. */
      --h-traits:110px; --h-stats:106px; --h-spells:78px;
      --h-pack:126px; --h-chron:110px; --h-notice:110px;
    }
    #log{height:46px;}
    #game.hasboon:not(.logbig) #log{height:25px;}
    #game.logbig #log{height:174px;}
    /* the pair at this step takes ten of these off the prose besides: the rule
       stands with the rest of what a second hand costs, above. */
    #game.logbig{
      --h-traits:74px; --h-stats:70px; --h-spells:52px;
      --h-kit:84px; --h-pack:74px; --h-chron:56px; --h-notice:56px;
    }
  }
  /* fullscreen: the window sits centred on the desktop, like it should */
  @media (min-height:820px){ body{align-items:center;} }

  /* a phone: the enrolment column shortens so the ledger is signed with
     less scrolling, and the margins narrow to give the window the width */
  @media (max-width:700px){
    body{padding:8px;}
    .radio-list{max-height:126px;}
    .crebtns button{flex:1 1 auto;}
  }
  /* a touch screen: fields hold 16px type, for iOS Safari zooms the whole
     page upon focusing anything smaller, and strands the layout mid-zoom */
  @media (pointer:coarse){
    input[type=text], textarea{font-size:16px;}
  }
  /* a phone in the single column: the sheet lists give up their inner
     scroll and stand at full height, so a swipe lands anywhere upon the
     page and moves the page. The little scrollers were eating the touch
     on itch: a thumb upon Spells or Inventory scrolled the list a row and
     the page not at all, and the top of the sheet sat out of reach. The
     log keeps its own scroll; it holds 140 lines, and it sits last upon
     the page, below everything it could block. */
  @media (max-width:780px) and (pointer:coarse){
    .listview, #game.logbig .listview{height:auto; max-height:none; overflow-y:visible;}
    table.lv th{position:static;}
    .radio-list{max-height:none;}
  }

  /* the desktop build: there the game is the window, not a window upon a
     desktop. Windows draws the frame already, so the wallpaper, the margins
     and the 960px column come off and the sheet sits flush in the client
     area, edge to edge. In a browser (itch, the open page) nothing changes:
     the class is only set when the game is served from file:. The folded
     strip keeps its frame and its margin, for there the real window is
     larger than the strip and the desk shows around it. */
  html.app body{background:var(--silver); padding:0; align-items:flex-start;}
  html.app #creator, html.app #game:not(.mini){
    max-width:none; border:none; padding:0; box-shadow:none;
  }
  /* The strip is as tall as its contents and no taller. The rules below stretch
     the unfolded window to the height of the desk (html.app body, align-items),
     and a folded window took that stretch too: 560 wide by the whole screen
     down, most of it empty silver. A flex item may refuse the stretch itself,
     which is cheaper than teaching the body about the fold. */
  html.app #game.mini{margin:16px auto; align-self:flex-start;}

  /* The PC build has the shell draw no frame at all (desktop/main.js), so this
     window's own title bar is the window's title bar: the handle it is dragged
     by, and the three buttons in its corner. Only the two window bars take the
     drag. A dialog's bar looks the same and must not carry the whole window off
     with it, and a button inside a drag region never receives the click. */
  html.app #game > .titlebar, html.app #creator > .titlebar{-webkit-app-region:drag;}
  html.app #game > .titlebar .tbtn, html.app #creator > .titlebar .tbtn{-webkit-app-region:no-drag;}
  html.app [data-win="close"]{cursor:pointer;}
  /* Folded and frameless, the strip is the whole of the window, so nothing may
     stand around it: not the auto margin above, and not the body padding the
     embed steps set (which is what would otherwise put a grey band under a
     strip whose window was sized to the strip). */
  html.app.folded body{padding:0;}
  html.app.folded #game.mini{margin:0;}
  /* and the sheet fills the window's height as well as its width. The client
     area of a desktop window is whatever the player has dragged it to, and the
     sheet's own height is set by its lists, so a tall window left a band of
     bare grey under the log. The log takes that room: it is the one panel that
     is never finished and always has more to show. Below its old 108px it
     never shrinks, so a short window reads exactly as it did.
     Browser and itch are untouched; the class is only set from file:. */
  /* Only on a window with room to spare. Below 760px of height the sheet has
     its own rules that shrink the log (the max-height blocks above), and they
     exist because at 960x660 there is no spare room at all: a floor of 108px
     fought them and pushed the hireling panel past the bottom of itch's embed.
     A window that short has no bare grey to fill in the first place. */
  @media (min-height:760px){
    html.app body{align-items:stretch;}
    html.app #game:not(.mini){min-height:100%; display:flex; flex-direction:column;}
    html.app #game:not(.mini) > .client{flex:1 1 auto; display:flex; flex-direction:column; min-height:0;}
    html.app #game:not(.mini) .logwrap{flex:1 1 auto; display:flex; flex-direction:column; min-height:0;}
    html.app #game:not(.mini) #log{flex:1 1 auto; height:auto; min-height:108px;}
    html.app #game:not(.mini).logbig #log{min-height:216px;}
    /* AND THE STANDING WEATHER CELL IS PAID OUT OF THE FLOOR (v1.6.4). The
       floors above were set when the boon row came and went; the weather cell
       made the row a fixture, so a window sized to the floor stood 21 pixels
       over its own height with nothing in it a player had turned on. The row's
       height comes off the floor, which is the trade the shrink ladder below
       760 has always made, and the fill above the floor is untouched. */
    html.app #game.hasboon:not(.mini):not(.logbig) #log{min-height:87px;}
    html.app #game.hasboon:not(.mini).logbig #log{min-height:195px;}
  }
  /* A shorter window has bare grey under the log too, and the commonest
     laptop screen there is shows the most of it: 43px at 1280x720, 23px at
     1024x700, 21px at 960x660. The guard above shut all of them out because
     of the floor, not the fill: 108px of log fought the shrink rules and
     pushed the hireling panel past the bottom of itch's embed. So below 760
     the log takes the spare room with no floor of its own. Its tiered height
     stands as the flex basis and it only ever grows, never shrinks, so every
     short window reads as it did with the grey turned into log. */
  @media (max-height:759px){
    html.app body{align-items:stretch;}
    html.app #game:not(.mini){min-height:100%; display:flex; flex-direction:column;}
    html.app #game:not(.mini) > .client{flex:1 1 auto; display:flex; flex-direction:column; min-height:0;}
    html.app #game:not(.mini) .logwrap{flex:1 1 auto; display:flex; flex-direction:column; min-height:0;}
    html.app #game:not(.mini) #log{flex:1 0 auto; min-height:0;}
  }
  /* the ledger keeps its 700px column (four narrow lists want no more), so
     in a window this wide it stands in the middle of the client area rather
     than in the top corner with the room empty beside it. */
  html.app #creator{min-height:100%; display:flex; flex-direction:column;}
  html.app #creator .client{margin:auto; width:100%;}

  .overlay{position:fixed; inset:0; background:var(--scrim); z-index:70; display:flex; align-items:center; justify-content:center; padding:14px; overflow-y:auto; -webkit-overflow-scrolling:touch;}
  .overlay .win{max-width:480px; margin:auto;} /* auto margins centre, yet let a tall dialog scroll from its top */
  /* Options is ten groups long and had grown to 764px, half again the height
     of the next longest window in the game and 72px past the bottom of a
     1280x720 screen, so the last two groups could only be reached by scrolling
     a window that gives no sign it scrolls. On any screen with the width for
     it the groups stand in two columns instead, which is what a Win9x settings
     sheet did with tabs and what a single sheet can do without them. A group
     is never split down the middle, and the OK button keeps the full width.
     A narrow screen is untouched: one column, as before. */
  @media (min-width:600px){
    #optionsdlg .win{max-width:700px;}
    #optionsdlg .client{columns:2; column-gap:10px;}
    #optionsdlg .client > fieldset{break-inside:avoid; -webkit-column-break-inside:avoid;
                                   page-break-inside:avoid; margin-top:0; margin-bottom:8px;}
    #optionsdlg .client > .dlgbtns{column-span:all; margin-top:2px;}
  }
  /* ---------- AND TWO COLUMNS WERE NOT ENOUGH EITHER (v2.6.1) ----------
     The note above was written against a 1280x720 screen and the sheet still
     stood 764 tall on one: two columns at 700 wide took 44 pixels more than the
     screen had, so the last group and the OK button were off the bottom on the
     very screen the change was made for. Measured across the sheet's thirteen
     groups: 700/2 is 764, 700/3 is 704, 900/2 is 686 and 900/3 is 601. Where
     there is width for it the sheet takes a third column and 200 more pixels of
     width, which puts a 1280x720 at 601 and a 960x660 at 601 -- inside both,
     with the room to spare the file asks for, and still one sheet without
     tabs. */
  @media (min-width:900px){
    #optionsdlg .win{max-width:900px;}
    #optionsdlg .client{columns:3;}
  }

  /* The collection bar: the same blocked trough the papers use, stood over a
     window whose list is a thing to fill. It is the setup bar of a Win9x
     install, which is what a collection at 41 of 200 wants to look like. */
  .collbar{margin:0 0 6px;}
  /* The tally sheet: one ruled row to a collection, the name and the figure
     upon the head of it and the trough beneath, so the whole of what the
     Guild has you filling is read down one column. */
  .collrow{padding:4px 4px 7px;}
  .collrow + .collrow{border-top:1px solid var(--rule2);}
  .collhead{display:flex; justify-content:space-between; gap:8px; margin-bottom:2px;}
  .collhead .collfig{font-weight:bold; color:var(--navyink); white-space:nowrap;}
  .collnote{color:var(--dim); margin:1px 0 0;}
  .dlgscroll{max-height:280px; overflow-y:auto;}
  .dlgscroll .ach{padding:3px 4px; border-bottom:1px solid var(--rule2);}
  .dlgscroll .ach.locked{color:var(--dim4);}
  .dlgscroll .ach b{display:block;}
  /* the Glossary's search bar, which is the whole of the window's own style:
     the list beneath it is the patch window's .sunken.dlgscroll and its rows
     are .ach, so sixteen definitions cost three rules */
  .glossbar{margin:0 0 6px;}
  .glossbar input{width:100%; box-sizing:border-box;}
  .dlgscroll .ach.glossnone{color:var(--dim); font-style:italic;}
  /* the patch-note category head: New, Adjustments, Fixes */
  .dlgscroll .ach .patchcat{font-weight:bold; color:var(--navyink); margin:6px 0 1px;}
  /* the patch window: the newest release stands open, the rest are one line
     apiece with a Win9x tree knot before the version, opened on a click */
  .dlgscroll .ach .patchline{margin-top:1px;}
  .patchfold .patchhead{cursor:pointer;}
  .patchfold .patchhead b::before{content:"\002b\00a0";}   /* + */
  .patchfold.open .patchhead b::before{content:"\2212\00a0";}  /* minus */
  .patchfold .patchbody{display:none;}
  .patchfold.open .patchbody{display:block;}
  /* THE TREE, drawn flat. Three columns abreast, a talent to a box, the rank in
     the corner the way the reference puts it. A box that cannot be taken yet is
     dimmed rather than hidden, because the shape of what is coming is half of
     what a tree is for. */
  /* the button stands the row's whole height and sits flush right, so the line
     reads as one thing rather than as a label with a chip loose upon it */
  .treeplus{flex:0 0 auto; align-self:stretch; margin:0; padding:0 6px;
    font-size:11px; line-height:1;}
  /* and when a point is owed it says the figure in the chrome's own blue */
  .treeplus.due{font-weight:bold; color:#000080;}
  html.dark .treeplus.due{color:#b9c6ff;}
  .treespacer{flex:1 1 auto;}
  #treereset{margin-right:auto;}
  /* ---------- THE TREE'S TWO PANES (v1.6.6) ----------
     The window was three columns of glyphs 300px wide, and every figure in it
     lived in hover text: what the column stood at, what the ranks had bought,
     what the move actually costs. Read with the help cursor armed it came out
     as a wall of prose at the foot of the screen, which is the one shape a
     summary must not take. So the figures come out of the tips and onto a
     permanent pane beside the grid, on the shape the Armoury already keeps for
     its book and its forge (.armcols): the left pane is untouched and fixed at
     the three columns' own width, and the right takes the rest.

     The width is a rule here rather than the inline style the dialog carried,
     because a second pane is a thing the stylesheet should be able to see. The
     capture scripts clip `#treedlg .win` and go on clipping it. */
  #treedlg .win{max-width:600px;}
  .treepanes{display:flex; align-items:stretch; gap:6px;}
  /* the three columns are 82px apiece with two 6px gutters, which is 258, and
     the pane is set four past that so a column's own border and the grid's
     centring have somewhere to sit. It is never squeezed by the summary. */
  .treemain{flex:0 0 262px; width:262px; min-width:0;}
  /* AND THE SUMMARY DRIVES NO HEIGHT OF ITS OWN. The grid is the tall thing in
     this window and the pane stretches to it (.treepanes); where the summary
     is the longer of the two it scrolls, on the same cut every other list in
     the file takes. */
  .treesum{flex:1 1 auto; min-width:0; overflow-y:auto; max-height:340px;
    padding:0 0 2px; font-size:11px;}
  .treesum .besthead:first-child{margin-top:0;}
  /* a figure the draft has moved and the pen has not yet kept, marked the way
     the column head marks it: the tree's own blue, which is what the window
     already uses for a figure that is standing on staged points */
  .treesum .kv b.drafted{color:#000080;}
  html.dark .treesum .kv b.drafted{color:#b9c6ff;}
  /* AND A PHONE HAS NO SECOND COLUMN TO GIVE. The rule above is an id and so
     outranks the 480px every overlay is held to, at every width; left alone
     that would squeeze the summary to a finger's width beside a grid that
     cannot shrink. Below the fold the two panes stack instead -- the grid
     first, exactly as it stood before this release, and the figures under it. */
  @media (max-width:560px){
    #treedlg .win{max-width:480px;}
    .treepanes{flex-direction:column;}
    .treemain{flex:0 0 auto; width:auto;}
    .treesum{max-height:220px;}
  }
  #treeleft{font-size:11px; margin:0 0 4px; display:flex; align-items:center; gap:6px;}
  .treebar{flex:1 1 auto; height:8px; border:1px solid var(--ink); background:var(--paper);
    display:block; min-width:40px;}
  .treefill{display:block; height:100%; background:#000080;}
  .treeleftn{flex:0 0 auto; color:var(--dim); white-space:nowrap;}
  #helptip .req{display:block; margin-top:3px; color:#a00000; font-weight:bold;}
  html.dark #helptip .req{color:#ff7b7b;}
  .treecols{display:flex; gap:6px; margin:6px 0; justify-content:center;}
  .treecol{flex:0 0 82px; width:82px; text-align:center;}
  /* THE HEAD OF A COLUMN (v2.0.2). The window shipped with none: three stacks
     of glyphs, no names on them, and the only way to learn what a column did
     was to rest the pointer upon all fifteen tiles in turn. The head carries
     the column's name and, under it, WHAT THE ABILITY DOES RIGHT NOW in that
     column's own unit -- which is the figure the ranks are moving, so a rank
     staged in the draft moves it before the player has paid for it. */
  .treehead{font-size:10px; line-height:11px; margin:0 0 4px; cursor:help;}
  .treehead .thn{display:block; font-weight:bold;}
  .treehead .thv{display:block; font-size:11px; font-weight:bold; color:#000080;
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis;}
  html.dark .treehead .thv{color:#b9c6ff;}
  /* and the column's own tally, so the gates below read as a price rather than
     as an accident: four rows deep the gate asks for ten in THIS column */
  .treehead .thc{display:block; font-size:9px; line-height:10px; color:var(--dim);}
  /* a tile and nothing else: the glyph, the rank in its corner, and the slip
     carrying the name and the figure for whoever rests the pointer on it */
  .treenode{position:relative; display:inline-block; border:1px solid var(--ink);
    background:var(--paper); padding:2px; margin:0 0 2px; cursor:pointer; line-height:0;}
  /* THE GLYPH TAKES ITS COLUMN'S COLOUR ONCE IT IS BOUGHT (v2.0.3). The figure
     is drawn in currentColor, so the whole of the rule is which colour the box
     hands down: the ink until a point stands in the talent, the column's own
     from the first point, and the column's brighter from the last. .full is
     written after .taken because a full talent is also a taken one and the two
     rules weigh the same. */
  .treenode .tg{width:30px; height:30px; display:block; color:var(--ink);}
  .treecol.c-weight .treenode.taken .tg{color:var(--tree-weight);}
  .treecol.c-weight .treenode.full  .tg{color:var(--tree-weight-lit);}
  .treecol.c-reach  .treenode.taken .tg{color:var(--tree-reach);}
  .treecol.c-reach  .treenode.full  .tg{color:var(--tree-reach-lit);}
  .treecol.c-thrift .treenode.taken .tg{color:var(--tree-thrift);}
  .treecol.c-thrift .treenode.full  .tg{color:var(--tree-thrift-lit);}
  .treenode.locked .tg{filter:grayscale(1);}
  .treenode.shut{cursor:default;}
  .treenode.locked{opacity:0.45;}
  .treenode.taken{background:var(--headrow);}
  /* THE FRAME IS A THIRD READING OF THE SAME COLUMN COLOUR (v2.0.3). One hue to
     a column and the THICKNESS says the state: a hairline of ink where nothing
     can be done, two of the column's own where a point may be spent this
     moment, three of its brighter where the talent is taken whole. The frame
     that flagged a spendable point was a flat green and read as a fourth
     meaning; it is the column's colour now, so a player scanning for somewhere
     to spend follows one colour rather than two.
     The border grows OUTWARD: the sheet sets border-box on everything, which
     would have the frame eat into the white field the figure stands on, and a
     bought talent would show a smaller picture than an unbought one. */
  .treenode{box-sizing:content-box;}
  .treenode.can {border:2px solid var(--tree-weight);}
  .treenode.full{border:3px solid var(--tree-weight-lit);}
  .treecol.c-weight .treenode.can {border-color:var(--tree-weight);}
  .treecol.c-weight .treenode.full{border-color:var(--tree-weight-lit);}
  .treecol.c-reach  .treenode.can {border-color:var(--tree-reach);}
  .treecol.c-reach  .treenode.full{border-color:var(--tree-reach-lit);}
  .treecol.c-thrift .treenode.can {border-color:var(--tree-thrift);}
  .treecol.c-thrift .treenode.full{border-color:var(--tree-thrift-lit);}
  .treenode .tn{flex:1 1 auto; min-width:0; font-weight:bold; font-size:11px;
    line-height:12px; overflow-wrap:break-word;}
  /* the figure wraps rather than running out of the box: a talent's line is the
     thing a player is choosing on, so it is never the part that gets cut */
  .treenode .tv{display:block; font-size:10px; color:var(--dim); line-height:12px;
    overflow-wrap:break-word;}
  .treenode .tr{position:absolute; right:0; bottom:0; padding:0 2px;
    background:var(--ink); color:var(--paper); font-size:9px; line-height:10px;
    font-weight:bold; text-align:center; letter-spacing:-0.3px;}
  .treearrow{text-align:center; color:var(--dim); font-size:10px; line-height:8px; margin:0 0 3px;}
  .dlgbtns{display:flex; justify-content:flex-end; gap:6px; margin-top:8px;}
  #savedl{margin-right:auto;}   /* the file stands off on its own, away from OK */
  /* ---- the Long Charter ---- */
  /* The window is cut to the screen it stands on, and the wall takes whatever
     is left over.

     Reported: the Skill Tree could not be shut on a phone. The window was
     taller than the screen: a phone turned on its side, a short one, or any
     browser with its address bar showing, since 100vh counts the room the bar
     is standing in and the screen does not. So the overlay scrolled, and
     opening the window put the focus upon OK at its foot, which carried the
     title bar and its × off the top. A finger could not scroll back, because
     the wall takes the touch to be dragged (touch-action:none) and the wall is
     most of the screen. What was left was a 23px button against the bottom
     edge, under the phone's own bar as often as not.

     So: the window is at most as tall as the small viewport (the one with the
     address bar showing), the wall shrinks to fit inside it, and the title bar
     sticks to the top of the overlay if ever the window is taller still. */
  #chartdlg .win{max-width:1000px; display:flex; flex-direction:column;
                 max-height:calc(100vh / var(--ui-zoom,1) - 28px);}
  @supports (height:100svh){
    #chartdlg .win{max-height:calc(100svh / var(--ui-zoom,1) - 28px);}
  }
  /* the five Guild windows stand at one family of widths. a bare px figure
     overflows at the 2.0 Size rung, so every one is divided by the zoom. */
  #guilddlg .win{max-width:min(620px, calc(96vw / var(--ui-zoom,1)));}
  #counterdlg .win{max-width:min(560px, calc(96vw / var(--ui-zoom,1)));}
  #honourdlg .win{max-width:min(560px, calc(96vw / var(--ui-zoom,1)));}
  #namesdlg .win{max-width:min(560px, calc(96vw / var(--ui-zoom,1)));}
  #featsdlg .win{max-width:min(560px, calc(96vw / var(--ui-zoom,1)));}
  #guilddlg #guildlist{max-height:300px;}
  /* The book of benefactors stands in a panel down the right of the Guildhouse
     rather than at the foot of the works, and a bevelled toggle beside the
     summary opens it. It is shut by default, so the works keep the full width.
     The two are a wrapping flex row rather than a media query: the Size rungs
     zoom the page and a media query does not move with them, so the panel
     drops beneath the works when the room runs short, at 2.0 and 3.0 alike and
     on a phone. */
  .guildhead{display:flex; align-items:flex-start; gap:6px; margin-bottom:6px;}
  .guildhead p{flex:1 1 auto; margin:0;}
  .guildhead button{flex:0 0 auto;}
  /* the toggle wears the pressed bevel while the panel stands open, as Make
     Camp does while the descent is halted */
  #guild-benef.open{box-shadow:inset 1px 1px 0 var(--lo), inset -1px -1px 0 var(--hi);}
  /* the two boxes take one height and stand upon one line, as a pair of Win9x
     lists does; the shorter of them carries the empty room rather than leaving
     a step between their two feet */
  .guildbody{display:flex; flex-wrap:wrap; gap:6px; align-items:stretch;}
  #guilddlg #guildlist{flex:3 1 300px; min-width:0;}
  #guilddlg #guildbenef{flex:1 1 190px; min-width:0; max-height:300px;}
  #counterdlg #countershop{max-height:340px;}
  /* twelve rows, each of them three or four lines: the board takes the shop's
     height rather than the plain .dlgscroll cut */
  #featsdlg #featslist{max-height:340px;}
  /* #honourshop is a bare .sunken and not a .dlgscroll, so unlike the two
     above it takes its scrolling here or the rows below the cap cannot be
     reached at all. */
  #honourdlg #honourshop{max-height:320px; overflow-y:auto;}

  /* ---------- THE PLATE OF FIGURES ----------
     Two windows in this game quote a figure the player is about to act upon,
     and both quoted it from the middle of a paragraph: the Roll's standing, and
     the pension a retirement would pay. A player opening either one had to read
     a sentence to its end to find the number they had come for, and the
     retirement window quoted six of them in a single comma-list. Both now put
     the figures on a plate and fold the prose behind a disclosure, so what is
     being decided is read at a glance and the rules stand one click away.
     The plate is the Win9x group box the sheet already draws (fieldset plus
     .grouplabel), and the two windows share every rule below, because they are
     the same plate twice. */
  .keyfig{display:grid; grid-template-columns:1fr auto; row-gap:6px; column-gap:12px; align-items:center;}
  /* the figure the window exists to state, set at the size a headline takes */
  .keyfig .kfbig{font-size:17px; font-weight:bold; color:var(--navyink); text-align:right; line-height:1.15;}
  .keyfig .kfval{text-align:right; font-weight:bold;}
  .keyfig .kfnone{text-align:right; color:var(--mute);}
  /* what the thing in the row is worth, worn as the bevelled chip a Win9x
     sheet states a figure in that cannot be typed into */
  .kfchip{
    background:var(--silver); color:var(--navyink); font-weight:bold;
    padding:0 4px; margin-left:5px; white-space:nowrap;
    box-shadow:inset 1px 1px 0 var(--lo), inset -1px -1px 0 var(--hi);
  }
  /* a count against a ceiling, drawn as the blocky Win9x gauge. "2 of 8" in
     the middle of a sentence is a figure to be parsed; eight cells with two
     filled is a figure to be seen, and the count stands beside it for the
     reader who wants it exactly. */
  .slotrow{display:flex; align-items:center; gap:8px; margin-top:9px;}
  .slotbar{
    flex:1; display:flex; gap:1px; height:12px; padding:1px; overflow:hidden;
    background:var(--lo); box-shadow:inset 1px 1px 0 var(--dark), inset -1px -1px 0 var(--hi);
  }
  .slotbar i{flex:1;}
  .slotbar i.on{background:var(--navyink);}
  .slotrow .slotfig{font-weight:bold;}
  /* the prose the plate replaced, folded away behind the one control in this
     sheet drawn as a link: it opens a paragraph and does nothing else, and a
     bevelled button would promise an action */
  /* the one figure upon the papers a player may set: which of the three things
     the floor shows them they would rather be shown. Underlined like a
     disclosure and inline like the value it stands in for. */
  .wishpick{background:none; border:0; box-shadow:none; padding:0; font:inherit;
    color:var(--navyink); text-decoration:underline; cursor:pointer;}
  .wishpick:hover{text-decoration:none;}
  .wishpick:active{box-shadow:none;}
  .disclose{
    display:block; background:none; border:0; box-shadow:none; padding:0;
    margin-top:9px; font:inherit;
    color:var(--navyink); text-decoration:underline; cursor:pointer; text-align:left;
  }
  .disclose:active{box-shadow:none;}
  .disclose:hover{text-decoration:none;}
  .disclose .darr{text-decoration:none; display:inline-block;}
  .disclosebody{
    margin-top:6px; padding:6px 8px; line-height:1.5; color:var(--dim2);
    background:var(--paper);
    box-shadow:inset 1px 1px 0 var(--lo), inset -1px -1px 0 var(--hi);
  }
  /* THE TITLE JUST ENTERED, over the plate. The toast that announces a title is
     long gone by the time the player opens this window to spend against it, so
     the Roll says it once more, in the tooltip the rest of the sheet uses, and
     only for a title this window has not shown before (LEGACY.titleSeen). */
  .titletip{
    position:relative; background:var(--tip); border:1px solid var(--tipedge);
    color:var(--ink); padding:6px 9px; line-height:1.4; margin-bottom:11px;
    box-shadow:2px 2px 5px rgba(0,0,0,.3); animation:tipin .22s ease-out;
  }
  .titletip::before, .titletip::after{content:""; position:absolute; width:0; height:0;}
  .titletip::before{bottom:-9px; left:22px;
    border-left:8px solid transparent; border-right:8px solid transparent; border-top:9px solid var(--tipedge);}
  .titletip::after{bottom:-7px; left:23px;
    border-left:7px solid transparent; border-right:7px solid transparent; border-top:8px solid var(--tip);}
  @keyframes tipin{from{transform:translateY(-6px); opacity:0;} to{transform:none; opacity:1;}}


  /* THE STANDING ORDERS' rows (v1.6.5): name, figure, pen, door, one line
     apiece. The figure is the one part with give -- it thins to an ellipsis
     before the pen or the door wraps, since a row that wraps reads as two
     offices. The pen a player holds themselves reads in the gold the file
     marks a thing bought and kept with; the Guild's reads dim, being the
     resting state of a game that plays itself. */
  .buildrow{display:flex; align-items:center; gap:8px; padding:5px 8px; border-bottom:1px solid var(--silver);}
  .buildrow:last-child{border-bottom:0;}
  .buildname{font-weight:bold; white-space:nowrap;}
  .buildfig{flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--navyink); font-size:11px;}
  .buildpen{font-size:10px; color:var(--dim); white-space:nowrap; cursor:pointer;}
  .buildpen.own{color:var(--goldink); font-weight:bold;}
  .buildpen input{margin:0 3px 0 0; vertical-align:-2px; cursor:pointer;}
  .buildrow button{white-space:nowrap;}

  /* RANK CHOICES (v1.6.8): four fixed columns like a proficiency track, with
     three roads stacked inside each. Narrow screens scroll the track alone;
     the title, Auto box and OK button stay outside it. */
  #rankdlg .rankwin{width:820px; max-width:min(820px, calc(96vw / var(--ui-zoom,1)));
    max-height:calc(100svh / var(--ui-zoom,1) - 28px); display:flex; flex-direction:column;}
  .rankclient{display:flex; flex-direction:column; min-height:0;}
  .rankprogress{display:grid; grid-template-columns:repeat(4,minmax(0,1fr));
    border:1px solid var(--dark); margin:5px 0; background:var(--lo); gap:1px;}
  .rankseg{display:block; padding:3px 4px; text-align:center; background:var(--silver);
    color:var(--mute); font-size:10px; font-weight:bold;}
  .rankseg.taken{background:var(--navy); color:#fff;}
  .rankseg.pending{background:var(--chip); color:var(--navyink);}
  .rankscroll{overflow:auto; min-height:0; padding:6px;}
  .rankstages{display:grid; grid-template-columns:repeat(4,minmax(150px,1fr));
    gap:6px; min-width:650px;}
  .rankstage{border-left:1px solid var(--lo); border-right:1px solid var(--hi);
    padding:0 5px 5px;}
  .rankstage h3{text-align:center; font-size:11px; padding:3px 2px 5px;}
  .rankstage.locked h3{color:var(--mute);}
  .rankcards{display:flex; flex-direction:column; gap:5px;}
  .rankcard{width:100%; min-height:72px; padding:6px; text-align:left;
    display:grid; grid-template-columns:32px 1fr; gap:6px; align-items:center;}
  .rankcardcopy{display:block; min-width:0;}
  .rankcardcopy b{display:block; margin-bottom:4px;}
  .rankcardcopy small{display:block; font-size:10px; line-height:1.25; font-weight:normal;}
  .rankmark{width:30px; height:30px; display:flex; align-items:center; justify-content:center;
    border:1px solid var(--dark); box-shadow:inset 1px 1px 0 var(--hi), inset -1px -1px 0 var(--lo);
    background:var(--headrow); color:var(--ink); font-size:9px; font-weight:bold;}
  .rankmark-offence{color:var(--illink);}
  .rankmark-defence{color:var(--navyink);}
  .rankmark-mastery{color:var(--goldink);}
  .rankcard.pending{background:var(--chip); border-color:var(--navyink);}
  .rankcard.selected:disabled{background:var(--navy); color:#fff; text-shadow:none;
    box-shadow:inset 2px 2px 0 var(--navy2), inset -2px -2px 0 var(--dark);}
  .rankcard.selected .rankmark{background:var(--silver); color:var(--ink);}
  .rankcard.shut{opacity:.42;}
  .rankcard.locked{opacity:.55;}
  .rankfoot{display:flex; align-items:flex-end; justify-content:space-between; gap:8px; padding-top:6px;}
  .rankfoot .dlgbtns{margin-top:0; flex:0 0 auto;}
  .rankplus{padding:0; width:17px; height:17px; line-height:13px; margin-left:6px;
    color:var(--navyink); font-weight:bold; vertical-align:1px;}
  @media (max-width:560px){
    .rankfoot{align-items:flex-start;}
    .rankcard{min-height:68px;}
  }
  /* ---------- THE PENSION PLATE (the retirement card) ---------- */
  /* the card is 300px and the plate is the whole of it: the buttons keep their
     own gap and the group box wants none of its own beneath it */
  #fatetext fieldset{margin-bottom:0;}
  .pensionwho{margin-bottom:8px; color:var(--dim2);}
  /* the one figure the window is opened to read, on the ground a Win9x sheet
     keeps for a selected row */
  .pensionsum{
    position:relative; overflow:hidden; text-align:center; padding:9px;
    background:var(--navy); box-shadow:inset 1px 1px 0 var(--dark), inset -1px -1px 0 #3d5ca6;
  }
  .pensionsum b{display:block; font-size:21px; color:#fff; line-height:1;}
  .pensionsum small{display:block; font-size:9.5px; color:#d8e0f7; margin-top:3px;}
  .pensionrows{margin-top:8px; padding:5px 8px; display:grid; grid-template-columns:1fr auto; row-gap:3px;}
  .pensionrows span:nth-child(even){text-align:right; font-weight:bold;}
  .pensionnow{display:flex; justify-content:space-between; gap:8px; margin-top:9px;}
  .pensionnow b{color:var(--navyink);}
  .pensionnote{margin-top:8px; line-height:1.45; color:var(--dim2);}
  /* ten scraps of paper over the figure. This is the one window in the game
     that closes a chronicle for good, and it is the only one that gets them. */
  .conf{
    position:absolute; top:-9px; width:4px; height:7px;
    animation:conffall 2.4s linear infinite;
  }
  @keyframes conffall{
    0%{transform:translateY(0) rotate(0); opacity:0;}
    12%{opacity:.95;}
    100%{transform:translateY(62px) rotate(560deg); opacity:0;}
  }
  @media (prefers-reduced-motion: reduce){ .conf{display:none;} .titletip{animation:none;} }
  body.stillmotion .conf{display:none;}
  body.stillmotion .titletip{animation:none;}
  @media (max-height:700px){ #guilddlg #guildlist{max-height:200px;} #guilddlg #guildbenef{max-height:200px;}
                             #featsdlg #featslist{max-height:200px;} }
  #chartdlg .win > .client{flex:1 1 auto; display:flex; flex-direction:column; min-height:0;
                           overflow-y:auto; overscroll-behavior:contain;}
  #chartdlg .win > .titlebar{position:sticky; top:0; z-index:3;}
  /* every part of the window stands at its own height; the wall alone gives */
  #chartdlg .win > .client > *{flex:0 0 auto;}
  /* THE ROW OWNS THE HEIGHT THE WRAP OWNED (v1.6.6). The wrap was the client's
     one flexible child and the figures panel now stands beside it, so the pane
     row takes that office and the wrap fills it. Everything the height rules
     below said about the wall they now say about the row, which keeps the one
     thing that matters: the wall is still the part of this window that gives
     when the screen is short. */
  #chartdlg .win > .client > .chartpanes{flex:1 1 auto;}
  /* And on a screen so small that even the shrunken wall leaves nothing over,
     what will not fit scrolls within the window rather than out of it, and the
     two ways out are pinned to the ends: the title bar to the top, the OK
     button to the foot. Whatever else is off the screen, neither of them is. */
  #chartdlg .win > .client > .dlgbtns{position:sticky; bottom:0; z-index:2;
                                      background:var(--silver); padding-top:2px;}
  .chartbar{display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin-bottom:4px;}
  .chartbar label{display:inline-flex; align-items:center; gap:3px; cursor:pointer;}
  .chartbar .chartsp{margin-left:auto; display:inline-flex; align-items:center; gap:4px;}
  .chartbar .chartpen{font-weight:bold;}
  .chartfig b{color:var(--navyink);}
  /* The height is the wrap's now and the canvas fills it, so the wall is one
     flexible item in the window's column: it stands at the height below when
     there is room for it and gives that room up when there is not. */
  /* THE HEIGHT IS THE WHOLE OF THE FIT (v2.3.1). Measured at four screen
     sizes, the fitting zoom is bound by the height at every one of them and by
     the width at none: at 1366x768 the wall came out 308px across in a canvas
     980 wide, so two thirds of the sheet was bare paper and the chart of 2,111
     marks was squeezed into the other third. A round chart in a wide frame
     cannot fill the corners, but it should not be a third of the frame either.
     The figures here are what the window can actually spare -- the wrap is a
     flexible item with a floor, so it takes this where there is room and gives
     it back where there is not, which is what the note above already said it
     was for. It was simply asking for too little. */
  .chartpanes{display:flex; align-items:stretch; gap:6px;
              height:620px; min-height:120px;}
  .chartwrap{position:relative; padding:0; overflow:hidden; background:var(--paper);
             flex:1 1 auto; min-width:0; height:100%;}
  /* ---------- THE FIGURES, BESIDE THE WALL (v1.6.6) ----------
     The charter in figures was a comma-joined paragraph in the 72px strip
     under the wall, which on a deep charter is forty levers of prose in a box
     three lines tall, and it stood only while nothing was selected. It is a
     column of rows now, on the same two-pane shape the Armoury and the
     Upgrades window keep. The width is what the list needs and not a share of
     anything: the wall takes the rest, and the canvas reads its own box
     (chartCanvasSize) so the fitting zoom follows it without being told. */
  .chartsum{flex:0 0 250px; width:250px; height:100%; overflow-y:auto;
            padding:0 0 2px; font-size:11px;}
  .chartsum .ci-ill{color:var(--illink);}
  /* a lever's row carries the lexicon's sentence and no second figure beside
     it (see renderChartSum), so it takes the whole width and wraps rather than
     leaving a bold column of numbers that state the lever in other units */
  .chartsum .kv.figline{display:block;}
  #chartcanvas{display:block; width:100%; height:100%; cursor:grab; touch-action:none;}
  @media (max-height:820px){ .chartpanes{height:470px;} }
  /* A phone held upright is nearly all height and the wall was given 400px of
     it, so the player saw a letterbox onto a chart of a thousand skills and
     had to drag it four times to cross one quarter. It takes the screen it is
     standing on instead. The toolbar, the reading strip and the two legend
     rows come to about 300px, so the wall gets the rest. */
  @media (max-width:560px) and (min-height:620px){
    /* This is the height asked for, not the height taken: the window is cut to
       the screen and the wall gives up whatever the rest of it needs, so the
       old floor of 240 here only served to push the OK button out of the
       window on a screen the 400 guessed wrong about. The floor is the base
       one, and 100vh may count the address bar's room without harm. */
    .chartpanes{height:calc(100vh / var(--ui-zoom,1) - 400px); max-height:760px;}
  }
  /* AND A PHONE HAS NO COLUMN TO SPARE. Two panes abreast on a 375px screen
     would leave the wall about 110px of width, which is the letterbox the rule
     above exists to stop. They stack instead: the wall keeps the height that
     rule gives it, and the figures take a box of their own beneath it, which
     is exactly where a phone reader already scrolls to find the strip. */
  @media (max-width:560px){
    .chartpanes{flex-direction:column; height:auto; min-height:0;}
    .chartwrap{flex:0 0 auto; height:calc(100vh / var(--ui-zoom,1) - 400px);
               min-height:120px; max-height:760px;}
    .chartsum{flex:0 0 auto; width:auto; height:auto; max-height:170px;}
  }
  @media (max-width:560px) and (max-height:619px){
    .chartwrap{height:300px;}
  }
  /* A phone on its side is nearly all width: 360px of height with the address
     bar in it, and the bars, the reading strip and the two legend rows want
     more than that between them before the wall is drawn at all. The legend
     names seven marks that the reading strip names again in words the moment
     one is pressed, so it stands down, and the strip keeps the two lines it
     needs. That leaves the wall about half the screen instead of nothing.
     The same holds of the narrowest phones upright, where the two legend rows
     wrap to four lines and take 76px of a screen that has none to give. */
  @media (max-height:520px), (max-width:340px){
    #chartdlg .chartlegend{display:none;}
  }
  #chartcanvas.dragging{cursor:grabbing;}
  /* a long press upon the wall is how a skill is taken, so the canvas must not
     answer it with a text selection or the platform's own press-and-hold menu */
  #chartcanvas{user-select:none; -webkit-user-select:none; -webkit-touch-callout:none;}
  /* the three bonuses of a mastery, one to a line and the whole width, so the
     figure is read before the pointer moves rather than after */
  .masterylist{margin:6px 0 2px;}
  .masterylist button{display:block; width:100%; text-align:left; margin:0 0 4px; padding:4px 7px;}
  .masterylist button .mo-fig{font-weight:bold;}
  .masterylist button .mo-held{color:var(--dim); font-weight:normal;}
  #masterynote .mn-dim{color:var(--dim);}
  .charthint{position:absolute; left:0; top:0; max-width:250px; padding:2px 5px;
    background:var(--tip); border:1px solid var(--tipedge); color:var(--ink);
    pointer-events:none; display:none; z-index:2;}
  .charthint b{display:block;}
  /* A fixed height, not a floor. Reading a skill rewrites this panel, and a
     panel that changes height moves the whole wall under the pointer: measured
     at 30px of travel on a phone and 6px on a desktop, which is enough to slide
     a neighbouring skill under a finger mid-press. The window is a fixed shape
     now and the panel scrolls within it. */
  .chartinfo{margin-top:4px; padding:4px 6px; height:72px; overflow-y:auto;}
  @media (max-width:560px){ .chartinfo{height:104px;} }
  /* and on a screen too short to spare it, two lines and its own scroll */
  @media (max-height:520px){ .chartinfo{height:52px;} }
  .chartinfo .ci-name{font-weight:bold; color:var(--navyink);}
  .chartinfo .ci-kind{color:var(--dim);}
  .chartinfo .ci-state{margin-top:2px;}
  .chartinfo .ci-ill{color:var(--illink);}
  .chartinfo button{margin:3px 4px 0 0; padding:1px 6px;}
  /* the colours of the wall, said once under it */
  .chartlegend .lg-note{color:var(--dim);}
  .chartlegend i.lg-fam{width:9px; height:9px; display:inline-block; vertical-align:-1px;}
  #chartamend.armed{font-weight:bold; color:var(--illink);}
  .chartlegend{display:flex; gap:12px; flex-wrap:wrap; margin-top:4px; color:var(--dim);}
  .chartlegend i{display:inline-block; width:8px; height:8px; margin-right:3px;
    vertical-align:-1px; background:var(--mute);}
  /* Every swatch is the shape the wall draws, which three of them were not: a
     plain skill and the ring upon an open one are drawn round on the sheet and
     were square here, and the arc of a country's progress was not in the legend
     at all. A legend that teaches a shape the chart does not use is worse than
     no legend, because the reader trusts it and then cannot find the thing. */
  .chartlegend .lg-clause{border-radius:50%;}
  .chartlegend .lg-seal{width:9px; height:9px; background:var(--faint);}
  .chartlegend .lg-writ{background:var(--illink); transform:rotate(45deg);}
  .chartlegend .lg-school{border-radius:50%; background:var(--paper); box-shadow:0 0 0 2px var(--faint);}
  .chartlegend .lg-signed{background:var(--navyink);}
  .chartlegend .lg-open{border-radius:50%; background:var(--paper); box-shadow:0 0 0 2px var(--navy2);}
  .chartlegend .lg-gauge{width:14px; height:4px; background:var(--navyink); vertical-align:1px;}
  /* the eight quarters, one to a line, each with its badge and a box */
  .focuslist{margin:6px 0; max-height:300px; overflow-y:auto;}
  .focuslist label{display:flex; align-items:center; gap:6px; padding:2px 3px; cursor:pointer;}
  .focuslist label:hover{background:var(--headrow);}
  .focuslist canvas{width:24px; height:24px; flex:0 0 24px;}
  .focuslist .fo-name{flex:1 1 auto;}
  .focuslist .fo-ord{color:var(--dim); font-weight:bold;}
  .focuslist .fo-oath{color:var(--illink);}
  /* the statusbar cell and the menu badge: the points waiting, where the eye
     already is. Both carry the same figure and neither shows at zero. */
  .chartcell{flex:0 0 auto; padding:3px 12px; font-size:12px; font-weight:bold; color:var(--navyink);}
  .chartcell.waiting{animation:chartnudge 1.6s steps(2) infinite;}
  @keyframes chartnudge{0%,49%{background:var(--silver);} 50%,100%{background:var(--chip);}}
  #chartbadge, #musterbadge{margin-left:4px; padding:0 4px; background:var(--chip);
    border:1px solid var(--navyink); color:var(--navyink); font-weight:bold;}
  @media (prefers-reduced-motion:reduce){ .chartcell.waiting{animation:none; background:var(--chip);} }
  /* A BOON IS A LABEL, NOT A SEAM (v2.1.0). The chips carried five pixels of
     side padding and none at all above or below, which at this type size left
     the name touching its own border on two edges; a slate of four read as one
     ruled line of small print. They take room now, and the name is set bold
     against a clock that is not: the name is the thing being read, and the
     seconds are the thing being glanced at. */
  .buffchip{display:inline-block; padding:1px 7px; margin:1px 0 1px 5px; background:var(--chip);
    border:1px solid var(--navyink); color:var(--navyink); cursor:help; font-weight:bold;}
  .buffchip .bt{font-weight:normal; opacity:.85;}
  /* a boon that carries an ill (any figure below par) reads in red, to tell
     it apart at a glance from the boons that only help */
  .buffchip.ill{background:var(--chipill); border-color:var(--illink); color:var(--illink);}
  /* THE WEATHER CELL, AND WHY IT IS NOT A CHIP. It carries the same metrics as
     a boon chip so the two sit level on one line, and it is dashed and unfilled
     so the eye can tell at once which of them is a thing that will run out and
     which is the standing sky. Every colour is a token, so the dark desk and
     the chrome desks answer it without a rule of their own. */
  .skycell{display:inline-block; padding:1px 7px; margin:1px 0 1px 5px; background:transparent;
    border:1px dashed var(--navyink); color:var(--navyink); cursor:help; font-weight:bold;}
  .skycell .sc{font-weight:normal; opacity:.85;}
  /* the red moon is the one sky that pays a rate, so it is drawn in the same
     red the chips use for an ill and ruled solid: it is the sky the player is
     meant to look up at */
  .skycell.moon{border-color:var(--illink); color:var(--illink); border-style:solid;}
  /* and a sky the court has raised out of another country reads in the gold the
     rest of the court's own work reads in */
  .skycell.court{border-color:var(--goldink); color:var(--goldink);}
  /* the sky and the boon it pays stand together, and the ordinary boons stand
     off from them: the gap is the whole of the grouping, since a second border
     or a rule would put a little box in the middle of the status bar */
  .skygroup{margin-right:14px;}
  #spellbody tr{cursor:help;} /* each spell carries the tutor's slip */
  /* the names a school is made of, standing beneath its row: dim and stepped
     in, with no event and no odds of their own, for a school is the thing
     that fires and these only feed it. The step is the whole of the signal;
     a border or a shade would rule the panel into eight little boxes. */
  #spellbody tr.trickrow td{color:var(--dim); padding-left:16px; max-width:none;}
  /* an act's head stands a step above a chapter's, the way the charter's
     archead stands above its rows: the same band, ruled off heavier */
  .bestacthead{background:var(--silver); font-weight:bold; letter-spacing:.4px;
    padding:3px 4px; border-top:1px solid var(--dark); border-bottom:1px solid var(--dark);}
  .bestacthead:first-child{border-top:none;}
  .besthead{background:var(--headrow); font-weight:bold; padding:2px 4px; border-bottom:1px solid var(--rule3);}
  /* the plate credit under a chapter head: the engraver's line, in the
     book's hand and a shade quieter than the lore */
  .bestplates{color:var(--dim2); font-size:10px; font-style:italic; line-height:1.35;
    padding:2px 6px; border-bottom:1px solid var(--rule);}
  .bestrow{display:flex; justify-content:space-between; padding:1px 6px; border-bottom:1px solid var(--rule);}
  .bestrow .m, .bestname .m, .armhead .m, .ach .m{color:#8a00b0; font-weight:bold;}
  /* the mark a beast leaves, in the same red the boon chips use for an ill, so
     the one colour means one thing everywhere: this will cost you something */
  .bestname .db{background:var(--chipill); border:1px solid var(--illink); color:var(--illink);
    font-weight:bold; font-size:0.82em; padding:0 4px; border-radius:2px; cursor:help; white-space:nowrap;}
  .kv{display:flex; justify-content:space-between; padding:2px 6px; border-bottom:1px solid var(--rule);}
  .shoprow{display:flex; align-items:center; gap:6px; padding:4px 2px; border-bottom:1px solid var(--rule2);}
  .shoprow .desc{flex:1;}
  .shoprow button{padding:2px 10px; flex:0 0 auto;}
  /* a Roll of Honour line reads as a head and a note, and the head carries the
     run of marks the Guildhouse draws a work's stages in: one square to a
     level, filled for what is bought and empty for what is not. The chip that
     stood here said "Lv 3/5" beside a button that already said what the next
     level costs, which is the state written twice in one row. */
  .shoprow .uphead{display:flex; align-items:baseline; gap:5px;}
  .shoprow .upnote{color:var(--dim3); margin-top:1px;}
  /* the board of feats says its state in two places and no more: the button
     names the one action the row offers, and a feat standing upon the papers
     is marked down its left edge. The chip beside the name was a third saying
     of the same thing and came off on the 10th of August, 2026.

     The mark is a hard 1px rule in the green the chrome already reads a pass
     in, and the row keeps the paper every other row stands on. A borderless
     full-bleed tint was drawn here first and taken off again: a pastel wash
     over a whole row is the modern web's success banner, which VOICE.md bars
     by name, and the tint was a colour invented for this one use. The name is
     bold upon every row of the board already, which is the second half of the
     state and wants no rule of its own.

     The rule is INSET from the scroller. Drawn at the row's own left edge it
     stood hard against the sunken border of the list, a coloured line touching
     a bevel, and read as part of the frame rather than as a mark upon the row.
     Every row on this board carries the two pixels of paper instead, and the
     marked row spends them on the margin and the rule, so a marked row and a
     plain one line up to the pixel and the green stands clear of the frame. */
  #featslist .shoprow{padding-left:4px;}
  #featslist .shoprow.featon{border-left:1px solid var(--okink); margin-left:2px; padding-left:1px;}
  /* the standing choice already made, upon the roster's row and the two beside
     it: the works' own filled square and plain text, never a disabled button.
     A disabled button on these same rows means "you cannot afford this", and
     one mark may not carry two meanings on one list. */
  .pickon{font-weight:bold; white-space:nowrap;}
  /* a line with nothing left to buy carries no button at all: the word stands
     in the green a passed check is read in, where the button stood */
  .shoprow .updone{color:var(--okink); font-weight:bold; font-size:10px; letter-spacing:.6px;
    flex:0 0 auto; padding:2px 10px;}

  /* the work row: the foe's plate stands beside the errand bar */
  .workrow{display:flex; gap:6px; margin-top:6px; align-items:stretch;}
  .workmain{flex:1; min-width:0;}
  .workmain .statusbar{margin-top:0;}
  /* THE WORK BAR IS THE BAR (v2.1.0). Every other trough on the sheet reports
     something standing; this one is the only thing in the window that moves on
     its own, and it stood at the same sixteen pixels as the encumbrance rule
     nobody watches. Four more, and the figure with it. */
  #bar-task{height:20px; margin-top:6px;}
  #bar-task .ptext{line-height:20px; font-size:12px;}
  #foeplate{
    flex:0 0 auto; width:216px; display:flex; gap:6px; padding:4px;
    border-top:1px solid var(--hi); border-left:1px solid var(--hi);
    border-bottom:1px solid var(--lo); border-right:1px solid var(--lo);
  }
  /* THE BEAST STANDS ITS FULL HEIGHT. The plate takes the height of the work
     row beside it, which is two rows and a bar and more once a boon is in
     force, and the drawing sat in a 38px square at the top of it with the rest
     of the plate left white: the one picture in the sheet that is drawn afresh
     for every fight, kept the size of an icon under a field of nothing. It is
     square and it stretches, so its width comes off its height, and the plate
     is given the thirty pixels that costs -- the name and the bar beside it
     have the room to spare, and the plate is a fixed width still, so a boon
     coming into force lifts the beast rather than shifting the row. */
  #foeart{align-self:stretch; width:auto; height:auto; aspect-ratio:1;
    flex:0 0 auto; min-width:38px; position:relative;
    background:var(--plate); padding:1px;}
  /* AND THE DRAWING IS LIFTED OUT OF THE FLOW, which is the whole of what makes
     the square above work. A box that takes its width from its height must have
     nothing of its own to say about its width, and half these plates are now
     raster pictures 256 across: left in the flow, one of them made the square
     256 wide and dragged the work row down with it. Out of the flow the box has
     no content width at all, so the row's height is the only thing left to
     measure it by. Inset by the padding, so the sunken bevel keeps its hairline
     under the picture. The two figures are forced because a raster plate is
     written with its own inline hundred-per-cent, which is right everywhere
     else it is drawn and one pixel too wide here. */
  #foeart svg, #foeart img{position:absolute; left:1px; top:1px;
    width:calc(100% - 2px) !important; height:calc(100% - 2px) !important;
    display:block;}
  .foeinfo{flex:1; min-width:0; display:flex; flex-direction:column; justify-content:space-between; padding:1px 0;}
  #foename{font-weight:bold; font-size:11px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;}
  #foehp{height:12px;}
  /* the beast's plate is a solid band, not blocks: it drains rather than fills */
  #foehp{--fillcol:#a00000;}
  #foehp .fill{background:#a00000;}
  #foehp .ptext{line-height:10px; font-size:9px;}
  /* a pale beast tints its plate (4G.4): the omen is upon the frame too */
  #foeplate.pale{background:var(--paleground);}
  #foeplate.pale #foename{color:var(--paleink);}
  /* THE FRAME HOLDS ITS GROUND BETWEEN FIGHTS (v1.6.5). The plate came and
     went with the beast, and the work row re-set itself around its 216
     pixels at every meeting and parting: the task, the sky and the boons
     shuffled left and right at exactly the moment a reader was following
     them. Vacant, the plate spends its room and shows nothing -- invisible
     rather than gone -- and the row stands still. The folded strip keeps
     the old manners: an inch-and-a-half window has no room to spend on an
     empty frame. */
  #foeplate.vacant{visibility:hidden;}
  #game.mini #foeplate.vacant{display:none;}
  /* on a narrow window the plate has no thirty pixels to give, so the drawing
     is capped and stands as tall as the room allows */
  @media (max-width:780px){
    #foeplate{width:168px;}
    #foeart{max-width:56px; max-height:56px;}   /* both, so the cap stays square */
  }
  /* and in the folded strip the row is one line high: there is nothing to
     stretch into, so the drawing keeps the icon it always was */
  #game.mini #foeart{align-self:center; aspect-ratio:auto; max-width:none;
    width:38px; height:38px;}

  /* dispatches wait in the statusbar until the player has a minute */
  /* THE THREE CONTROLS ARE THE ONLY BUTTONS ON THE SHEET (v2.1.0), and they
     were set a pixel smaller than the prose beside them and pinched to eight
     pixels of side padding, so the one row a player actually clicks read as
     the flattest thing in the window. All three take the sheet's own type
     size, bold, on twelve pixels a side: a letter waiting, the tree, and the
     halt are worth the ink. */
  .dispatchbtn{flex:0 0 auto; font-size:12px; font-weight:bold; padding:3px 12px;}
  .dispatchbtn b{color:var(--navyink);}
  .dispatchbtn.important{border-color:#800000; color:#800000;}
  .dispatchbtn.important b{color:#800000;}
  /* Make Camp (Q4): a plain sheet button that halts the descent. While
     camped it wears the pressed bevel, and the frozen work bar dims so the
     held clock reads at a glance. */
  .campbtn{flex:0 0 auto; font-size:12px; font-weight:bold; padding:3px 12px;}
  /* the kit goal sits under the kit it governs, one line, clipped rather than
     wrapped, because the column beside it is 170px and has always clipped. The
     class keeps the name the standing order gave it: it is the same one line in
     the same place, and renaming a class buys nothing a comment cannot. */
  /* THE MAIN ABILITY LEADS THE PANEL (v1.9.0). It is the one thing on this
     sheet the trade does on purpose, so it reads as a heading over the cantrips
     rather than as a line under them: full width, its own rule beneath, and the
     name carrying the weight. It is not a control and wears no affordance. */
  /* It leads the list from inside the sunken box, which is height-bounded, so
     it takes its room from the rows rather than adding it to the panel: put
     outside, it grew the sheet past the itch embed by twenty pixels and
     qa-itch caught it at all three viewports. Sticky, so it stays the heading
     while the schools scroll under it. */
  /* Sticky was not enough on its own: the table's own header is sticky at the
     same top and a step higher in z, so the moment the list scrolled, the
     header slid over the word's row and the technique vanished under "Trick |
     On | Fires". The row's height is pinned so the header can stand exactly
     one row lower, and only in a list that is actually showing the row. */
  .lv-spells{--wordrow-h:16px;}
  .wordrow{position:sticky; top:0; z-index:3; height:var(--wordrow-h);
    display:flex; align-items:stretch;
    width:100%; border-bottom:1px solid var(--headrow); color:var(--ink);
    background:var(--paper);}
  .lv-spells:has(.wordrow:not(.hidden)) table.lv th{top:var(--wordrow-h);}
  .wordrow #wordname{flex:1 1 auto; min-width:0; padding:1px 4px; text-align:center;
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis;}
  .wordrow b{letter-spacing:0.02em;}
  .leanbtn{width:100%; margin-top:3px; text-align:left; overflow:hidden;
    white-space:nowrap; text-overflow:ellipsis;}
  #game.camped .campbtn{box-shadow:inset 1px 1px 0 var(--lo), inset -1px -1px 0 var(--hi);}
  #game.camped #bar-task .fill{opacity:.4;}
  /* the d20, rolled in the open (v1.1.0): a small plate over the game,
     cycling for a breath and settling upon the true result. The switch
     lives in Options; reduced motion never raises the plate. */
  #dicebox{position:fixed; left:50%; top:32%; transform:translateX(-50%);
    background:var(--silver); border:2px solid; border-color:var(--hi) var(--dark) var(--dark) var(--hi);
    box-shadow:2px 2px 0 #000; padding:8px 14px; z-index:70; text-align:center;}
  #dicebox .die{display:inline-block; min-width:44px; padding:4px 8px;
    background:var(--paper); border:1px solid; border-color:var(--dark) var(--hi) var(--hi) var(--dark);
    font-size:24px; font-weight:bold; color:var(--navyink);}
  #dicebox .dsub{margin-top:5px; font-size:11px;}
  /* --okink and not the rarity green: the plate is grey chrome, not white
     paper, and the fine-rarity green stood at 2.9:1 upon it */
  #dicebox .ok{color:var(--okink); font-weight:bold;}
  #dicebox .bad{color:var(--illink); font-weight:bold;}

  /* the Win98 yellow tooltip, for the Guild appraiser's figures */
  #eqtip{
    position:fixed; z-index:80; background:var(--tip); border:1px solid var(--tipedge);
    padding:4px 7px; font-size:10px; line-height:1.4; max-width:230px;
    box-shadow:2px 2px 4px rgba(0,0,0,.3); pointer-events:none;
  }
  #eqtip b{display:block; margin-bottom:1px;}
  #eqtip .foot{color:var(--dim); font-style:italic; margin-top:3px;}
  /* the label over the effects a piece carries beyond its own plain work */
  #eqtip .eqhead{margin-top:3px; font-weight:bold; opacity:0.8;}
  /* the working of a figure, said quieter than the figure itself */
  #eqtip .dimnote{color:var(--dim);}
  /* a set is boxed off from the piece's own figures, because it is a fact about
     the whole kit standing in the middle of lines about one item, and two sets
     can stand at once. The groove is the same etched bevel .sunken uses, with
     no ground of its own, so it reads as a rule and not as a second panel. */
  #eqtip .setbox{
    margin:3px 0; padding:1px 5px;
    border-top:1px solid var(--lo); border-left:1px solid var(--lo);
    border-bottom:1px solid var(--hi); border-right:1px solid var(--hi);
  }

  /* the plate under glass: a beast's portrait, enlarged on highlight */
  #arttip{
    position:fixed; z-index:80; background:var(--silver); border:1px solid var(--dark);
    box-shadow:inset 1px 1px 0 var(--hi), inset -1px -1px 0 var(--lo), 2px 2px 6px rgba(0,0,0,.4);
    padding:4px; pointer-events:none;
  }
  #arttip .art{width:176px; height:176px; background:var(--plate); padding:2px;
    border-top:1px solid var(--lo); border-left:1px solid var(--lo);
    border-bottom:1px solid var(--hi); border-right:1px solid var(--hi);}
  #arttip .art svg, #arttip .art img{width:100%; height:100%; display:block;}
  #arttip .cap{text-align:center; font-weight:bold; padding:3px 2px 1px;}
  /* the glass stands over every plate that carries a key, wherever it is drawn:
     the foe, the bestiary and the Pets and Hands rows (.bestart), the two cards
     on the sheet (.hireart) and a module's cover in both its sizes */
  #foeart[data-art], .bestart[data-art], .hireart[data-art],
  .modcardart[data-art], .modcoverbox[data-art]{cursor:zoom-in;}

  /* the tutor's hand: key words carry a short lesson on highlight */
  #helptip{
    position:fixed; z-index:80; background:var(--tip); border:1px solid var(--tipedge);
    padding:4px 7px; font-size:10px; line-height:1.4; max-width:240px;
    box-shadow:2px 2px 4px rgba(0,0,0,.3); pointer-events:none;
  }
  /* the block is the HEADING's, so it stands on the slip's own child alone:
     the figures minted in bold inside the mech and lore spans (v1.6.4) are
     words in a run of prose, and the bare `b` selector was breaking the line
     at every one of them */
  #helptip > b{display:block; margin-bottom:1px;}
  /* the slip is two things and now looks like two things: the figures, one to
     a line, and then the prose beneath a rule. A player comparing two spells
     reads the top half and stops; a player who wants the world reads on. The
     rule only appears where there are figures above it to divide from, so a
     plain lesson of the chrome ("Minimize") is one paragraph as before. */
  #helptip .mech{display:block; margin:2px 0 0;}
  #helptip .lore{display:block;}
  #helptip .mech + .lore{
    font-style:italic; margin-top:4px; padding-top:3px;
    border-top:1px solid var(--tipedge);
  }
  .barlabel[data-help], .grouplabel[data-help],
  .barlabel[data-helpstats], .grouplabel[data-helpstats]{cursor:help;}
  .statusbar .cell[data-help]{cursor:help;}
  .optrow[data-help]{cursor:help;}
  /* What's This? (the Win9x idiom): the ? in the titlebar arms the help
     cursor and rings every part of the chrome that can explain itself, so
     the hundred slips of the tutor are found on purpose rather than by
     bumping into one. The ring is a 1px dotted navy, no glow and no fill. */
  body.whatsthis, body.whatsthis *{cursor:help !important;}
  body.whatsthis [data-help], body.whatsthis [data-helpstats]{outline:1px dotted var(--navyink); outline-offset:1px;}
  .tbtn.pressed{border-color:var(--lo) var(--hi) var(--hi) var(--lo); background:var(--pressed);}
  /* the saving cell reads as a control: it takes a copy on click */
  .statusbar .cell.savecell{cursor:pointer; min-width:92px;}
  .statusbar .cell.savecell:hover{color:var(--navyink);}
  .statusbar .cell.savewarn{color:var(--illink); font-weight:bold;}
  /* the Guild calendar (F8): the town keeps a year of its own days, and the
     menu bar carries the leaf that opens it, at the far right beside the
     patch notes. It stands navy upon a day the hall keeps. The whole glyph is
     drawn in currentColor, so the one colour rule lights it, and the navy of
     a kept day gives way to the white of the menu bar's own hover. */
  .menubar .calcell{padding:2px 6px; color:var(--faint);}
  .menubar .calcell.kept{color:var(--navyink);}
  .menubar .calcell:hover, .menubar .calcell.kept:hover{color:#fff;}
  .calnav{display:flex; justify-content:space-between; align-items:center; margin-bottom:5px;}
  .calnav button{padding:1px 8px;}
  table.calgrid{
    width:100%; border-collapse:collapse; background:var(--paper); table-layout:fixed;
    border-top:1px solid var(--lo); border-left:1px solid var(--lo);
    border-bottom:1px solid var(--hi); border-right:1px solid var(--hi);
  }
  table.calgrid th{background:var(--silver); font-weight:bold; padding:2px 0; border-bottom:1px solid var(--lo);}
  table.calgrid td{text-align:center; padding:3px 0;}
  table.calgrid td.pad{color:var(--mute);}
  table.calgrid td.kept{color:var(--navyink); font-weight:bold; border-bottom:2px solid var(--navyink);}
  table.calgrid td.today{background:var(--navy); color:#fff; font-weight:bold; border-bottom:0;}
  table.calgrid td.today.kept{border-bottom:2px solid var(--hi);}
  .calnote{margin-top:8px; padding:4px 6px;}
  .calent{padding:3px 0; border-bottom:1px solid var(--rule);}
  .calent:last-child{border-bottom:0;}
  .calent b{color:var(--navyink);}
  .calent .calsay{color:var(--c-common); font-size:10px; line-height:1.4; margin-top:1px;}
  .calent .calstate{color:var(--faint); margin-top:2px;}
  .calsoon{margin-top:7px; color:var(--faint);}

  /* bestiary plates: a framed sketch and the Guild's notes */
  .bestplate{display:flex; gap:6px; padding:4px 4px; border-bottom:1px solid var(--rule);}
  .bestart{width:48px; height:48px; flex:0 0 auto; background:var(--plate); padding:1px;}
  .bestart svg{width:100%; height:100%; display:block;}
  .bestbody{flex:1; min-width:0;}
  .bestname{font-weight:bold;}
  .bestname .cnt{font-weight:normal; color:var(--dim);}
  /* the figures the fight is settled by, above the lore and set apart from it:
     the plate states what a thing IS before it tells you about it */
  .beststats{font-size:10px; margin-top:1px;}
  /* and the same line on the foe's own plate, under its hit points */
  .foestats{font-size:9px; color:var(--dim); line-height:1.2; margin-top:1px;
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis;}
  #game.mini .foestats{display:none;}   /* the strip has no room for it */
  .bestdesc{color:var(--dim2); font-size:10px; line-height:1.35; margin-top:1px; font-style:italic;}
  /* the Guild's practical note, entered at mastery: a second author, a
     second hand, so it reads upright where the lore reads italic */
  .bestnote{font-style:normal; color:var(--dim3);}
  /* the standing a hand is at, standing under its own description in the book
     of hands. Upright and in the body's own ink, against the italic the
     descriptions around it are set in: it is the figure the row is scanned
     for, and it is the only line here that is neither prose nor a note. */
  .handstand{font-style:normal; margin-top:2px;}

  /* the armoury book: a row to a pattern, the name and its marks above and the
     piece's own figures beneath, ruled the way the bestiary's rows are ruled */
  .armrow{padding:2px 6px 4px; border-bottom:1px solid var(--rule);}
  .armhead{display:flex; justify-content:space-between; gap:8px; align-items:baseline;}
  .armhead .armfig{color:var(--dim); white-space:nowrap;}
  .armhead .cnt{font-weight:bold; color:var(--navyink);}
  .armnote{color:var(--dim2); font-size:10px; line-height:1.35; margin-top:1px;}
  /* the forge's line under a slot heading, said once for everything beneath it,
     and the line that says the Guild will not fit a piece yet. Both are
     secondary text and both take the note's own treatment: .armbar carried no
     rule at all and rendered at the row's inherited size and colour. */
  .armslotnote{color:var(--dim2); font-size:10px; line-height:1.35;
    padding:1px 4px 2px; font-style:italic;}
  .armbar{color:var(--dim2); font-size:10px; line-height:1.35;}
  /* the five words of the Show: row, each in its own scarcity. Weight is set
     here rather than left to the colour classes, four of which carry bold and
     the common one does not: five words of one kind must differ in hue alone. */
  .armfiltword{font-weight:bold;}
  .armstore{margin-top:2px;}
  .armstore button{padding:1px 8px; margin-left:4px;}
  /* a pattern the deep has not given up: the row still states its item level,
     because that is what says where to go and hunt for it */
  .armrow.armdim, .armrow.armdim .armfig{color:var(--dim4);}
  /* the row the forge is looking at, marked the way a selected line is marked
     in the era: the navy band and reversed text, no glow and no radius */
  .armrow.armsel{background:var(--navy); color:#fff;}
  .armrow.armsel .armfig, .armrow.armsel .armnote{color:#dfe4ef;}
  .armrow.armsel b{color:#fff;}
  .armrow[data-arm-row]{cursor:pointer;}
  /* a name struck off the memorial wall, shown the way the mason shows it */
  .loststruck{text-decoration:line-through;}

  /* ---------- the Armoury: the book, the seam and the forge ----------
     Two columns inside one client. The seam is a bevelled strip a dozen pixels
     wide carrying one arrow, which is how the era folded a pane away, and the
     window itself grows and shrinks with the fold rather than leaving a hole
     where the forge stood. */
  .armcols{display:flex; align-items:stretch; gap:0;}
  .armbook{flex:1 1 auto; min-width:0;}
  /* THE BOOK TAKES THE HEIGHT THE FORGE LEAVES, AND DRIVES NONE OF ITS OWN.
     The window is a collection window like the bestiary: it stands at a
     bounded, compact height and the list scrolls inside it. 243 patterns must
     never make it taller, which is the fault the first cut of this rule
     shipped: a flex-basis of `auto` let the list ask for its whole content and
     the Armoury grew to fill the screen, with the forge sitting as a short
     panel above an enormous grey field, which is worse than the gap it was
     closing.

     So the basis is nought and the list takes only what is LEFT of the column
     after the summary, the trough and the three rows of boxes. The column's own
     height comes from the forge beside it, stretched by .armcols, so the two
     stand level and the list fills the difference. The floor is what the list
     falls back to with the forge folded away, where there is no tall neighbour
     to stretch against, and it is near the .dlgscroll cut every other list in
     the file uses. Nothing here is a viewport share: the window is the size of
     its own contents and not the size of the screen. */
  #armourydlg .armbook{display:flex; flex-direction:column; min-height:0;}
  #armourydlg #armlist{flex:1 1 0; min-height:260px; max-height:none;}
  .smithseam{flex:0 0 auto; width:15px; padding:0; margin:0 3px; font-size:9px; line-height:1;}
  /* relative and clipped, because a take throws glitter the height of it: the
     flecks are placed against this box and the ones that run past its foot are
     cut off here rather than falling into the book beside it */
  .smithpane{flex:0 0 274px; width:274px; display:none; padding-left:3px;
    position:relative; overflow:hidden;}
  #armourydlg.forgeopen .smithpane{display:block;}
  #armourydlg.forgeopen .win{max-width:820px;}
  /* the pane's own name, centred and set larger than a row label: it is the
     heading of a panel and not a line of the table under it */
  .smithhead{background:var(--headrow); font-weight:bold; padding:3px 4px;
    border:1px solid var(--rule3); margin-bottom:4px;
    text-align:center; font-size:14px; letter-spacing:.5px;}
  /* the smith's plate. It is a photograph of a drawing and not line art, so it
     is an img in the same etched well the bestiary uses and the whole picture
     stands: the sky band and the grass are the drawing. Wider than the inked
     stand-in it replaced, because the drawing carries a scene and not a figure. */
  .smithplate{background:var(--plate); padding:1px; width:180px; margin:0 auto 4px;
    position:relative;}
  .smithplate img{display:block; width:100%; height:auto;}
  /* THE WORD, on a take. It stands over the plate, where the eye already is at
     the moment the hammer lands, and it snaps in rather than fading: the scale
     is stepped, so it arrives in three jumps and no smooth motion at all.
     --okink and not the rarity green, for the reason #dicebox states above: the
     fine-rarity green is a scarcity band and this is a pass, and it must not be
     read as an item's colour. */
  .smithup{position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
    pointer-events:none;}
  .smithup span{background:var(--halo); border:2px solid var(--okink); color:var(--okink);
    font-size:26px; font-weight:bold; letter-spacing:1px; padding:1px 8px;}
  .smithup.pop{animation:smithup steps(3) forwards;}
  @keyframes smithup{from{transform:scale(2);} to{transform:scale(1);}}
  /* the piece in the tongs. It is what the whole panel is about, so the name
     stands larger than the rows that price it and than the prompt that stands
     here before a pattern is picked. */
  .smithpick{color:var(--dim2); font-size:10px; line-height:1.35; min-height:26px;}
  .smithpick b{color:var(--navyink); font-size:13px; line-height:1.25;}
  .smithfigs{margin-top:4px;}
  .smithfigs .kv{padding:1px 2px;}
  /* the rank's own rule, where it is clipping the work upon the pick. A
     wrapping sentence and not a kv row: the kv is two short columns holding a
     label and a figure, and this is a rule a reader has to read. */
  .smithfigs .smithrule{color:var(--dim2); font-size:10px; line-height:1.35;
    padding:2px 2px 0;}
  .smithbtns{display:flex; justify-content:flex-end; margin-top:5px;}
  .smithsay{color:var(--dim2); font-size:10px; line-height:1.35; margin-top:4px; min-height:26px; font-style:italic;}
  /* what the hammer says for itself, once the Roll holds it */
  .smithhammer{color:var(--dim2); font-size:10px; line-height:1.35; margin-top:4px;}
  .smithhammer b{color:var(--navyink);}
  /* the artefact's own picture, set into the line that names it and into the
     book's mark, so the thing is drawn the one way wherever it stands */
  .smithhammer .smithicon, .armnote .smithicon{display:inline-block;
    vertical-align:-3px; margin-right:3px;}
  /* and the stamp's own, which is the same drawing at the case's size */
  .smithstamp .smithicon{display:block;}
  /* ---------- the case ----------
     A sunken trough with the strip running through it and one bevelled marker
     down the middle: a Win9x well with a pointer on it, and the faces inside
     are the window's own icons rather than the smith's crayon. Hard edges, no
     radius, no gradient and no glow; the tile width is set from SMITH_TILE_W at
     paint, so the figure is typed in the dial block and nowhere else. */
  .smithcasewrap{position:relative; margin:5px 0 0;}
  /* the trough is a well of PAPER and not of the panel's grey, for the same
     reason a beast's plate is: the faces are drawn in black outline and the
     ground is knocked out of them, so an ink drawing over the dark theme's own
     ground would be an ink drawing nobody could see */
  .smithcase{position:relative; height:44px; overflow:hidden; background:var(--plate);}
  .smithtrack{position:absolute; top:0; left:0; height:100%; display:flex; align-items:center;}
  .smithtile{flex:0 0 auto; width:var(--tilew); height:100%;
    display:flex; align-items:center; justify-content:center;
    border-right:1px solid var(--rule3);}
  /* a tile the smith owes you: the boon chip's own ground, because that is what
     it is -- a take already paid for and not yet handed over. Ground and not
     ink, so the drawing on it is the same drawing and nothing is redrawn twice
     (the faces are knocked-out ink, see the note above .smithcase). */
  .smithtile.owed{background:var(--chip);}
  .smithicon{display:block; image-rendering:auto;}
  .smithmark{position:absolute; top:0; bottom:0; left:50%; width:3px; margin-left:-2px;
    background:var(--silver); box-shadow:inset 1px 0 0 var(--hi), inset -1px 0 0 var(--lo);
    pointer-events:none;}
  .smithmark::before, .smithmark::after{content:""; position:absolute; left:-4px;
    width:0; height:0; border-left:5px solid transparent; border-right:5px solid transparent;}
  .smithmark::before{top:0; border-top:7px solid var(--ink);}
  .smithmark::after{bottom:0; border-bottom:7px solid var(--ink);}
  /* the stamp that lands over the case */
  .smithstamp{position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
    font-size:26px; font-weight:bold; color:var(--navyink); pointer-events:none;}
  .smithstamp .halo{background:var(--halo); padding:0 5px; border:1px solid var(--ink);}
  .smithstamp.big{font-size:34px;}
  .smithstamp.hit{animation:smithstamp .7s ease-out;}
  @keyframes smithstamp{from{transform:scale(2.2); opacity:0;} 40%{transform:scale(1); opacity:1;} to{opacity:1;}}
  /* the sparks off the anvil: square pixels thrown out and gone, no glow and no
     fade to a blur, because 1996 had neither */
  .smithspark{position:absolute; width:3px; height:3px; background:var(--ink);
    left:50%; top:50%; pointer-events:none;
    animation:smithspark .55s linear forwards;}
  @keyframes smithspark{
    from{transform:translate(0,0); opacity:1;}
    to{transform:translate(var(--sx), var(--sy)); opacity:0;}
  }
  .smithflash{position:absolute; inset:0; background:#fff; pointer-events:none;
    animation:flashout .22s ease-out; opacity:0;}
  /* the glitter of a take: square gold flecks falling the height of the pane,
     hard-edged and the same size the whole way down. No blur, no glow, no
     gradient and no radius: it is the anvil's own spark in gold, thrown wider
     and further, and 1996 could draw it exactly like this. */
  .smithglint{position:absolute; top:-6px; width:4px; height:4px;
    background:var(--forgegold); pointer-events:none;
    animation:smithglint linear forwards;}
  @keyframes smithglint{
    from{transform:translate(0,0);}
    to{transform:translate(var(--gx), var(--gy));}
  }
  /* AND NOTHING OF THE FORGE IS STILLED HERE. The sheet stills the motion a
     player did not ask for; every part of this sequence is the answer to a
     button they pressed, drawn once, in the panel they are looking at. It is
     read for what it says, so it says the same thing under either preference.
     The pane's jolt on a take is the exception and is stilled with every other
     .shake at the top of the sheet, since a window that kicks is exactly the
     motion the switch is for. */
  /* on a narrow window the forge stands under the book rather than beside it,
     since 274 pixels of it and a readable book do not both fit across a phone */
  @media (max-width:700px){
    .armcols{flex-wrap:wrap;}
    .smithpane{flex:1 1 100%; width:auto; padding-left:0; margin-top:5px;}
    .smithseam{width:auto; flex:1 1 100%; margin:4px 0 0; padding:1px 0;}
  }

  /* the trophy case and the Guildhouse book share the achievements' ruling */
  .dlgscroll .prov{display:block; color:var(--dim); font-style:italic;}
  .dlgscroll .ach.locked .prov{color:var(--dim4);}

  /* the Guild plate: one ink on paper, framed by the etched bevel the markup
     carries as class sunken, the same way the bestiary plate takes it.
     both children are named. a frame that styles svg alone renders an
     embedded scan at its intrinsic pixel size. */
  .guildplate{background:var(--plate); padding:1px; margin:0 auto 6px;}
  .guildplate svg, .guildplate img{display:block; width:100%; height:auto;}
  #guildhouseart{max-width:460px;}
  #countershopart, #honourart, #featsart, #namesart{max-width:460px;}
  /* The floor is 320 and not 260. crispEdges is not a promise Chromium keeps
     at any width: the elevation is a 240 by 120 field, and under about 310
     device pixels of width its strokes fall under a pixel apiece and come back
     antialiased, which is grey, and grey is the one thing this plate is not.
     Measured rather than guessed, at device scale 1 and every ten pixels from
     240 to 460 (tools/probe-plate-ink.mjs): grey to 300, hard from 310 up. 320
     is the round figure above the knee, and the window still stands inside a
     595 pixel viewport with it. The four small plates are a 240 by 60 field
     and hold their ink at 340, which is why that figure is unmoved. */
  @media (max-height:700px){ #guildhouseart{max-width:340px;} }
  @media (max-height:600px){ #guildhouseart{max-width:320px;}
    #countershopart, #honourart, #featsart, #namesart{max-width:340px;} }
  .guildcap{color:var(--dim); font-style:italic;}
  /* the run of stage marks, held to one width so the eight names begin upon
     one line: six squares now stand where four stood */
  .guildmark{display:inline-block; min-width:6.5em;}
  /* the Roll's ladders run from one square to twenty, so its run breaks where
     it must. It keeps the Guildhouse's own column width all the same: cutting
     the minimum to nought let every line begin its name at a different inch,
     and the Roll's names are read down the column before they are read across
     the row. A line with no ceiling states its level here in words instead,
     and the column holds that too. */
  .rollmark{word-break:break-all;}
  /* the flame alternates solid and hollow, not full ink and half ink: the
     plates carry no grey at all now, and a flame at .55 was the last of it */
  @keyframes shoplamp{0%,49%{fill:#1c1c1c;} 50%,100%{fill:none;}}
  .guildplate.lit .lamp{animation:shoplamp 3.6s steps(2) infinite;}
  /* the stilling is written a second time here, as the credit roll's is at 672
     and the waiting chart cell's at 982. the list up at 586 carries the same
     selector, but it is written above this one and at the same weight, so it
     is overruled where it stands. body.stillmotion needs no second copy: it
     carries one class more and outweighs this rule from where it is. */
  @media (prefers-reduced-motion: reduce){ .guildplate.lit .lamp{animation:none;} }

  /* the shelf of modules: a cover plate, the back-cover matter beside it,
     and the roll of ends beneath. Same bevels and rules as every other
     window; the cover is the bestiary plate at a module's proportions. */
  .modplate{display:flex; gap:8px; padding:6px 4px; border-bottom:1px solid var(--rule);}
  .modplate.locked{color:var(--dim4);}
  .modcoverbox{width:84px; flex:0 0 auto; background:var(--plate); padding:1px;}
  .modcoverbox svg{width:100%; height:100%; display:block;}
  .modplate.locked .modcoverbox{opacity:.4;}
  .modbody{flex:1; min-width:0;}
  .modname{font-weight:bold;}
  .modwhere{color:var(--dim); font-size:10px;}
  .modblurb{color:var(--dim2); font-size:10px; line-height:1.35; margin-top:3px; font-style:italic;}
  .modends{margin-top:4px;}
  .modends .endhead{font-weight:bold; color:var(--navyink); font-size:10px;}
  .modend{font-size:10px; padding:1px 0;}
  .modend .endmark{display:inline-block; width:12px;}
  .modend.unseen{color:var(--dim4); font-style:italic;}
  .modend .endnote{display:block; color:var(--dim3); margin-left:12px;}
  .modend.unseen .endnote{color:var(--dim4);}
  /* the plate a module opens upon */
  .modopen{display:flex; gap:10px; align-items:flex-start;}
  .modopen .modcoverbox{width:110px;}
  .modopen .modblurb{font-size:11px;}

  /* the module row upon the enrolment sheet: two cover plates as buttons,
     bevelled out when unchosen and in when chosen, as the era drew them */
  .modpickrow{display:flex; gap:6px;}
  .modcard{display:flex; flex-direction:column; align-items:center; gap:2px;
    flex:1 1 0; min-width:0; padding:5px 4px 6px; text-align:center; cursor:pointer;}
  .modcard .modcardart{width:56px; background:var(--plate); padding:1px; display:block;}
  .modcard .modcardart svg{width:100%; height:100%; display:block;}
  .modcard .modcardname{font-weight:bold; font-size:10px; line-height:1.2;}
  .modcard .modcardsub{font-size:10px; color:var(--dim);}
  .modcard .modcardends{font-size:10px; color:var(--dim3);}
  .modcard.sel{box-shadow:inset 1px 1px 0 var(--lo), inset -1px -1px 0 var(--hi);
    padding:6px 3px 5px 5px;}
  .modcard.locked, .modcard:disabled{color:var(--dim4); cursor:default;}
  .modcard.locked .modcardart{opacity:.35;}
  .modcard.locked .modcardname, .modcard.locked .modcardsub, .modcard.locked .modcardends{color:var(--dim4);}

  tr.archead td{background:var(--headrow); font-weight:bold;}

  /* ============ THE HALL BY LAMPLIGHT (the dark ground) ============
     Win9x after dark, and not a filter over the light theme: the chrome keeps
     its bevels (a lit edge above-left, a shadowed one below-right, only now
     both are cut from the dark), the page is a dark ground with pale ink, and
     every hue that carried meaning in print is raised to carry it against the
     dark. The switch is in Options; the class is set on <html> before the
     first paint, so no white ever flashes. */
  html.dark{
    color-scheme:dark;         /* the scrollbars, ticks and radios come dark too */
    --silver:#2e2f33; --hi:#565961; --lo:#161719; --dark:#000000;
    --navy:#0d1a3f; --navy2:#2f5f9e;
    --paper:#17181b; --ink:#dcdcde;
    --plate:#cfc9bb;           /* a beast is inked on paper; the plate stays paper */
    --desk:#121317;
    --navyink:#8fb4ee;
    --mute:#77797d; --faint:#a9abaf;
    --dim:#a6a8ab; --dim2:#c2c4c7; --dim3:#b4b6b9; --dim4:#85878b;
    --rule:#2a2c30; --rule2:#313338; --rule3:#3a3c41;
    --headrow:#26272b;
    --tip:#2c2c22; --tipedge:#7d7d61;
    --halo:#000000;
    --scrim:rgba(0,0,0,.55);
    --chip:#1b2740; --chipill:#341d1d; --illink:#f08a8a;
    --okink:#5fc45f;
    --paleground:#2a2637; --paleink:#bbaee2;
    --pressed:#202124;
    --c-common:#c9cbce; --c-fine:#5fc45f; --c-scarce:#7fa8ff;
    --c-prized:#d08ae8; --c-storied:#e8a24e; --c-fabled:#ff7a7a;
    --c-iron:#5ad0d8; --c-silver:#a8c0dc; --c-crowned:#e8cc6a;
    --forgegold:#e0b000;
    --goldink:#d8a83c;
    /* the same three ladders, raised off the dark ground: a navy or an olive
       that reads on paper is a smudge on it */
    --tree-weight:#7fa8ff; --tree-weight-lit:#a9c4ff;
    --tree-reach:#5fc45f;  --tree-reach-lit:#93e093;
    --tree-thrift:#d8a83c; --tree-thrift-lit:#f0c860;
    /* the twelve trades, raised off the dark ground. A slate, a moss and a
       charcoal that read on paper are all the same smudge on it, so every one
       is carried up rather than a chosen few: the set has to be told apart at
       sixteen pixels in either theme or it is not a set. The raised values are
       declared once, in :root, because the navy grounds want them in the light
       theme too; here the paper pair simply points at them. */
    --t-fighter:var(--t-fighter-lit); --t-wizard:var(--t-wizard-lit);
    --t-cleric:var(--t-cleric-lit);   --t-rogue:var(--t-rogue-lit);
    --t-ranger:var(--t-ranger-lit);   --t-barbarian:var(--t-barbarian-lit);
    --t-paladin:var(--t-paladin-lit); --t-bard:var(--t-bard-lit);
    --t-druid:var(--t-druid-lit);     --t-sorcerer:var(--t-sorcerer-lit);
    --t-warlock:var(--t-warlock-lit); --t-monk:var(--t-monk-lit);
  }
  /* the log's hands, raised off the dark ground */
  html.dark .lg-good{color:#6ec96e;}
  html.dark .lg-bad{color:#ff7b7b;} html.dark .lg-crit{color:#ff8a8a;}
  html.dark .dispatchbtn.important{border-color:#ff8a8a; color:#ff8a8a;}
  html.dark .dispatchbtn.important b{color:#ff8a8a;}
  html.dark .lg-amb{color:#8f90a0;}
  html.dark .lg-fig{color:#7f8090;}
  /* the seven kinds, lifted off the dark plate the way every other ink is */
  html.dark .lg-c-combat{color:#e08585;}
  html.dark .lg-c-trade{color:#d8a83c;}
  html.dark .lg-c-road{color:#c8a071;}
  html.dark .lg-c-rest{color:#6ec96e;}
  html.dark .lg-c-descent{color:#bb8ed4;}
  html.dark .lg-c-guild{color:#8fa6dd;}
  html.dark .lg-c-town{color:#9aa8b8;}
  html.dark .lgfhint{color:#9092a4;}
  html.dark #log.quiet .lg-sys{color:#7e86b8;}
  html.dark .total-good{color:#ff8a8a;} html.dark .total-great{color:#e79ae7;}
  /* the panel takes its colours from the tokens, so the dark theme needs no
     override of its own; only the two figures are named here, and --navyink
     already answers for the dark sheet */
  html.dark .bestrow .m, html.dark .bestname .m, html.dark .armhead .m, html.dark .ach .m{color:#d18ae8;}
  html.dark #dicebox .ok{color:#6ec96e;} html.dark #dicebox .bad{color:#ff7b7b;}
  /* the bars: the segmented fills are the sheet's one piece of light, so each
     errand's tint is raised rather than left to sink into the dark paper */
  /* At night the blocks are the light thing and the trough is the dark one,
     so the ink upon a block turns over with them: the paper's own near-black
     on the bright golds, greens and greys, and white kept on the blues and
     reds, which stay too deep to write on in anything else. Every one of
     these colours is the colour it was; only the ink laid on it is named. */
  html.dark .pbar{--fillcol:#3b6fc4; --fillink:#ffffff;}
  /* the same seven kinds, lifted off the dark plate as every other ink is */
  html.dark .pbar.kill{--fillcol:#c04141; --fillink:#ffffff;}
  html.dark .pbar.boss{--fillcol:#9e2a2a; --fillink:#ffffff;}
  html.dark .pbar.sell{--fillcol:#c99320; --fillink:var(--paper);}
  html.dark .pbar.buy{--fillcol:#c99320; --fillink:var(--paper);}
  html.dark .pbar.road{--fillcol:#a9784a; --fillink:var(--paper);}
  html.dark .pbar.rest{--fillcol:#3fae3f; --fillink:var(--paper);}
  /* the descent's purple is set a shade deeper than the log's, because white is
     written ON it: at #9a63bb the figure came in at 4.3:1 against the 4.5 WCAG
     AA asks of small text, which verify-bars holds the whole ladder to */
  html.dark .pbar.walk{--fillcol:#8f55b0; --fillink:#ffffff;}
  html.dark .pbar.plotcue{--fillcol:#8f55b0; --fillink:#ffffff;}
  html.dark .pbar.hirebar{--fillcol:#3fae3f; --fillink:var(--paper);}
  html.dark #bar-hp{--fillcol:#a83c3c; --fillink:#ffffff;}
  /* the alarm red comes down a shade from #d04a4a, which sat at the exact
     point where neither ink read upon it */
  html.dark #bar-hp.alarm{--fillcol:#c84040; --fillink:#ffffff;}
  html.dark #bar-hp.alarm .fill{background:#c84040;}
  html.dark #bar-hp.alarm + .pfig{color:#c84040;}
  html.dark #foehp{--fillcol:#c04141; --fillink:#ffffff;}
  html.dark #foehp .fill{background:#c04141;}
  /* the hand at your side used to want a ground of its own at night, having
     none by day. It carries one at every hour now (.hireart), so there is
     nothing for the night to add. */
  /* the heavy beats, dimmed: a white pane at full strength is a lamp in a
     dark room. Same one-frame idea, a fraction of the light. */
  html.dark #flash{background:#dfe6ff;}
  html.dark #flash.on{animation-name:flashoutdark;}
  @keyframes flashoutdark{from{opacity:calc(var(--flashmax,.8) * 0.35);} to{opacity:0;}}
  html.dark .lg-hit{animation-name:loghitdark;}
  @keyframes loghitdark{from{background:#4a3a12;} to{background:transparent;}}
  /* high contrast, at night, lightens where by day it darkened */
  html.dark body.hicontrast{
    --c-common:#ffffff; --c-fine:#8ee88e; --c-scarce:#a8c4ff;
    --c-prized:#e6a8f6; --c-storied:#ffbe6a; --c-fabled:#ff9c9c;
    --c-iron:#7ae4ec; --c-silver:#c4d6ee; --c-crowned:#ffe08a;
    --ink:#ffffff;
  }
  html.dark body.hicontrast .lg-good{color:#8ee88e;}
  html.dark body.hicontrast{--goldink:#f0c052;}
  html.dark body.hicontrast .lg-amb{color:#b0b1c2;}
  html.dark body.hicontrast #log.quiet .lg-sys{color:#a6b0e0;}
  html.dark body.hicontrast table.lv tr.locked td{color:#b0b2b6;}
  html.dark body.hicontrast .optnote,
  html.dark body.hicontrast .barlabel .optnote{color:#c8cacd;}

  /* ============ THE CHROME TAKES ITS ROOM BACK (v2.1.0) ============
     The other half of the trade written at the embed ladder above. The work
     row's doubled padding, the taller work bar and the boons' bigger chips are
     for a window with the height to spend; short of 820 they go back to the
     metrics they kept before, and every figure in that ladder holds unchanged.
     It stands here, at the foot of the sheet, because it takes back rules that
     are written a thousand lines below where the ladder itself stands, and a
     rule cannot take back one that has not been written yet. */
  @media (max-height:820px){
    .statusbar{gap:4px;}
    .statusbar .cell{padding:2px 6px;}
    .buffrow{margin-top:4px;}
    .buffrow #buffcell{padding:2px 6px;}
    .buffchip{padding:0 6px; margin:0 0 0 4px;}
    .skycell{padding:0 6px; margin:0 0 0 4px;}
    .skygroup{margin-right:10px;}
    .dispatchbtn, .campbtn{font-size:11px; padding:2px 8px;}
    .chartcell{font-size:11px; padding:1px 7px;}
    #bar-task{height:16px; margin-top:4px;}
    #bar-task .ptext{line-height:16px; font-size:11px;}
    .footbar{margin-top:4px;}
    .footbar .cell{padding:2px 7px;}
  }

  /* ============ THE OTHER DESKS OF THE NINETIES (the chrome themes) ============
     The sheet is written in tokens, so a second desktop is a second set of
     answers to the same questions: --silver and its bevels, the title bar's
     pair, the desk behind the window. The class rides on <html> beside dark,
     set before the first paint, and the choice is the machine's own
     (DESK_KEY), never the chronicle's. win98 is no class at all: it is what
     the sheet says with nothing added. Each desk answers every token it
     touches a second time under html.dark, or the day value would leak into
     the lamplight. */
  /* GNOME 1.x, circa 1999: the GTK bevels a shade cooler and flatter than the
     Guild's grey, a steel blue title bar in the Sawmill manner, and a dark
     slate desktop behind it. */
  html.desk-gnome{
    --silver:#d6d6d6; --hi:#ffffff; --lo:#7f7f7f; --dark:#2e2e2e;
    --navy:#2e4270; --navy2:#6279a8;
    --desk:#33506e;
    --pressed:#bcbcbc;
  }
  html.dark.desk-gnome{
    --silver:#32342f; --hi:#55574f; --lo:#181915; --dark:#000000;
    --navy:#26334f; --navy2:#42567f;
    --desk:#15181d;
    --pressed:#262823;
  }
  /* Mac OS 8, the platinum face: paler grey and softer bevels, a title bar of
     pinstripes with the title centred, the close box on the left and a zoom
     box drawn at the right so the centred title hangs true. The stripes and
     their ink are tokens too, since the lamplight wants its own. */
  html.desk-mac{
    --silver:#dddddd; --hi:#ffffff; --lo:#9a9a9a; --dark:#4a4a4a;
    --navy:#2f3f9e; --navy2:#5a5ac8;
    --desk:#3d6b8a;
    --pressed:#c4c4c4;
    --mactb-a:#f2f2f2; --mactb-b:#c6c6c6; --mactb-ink:#111111;
  }
  html.dark.desk-mac{
    --silver:#383838; --hi:#5c5c5c; --lo:#1d1d1d; --dark:#000000;
    --navy:#272e54; --navy2:#474f8c;
    --desk:#111417;
    --pressed:#2b2b2b;
    --mactb-a:#484848; --mactb-b:#2a2a2a; --mactb-ink:#e4e4e4;
  }
  html.desk-mac .titlebar{
    background:repeating-linear-gradient(0deg,var(--mactb-a) 0 2px,var(--mactb-b) 2px 3px);
    color:var(--mactb-ink);
  }
  html.desk-mac .titlebar .tglyph{display:none;}   /* platinum keeps no icon in the bar */
  html.desk-mac .titlebar .tname{text-align:center;}
  html.desk-mac .titlebar .tbtn{order:-1;}
  html.desk-mac .titlebar::after{
    content:""; flex:0 0 auto; width:16px; height:14px;
    background:var(--silver); border:1px solid var(--dark);
    box-shadow:inset 1px 1px 0 var(--hi), inset -1px -1px 0 var(--lo);
  }
  /* ============ THE HALL AFTER CLOSING ============
     Two things live here: the Extras drop's own header row, and the little
     black screen the amusement runs on. They stand together because they are
     one feature, and last in the sheet because the screen deliberately owes
     nothing to the page's lamps: a monitor from 1991 was the colour it was
     whatever the room was painted, so nothing below reads a theme var. */

  /* a label under a drop that is a label and not a control. The bar's own
     button rules do not reach it, so it states its own metrics. */
  .menuhead{
    padding:3px 14px 3px 8px; font-size:11px; font-weight:bold;
    color:var(--dim); cursor:default; white-space:nowrap; user-select:none;
  }

  /* the screen. The canvas is 320x200 logical and is shown at twice that, and
     it gives way with the window rather than pushing the sheet sideways: the
     8:5 of the mode is held by aspect-ratio so the picture never stretches. */
  .fyrscreen{
    position:relative; background:#000; padding:6px;
    border:1px solid var(--dark);
    box-shadow:inset 1px 1px 0 var(--lo), inset -1px -1px 0 var(--hi);
    line-height:0;
  }
  .fyrscreen canvas{
    display:block; width:640px; max-width:100%; aspect-ratio:8/5; height:auto;
    background:#000;
    image-rendering:pixelated;
    image-rendering:crisp-edges;
    -ms-interpolation-mode:nearest-neighbor;
    touch-action:manipulation;
  }
  /* the glass: the line grille of a cheap monitor, and the corners going dark
     the way a tube's do. Neither takes a click; the canvas under them does. */
  .fyrscan{
    position:absolute; inset:6px; pointer-events:none;
    background:repeating-linear-gradient(transparent 0 2px, rgba(0,0,0,.18) 2px 3px);
    box-shadow:inset 0 0 24px 6px rgba(0,0,0,.55);
  }
  .fyrkeys{
    margin-top:4px; font-size:10px; color:var(--dim); text-align:center;
    user-select:none;
  }
  /* a phone holds the screen and drops the key legend, which names keys it
     has none of; the tap on the glass is the whole of the control there. */
  @media (max-width:560px){
    .fyrkeys{display:none;}
  }
