/* ------------------------------------------------------------------
   hausfold.co — the whole site's stylesheet. Served as-is: this Worker
   has no build step, so what's in ./public is what's on the domain.

   It was inline in index.html until 2026-08-08, when /desktops arrived
   and there were five pages to keep in agreement — the landing page,
   the two under /desktops, 404, and perch's privacy policy, which had
   been hand-syncing its own copy of the tokens since it was written.
   One file, one set of tokens; the alternative was the same 200 lines
   pasted five times and drifting by the second edit.

   Palette: nebelung's neutral ramp in dark, every value pushed one
            step outward for contrast (crust/subtext1/overlay2/
            surface1). A paper-warm mirror in light, pushed the same
            distance. The site is greyscale at rest. The only colour
            anywhere is a product's own accent, and only while you
            hover its name: borrowed, never the page's own.
   Port:    nebelung ships its palette as CSS now, so the dark theme
            no longer hand-copies hexes: the block below the header is
            nebelung's own dist/css/nebelung-mocha.css, vendored here
            by scripts/sync-nebelung.mjs, and both dark blocks read
            var(--nebelung-*) from it. Refresh it with
            `node scripts/sync-nebelung.mjs`; CI runs the same script
            with --check, which also refuses a --nebelung-* reference
            outside the two dark blocks.
   By hand: two dark values are deliberately not nebelung's and stay
            literal — --ink #ebebeb is extrapolated one rung above the
            ramp's #d7d7d7 text, following its own ~0x14 spacing, and
            --well #1a1a1a is hand-picked (it is NOT mantle #191919).
            The whole light theme is hand-picked too, and is not
            latte: nebelung's pastels are built for a dark ground and
            wash out on paper.
   Accents: the dark values ARE nebelung's — rice pink, pounce peach,
            perch green, nebelung mauve. holt and trill have no row
            upstream yet, so teal and yellow are provisional choices
            of ours from nebelung's palette rather than assignments it
            makes; reconcile them if those two get a row.
   Type:    New York (ui-serif) + SF Mono. The Mac's own faces, which
            is the thesis of the site set in the site.
   Mark:    grey until you hover it, then all six product accents fold
            into one iridescent sheen — light on a soap film — turning
            slowly around the glyph, and it fades in rather than
            snapping. It reuses the very same --a-* tokens the index
            spends one at a time, so the house cannot show a colour no
            product owns. This is the site's only animation; it runs on
            hover only, never on load, and prefers-reduced-motion holds
            the sheen still rather than dropping it.
   Favicon: the same mark and the same sweep, held still, on a crust
            tile — public/favicon.svg, linked from every page. It is
            the ONE place this site keeps colour with no hover to gate
            it, because a favicon has no hover; AGENTS.md records it as
            the third exception to greyscale-at-rest and says why it
            doesn't open the door. Its wedge fan is generated by
            scripts/sync-nebelung.mjs out of the block below, so a PIN
            bump moves the icon with the palette. WebKit won't resolve
            that SVG, so public/favicon.ico rides alongside it for
            Safari — same mark, same script, but --ink on crust with no
            accent sweep, so it stays outside this exception rather
            than extending it.
   Shots:   the frames on /desktops/nebelhaus, /pounce and /perch are
            placeholders on purpose — drawn in CSS, no image files. The
            landing page's own desktop entry deliberately has none: an
            empty box under the page's first heading reads as a broken
            image, not as a slot, so that one waits for a real capture
            rather than holding its place with a dashed outline. The family's only
            real rice capture is hausfold/assets/hero.png, which the
            workshop's SHOTLIST.md still calls a placeholder itself. A
            grey frame that says what it is beats a stale screenshot
            that lies, and it keeps the site greyscale until there's a
            shot worth spending colour on.
   ------------------------------------------------------------------ */

/* >>> nebelung — generated by scripts/sync-nebelung.mjs; do not edit by hand <<< */
/* nebelung's own CSS port (dist/css/nebelung-mocha.css), verbatim but for
 * `color-scheme`. Nothing here paints anything: these are the upstream
 * names, and only the two dark blocks below spend any of them. The light
 * theme is hand-picked and must not reference them.
 *
 * From github:hausfold/nebelung @ 49f196de2aad — a pin, so nothing
 * here moves until someone moves it. `node scripts/sync-nebelung.mjs
 * --latest` says whether there's anything to move to. */
:root {
  /* Neutral ramp, lightest → darkest. */
  --nebelung-text: #d7d7d7;
  --nebelung-subtext1: #c3c3c3;
  --nebelung-subtext0: #aeaeae;
  --nebelung-overlay2: #9a9a9a;
  --nebelung-overlay1: #858585;
  --nebelung-overlay0: #717171;
  --nebelung-surface2: #5c5c5c;
  --nebelung-surface1: #494949;
  --nebelung-surface0: #343434;
  --nebelung-base: #202020;
  --nebelung-mantle: #191919;
  --nebelung-crust: #121212;

  /* Accents. */
  --nebelung-rosewater: #f3e1dd;
  --nebelung-flamingo: #efcece;
  --nebelung-pink: #f2c4e5;
  --nebelung-mauve: #c9a8f1;
  --nebelung-red: #ed8fa9;
  --nebelung-maroon: #e6a3ad;
  --nebelung-peach: #f5b58e;
  --nebelung-yellow: #f7e2b5;
  --nebelung-green: #abe1a6;
  --nebelung-teal: #9be0d5;
  --nebelung-sky: #91dbe8;
  --nebelung-sapphire: #7dc6e7;
  --nebelung-blue: #8db4f3;
  --nebelung-lavender: #b5bff8;

  /* Semantic aliases — the names to reach for first. Override any of these in
   * your own :root to re-point the system without touching the ramp above. */
  --nebelung-bg: var(--nebelung-base);
  --nebelung-bg-alt: var(--nebelung-mantle);
  --nebelung-bg-deep: var(--nebelung-crust);
  --nebelung-fg: var(--nebelung-text);
  --nebelung-fg-muted: var(--nebelung-subtext0);
  --nebelung-border: var(--nebelung-surface1);
  --nebelung-accent: var(--nebelung-mauve);
  --nebelung-success: var(--nebelung-green);
  --nebelung-warning: var(--nebelung-yellow);
  --nebelung-danger: var(--nebelung-red);
  --nebelung-info: var(--nebelung-teal);
}
/* >>> end nebelung <<< */

:root {
  color-scheme: light dark;

  /* paper */
  --ground: #faf9f7;
  --ink: #0e0e0e;
  --ink-2: #35332f;
  --ink-3: #66645f;
  --rule: #c4c0bb;
  --well: #f2f0ed;

  /* borrowed accents, light ground */
  --a-nebelhaus: #a83a8b;
  --a-pounce: #a8570f;
  --a-holt: #0f7268;
  --a-perch: #2e7a37;
  --a-nebelung: #6a3fb0;
  --a-trill: #8a6512;

  --measure: 41rem;
  --step: clamp(0.94rem, 0.9rem + 0.2vw, 1.02rem);
}

/* nebelung's ramp, one step out. Said twice on purpose — once for the
   system scheme, once for an explicit toggle — so the two must not
   drift; scripts/sync-nebelung.mjs --check asserts they haven't. Only
   --ink and --well are ours; see "By hand" in the header. */
@media (prefers-color-scheme: dark) {
  :root {
    color-scheme: dark;
    --ground: var(--nebelung-crust);
    --ink: #ebebeb;
    --ink-2: var(--nebelung-subtext1);
    --ink-3: var(--nebelung-overlay2);
    --rule: var(--nebelung-surface1);
    --well: #1a1a1a;

    --a-nebelhaus: var(--nebelung-pink);
    --a-pounce: var(--nebelung-peach);
    --a-holt: var(--nebelung-teal);
    --a-perch: var(--nebelung-green);
    --a-nebelung: var(--nebelung-mauve);
    --a-trill: var(--nebelung-yellow);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --ground: var(--nebelung-crust);
  --ink: #ebebeb;
  --ink-2: var(--nebelung-subtext1);
  --ink-3: var(--nebelung-overlay2);
  --rule: var(--nebelung-surface1);
  --well: #1a1a1a;

  --a-nebelhaus: var(--nebelung-pink);
  --a-pounce: var(--nebelung-peach);
  --a-holt: var(--nebelung-teal);
  --a-perch: var(--nebelung-green);
  --a-nebelung: var(--nebelung-mauve);
  --a-trill: var(--nebelung-yellow);
}

:root[data-theme="light"] {
  color-scheme: light;
  --ground: #faf9f7;
  --ink: #0e0e0e;
  --ink-2: #35332f;
  --ink-3: #66645f;
  --rule: #c4c0bb;
  --well: #f2f0ed;

  --a-nebelhaus: #a83a8b;
  --a-pounce: #a8570f;
  --a-holt: #0f7268;
  --a-perch: #2e7a37;
  --a-nebelung: #6a3fb0;
  --a-trill: #8a6512;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: ui-serif, "New York", Georgia, "Iowan Old Style", serif;
  font-size: var(--step);
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

.sheet {
  max-width: var(--measure);
  margin: 0 auto;
  padding: clamp(3.5rem, 9vw, 7.5rem) clamp(1.4rem, 5vw, 2rem)
    clamp(2.5rem, 6vw, 4rem);
  display: flex;
  flex-direction: column;
  gap: clamp(3rem, 7vw, 4.75rem);
}

/* Subpages open on a breadcrumb rather than the ⌂, so the top of the
   sheet is tighter than the landing page's masthead needs. */
.sheet--inner {
  padding-top: clamp(2.25rem, 6vw, 4rem);
  gap: clamp(2.5rem, 6vw, 3.75rem);
}

/* --- masthead ------------------------------------------------- */

.masthead {
  display: flex;
  flex-direction: column;
  gap: 1.6rem;
}

.mark {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: clamp(3.4rem, 11vw, 5rem);
  line-height: 0.9;
  color: var(--ink-3);
  font-weight: 300;
  user-select: none;
  /* Shrink-to-glyph, so the hover target is the house and not the
     full width of the masthead column. The padding/margin pair widens
     the hit box back over the glyph — line-height: 0.9 crops the em box
     and the roof and floor of ⌂ fall outside it — without moving a
     pixel of layout. */
  align-self: flex-start;
  padding: 0.09em 0;
  margin: -0.09em 0;
  position: relative;
}

/* Registered so the angle interpolates. A browser without @property
   never defines --mark-ang at all — the var() fallback below is what
   keeps the gradient valid there, and the discrete 0/360deg flip
   between two identical frames means the sheen shows but holds still.
   An acceptable floor, no guard needed. */
@property --mark-ang {
  syntax: "<angle>";
  initial-value: 0deg;
  inherits: false;
}

/* All six accents folded into one conic gradient — light on a soap
   film — turning slowly around a point just above the glyph's centre.
   The coloured copy lives on ::after so hover can fade it in and out
   instead of snapping; the animation is defined but paused, and hover
   only runs it, so it never advances while unseen.

   The copy exists ONLY where the clip is real: without the guard, a
   browser that ignores background-clip would paint a coloured
   rectangle over the glyph. Forced-colors modes strip the background
   but keep the transparent fill, so there the copy is simply
   invisible and the grey glyph underneath stands alone. */
@supports (background-clip: text) or (-webkit-background-clip: text) {
  .mark::after {
    content: "⌂";
    position: absolute;
    inset: 0;
    padding: 0.09em 0;
    background-image: conic-gradient(
      from var(--mark-ang, 0deg) at 50% 42%,
      var(--a-nebelung),
      var(--a-holt),
      var(--a-perch),
      var(--a-trill),
      var(--a-pounce),
      var(--a-nebelhaus),
      var(--a-nebelung)
    );
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    -webkit-text-fill-color: transparent;
    opacity: 0;
    transition: opacity 0.7s ease;
    animation: mark-turn 18s linear infinite paused;
  }

  .mark:hover::after {
    opacity: 1;
    animation-play-state: running;
  }
}

@keyframes mark-turn {
  to {
    --mark-ang: 360deg;
  }
}

/* Still colour, not grey: the sheen is the point, the turn is the
   flourish. The opacity fade stays on purpose — a crossfade is the
   reduced-motion-safe form, not the thing the setting suppresses. */
@media (prefers-reduced-motion: reduce) {
  .mark::after {
    animation: none;
  }
}

.wordmark {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: clamp(1.5rem, 5vw, 1.95rem);
  font-weight: 400;
  letter-spacing: 0.02em;
  margin: 0;
  color: var(--ink);
}

.standfirst {
  font-size: clamp(1.28rem, 4vw, 1.72rem);
  line-height: 1.32;
  font-weight: 400;
  letter-spacing: -0.014em;
  margin: 0;
  max-width: 22ch;
  text-wrap: balance;
}

.lede {
  display: flex;
  flex-direction: column;
  gap: 1.05rem;
  color: var(--ink-2);
  max-width: 62ch;
}

.lede p {
  margin: 0;
}

.lede strong {
  font-weight: 400;
  color: var(--ink);
}

/* --- the index -------------------------------------------------- */

.index {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.72rem;
  max-width: 58ch;
}

/* No marker and no indent: every line starts on the same left edge as
   the lede above it, so the index reads as one more paragraph of the
   page rather than a widget bolted to it. */
.index li {
  color: var(--ink-2);
  line-height: 1.5;
}

/* There was an `.index--floor` modifier here until 2026-08-12, buying a
   little extra air under a one-row list holding haus — the landing page
   was one index of seven names in two tiers, and the tier was carried by
   whitespace because a heading over the lower half would have had to name
   rows it couldn't (nebelung doesn't run on haus, haus consumes it; holt
   runs anywhere). The page is now sectioned instead, and the regrouping is
   what made the headings honest: holt and nebelung came out of the list
   entirely, so what's left under `Apps` really is apps. One list, no
   modifier. */

.index-name {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 0.92rem;
  color: var(--ink);
}

/* The one place colour is allowed: a product's own accent, on hover of
   its own name. Each li carries its accent; the name just spends it.
   Scoped to .index-name rather than to the anchor, so a name with no
   link on it — `trill`, today — still answers to the pointer. */
.index li[data-accent] .index-name:hover,
.index li[data-accent] a.index-name:focus-visible {
  color: var(--accent, var(--ink));
  text-decoration-color: var(--accent, var(--ink));
}

[data-accent="nebelhaus"] { --accent: var(--a-nebelhaus); }
[data-accent="pounce"] { --accent: var(--a-pounce); }
[data-accent="holt"] { --accent: var(--a-holt); }
[data-accent="perch"] { --accent: var(--a-perch); }
[data-accent="nebelung"] { --accent: var(--a-nebelung); }
[data-accent="trill"] { --accent: var(--a-trill); }

/* --- breadcrumb --------------------------------------------------- */

/* The only navigation the site has. Two or three words of mono at the
   top of a subpage, with the current page not a link — enough to get
   back up, not a nav bar. */
.crumbs {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 0.78rem;
  color: var(--ink-3);
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: baseline;
}

.crumbs .sep {
  color: var(--rule);
  user-select: none;
}

.crumbs [aria-current="page"] {
  color: var(--ink-2);
}

/* --- the catalogue ------------------------------------------------ */

.catalogue {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: clamp(2.5rem, 6vw, 3.5rem);
}

.entry {
  display: flex;
  flex-direction: column;
  gap: 1.05rem;
}

.entry-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4rem 0.9rem;
}

.entry-name {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 1.12rem;
  color: var(--ink);
  margin: 0;
  font-weight: 400;
}

/* Same borrowed-accent rule as the landing index: a product's name takes
   a product's colour, on hover, and only there. */
.entry-head a:hover,
.entry-head a:focus-visible {
  color: var(--accent, var(--ink));
  text-decoration-color: var(--accent, var(--ink));
}

.entry-line {
  margin: 0;
  color: var(--ink-2);
  max-width: 58ch;
}

/* Three words, not a filter UI. With one desktop in the list there is
   nothing to filter; these are here to say what kind of thing it is at
   a glance, and they'll still be true at four. */
.meta {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  color: var(--ink-3);
  white-space: nowrap;
}

/* --- the shot frames ---------------------------------------------- */

/* Deliberately empty. A dashed hairline and a mono caption saying what
   the picture will be — never a fake screenshot, never a stock image.
   When a real capture exists, drop an <img> inside and delete the
   <span> label beside it. */
.shot {
  aspect-ratio: 16 / 10;
  border: 1px dashed var(--rule);
  border-radius: 3px;
  background: var(--well);
  display: grid;
  place-items: center;
  padding: 1rem;
}

.shot span {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  color: var(--ink-3);
  text-align: center;
  text-wrap: balance;
  line-height: 1.5;
}

.shot img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 2px;
}

/* Two small frames beside each other on anything wider than a phone,
   stacked below. No carousel, no lightbox — they're pictures. */
.shots {
  display: grid;
  gap: 0.9rem;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}

/* Letterbox, not a void. A full-width 16:9 empty frame is 400px of
   nothing and reads as a broken image; a banner-shaped one reads as a
   slot. Give it 16:9 back on the day it holds a real capture. */
.shot--wide {
  aspect-ratio: 2.4 / 1;
}

.shots .shot--wide {
  grid-column: 1 / -1;
}

/* --- sections ------------------------------------------------------ */

.block {
  display: flex;
  flex-direction: column;
  gap: 1.05rem;
}

.block h2 {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  font-weight: 400;
  color: var(--ink-3);
  margin: 0;
  padding-bottom: 0.75rem;
  border-bottom: 1px solid var(--rule);
}

.block p {
  margin: 0;
  color: var(--ink-2);
  max-width: 62ch;
}

/* The landing page's catalogue section, and the only fragment target on the
   site. Every /desktops link already in the wild — the 301 in _redirects,
   404.html, /haus's Elsewhere list — lands here, and a fragment jump skips
   .sheet's whole top padding, so without this the DESKTOPS rule arrives
   flush against the top edge of the viewport. Not the sheet's full padding:
   a fragment SHOULD sit higher than the top of the document, just not
   touching it. */
#desktops {
  scroll-margin-top: clamp(1.5rem, 4vw, 2.5rem);
}

/* --- the command --------------------------------------------------- */

.cmd {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem 0.9rem;
  border: 1px solid var(--rule);
  border-radius: 3px;
  background: var(--well);
  padding: 0.85rem 1rem;
}

.cmd code {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 0.82rem;
  line-height: 1.6;
  color: var(--ink);
  overflow-x: auto;
  white-space: pre;
  /* The command is long and a phone is narrow. `min-width: 0` is the
     load-bearing half: without it a flex item refuses to shrink below its
     content, the box pushes the sheet wider than the viewport, and every
     paragraph on the page runs off the right edge. With it, the command
     scrolls inside its own frame and the page doesn't move. */
  flex: 1 1 12rem;
  min-width: 0;
  -webkit-overflow-scrolling: touch;
}

/* Hidden in markup and revealed by the script, so a page with no JS
   shows a plain selectable command and not a button that does nothing. */
.copy {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: 2px;
  padding: 0.3rem 0.6rem;
  cursor: pointer;
  flex: 0 0 auto;
}

.copy:hover,
.copy:focus-visible {
  color: var(--ink);
  border-color: var(--ink-3);
}

.copy[hidden] {
  display: none;
}

.aside {
  font-size: 0.86rem;
  color: var(--ink-3);
  margin: 0;
  max-width: 62ch;
}

.aside code,
.block p code,
.facts code {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 0.86em;
  color: var(--ink-2);
}

/* --- fact lists ---------------------------------------------------- */

/* One term, one clause. A table would rule four lines to say two
   things; this says them in the same left edge as the prose. */
.facts {
  margin: 0;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.5rem 1.1rem;
  max-width: 58ch;
}

.facts dt {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 0.82rem;
  color: var(--ink);
  line-height: 1.75;
}

.facts dd {
  margin: 0;
  color: var(--ink-2);
  line-height: 1.75;
}

@media (max-width: 30rem) {
  .facts {
    grid-template-columns: 1fr;
    gap: 0.15rem;
  }

  .facts dd {
    margin-bottom: 0.65rem;
  }
}

.plain {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  color: var(--ink-2);
  max-width: 58ch;
}

.plain .index-name {
  font-size: 0.88rem;
}

/* Same correction, for the one place a product name sits inside an .aside:
   the landing page's closing "also from hausfold" line. (The note under the
   desktop catalogue used to be the other one; it lost its haus link when the
   catalogue moved onto the landing page and haus got a block of its own.)
   .index-name's 0.92rem is an absolute rem, so
   without this it renders BIGGER and at brighter ink than the
   0.86rem/--ink-3 note around it — a link that outshouts its own
   sentence. Relative units here, like `.aside code` already uses. */
.aside .index-name {
  font-size: 0.88em;
  color: var(--ink-2);
}

/* holt and nebelung are named in a closing .aside rather than in the
   index, so the accent rule above — scoped to `.index li[data-accent]` —
   never reaches them. Same bargain, one level down: the accent sits on the
   anchor itself here because there is no list item to hang it on, and the
   [data-accent="…"] token rules are element-agnostic already. */
.aside a.index-name[data-accent]:hover,
.aside a.index-name[data-accent]:focus-visible {
  color: var(--accent, var(--ink-2));
  text-decoration-color: var(--accent, var(--ink-2));
}

/* --- colophon ----------------------------------------------------- */

/* One hairline and one line of type. The grid of ruled cells this
   replaced spent four boxes on two facts. */
.colophon {
  border-top: 1px solid var(--rule);
  padding-top: 1.15rem;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.45rem 1.6rem;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 0.8rem;
  color: var(--ink-3);
}

/* The broadsheet conceit, kept to one mark: masthead, standfirst and
   lede are all newspaper words, and this is the edition they belong to.
   Month is enough — the page changes on the order of months. */
.colophon .issue {
  margin-left: auto;
  white-space: nowrap;
  font-size: 0.66rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

/* Once the row wraps, `margin-left: auto` would strand the issue alone
   on its own right-hand line. Let it sit with the links instead. */
@media (max-width: 30rem) {
  .colophon .issue {
    margin-left: 0;
  }
}

/* The org github link is a mark, not a URL — an icon reads faster than
   the seventh "github.com/hausfold" on the page, and it's the only
   colophon link that repeats verbatim across the whole site.

   `.colophon` aligns its row on the text baseline, but a flex container
   with no text of its own synthesizes its baseline as its bottom edge —
   that bottom edge then lands ON the baseline, so the whole glyph floats
   above the row instead of sitting in it. `align-self: center` opts this
   one item out of baseline alignment and centers it on the row's cross
   axis instead; sizing the mark in `em` keeps it in step with the
   colophon's own font-size rather than a fixed pixel count. */
.colophon .gh {
  display: inline-flex;
  align-self: center;
  text-decoration: none;
}

.colophon .gh svg {
  display: block;
  width: 1.05em;
  height: 1.05em;
}

.colophon .gh:hover,
.colophon .gh:focus-visible {
  color: var(--ink);
}

a {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: var(--ink-3);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.25em;
}

a:hover,
a:focus-visible {
  text-decoration-color: currentColor;
}

a:focus-visible {
  outline: 2px solid var(--ink-3);
  outline-offset: 3px;
}
