/* The main site's stylesheet (newmediaxp-www assets/css/style.css), its regions: fonts, tokens, base, header, footer, shared bits, 404, responsive.
   Written by scripts/build-assets.mjs: change it in www. */

/*#region fonts (self-hosted, latin subset; variable fonts, each range = the weights the site uses, up to bold 700 so
   <strong> and <b> get the real weight: the files hold more (Roboto and Roboto Slab 100-900, JetBrains Mono 400-800),
   and a weight outside a range is faked by the browser) */
@font-face { font-family: 'JetBrains Mono'; font-style: normal; font-weight: 500 700; font-display: swap; src: url(/assets/fonts/jetbrains-mono-latin.woff2) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Roboto'; font-style: normal; font-weight: 400 700; font-display: swap; src: url(/assets/fonts/roboto-latin.woff2) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Roboto Slab'; font-style: normal; font-weight: 400 700; font-display: swap; src: url(/assets/fonts/roboto-slab-latin.woff2) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
/*#endregion*/

/*#region tokens */
:root {
  color-scheme: light;

  --chrome: linear-gradient(hsl(250 50% 30%), hsl(200 50% 30%));          /* header */
  --chrome-reverse: linear-gradient(hsl(200 50% 30%), hsl(250 50% 30%));  /* footer + mobile menu */
  --chrome-text: hsl(180 100% 80%);
  --chrome-name: hsl(0 0% 100%); /* the header wordmark */
  --chrome-line: hsl(180 100% 80% / .22);
  --chrome-hover: hsl(180 100% 80% / .12);

  --px-red: hsl(0 100% 50%);
  --px-green: hsl(120 100% 45%);
  --px-blue: hsl(240 100% 58%);

  /* light (default) */
  --bg: hsl(170 74% 88%);
  --text: hsl(230 40% 9%);
  --muted: hsl(230 24% 26%);
  --faint: hsl(230 14% 38%);
  --link: hsl(240 100% 35%);
  --chip-bg: hsl(70 100% 20%);
  --chip-ink: hsl(70 100% 90%);
  /* --btn-*, --card-hover, --hl-mark, --yellow-*, --pager-current-*, --grey-* … come from palette.css */
  --ring: var(--link); /* keyboard focus */
  --grey-outline: rgb(255 255 255 / .45); /* .btn__logo's ring in a grey button: its text colour, dulled */
  --glint: hsl(0 0% 100% / .45);           /* the shine on button shadows: dimmer on the near-black light-mode shadows */
  --art-shadow: drop-shadow(0 12px 18px hsl(230 60% 14% / .3)); /* icons: follows each icon's own shape */
  --line: hsl(250 50% 30% / .2);
  --surface: hsl(168 70% 97% / .62);
  --shadow: 0 14px 30px -18px hsl(200 70% 12% / .7);
  --page-glow:
    radial-gradient(70vmax 46vmax at 22% 30%, hsl(180 100% 95% / .7), #0000 70%),
    radial-gradient(56vmax 40vmax at 92% 8%, hsl(60 100% 80% / .3), #0000 70%);
  --error: hsl(0 85% 42%);
  --error-bg: hsl(0 100% 50% / .12);
  --solid-bg: hsl(168 70% 98%); /* an opaque --surface: text boxes, the sudoku board */
  /* the sudoku board: lines between squares and boxes, the selected square's row / column / box, its number elsewhere */
  --board-line: hsl(230 40% 9% / .14);
  --board-box: hsl(230 40% 9% / .8);
  --board-peer: hsl(240 100% 35% / .06);
  --board-same: hsl(240 100% 35% / .15);

  --font-head: "Roboto Slab", Georgia, serif;
  --font-body: Roboto, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, Consolas, monospace;
  --wrap: 1180px; /* page content */
  --site: 1600px; /* the header and footer */
  --ease: cubic-bezier(.2, .8, .2, 1);
}

[data-theme="dark"] {
  color-scheme: dark;
  --bg: hsl(230 74% 10%);
  --text: hsl(150 60% 80%);
  --muted: hsl(158 28% 70%);
  --faint: hsl(170 16% 58%);
  --link: hsl(240 100% 85%);
  --chip-bg: hsl(70 50% 50%);
  --chip-ink: hsl(230 74% 8%);
  --grey-outline: rgb(22 22 22 / .45);
  --glint: hsl(0 0% 100% / .85);
  --art-shadow: drop-shadow(0 14px 22px hsl(0 0% 0% / .55));
  --line: hsl(180 100% 80% / .14);
  --surface: hsl(232 58% 15% / .62);
  --shadow: 0 16px 32px -18px hsl(0 0% 0% / .9);
  --page-glow:
    radial-gradient(70vmax 46vmax at 24% 30%, hsl(250 60% 24% / .5), #0000 70%),
    radial-gradient(56vmax 40vmax at 92% 8%, hsl(200 60% 24% / .4), #0000 70%);
  --error: hsl(0 100% 72%);
  --error-bg: hsl(0 100% 60% / .16);
  --solid-bg: hsl(232 58% 13%);
  --board-line: hsl(180 100% 80% / .13);
  --board-box: hsl(150 60% 80% / .75);
  --board-peer: hsl(240 100% 85% / .07);
  --board-same: hsl(240 100% 85% / .17);
}
/*#endregion*/

/*#region base */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; background: var(--bg); }
@media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }
body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  font: 400 1rem/1.55 var(--font-body);
  color: var(--text);
  background: var(--page-glow), var(--bg);
  overflow-x: hidden;
  overflow-x: clip;
  -webkit-font-smoothing: antialiased;
}
img, svg { display: block; max-width: 100%; }
img { height: auto; }
[hidden] { display: none !important; }
a { color: var(--link); }
/* every page title is sized like the article title (the 404 digits are art and set their own) */
h1 { font: 700 clamp(2rem, 1.4rem + 2.2vw, 3rem)/1.06 var(--font-head); letter-spacing: -.015em; }
:focus-visible { outline: 2px solid var(--ring); outline-offset: 3px; }

.wrap { width: min(100% - 48px, var(--wrap)); margin-inline: auto; }
.top__bar, .foot__bar, .wrap--wide { --wrap: var(--site); } /* .wrap--wide: front matter wide: true, or a section of its own */
main { flex: 1 0 auto; }
.top, main, .foot { position: relative; z-index: 1; }
.top { z-index: 10; }

/* hidden above the page by its own height: it wraps on very narrow screens, so a fixed offset could let it peek out */
.skip {
  position: absolute; left: 12px; top: 0; z-index: 20;
  max-width: calc(100% - 24px);
  padding: 10px 14px; border-radius: 8px;
  background: var(--chrome); color: var(--chrome-text);
  transform: translateY(-100%);
}
.skip:focus { top: 12px; transform: none; }
.skip:focus-visible { outline-color: var(--chrome-text); } /* drawn over the header chrome */

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
/*#endregion*/

/*#region header */
.top { background: var(--chrome); color: var(--chrome-text); box-shadow: 0 1px 0 hsl(250 100% 20%); }
.top :focus-visible { outline-color: var(--chrome-text); }
.top__bar { display: flex; align-items: center; gap: 20px; height: 64px; }

.brand { display: flex; align-items: center; gap: 11px; color: var(--chrome-name); flex: none; } /* the wordmark draws in this colour */
.brand__logo { width: 44px; height: 44px; transition: filter .15s; }
/* two masked layers; ::before = the wordmark, ::after = the glitch ghost behind it (logo hover) */
.brand__word {
  position: relative;
  /* 26px tall: "New Media XP" 566×64 → 230px, "NMX" 184×64 → 74.8px (end of file). Explicit width for iOS 14 and older */
  --word-img: url(/assets/img/nmx-wordmark.png);
  height: 26px;
  width: 230px;
  isolation: isolate; /* keeps the ghost (z -1) inside the wordmark box, above the header bar */
}
.brand__word::before,
.brand__word::after {
  content: "";
  position: absolute; inset: 0;
  -webkit-mask: var(--word-img) center / contain no-repeat;
  mask: var(--word-img) center / contain no-repeat;
}
.brand__word::before { background: currentColor; }
.brand__word::after { z-index: -1; background: var(--px-red); opacity: 0; }

.brand__home:hover .brand__logo { filter: drop-shadow(0 0 4px hsl(0 0% 100%)); }
.brand__home:hover + .brand__word::after { opacity: .9; animation: nmx-glitch-ghost .48s steps(1) infinite; }
.brand__home:hover + .brand__word::before { animation: nmx-glitch-main .36s steps(1) infinite; }
@keyframes nmx-glitch-ghost {
  0%   { transform: translate(-2px, 1px);  background: var(--px-red); }
  25%  { transform: translate(2px, -1px);  background: var(--px-blue); }
  50%  { transform: translate(-1px, -1px); background: var(--px-green); }
  75%  { transform: translate(2px, 1px);   background: var(--px-red); }
}
@keyframes nmx-glitch-main {
  0%   { transform: none; }
  33%  { transform: translate(1px, 0); }
  66%  { transform: translate(-1px, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .brand__home:hover + .brand__word::after { opacity: 0; } /* glow only (the animations stop at the end of the file) */
}

.nav { margin-left: auto; }
.nav ul { display: flex; gap: 2px; margin: 0; padding: 0; list-style: none; }
.nav a {
  position: relative;
  display: block;
  padding: 8px 14px;
  border-radius: 8px;
  color: var(--chrome-text);
  font: 600 1.125rem/1.55 var(--font-head);
  text-decoration: none;
  transition: background-color .15s;
}
.nav a:hover { background: var(--chrome-hover); }
.nav a[aria-current]::after {
  content: "";
  position: absolute; left: 14px; right: 14px; bottom: 3px;
  height: 2px;
  background: var(--chrome-text);
}

.top__actions { display: flex; gap: 6px; }
.icon-btn {
  display: grid; place-items: center;
  width: 40px; height: 40px;
  padding: 0;
  border: 2px solid var(--chrome-line);
  border-radius: 10px;
  background: transparent;
  color: var(--chrome-text);
  cursor: pointer;
  transition: background-color .15s;
}
.icon-btn:hover { background: var(--chrome-hover); }
.i-sun { display: none; }
[data-theme="dark"] .i-sun { display: block; }
[data-theme="dark"] .i-moon { display: none; }
.nav-btn { display: none; }
.nav-btn path { transform-box: fill-box; transform-origin: center; transition: transform .2s, opacity .15s; }
.top.is-open .nav-btn .l1 { transform: translateY(5px) rotate(45deg); }
.top.is-open .nav-btn .l2 { opacity: 0; }
.top.is-open .nav-btn .l3 { transform: translateY(-5px) rotate(-45deg); }
/*#endregion*/

/*#region footer */
.foot { background: var(--chrome-reverse); color: var(--chrome-text); font-size: .9rem; }
.foot :focus-visible { outline-color: var(--chrome-text); }
.foot__bar { display: flex; align-items: center; gap: 12px 28px; min-height: 56px; padding-block: 10px; }
.foot__copyright { margin: 0; color: rgba(255, 255, 255, .6); }
.foot__links { display: flex; flex-wrap: wrap; gap: 6px 20px; margin: 0 0 0 auto; padding: 0; list-style: none; }
.foot a, .foot__links button { color: var(--chrome-text); font-family: var(--font-head); text-decoration: none; }
.foot a:hover, .foot__links button:hover { text-decoration: underline; text-underline-offset: 3px; }
.foot__links button { padding: 0; border: 0; background: none; font-size: inherit; line-height: inherit; cursor: pointer; }
.foot__own { line-height: 0; } /* the web app's own doc (base-page.pug); no taller line, so the links stay level */
/*#endregion*/

/*#region shared bits */
/* a highlighter stroke behind the lower ~40% of the text */
.hl {
  margin-inline: -.06em;
  padding-inline: .12em;
  border-radius: .3em .12em .3em .12em;
  background: linear-gradient(transparent 55%, var(--hl-mark) 55% 95%, transparent 95%);
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

/* link-colour fill; hover = half pressed */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 46px; padding: 0 20px;
  border: 0;
  border-radius: 10px;
  background: var(--btn-bg);
  color: var(--btn-ink);
  box-shadow: 4px 4px 0 var(--btn-shadow);
  font: 500 1rem/1 var(--font-body);
  text-decoration: none;
  cursor: pointer;
  transition: transform .15s, box-shadow .15s, background-color .2s;
}
.btn { max-width: 20rem; } /* no button is wider than 320px: one that fills its row or window stops there */
.btn:hover { transform: translate(2px, 2px); box-shadow: 2px 2px 0 var(--btn-shadow); }
.btn:active { transform: translate(3px, 3px); box-shadow: 1px 1px 0 var(--btn-shadow); }
.btn svg { flex: none; transition: transform .15s; }
/* the arrow after a link button's text (icons.pug +linkIcon) moves the way it points */
.btn:hover .arrow { transform: translateX(3px); }
.btn:hover .arrow--out { transform: translate(2px, -2px); }
.btn:hover .arrow--down { transform: translateY(3px); }
.btn:hover .arrow--up { transform: translateY(-3px); }
.btn .arrow--out, .btn .arrow--down, .btn .arrow--up { margin-inline: -3px; } /* turned, the arrow is narrower than its box */
/* a 1px inner edge in each button's pixel-shadow colour, so edge and shadow read as one block;
   on ::after so it moves with the press */
.btn, .pager__step, .pager__num { position: relative; }
.btn { --edge: var(--btn-shadow); }
.pager__step, .pager__num { --edge: var(--yellow-shadow); } /* --edge, not --ring: --ring is the keyboard focus colour */
.btn::after, .pager__step::after, .pager__num::after {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  box-shadow: inset 0 0 0 1px var(--edge);
  pointer-events: none;
}
/* glint: a white arc + dash 1px inside the pixel shadow's rounded bottom-right corner, concentric with it
   (--corner = button radius, --depth = shadow offset). Hidden when pressed: a 1px shadow has no side to shine */
.btn { --corner: 10px; }
.pager__step, .pager__num { --corner: 8px; }
.btn, .pager__step, .pager__num { --depth: 4px; }
.btn:hover, .pager a[href]:hover { --depth: 2px; }
.btn::before, .pager__step::before, .pager__num::before, .share__social a::before, .range__knob::before {
  content: "";
  position: absolute;
  z-index: 1; /* above the share icons' filtered image, which paints as its own layer */
  right: calc(1px - var(--depth));
  bottom: calc(1px - var(--depth));
  width: calc(2 * var(--corner) - 2px);
  height: calc(2 * var(--corner) - 2px);
  border: 1.5px solid transparent;
  border-right-color: var(--glint);
  border-bottom-color: var(--glint);
  border-radius: 50%;
  /* two wedges from the centre: 20°–55° (edge points tan 20° → 68.2%, cot 55° → 85%) and 63°–74° (cot → 75.5%, 64.3%) */
  -webkit-clip-path: polygon(50% 50%, 100% 68.2%, 100% 100%, 85% 100%, 50% 50%, 75.5% 100%, 64.3% 100%);
  clip-path: polygon(50% 50%, 100% 68.2%, 100% 100%, 85% 100%, 50% 50%, 75.5% 100%, 64.3% 100%);
  pointer-events: none;
  transition: right .15s, bottom .15s, opacity .15s;
}
.btn:active::before, .pager a[href]:active::before,
.pager__num[aria-current]::before, .pager__step[aria-disabled="true"]::before, .btn--off::before, .btn:disabled::before,
.share__social a:active::before, .range__track:active .range__knob::before { opacity: 0; }
.btn--green { --btn-bg: var(--green-bg); --btn-ink: var(--green-ink); --btn-shadow: var(--green-shadow); }
.btn--yellow { --btn-bg: var(--yellow-bg); --btn-ink: var(--yellow-ink); --btn-shadow: var(--yellow-shadow); }
.btn--orange { --btn-bg: var(--orange-bg); --btn-ink: var(--orange-ink); --btn-shadow: var(--orange-shadow); }
.btn--red { --btn-bg: var(--red-bg); --btn-ink: var(--red-ink); --btn-shadow: var(--red-shadow); }
.btn--grey { --btn-bg: var(--grey-bg); --btn-ink: var(--grey-ink); --btn-shadow: var(--grey-shadow); }
.btn--small {
  --corner: 8px;
  height: 42px; padding: 0 16px;
  border-radius: 8px;
  font-size: .92rem;
}
/* a site's logo first in a button */
.btn__logo { width: 20px; height: 20px; margin-left: -4px; border-radius: 5px; flex: none; box-shadow: 0 0 0 1px var(--grey-outline); }
.btn__logo--square { border-radius: 0; }
/* another site's logo (/assets/img/<name>-icon.svg): the SVG draws only the mark, the square behind it is painted here
   in that site's colours (white unless named). Forced colours would repaint the square under a white mark, so it
   keeps its own; hex, as each brand publishes it */
.site-logo { border-radius: 25%; background: #fff; forced-color-adjust: none; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
.site-logo--apple, .site-logo--github, .site-logo--threads, .site-logo--x { background: #000; }
.site-logo--appstore { background: linear-gradient(#18bffb, #2072f3); }
.site-logo--crazygames { background: #150d34; }
.site-logo--discord { background: #5865f2; }
.site-logo--facebook { background: #0866ff; }
.site-logo--gamejolt { background: linear-gradient(#2f7f6f, #ccff00); }
.site-logo--instagram { background: radial-gradient(circle at 25% 105%, #ffd600, #ff7a00 20%, #ff0069 45%, #d300c5 70%, #7638fa 95%); }
.site-logo--itch { background: #fa5c5c; }
.site-logo--linkedin { background: #0a66c2; }
.site-logo--npm { background: #c12127; }
.site-logo--pinterest { background: #e60023; }
.site-logo--reddit { background: #ff4500; }
.site-logo--twitter { background: #1d9bf0; }
.site-logo--youtube { background: #f5f5f5; }
/* unpublished (not a link), or a disabled button */
.btn.btn--off,
.btn.btn--off:hover,
.btn.btn--off:active,
.btn:disabled { opacity: .55; cursor: default; transform: translate(3px, 3px); box-shadow: 1px 1px 0 var(--btn-shadow); }
.btn .badge { background: var(--btn-ink); color: var(--btn-bg); }

.chip {
  display: inline-flex; align-items: center;
  padding: 5px 8px 4px;
  border-radius: 4px;
  background: var(--chip-bg);
  color: var(--chip-ink);
  font: 500 .68rem/1.2 var(--font-mono);
  letter-spacing: .08em;
  text-transform: uppercase;
  white-space: nowrap;
  text-decoration: none;
}
[data-theme="dark"] .chip { font-weight: 700; } /* dark letters on a light chip look thinner */
a.chip { position: relative; transition: transform .15s, box-shadow .15s; }
/* 3px of invisible tap area all round; the 6px gap between chips is shared exactly */
a.chip::before { content: ""; position: absolute; inset: -3px; }
a.chip:hover { transform: translateY(-1px); box-shadow: 0 0 0 2px var(--hl-mark); } /* the other theme's tag colour */
.chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; padding: 0; list-style: none; }

.link-buttons { display: flex; flex-wrap: wrap; gap: 12px; margin: 0; padding: 0; list-style: none; }
.badge {
  padding: 3px 5px 2px;
  border-radius: 3px;
  font: 500 .6rem/1.2 var(--font-mono);
  letter-spacing: .06em;
  text-transform: uppercase;
}

/* the site's text link. The hover underline is a bottom border, so it runs under the arrow too. Inline, so a link inside a sentence wraps with it; the arrow is drawn in the
   padding of a word joiner (U+2060), so it never wraps onto a line of its own */
.link-point {
  padding-bottom: .35em;
  border-bottom: 2px solid transparent;
  color: var(--link);
  /* no font-size: the text size around it, so a "Read more" after a paragraph matches it */
  font-weight: 500;
  text-decoration: none;
  margin-right: .25em; /* room between the arrow and the next word */
}
.link-point:hover { border-bottom-color: currentColor; }
.link-point::after,
.foot a[href^="http"]::after,
.foot a[href="#top"]::after,
.info-links__lines a[href^="http"]::after,
.info-links__lines a[href^="mailto:"]::after {
  --arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14M13 6l6 6-6 6'/%3E%3C/svg%3E");
  content: "\2060";
  position: relative; left: 0; top: 0;
  margin-left: .375em;
  padding-left: 1.125em;
  /* colour only under the arrow: Safari leaves an inline box unmasked outside its mask tile, and the text box is taller */
  background: linear-gradient(currentColor, currentColor) center / 1.125em 1em no-repeat;
  -webkit-mask: var(--arrow) center / 1.125em no-repeat;
  mask: var(--arrow) center / 1.125em no-repeat;
  forced-color-adjust: none; /* keeps the arrow in the (forced) link colour */
  transition: left .2s, top .2s;
  --dx: 3px; --dy: 0px;
}
.link-point[href^="http"]::after,
.foot a[href^="http"]::after,
.info-links__lines a[href^="http"]::after { --arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14M13 6l6 6-6 6' transform='rotate(-45 12 12)'/%3E%3C/svg%3E");
  margin-left: .45em; padding-left: .75em; --dx: 2px; --dy: -2px; } /* turned, the arrow is half as wide: a narrower box keeps the same gaps */
.link-point[href^="#"]::after { --arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14M13 6l6 6-6 6' transform='rotate(90 12 12)'/%3E%3C/svg%3E"); margin-left: .45em; padding-left: .75em; --dx: 0px; --dy: 3px; }
.link-point[href="#top"]::after,
.foot a[href="#top"]::after { --arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14M13 6l6 6-6 6' transform='rotate(-90 12 12)'/%3E%3C/svg%3E"); margin-left: .45em; padding-left: .75em; --dx: 0px; --dy: -3px; }
.link-point[href^="mailto:"]::after,
.info-links__lines a[href^="mailto:"]::after { --arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='5' width='18' height='14' rx='1.5'/%3E%3Cpath d='M3.5 6.5 12 13l8.5-6.5'/%3E%3C/svg%3E"); --dx: 0px; --dy: 0px; } /* an envelope */
/* an envelope hops once on hover, as if sent (it has no direction to move in) */
@keyframes nmx-mail-hop { 0%, 65%, 100% { top: 0; } 35% { top: -4px; } 82% { top: -1.5px; } }
.link-point[href^="mailto:"]:hover::after,
.info-links__lines a[href^="mailto:"]:hover::after,
.btn:hover .mail { animation: nmx-mail-hop .6s ease-out; }
.btn .mail { position: relative; }
.link-point:hover::after,
.foot a[href^="http"]:hover::after,
.foot a[href="#top"]:hover::after,
.info-links__lines a[href^="http"]:hover::after { left: var(--dx); top: var(--dy); }

.count {
  padding: 4px 7px;
  border-radius: 6px;
  box-shadow: inset 0 0 0 1px var(--line);
  color: var(--muted);
  font: 600 .72rem/1 var(--font-mono);
  letter-spacing: .08em;
}

/* a copy button (share.pug +copyButton): "Copied" for a moment after a click */
.copy__done { display: none; }
.copy.is-copied .copy__idle { display: none; }
.copy.is-copied .copy__done { display: inline; }

.error { color: var(--error); }

/* windows (native <dialog>, window.pug), framed in the share icons' outline colour */
.window {
  width: min(100% - 32px, 400px);
  padding: 0;
  overflow: auto; /* clips the title bar to the window's corners, and scrolls a tall window on a short screen */
  border: 2px solid var(--grey-shadow);
  border-radius: 18px;
  background: var(--page-glow), var(--bg);
  color: var(--text);
  box-shadow:
    0 0 0 3px var(--grey-shadow),
    0 28px 60px -22px hsl(230 60% 6% / .85);
}
.window::backdrop { background: hsl(230 60% 6% / .5); }
html:has(.window[open]) { overflow: hidden; } /* no page scroll behind it */
html:has(.window) { scrollbar-gutter: stable; } /* …without the page jumping sideways when the scrollbar goes */
/* the close button stays at the top right beside the title, which wraps onto more lines, its first line centred on
   the button (under 260px wide the button goes on a line of its own above the title: responsive region) */
.window__bar {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 12px;
  padding: 12px 14px 14px 20px; /* room below for the close button's pixel shadow */
  border-bottom: 2px solid var(--line);
}
.window h2 { margin: 0; font: 700 clamp(1.3rem, 1.15rem + .6vw, 1.6rem)/1.2 var(--font-head); overflow-wrap: anywhere; } /* the article headings' size */
.window__bar > h2 { flex: 1; min-width: 0; padding-top: calc((40px - 1.2em) / 2); }
/* square at the Share button's 40px height */
.window__close {
  --btn-bg: var(--red-bg); --btn-ink: var(--red-ink); --btn-shadow: var(--red-shadow);
  flex: none;
  width: 40px; height: 40px;
  margin-left: auto;
  padding: 0;
}
/* beside a red button (a "Yes, …" that deletes or clears), the close button, the safe way out, is green instead */
.window:has(.window__body .btn--red) .window__close { --btn-bg: var(--green-bg); --btn-ink: var(--green-ink); --btn-shadow: var(--green-shadow); }
.window__body { padding: 22px 22px 24px; }
/* a label too long for one line wraps, and its button grows to hold it */
.window__body .btn { height: auto; min-height: 46px; padding-block: 8px; line-height: 1.2; text-align: center; }
.window__body .btn--small { min-height: 42px; }
/* browsers without <dialog> (iOS < 15.4) would show every window on the page: hidden unless open */
.window:not([open]) { display: none; }

/* the Share button (share.pug) and the share window */
.btn--share { height: 40px; padding: 0 14px 0 16px; font-size: .95rem; }
.btn--share:hover svg { transform: translate(2px, -2px); }
.share__social { display: flex; flex-wrap: wrap; justify-content: center; gap: 12px; margin: 0; padding: 0; list-style: none; }
/* share icons: the button recipe with the grey button's shadow; zero-blur drop-shadows trace each icon's squircle */
.share__social a {
  --outline: drop-shadow(1px 0 0 var(--grey-shadow)) drop-shadow(-1px 0 0 var(--grey-shadow)) drop-shadow(0 1px 0 var(--grey-shadow)) drop-shadow(0 -1px 0 var(--grey-shadow));
  /* glint: squircle corner ≈ a 12.3px circle (measured from the icon alpha); the outline adds 1px to corner and depth */
  --corner: 13px; --depth: 5px;
  position: relative;
  display: block;
  border-radius: 28%; /* focus outline shape */
  transition: transform .15s;
}
/* the outline + pixel shadow sit on the image, so they don't also outline/shadow the glint (on the link) */
.share__social img { width: 48px; height: 48px; filter: var(--outline) drop-shadow(4px 4px 0 var(--grey-shadow)); transition: filter .15s; }
.share__social a:hover { transform: translate(2px, 2px); --depth: 3px; }
.share__social a:hover img { filter: var(--outline) drop-shadow(2px 2px 0 var(--grey-shadow)); }
.share__social a:active { transform: translate(3px, 3px); }
.share__social a:active img { filter: var(--outline) drop-shadow(1px 1px 0 var(--grey-shadow)); }
.share__copy { width: 100%; margin-top: 22px; }
/*#endregion*/

/*#region 404 */
.not-found {
  --pad: clamp(26px, 4vw, 44px);
  position: relative;
  overflow: hidden; /* clips the lights to the panel; their lamp bars sit on its top edge */
  max-width: 640px;
  margin: clamp(32px, 6vw, 72px) auto clamp(44px, 6vw, 80px);
  padding: var(--pad);
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--surface);
  text-align: center;
}
.not-found__code { position: relative; z-index: 0; width: fit-content; margin: 0 auto; }
/* the hero's stage lights, one per digit: the digits sit in three equal columns (centres 1/6, 1/2, 5/6) */
.not-found .beam { top: calc(-1 * var(--pad) - 1px); bottom: -8%; width: 46%; }
.not-found .beam--r { left: calc(100% / 6); }
.not-found .beam--g { left: 50%; }
.not-found .beam--b { left: calc(500% / 6); }
.not-found h1 {
  position: relative; z-index: 1;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  margin: 0;
  font: 700 clamp(5.5rem, 3.4rem + 10vw, 9.5rem)/1 var(--font-head);
  letter-spacing: normal;
}
.not-found h1 span { padding-inline: .04em; }
.not-found__text { margin: 12px 0 0; font: 700 clamp(1.4rem, 1.2rem + .8vw, 1.9rem)/1.2 var(--font-head); }
.not-found .btn { margin-top: clamp(22px, 3vw, 30px); }
/*#endregion*/

/*#region responsive */
@media (max-width: 1000px) {
  /* one card a row; the featured card takes the library cards' size, spacing and type */
  .library__grid { grid-template-columns: minmax(0, 1fr); gap: 22px; }
  .feature__card { --art: 200px; }
  .feature__body { padding: 12px 16px 14px; }
  .feature__meta { margin: 0 0 7px; }
  .feature__meta time { font-size: .72rem; }
  .feature__title { font: 700 clamp(1.15rem, 1.02rem + .35vw, 1.35rem)/1.2 var(--font-head); letter-spacing: -.01em; }
  .feature__sub { font: 600 1rem/1.3 var(--font-head); }
  .feature__desc { margin-top: 6px; font-size: .95rem; line-height: 1.4; }
  .feature__tags { padding-top: 8px; }
  .feature__tags .chip,
  .feature__meta .chip { font-size: .62rem; }
  .feature__card--product { --art: 132px; }
  .feature__card--product .feature__body { padding: 10px 14px 12px; }
  .feature__card--product .feature__meta { margin-bottom: 11px; }
  .feature__card--product .feature__desc { margin-top: 4px; }
}

@media (max-width: 720px) {
  .wrap { width: min(100% - 32px, var(--wrap)); }

  .foot__bar { flex-direction: column; justify-content: center; text-align: center; padding-block: 16px; } /* copyright above the links, always */
  .foot__links { justify-content: center; margin: 0; }

  /* home */
  .hero { padding: 28px 0 30px; }
  .hero__in { grid-template-columns: minmax(0, 1fr); gap: 18px; text-align: center; }
  .beam { top: -28px; }
  .hero__btns { justify-content: center; }

  /* blog */
  .page-head { padding-block: 22px 16px; }
}

@media (max-width: 600px) {
  /* pager compresses to ‹ 1 2 ›: labels stay for screen readers, 40px tap targets */
  .library__head { margin-bottom: 4px; }
  .library__head::after { flex-basis: 12px; }
  .pager { gap: 4px; }
  .pager__nums { gap: 4px; }
  .pager__step, .pager__num { min-width: 40px; height: 40px; }
  .pager__step { padding: 0; }
  .pager__label {
    position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
  .pager--foot { margin-top: 16px; }
  .library__grid { padding-top: 12px; }
  .card::after,
  .feature__card::after { box-shadow: 0 0 0 3px var(--card-hover), 0 12px 24px -12px hsl(230 60% 8% / .5); }

  /* narrow text column: a card grows taller than its image when the text needs it (the blur fills above and
     below the image), up to a cap of description lines */
  .card__desc,
  .feature__desc { -webkit-line-clamp: 6; }
  .card--nosub .card__desc,
  .feature__card--nosub .feature__desc { -webkit-line-clamp: 7; }
  .card--product .card__desc,
  .feature__card--product .feature__desc { -webkit-line-clamp: 4; }
}

/* under 600px ("not ≥600px": a fractional width under zoom or display scaling gets one layout or the other).
   Menu button: logo + "NMX" + links + theme button need ≈544px, plus the 16px margins and a 17px desktop scrollbar */
@media not all and (min-width: 600px) {
  .top__actions { margin-left: auto; }

  /* without JS the nav wraps to a second row; with JS it collapses behind the menu button */
  .top__bar { flex-wrap: wrap; gap: 12px; height: auto; min-height: 64px; }
  .nav { order: 3; width: 100%; margin: 0; }
  .nav ul { flex-wrap: wrap; padding-bottom: 8px; }

  .js .top__bar { flex-wrap: nowrap; height: 64px; }
  .js .nav-btn { display: grid; order: 2; margin-left: -6px; } /* shown after the theme button (first in the DOM for Tab order); 12px gap − 6 = the 6px between icon buttons */
  .js .nav {
    display: none;
    position: absolute; left: 0; right: 0; top: 100%;
    width: auto;
    background: var(--chrome-reverse);
    border-top: 1px solid var(--chrome-line);
    box-shadow: 0 14px 24px -12px hsl(250 60% 10% / .6);
  }
  .js .top.is-open .nav { display: block; }
  .js .nav ul { flex-direction: column; align-items: flex-end; padding: 8px 16px 14px; }
  .js .nav a { padding: 12px 10px; text-align: right; }
  .js .nav a[aria-current]::after { left: auto; right: 10px; width: 24px; bottom: 6px; }

  /* home: the bands stack, all text left-aligned */
  .band__in,
  .band--flip .band__in { grid-template-columns: minmax(0, 1fr); gap: 16px; }
  .band--flip .band__art { order: 0; }
  .band:not(.band--flip) .band__copy { text-align: left; }
  .band:not(.band--flip) .kicker { justify-content: flex-start; }
  .band:not(.band--flip) .band__pitch { margin-left: 0; }

  /* the notice text goes under its date and tags */
  .notice { flex-wrap: wrap; }
  .notice p { flex-basis: 100%; }
}

/* cards stack (article cards under 500px, product cards under 400px, each featured card with its kind): the image on
   top at its widest-window size (the blur fills the sides), square and smaller once the card is narrower; text uncapped */
@media (max-width: 499px) {
  .card:not(.card--product),
  .feature__card:not(.feature__card--product) { grid-template-columns: minmax(0, 1fr); }
  .card:not(.card--product) .card__art,
  .feature__card:not(.feature__card--product) .feature__art { width: 100%; aspect-ratio: 1; max-height: 200px; border-radius: calc(var(--r) - 1px) calc(var(--r) - 1px) 0 0; }
  .card:not(.card--product) .card__main,
  .card:not(.card--product) .card__sub,
  .feature__card:not(.feature__card--product) .feature__main,
  .feature__card:not(.feature__card--product) .feature__sub { white-space: normal; }
  .card:not(.card--product) .card__desc,
  .feature__card:not(.feature__card--product) .feature__desc { -webkit-line-clamp: unset; }
}
/* a product card side by side but narrow: one tag, so the tags stay on one row */
@media (min-width: 400px) and (max-width: 480px) {
  .card--product .chips li:nth-child(n+2),
  .feature__card--product .chips li:nth-child(n+2) { display: none; }
}
@media not all and (min-width: 400px) {
  .card--product,
  .feature__card--product { grid-template-columns: minmax(0, 1fr); }
  .card--product .card__art,
  .feature__card--product .feature__art { width: 100%; aspect-ratio: 1; max-height: 132px; border-radius: calc(var(--r) - 1px) calc(var(--r) - 1px) 0 0; }
  .card--product .card__main,
  .feature__card--product .feature__main { white-space: normal; }
  .card--product .card__desc,
  .feature__card--product .feature__desc { -webkit-line-clamp: unset; }
}

/* the short name from 799px to 600px, where it keeps the links out of the menu, and again under 480px */
@media (min-width: 600px) and (max-width: 799px), (max-width: 479px) {
  .brand__word { --word-img: url(/assets/img/nmx-wordmark-short.png); width: 74.8px; }
}
@media (max-width: 259px) {
  .brand__word { display: none; }
  /* a window's title has no room for its words beside the close button: the button goes on a line of its own above
     it, still at the right (wrap-reverse puts the button's line on top) */
  .window__bar { flex-wrap: wrap-reverse; align-items: center; }
  .window__bar > h2 { flex: 1 1 auto; padding-top: 0; }
}
/* hide the whole home link rather than leave an empty focusable one; Home is in the menu */
@media (max-width: 179px) {
  .brand { display: none; }
}
/* only the menu button is left, kept at the right */
@media (max-width: 119px) {
  .top__actions { display: none; }
  .js .nav-btn { margin-left: auto; }
}

/* Windows high-contrast (forced colours): fills and shadows are dropped, so give every button a real border */
@media (forced-colors: active) {
  .btn, .pager__step, .pager__num { border: 1px solid ButtonText; }
  .pager__num[aria-current] { border: 2px solid Highlight; }
  .chip { border: 1px solid LinkText; }
  .badge { border: 1px solid CanvasText; }
  /* shapes drawn only with a background would vanish; the glints would float beside the dropped pixel shadows */
  .nav a[aria-current]::after, .brand__word::before, .prose h2::before, .prose ul:not(.link-buttons) > li::before, .notice::before { background: CanvasText; }
  .btn::before, .pager__step::before, .pager__num::before, .share__social a::before { display: none; }
  /* the sudoku board's tints and inner rings are dropped: an outline marks the selected square, the dots stay */
  .sudoku__cell.is-selected { outline: 2px solid Highlight; outline-offset: -3px; }
  .sudoku__cell.is-entry { color: LinkText; }
  .sudoku__cell.is-conflict::before { background: CanvasText; }
  /* the browser's own slider instead of the drawn knob */
  .range__knob { display: none; }
  .range input,
  .range input::-webkit-slider-thumb { -webkit-appearance: auto; appearance: auto; }
}

@media (prefers-reduced-motion: reduce) {
  .fireflies, .birds { display: none !important; }
  *, *::before, *::after { transition-duration: .01ms !important; animation: none !important; }
}
/*#endregion*/
