/* JetBrains Mono, self-hosted variable font, see fonts/OFL.txt */
@font-face {
  font-family: "JetBrains Mono";
  src: url("fonts/jetbrains-mono-latin-wght-normal.woff2") format("woff2");
  font-weight: 100 800;
  font-display: swap;
  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: "JetBrains Mono";
  src: url("fonts/jetbrains-mono-latin-ext-wght-normal.woff2") format("woff2");
  font-weight: 100 800;
  font-display: swap;
  unicode-range:
    U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
    U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB,
    U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* JetBrains Mono cut down to ASCII, box drawing and block elements, for the ASCII headings.
   System monospace fonts on Android lack the box drawing glyphs, the browser borrows them from
   a font of another width and the headings fall apart. block: better a moment of nothing than
   a misaligned heading. */
@font-face {
  font-family: "woc ascii";
  src: url("fonts/jetbrains-mono-ascii.woff2") format("woff2");
  font-display: block;
}

:root {
  color-scheme: dark;
  --bg: #0e1116;
  --surface: #161b22;
  --line: #2a313c;
  --text: #e6e8eb;
  --muted: #9aa4b2;
  --accent: #5cc8b0;
  --accent-soft: rgb(92 200 176 / 0.45);
  /* The box drawing shadow of the ASCII logo and headings, the accent a shade deeper */
  --accent-deep: #267a69;
  /* The one font of the site, so everything renders with the same glyphs for every visitor */
  --term: "JetBrains Mono", ui-monospace, monospace;
  --wide: 68rem;
  --narrow: 42rem;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: #000;
  color: var(--text);
  font: 0.9375rem/1.7 var(--term);
  overflow: hidden;
}

/* Faint CRT backdrop: scanlines, a sparse grid and a darker rim. Fixed, so it does not scroll. */
/* The whole page scrolls inside .screen, a box exactly the size of the viewport. That lets the
   curve filter bend the picture in screen coordinates, so content bends as it scrolls past the
   edges like on a curved tube. The backdrop sits on .screen and does not scroll, so the grid
   is bent too. */
.screen {
  position: fixed;
  /* One pixel above the viewport, so .screen is not exactly viewport sized. Chrome on Android
     would otherwise treat it as the root scroller and hide the address bar as it scrolls, and
     during that animation the chin and the keys slide out of place. */
  inset: -1px 0 0;
  overflow-x: hidden;
  overflow-y: auto;
  outline: none;
  filter: url(#crt-curve);
  scrollbar-width: thin;
  scrollbar-color: var(--line) transparent;
  background-color: var(--bg);
  background-image:
    radial-gradient(ellipse at center, transparent 55%, rgb(0 0 0 / 0.5)),
    repeating-linear-gradient(
      to bottom,
      rgb(255 255 255 / 0.022) 0 1px,
      transparent 1px 3px
    ),
    linear-gradient(to right, rgb(92 200 176 / 0.035) 1px, transparent 1px),
    linear-gradient(to bottom, rgb(92 200 176 / 0.035) 1px, transparent 1px);
  background-size:
    auto,
    auto,
    2rem 2rem,
    2rem 2rem;
}

/* CRT refresh bar: a brighter band rolls from the bottom of the screen to the top, again and
   again. It brightens whatever is under it and ignores scrolling, because it is fixed. The
   leading edge at the top is the brightest part and it fades out below. */
body::after {
  content: "";
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 10rem;
  z-index: 10;
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    transparent,
    rgb(200 255 240 / 0.05) 6%,
    rgb(200 255 240 / 0.015) 45%,
    transparent
  );
  /* Brightness lifts everything, contrast then pulls the dark background back down to where
     design6 left it, so only the lighter content under the bar really lights up. */
  backdrop-filter: brightness(2.2) contrast(1.17);
  mask-image: linear-gradient(
    to bottom,
    transparent,
    #000 6%,
    rgb(0 0 0 / 0.35) 45%,
    transparent
  );
  transform: translateY(100vh);
  animation: refresh-bar 9s linear infinite;
}

@keyframes refresh-bar {
  from {
    transform: translateY(100vh);
  }

  to {
    transform: translateY(-100%);
  }
}

@media (prefers-reduced-motion: reduce) {
  body::after {
    display: none;
  }
}

/* Pull to refresh. fx.js drags the content of .screen down after the finger and centres this
   hint in the gap it opens above it, over the picture and under the glass. */
.pull-hint {
  position: fixed;
  top: var(--bezel);
  left: 50%;
  z-index: 15;
  opacity: 0;
  pointer-events: none;
  color: var(--accent);
  font-size: 0.8125rem;
  white-space: nowrap;
}

@media (prefers-reduced-motion: no-preference) {
  .pull-release :is(.screen > *, .pull-hint) {
    transition:
      transform 0.2s ease-out,
      opacity 0.2s ease-out;
  }
}

/* The monitor. --bezel is the visible plastic on the top and sides, --chin the deeper strip
   along the bottom where the switch sits, --glass-r the corner radius of the screen. */
:root {
  --bezel: 1rem;
  --chin: 3.25rem;
  --glass-r: 1.75rem;
  --plastic: #dbd1b1;
}

@media (max-width: 40rem) {
  :root {
    --bezel: 0.5rem;
    --chin: 2.75rem;
    --glass-r: 1.25rem;
  }
}

/* The glass over the curved picture. .crt carries the reflections, ::before the vignette,
   ::after the light caught by the curved edge of the glass. */
.crt {
  position: fixed;
  inset: var(--bezel) var(--bezel) var(--chin);
  z-index: 20;
  pointer-events: none;
  border-radius: var(--glass-r);
  box-shadow: inset 0 0 0.5rem 0.25rem rgb(0 0 0 / 0.95);
  background:
    radial-gradient(
      ellipse 60% 40% at 28% 16%,
      rgb(255 255 255 / 0.06),
      transparent 70%
    ),
    radial-gradient(
      ellipse 35% 25% at 78% 88%,
      rgb(255 255 255 / 0.025),
      transparent 70%
    ),
    radial-gradient(ellipse at center, rgb(255 255 255 / 0.02), transparent 45%);
}

/* A thick black frame with the rounded shape of the screen, blurred. Unlike a radial gradient
   it follows the rounded rectangle, so the corners darken and the long sides stay straight.
   The frame width sets how far the dark reaches in, the blur sets how hard the falloff is. */
.crt::before {
  content: "";
  position: absolute;
  inset: -1.5rem;
  border: 4.5rem solid rgb(0 0 0 / 0.92);
  border-radius: calc(var(--glass-r) + 1.5rem);
  filter: blur(0.75rem);
}

/* The glint on the glass edge, brightest top left and fading out towards bottom right */
.crt::after {
  content: "";
  position: absolute;
  inset: 0.625rem;
  border: 2px solid rgb(220 255 245 / 0.28);
  border-radius: calc(var(--glass-r) - 0.5rem);
  filter: blur(1px);
  mask-image: linear-gradient(
    135deg,
    #000,
    rgb(0 0 0 / 0.35) 35%,
    transparent 65%
  );
}

@media (max-width: 40rem) {
  .crt::before {
    border-width: 3rem;
    filter: blur(0.5rem);
  }
}

/* Yellowed plastic case around the glass. It is one thick border reaching --over past the
   viewport, because a border can have a square-ish outside and a rounded inside, and the
   overhang keeps the outer rounding off screen. The #plastic filter gives it the matte grain.
   The inset shadows fall on the glass, as if the case were casting a shadow into the tube. */
.bezel {
  --over: 4rem;
  --outer: calc(var(--glass-r) + var(--over) + var(--bezel));
  --outer-chin: calc(var(--glass-r) + var(--over) + var(--chin));
  position: fixed;
  inset: calc(-1 * var(--over));
  z-index: 25;
  pointer-events: none;
  border: calc(var(--over) + var(--bezel)) solid var(--plastic);
  border-bottom-width: calc(var(--over) + var(--chin));
  border-radius: var(--outer) / var(--outer) var(--outer) var(--outer-chin)
    var(--outer-chin);
  box-shadow:
    inset 0 0 0 2px rgb(60 52 36 / 0.55),
    inset 0 0.25rem 0.5rem rgb(0 0 0 / 0.6);
  filter: url(#plastic);
}

.crt-off .screen {
  filter: none;
}

/* Power on and off, over the picture and under the glass. .power blacks out the tube, .beam is
   the electron beam: a dot, a line, then the whole face. Idle it is not there at all. */
.power {
  position: fixed;
  inset: var(--bezel) var(--bezel) var(--chin);
  z-index: 12;
  display: none;
  overflow: hidden;
  pointer-events: none;
  border-radius: var(--glass-r);
}

.powering-on .power,
.powering-off .power {
  display: block;
}

.beam {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  background: #eafff8;
  box-shadow:
    0 0 8px 2px rgb(200 255 240 / 0.9),
    0 0 30px 8px rgb(92 200 176 / 0.5);
}

.powering-on .power {
  animation: tube-on 1.3s linear both;
}

.powering-on .beam {
  animation: beam-on 1.3s ease-out both;
}

.powering-off .power {
  animation: tube-off 0.75s linear both;
}

.powering-off .beam {
  animation: beam-off 0.75s ease-in both;
}

@keyframes tube-on {
  0%,
  61% {
    background: #000;
  }

  62%,
  100% {
    background: transparent;
  }
}

@keyframes beam-on {
  0% {
    width: 0;
    height: 0;
    border-radius: 50%;
    opacity: 0;
  }

  8%,
  25% {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    opacity: 1;
  }

  42% {
    width: 100%;
    height: 2px;
    border-radius: 0;
    opacity: 1;
  }

  62% {
    width: 100%;
    height: 100%;
    border-radius: 0;
    opacity: 1;
  }

  100% {
    width: 100%;
    height: 100%;
    border-radius: 0;
    opacity: 0;
  }
}

/* After switching off, the dark tube and the case fade out over the now flat page */
.crt-off.fading-out :is(.power, .crt, .bezel, .badge) {
  display: block;
  animation: monitor-fade 0.7s ease-in both;
}

.crt-off.fading-out .power {
  background: #000;
}

@keyframes monitor-fade {
  to {
    opacity: 0;
  }
}

@keyframes tube-off {
  0%,
  12% {
    background: transparent;
  }

  13%,
  100% {
    background: #000;
  }
}

@keyframes beam-off {
  0% {
    width: 100%;
    height: 100%;
    border-radius: 0;
    opacity: 0;
  }

  12% {
    width: 100%;
    height: 100%;
    border-radius: 0;
    opacity: 1;
  }

  45% {
    width: 100%;
    height: 2px;
    border-radius: 0;
    opacity: 1;
  }

  75% {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    opacity: 1;
  }

  100% {
    width: 0;
    height: 0;
    border-radius: 50%;
    opacity: 0;
  }
}

/* Maker's badge set into the chin as a separate piece of darker plastic, standing slightly
   proud: lit top edge, shade below and a short soft drop shadow */
.badge {
  position: fixed;
  left: 50%;
  bottom: calc(var(--chin) / 2);
  z-index: 26;
  transform: translate(-50%, 50%);
  pointer-events: none;
  font: 800 1.375rem/1 var(--term);
  letter-spacing: 0.1em;
  color: #a89d7f;
  text-shadow:
    0 -1px 0 rgb(255 255 255 / 0.5),
    0 1px 0 rgb(50 43 30 / 0.55),
    0 2px 3px rgb(50 43 30 / 0.3);
}

.crt-off .crt,
.crt-off .bezel,
.crt-off .badge,
.crt-off body::after {
  display: none;
}

/* Switch for the monitor effects, bottom right inside the bezel, with the language key beside it */
/* Same place and size with the monitor on or off, only the look changes */
:is(.crt-toggle, .lang-key) {
  position: fixed;
  right: calc(var(--bezel) + 1.5rem);
  bottom: calc((var(--chin) - 1.75rem) / 2);
  z-index: 30;
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 1.75rem;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: rgb(14 17 22 / 0.85);
  color: var(--accent);
  cursor: pointer;
  transition: border-color 0.15s;
}

:is(.crt-toggle, .lang-key):hover,
:is(.crt-toggle, .lang-key):focus-visible {
  border-color: var(--accent);
}

.crt-toggle svg {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.lang-key {
  right: calc(var(--bezel) + 1.5rem + 2.75rem + 0.5rem);
  font: 600 0.8125rem/1 var(--term);
  letter-spacing: 0.05em;
}

.crt-off :is(.crt-toggle, .lang-key) {
  color: var(--muted);
}

/* While the monitor is on, the switch is a plastic button on the chin */
:root:is(:not(.crt-off), .fading-out) :is(.crt-toggle, .lang-key) {
  border: 1px solid rgb(60 52 36 / 0.35);
  background: linear-gradient(#ddd3b4, #c9bf9f);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.45),
    0 1px 2px rgb(60 52 36 / 0.35);
  color: #544d3e;
}

:root:is(:not(.crt-off), .fading-out) :is(.crt-toggle, .lang-key):hover,
:root:is(:not(.crt-off), .fading-out)
  :is(.crt-toggle, .lang-key):focus-visible {
  border-color: rgb(60 52 36 / 0.7);
}
/* The power symbol lights up green while the monitor is on and goes dark at once on switching
   off, before the tube has collapsed */
:root:not(.crt-off, .led-off) .crt-toggle {
  color: #2fb45a;
}

:root:not(.crt-off, .led-off) .crt-toggle svg {
  filter: drop-shadow(0 0 2px rgb(111 240 150 / 0.9))
    drop-shadow(0 0 5px rgb(111 240 150 / 0.45));
}

a {
  color: var(--accent);
  text-decoration: none;
  transition: color 0.15s;
}

a:hover {
  color: var(--text);
}

.wrap {
  max-width: var(--wide);
  margin: 0 auto;
  padding: 0 1rem;
}

p {
  margin: 0 auto 1rem;
  max-width: var(--narrow);
}

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

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ASCII art */

/* Centred as a block. text-align stays left, centring a <pre> centres every line on its own. */
.ascii {
  font-family: var(--term);
  line-height: 1;
  letter-spacing: 0;
  white-space: pre;
  text-align: left;
  width: fit-content;
  margin: 0 auto;
  color: var(--accent);
}

/* Until fx.js starts the reveal. Without JS the art is simply there. */
.js [data-reveal]:not(.is-shown) {
  visibility: hidden;
}

/* Tones from the asciigen export, darkest first, and --t4 the top that t3 is lifted towards.
   Every tone is lifted --lift of the way towards the next one and drawn heavy, as the
   portraits on the business cards are, see PORTRAIT in tools/business_card_print.py. */
.portrait {
  --t0: #31635b;
  --t1: #459182;
  --t2: #5cc8b0;
  --t3: #9dded0;
  --t4: #e2f6f1;
  --lift: 40%;
  font-weight: 800;
}

.t0 {
  color: color-mix(in srgb, var(--t0), var(--t1) var(--lift));
}

.t1 {
  color: color-mix(in srgb, var(--t1), var(--t2) var(--lift));
}

.t2 {
  color: color-mix(in srgb, var(--t2), var(--t3) var(--lift));
}

.t3 {
  color: color-mix(in srgb, var(--t3), var(--t4) var(--lift));
}

.ascii.is-glitching {
  text-shadow:
    -2px 0 var(--accent-soft),
    2px 0 rgb(154 164 178 / 0.35);
}

/* Hero */

.hero {
  min-height: 92vh;
  display: flex;
  align-items: center;
  text-align: center;
  border-bottom: 1px solid var(--line);
  padding: 6rem 0 4rem;
}

.hero .wrap {
  width: 100%;
}

.logo,
.heading {
  font-family: "woc ascii", var(--term);
}

/* The box drawing shadow, wrapped by fx.js. The stroke gives its thin lines the weight of a
   whole pixel everywhere. Box drawing glyphs are taller than a line of height 1 and reach into
   the row above, so the shadow is painted behind the blocks, inside the <pre>'s own stacking
   context. */
.logo,
.heading {
  position: relative;
  z-index: 0;
}

.rim {
  position: relative;
  z-index: -1;
  color: var(--accent-deep);
  -webkit-text-stroke: 0.03em currentColor;
}

/* With JS the art is painted on a canvas by ascii.js. The text stays for the layout, unseen. */
.has-canvas,
.has-canvas .rim {
  color: transparent;
  -webkit-text-stroke: 0;
}

.has-canvas canvas {
  position: absolute;
  display: block;
}

/* Transparent text still casts its text-shadow, so the canvas carries the glitch instead */
.has-canvas.is-glitching {
  text-shadow: none;
}

.has-canvas.is-glitching canvas {
  filter: drop-shadow(-2px 0 var(--accent-soft))
    drop-shadow(2px 0 rgb(154 164 178 / 0.35));
}

/* Whole pixels only. At a fractional size the rows of a <pre> fall on fractional pixels and the
   thin lines of the box drawing shadow snap to one pixel on some rows and two on others. */
.logo {
  font-size: round(down, min(1.5rem, calc((100vw - 2rem) / 29)), 1px);
  margin: 0 auto 2.5rem;
}

.tagline {
  font-size: clamp(1.5rem, 3.5vw, 2.25rem);
  line-height: 1.25;
  font-weight: 600;
  margin: 0 auto 1rem;
  max-width: 32ch;
}

/* The English motto breaks before its parenthesis, so the first line has to fit whole */
:lang(en) .tagline {
  max-width: 37ch;
}

.what {
  font-family: var(--term);
  font-size: clamp(0.875rem, 2vw, 1.0625rem);
  color: var(--muted);
  margin: 0 auto 2rem;
}

.what span {
  color: var(--line);
  padding: 0 0.5em;
}

.range {
  color: var(--muted);
}

/* The closing line of the hero, after the copy and before the address */
.fields {
  margin-top: 2rem;
}

.cta {
  font-family: var(--term);
  font-size: 1.125rem;
  display: inline-block;
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 0.6rem 1rem;
}

.cta:hover {
  border-color: var(--accent);
}

/* Sections */

section {
  padding: 6rem 0;
  border-bottom: 1px solid var(--line);
  text-align: center;
}

/* --cols is the width of the widest heading on the page in characters, set on <main> per
   language, so all the headings share one size. A glyph is 0.6em wide. */
main:lang(cs) {
  --cols: 74;
}

main:lang(en) {
  --cols: 82;
}

.heading {
  font-size: round(
    down,
    min(0.875rem, calc((100vw - 2rem) / var(--cols, 77) / 0.6)),
    1px
  );
  margin-bottom: 3rem;
}

h3 {
  font-size: 1.125rem;
  line-height: 1.3;
  margin: 0 0 0.5rem;
  font-weight: 600;
}

/* References */

.stats {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 1rem 3rem;
  margin: 0 0 3rem;
}

.stat b {
  display: block;
  font-family: var(--term);
  font-size: 2.25rem;
  line-height: 1.2;
  color: var(--text);
  font-weight: 500;
}

.stat span {
  color: var(--muted);
  font-size: 0.9375rem;
}

.refs {
  list-style: none;
  padding: 0;
  margin: 0;
  border-top: 1px solid var(--line);
}

.refs {
  max-width: var(--narrow);
  margin: 0 auto;
}

.refs li {
  padding: 1.25rem 0;
  border-bottom: 1px solid var(--line);
}

.refs .who {
  font-weight: 600;
}

/* Name, then the short description on a line of its own, then the long one */
.refs .when {
  display: block;
  font-family: var(--term);
  font-size: 0.8125rem;
  color: var(--muted);
}

.refs .when a {
  color: var(--accent);
}

.refs .when a:hover {
  color: var(--text);
}

.refs p {
  margin: 0.25rem auto 0;
  color: var(--muted);
  font-size: 0.9375rem;
}

/* People: portraits glued to the screen edges, facing each other across the text */

/* The bios sit under the portraits, each taking its half of the screen */
.people {
  display: grid;
  grid-template-columns: auto 1fr 1fr auto;
  grid-template-areas:
    "jan text text tadeas"
    "jan-bio jan-bio tadeas-bio tadeas-bio";
  align-items: end;
  gap: 2rem;
}

.person {
  margin: 0;
}

.jan {
  grid-area: jan;
}

.tadeas {
  grid-area: tadeas;
}

.jan-bio {
  grid-area: jan-bio;
}

.tadeas-bio {
  grid-area: tadeas-bio;
}

/* Name and addresses centred over the bio, the bio itself set flush on both sides */
.bio {
  align-self: start;
  padding: 0 2rem;
}

.bio-head {
  margin-bottom: 1.5rem;
}

.bio p {
  text-align: justify;
}

/* About 70 columns at 0.6em per glyph, so a portrait is about 42em wide */
.portrait {
  font-size: min(0.75vw, 0.6rem);
  margin: 0;
}

.tadeas .portrait {
  margin-left: auto;
}

.bio-head h3 {
  font-size: 1.375rem;
  margin: 0 0 0.25rem;
}

.bio-head > a,
.bio-links {
  display: block;
  font-family: var(--term);
  font-size: 0.9375rem;
}

/* Several links on one line, so both bios start on the same row. Wraps on narrow screens. */
.bio-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  margin: 0;
}

.sep {
  padding: 0 0.5rem;
  color: var(--muted);
}

.people-text {
  grid-area: text;
  align-self: center;
  padding: 0 1rem;
}

@media (max-width: 60rem) {
  .people {
    grid-template-columns: 1fr 1fr;
    grid-template-areas:
      "jan tadeas"
      "text text"
      "jan-bio tadeas-bio";
    gap: 3rem 0.5rem;
  }

  .bio {
    padding: 0 1rem;
  }

  .portrait {
    font-size: calc((50vw - 0.5rem) / 43);
  }

  .bio-head h3 {
    font-size: 1.125rem;
  }

  .bio-head > a,
  .bio-links {
    font-size: 0.8125rem;
  }
}

/* Phones: text first, then Jan on the left edge with his bio, then Tadeáš on the right edge
   with his. Each portrait decodes on its own once it is wholly on screen. */
@media (max-width: 40rem) {
  .people {
    grid-template-columns: 1fr;
    grid-template-areas:
      "text"
      "jan"
      "jan-bio"
      "tadeas"
      "tadeas-bio";
    gap: 2rem;
  }

  .tadeas {
    margin-top: 2rem;
  }

  .people-text {
    padding: 0 1rem;
  }

  /* The portraits stay on their edges, Tadeáš through the margin-left: auto set above */
  .portrait {
    font-size: calc(85vw / 43);
  }
}

/* Contact */

.contact .muted strong {
  display: block;
  color: var(--text);
  font-weight: 600;
}

.contact .mail {
  font-family: var(--term);
  font-size: clamp(1.25rem, 5vw, 2.5rem);
}

/* Footer */

/* The teaser under the footer text lets it scroll clear of the chin, the vignette and the
   squeeze of the curve, so it can be read in the middle of the tube. The bottom padding
   keeps the teaser clear of the chin and of the keys on it. */
footer {
  padding: 2rem 0 var(--chin);
  font-family: var(--term);
  font-size: 0.8125rem;
  color: var(--muted);
}

footer {
  text-align: center;
}

footer p {
  max-width: none;
  margin: 0 0 0.5rem;
}

.ids-block {
  margin-top: 2.5rem;
  font-family: var(--term);
  font-size: 0.8125rem;
}

.ids-block p {
  max-width: none;
  margin: 0 0 0.5rem;
}

.ids strong {
  font-weight: 600;
}

.ids {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.25rem 1.5rem;
  color: var(--text);
}

footer .legal,
footer .copy,
footer .host {
  font-size: 0.75rem;
}

footer .host a {
  color: inherit;
}

footer .host img {
  vertical-align: -0.2em;
  margin: 0 0.1em;
}

/* The teaser at the very end of the page: one line in the face of the portraits and under it
   a head cut off below the nose, which sits on the bottom edge as if peeking over it. */
.soon {
  margin-top: 8rem;
}

.soon-text {
  margin-bottom: 1.5rem;
  font-size: clamp(0.8125rem, 3.4vw, 1.125rem);
  font-weight: 800;
}

/* The portraits of the bios drop the centring of .ascii, this one keeps it */
.soon .portrait {
  margin: 0 auto;
}

/* 76 columns at 0.6em per glyph, so the head is about 46em wide */
@media (max-width: 40rem) {
  .soon .portrait {
    font-size: calc(85vw / 46);
  }
}

/* The 404 page */
.notfound {
  min-height: 100%;
  display: grid;
  place-content: center;
  padding: 2rem 1rem;
  text-align: center;
}

/* The same whole pixel rounding as the logo, sized for 25 columns */
.notfound .heading {
  font-size: round(down, min(2rem, calc((100vw - 2rem) / 25 / 0.6)), 1px);
  margin: 0 auto 2.5rem;
}

.notfound p {
  margin: 0 0 0.5rem;
  color: var(--muted);
}

.notfound a {
  color: var(--accent);
}
