/* Hallmark · shape: Index-First · genre: modern-minimal · theme: Manifest (custom, first built for this index) · job: try · draw: none, the theme is named for the manifest sheet a dispatch desk files
 * hero: headline, one line, search and its actions on the sheet, the count strip and the replacements ledger directly below · nav: wordmark left, three links right, stacks under 40rem · footer: a mast, the wordmark over the links, attribution under the rule · imagery: each project's own mark from the selfh.st icon pack hotlinked at the row, the GitHub owner avatar behind it, a letter tile where a project has neither · signature: every listing names the hosted product it replaces, keyed with the orange rule
 * axes: light/grotesk-condensed/two-signal · posture: restrained · contrast: pass · fold: pass · v2.0.0 */
/* Hallmark · pre-emit critique: P4 H4 E4 S5 R5 V4 · weakest: V, a catalogue earns its distinction in the row; the icon column and the two signals carry it */
/* Hallmark · dismissed 58 · the home page is an index; its sections are the listings themselves, parted by bar rules, and it is read by scanning */

:root {
  color-scheme: light;
  --space-3xs: 2px; --space-2xs: 4px; --space-xs: 8px; --space-sm: 12px; --space-md: 16px; --space-lg: 24px; --space-xl: 40px; --space-2xl: 64px;
  --text-xs: 0.75rem; --text-sm: 0.8125rem; --text-md: 0.9375rem; --text-lg: 1.0625rem; --text-xl: 1.375rem; --text-2xl: 1.75rem;
  --text-display: clamp(2rem, 1.375rem + 2.75vw, 2.75rem); --text-section: 1.5rem; --text-title: 1.25rem; --text-lead: 1.125rem;
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1); --ease-in: cubic-bezier(0.7, 0, 0.84, 0); --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --dur-micro: 120ms; --dur-short: 220ms; --dur-long: 420ms;
  --color-error: oklch(52% 0.19 27); --color-success: oklch(50% 0.12 150);
  --container: 76rem; --gutter: 24px; --gap-columns: 24px; --section-gap-s: 56px; --section-gap: 72px;
  --z-base: 1; --z-raised: 10; --z-dropdown: 100; --z-sticky: 200; --z-sticky-nav: 300; --z-modal: 400; --z-toast: 500; --z-tooltip: 600;
  --color-paper: oklch(92.5% 0.016 152); --color-paper-2: oklch(90% 0.018 152); --color-paper-3: oklch(86.5% 0.02 152);
  --color-sheet: oklch(98.7% 0.004 130); --color-band: oklch(96.4% 0.013 150); --color-hover: oklch(93% 0.03 152);
  --color-ink: oklch(19% 0.024 162); --color-ink-2: oklch(30% 0.02 162); --color-muted: oklch(36% 0.018 160);
  --color-rule: oklch(84.5% 0.014 150); --color-rule-2: oklch(19% 0.024 162);
  --color-accent: oklch(50% 0.155 155); --color-accent-deep: oklch(43% 0.14 155); --color-accent-ink: oklch(98.7% 0.004 130);
  --color-accent-2: oklch(54% 0.175 38); --color-accent-2-deep: oklch(45% 0.155 38);
  --color-focus: oklch(45% 0.15 155);
  --font-display: "Barlow Condensed", "Arial Narrow", ui-sans-serif, sans-serif;
  --font-body: "Barlow", ui-sans-serif, system-ui, sans-serif;
  --font-outlier: "DM Mono", ui-monospace, SFMono-Regular, monospace;
  --radius-card: 6px; --radius-pill: 999px; --radius-icon: 8px; --rule-hair: 1px; --rule-bar: 3px; --shadow-card: none;
  --tracking-display: -0.005em; --display-weight: 600; --icon-size: 40px;
}

*, *::before, *::after { box-sizing: border-box; }
html, body { overflow-x: clip; }
html { scrollbar-color: var(--color-muted) var(--color-paper); scroll-padding-top: var(--space-2xl); }
body { margin: 0; background: var(--color-paper); color: var(--color-ink-2); font-family: var(--font-body); font-size: var(--text-md); line-height: 1.5; -webkit-font-smoothing: antialiased; caret-color: var(--color-accent); }
::selection { background: color-mix(in oklab, var(--color-accent) 22%, transparent); color: var(--color-ink); }
:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
a { color: var(--color-ink); text-decoration: underline; text-decoration-color: var(--color-accent); text-decoration-thickness: 1px; text-underline-offset: 0.15em; transition: text-decoration-thickness var(--dur-micro) var(--ease-out); }
@media (hover: hover) { a:hover { text-decoration-thickness: 2px; } }
h1, h2, h3 { margin: 0; font-family: var(--font-display); font-weight: var(--display-weight); font-synthesis: none; letter-spacing: var(--tracking-display); line-height: 1.08; overflow-wrap: break-word; min-width: 0; text-wrap: balance; color: var(--color-ink); }
h1 { max-width: 24ch; font-size: var(--text-display); }
h2 { max-width: 34ch; font-size: var(--text-section); text-transform: uppercase; line-height: 1.15; letter-spacing: 0.01em; }
h3 { max-width: 44ch; font-size: var(--text-title); line-height: 1.2; }
.lead { font-size: var(--text-lead); line-height: 1.45; max-width: 54ch; color: var(--color-ink-2); }
p { margin: 0; text-wrap: pretty; }
img, video { max-width: 100%; height: auto; display: block; }
[hidden] { display: none !important; }
button, input, select, textarea { font: inherit; }
.num { font-family: var(--font-outlier); font-variant-numeric: tabular-nums; }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
@media (max-width: 60rem) { :root { --gutter: 20px; --section-gap-s: 48px; --section-gap: 64px; } }
@media (max-width: 40rem) { :root { --gutter: 16px; --section-gap-s: 40px; --section-gap: 56px; --gap-columns: 16px; --icon-size: 36px; } }
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; } }

/* The sheet: the manifest page laid on the dispatch stock. */
.sheet { width: 100%; max-width: var(--container); min-height: 100dvh; margin-inline: auto; padding-inline: var(--gutter); background: var(--color-sheet); border-top: var(--rule-bar) solid var(--color-ink); overflow-wrap: break-word; }

/* Chrome */
.site-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-xs) var(--space-lg); padding-block: var(--space-sm); border-bottom: var(--rule-hair) solid var(--color-rule); }
.wordmark { font-family: var(--font-display); font-weight: var(--display-weight); font-size: var(--text-xl); letter-spacing: var(--tracking-display); color: var(--color-ink); text-decoration: none; display: inline-flex; align-items: center; min-height: 44px; }
.site-nav { display: flex; flex-wrap: wrap; gap: var(--space-2xs) var(--space-md); }
.site-nav a { font-weight: 500; font-size: var(--text-sm); color: var(--color-ink-2); white-space: nowrap; display: inline-flex; align-items: center; min-height: 44px; padding-inline: var(--space-2xs); }

/* Hero */
.hero { padding-block: var(--space-2xl) 0; }
.hero .lead { margin-top: var(--space-md); }
.search { margin-top: var(--space-xl); max-width: 44rem; }
.search label { display: block; font-weight: 500; font-size: var(--text-sm); color: var(--color-ink-2); margin-bottom: var(--space-xs); }
.search input { width: 100%; height: 52px; padding-inline: var(--space-md); border: var(--rule-hair) solid var(--color-muted); border-radius: var(--radius-card); background: var(--color-sheet); color: var(--color-ink); font-size: var(--text-md); }
.search input::placeholder { color: var(--color-muted); }
.search input:disabled { color: var(--color-muted); border-color: var(--color-rule); }
.hero-actions { display: flex; flex-wrap: wrap; gap: var(--space-sm); margin-top: var(--space-lg); }
.btn { display: inline-flex; align-items: center; min-height: 48px; padding-inline: var(--space-lg); border: var(--rule-hair) solid var(--color-ink); border-radius: var(--radius-card); font-family: var(--font-display); font-weight: 500; font-size: var(--text-lg); color: var(--color-ink); background: transparent; text-decoration: none; white-space: nowrap; }
.btn--primary { background: var(--color-accent); border-color: var(--color-accent); color: var(--color-accent-ink); }
@media (hover: hover) { .btn--primary:hover { background: var(--color-accent-deep); border-color: var(--color-accent-deep); } .btn:hover { text-decoration: none; } }
a:active { text-decoration-thickness: 2px; }
.btn:active { background: var(--color-paper-3); }
.btn--primary:active { background: var(--color-accent-deep); border-color: var(--color-accent-deep); }
#results { margin-top: var(--space-lg); }
#results:empty { margin-top: 0; }
.results-note { font-size: var(--text-sm); color: var(--color-muted); margin-bottom: var(--space-sm); }

/* The count strip: the manifest header figures, set as large as the heads. */
.count-strip { list-style: none; margin: var(--space-xl) 0 0; padding: var(--space-md) 0; display: flex; flex-wrap: wrap; gap: var(--space-sm) var(--space-xl); border-top: var(--rule-bar) solid var(--color-ink); border-bottom: var(--rule-hair) solid var(--color-rule); }
.count-num { font-family: var(--font-display); font-weight: var(--display-weight); font-size: var(--text-2xl); line-height: 1.05; color: var(--color-ink); font-variant-numeric: tabular-nums; }
.count-label { margin-top: var(--space-3xs); font-size: var(--text-sm); color: var(--color-muted); }

/* Sections */
.section { margin-top: var(--section-gap-s); }
.section--wide { margin-top: var(--section-gap); }
/* A list that directly answers a page head sits closer than a new section. */
.page-head + .section { margin-top: var(--space-xl); }
.section-head { margin-bottom: var(--space-md); }
.section-head--long h2 { font-size: var(--text-xl); max-width: 60ch; }
.section-head p { margin-top: var(--space-xs); max-width: 65ch; color: var(--color-ink-2); }
.page-head { padding-top: var(--space-xl); }
.page-head h1 { max-width: 26ch; }
.page-head .lead { margin-top: var(--space-sm); }
.page-head--alt { border-top: var(--rule-bar) solid var(--color-accent-2); margin-top: var(--space-md); padding-top: var(--space-lg); }
.page-head--app { display: flex; gap: var(--space-md); align-items: flex-start; }
.page-head--app .icon { margin-top: var(--space-2xs); }
.page-head-main { min-width: 0; }
.crumb { font-size: var(--text-sm); font-weight: 500; color: var(--color-muted); margin-bottom: var(--space-xs); }
.crumb a { color: var(--color-ink-2); display: inline-flex; align-items: center; min-height: 44px; padding-inline: var(--space-2xs); }
.count-line { margin-top: var(--space-xs); font-size: var(--text-sm); color: var(--color-muted); }

/* Entries: one manifest line each. Icon, the filing, then its figures. */
.entries { list-style: none; margin: 0; padding: 0; border-top: var(--rule-bar) solid var(--color-rule-2); }
.entry { display: grid; grid-template-columns: var(--icon-size) minmax(0, 1fr) auto; grid-template-areas: "icon main figs"; gap: var(--space-2xs) var(--space-md); padding-block: var(--space-sm); padding-inline: var(--space-xs); border-bottom: var(--rule-hair) solid var(--color-rule); transition: background-color var(--dur-micro) var(--ease-out); }
.entries .entry:nth-child(even) { background: var(--color-band); }
/* Hover must outrank the band rule above (same specificity, later in the
   file) and read in a still image: a deeper tint, the green keyline at the
   row's left edge, and the name taking the signal. */
@media (hover: hover) {
  .entries .entry:hover { background: var(--color-hover); box-shadow: inset var(--rule-bar) 0 0 var(--color-accent); }
  .entries .entry:hover .entry-name a { color: var(--color-accent-deep); text-decoration-color: var(--color-accent-deep); }
}
.icon { grid-area: icon; position: relative; width: var(--icon-size); height: var(--icon-size); border-radius: var(--radius-icon); background: var(--color-paper-2); overflow: hidden; }
/* The letter stays hidden while an image is in play, so first paint is the
   plain tile, never a placeholder glyph that swaps out. It is revealed only
   when there is no image (icon--noimg) or the image failed (icon--fallback,
   set by the img's onerror). */
.icon-letter { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-family: var(--font-display); font-weight: var(--display-weight); font-size: var(--text-xl); color: var(--color-ink-2); opacity: 0; }
.icon--noimg .icon-letter, .icon--fallback .icon-letter { opacity: 1; }
.icon-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; background: var(--color-paper-2); }
.icon--lg { width: 56px; height: 56px; border-radius: 10px; }
.icon--lg .icon-letter { font-size: var(--text-2xl); }
.entry-main { grid-area: main; min-width: 0; }
.entry-name a { display: inline-flex; align-items: center; min-height: 44px; margin-block: calc(-1 * var(--space-xs)); padding-block: var(--space-xs); }
.entry-desc { margin-top: var(--space-3xs); max-width: 72ch; }
.entry-replaces { margin-top: var(--space-xs); padding-left: var(--space-sm); border-left: var(--rule-bar) solid var(--color-accent-2); font-size: var(--text-sm); line-height: 1.5; }
.entry-replaces .replaces-label { font-weight: 600; color: var(--color-ink); }
.entry-replaces a { text-decoration-color: var(--color-accent-2); }
/* Figures ride in two lines, not a four-line stack: stars and the status
   chip on the first, date and release on the second. The row's height is
   set by the filing, and the column is capped so the rail stays close. */
.entry-figs { grid-area: figs; min-width: 0; max-width: 14rem; }
.fig-top { display: flex; flex-wrap: wrap; justify-content: flex-end; align-items: center; column-gap: var(--space-xs); row-gap: var(--space-2xs); }
.fig-sub { display: flex; flex-wrap: wrap; justify-content: flex-end; column-gap: var(--space-sm); row-gap: var(--space-3xs); margin-top: var(--space-2xs); }
.fig-line { font-family: var(--font-outlier); font-size: var(--text-md); color: var(--color-ink); font-variant-numeric: tabular-nums; line-height: 1.3; white-space: nowrap; }
.fig-unit { font-size: var(--text-xs); color: var(--color-muted); }
.fig-note { font-family: var(--font-body); font-size: var(--text-sm); color: var(--color-muted); }
.chip { display: inline-block; padding: var(--space-3xs) var(--space-xs); border-radius: var(--radius-pill); font-weight: 600; font-size: var(--text-xs); line-height: 1.5; white-space: nowrap; }
.chip-active { background: var(--color-accent); color: var(--color-accent-ink); }
.chip-quiet { border: var(--rule-hair) solid var(--color-rule); color: var(--color-muted); font-weight: 500; }
.fig-date, .fig-release { font-family: var(--font-outlier); font-size: var(--text-xs); color: var(--color-muted); font-variant-numeric: tabular-nums; }
.fig-release { overflow-wrap: anywhere; }

/* The replacements ledger on the home page. */
.ledger { list-style: none; margin: 0; padding: 0; border-top: var(--rule-bar) solid var(--color-rule-2); }
.ledger li { display: grid; grid-template-columns: minmax(0, 14rem) minmax(0, 1fr); gap: var(--space-2xs) var(--space-lg); padding-block: var(--space-xs); padding-inline: var(--space-xs); border-bottom: var(--rule-hair) solid var(--color-rule); align-items: baseline; }
.ledger-product { font-family: var(--font-display); font-weight: var(--display-weight); font-size: var(--text-lg); display: inline-flex; align-items: center; min-height: 44px; margin-block: calc(-1 * var(--space-xs)); padding-block: var(--space-xs); }
.ledger-apps { min-width: 0; }

/* Link columns for the category and product indexes: name and count in one flex row. */
.linkcols { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0 var(--gap-columns); border-top: var(--rule-bar) solid var(--color-rule-2); }
.linkcols li { border-bottom: var(--rule-hair) solid var(--color-rule); min-width: 0; }
.linkcols a { display: flex; align-items: baseline; gap: var(--space-xs); min-height: 44px; padding-block: var(--space-2xs); text-decoration: none; }
.linkcols a:hover { text-decoration: underline; text-decoration-color: var(--color-accent); }
.linkcols .item-name { flex: 1 1 auto; min-width: 0; text-wrap: balance; }
.linkcols .n { flex: none; font-family: var(--font-outlier); font-size: var(--text-xs); color: var(--color-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* The record: an app page's facts, filed as ruled cells. */
.altto { margin-top: var(--space-lg); padding: var(--space-md); background: var(--color-band); border-left: var(--rule-bar) solid var(--color-accent-2); }
.altto-label { display: block; font-weight: 600; font-size: var(--text-sm); color: var(--color-ink); margin-bottom: var(--space-2xs); }
.altto-list { font-family: var(--font-display); font-weight: var(--display-weight); font-size: var(--text-xl); line-height: 1.3; color: var(--color-ink); max-width: 44ch; }
.altto-list a { text-decoration-color: var(--color-accent-2); }
.record { margin-top: var(--space-lg); border-top: var(--rule-bar) solid var(--color-rule-2); }
.record > div { display: grid; grid-template-columns: minmax(0, 12rem) minmax(0, 1fr); gap: var(--space-2xs) var(--space-lg); padding-block: var(--space-xs); border-bottom: var(--rule-hair) solid var(--color-rule); }
.record dt { font-weight: 500; font-size: var(--text-sm); color: var(--color-muted); }
.record dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
.record .num { font-size: var(--text-md); }

/* Entry names are h2 on category pages (heading order runs h1, then the
   entries) and h3 under a section head elsewhere. The class carries the
   title styling either way, so the printed row never changes. */
h2.entry-name { font-size: var(--text-title); text-transform: none; line-height: 1.2; letter-spacing: var(--tracking-display); max-width: 44ch; }

/* The screenshot: the project's own og:image, framed like a filed print
   under the app page head. If the image fails, the figure removes itself
   (inline onerror) and the page keeps its shape. */
.shot { margin: var(--space-lg) 0 0; padding: var(--space-sm); border: var(--rule-hair) solid var(--color-rule); background: var(--color-band); }
.shot img { width: 100%; border-radius: var(--radius-card); }

/* Long-form text column (the About page). */
.text-col { max-width: 65ch; }
.text-col p + p { margin-top: var(--space-sm); }

/* Footer */
.site-foot { margin-top: var(--section-gap-s); padding-block: var(--space-xl) var(--space-2xl); border-top: var(--rule-bar) solid var(--color-rule-2); }
.foot-mark { font-family: var(--font-display); font-weight: var(--display-weight); font-size: var(--text-xl); letter-spacing: var(--tracking-display); color: var(--color-ink); }
.foot-nav { display: flex; flex-wrap: wrap; gap: var(--space-2xs) var(--space-md); margin-top: var(--space-sm); }
.foot-nav a { font-weight: 500; font-size: var(--text-sm); color: var(--color-ink-2); white-space: nowrap; display: inline-flex; align-items: center; min-height: 44px; padding-inline: var(--space-2xs); }
.site-foot p { max-width: 65ch; }
.foot-note { margin-top: var(--space-md); font-size: var(--text-sm); color: var(--color-muted); }

/* Small screens: one column, figures become a row under the filing. */
@media (max-width: 60rem) {
  .linkcols { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ledger li { grid-template-columns: minmax(0, 11rem) minmax(0, 1fr); }
}
@media (max-width: 40rem) {
  .linkcols { grid-template-columns: minmax(0, 1fr); }
  .ledger li { grid-template-columns: minmax(0, 1fr); gap: var(--space-3xs); }
  .entry { grid-template-columns: var(--icon-size) minmax(0, 1fr); grid-template-areas: "icon main" ". figs"; row-gap: var(--space-xs); }
  .entry-figs { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2xs) var(--space-md); max-width: none; }
  .fig-top, .fig-sub { display: contents; }
  .record > div { grid-template-columns: minmax(0, 1fr); }
  .record dd { margin-top: var(--space-3xs); }
  .hero { padding-top: var(--space-xl); }
  .page-head { padding-top: var(--space-lg); }
  .page-head--app { gap: var(--space-sm); }
}
