/* TypeAnyKey. The case.
 *
 * The whole site, one stylesheet. See DESIGN.md for why any of this is the
 * way it is. The short version: this is a compositor's type case rendered in
 * a browser, so compartments are ruled rather than boxed, size carries
 * information, and nothing that can hold still is allowed to move.
 *
 * Rules that are load-bearing, not taste:
 *   - no gradient, no shadow, no blur, no radius above 1px on a compartment
 *   - the spot colour marks two things and nothing else: the four signature
 *     places (wordmark rule, active drawer, the word COPIED, the warning
 *     that an Alt code needs a registry change) and the hover state of
 *     anything you can act on. Never as a fill, never a tint, never on a
 *     resting element. A copy is an inversion to solid ink, not a wash
 *   - the page body never scrolls sideways. Tables get their own scroller
 */

/* ---------------------------------------------------------------- tokens */
:root{
  --paper:#FFFFFF;
  --paper-raised:#FAFAFA;
  --paper-sunk:#EFEFEE;
  --rule:#DEDEDC;
  --rule-strong:#B2B2AF;
  /*  The border of a thing you can operate, as opposed to a rule between two
   *  compartments. WCAG wants 3:1 on a control boundary and --rule is 1.35:1
   *  against paper, so the select, the toggle and the search field were
   *  drawing their own edges at a ratio a person cannot be assumed to see.
   *  #8E8E8B is 3.29 on paper and 3.15 on raised paper. A rule between two
   *  compartments is not a control and keeps --rule: it is texture, and it
   *  is the thing that makes this look like a type case. */
  --rule-control:#8E8E8B;
  --ink:#0A0A0A;
  --ink-2:#3D3D3B;
  /*  Third-tier ink: counts, key legends, the word under a glyph. It was
   *  #767674, which is 4.55 against white and 3.96 against the drawer floor
   *  a lot of it actually sits on - below AA for text this size, and the
   *  contrast failure Lighthouse reported on every page tested. #686866 is
   *  4.85 on the drawer floor, 5.35 on a compartment, 5.58 on paper, and is
   *  still clearly a tier below --ink-2 at 9.46. */
  --ink-3:#686866;
  /* The spot. Rubine, a real printing ink, and nothing in this category
   * uses magenta. Four signature places (the wordmark rule, the active
   * drawer, the word COPIED, the warning that an Alt code needs a registry
   * change) plus one job: it is the colour of the pointer. Every hover cue
   * on the site is this and only this, which is what makes a hover legible
   * as "you can take this" rather than as a generic highlight. It is never
   * a fill and never a tint. A tint reads as a highlighter; ink does not.
   * Focus rings stay --ink: an outline has to win on contrast, not hue. */
  --spot:#C4006B;

  --u:64px;                 /* the compartment unit */
  /* The spine. --rail is the cabinet column; +1px is the rule down the left
   * of the drawers; +16px is the inset the drawer label already hangs at.
   * Every section heading on a page that has a case lands on --spine-text,
   * and every ruled block on --spine-box, so one vertical line runs from the
   * first drawer to the footer. */
  --rail:150px;
  --spine-box:calc(var(--rail) + 1px);
  --spine-text:calc(var(--rail) + 17px);
  --rail-h:56px;
  --measure:62ch;

  --ease-out:cubic-bezier(.22,1,.36,1);
  --ease-io:cubic-bezier(.65,0,.35,1);
  --ease-press:cubic-bezier(.34,1.4,.64,1);

  --f-disp:'Fraunces',Georgia,'Times New Roman',serif;
  --f-read:'Charis SIL',Georgia,'Times New Roman',serif;
  --f-mono:'Martian Mono',ui-monospace,SFMono-Regular,Menlo,monospace;
  /* Charis first so accented Latin sets in the reading face; the Noto faces
   * pick up only what it lacks; the system emoji font takes the 102
   * characters no bundled outline would ever be asked to draw. */
  --f-glyph:'Charis SIL','Noto Sans Symbols 2','Noto Sans Symbols',
            'Noto Sans Math','Noto Sans Mono','Noto Sans','Noto Sans Thai',
            'Noto Sans Runic','Noto Sans Canadian Aboriginal','Noto Sans JP',
            'Apple Color Emoji','Segoe UI Emoji','Noto Color Emoji',serif;

  color-scheme:light;
}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]){
    --paper:#0B0B0C; --paper-raised:#151517; --paper-sunk:#08080A;
    --rule:#2A2A2D;  --rule-strong:#46464A; --rule-control:#6E6E72;
    --ink:#F2F2F0;   --ink-2:#B4B4B1; --ink-3:#90908E;
    --spot:#FF3D97;
    color-scheme:dark;
  }
}
:root[data-theme="dark"]{
  --paper:#0B0B0C; --paper-raised:#151517; --paper-sunk:#08080A;
  --rule:#2A2A2D;  --rule-strong:#46464A; --rule-control:#6E6E72;
  --ink:#F2F2F0;   --ink-2:#B4B4B1; --ink-3:#90908E;
  --spot:#FF3D97;
  color-scheme:dark;
}
/* A theme change is not an animation. Without this every cell mid-ebb
 * animates its background across the swap. */
html.swapping *,html.swapping *::before,html.swapping *::after{transition:none!important}

/* ------------------------------------------------------------------ base */
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html{-webkit-text-size-adjust:100%;max-width:100%;overflow-x:hidden}
body{
  background:var(--paper);color:var(--ink);
  font:400 16px/1.6 var(--f-read);
  -webkit-font-smoothing:antialiased;
  max-width:100%;overflow-x:hidden;
  padding-bottom:calc(var(--rail-h) + 20px);
}
img{max-width:100%}
[hidden]{display:none!important}
a{color:var(--ink);text-decoration:underline;text-underline-offset:2px;
  text-decoration-thickness:1px;text-decoration-color:var(--rule-strong)}
a:hover{text-decoration-color:var(--spot)}
:focus-visible{outline:2px solid var(--ink);outline-offset:2px}
.wrap{max-width:1320px;margin:0 auto;padding-inline:24px}
.skip-link{position:absolute;left:-9999px;top:0;background:var(--ink);color:var(--paper);
  padding:10px 16px;font:500 12px/1 var(--f-mono);z-index:99}
.skip-link:focus{left:8px;top:8px}
.vh{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}

/* ---------------------------------------------------------------- header
 * One row, at every width that can hold one. The rail used to carry three
 * locale chips beside three counts beside the toggle, which overflowed the
 * flex line at EVERY width from 768 to 1440 and wrapped the whole right-hand
 * group onto a second row: the header was 117px tall on a 1440px screen and
 * had never once rendered as designed. The chips are now one <select> and the
 * counts stand down before the line can break, in that order. */
.site-header{border-bottom:1px solid var(--rule)}
.header-inner{display:flex;align-items:center;gap:20px;flex-wrap:wrap;
  padding-block:18px 16px}   /* never a shorthand here: .wrap owns the sides */
.logo{display:flex;align-items:center;gap:10px;text-decoration:none;flex-shrink:0}
.logo svg{display:block;color:var(--ink)}
.wordmark{font:600 24px/1 var(--f-disp);font-variation-settings:'opsz' 60,'WONK' 1,'SOFT' 0;
  letter-spacing:-.01em;position:relative;color:var(--ink)}
.wordmark::after{content:"";position:absolute;left:0;right:-6px;bottom:-5px;height:1px;background:var(--spot)}
.main-nav{margin-left:4px;min-width:0}
.nav-list{display:flex;gap:18px;list-style:none}
.nav-list a{font:500 11px/1 var(--f-mono);font-variation-settings:'wdth' 87.5;
  letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3);text-decoration:none;
  border-bottom:1px solid transparent;padding-bottom:3px;white-space:nowrap;
  transition:color 90ms linear,border-color 90ms linear}
.nav-list a:hover{color:var(--ink);border-bottom-color:var(--spot)}
.nav-list a[aria-current="page"]{color:var(--ink);border-bottom-color:var(--ink)}
.nav-list a[aria-current="page"]:hover{border-bottom-color:var(--spot)}
.header-counts{margin-left:auto;display:flex;align-items:center;gap:14px;
  font:400 11px/1 var(--f-mono);font-variation-settings:'wdth' 87.5;
  letter-spacing:.04em;color:var(--ink-3);flex-shrink:0}
.header-counts .count{white-space:nowrap}
.theme-toggle{font:500 11px/1 var(--f-mono);letter-spacing:.08em;background:none;
  border:1px solid var(--rule-control);color:var(--ink-2);padding:8px 11px;cursor:pointer;
  transition:border-color 90ms linear,color 90ms linear}
.theme-toggle:hover{border-color:var(--spot);color:var(--ink)}
.mobile-menu-btn{display:none}

/* ------------------------------------------------------------------ tray
 * The only surface on the page that changes between visits. It sits above
 * the case precisely so the case can promise never to move. */
.tray{border-bottom:2px solid var(--rule-strong);background:var(--paper-raised)}
.tray-in{display:flex;align-items:center;gap:16px;flex-wrap:wrap;padding-block:12px 13px}
.tray-lab{font:500 10px/1 var(--f-mono);letter-spacing:.14em;color:var(--ink-3);
  text-transform:uppercase;white-space:nowrap}
.tray-set{display:flex;gap:2px;min-height:44px}
.tray-set .cell{width:44px;height:44px;border:1px solid var(--rule)}
.tray-set .cell .g{font-size:21px}
.tray-sep{width:1px;align-self:stretch;background:var(--rule);min-height:32px}
.tray-empty{font:400 12px/1.4 var(--f-mono);font-variation-settings:'wdth' 87.5;color:var(--ink-3)}

/* ------------------------------------------------------------------ case */
.case{display:grid;grid-template-columns:150px minmax(0,1fr);align-items:start}
.cabinet{position:sticky;top:0;padding:24px 20px 24px 0;
  font:500 10px/2.15 var(--f-mono);font-variation-settings:'wdth' 87.5;
  letter-spacing:.09em;text-transform:uppercase;max-height:100vh;overflow-y:auto}
.cabinet .ttl{color:var(--ink);letter-spacing:.14em;margin-bottom:10px}
.cabinet a{display:block;color:var(--ink-3);text-decoration:none;
  border-bottom:1px solid transparent;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cabinet a:hover{color:var(--ink);border-bottom-color:var(--spot)}
.cabinet a.on{color:var(--ink);border-bottom-color:var(--spot)}
.drawers{border-left:1px solid var(--rule);background:var(--paper-sunk);min-width:0;overflow:hidden}

.dlabel{position:sticky;top:0;z-index:5;background:var(--paper);
  display:flex;align-items:baseline;gap:12px;padding:15px 0 9px 16px;
  border-bottom:2px solid var(--rule-strong)}
.dlabel h2,.dlabel h3{font:400 21px/1 var(--f-disp);
  font-variation-settings:'opsz' 40,'WONK' 1;letter-spacing:-.005em}
.dlabel .n{font:500 10px/1 var(--f-mono);font-variation-settings:'wdth' 87.5;
  color:var(--ink-3);letter-spacing:.1em}
.dlabel .hint{margin-left:auto;padding-right:4px;font:400 10px/1.3 var(--f-mono);
  font-variation-settings:'wdth' 87.5;color:var(--ink-3);letter-spacing:.05em;text-align:right}

/* --------------------------------------------------------- compartments */
/* The three tiers do not tile 14 columns evenly, so a dense flow always
 * leaves slots over: 16 of 112 in the first drawer on the home page, 16 of
 * 168 in the second. Those slots were showing the drawer floor, which is a
 * darker paper than a compartment, so the tail of every drawer read as a
 * hole punched in the case rather than as the end of the run. The grid
 * carries the compartment paper itself now; a leftover slot is blank, not
 * missing. */
.grid{display:grid;grid-template-columns:repeat(14,minmax(0,1fr));
  grid-auto-rows:var(--u);grid-auto-flow:dense;
  background:var(--paper-raised);
  border-top:1px solid var(--rule);border-left:1px solid var(--rule);
  margin-bottom:34px}
/* border:0 is load-bearing. A <button> keeps its user-agent border on any
 * edge you do not set, which is invisible on paper and a glowing white
 * outline on every cell in dark mode. */
.cell{
  position:relative;background:var(--paper-raised);
  border:0;border-right:1px solid var(--rule);border-bottom:1px solid var(--rule);
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  cursor:pointer;user-select:none;padding:0;font:inherit;color:inherit;
  text-align:center;overflow:hidden;-webkit-tap-highlight-color:transparent;
  transition:opacity 140ms var(--ease-out);
}
.cell::before{content:"";position:absolute;inset:0 0 auto 0;height:1px;
  background:var(--spot);opacity:0;transition:opacity 90ms linear}
.cell:hover::before,.cell:focus-visible::before{opacity:1}
.cell:focus-visible{outline:2px solid var(--ink);outline-offset:-2px;z-index:3}
.g{font-family:var(--f-glyph);font-size:30px;line-height:1;color:var(--ink);display:block;
  transition:transform 90ms var(--ease-out),color 400ms var(--ease-io)}
.cell:hover .g,.cell:focus-visible .g{transform:scale(1.08)}
.cell .nm{font:400 10px/1.25 var(--f-disp);font-variation-settings:'opsz' 14;
  color:var(--ink-2);margin-top:7px;padding:0 6px;max-width:100%;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cell .wc{font:500 9px/1 var(--f-mono);font-variation-settings:'wdth' 75;
  color:var(--ink-3);letter-spacing:.02em;margin-top:4px}

.t-a{grid-column:span 2;grid-row:span 2}
.t-a .g{font-size:56px}
.t-a .nm{font-size:11px;margin-top:10px;white-space:normal;line-height:1.2}
.t-b{grid-column:span 2}
.t-b .nm{display:none}
.t-b .wc{position:absolute;right:7px;bottom:6px;margin:0}
.t-c .nm,.t-c .wc{display:none}

/* copy: a held state, not an animation. See DESIGN.md section 7. */
.cell.press .g{transform:scale(.94);transition:transform 60ms var(--ease-io)}
/* Ink hits paper. The compartment fills solid and the glyph is knocked out
 * of it, which is what a press does and what a tint never looks like. */
.cell.copied{background:var(--ink)}
.cell.copied .g,.cell.copied .nm,.cell.copied .wc{color:var(--paper)}
.cell.pop .g{transform:scale(1.06);transition:transform 110ms var(--ease-press)}
.cell.ebb{transition:background 400ms var(--ease-io)}
.cell.dim{opacity:.16}

/* ------------------------------------------------------- accents matrix
 * 424 accented characters are a table, not a list. An empty compartment is
 * information: no such character exists. */
.mxwrap{overflow-x:auto;margin-bottom:34px;-webkit-overflow-scrolling:touch}
.mx{display:grid;grid-template-columns:46px repeat(var(--mx-cols,10),minmax(58px,1fr));
  border-top:1px solid var(--rule);border-left:1px solid var(--rule);
  min-width:640px;background:var(--paper-sunk)}
.mx>div{border-right:1px solid var(--rule);border-bottom:1px solid var(--rule);
  min-height:48px;display:flex;align-items:center;justify-content:center;
  background:var(--paper-raised)}
.mx .hd{font:500 9px/1.15 var(--f-mono);font-variation-settings:'wdth' 75;
  color:var(--ink-3);text-transform:uppercase;letter-spacing:.05em;
  background:var(--paper);padding:6px 3px;text-align:center}
.mx .rh{font:400 15px/1 var(--f-disp);color:var(--ink-2);background:var(--paper)}
.mx .none{background:var(--paper-sunk);cursor:default}
.mx .cell{border:0;width:100%;height:100%}

/* ----------------------------------------------------------- search bar */
.sift{display:flex;align-items:center;gap:14px;padding:16px 0;border-bottom:1px solid var(--rule)}
.sift input{flex:1;min-width:0;background:var(--paper-raised);border:1px solid var(--rule-control);
  color:var(--ink);font:400 15px/1 var(--f-read);padding:12px 14px}
.sift input:focus{outline:none;border-color:var(--spot);box-shadow:inset 0 0 0 1px var(--spot)}
.sift input::placeholder{color:var(--ink-3)}
.sift .hint{font:400 10px/1.4 var(--f-mono);font-variation-settings:'wdth' 87.5;
  color:var(--ink-3);letter-spacing:.05em;white-space:nowrap}
/* Search dims, it never filters, never reorders and never rebuilds. A
 * character's coordinates are a published promise. */
.sift-count{font:500 10px/1 var(--f-mono);color:var(--ink-2);letter-spacing:.1em}
.sift-more{font:500 10px/1 var(--f-mono);color:var(--ink);letter-spacing:.1em;
  text-decoration:none;border-bottom:1px solid var(--ink);padding-bottom:2px;white-space:nowrap}
/*  --spot has four sanctioned uses and this is not one of them: a search
    that found nothing is not an accent-worthy event.  */
.sift-more:hover{color:var(--ink);border-bottom-color:var(--spot)}

/* ------------------------------------------------------------ page head */
.phead{padding:34px 0 6px;max-width:74ch}
.phead h1{font:400 44px/1.08 var(--f-disp);
  font-variation-settings:'opsz' 100,'WONK' 1,'SOFT' 20;
  letter-spacing:-.022em;margin-bottom:14px}
.phead .lede{font:400 19px/1.55 var(--f-read);color:var(--ink-2);max-width:64ch}
/* On a guide page the hero is question, answer, provenance, in that order.
   The answer takes full-strength ink because it is the thing the page is
   named after; the formal Unicode name that used to hold this slot is
   provenance, so it drops to a caption rather than competing at the same
   size and weight. Only when both are present: a hub page has a lede and no
   answer, and keeps its lede. */
.phead .lead{font:400 20px/1.5 var(--f-read);color:var(--ink);
  max-width:64ch;margin-top:2px}
.phead .lead + .lede{font:500 10px/1.5 var(--f-mono);
  font-variation-settings:'wdth' 87.5;letter-spacing:.1em;text-transform:uppercase;
  color:var(--ink-3);margin-top:12px}
.phead .lead kbd{font:500 15px/1 var(--f-mono);border:1px solid var(--rule-control);
  padding:2px 6px;background:var(--paper-raised);white-space:nowrap}
.phead .meta{margin-top:14px;font:500 10px/1 var(--f-mono);letter-spacing:.12em;
  text-transform:uppercase;color:var(--ink-3);display:flex;gap:18px;flex-wrap:wrap}

/* --------------------------------------------------------- reading rail
 * One fixed readout. No popover, no tooltip, no toast, anywhere on the site. */
.rail{position:fixed;left:0;right:0;bottom:0;height:var(--rail-h);z-index:40;
  background:var(--paper);border-top:2px solid var(--ink)}
.rail-in{max-width:1320px;margin:0 auto;padding-inline:24px;height:100%;
  display:grid;grid-template-columns:300px 92px 124px 132px 124px 1fr;align-items:center}
.fld{padding-right:14px;min-width:0}
.fld .k{font:500 8px/1 var(--f-mono);font-variation-settings:'wdth' 75;
  letter-spacing:.16em;color:var(--ink-3);text-transform:uppercase;display:block;margin-bottom:5px}
.fld .v{font:500 12px/1 var(--f-mono);font-variation-settings:'wdth' 87.5;
  color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.fld.name .v{font:400 15px/1.2 var(--f-disp);font-variation-settings:'opsz' 20;
  white-space:normal;max-height:2.4em}
.fld .v.nil{color:var(--ink-3)}
/* A code that needs a registry change is not a code you can type. Saying so
 * in the rail is the whole reason the verdict is computed. */
.fld .v.hexonly{color:var(--ink-3)}
.fld .v.hexonly::after{content:" needs regedit";font-size:9px;letter-spacing:.06em;color:var(--spot)}
.rail .st{justify-self:end;padding-left:16px;font:500 11px/1 var(--f-mono);
  letter-spacing:.16em;color:var(--spot);opacity:0;transition:opacity 400ms var(--ease-io)}
.rail .st.on{opacity:1;transition:none}

/* --------------------------------------------------------------- manual
 * The prose is unchanged. Only its clothes are. */
.brk{height:2px;background:var(--ink);margin-top:66px}
.manual{padding:52px 0 80px;display:grid;grid-template-columns:150px minmax(0,var(--measure))}
.manual .num{font:500 10px/2.1 var(--f-mono);color:var(--ink-3);letter-spacing:.1em}
.manual h2{font:400 30px/1.18 var(--f-disp);font-variation-settings:'opsz' 48,'WONK' 1;
  letter-spacing:-.014em;margin:0 0 16px}
.manual h3{font:400 22px/1.25 var(--f-disp);font-variation-settings:'opsz' 32,'WONK' 1;
  letter-spacing:-.008em;margin:34px 0 12px}
.manual h4{font:500 10px/1 var(--f-mono);letter-spacing:.14em;text-transform:uppercase;
  color:var(--ink-3);margin:28px 0 10px}
.manual p{font:400 17px/1.65 var(--f-read);margin:0 0 17px}
.manual ul,.manual ol{margin:0 0 17px 20px}
.manual li{font:400 17px/1.65 var(--f-read);margin-bottom:7px}
.manual table{border-collapse:collapse;width:100%;margin:0 0 20px;
  font:500 13px/1.5 var(--f-mono);font-variation-settings:'wdth' 87.5}
.manual .tablewrap{overflow-x:auto;margin-bottom:20px}
.manual th,.manual td{border:1px solid var(--rule);padding:8px 11px;text-align:left}
.manual th{font-weight:600;color:var(--ink-3);text-transform:uppercase;
  font-size:9px;letter-spacing:.12em}
.manual kbd{font:500 12px/1 var(--f-mono);border:1px solid var(--rule);
  padding:3px 6px;background:var(--paper-raised)}

/* card grids inside the manual: the category explainers */
.cardset{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));
  gap:0;border-top:1px solid var(--rule);border-left:1px solid var(--rule);margin-bottom:24px}
.cardset .card{border-right:1px solid var(--rule);border-bottom:1px solid var(--rule);
  padding:16px 18px;background:var(--paper-raised)}
.cardset .card h4{margin:0 0 7px;font:400 17px/1.2 var(--f-disp);
  font-variation-settings:'opsz' 22;color:var(--ink);text-transform:none;letter-spacing:0}
.cardset .card .n{font:500 9px/1 var(--f-mono);color:var(--ink-3);letter-spacing:.1em}
.cardset .card p{font:400 14px/1.55 var(--f-read);color:var(--ink-2);margin:8px 0 0}

/* FAQ: a details list, not an accordion widget */
.faq{border-top:1px solid var(--rule)}
.faq details{border-bottom:1px solid var(--rule)}
.faq summary{cursor:pointer;padding:15px 0;list-style:none;
  font:400 18px/1.35 var(--f-disp);font-variation-settings:'opsz' 24;display:flex;gap:14px}
.faq summary::-webkit-details-marker{display:none}
.faq summary::before{content:"+";color:var(--ink-3);font:500 14px/1.45 var(--f-mono);flex-shrink:0}
.faq details[open] summary::before{content:"\2212"}
.faq p{padding:0 0 16px 28px;font:400 16px/1.62 var(--f-read);color:var(--ink-2);max-width:var(--measure)}

/* colophon: indie studios sign their work, and it is the best E-E-A-T on the page */
.colophon{font:400 13px/1.75 var(--f-mono);font-variation-settings:'wdth' 87.5;
  color:var(--ink-3);border-top:1px solid var(--rule);padding-top:20px;margin-top:38px}
.colophon b{color:var(--ink-2);font-weight:500}

/* ------------------------------------------------------- tools / guides */
.toolset{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));
  border-top:1px solid var(--rule);border-left:1px solid var(--rule);margin:0 0 40px}
.toolset a{border-right:1px solid var(--rule);border-bottom:1px solid var(--rule);
  padding:24px 22px 26px;background:var(--paper-raised);text-decoration:none;display:block}
.toolset a:hover{background:var(--paper);box-shadow:inset 0 1px 0 0 var(--spot)}
.toolset h2{font:400 24px/1.15 var(--f-disp);font-variation-settings:'opsz' 34,'WONK' 1;
  margin-bottom:9px;letter-spacing:-.01em}
.toolset p{font:400 15px/1.55 var(--f-read);color:var(--ink-2);margin-bottom:14px}
.toolset .go{font:500 10px/1 var(--f-mono);letter-spacing:.14em;text-transform:uppercase;color:var(--ink)}

.guidelist{border-top:1px solid var(--rule);margin-bottom:34px}
.guidelist a{display:grid;grid-template-columns:52px minmax(0,1fr) auto;align-items:center;
  gap:16px;border-bottom:1px solid var(--rule);padding:13px 8px 13px 0;text-decoration:none}
.guidelist a:hover{background:var(--paper-raised);box-shadow:inset 2px 0 0 0 var(--spot)}
.guidelist .g{font-size:24px;text-align:center}
.guidelist .t{font:400 17px/1.3 var(--f-read)}
.guidelist .c{font:500 10px/1 var(--f-mono);font-variation-settings:'wdth' 87.5;color:var(--ink-3);letter-spacing:.06em}

/* one guide page: the character is the hero, the codes are a table */
.spec{display:grid;grid-template-columns:180px minmax(0,1fr);gap:0;
  border-top:1px solid var(--rule);border-left:1px solid var(--rule);margin-bottom:34px}
.spec .face{border-right:1px solid var(--rule);border-bottom:1px solid var(--rule);
  background:var(--paper-raised);display:flex;align-items:center;justify-content:center;
  min-height:180px;padding:20px}
.spec .face .g{font-size:96px}
/* margin:0 because .rows is a <dl> now, not a <div>: the dt/dd pairs inside
   it were never in one, which is invalid HTML. The UA default on dl is
   margin:1em 0 and it would shift this rail visibly. */
.spec .rows{margin:0;border-bottom:1px solid var(--rule);border-right:1px solid var(--rule);
  background:var(--paper-raised)}
.spec .row{display:grid;grid-template-columns:132px minmax(0,1fr);
  border-bottom:1px solid var(--rule);align-items:baseline}
.spec .row:last-child{border-bottom:0}
.spec .row dt{font:500 9px/1 var(--f-mono);letter-spacing:.14em;text-transform:uppercase;
  color:var(--ink-3);padding:14px 16px}
.spec .row dd{font:500 14px/1 var(--f-mono);font-variation-settings:'wdth' 87.5;padding:14px 16px 14px 0}
.spec .row dd.nil{color:var(--ink-3)}
.spec .note{font-size:10px;color:var(--spot);letter-spacing:.06em;margin-left:8px}
.btn-copy{font:500 10px/1 var(--f-mono);letter-spacing:.14em;text-transform:uppercase;
  background:var(--ink);color:var(--paper);border:0;padding:12px 18px;cursor:pointer}
.btn-copy:hover{background:var(--spot)}

/* --------------------------------------------------------------- footer */
.site-footer{border-top:1px solid var(--rule);margin-top:8px}
/* The language row. Carries the wrap measurements itself so the template can
   drop it in or leave it out without an empty ruled box either way. */
.langrow{max-width:1320px;margin:0 auto;padding-inline:24px;
  display:flex;align-items:baseline;gap:18px;flex-wrap:wrap;
  padding-block:18px;border-bottom:1px solid var(--rule)}
.langrow-lab{font:500 10px/1 var(--f-mono);letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink-3)}
.langrow a{font:500 12px/1 var(--f-mono);font-variation-settings:'wdth' 87.5;
  color:var(--ink-2);text-decoration:none;border-bottom:1px solid transparent;
  padding-bottom:3px;transition:color 90ms linear,border-color 90ms linear}
.langrow a:hover{color:var(--ink);border-bottom-color:var(--spot)}
@media (max-width:640px){.langrow{padding-inline:16px;gap:14px}}
.site-footer .wrap{display:flex;gap:24px;align-items:baseline;flex-wrap:wrap;padding-block:22px 30px}
.footer-copyright{font:400 11px/1.5 var(--f-mono);font-variation-settings:'wdth' 87.5;color:var(--ink-3)}
.footer-nav{margin-left:auto;display:flex;gap:20px;list-style:none}
.footer-nav a{font:500 10px/1 var(--f-mono);letter-spacing:.1em;text-transform:uppercase;
  color:var(--ink-3);text-decoration:none}
.footer-nav a:hover{color:var(--ink);text-decoration:underline;
  text-underline-offset:3px;text-decoration-color:var(--spot)}

/* --------------------------------------------------------------- spine
 * One left edge per page, for every heading and every rule under one.
 *
 * Measured before this rule existed, on one 1280px viewport: section labels
 * began at x=24 ("the three cases", "how-to guides"), x=175 (the drawer
 * labels, pushed by the 150px cabinet column), x=298 (the accents matrix),
 * x=385 (`/keyboards`, where .tool-content centred itself) and x=48. Five
 * edges, and the 2px rule under each heading started at a different place,
 * which is what reads as a title stopping halfway across the page.
 *
 * The case owns the spine: where there is a cabinet, everything below it
 * lines up past the cabinet, and .manual already did. Where there is no
 * cabinet - a guide, a keyboard page, an article - the spine is the wrap
 * edge and nothing is indented at all. Two registers, never five.
 */
@media (min-width:1101px){
  /*  A .wrap child starts at the wrap's own 24px and takes the spine on top
      of it. A .container IS a wrap - it carries the 24px itself - so it takes
      24px plus the spine. Both land on the same pixel, which is the point.
      A heading takes --spine-text, a ruled block --spine-box, because the
      drawer label already hangs 16px over the grid it labels and the whole
      exercise is to repeat that relationship, not to flatten it. */
  /*  margin, not padding, on anything that draws a rule. A drawer label's
      2px rule starts at the label's BOX and its text hangs 16px inside it;
      padding moved the text and left the rule at the page edge, which is the
      same "title stops halfway" reading in reverse. One box edge at
      --spine-box, and every label keeps its own 16px hang. */
  main:has(.case) .wrap > .dlabel,
  main:has(.case) .wrap > .toolset,
  main:has(.case) .wrap > .guidelist,
  main:has(.case) .wrap > .gridg,
  main:has(.case) .wrap > .plain-list,
  main:has(.case) .wrap > .guide-group,
  main:has(.case) .wrap > .section-more{margin-left:var(--spine-box)}
  main:has(.case) .section > .container{padding-left:calc(24px + var(--spine-box))}
  main:has(.case) .section > .container.tool-content{
    max-width:calc(24px + var(--spine-box) + var(--measure) + 24px)}
  /*  The hard rule before the manual is a full-bleed divider by design and
      is the one thing that deliberately crosses the spine. */
  main:has(.case) .wrap > .brk{padding-left:0}
}

/* ------------------------------------------------------------ responsive
 * The header sheds in a fixed order, and each step is measured rather than
 * guessed: counts first (the same three numbers are printed on the page
 * itself), then the nav drops to its own line. Nothing is allowed to wrap
 * on its own. */
@media (max-width:1239px){
  .header-counts .count{display:none}
}
/*  The second line is a layout, not a failure, and two things ask for it.
 *
 *  One is width. The other is language: measured at 1280px, the nav is
 *  494px in English, 728px in Spanish, 860px in German and 920px in French.
 *  The wrap caps at 1320px, so 1272px is the widest this row can ever be,
 *  and 175px of logo plus a 920px nav plus the controls does not fit inside
 *  it at any viewport size. A localised site would therefore have wrapped on
 *  some screens and not others, which is the accidental break this whole
 *  change is undoing. Those three take the ruled second row at every width
 *  instead, on purpose and predictably. English keeps the single row. */
html:not([lang="en"]) .main-nav,
.main-nav.stacked{order:3;flex-basis:100%;margin-left:0;margin-top:2px;
  padding-top:12px;border-top:1px solid var(--rule)}
/*  Only above the phone breakpoint: below it the nav is one scrolling strip
    in every language, and this selector outranks the plain `.nav-list` there
    by two classes, which is how the French header stayed 197px tall after
    the strip was written. */
@media (min-width:641px){
  html:not([lang="en"]) .nav-list{gap:20px;flex-wrap:wrap}
}
@media (max-width:959px){
  .main-nav{order:3;flex-basis:100%;margin-left:0;margin-top:2px;
    padding-top:12px;border-top:1px solid var(--rule)}
  .nav-list{gap:20px;flex-wrap:wrap}
  .header-inner{gap:14px;padding-block:16px 12px}
}
@media (max-width:1100px){
  .case{grid-template-columns:minmax(0,1fr)}
  .cabinet{display:none}
  .drawers{border-left:0}
  .grid{grid-template-columns:repeat(10,minmax(0,1fr))}
  .manual{grid-template-columns:minmax(0,1fr)}
  .manual .num{display:none}
  .rail-in{grid-template-columns:minmax(0,1fr) 84px 124px auto}
  .rail .fld:nth-child(4),.rail .fld:nth-child(5){display:none}
  .phead h1{font-size:36px}
}
@media (max-width:640px){
  .wrap{padding-inline:16px}
  /* The keyboard hint is nowrap and was refusing to shrink, which squeezed
     the input to a 56px box. There is no "/" key on a phone anyway. */
  .sift{flex-wrap:wrap;gap:8px}
  .sift input{flex:1 1 100%;font-size:16px}   /* 16px stops iOS zooming on focus */
  .sift .hint{display:none}
  .grid{grid-template-columns:repeat(6,minmax(0,1fr))}
  .t-a .g{font-size:40px}
  .t-a .nm{font-size:9px}
  .dlabel{padding-left:10px;flex-wrap:wrap;gap:8px}
  .dlabel .hint{margin-left:0;flex-basis:100%;text-align:left}
  /* the header was pushing the first drawer off a 390px screen */
  .header-inner{gap:12px;padding-block:14px 10px}
  .wordmark{font-size:20px}
  /*  One line that scrolls, not three lines that wrap. Wrapping put the
      header at 143px in English and 197px in French on a 390px screen -
      a quarter of the viewport spent on chrome before the reader sees a
      single character. Every link stays in the markup and in the tab
      order; only the ones past the edge need a swipe, and the fade says
      so. The page body still never scrolls sideways: this strip has its
      own scroller, which is the same exception tables get. */
  .main-nav{margin-left:0;order:3;width:100%;padding-top:10px;
    position:relative;min-width:0}
  .main-nav::after{content:"";position:absolute;right:0;bottom:0;top:10px;
    width:28px;pointer-events:none;
    background:linear-gradient(to right,transparent,var(--paper))}
  .nav-list{gap:18px;flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;
    -webkit-overflow-scrolling:touch;padding-right:24px}
  .nav-list::-webkit-scrollbar{display:none}
  .nav-list a{font-size:10px}
  .header-counts{margin-left:auto;gap:8px}
  /*  `.header-counts span` was a descendant selector and reached into the
      locale control, which is why the switcher rendered as empty boxes on
      every phone for as long as the chips existed. Only the counts go. */
  .header-counts > .count{display:none}  /* the counts are on the page itself */
  .locswitch select{padding:7px 22px 7px 9px}
  .tray-in{padding-block:9px 10px;gap:12px}
  .phead{padding-top:22px}
  .phead .lede{font-size:17px}
  .rail{height:52px}
  .rail-in{grid-template-columns:minmax(0,1fr) auto;padding-inline:16px}
  .rail .fld:nth-child(3){display:none}
  .spec{grid-template-columns:minmax(0,1fr)}
  .spec .face .g{font-size:72px}
  .phead h1{font-size:30px}
  .toolset,.cardset{grid-template-columns:minmax(0,1fr)}
}

/* ------------------------------------------------------- reduced motion
 * The wash, the 640ms hold and the 400ms ebb survive. They are the only
 * confirmation channel, so removing them would remove the confirmation
 * rather than the motion. */
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  .g,.cell::before{transition:none!important;transform:none!important}
  .cell:hover .g,.cell:focus-visible .g,.cell.press .g,.cell.pop .g{transform:none!important}
  .cell.ebb{transition:background 400ms linear}
}

@media print{
  .rail,.tray,.cabinet,.theme-toggle,.sift{display:none}
  body{padding-bottom:0;background:#fff;color:#000}
}

/* ================================================================ manual
 * The long-form sections below the hard rule.
 *
 * build.py emits these class names unchanged from the previous design, on
 * purpose: D3 in DESIGN.md promised the SEO prose would keep the same words,
 * the same headings and the same internal links, so only the clothes change.
 * Restyling here rather than rewriting the generators is what keeps that
 * promise literally true.
 */
.section{padding:0}
.seo-content,.popular-section{padding-top:8px}
.container{max-width:1320px;margin:0 auto;padding-inline:24px}
/* .container centres itself because it is a 1320px wrapper. .prose and
 * .tool-content then narrow max-width to the measure, and the auto margins
 * go on centring - which put the <h1> of /about, /keyboards and /how-to at
 * x=385 while their own header and footer sat at x=24. Nothing on this site
 * is centred; see the .text-center override below, which says so. */
.container.prose,.container.tool-content{margin-inline:0}
/* .wrap and .container are the same wrapper under two names, and the guide
 * pages nest one inside the other. Two 24px gutters is 48px, which is where
 * "Symbols related to Euro Sign" sat while the <h1> above it sat at 24. The
 * inner one is already inside a gutter; it does not need its own. */
.wrap .container{padding-inline:0;max-width:none}
/* Left-aligned, never centred. `margin:0 auto` put the heading of every
 * long-form section 361px from the page edge on /keyboards and /how-to,
 * while the header, the footer and every other heading on the same page sat
 * at 24px. The gutter it was carrying inside its own max-width is real, but
 * it belongs to the spine rule below, where the case can switch it off. */
.tool-content{max-width:calc(var(--measure) + 24px);margin-inline:0;
  padding-block:44px 8px}
.section-title{font:400 30px/1.18 var(--f-disp);
  font-variation-settings:'opsz' 48,'WONK' 1;letter-spacing:-.014em;margin:0 0 16px}
.subsection-title{font:400 22px/1.25 var(--f-disp);
  font-variation-settings:'opsz' 32,'WONK' 1;letter-spacing:-.008em;margin:34px 0 12px}
.tool-content p{font:400 17px/1.65 var(--f-read);margin:0 0 17px;max-width:var(--measure)}
.tool-content ul,.tool-content ol{margin:0 0 17px 20px;max-width:var(--measure)}
.tool-content li{font:400 17px/1.65 var(--f-read);margin-bottom:7px}
.secondary-text{color:var(--ink-2)}
.text-center{text-align:left}          /* nothing on this page is centred */
.mb-4{margin-bottom:16px}.mb-6{margin-bottom:24px}.mt-8{margin-top:32px}

/* the popular strip reads as a shallow drawer, not a card grid */
.popular-symbols-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(96px,1fr));
  border-top:1px solid var(--rule);border-left:1px solid var(--rule);margin-bottom:26px}
.popular-symbol-item{border-right:1px solid var(--rule);border-bottom:1px solid var(--rule);
  background:var(--paper-raised);padding:16px 8px;text-align:center;text-decoration:none;display:block}
.popular-symbol-item:hover{background:var(--paper);box-shadow:inset 0 1px 0 0 var(--spot)}
.popular-symbol-char{display:block;font-family:var(--f-glyph);font-size:32px;line-height:1;color:var(--ink)}
.popular-symbol-name{display:block;margin-top:9px;font:400 11px/1.3 var(--f-disp);
  font-variation-settings:'opsz' 14;color:var(--ink-2)}

/* numbered steps: the number hangs in the margin like a manual */
.how-to-steps{margin:0 0 26px;max-width:var(--measure)}
.step-item{display:grid;grid-template-columns:44px minmax(0,1fr);gap:0 16px;
  padding:16px 0;border-bottom:1px solid var(--rule)}
.step-item:first-child{border-top:1px solid var(--rule)}
.step-number{font:500 11px/1.6 var(--f-mono);color:var(--ink-3);letter-spacing:.1em}
.step-title{font:400 18px/1.35 var(--f-disp);font-variation-settings:'opsz' 24;margin-bottom:5px}
.step-desc{font:400 16px/1.6 var(--f-read);color:var(--ink-2);margin:0}

/* category explainers and the alternate-method list: ruled compartments */
.category-descriptions,.alt-methods-grid{display:grid;
  grid-template-columns:repeat(auto-fit,minmax(260px,1fr));
  border-top:1px solid var(--rule);border-left:1px solid var(--rule);margin-bottom:26px}
.category-desc-item,.alt-method-item{border-right:1px solid var(--rule);
  border-bottom:1px solid var(--rule);padding:16px 18px;background:var(--paper-raised)}
.category-desc-item h3,.alt-method-title{font:400 17px/1.25 var(--f-disp);
  font-variation-settings:'opsz' 22;margin:0 0 8px;color:var(--ink)}
.category-desc-item p,.alt-method-desc{font:400 14px/1.55 var(--f-read);
  color:var(--ink-2);margin:0;max-width:none}

/* FAQ */
.faq-container{border-top:1px solid var(--rule);margin-bottom:26px;max-width:var(--measure)}
.faq-item{border-bottom:1px solid var(--rule);padding:15px 0}
.faq-question{font:400 18px/1.35 var(--f-disp);font-variation-settings:'opsz' 24;
  margin:0 0 8px;display:flex;gap:12px}
.faq-question::before{content:"?";color:var(--ink-3);font:500 13px/1.5 var(--f-mono);flex-shrink:0}
.faq-answer{font:400 16px/1.62 var(--f-read);color:var(--ink-2);margin:0 0 0 25px;max-width:none}

/* related tools */
.related-tools-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));
  border-top:1px solid var(--rule);border-left:1px solid var(--rule);margin-bottom:34px}
.related-tool-card{border-right:1px solid var(--rule);border-bottom:1px solid var(--rule);
  padding:18px 20px;background:var(--paper-raised);text-decoration:none;display:block}
.related-tool-card:hover{background:var(--paper);box-shadow:inset 0 1px 0 0 var(--spot)}
.tool-name{font:400 19px/1.2 var(--f-disp);font-variation-settings:'opsz' 26;
  margin:0 0 7px;color:var(--ink)}
.tool-desc{font:400 14px/1.55 var(--f-read);color:var(--ink-2);margin:0;max-width:none}

/* guide pages */
.shortcut-table{border-collapse:collapse;width:100%;margin:0 0 26px;
  font:500 13px/1.5 var(--f-mono);font-variation-settings:'wdth' 87.5}
.shortcut-table caption{text-align:left;font:500 9px/1 var(--f-mono);letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink-3);padding-bottom:10px}
.shortcut-table th,.shortcut-table td{border:1px solid var(--rule);padding:9px 12px;
  text-align:left;vertical-align:top}
.shortcut-table thead th{font-size:9px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-3)}
.shortcut-table td:last-child{font:400 14px/1.5 var(--f-read);color:var(--ink-2)}
.shortcut-table code{font:500 13px/1 var(--f-mono);background:var(--paper-sunk);padding:2px 5px}
.related-grid{display:flex;flex-wrap:wrap;gap:2px;margin-bottom:18px}
.related-chip{width:52px;height:52px;display:flex;align-items:center;justify-content:center;
  border:1px solid var(--rule);background:var(--paper-raised);font-family:var(--f-glyph);
  font-size:22px;text-decoration:none;color:var(--ink)}
.related-chip:hover{border-color:var(--spot);color:var(--ink);background:var(--paper)}
.section-more{font:500 10px/1 var(--f-mono);letter-spacing:.12em;text-transform:uppercase}
/* The language switch in the header.
 *
 * This was three <a> chips, one per other language, each carrying a flag
 * emoji and a two-letter code. Three faults, all of them shipped:
 *   - three chips is ~230px of a header that had no room for one, and they
 *     were the reason the whole right-hand group wrapped to a second row
 *   - `.header-counts span{display:none}` below 640px is a DESCENDANT
 *     selector, so on every phone it also hid `.flag` and `.lc` and the
 *     chips rendered as three empty bordered boxes
 *   - a flag is not a language, and Windows ships no glyph for a regional
 *     indicator pair, which the old comment here admitted
 * One native <select> answers all three. It is one control at every width,
 * it opens as the platform's own picker on a phone, and the endonym is the
 * label, so a reader looks for the word they already use.
 */
.locswitch{display:inline-flex;align-items:center;position:relative}
.locswitch select{appearance:none;-webkit-appearance:none;
  border:1px solid var(--rule-control);background:var(--paper);color:var(--ink-2);
  font:500 10px/1 var(--f-mono);letter-spacing:.1em;text-transform:uppercase;
  padding:8px 24px 8px 10px;cursor:pointer;border-radius:0;
  transition:border-color 90ms linear,color 90ms linear}
.locswitch::after{content:"";position:absolute;right:9px;top:50%;
  width:5px;height:5px;margin-top:-4px;pointer-events:none;
  border-right:1px solid currentColor;border-bottom:1px solid currentColor;
  transform:rotate(45deg);color:var(--ink-3)}
.locswitch:hover select,.locswitch select:focus-visible{border-color:var(--spot);color:var(--ink)}
.locswitch:hover::after{color:var(--spot)}
.locswitch select:focus-visible{outline:2px solid var(--ink);outline-offset:2px}
/* An example glyph inside a table. The character is the whole point of the
   cell, so it takes the glyph face at reading size instead of the body font
   the other columns use. */
.shortcut-table td.ex{font-family:var(--f-glyph);font-size:20px;color:var(--ink);
  text-align:center}
/* A line said under a table rather than over it: where the numbers came from,
   or the one instruction that would be pompous as a heading. */
.section-note{font:400 13px/1.6 var(--f-read);color:var(--ink-3);margin:6px 0 18px}
/* A list of links that is a list of places, not prose. Bullets add nothing. */
.plain-list{list-style:none;padding:0;margin:0 0 22px}
.plain-list li{border-bottom:1px solid var(--rule);padding:10px 0}
.plain-list a{font:500 15px/1.4 var(--f-read)}
/* kbd is styled inside .manual already; the keyboard pages are prose. */
.prose kbd{font:500 12px/1 var(--f-mono);border:1px solid var(--rule);
  background:var(--paper-raised);padding:3px 6px}
.breadcrumb{font:500 10px/1 var(--f-mono);letter-spacing:.12em;text-transform:uppercase;
  color:var(--ink-3);margin-bottom:14px}
.guide-group{margin-bottom:30px}
.guide-group-title{font:400 21px/1 var(--f-disp);font-variation-settings:'opsz' 30,'WONK' 1;
  padding-bottom:9px;border-bottom:2px solid var(--rule-strong);margin-bottom:0}
.guide-list{list-style:none;border-top:0}
.guide-list li{border-bottom:1px solid var(--rule)}
.guide-list a{display:block;padding:11px 4px;text-decoration:none;font:400 16px/1.4 var(--f-read)}
.guide-list a:hover{background:var(--paper-raised);box-shadow:inset 2px 0 0 0 var(--spot)}

/* --------------------------------------------------------- the page index
 * The prose column is the reading measure, 62ch, inside a 1320px wrap, so on
 * a wide screen it left roughly 800px of empty page down its right. That does
 * not read as a measure held on purpose, it reads as a column that stopped.
 *
 * The case answers this on its own pages with a sticky index of the drawers
 * down the left. This is that object again for prose: the section's own
 * headings, set in the margin the prose was not using. case.js builds it from
 * the headings already in the markup, and only where there are at least three
 * of them, so short pages are untouched and no generator has to know.
 *
 * Below 1180px there is no spare margin, so there is no rail: the index is
 * hidden rather than stacked, because a list of links between a heading and
 * its own first paragraph is worse than scrolling.
 */
.pagenav{display:none}
@media (min-width:1180px){
  /*  Three columns: the measure, air, the index. Putting the index straight
      after the prose only moved the empty space further right; sending it to
      the far edge turns the same two blocks into a spread that holds the
      whole width, which is what the page is actually asking for. */
  .section > .container.tool-content,
  .section > .container.prose{
    display:grid;
    grid-template-columns:minmax(0,var(--measure)) minmax(40px,1fr) 220px;
    /*  The container goes back to being the site's 1320px band, centred like
        the header and the footer, and the MEASURE moves to the first grid
        column where it belongs.
        `.container.prose{margin-inline:0}` further up exists to stop a column
        narrowed to 62ch from centring itself in a 1320px box - the bug that
        put /about's <h1> at x=385. Once the width is a column rather than a
        max-width on the container, that problem is gone and the rule is
        actively wrong: it left the prose at x=24 while the header sat at
        x=324. So it is reversed here, above 1180px only. */
    max-width:1320px;
    margin-inline:auto;
  }
  .section > .container.tool-content > *,
  .section > .container.prose > *{grid-column:1;min-width:0}
  /*  Both selectors, and both at least as specific as the `> *` rule above:
      `.pagenav` alone is one class against that rule's two plus a child
      combinator, so it lost and the rail rendered in the prose column. */
  .section > .container.tool-content > .pagenav,
  .section > .container.prose > .pagenav{display:block;grid-column:3;grid-row:1 / 200;
    position:sticky;top:24px;align-self:start;justify-self:end;
    width:220px;padding-left:20px;border-left:1px solid var(--rule)}
  /*  Not uppercase mono. These are whole sentences - "What Degree Symbol is
      used for" - and set in caps at 10px every one of them wrapped to three
      lines and the rail read as a wall. Sentence case in the reading face
      scans the way the headings it points at do. */
  .pagenav ol{list-style:none;margin:0;padding:0;
    font:400 13px/1.45 var(--f-read)}
  .pagenav li{margin-bottom:9px}
  .pagenav::before{content:"";display:block;width:18px;height:1px;
    background:var(--rule-strong);margin:0 0 12px -20px}
  .pagenav a{display:block;color:var(--ink-3);text-decoration:none;
    border-left:2px solid transparent;margin-left:-22px;padding-left:20px;
    transition:color 90ms linear,border-color 90ms linear}
  .pagenav a:hover{color:var(--ink);border-left-color:var(--spot)}
  /* Where you are, in the spot colour, the same as the active drawer in the
     cabinet. It is a position, not a hover, which is the one other thing
     --spot is allowed to mark. */
  .pagenav a.on{color:var(--ink);border-left-color:var(--spot)}
  /* A table or a wide grid inside the prose column may still run full width;
     it has its own scroller and the rail must not collide with it. */
  .tool-content .tablewrap,.tool-content .category-descriptions,
  .tool-content .alt-methods-grid{max-width:100%}
}

/* ------------------------------------------------------------- how-to hub
 * The ten places a reader might be typing. These four class names were
 * emitted by the build and had NO CSS behind them at all, so the page
 * rendered as ten underlined links run together into one paragraph, each
 * followed by its monthly search volume. Compartments, like the rest of the
 * site: ruled, not boxed, and the name carries the card.
 */
.hub{padding-block:44px 8px}
.hub .tool-title,.hub .lead,.hub .section-note{max-width:var(--measure)}
.hub .lead{margin-bottom:26px}
.hub .section-note{margin-top:18px}
.category-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(232px,1fr));
  border-top:1px solid var(--rule);border-left:1px solid var(--rule);
  background:var(--paper-raised);margin-bottom:4px}
.cat-card{position:relative;display:flex;align-items:center;min-height:84px;
  padding:16px 20px;text-decoration:none;background:var(--paper-raised);
  border-right:1px solid var(--rule);border-bottom:1px solid var(--rule);
  overflow:hidden}
.cat-card::before{content:"";position:absolute;inset:0 0 auto 0;height:1px;
  background:var(--spot);opacity:0;transition:opacity 90ms linear}
.cat-card:hover::before,.cat-card:focus-visible::before{opacity:1}
.cat-card:hover{background:var(--paper)}
.cat-card:focus-visible{outline:2px solid var(--ink);outline-offset:-2px;z-index:3}
.cat-name{font:400 20px/1.22 var(--f-disp);font-variation-settings:'opsz' 28;
  color:var(--ink)}
@media (max-width:640px){
  .category-grid{grid-template-columns:repeat(2,minmax(0,1fr))}
  .cat-card{padding:14px 13px 15px}
  .cat-name{font-size:16px}
}

/* static pages: about, privacy, contact, 404 */
.prose{max-width:var(--measure);padding-block:44px 60px}
.prose h1{font:400 40px/1.1 var(--f-disp);
  font-variation-settings:'opsz' 90,'WONK' 1,'SOFT' 20;letter-spacing:-.02em;margin-bottom:16px}
.prose h2{font:400 24px/1.25 var(--f-disp);font-variation-settings:'opsz' 32,'WONK' 1;margin:32px 0 12px}
.prose p,.prose li{font:400 17px/1.65 var(--f-read);margin-bottom:16px}
.prose ul,.prose ol{margin-left:20px}
.lead{font:400 19px/1.55 var(--f-read);color:var(--ink-2)}
.tool-title{font:400 40px/1.1 var(--f-disp);
  font-variation-settings:'opsz' 90,'WONK' 1,'SOFT' 20;letter-spacing:-.02em;margin-bottom:12px}
.tool-subtitle{font:400 19px/1.55 var(--f-read);color:var(--ink-2);margin-bottom:20px}
.guide-hero{padding-block:36px 0}
.guide-char-display{font-family:var(--f-glyph);font-size:96px;line-height:1;margin-bottom:18px}
.hidden{display:none}

/* ------------------------------------------------------- guide drawers
 * The guides index is a case too, but its compartments navigate instead of
 * copying, so they get their own class: case.js copies anything matching
 * .cell on pointerdown and would otherwise swallow the link.
 *
 * Wider than a symbol compartment on purpose. Here the name is what you
 * scan for, not the glyph, so the glyph sits in a fixed gutter at the left
 * and the name gets the room.
 */
.gridg{display:grid;grid-template-columns:repeat(auto-fill,minmax(236px,1fr));
  border-top:1px solid var(--rule);border-left:1px solid var(--rule);margin-bottom:34px}
.gcell{display:grid;grid-template-columns:62px minmax(0,1fr);align-items:center;
  min-height:72px;background:var(--paper-raised);text-decoration:none;color:var(--ink);
  border-right:1px solid var(--rule);border-bottom:1px solid var(--rule);
  position:relative;overflow:hidden}
.gcell::before{content:"";position:absolute;inset:0 0 auto 0;height:1px;
  background:var(--spot);opacity:0;transition:opacity 90ms linear}
.gcell:hover::before,.gcell:focus-visible::before{opacity:1}
.gcell:hover{background:var(--paper)}
.gcell:focus-visible{outline:2px solid var(--ink);outline-offset:-2px;z-index:3}
.gcell .g{font-size:30px;text-align:center;border-right:1px solid var(--rule);
  height:100%;display:flex;align-items:center;justify-content:center}
.gcell:hover .g{color:var(--ink)}
.gcell .tx{padding:10px 12px;min-width:0}
/* Two lines rather than an ellipsis: "Ballot Box with Check" is the whole
   point of the row, and "Ballot Box with Ch..." is not an answer. */
.gcell .nm{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
  font:400 14px/1.25 var(--f-disp);font-variation-settings:'opsz' 18;
  color:var(--ink);overflow:hidden}
.gcell .wc{display:block;margin-top:5px;font:500 9px/1 var(--f-mono);
  font-variation-settings:'wdth' 75;letter-spacing:.05em;color:var(--ink-3)}
.gcell.dim{opacity:.16;transition:opacity 140ms var(--ease-out)}
@media (max-width:640px){
  /* One column at 312 rows is a list again, which is the thing we replaced.
     Two, with a narrower gutter and the name allowed three lines. */
  .gridg{grid-template-columns:repeat(2,minmax(0,1fr))}
  .gcell{grid-template-columns:44px minmax(0,1fr);min-height:66px}
  .gcell .g{font-size:22px}
  .gcell .tx{padding:8px 9px}
  .gcell .nm{font-size:13px;-webkit-line-clamp:3}
}

/*  The invisible-characters table. A copy button whose character draws nothing
    would be an invisible button, so the slot carries the word instead and the
    dashes say "there is something here to take". */
.blank-slot{font:600 12px/1 var(--mono,ui-monospace,monospace);letter-spacing:.04em;
  text-transform:uppercase;opacity:.75}
.cell:has(.blank-slot){min-width:5.5rem;border-style:dashed}
.cell:has(.blank-slot):hover,.cell:has(.blank-slot):focus-visible{border-style:solid}
.cell:has(.blank-slot) .blank-slot{opacity:1}

.inv-item{border-top:1px solid var(--rule);padding:1.1rem 0}
.inv-head{display:flex;align-items:center;gap:.6rem;flex-wrap:wrap;margin:0 0 .2rem}
.inv-head .inv-name{font-weight:600}
.inv-width{margin:.1rem 0 .6rem;opacity:.7;font-size:.92em}
.cell.inv-copy{display:inline-flex;min-width:5rem;height:2rem;border:1px dashed var(--rule);
  border-radius:2px;margin-left:auto}
.cell.inv-copy:hover,.cell.inv-copy:focus-visible{border-style:solid}

/*  A button that reads as a link, for the PNG rasteriser beside the SVG link. */
.linkish{background:none;border:0;padding:0;font:inherit;color:inherit;
  text-decoration:underline;text-underline-offset:2px;cursor:pointer}

/* ------------------------------------------------------------- consent
 * One small card above the rail, never over it: the rail is the readout and
 * a banner that covers it hides the thing the page is for. [hidden] is
 * restated because .consent sets display, and a class selector outranks the
 * user-agent rule that hidden relies on. */
.consent{position:fixed;right:16px;bottom:calc(var(--rail-h) + 12px);z-index:50;
  max-width:420px;display:flex;flex-direction:column;gap:14px;padding:16px 18px;
  background:var(--paper-raised);color:var(--ink);border:2px solid var(--ink)}
.consent[hidden]{display:none}
.consent p{font:400 14px/1.5 var(--f-read);margin:0}
.consent p a{color:var(--ink);text-decoration-color:var(--spot);text-underline-offset:3px}
.consent-actions{display:flex;gap:10px;flex-wrap:wrap}
.consent-actions button{font:500 11px/1 var(--f-mono);letter-spacing:.1em;text-transform:uppercase;
  padding:10px 14px;cursor:pointer;border:1px solid var(--ink);background:none;color:var(--ink)}
.consent-actions button[data-consent="granted"]{background:var(--ink);color:var(--paper)}
.consent-actions button:hover{border-color:var(--spot)}
.consent-actions button[data-consent="granted"]:hover{background:var(--spot);border-color:var(--spot)}
.consent-actions button:focus-visible{outline:2px solid var(--spot);outline-offset:2px}
@media (max-width:640px){.consent{left:16px;right:16px;max-width:none}}
.footer-consent{font:500 10px/1 var(--f-mono);letter-spacing:.1em;text-transform:uppercase;
  color:var(--ink-3);background:none;border:0;padding:0;cursor:pointer}
.footer-consent:hover{color:var(--ink);text-decoration:underline;
  text-underline-offset:3px;text-decoration-color:var(--spot)}
