/*
 * Pitchrow — dark-first, high contrast, zero ornament.
 *
 * Rules this file holds to:
 *   - No gradients anywhere. Flat surfaces separated by hairline borders.
 *   - No web fonts. A downloaded face costs a request and a reflow on the
 *     exact pages whose speed is the product; the system UI stack is already
 *     SF Pro / Segoe UI Variable / Roboto and reads modern with tight tracking.
 *   - Nothing may change size on hover or focus. Only colour transitions.
 */

:root {
  color-scheme: dark;

  --bg:            #0B0B0C;
  --surface:       #131316;
  --surface-2:     #1A1A1F;
  --text:          #F5F5F7;
  --muted:         #A1A1AB;
  --faint:         #6E6E78;
  --border:        #1F1F23;
  --border-strong: #33333B;

  --accent:        #4F7CFF;
  --accent-hover:  #6B90FF;
  --accent-fg:     #FFFFFF;
  --accent-soft:   rgba(79, 124, 255, 0.12);
  --accent-line:   rgba(79, 124, 255, 0.35);

  --ok:   #3FB950;
  --warn: #D29922;
  --bad:  #F85149;

  --sans: ui-sans-serif, system-ui, -apple-system, "SF Pro Text",
          "Segoe UI Variable Text", "Segoe UI", Inter, Roboto,
          "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", "Cascadia Code", "Roboto Mono", Menlo,
          Consolas, monospace;

  --shell: 44rem;
  --shell-wide: 72rem;

  --radius: 8px;
  --radius-sm: 6px;
  --radius-pill: 999px;
}

/* Dark is the brand default. Users who have explicitly asked their system for
   light get a properly considered light palette rather than an inverted guess. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    color-scheme: light;

    --bg:            #FFFFFF;
    --surface:       #FAFAFB;
    --surface-2:     #F3F3F5;
    --text:          #0B0B0C;
    --muted:         #5C5C66;
    --faint:         #8A8A94;
    --border:        #E7E7EB;
    --border-strong: #D2D2D9;

    --accent:        #2F5FE0;
    --accent-hover:  #244BC0;
    --accent-fg:     #FFFFFF;
    --accent-soft:   rgba(47, 95, 224, 0.07);
    --accent-line:   rgba(47, 95, 224, 0.30);

    --ok:   #1A7F37;
    --warn: #9A6700;
    --bad:  #CF222E;
  }
}
/* The same palette again, for a visitor who chose light explicitly. */
  :root[data-theme="light"] {
    color-scheme: light;

    --bg:            #FFFFFF;
    --surface:       #FAFAFB;
    --surface-2:     #F3F3F5;
    --text:          #0B0B0C;
    --muted:         #5C5C66;
    --faint:         #8A8A94;
    --border:        #E7E7EB;
    --border-strong: #D2D2D9;

    --accent:        #2F5FE0;
    --accent-hover:  #244BC0;
    --accent-fg:     #FFFFFF;
    --accent-soft:   rgba(47, 95, 224, 0.07);
    --accent-line:   rgba(47, 95, 224, 0.30);

    --ok:   #1A7F37;
    --warn: #9A6700;
    --bad:  #CF222E;
  }

* { box-sizing: border-box; }

/*
 * Always reserve the scrollbar gutter. Without it a short page has no
 * scrollbar and a long one does, so the viewport width changes between
 * navigations and the centred layout slides sideways every time.
 */
html {
  -webkit-text-size-adjust: 100%;
  scrollbar-gutter: stable;
}
@supports not (scrollbar-gutter: stable) {
  html { overflow-y: scroll; }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.6;
  letter-spacing: -0.005em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-feature-settings: "cv05" 1, "ss01" 1;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

::selection { background: var(--accent-soft); color: var(--text); }

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

:where(a, button, input, select, textarea):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

.shell { width: 100%; max-width: var(--shell); margin: 0 auto; padding: 0 1.5rem; }
.shell-wide { max-width: var(--shell-wide); }

.skip {
  position: absolute; left: -9999px; top: 0;
  background: var(--surface-2); color: var(--text);
  padding: .6rem 1rem; border-radius: var(--radius); z-index: 10;
  border: 1px solid var(--border-strong);
}
.skip:focus { left: 1rem; top: 1rem; }

/* ---------- header ---------- */

.site-header {
  border-bottom: 1px solid var(--border);
  position: sticky; top: 0; z-index: 20;
  background: transparent;
}
/*
 * The blur lives on a pseudo-element rather than on the header itself.
 * backdrop-filter makes an element a containing block for position: fixed
 * descendants, which pinned the mobile drawer inside the header instead of the
 * viewport. Moving the filter down a level keeps the effect and frees the
 * drawer. Not a gradient — a blur.
 */
.site-header::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: saturate(140%) blur(12px);
  -webkit-backdrop-filter: saturate(140%) blur(12px);
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .site-header::before { background: var(--bg); }
}

/*
 * Header and footer are the site's chrome and hold one width on every page,
 * while main varies with the page. At 76rem the header sat 32px left of the
 * content below it, which is the misalignment that shows up first.
 */
.site-header .header-inner {
  max-width: var(--shell-wide);
  display: flex; align-items: center; gap: 1.25rem;
  min-height: 60px;
}

.wordmark {
  display: inline-flex; align-items: center; gap: .55rem;
  /* The header is a wordmark and one menu button; at 1rem the brand read as
     small print next to it. The footer keeps the smaller size below. */
  font-weight: 600; font-size: 1.35rem; letter-spacing: -0.02em;
  color: var(--text);
}
.wordmark:hover { color: var(--text); }
/* Mark is an inline SVG (see layout.tsx) so the stylesheet stays free of
   gradients entirely, including the solid-fill kind used as a drawing trick. */
.wordmark-mark { display: block; flex: 0 0 auto; color: var(--accent); }
/*
 * The light travels along the row — the daily rotation, in miniature.
 *
 * Heights never change: equal cards are the whole point of the mark, so only
 * opacity, a one-pixel lift and a short glow are animated. It plays once on
 * load so touch users see it too, and loops while hovered. The global
 * prefers-reduced-motion rule switches it off entirely.
 */
@keyframes pitchrow-travel {
  0%, 100% { opacity: .28; transform: translateY(0); filter: none; }
  12%      { opacity: 1; transform: translateY(-1.5px);
             filter: drop-shadow(0 0 3px currentColor); }
  32%      { opacity: .28; transform: translateY(0); filter: none; }
}
.wordmark-mark .m {
  transform-box: fill-box;
  transform-origin: center;
  transition: opacity .2s ease;
  /* No fill-mode: each card settles back to its resting opacity below. */
  animation: pitchrow-travel 1.8s ease-in-out 1;
}
.wordmark-mark .m1 { opacity: .28; animation-delay: .2s; }
.wordmark-mark .m2 { opacity: 1;   animation-delay: .38s; }
.wordmark-mark .m3 { opacity: .28; animation-delay: .56s; }
.wordmark:hover .wordmark-mark .m { animation-iteration-count: infinite; }

.site-nav {
  display: flex; align-items: center; gap: .9rem;
  font-size: .875rem; margin-left: auto;
}
.site-nav > a {
  color: var(--muted); white-space: nowrap; font-weight: 450;
  transition: color .12s ease;
}
.site-nav > a:hover { color: var(--text); }
.site-nav > a.btn { color: var(--accent-fg); }
.nav-link[aria-current="page"] { color: var(--text); font-weight: 520; }

/* ---------- header search ---------- */

.hsearch { position: relative; display: flex; align-items: center; flex: 1 1 14rem; max-width: 24rem; }
.hsearch-icon { position: absolute; left: .7rem; color: var(--faint); pointer-events: none; }
.hsearch input {
  width: 100%; padding: .45rem .75rem .45rem 2.15rem;
  font-size: .875rem; border-radius: var(--radius);
  background: var(--surface); border: 1px solid var(--border);
  color: var(--text);
}
.hsearch input:focus { border-color: var(--accent); background: var(--bg); outline: none; }
.hsearch input::-webkit-search-cancel-button { filter: grayscale(1); opacity: .5; }

/* Shown only on narrow screens, where the field itself does not fit. */
.hsearch-compact { display: none; color: var(--muted); padding: .35rem; }
.hsearch-compact:hover { color: var(--text); }

/* ---------- account menu ---------- */

.umenu { position: relative; }
.umenu-trigger {
  display: inline-flex; align-items: center; gap: .3rem;
  cursor: pointer; list-style: none;
  padding: .2rem .3rem .2rem .2rem; border-radius: var(--radius);
  border: 1px solid transparent; transition: background-color .12s ease, border-color .12s ease;
}
.umenu-trigger::-webkit-details-marker { display: none; }
.umenu-trigger::marker { content: ""; }
.umenu-trigger:hover, .umenu[open] .umenu-trigger {
  background: var(--surface); border-color: var(--border-strong);
}
.umenu-caret { color: var(--faint); transition: transform .12s ease; }
.umenu[open] .umenu-caret { transform: rotate(180deg); }

.umenu-panel {
  position: absolute; right: 0; top: calc(100% + .5rem);
  min-width: 13.5rem; padding: .35rem; z-index: 30;
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  box-shadow: 0 10px 30px rgba(0, 0, 0, .32);
}
.umenu-head {
  padding: .5rem .6rem .6rem; margin-bottom: .35rem;
  border-bottom: 1px solid var(--border);
}
.umenu-name { display: block; color: var(--text); font-weight: 550; font-size: .875rem; }
.umenu-handle { display: block; color: var(--faint); font-size: .8rem; font-family: var(--mono); }
.umenu-panel a {
  display: block; padding: .48rem .6rem; border-radius: var(--radius-sm);
  color: var(--muted); font-size: .875rem;
}
.umenu-panel a:hover { background: var(--surface-2); color: var(--text); }
.umenu-sep { height: 1px; background: var(--border); margin: .35rem 0; }

.avatar {
  width: 28px; height: 28px; border-radius: 50%; display: block;
  object-fit: cover; border: 1px solid var(--border-strong); flex: 0 0 auto;
}
.avatar-mono {
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--surface-2); color: var(--muted);
  font-size: .8rem; font-weight: 600;
}

/* ---------- buttons ---------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--accent); color: var(--accent-fg);
  padding: .6rem 1rem; border-radius: var(--radius);
  font-weight: 550; font-size: .9rem; font-family: inherit;
  line-height: 1.35; cursor: pointer; letter-spacing: -0.01em;
  /* Transparent rather than none, so the solid and ghost variants box out to
     exactly the same height when they sit side by side. */
  border: 1px solid transparent;
  transition: background-color .12s ease, border-color .12s ease, color .12s ease;
  /* A two-word label should not stack; these sit in rows beside content. */
  white-space: nowrap;
}
.btn:hover { background: var(--accent-hover); color: var(--accent-fg); }
.btn-sm { padding: .4rem .75rem; font-size: .85rem; }
.btn-ghost {
  background: transparent; color: var(--text);
  border-color: var(--border-strong);
}
.btn-ghost:hover { background: var(--surface-2); border-color: var(--faint); color: var(--text); }

/* ---------- main ---------- */

/* main carries class="shell", so a bare `main` selector loses to `.shell` on
   specificity and its vertical padding silently never applies. */
main { flex: 1; }
main.shell { padding-top: 3.5rem; padding-bottom: 5rem; }

h1 {
  font-size: 2.1rem; line-height: 1.15; letter-spacing: -0.035em;
  margin: 0 0 .6rem; font-weight: 620;
}
h2 { font-size: 1.05rem; letter-spacing: -0.02em; margin: 0; font-weight: 570; }

.lede {
  font-size: 1.0625rem; color: var(--muted); margin: 0 0 1.75rem;
  max-width: 36rem; line-height: 1.6;
}

.section-label {
  font-family: var(--mono);
  font-size: .6875rem; text-transform: uppercase; letter-spacing: .12em;
  color: var(--faint); font-weight: 500; margin: 0 0 1.25rem;
}

.rule { border: 0; border-top: 1px solid var(--border); margin: 3rem 0; }

/* ---------- hero ---------- */

.hero { margin-bottom: 2.75rem; }
.hero h1 { font-size: 2.6rem; letter-spacing: -0.04em; line-height: 1.08; }
.hero-actions { display: flex; flex-wrap: wrap; gap: .6rem; align-items: center; }
.hero-note { font-size: .85rem; color: var(--faint); margin: 1rem 0 0; }

/* ---------- the wall ---------- */

.wall { display: flex; flex-direction: column; }

/*
 * Padding and margin are fixed and only colours change on hover, so hovering a
 * card can never reflow the grid.
 */
.pitch {
  padding: 1.6rem 1rem;
  margin: 0 -1rem;
  border-bottom: 1px solid var(--border);
  border-radius: var(--radius);
  transition: background-color .12s ease, border-color .12s ease;
}
.pitch:hover { background: var(--surface); }
.pitch:last-child { border-bottom: 0; }

/*
 * A row per pitch, laid out across the full width.
 *
 * The site is called Pitchrow and the mark is three cards in a row, so rows are
 * the format. What made the page read as a thin strip was the 44rem column, not
 * the format — these span the wide shell and put identity, pitch and attribution
 * in their own tracks instead of stacking them.
 */
/*
 * On a wide screen the wall is a grid of cards, not a list of rows.
 *
 * As rows it put five pitches on a full desktop screen: text lines running the
 * best part of a thousand pixels, the maker and category stranded in the far
 * right with a gulf of empty space before them, and each row tall enough that
 * scrolling showed almost nothing new. A wall that shows five things is not a
 * wall. Three columns put nine to twelve in the same space, give the text a
 * readable measure, and put the meta back under the words it belongs to.
 *
 * Rows return below 900px, where one column is the only sensible shape.
 */
.wall--rows {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
  gap: .75rem;
}
.wall--rows .pitch {
  display: flex; flex-direction: column; gap: .55rem;
  height: 100%;
  margin: 0; padding: 1.15rem;
  border: 1px solid var(--border); border-bottom: 1px solid var(--border);
  border-radius: var(--radius);
}
.wall--rows .pitch:hover { border-color: var(--border-strong); background: var(--surface); }
.wall--rows .pitch-head {
  margin: 0; display: flex; align-items: center; gap: .7rem; min-width: 0;
}
/* Width rather than the custom property: the component sets --thumb inline, and
   an inline custom property beats one from a stylesheet. */
.wall--rows .pitch .thumb { width: 44px; height: 44px; }
.wall--rows .pitch .thumb-mono { font-size: 19px; }
.wall--rows .pitch-title { min-width: 0; }
.wall--rows .pitch h2 { font-size: 1rem; margin-bottom: .1rem; }
.wall--rows .tagline {
  font-size: .8125rem;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.wall--rows .pitch-excerpt {
  margin: 0; font-size: .875rem; line-height: 1.6; max-width: none;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
/* Pushed to the bottom so the meta lines up across a row of uneven cards. */
.wall--rows .pitch-meta {
  margin: auto 0 0; padding-top: .2rem;
  justify-content: flex-start; text-align: left;
  flex-direction: row; align-items: center; gap: .5rem;
}
.wall--rows .pitch-meta .dot { display: inline; }

/* Below the wide layout a row cannot hold four tracks, so it stacks. */


/*
 * Whole-card click.
 *
 * The row lights up on hover, which promises the whole thing is clickable — but
 * only the title was a link, so clicking the body just selected text. The title
 * anchor is stretched over the card with a pseudo-element instead of wrapping
 * the card in an <a>, because the card already contains links and nested
 * anchors are invalid.
 *
 * Being a real anchor, this keeps cmd/middle-click-to-new-tab and the
 * right-click menu working, which a JavaScript click handler would not.
 *
 * Opt-in via .pitch--link: the admin queue reuses .pitch and has Approve and
 * Reject buttons inside, which an overlay would cover.
 */
.pitch--link { position: relative; }
.pitch--link h2 a::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: var(--radius);
}
/* Keep the genuinely separate destinations above the overlay. */
.pitch--link .pitch-meta a { position: relative; z-index: 1; }

/* With the label itself stretched, show focus on the card it now represents. */
.pitch--link:has(h2 a:focus-visible) {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
  border-radius: var(--radius);
}
.pitch--link h2 a:focus-visible { outline: none; }

.pitch-head { display: flex; gap: .875rem; align-items: flex-start; margin-bottom: .75rem; }
.pitch-title { min-width: 0; }
.pitch h2 { font-size: 1.0625rem; margin-bottom: .125rem; }
.pitch h2 a { color: var(--text); }
.pitch:hover h2 a { color: var(--accent); }

.tagline { margin: 0; color: var(--muted); font-size: .9375rem; line-height: 1.45; }

.pitch-excerpt {
  font-size: .9375rem; line-height: 1.65; margin: 0 0 .875rem;
  color: var(--muted); max-width: 40rem;
}

.pitch-meta {
  margin: 0; font-size: .8125rem; color: var(--faint);
  display: flex; align-items: center; flex-wrap: wrap; gap: .5rem;
}
.pitch-meta a { color: var(--faint); }
.pitch-meta a:hover { color: var(--text); }
.dot { color: var(--border-strong); }

/* Sponsored placements. Marked visually here and, more importantly, with
   rel="sponsored" on the outbound link — see routes/product.tsx. */
.sponsor-tag {
  font-family: var(--mono); font-size: .625rem; text-transform: uppercase;
  letter-spacing: .1em; color: var(--accent);
  border: 1px solid var(--accent-line); border-radius: var(--radius-sm);
  padding: .1rem .4rem; white-space: nowrap;
}
.pitch--sponsored { background: var(--accent-soft); }
.pitch--sponsored:hover { background: var(--accent-soft); }

/* ---------- thumbnails ---------- */

.thumb {
  flex: 0 0 auto; border-radius: var(--radius-sm); object-fit: cover;
  border: 1px solid var(--border); background: var(--surface-2);
  /* Set inline by the component; a media query can then change it per layout. */
  width: var(--thumb, 56px); height: var(--thumb, 56px);
}
.thumb-mono { font-size: calc(var(--thumb, 56px) * 0.42); }
/* Deterministic hue per product, deliberately desaturated so a long wall reads
   as tinted neutrals rather than a bag of sweets. */
.thumb-mono {
  display: inline-flex; align-items: center; justify-content: center;
  font-weight: 560; letter-spacing: -0.02em;
  color: hsl(var(--mono-h) 62% 74%);
  background: hsl(var(--mono-h) 38% 17%);
  border: 1px solid hsl(var(--mono-h) 34% 26%);
}
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .thumb-mono {
    color: hsl(var(--mono-h) 42% 38%);
    background: hsl(var(--mono-h) 40% 95%);
    border-color: hsl(var(--mono-h) 30% 88%);
  }
}
/* The same palette again, for a visitor who chose light explicitly. */
  :root[data-theme="light"] .thumb-mono {
    color: hsl(var(--mono-h) 42% 38%);
    background: hsl(var(--mono-h) 40% 95%);
    border-color: hsl(var(--mono-h) 30% 88%);
  }

/* ---------- compact rows ---------- */

.rows { list-style: none; margin: 0; padding: 0; }
.row {
  display: flex; align-items: center; gap: .75rem;
  padding: .7rem 0; border-bottom: 1px solid var(--border);
}
.row:last-child { border-bottom: 0; }
.row--link {
  position: relative;
  padding-left: .75rem; padding-right: .75rem;
  margin-left: -.75rem; margin-right: -.75rem;
  border-radius: var(--radius-sm);
  transition: background-color .12s ease;
}
.row--link:hover { background: var(--surface); }
.row--link:hover .row-name { color: var(--accent); }
.row--link .row-name::after { content: ""; position: absolute; inset: 0; }
.row--link:has(.row-name:focus-visible) {
  outline: 2px solid var(--accent); outline-offset: -2px; border-radius: var(--radius-sm);
}
.row--link .row-name:focus-visible { outline: none; }
/* Addresses and long product names live in these rows. */
.row-main { flex: 1 1 auto; min-width: 0; }
.row-name { display: block; font-weight: 520; color: var(--text); font-size: .9375rem; }
.row-name, .row-tagline { overflow-wrap: anywhere; }
.row-name:hover { color: var(--accent); }
.row-tagline { display: block; color: var(--faint); font-size: .8125rem; line-height: 1.45; }

/* ---------- product page ---------- */

.product-header { display: flex; gap: 1rem; align-items: flex-start; margin-bottom: 1.5rem; }
.product-header h1 { margin-bottom: .3rem; font-size: 1.9rem; }
.product-tagline { font-size: 1.0625rem; color: var(--muted); margin: 0; line-height: 1.5; }

.prose {
  font-size: 1.0625rem; line-height: 1.7; margin: 0 0 2rem;
  white-space: pre-wrap; max-width: 38rem; color: var(--text);
  /* Marked as the maker's own words rather than page furniture. This is the
     one place on the site where a block of prose is the content. */
  padding-left: 1.1rem; border-left: 2px solid var(--accent-line);
}

.visit-row { display: flex; flex-wrap: wrap; align-items: center; gap: .875rem; margin-bottom: 2rem; }
.visit-url { font-family: var(--mono); font-size: .8125rem; color: var(--faint); word-break: break-all; }

.shot {
  width: 100%; height: auto; border-radius: var(--radius);
  border: 1px solid var(--border); margin-bottom: 2rem; display: block;
  /* Screenshots are captured at 1280x800. Declaring the ratio reserves the box
     before load so the pitch below never jumps down. */
  aspect-ratio: 1280 / 800;
  object-fit: cover;
  background: var(--surface);
}

.facts {
  display: flex; flex-wrap: wrap; gap: .4rem; list-style: none;
  margin: 0 0 2rem; padding: 1.1rem 0 0;
  border-top: 1px solid var(--border);
}
.fact {
  display: inline-block; font-size: .8125rem; padding: .3rem .65rem;
  border-radius: var(--radius); border: 1px solid var(--border);
  background: var(--surface); color: var(--muted); white-space: nowrap;
}
.fact--link { color: var(--accent); border-color: var(--accent-line); background: var(--accent-soft); }
.fact--link:hover { border-color: var(--accent); }
.fact--quiet { color: var(--faint); font-family: var(--mono); font-size: .75rem; }

.tags { display: flex; flex-wrap: wrap; gap: .35rem; list-style: none; margin: 0; padding: 0; }
.tag {
  font-size: .78rem; padding: .15rem .5rem; border-radius: var(--radius-pill);
  background: var(--surface-2); color: var(--muted); border: 1px solid var(--border);
}

.maker-card {
  display: flex; gap: .875rem; align-items: flex-start;
  padding: 1.15rem; border: 1px solid var(--border);
  border-radius: var(--radius); background: var(--surface);
}
.maker-card p { margin: .2rem 0 0; font-size: .875rem; color: var(--faint); }

/* A notice sitting inside a card rather than leading a page. */
.notice-inline { margin: 1.1rem 0 0; }

.notice {
  padding: .875rem 1rem; border-radius: var(--radius);
  background: var(--surface); color: var(--muted);
  font-size: .875rem; margin: 0 0 1.75rem;
  border: 1px solid var(--border);
  border-left: 2px solid var(--accent);
}

/* ---------- chips & search ---------- */

.chips {
  display: flex; flex-wrap: wrap; list-style: none; margin: 0; padding: 0;
  /* Row gap is larger than column gap: wrapped filter rows need more air
     between them than neighbouring chips do. */
  column-gap: .45rem; row-gap: .6rem;
}
.chip {
  display: inline-flex; align-items: center; gap: .4rem;
  padding: .45rem .8rem; border-radius: var(--radius);
  border: 1px solid var(--border); background: transparent;
  color: var(--muted); font-size: .85rem;
  transition: border-color .12s ease, color .12s ease, background-color .12s ease;
}
.chip:hover { border-color: var(--border-strong); color: var(--text); }
.chip[aria-current="page"] {
  background: var(--accent); border-color: var(--accent); color: var(--accent-fg);
}
.chip .count { color: var(--faint); font-variant-numeric: tabular-nums; font-size: .78rem; }
.chip[aria-current="page"] .count { color: rgba(255,255,255,.72); }

.searchbar { display: flex; gap: .5rem; margin-bottom: 2rem; }
.searchbar input { flex: 1; }

.empty { color: var(--faint); }

/* ---------- forms ---------- */

.form { max-width: 34rem; }
.field { margin-bottom: 1.5rem; }
.field label { display: block; font-weight: 520; font-size: .875rem; margin-bottom: .4rem; }

input, select, textarea {
  width: 100%; padding: .6rem .75rem; font-size: .9375rem; font-family: inherit;
  border: 1px solid var(--border-strong); border-radius: var(--radius);
  background: var(--surface); color: var(--text);
  transition: border-color .12s ease;
}
input::placeholder, textarea::placeholder { color: var(--faint); }
input:hover, select:hover, textarea:hover { border-color: var(--faint); }
textarea { line-height: 1.6; resize: vertical; }

.hint { font-size: .8125rem; color: var(--faint); margin: .3rem 0 .5rem; line-height: 1.55; }
.field .hint { margin-top: 0; margin-bottom: .55rem; }
.error { color: #FF6B6B; font-size: .8125rem; margin: .35rem 0 0; }
.error-banner {
  padding: .8rem 1rem; border-radius: var(--radius); margin: 0 0 1.5rem;
  background: var(--surface); border: 1px solid var(--border);
  border-left: 2px solid #FF6B6B; color: var(--text); font-size: .9rem;
}
.cf-turnstile { margin-bottom: 1.35rem; }

/* ---------- dashboard ---------- */

.stat-table { width: 100%; border-collapse: collapse; font-size: .875rem; }
.stat-table th {
  text-align: left; font-family: var(--mono); font-size: .6875rem;
  text-transform: uppercase; letter-spacing: .1em; color: var(--faint);
  font-weight: 500; padding: 0 .8rem .7rem 0; border-bottom: 1px solid var(--border);
}
.stat-table td { padding: .8rem .8rem .8rem 0; border-bottom: 1px solid var(--border); vertical-align: top; }
.stat-table td.num { text-align: right; font-variant-numeric: tabular-nums; padding-right: 0; color: var(--muted); }
.status {
  display: inline-block; font-family: var(--mono);
  font-size: .6875rem; text-transform: uppercase; letter-spacing: .08em;
  padding: .15rem .45rem; border-radius: var(--radius-sm);
  background: var(--surface-2); color: var(--muted);
  border: 1px solid var(--border); white-space: nowrap;
}
.dash-actions { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem; margin-top: 2.25rem; }

/* ---------- first run ---------- */

.first-run {
  padding: 2.5rem 1.75rem; border: 1px dashed var(--border-strong);
  border-radius: var(--radius); text-align: center; background: var(--surface);
}
.first-run p { margin: 0 0 1.25rem; color: var(--muted); max-width: 26rem; margin-inline: auto; }

/* ---------- footer ---------- */

.site-footer {
  border-top: 1px solid var(--border); margin-top: auto;
  padding: 2.25rem 0 1.5rem; font-size: .875rem; color: var(--faint);
  background: var(--surface);
}
/*
 * Brand on the left, link columns spread across the rest.
 *
 * The columns block used to be `auto`, so it shrank to its contents and sat
 * jammed against the right edge with a wide empty gap in the middle of the
 * footer. There were also four groups in a three-column grid, so the fourth
 * wrapped underneath and left a tall hole beside it.
 */
.footer-top {
  display: grid; gap: 2rem 4rem;
  grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
  align-items: start; padding-bottom: 1.6rem;
}
.footer-brand { max-width: 22rem; }
.footer-brand .wordmark { font-size: 1.25rem; margin-bottom: .7rem; }
.footer-brand p { margin: 0; line-height: 1.6; color: var(--faint); font-size: .8125rem; }

.footer-cols { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 2rem 1.5rem; }
.footer-cols .section-label { margin-bottom: .55rem; }
.footer-cols ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .35rem; }
.footer-cols a { color: var(--muted); font-size: .8125rem; white-space: nowrap; }
.footer-cols a:hover { color: var(--text); }

.footer-legal {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: .35rem 1.5rem; padding-top: 1.1rem;
  border-top: 1px solid var(--border);
  font-size: .75rem;
}
.footer-legal p { margin: 0; }
.footer-legal strong { color: var(--muted); font-weight: 560; }
.footer-sep { margin: 0 .5rem; color: var(--border-strong); }
.footer-org { font-family: var(--mono); font-size: .6875rem; letter-spacing: .01em; }

/* ---------- breadcrumbs ---------- */

.crumbs { margin: 0 0 1.4rem; font-size: .8125rem; }
.crumbs ol {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; align-items: center; gap: .1rem;
}
.crumbs li { display: inline-flex; align-items: center; min-width: 0; }
.crumbs a { color: var(--faint); }
.crumbs a:hover { color: var(--text); }
.crumbs [aria-current="page"] {
  color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 20rem;
}
.crumbs-sep { color: var(--border-strong); margin: 0 .45rem; }

/* ---------- category grid ---------- */

.cat-grid {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: .5rem;
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
}
.cat-tile {
  display: flex; align-items: center; justify-content: space-between; gap: .75rem;
  padding: .7rem .85rem; min-height: 44px;
  border: 1px solid var(--border); border-radius: var(--radius);
  color: var(--muted); font-size: .875rem;
  transition: border-color .12s ease, color .12s ease, background-color .12s ease;
}
.cat-tile:hover {
  border-color: var(--border-strong); color: var(--text); background: var(--surface);
}
.cat-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cat-count {
  font-family: var(--mono); font-size: .75rem; color: var(--faint);
  font-variant-numeric: tabular-nums; flex: 0 0 auto;
}
.cat-tile:hover .cat-count { color: var(--muted); }

/* ---------- responsive (kept last so overrides always win) ---------- */






/*
 * The wordmark is never truncated — the brand name has to survive on the
 * commonest phone widths. Below this size the search field cannot be given a
 * usable width alongside it, so it becomes an icon leading to the search page
 * and the name keeps its place.
 */


/* The category filter leads the page, so it owns the gap to the heading. */
.chips { margin-bottom: 2.25rem; }

/* ---------- review queue ---------- */

.rev {
  border: 1px solid var(--border); border-radius: var(--radius);
  padding: 1.25rem; margin-bottom: .85rem; background: var(--surface);
}
.rev-head { display: flex; gap: .85rem; align-items: flex-start; margin-bottom: .8rem; }
.rev-title { flex: 1; min-width: 0; }
.rev h2 { font-size: 1rem; margin-bottom: .1rem; }
.rev h2 a { color: var(--text); }
.rev h2 a:hover { color: var(--accent); }

.rev-meta {
  margin: 0; font-size: .8125rem; color: var(--faint);
  /* No dot separators. This row wraps, and a dot is either its own element -
     which can wrap alone and start a line - or attached to the item after it,
     which drags it to the start of the line just the same. Space separates it
     without either problem. */
  display: flex; flex-wrap: wrap; align-items: center; gap: .35rem 1rem;
  min-width: 0;
}
/* The product URL, stripped of its scheme. Same problem as the message above:
   a flex item will not shrink below an unbreakable token unless it is allowed
   to break. */
.rev-meta a { color: var(--faint); min-width: 0; overflow-wrap: anywhere; }
.rev-meta a:hover { color: var(--text); }

.rev-pitch { margin-top: .9rem; }
.rev-pitch summary {
  cursor: pointer; font-size: .8125rem; color: var(--faint);
  font-family: var(--mono); text-transform: uppercase; letter-spacing: .08em;
  list-style: none;
}
.rev-pitch summary::-webkit-details-marker { display: none; }
.rev-pitch summary::before { content: "▸ "; }
.rev-pitch[open] summary::before { content: "▾ "; }
.rev-pitch summary:hover { color: var(--text); }
.rev-pitch p {
  margin: .7rem 0 0; font-size: .9375rem; line-height: 1.65;
  color: var(--muted); white-space: pre-wrap;
}

/* Decisions sat flush against the meta line, which read as cramped. */
.rev-actions {
  display: flex; flex-wrap: wrap; gap: .55rem;
  margin-top: 1.25rem; padding-top: 1.1rem;
  border-top: 1px solid var(--border);
}
.rev-actions form { margin: 0; }

/* Status is the thing you scan for, so it carries colour. */
.status--pending  { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 35%, transparent); }
.status--approved { color: var(--ok);   border-color: color-mix(in srgb, var(--ok) 35%, transparent); }
.status--rejected { color: var(--bad);  border-color: color-mix(in srgb, var(--bad) 35%, transparent); }

.notice-inline { margin: 1.1rem 0 0; }

/* Announce a new tab to screen readers without showing it twice sighted. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------- sponsor page ---------- */

.sponsor-h2 { font-size: 1rem; margin: 2rem 0 .75rem; letter-spacing: -0.015em; }
/* Bordered rows rather than disc bullets: these are claims worth separating,
   and a plain list read as one grey block on a phone. */
.sponsor-list {
  list-style: none; margin: 0 0 2rem; padding: 0;
  display: flex; flex-direction: column; gap: .5rem;
}
.sponsor-list li {
  position: relative; margin: 0; line-height: 1.6;
  font-size: .875rem; color: var(--muted);
  padding: .85rem 1rem .85rem 2.1rem;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface);
}
.sponsor-list li::before {
  content: ""; position: absolute; left: .95rem; top: 1.25rem;
  width: 6px; height: 6px; border-radius: 50%; background: var(--accent);
}
.sponsor-list strong { color: var(--text); font-weight: 560; }
.sponsor-note {
  color: var(--muted); font-size: .9375rem; line-height: 1.65;
  border-left: 2px solid var(--accent); padding-left: 1rem;
  margin: 1.75rem 0 0; max-width: 38rem;
}
.sponsor-note strong { color: var(--text); font-weight: 560; }
.sponsor-list { margin-top: 1.75rem; }
code {
  font-family: var(--mono); font-size: .875em;
  background: var(--surface-2); padding: .1em .35em; border-radius: var(--radius-sm);
}

/* Handled enquiries recede rather than disappear. */
.rev--done { opacity: .55; }
.rev-message {
  margin: .9rem 0 0; font-size: .9375rem; line-height: 1.65;
  color: var(--muted); white-space: pre-wrap;
  /* Report reasons and enquiry messages are typed by other people and reliably
     contain a pasted URL, which is one unbreakable token. `anywhere` rather
     than `break-word` because it also shrinks the min-content width, which is
     what stops a flex or grid parent being forced wide by it. */
  overflow-wrap: anywhere;
}

/* ---------- sponsor: scarcity + fine print ---------- */

.slots {
  /*
   * Block, not inline-flex. As a flex row the leading <strong> and the sentence
   * after it became separate flex items, so the label wrapped into a narrow
   * column with the rest of the text running beside it. It is one sentence.
   */
  display: block;
  margin: 0 0 1.75rem; font-size: .9375rem; color: var(--muted);
  line-height: 1.55;
  padding: .8rem 1rem; border-radius: var(--radius);
  border: 1px solid var(--accent-line); background: var(--accent-soft);
}
.slots strong { color: var(--accent); font-weight: 600; }
.slots--full { border-color: var(--border-strong); background: var(--surface); }
.slots--full strong { color: var(--muted); }

.fineprint {
  font-size: .8125rem; line-height: 1.7; color: var(--faint);
  margin: 2rem 0 0; max-width: 38rem;
}
.opt { color: var(--faint); font-weight: 400; }

.upload-preview {
  display: block; max-width: 100%; margin-top: .75rem;
  border: 1px solid var(--border); border-radius: var(--radius);
}
input[type=file] {
  padding: .5rem; font-size: .875rem; cursor: pointer;
}
input[type=file]::file-selector-button {
  font: inherit; font-size: .8125rem; margin-right: .75rem; cursor: pointer;
  padding: .35rem .7rem; border-radius: var(--radius-sm);
  border: 1px solid var(--border-strong); background: var(--surface-2); color: var(--text);
}

/* ---------- auction board ---------- */

.board { list-style: none; margin: 0; padding: 0; counter-reset: none; }
.board-row {
  display: grid; align-items: center; gap: .75rem;
  grid-template-columns: 1.75rem 1fr auto auto;
  padding: .8rem .75rem; margin: 0 -.75rem;
  border-bottom: 1px solid var(--border); border-radius: var(--radius);
}
.board-row:last-child { border-bottom: 0; }
.board-row--in { background: var(--accent-soft); }
.board-rank {
  font-family: var(--mono); font-size: .8125rem; color: var(--faint);
  font-variant-numeric: tabular-nums;
}
.board-name { min-width: 0; display: flex; flex-direction: column; gap: .1rem; }
.board-name a { color: var(--text); font-weight: 520; font-size: .9375rem; }
.board-name a:hover { color: var(--accent); }
.board-maker { font-family: var(--mono); font-size: .75rem; color: var(--faint); }
.board-amount {
  font-size: 1rem; font-weight: 620; color: var(--text);
  font-variant-numeric: tabular-nums; letter-spacing: -0.02em;
}
.board-state {
  font-family: var(--mono); font-size: .625rem; text-transform: uppercase;
  letter-spacing: .09em; color: var(--faint); white-space: nowrap;
}
.board-row--in .board-state { color: var(--accent); }
.countdown { font-variant-numeric: tabular-nums; }



.upload-preview--square {
  width: 96px; height: 96px; object-fit: cover; border-radius: var(--radius-sm);
}

/* ---------- hero ---------- */

.hero-form {
  display: flex; gap: .5rem; margin: 1.75rem 0 .85rem;
  max-width: 32rem;
}
.hero-form input {
  flex: 1; min-width: 0; padding: .8rem 1rem; font-size: 1rem;
  border-radius: var(--radius); border: 1px solid var(--border-strong);
  background: var(--surface); color: var(--text);
}
.hero-form input:focus {
  border-color: var(--accent); background: var(--bg); outline: none;
}
.hero-form .btn { padding-inline: 1.35rem; white-space: nowrap; }

/* Honest liveness: a real fact about the wall, not an invented counter. */
.pulse {
  /* Fills its container like the field, the button and the points above it —
     as an inline pill it stopped short of the right edge and read as an
     unfinished element rather than a status bar. */
  display: flex; align-items: center; gap: .55rem;
  margin: 0 0 2.5rem; font-size: .8125rem; color: var(--faint);
  font-family: var(--mono); letter-spacing: .01em;
  padding: .45rem .8rem; border-radius: var(--radius);
  border: 1px solid var(--border); background: var(--surface);
}
.pulse-dot {
  flex: 0 0 auto; width: 6px; height: 6px; border-radius: 50%;
  background: var(--ok);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--ok) 18%, transparent);
}

/* ---------- wall cards, more finish ---------- */

.pitch { padding: 1.75rem 1.15rem; margin: 0 -1.15rem; }
.pitch-head { gap: 1rem; margin-bottom: .85rem; }
.pitch h2 { font-size: 1.125rem; }
.thumb { border-radius: 10px; }
.thumb-mono { font-size: 1.05em; }



/* ---------- home layout ---------- */

.home-split {
  display: grid; gap: 2rem;
  grid-template-columns: minmax(0, 1fr) 15rem;
  align-items: start;
}
.rail { display: flex; flex-direction: column; gap: 1.75rem; position: sticky; top: 5rem; }
.rail-block { }
.rail-block p { margin: 0 0 .6rem; font-size: .875rem; color: var(--muted); line-height: 1.6; }
.rail-list { list-style: none; margin: 0; padding: 0; }
.rail-list li { border-bottom: 1px solid var(--border); }
.rail-list li:last-child { border-bottom: 0; }
.rail-list a {
  display: flex; align-items: center; justify-content: space-between; gap: .6rem;
  padding: .5rem 0; font-size: .875rem; color: var(--muted);
}
.rail-list a:hover { color: var(--text); }
.rail-count { font-family: var(--mono); font-size: .75rem; color: var(--faint); }
.promo {
  padding: 1.1rem; border: 1px solid var(--accent-line);
  border-radius: var(--radius); background: var(--accent-soft);
  display: flex; flex-direction: column; align-items: flex-start; gap: .5rem;
}
.promo .section-label { margin: 0; }
.promo-slots { display: flex; gap: .3rem; }
.promo-slot {
  width: 22px; height: 26px; border-radius: 3px;
  border: 1px dashed var(--accent-line);
}
.promo-slot.is-taken { background: var(--accent); border-style: solid; border-color: var(--accent); }
.promo-state {
  font-size: 1.0625rem; font-weight: 600; color: var(--text);
  letter-spacing: -0.02em;
}
.promo-line { margin: 0; font-size: .8125rem; line-height: 1.5; color: var(--muted); }
.promo-cta { margin-top: .2rem; }

/*
 * At 72rem the hero was a 34rem block with a third of the page empty beside it.
 * It now spans the shell: headline and action on the left, the promise on the
 * right, with the type scaled to the wider page.
 */
.hero {
  display: grid; grid-template-columns: minmax(0, 1fr) 17rem;
  gap: 3.5rem; align-items: start;
  padding: 1rem 0 0; margin-bottom: 2.5rem;
}
.hero-main { min-width: 0; }
.hero h1 {
  font-size: clamp(2.2rem, 4.4vw, 3.35rem);
  line-height: 1.05; letter-spacing: -0.042em;
  max-width: 18ch; margin-bottom: .85rem;
  /* Even lines rather than a long first line and an orphan, which is how the
     previous headline came to read wrong on a phone. */
  text-wrap: balance;
}
.hero .lede { font-size: 1.125rem; max-width: 34rem; margin-bottom: 0; }
.hero-form { max-width: 34rem; }
.hero-form input { padding: .85rem 1.05rem; }
.pulse { max-width: none; }

.hero-points {
  list-style: none; margin: .4rem 0 0; padding: 0;
  display: flex; flex-direction: column; gap: .5rem;
}
.hero-points li {
  display: grid; grid-template-columns: auto 1fr; column-gap: .7rem;
  align-items: start;
  font-size: .8125rem; color: var(--faint); line-height: 1.5;
  padding: .8rem .9rem; border-radius: var(--radius);
  border: 1px solid var(--border); background: var(--surface);
}
.point-icon {
  grid-row: span 2; display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: var(--radius-sm);
  background: var(--accent-soft); color: var(--accent);
  border: 1px solid var(--accent-line);
}
.hero-points strong {
  color: var(--text); font-weight: 560; font-size: .9375rem;
  letter-spacing: -0.01em; align-self: center;
}
.hero-points li > strong + * { grid-column: 2; }

/* ---------- report page & admin alerts ---------- */

.backlink { margin: 0 0 1.25rem; font-size: .875rem; }
.backlink a { color: var(--faint); }
.backlink a:hover { color: var(--text); }

/* Confirms which pitch is about to be reported, so a mis-tap is visible before
   the report is filed rather than after. */
.report-target {
  display: flex; align-items: center; gap: .8rem;
  padding: .85rem .95rem; margin-bottom: 1.75rem; max-width: 34rem;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface);
}
.report-target > div { min-width: 0; }
.report-target strong { display: block; font-size: .9375rem; font-weight: 560; }
.report-target span {
  display: block; font-size: .8125rem; color: var(--faint); line-height: 1.5;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.report-line {
  margin: 2.5rem 0 0; padding-top: 1.25rem;
  border-top: 1px solid var(--border);
  font-size: .8125rem; color: var(--faint);
}

/* A radio list, not a select: every option is visible and one tap wide. */
.choices { border: 0; padding: 0; margin: 0 0 1.5rem; }
.choices legend {
  padding: 0; font-weight: 520; font-size: .875rem; margin-bottom: .55rem;
}
.choice {
  display: flex; align-items: center; gap: .7rem;
  padding: .7rem .85rem; min-height: 44px;
  border: 1px solid var(--border); border-radius: var(--radius);
  font-size: .875rem; color: var(--muted); cursor: pointer;
  transition: border-color .12s ease, color .12s ease, background-color .12s ease;
}
.choice + .choice { margin-top: .4rem; }
.choice:hover { border-color: var(--border-strong); color: var(--text); }
/* The global input rule sizes text boxes; a radio needs none of it. */
.choice input {
  width: auto; flex: 0 0 auto; margin: 0; padding: 0;
  accent-color: var(--accent);
}
/* Enhancement only. The checked state is carried by the radio itself via
   accent-color, which works everywhere; this just highlights the whole row on
   engines that support :has(). Nothing depends on it. */
.choice:has(input:checked) {
  border-color: var(--accent); color: var(--text); background: var(--surface);
}
.choice:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }

.optional { font-weight: 400; color: var(--faint); }

/* Reports and enquiries sit far down a long admin page; without this they were
   only found by scrolling to them. */
.alert {
  display: flex; align-items: center; gap: .55rem; flex-wrap: wrap;
  padding: .8rem 1rem; margin: 0 0 1.75rem;
  border: 1px solid var(--border-strong); border-radius: var(--radius);
  background: var(--surface); font-size: .875rem;
}
.alert a { color: var(--text); text-decoration: underline; text-underline-offset: 2px; }
.alert-dot {
  flex: 0 0 auto; width: 7px; height: 7px; border-radius: 50%;
  background: var(--accent);
}

/* Reports grouped under one pitch. */
.report-list { list-style: none; margin: .5rem 0 1rem; padding: 0; }
.report-list li { padding: .7rem 0; border-top: 1px solid var(--border); }
.report-list li:first-child { border-top: 0; }
.report-list .rev-message { margin: 0 0 .3rem; }
.report-list .rev-meta { margin: 0; }
.report-list .is-done { opacity: .55; }

/* A form that has to sit inside a line of running text. */
.inline-form { display: inline; }
.linkbtn {
  background: none; border: 0; padding: 0; margin: 0;
  font: inherit; color: var(--faint); cursor: pointer;
  text-decoration: underline; text-underline-offset: 2px;
}
.linkbtn:hover { color: var(--text); }

/* Auction rows in the admin queue. */
.slot-num {
  flex: 0 0 auto; min-width: 1.5rem;
  font-family: var(--mono); font-size: .8125rem; color: var(--faint);
  text-align: right;
}
.bid-amount {
  flex: 0 0 auto; font-family: var(--mono); font-size: .875rem; color: var(--text);
}

/* Signed-out state of a page that needs an account. */
.gate { max-width: 32rem; padding: 1rem 0 2rem; }
.gate .lede { margin-bottom: 1.5rem; }
.gate .hint { margin-top: .9rem; }

/* Dashboard: one thing to do, then quiet links. */
.first-run h2 {
  margin: 0 0 .6rem; font-size: 1.125rem; letter-spacing: -0.015em;
}
.first-run .hint { max-width: 26rem; margin-inline: auto; }
.dash-links {
  display: flex; flex-wrap: wrap; align-items: center; gap: .5rem;
  margin: 2.25rem 0 0; font-size: .875rem; color: var(--faint);
}
.dash-links a { color: var(--muted); }
.dash-links a:hover { color: var(--text); }
.dash-signout { margin: .9rem 0 0; font-size: .8125rem; }
.dash-signout a { color: var(--faint); }
.dash-signout a:hover { color: var(--text); }

/* Review queue. */

/* The rules behind a decision, available without restating them every visit. */
.rules { margin: -.4rem 0 1.5rem; }
.rules summary {
  cursor: pointer; font-size: .8125rem; color: var(--faint);
  font-family: var(--mono); text-transform: uppercase; letter-spacing: .08em;
  list-style: none;
}
.rules summary::-webkit-details-marker { display: none; }
.rules summary::before { content: "▸ "; }
.rules[open] summary::before { content: "▾ "; }
.rules summary:hover { color: var(--text); }
.rules p {
  margin: .7rem 0 0; font-size: .875rem; line-height: 1.6;
  color: var(--muted); max-width: 38rem;
}

/* The screening verdict is context for a decision, not an announcement, and
   every card in the queue carries one — a bordered callout each time was more
   furniture than information. */
.rev-screen {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .5rem;
  margin: .9rem 0 0; font-size: .8125rem; line-height: 1.55;
  color: var(--faint); overflow-wrap: anywhere;
}
/* No border and no box: it is a machine annotation, and as a bordered pill it
   read as a second status badge under the real one. */
.verdict {
  flex: 0 0 auto; font-family: var(--mono); font-size: .6875rem;
  text-transform: uppercase; letter-spacing: .08em; color: var(--muted);
}
.verdict--pass   { color: var(--ok); }
.verdict--review { color: var(--warn); }
.verdict--reject { color: var(--bad); }

/* Tighter than the default chip so four filters hold one row on a phone. */
.chips .chip { padding: .4rem .65rem; }

/* Compact number fields: a box for "3" does not need the whole column. */
.numgrid {
  display: grid; gap: 0 1rem; margin-top: .9rem;
  grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr));
}
.numgrid .field { margin-bottom: 1rem; }
.numgrid label { font-size: .8125rem; }
.numgrid input { padding: .5rem .6rem; }

/* The disclosure summary states the values it hides, so folding them away does
   not hide what the round will actually use. */
.defaults > summary {
  font-family: var(--sans); text-transform: none; letter-spacing: 0;
  font-size: .8125rem;
}
.defaults { margin-bottom: 1.5rem; }

/*
 * iOS lays a datetime-local out inside its own shadow tree and centres the
 * value there, so text-align alone does nothing — the appearance has to be
 * reset first. Constrained too: it was the only full-width field in a form
 * whose other inputs sit two to a row, and a centred date in a 339px box read
 * as a mistake rather than a control.
 */
input[type="datetime-local"] {
  -webkit-appearance: none;
  appearance: none;
  text-align: left;
  max-width: 15rem;
}

.waitlist-intro {
  margin: 0 0 1.5rem; font-size: .9375rem; line-height: 1.6;
  color: var(--muted); max-width: 34rem;
}

/*
 * Admin section nav.
 *
 * Wraps rather than scrolling sideways. Five tabs will not hold one row on a
 * phone, and a sideways scroller hides two of them behind an edge with nothing
 * to say they are there — which is the same complaint that split these pages
 * up in the first place. The underline is on the tab rather than a container
 * border, so any number of rows still lines up.
 */
.adminnav {
  display: flex; flex-wrap: wrap; gap: .15rem .25rem; margin: 0 0 1.75rem;
}
.adminnav-tab {
  display: inline-flex; align-items: center; gap: .35rem; flex: 0 0 auto;
  /* Tight enough that six tabs take two rows on a phone rather than three,
     while the row itself stays a 44px touch target. */
  padding: .5rem .45rem; min-height: 44px;
  font-size: .8125rem; color: var(--muted); white-space: nowrap;
  border-bottom: 2px solid var(--border);
  transition: color .12s ease, border-color .12s ease;
}
.adminnav-tab:hover { color: var(--text); }
.adminnav-tab[aria-current="page"] {
  color: var(--text); border-bottom-color: var(--accent);
}
/* Only things that want doing carry one, so it can afford to be loud. */
.adminnav-badge {
  font-family: var(--mono); font-size: .625rem; line-height: 1;
  padding: .18rem .3rem; border-radius: var(--radius-sm);
  background: var(--accent); color: var(--accent-fg);
}

/* A finished round is a sentence, not a card. */
.lastround {
  margin: 0; font-size: .875rem; line-height: 1.6; color: var(--muted);
  max-width: 38rem;
}

/* Share block on the dashboard. */
.share-label {
  margin: 1.25rem 0 .4rem; font-size: .8125rem; font-weight: 520; color: var(--text);
}
.copyrow {
  display: flex; align-items: center; gap: .5rem;
  border: 1px solid var(--border); border-radius: var(--radius);
  padding: .5rem .5rem .5rem .7rem; background: var(--bg);
}
/* The post and the badge snippet are longer than a line, so they get their own
   row and the button sits under them rather than squeezing them. */
.copyrow--block { flex-direction: column; align-items: stretch; gap: .6rem; }
.copyrow code {
  font-family: var(--mono); font-size: .75rem; line-height: 1.55;
  color: var(--muted); white-space: pre-wrap; overflow-wrap: anywhere;
  min-width: 0;
}
.copyrow--block .btn { align-self: flex-start; }
.copyrow > .btn { flex: 0 0 auto; }
.badge-preview {
  display: block; margin: .25rem 0 .6rem; width: 180px; height: 40px;
}

/* Prev / count / next, with the count centred whether or not both ends exist. */
.pager {
  display: flex; align-items: center; justify-content: space-between; gap: .75rem;
  margin: 2rem 0 0; padding-top: 1.25rem; border-top: 1px solid var(--border);
}
.pager-count { font-family: var(--mono); font-size: .8125rem; color: var(--faint); }

/* Long-form pages: privacy, terms, contact. Measured for reading rather than
   scanning, which is the opposite of everything else on this site. */
.prose-page { max-width: 38rem; }
/* Legal pages: prose left at a readable measure, contents beside it. */
.page-split--prose { grid-template-columns: minmax(0, 38rem) minmax(0, 1fr); }
.page-aside nav { display: grid; gap: .5rem; }
.page-aside nav a { font-size: .875rem; color: var(--muted); }
.page-aside nav a:hover { color: var(--text); }
.prose-page h2 {
  margin: 2.25rem 0 .6rem; font-size: 1.0625rem; letter-spacing: -0.015em;
}
.prose-page p, .prose-page li {
  font-size: .9375rem; line-height: 1.7; color: var(--muted);
}
.prose-page p { margin: 0 0 1rem; }
.prose-page ul { margin: 0 0 1rem; padding-left: 1.1rem; }
.prose-page li { margin-bottom: .5rem; }
.prose-page strong { color: var(--text); font-weight: 560; }

.owner-block {
  padding: .95rem 1.1rem; border: 1px solid var(--border);
  border-radius: var(--radius); background: var(--surface);
  line-height: 1.7; margin: 0 0 1rem;
}

.deflist { margin: 0 0 1rem; }
.deflist dt {
  font-weight: 560; color: var(--text); font-size: .9375rem;
  margin-top: 1.1rem;
}
.deflist dd {
  margin: .3rem 0 0; font-size: .9375rem; line-height: 1.7; color: var(--muted);
}

/* The paragraph that makes a category hub a page rather than a list. */
.cat-intro {
  max-width: 40rem; margin: 0 0 1.75rem;
  font-size: 1rem; line-height: 1.7; color: var(--muted);
}

/* The category index: a card each, with the first line of its own prose. */
.cat-cards {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: .6rem;
  grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
}
.cat-card {
  display: flex; flex-direction: column; gap: .35rem; height: 100%;
  padding: .95rem 1rem;
  border: 1px solid var(--border); border-radius: var(--radius);
  transition: border-color .12s ease, background-color .12s ease;
}
.cat-card:hover { border-color: var(--border-strong); background: var(--surface); }
.cat-card-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: .75rem;
}
.cat-card-head strong { color: var(--text); font-size: .9375rem; font-weight: 560; }
/* Clamped: this is a summary and the full paragraph is on the category's own
   page. Unclamped, first sentences of very different lengths made the grid
   ragged for no gain. */
.cat-card-line {
  font-size: .8125rem; line-height: 1.55; color: var(--faint);
  overflow-wrap: anywhere;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden;
}

/* The pitch page, two columns.
   The pitch itself is prose and wants a readable measure, so the extra width
   goes to everything around it rather than to the text. */
.product-split {
  display: grid; gap: 2.5rem 3.5rem;
  grid-template-columns: minmax(0, 1fr) 18rem;
  align-items: start;
}
.product-main { min-width: 0; max-width: 42rem; }
.product-aside { min-width: 0; position: sticky; top: 5.5rem; }
.product-aside .facts { margin-bottom: 1.25rem; padding-top: 0; border-top: 0; }
.product-aside .maker-card { margin-bottom: 1.25rem; }
.product-aside .report-line { margin-top: 0; }

/*
 * A form page on a wide screen.
 *
 * A form has to keep a readable measure — a text input a thousand pixels wide
 * is worse, not better — so widening these pages only helps if there is
 * something to put beside the form. The aside carries the context that was
 * otherwise crammed into hint text under every field.
 */
.page-split {
  display: grid; gap: 2.5rem 4rem;
  grid-template-columns: minmax(0, 34rem) minmax(0, 1fr);
  align-items: start;
}
.page-main { min-width: 0; }
.page-aside { position: sticky; top: 5.5rem; max-width: 22rem; }
.page-aside h2 {
  margin: 0 0 .6rem; font-size: .875rem; font-weight: 560;
  font-family: var(--mono); text-transform: uppercase; letter-spacing: .08em;
  color: var(--faint);
}
.page-aside ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .8rem; }
.page-aside li {
  font-size: .875rem; line-height: 1.6; color: var(--muted);
  padding-left: .9rem; border-left: 2px solid var(--border);
}
.page-aside li strong { display: block; color: var(--text); font-weight: 560; }

/* Related pitches, so a pitch page is not a dead end for a reader or a crawler. */
.related { margin-top: 3rem; padding-top: 1.75rem; border-top: 1px solid var(--border); }
.related .section-label { margin-bottom: 1rem; }
.related .section-label a { color: var(--muted); }
.related .section-label a:hover { color: var(--text); }
/* Narrower cards here: this sits under a page whose main column is 42rem. */
.related .wall--rows { grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); }

/*
 * The hero.
 *
 * With a screenshot this page carries itself; without one it was a 64px square,
 * a heading and a paragraph, which is not a page anybody remembers. The type
 * scale does the work when there is no picture: the name is the largest thing
 * on the site, the tagline is a statement rather than a caption, and the one
 * action is unmissable.
 */
.product-header { align-items: center; gap: 1.25rem; margin-bottom: 1.25rem; }
.product-header h1 {
  font-size: clamp(2.1rem, 1.4rem + 2.2vw, 3rem);
  line-height: 1.05; letter-spacing: -0.035em; margin-bottom: .35rem;
}
.product-tagline {
  font-size: clamp(1.0625rem, .95rem + .4vw, 1.3rem);
  line-height: 1.4; color: var(--muted); text-wrap: balance;
}
.visit-row { align-items: center; gap: .9rem; margin-bottom: 1.75rem; }
.visit-row .btn { font-size: 1rem; padding: .7rem 1.25rem; }

.shot {
  display: block; width: 100%; height: auto; margin: 0 0 1.75rem;
  border: 1px solid var(--border); border-radius: var(--radius);
}
/* The pitch is the thing a reader came for, so it is set to be read. */
.product-main .prose {
  font-size: 1.0625rem; line-height: 1.75;
}

/* Live suggestions under the header search. Progressive enhancement: the form
   still submits to /search with the script blocked, this only adds a list. */
.hsearch { position: relative; }
.sugg {
  position: absolute; top: calc(100% + .4rem); left: 0; right: 0; z-index: 60;
  max-height: 24rem; overflow-y: auto;
  padding: .35rem;
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--radius); box-shadow: 0 12px 32px rgb(0 0 0 / .45);
}
.sugg-label {
  margin: .35rem .5rem .25rem; font-family: var(--mono); font-size: .625rem;
  text-transform: uppercase; letter-spacing: .1em; color: var(--faint);
}
.sugg-item {
  display: flex; align-items: center; gap: .6rem;
  padding: .45rem .5rem; border-radius: var(--radius-sm);
  color: var(--text);
}
.sugg-item:hover, .sugg-item.is-active { background: var(--surface-2); }
.sugg-item img, .sugg-mono {
  flex: 0 0 auto; width: 28px; height: 28px; border-radius: var(--radius-sm);
  object-fit: cover; border: 1px solid var(--border);
}
.sugg-mono {
  display: inline-flex; align-items: center; justify-content: center;
  font-size: .8125rem; color: var(--muted); background: var(--surface-2);
}
.sugg-text { min-width: 0; display: flex; flex-direction: column; }
.sugg-text strong {
  font-size: .875rem; font-weight: 520;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sugg-text span {
  font-size: .75rem; color: var(--faint);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sugg-empty { margin: .5rem; font-size: .8125rem; color: var(--faint); line-height: 1.5; }

.maker-date {
  margin: .25rem 0 0; font-size: .8125rem; color: var(--faint);
  font-family: var(--mono); white-space: nowrap;
}

/* The address field and the button that reads it. */
.url-row { display: flex; gap: .5rem; align-items: stretch; }
.url-row input { flex: 1 1 auto; min-width: 0; }
.url-row .btn { flex: 0 0 auto; }

/* An explicit dark choice, which has to beat the light media query. */
:root[data-theme="dark"] { color-scheme: dark; }

/* The theme control. Hidden until its script runs, so it is never a dead
   button, and it swaps which icon is showing rather than swapping the markup. */
.theme-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; flex: 0 0 auto; padding: 0; margin: 0;
  border: 1px solid var(--border); border-radius: var(--radius);
  color: var(--muted); background: transparent; cursor: pointer;
  font: inherit; appearance: none; -webkit-appearance: none;
  transition: color .12s ease, border-color .12s ease, background-color .12s ease;
}
.theme-toggle:hover { color: var(--text); border-color: var(--border-strong); background: var(--surface); }
.theme-toggle svg { display: block; }
/* Show the destination, not the current state: in dark you press it for light. */
.theme-toggle .icon-sun { display: block; }
.theme-toggle .icon-moon { display: none; }
:root[data-theme="light"] .theme-toggle .icon-sun { display: none; }
:root[data-theme="light"] .theme-toggle .icon-moon { display: block; }
@media (prefers-color-scheme: light) {
  :root:not([data-theme]) .theme-toggle .icon-sun { display: none; }
  :root:not([data-theme]) .theme-toggle .icon-moon { display: block; }
}
.theme-toggle-text { display: none; }
/* In the drawer it sits in a row of links, so it reads as one. */
.navmenu-panel .theme-toggle {
  width: auto; height: auto; padding: .8rem .75rem; border: 0;
  gap: .6rem; justify-content: flex-start; color: var(--muted);
}
.navmenu-panel .theme-toggle:hover { background: transparent; color: var(--text); }
.navmenu-panel .theme-toggle .theme-toggle-text { display: inline; }

/* ---------- responsive: widest first, narrowest last ---------- */

















/* Hero collapses before the wall does: the promise column needs real room. */

/* ---------- responsive: widest first, narrowest last ---------- */



















/* ---------- pinned slots ---------- */

.slot-grid {
  display: grid; gap: .7rem; margin-bottom: 1.5rem;
  /* auto-fit so one or two remaining slots still fill the width */
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
}
.slot {
  position: relative; display: flex; flex-direction: column; align-items: flex-start;
  gap: .45rem; min-height: 11.5rem; padding: 1.35rem;
  border-radius: var(--radius);
  transition: border-color .18s ease, background-color .18s ease, transform .18s ease;
}
.slot-tag {
  position: absolute; top: .9rem; right: .9rem;
  font-family: var(--mono); font-size: .5625rem; text-transform: uppercase;
  letter-spacing: .12em; padding: .12rem .4rem; border-radius: var(--radius-sm);
  color: var(--accent); border: 1px solid var(--accent-line);
}
.slot-tag--open { color: var(--faint); border-color: var(--border-strong); }
.slot-name {
  font-size: 1.0625rem; font-weight: 580; color: var(--text);
  letter-spacing: -0.02em; margin-top: .35rem;
}
.slot-tagline {
  font-size: .875rem; color: var(--muted); line-height: 1.45;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.slot-maker {
  margin-top: auto; font-family: var(--mono); font-size: .6875rem;
  text-transform: uppercase; letter-spacing: .09em; color: var(--faint);
}

.slot--filled { border: 1px solid var(--accent-line); background: var(--accent-soft); }
.slot--filled:hover { border-color: var(--accent); }
.slot--filled:hover .slot-name { color: var(--accent); }

.slot--open { border: 1px dashed var(--border-strong); background: transparent; }
.slot--open .slot-name { color: var(--muted); }
.slot-mark {
  width: 48px; height: 48px; border-radius: var(--radius-sm);
  border: 1px dashed var(--border-strong); transition: border-color .18s ease;
}
.slot--open:hover { border-color: var(--accent-line); background: var(--accent-soft); }
.slot--open:hover .slot-mark { border-color: var(--accent-line); }
.slot--open:hover .slot-name { color: var(--text); }
.slot--open:hover .slot-maker { color: var(--accent); }

/* ---------- row hover ---------- */

/*
 * Echoes the mark: a bar lights up, and the lit card lifts and glows.
 *
 * Only transforms, opacity and colour move. The bar is an absolutely positioned
 * pseudo-element and the lift is a transform, so nothing here can reflow the
 * row — hovering a list that shifts under the cursor is the bug this whole
 * layout has been fighting.
 */
.wall--rows .pitch { position: relative; overflow: hidden; }
.wall--rows .pitch::before {
  content: "";
  position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
  background: currentColor; color: var(--accent);
  transform: scaleY(0); transform-origin: top;
  transition: transform .28s cubic-bezier(.2, .7, .3, 1);
}
.wall--rows .pitch:hover::before,
.wall--rows .pitch:focus-within::before { transform: scaleY(1); }

.wall--rows .thumb {
  transition: transform .22s cubic-bezier(.2, .7, .3, 1), filter .22s ease,
              border-color .22s ease;
}
.wall--rows .pitch:hover .thumb,
.wall--rows .pitch:focus-within .thumb {
  transform: translateY(-2px);
  border-color: var(--accent-line);
  filter: drop-shadow(0 0 6px color-mix(in srgb, var(--accent) 30%, transparent));
}

/* The meta column fades up as the row lights, so attention lands on the pitch. */
.wall--rows .pitch-meta { transition: color .22s ease; }
.wall--rows .pitch:hover .pitch-meta { color: var(--muted); }

/* ---------- responsive: widest first, narrowest last ---------- */

/* ---------- responsive: widest first, narrowest last ---------- */



















/* ---------- mobile nav drawer ---------- */

.navmenu { display: none; margin-left: auto; }
.navmenu-trigger {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; cursor: pointer; list-style: none;
  border-radius: var(--radius); border: 1px solid var(--border);
  color: var(--text); position: relative; z-index: 60;
  transition: background-color .12s ease, border-color .12s ease;
}
.navmenu-trigger::-webkit-details-marker { display: none; }
.navmenu-trigger::marker { content: ""; }
.navmenu[open] .navmenu-trigger { background: var(--surface); border-color: var(--border-strong); }

/* Bars fold into a cross. */
.burger rect {
  transform-box: fill-box; transform-origin: center;
  transition: transform .3s cubic-bezier(.32, .72, 0, 1), opacity .18s ease;
}
.navmenu[open] .b1 { transform: translateY(4px) rotate(45deg); }
.navmenu[open] .b2 { opacity: 0; }
.navmenu[open] .b3 { transform: translateY(-4px) rotate(-45deg); }

/*
 * The drawer animates with a keyframe rather than a transition: <details>
 * reveals its content instantly, so there is no state to transition from, but
 * an animation runs the moment the element is displayed. That keeps the whole
 * thing working without JavaScript.
 */
.navmenu[open]::before {
  content: ""; position: fixed; inset: 0; z-index: 40;
  background: rgba(0, 0, 0, .55);
  animation: drawer-fade .26s ease both;
}
.navmenu-panel {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 50;
  width: min(19rem, 84vw); padding: 5.25rem 1.1rem 1.5rem;
  display: flex; flex-direction: column; gap: .1rem;
  background: var(--bg); border-left: 1px solid var(--border);
  overflow-y: auto;
  animation: drawer-in .34s cubic-bezier(.32, .72, 0, 1) both;
}
@keyframes drawer-fade { from { opacity: 0 } to { opacity: 1 } }
@keyframes drawer-in { from { transform: translateX(100%) } to { transform: translateX(0) } }

/* Items arrive in sequence, the way the light travels across the mark. */
.navmenu-panel > * { animation: drawer-item .34s cubic-bezier(.32, .72, 0, 1) both; }
.navmenu-panel > *:nth-child(1) { animation-delay: .05s }
.navmenu-panel > *:nth-child(2) { animation-delay: .09s }
.navmenu-panel > *:nth-child(3) { animation-delay: .13s }
.navmenu-panel > *:nth-child(4) { animation-delay: .17s }
.navmenu-panel > *:nth-child(5) { animation-delay: .21s }
.navmenu-panel > *:nth-child(6) { animation-delay: .25s }
.navmenu-panel > *:nth-child(7) { animation-delay: .29s }
.navmenu-panel > *:nth-child(8) { animation-delay: .33s }
.navmenu-panel > *:nth-child(9) { animation-delay: .37s }
.navmenu-panel > *:nth-child(10) { animation-delay: .41s }
@keyframes drawer-item {
  from { opacity: 0; transform: translateX(14px) }
  to { opacity: 1; transform: translateX(0) }
}

.navmenu-panel a {
  display: block; padding: .8rem .75rem; border-radius: var(--radius);
  color: var(--muted); font-size: 1rem;
}
.navmenu-panel a:active { background: var(--surface-2); }
.navmenu-panel a.navmenu-cta {
  display: flex; justify-content: center; width: 100%;
  margin: .5rem 0; min-height: 46px; font-size: .95rem;
  /* .btn loses to the panel's link colour on specificity, so reclaim it. */
  color: var(--accent-fg); background: var(--accent);
}
.navmenu-panel a.navmenu-cta:active { background: var(--accent-hover); }
.navmenu-panel .umenu-sep { margin: .55rem .75rem; }
.navmenu-panel .umenu-head { padding: 0 .75rem .8rem; margin-bottom: .35rem; }

/* ---------- responsive: widest first, narrowest last ---------- */

















/* Hero collapses before the wall does: the promise column needs real room. */

/* ---------- responsive: widest first, narrowest last ---------- */



















/* ---------- pinned slots ---------- */

.slot-grid {
  display: grid; gap: .7rem; margin-bottom: 1.5rem;
  /* auto-fit so one or two remaining slots still fill the width */
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
}
.slot {
  position: relative; display: flex; flex-direction: column; align-items: flex-start;
  gap: .45rem; min-height: 11.5rem; padding: 1.35rem;
  border-radius: var(--radius);
  transition: border-color .18s ease, background-color .18s ease, transform .18s ease;
}
.slot-tag {
  position: absolute; top: .9rem; right: .9rem;
  font-family: var(--mono); font-size: .5625rem; text-transform: uppercase;
  letter-spacing: .12em; padding: .12rem .4rem; border-radius: var(--radius-sm);
  color: var(--accent); border: 1px solid var(--accent-line);
}
.slot-tag--open { color: var(--faint); border-color: var(--border-strong); }
.slot-name {
  font-size: 1.0625rem; font-weight: 580; color: var(--text);
  letter-spacing: -0.02em; margin-top: .35rem;
}
.slot-tagline {
  font-size: .875rem; color: var(--muted); line-height: 1.45;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.slot-maker {
  margin-top: auto; font-family: var(--mono); font-size: .6875rem;
  text-transform: uppercase; letter-spacing: .09em; color: var(--faint);
}

.slot--filled { border: 1px solid var(--accent-line); background: var(--accent-soft); }
.slot--filled:hover { border-color: var(--accent); }
.slot--filled:hover .slot-name { color: var(--accent); }

.slot--open { border: 1px dashed var(--border-strong); background: transparent; }
.slot--open .slot-name { color: var(--muted); }
.slot-mark {
  width: 48px; height: 48px; border-radius: var(--radius-sm);
  border: 1px dashed var(--border-strong); transition: border-color .18s ease;
}
.slot--open:hover { border-color: var(--accent-line); background: var(--accent-soft); }
.slot--open:hover .slot-mark { border-color: var(--accent-line); }
.slot--open:hover .slot-name { color: var(--text); }
.slot--open:hover .slot-maker { color: var(--accent); }

/* ---------- row hover ---------- */

/*
 * Echoes the mark: a bar lights up, and the lit card lifts and glows.
 *
 * Only transforms, opacity and colour move. The bar is an absolutely positioned
 * pseudo-element and the lift is a transform, so nothing here can reflow the
 * row — hovering a list that shifts under the cursor is the bug this whole
 * layout has been fighting.
 */
.wall--rows .pitch { position: relative; overflow: hidden; }
.wall--rows .pitch::before {
  content: "";
  position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
  background: currentColor; color: var(--accent);
  transform: scaleY(0); transform-origin: top;
  transition: transform .28s cubic-bezier(.2, .7, .3, 1);
}
.wall--rows .pitch:hover::before,
.wall--rows .pitch:focus-within::before { transform: scaleY(1); }

.wall--rows .thumb {
  transition: transform .22s cubic-bezier(.2, .7, .3, 1), filter .22s ease,
              border-color .22s ease;
}
.wall--rows .pitch:hover .thumb,
.wall--rows .pitch:focus-within .thumb {
  transform: translateY(-2px);
  border-color: var(--accent-line);
  filter: drop-shadow(0 0 6px color-mix(in srgb, var(--accent) 30%, transparent));
}

/* The meta column fades up as the row lights, so attention lands on the pitch. */
.wall--rows .pitch-meta { transition: color .22s ease; }
.wall--rows .pitch:hover .pitch-meta { color: var(--muted); }

/* ---------- responsive: widest first, narrowest last ---------- */

/* ---------- responsive: widest first, narrowest last ---------- */



















/* ---------- mobile nav menu ---------- */

.navmenu { display: none; position: relative; margin-left: auto; }
.navmenu-trigger {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; cursor: pointer; list-style: none;
  border-radius: var(--radius); border: 1px solid var(--border);
  color: var(--text); transition: background-color .12s ease, border-color .12s ease;
}
.navmenu-trigger::-webkit-details-marker { display: none; }
.navmenu-trigger::marker { content: ""; }
.navmenu[open] .navmenu-trigger { background: var(--surface); border-color: var(--border-strong); }
.navmenu-panel { left: auto; right: 0; min-width: 15rem; }
/* .umenu-panel a sets a muted colour at higher specificity than .btn, so the
   call to action has to reclaim its own. */
.navmenu-panel a.navmenu-cta {
  display: flex; justify-content: center; width: 100%;
  margin: .15rem 0; min-height: 42px;
  color: var(--accent-fg); background: var(--accent);
}
.navmenu-panel a.navmenu-cta:hover { color: var(--accent-fg); background: var(--accent-hover); }
.navmenu-panel a:not(.navmenu-cta) { padding: .6rem .6rem; }

/* ---------- responsive: widest first, narrowest last ---------- */



















/* ---------- submit: signed out ---------- */

.kept {
  display: flex; align-items: flex-start; gap: .75rem;
  padding: .9rem 1rem; margin: 0 0 1.75rem;
  border: 1px solid var(--accent-line); border-radius: var(--radius);
  background: var(--accent-soft); max-width: 34rem;
}
.kept-icon {
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: var(--radius-sm);
  background: var(--bg); color: var(--accent); border: 1px solid var(--accent-line);
}
.kept-body { min-width: 0; font-size: .8125rem; color: var(--muted); line-height: 1.5; }
.kept-body strong {
  display: block; color: var(--text); font-weight: 560; font-size: .9375rem;
  word-break: break-all; margin-bottom: .1rem;
}

.steps { list-style: none; margin: 0 0 2rem; padding: 0; max-width: 34rem; }
.steps li {
  display: grid; grid-template-columns: auto 1fr; column-gap: .85rem;
  align-items: start; padding: 1rem 0;
  border-bottom: 1px solid var(--border);
  font-size: .875rem; color: var(--muted); line-height: 1.6;
}
.steps li:last-child { border-bottom: 0; }
.step-num {
  grid-row: span 2; display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: 50%;
  font-family: var(--mono); font-size: .75rem; font-variant-numeric: tabular-nums;
  color: var(--accent); background: var(--accent-soft);
  border: 1px solid var(--accent-line);
}
.steps strong {
  color: var(--text); font-weight: 560; font-size: .9375rem;
  letter-spacing: -0.01em; align-self: center;
}
.steps li > strong + * { grid-column: 2; }
.submit-cta { margin: 0; }

/* Footer stacks before the wall does — three link columns plus the brand need
   more room than a row of pitches. */

/* ---------- responsive: widest first, narrowest last ---------- */





















/* ---------- category filter ---------- */

.cat-filter { margin-bottom: 2.25rem; }
.cat-filter > summary {
  display: none; cursor: pointer; list-style: none;
  align-items: center; gap: .5rem;
  padding: .7rem .9rem; border-radius: var(--radius);
  border: 1px solid var(--border); background: var(--surface);
  font-size: .875rem; color: var(--text); min-height: 44px;
}
.cat-filter > summary::-webkit-details-marker { display: none; }
.cat-filter > summary::marker { content: ""; }
.cat-filter-label {
  font-family: var(--mono); font-size: .625rem; text-transform: uppercase;
  letter-spacing: .11em; color: var(--faint);
}
.cat-filter-value { flex: 1; font-weight: 550; }
.cat-filter-caret { color: var(--faint); transition: transform .18s ease; }
.cat-filter[open] > summary { border-color: var(--border-strong); }
.cat-filter[open] .cat-filter-caret { transform: rotate(180deg); }
.cat-filter > .chips { margin-bottom: 0; }
.cat-filter[open] > .chips { margin-top: .6rem; }

/* ---------- responsive: widest first, narrowest last ---------- */

/* ---------- responsive: widest first, narrowest last ---------- */

/* ---------- responsive: widest first, narrowest last ---------- */





















.rail-list a:has(.rail-sub) { display: block; padding: .55rem 0; }
.rail-name { display: block; color: var(--muted); font-size: .875rem; }
.rail-list a:hover .rail-name { color: var(--text); }
.rail-sub {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; font-size: .75rem; color: var(--faint); line-height: 1.4;
  margin-top: .1rem;
}

/* ---------- responsive: widest first, narrowest last ---------- */





















/* Product page reads denser on a phone: fewer, fuller lines. */

/* ---------- responsive: widest first, narrowest last ---------- */























/* ---------- maker page ---------- */

/*
 * A maker page is a profile: who, then what they made.
 *
 * It used to be a small identity block stacked above the pitches and left
 * hanging in the corner of a full-width page — the same information as every
 * other page but with none of the room used. Identity gets its own column and
 * stays put while the work scrolls.
 */
.maker-split {
  display: grid; gap: 2.5rem 3.5rem;
  grid-template-columns: 17rem minmax(0, 1fr);
  align-items: start;
}
.maker-profile { position: sticky; top: 5.5rem; min-width: 0; }
.maker-profile h1 {
  margin: 1rem 0 0; font-size: 1.6rem; line-height: 1.15; letter-spacing: -0.02em;
}
.maker-work { min-width: 0; }
.maker-work .wall--rows { grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr)); }
.maker-id { min-width: 0; }
.maker-id h1 { margin: 0; font-size: 1.75rem; }
.maker-handle {
  margin: .15rem 0 0; font-family: var(--mono); font-size: .8125rem; color: var(--faint);
}
.maker-avatar {
  flex: 0 0 auto; border-radius: 50%;
  width: var(--avatar, 64px); height: var(--avatar, 64px);
  object-fit: cover; border: 1px solid var(--border);
}
.maker-avatar--mono { font-size: calc(var(--avatar, 64px) * 0.4); }
.maker-avatar--mono {
  display: inline-flex; align-items: center; justify-content: center;
  font-weight: 600; letter-spacing: -0.02em;
  color: hsl(var(--mono-h) 45% 72%); background: hsl(var(--mono-h) 22% 15%);
  border-color: hsl(var(--mono-h) 22% 22%);
}
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .maker-avatar--mono {
    color: hsl(var(--mono-h) 42% 38%);
    background: hsl(var(--mono-h) 40% 95%);
    border-color: hsl(var(--mono-h) 30% 88%);
  }
}
/* The same palette again, for a visitor who chose light explicitly. */
  :root[data-theme="light"] .maker-avatar--mono {
    color: hsl(var(--mono-h) 42% 38%);
    background: hsl(var(--mono-h) 40% 95%);
    border-color: hsl(var(--mono-h) 30% 88%);
  }
.maker-bio {
  margin: .9rem 0 0; font-size: .9375rem; line-height: 1.65;
  color: var(--muted); max-width: none;
}
.maker-bio--empty { color: var(--faint); }
.maker-links { margin: 1rem 0 0; padding-top: 0; border-top: 0; }
.maker-edit { margin: 1rem 0 0; }
.social-fields { display: grid; gap: 0 1rem; grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); }

/* Three abreast at any width: the scarcity is the message. */
.slot-grid--compact { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .5rem; }
.slot-grid--compact .slot {
  min-height: 0; padding: .9rem .75rem; align-items: center; text-align: center;
  gap: .6rem;
}
.slot-grid--compact .slot-mark { width: 34px; height: 34px; }
.slot-grid--compact .slot-name {
  margin: 0; font-family: var(--mono); font-size: .625rem;
  text-transform: uppercase; letter-spacing: .1em;
}

/* ---------- responsive: widest first, narrowest last ---------- */

@media (max-width: 1000px) {
  .hero { grid-template-columns: 1fr; gap: 2rem; }
  .hero-points { flex-direction: row; flex-wrap: wrap; gap: 1.25rem; }
  .hero-points li { flex: 1 1 12rem; }
}

@media (max-width: 900px) {
  .maker-split { grid-template-columns: 1fr; gap: 1.75rem; }
  .maker-profile { position: static; }
  .page-split { grid-template-columns: 1fr; gap: 2rem; }
  .page-main { max-width: none; }
  .page-aside { position: static; max-width: none; }
  .product-split { grid-template-columns: 1fr; gap: 1.5rem; }
  .product-main { max-width: none; }
  .product-aside { position: static; }
  .product-aside .facts { padding-top: 1.1rem; border-top: 1px solid var(--border); }

  /* One column, and back to a row: a card grid of one card per row is just a
     list of boxes with wasted padding. */
  .wall--rows { display: flex; flex-direction: column; gap: 0; }
  .wall--rows .pitch {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: .5rem 1rem;
    align-items: start;
    border: 0; border-bottom: 1px solid var(--border);
    border-radius: var(--radius);
  }
  .wall--rows .pitch:last-child { border-bottom: 0; }
  .wall--rows .pitch-head { display: contents; }
  .wall--rows .pitch .thumb { width: 56px; height: 56px; grid-column: 1; grid-row: 1 / span 3; }
  .wall--rows .pitch .thumb-mono { font-size: 23px; }
  .wall--rows .pitch-title { grid-column: 2; }
  .wall--rows .pitch-excerpt { grid-column: 2; -webkit-line-clamp: 3; }
  .wall--rows .pitch-meta { grid-column: 2; margin: 0; }
}

@media (max-width: 900px) {
  .home-split { grid-template-columns: 1fr; gap: 2rem; }
  .rail { position: static; flex-direction: row; flex-wrap: wrap; gap: 2rem; align-items: start; }
  .rail-block { flex: 1 1 14rem; align-self: start; }
}

@media (max-width: 780px) {
  .footer-top { grid-template-columns: 1fr; gap: 1.35rem; padding-bottom: 1.25rem; }
  /* Three groups across, so they stay one row instead of wrapping to two. */
  .footer-cols { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1rem; }
  .footer-cols a { white-space: normal; }
  .site-footer { padding: 1.75rem 0 1.25rem; }
  .footer-legal { flex-direction: column; align-items: flex-start; gap: .3rem; padding-top: .9rem; }
}

@media (max-width: 720px) {
  .hsearch { max-width: none; }
}

@media (max-width: 560px) {
  h1 { font-size: 1.7rem; }
  .hero h1 { font-size: 1.9rem; letter-spacing: -0.03em; }
  .hero { margin-bottom: 2rem; }
  .lede { font-size: 1rem; }
  main.shell { padding-top: 2rem; padding-bottom: 3.5rem; }
  .shell { padding: 0 1.125rem; }
  .rule { margin: 2.25rem 0; }

  .site-header .header-inner { gap: .55rem; }
  .site-nav { gap: .5rem; }

  /* One line collapsed; the full set wraps into view when opened. Nothing ever
     sits off-screen where it will not be found. */
  .cat-filter > summary { display: flex; }
  .cat-filter:not([open]) > .chips { display: none; }
  /* Browse lives in the account menu and the footer on small screens. */
  .site-nav .nav-link[href="/browse"] { display: none; }

  /*
   * Two elements. Four controls in three different styles could not share 339px
   * without all of them looking cramped, and every page added later would have
   * had to fight for the same space. The menu holds everything instead.
   */
  .hsearch { display: none; }
  .hsearch-compact { display: none; }
  .site-nav { display: none; }
  .navmenu { display: block; }

  /*
   * iOS zooms the whole page when a focused field is under 16px, which throws
   * the layout sideways mid-interaction. Every input therefore goes to 16px at
   * this width — the one place where font-size is a behaviour, not a style.
   */
  input, select, textarea, .hsearch input { font-size: 16px; }

  /* Comfortable touch targets. */
  .btn { padding: .65rem 1rem; min-height: 44px; }
  .btn-sm { padding: .45rem .75rem; min-height: 40px; }
  .chip { min-height: 40px; }
  .umenu-panel a { padding: .6rem .6rem; }
  .footer-nav { gap: 1rem; row-gap: .6rem; }

  .pitch { padding: 1.35rem .75rem; margin: 0 -.75rem; }
  .pitch-head { gap: .75rem; }
  .cat-grid { grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr)); }
  .meta-grid { grid-template-columns: 1fr; gap: .25rem .75rem; }
  .meta-grid dt { margin-top: .6rem; }
}

@media (max-width: 560px) {
  .board-row { grid-template-columns: 1.5rem 1fr auto; row-gap: .3rem; }
  .board-state { grid-column: 2 / -1; }
}

@media (max-width: 560px) {
  .hero-form { flex-direction: column; margin-top: 1.5rem; }
  .hero-form .btn { width: 100%; }
  /*
   * Cards, not a hairline-separated column of prose.
   *
   * Each row carried a name, a two-line tagline, a three-line excerpt and an
   * attribution — five lines of grey text apiece, so scrolling the wall meant
   * reading it. The tagline already says what a thing does, and the pitch
   * itself is one tap away, so the excerpt comes off here and each pitch gets
   * a border and a surface instead.
   */
  .wall--rows { gap: .6rem; }
  .wall--rows .pitch {
    margin: 0; padding: 1rem;
    border: 1px solid var(--border); border-radius: var(--radius);
    background: var(--surface);
    grid-template-columns: auto minmax(0, 1fr);
    gap: .3rem .85rem;
  }
  .wall--rows .pitch:last-child { border-bottom: 1px solid var(--border); }
  .wall--rows .pitch-excerpt { display: none; }
  .wall--rows .thumb { width: 44px; height: 44px; }
  .wall--rows .pitch h2 { font-size: 1.0625rem; }
  .wall--rows .tagline { -webkit-line-clamp: 3; }
  .wall--rows .pitch-meta { padding-top: .15rem; }
}

@media (max-width: 560px) {
  .wall--grid { grid-template-columns: 1fr; }
  /* Back to a column here, and in a column flex container `align-self` governs
     WIDTH, not height. The `align-self: start` that stops the blocks stretching
     to equal heights in the 900px row layout therefore shrink-wraps each block
     to its longest line on a phone, leaving two thirds of the screen empty
     beside the category list. Both axes have to be reset, not just direction. */
  .rail { flex-direction: column; gap: 1.75rem; align-items: stretch; }
  .rail-block { flex: 0 0 auto; align-self: stretch; }
}

@media (max-width: 560px) {
  .product-header { gap: .85rem; margin-bottom: 1.15rem; }
  .product-header h1 { font-size: 1.6rem; }
  .product-tagline { font-size: 1rem; }
  .visit-row { margin-bottom: 1.5rem; gap: .6rem; }
  .prose { font-size: 1rem; line-height: 1.62; margin-bottom: 1.5rem; padding-left: .9rem; }
  .facts { margin-bottom: 1.5rem; padding-top: .9rem; }
  .maker-card { padding: .95rem; }
}

@media (max-width: 350px) {
  .navmenu-panel { min-width: 13.5rem; }
}

.avatar-field { display: flex; align-items: flex-start; gap: 1rem; }
.avatar-field > div { flex: 1; min-width: 0; }
.avatar-current {
  flex: 0 0 auto; width: 64px; height: 64px; border-radius: 50%;
  object-fit: cover; border: 1px solid var(--border); background: var(--surface-2);
}
.avatar-current--empty { border-style: dashed; border-color: var(--border-strong); }
