/*
 * Pitchrow — a noticeboard where pinning up your own note is the point.
 * Pitches are paper notes on a dotted ground: a pastel per product, a strip of
 * tape, a slight lean. A place makers want to be seen should look glad they came.
 *
 * Rules this file holds to:
 *   - No gradients anywhere. Flat colour, thin outlines, paper shadows.
 *   - 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 carries a heavy weight well.
 *   - Nothing may change layout on hover or focus. Colour, and a transform
 *     that moves a thing into or out of its own shadow — never its size or
 *     its place in the flow.
 */

:root {
  color-scheme: light;

  /* Light is the brand: a warm cream ground. Dark is there for anyone who
     asks for it with the toggle. It used to follow the system, which meant
     most visitors on a Mac never saw the site as it is meant to look. */
  --bg:            #FFF3E2;
  --surface:       #FFFFFF;
  --surface-2:     #FFF8EE;
  --text:          #15120F;
  --muted:         #4D4640;
  --faint:         #766C61;
  /* Hairlines between rows. Outlines are --ink. */
  --border:        #EBD9C2;
  --border-strong: #15120F;
  --ink:           #15120F;
  /* Three jobs --ink does in light, split so dark can do each differently:
     the outline of a note or panel, the outline of a control, and the key
     a button sits on. In light all three are ink. */
  --edge:          #15120F;
  --control:       #15120F;
  --press-color:   #15120F;

  --accent:        #3461F5;
  --accent-hover:  #2850D8;
  --accent-fg:     #FFFFFF;
  --accent-soft:   rgba(52, 97, 245, 0.10);
  --accent-line:   rgba(52, 97, 245, 0.35);

  /* A highlighter: marks, the founder tag, the selected chip. */
  --pop:           #FFD43B;
  --pop-fg:        #15120F;

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

  /* Outline weight, the key-press under a button, and paper resting on the
     board and lifted off it. */
  --line: 1.5px;
  --press: 0 3px 0 var(--press-color);
  --paper:      0 1px 1px rgba(70, 45, 10, .10), 0 10px 22px -12px rgba(70, 45, 10, .38);
  --paper-lift: 0 2px 3px rgba(70, 45, 10, .12), 0 20px 32px -14px rgba(70, 45, 10, .45);

  /* A note's paper: the hue comes from the product, these from the theme. */
  --card-s: 78%;
  --card-l: 92%;
  --note-s: 85%;
  --note-l: 84%;
  --tape: rgba(255, 221, 120, .75);
  --dots: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='22' height='22'%3E%3Ccircle cx='2' cy='2' r='1.1' fill='%23E6D2B5'/%3E%3C/svg%3E");

  --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: 12px;
  --radius-sm: 8px;
  --radius-pill: 999px;
}

/* Night: the same outlines and shadows, drawn in cream on a deep violet. */
:root[data-theme="dark"] {
  color-scheme: dark;

  /* Deep indigo rather than grey-violet: the first pass at night read as
     washed out, a board at dusk instead of one lit up. */
  --bg:            #141029;
  --surface:       #1F1A38;
  --surface-2:     #29224A;
  --text:          #FFF3E2;
  --muted:         #CFC5DC;
  --faint:         #9C92B0;
  --border:        #352D58;
  --border-strong: rgba(255, 243, 226, .42);
  --ink:           #FFF3E2;
  /* Cream outlines glared on every card at full strength. Notes and panels
     get a faint edge, controls a clear one, and a button sits on a key darker
     than the board instead of a strip of light. */
  --edge:          rgba(255, 243, 226, .14);
  --control:       rgba(255, 243, 226, .55);
  --press-color:   #07060B;

  --accent:        #7C98FF;
  --accent-hover:  #96ADFF;
  --accent-fg:     #15120F;
  --accent-soft:   rgba(124, 152, 255, 0.14);
  --accent-line:   rgba(124, 152, 255, 0.40);

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

  --paper:      0 1px 1px rgba(0, 0, 0, .45), 0 12px 24px -12px rgba(0, 0, 0, .75);
  --paper-lift: 0 2px 3px rgba(0, 0, 0, .5), 0 22px 34px -14px rgba(0, 0, 0, .85);
  /* Notes take their dark colour from the night rules in the noticeboard
     layer, not from --card-* and --note-*. */
  --tape: rgba(255, 243, 226, .16);
  --dots: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='22' height='22'%3E%3Ccircle cx='2' cy='2' r='1.1' fill='%232C2552'/%3E%3C/svg%3E");
}

* { 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 stays still
 * until the wordmark is hovered (or focused from the keyboard), so a page
 * load does not flash the mark at you. 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;
}
.wordmark-mark .m1 { opacity: .28; }
.wordmark-mark .m2 { opacity: 1; }
.wordmark-mark .m3 { opacity: .28; }
.wordmark:is(:hover, :focus-visible) .wordmark-mark .m {
  animation: pitchrow-travel 1.8s ease-in-out infinite;
}
.wordmark:is(:hover, :focus-visible) .wordmark-mark .m1 { animation-delay: .2s; }
.wordmark:is(:hover, :focus-visible) .wordmark-mark .m2 { animation-delay: .38s; }
.wordmark:is(:hover, :focus-visible) .wordmark-mark .m3 { animation-delay: .56s; }

.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); }

/* Waiting. A disabled button that looked exactly like an enabled one read as a
   dead page — and sign-in fetches clerk-js on the click, while a pitch takes
   up to fifteen seconds to check. Reduced motion leaves a still ring. */
.btn:disabled, .btn[aria-busy="true"] { opacity: .72; cursor: progress; }
.btn:disabled:hover { background: var(--accent); }
.btn-ghost:disabled:hover { background: transparent; border-color: var(--border-strong); }
.btn[aria-busy="true"]::after {
  content: ''; flex: 0 0 auto;
  width: .8em; height: .8em; margin-left: .55em;
  border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%;
  animation: btn-spin .7s linear infinite;
}
@keyframes btn-spin { to { transform: rotate(360deg) } }
.form-status { margin-top: .6rem; }

/* ---------- 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 .maker-entry .maker-avatar { width: 44px; height: 44px; }
.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;
}
.founder-tag {
  font-family: var(--mono); font-size: .625rem; text-transform: uppercase;
  letter-spacing: .1em; color: var(--muted);
  border: 1px solid var(--border-strong); 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: 700; letter-spacing: -0.02em;
  color: hsl(var(--mono-h) 55% 30%);
  background: hsl(var(--mono-h) 70% 86%);
  border: 1px solid hsl(var(--mono-h) 30% 70%);
}
:root[data-theme="dark"] .thumb-mono {
  color: hsl(var(--mono-h) 62% 80%);
  background: hsl(var(--mono-h) 38% 22%);
  border-color: hsl(var(--mono-h) 34% 30%);
}

/* ---------- 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);
}
.shot--pending {
  display: flex; align-items: center; justify-content: center;
  padding: 1.5rem; text-align: center; color: var(--faint);
  font-size: .875rem; line-height: 1.45;
}

.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 ---------- */

/*
 * Four figures across the card. Without a grid they stacked as a definition
 * list, so a 72rem-wide dashboard spent most of its width empty and the
 * numbers had the same weight as their labels.
 */
.figures {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1.1rem 1.25rem; margin: 1.2rem 0 0; padding: 1.15rem 0 0;
  border-top: 1px solid var(--border);
}
.figures > div { min-width: 0; }
.figures dt {
  margin: 0 0 .2rem; font-size: .75rem; font-weight: 450; color: var(--faint);
}
.figures dd {
  margin: 0; font-size: 1.7rem; font-weight: 600; line-height: 1.15;
  letter-spacing: -0.03em; font-variant-numeric: tabular-nums; color: var(--text);
}
.figure-note { display: block; margin-top: .3rem; font-size: .75rem; color: var(--faint); line-height: 1.35; }

.rev-tools {
  display: grid; gap: .65rem; margin-top: 1.15rem; padding-top: 1.05rem;
  border-top: 1px solid var(--border);
}
.rev-tools .rev-pitch { margin-top: 0; }
.rev-tools .stat-table { margin-top: .75rem; }

.stat-table { width: 100%; border-collapse: collapse; table-layout: fixed; 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: .55rem .75rem .55rem 0; border-bottom: 1px solid var(--border);
}
.stat-table td { padding: .55rem .75rem .55rem 0; border-bottom: 1px solid var(--border); vertical-align: top; }
/* Headers were left-aligned while the numbers were right-aligned, so each
   column of figures sat under the next heading along. */
.stat-table :is(th, td).num {
  text-align: right; font-variant-numeric: tabular-nums;
  padding-right: 0; padding-left: .75rem;
}
.stat-table td.num { color: var(--muted); }
.stat-table th:first-child,
.stat-table td:first-child { width: 28%; }
.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; }

/* As many equal columns as there are groups: Sponsor is only there while
   sponsorship is advertised, and a fixed four left an empty track. */
.footer-cols { display: grid; grid-auto-flow: column; grid-auto-columns: 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); }

/* A table wider than a phone scrolls inside itself, not the page. */
.table-scroll { overflow-x: auto; }
.funnel-days { min-width: 44rem; }
.funnel-days th { white-space: nowrap; }

/* Directories Pitchrow is listed on. Some only list a site that links back. */
.footer-launched {
  display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 1.25rem;
  padding: .9rem 0; border-top: 1px solid var(--border);
}
.footer-launched .section-label { margin: 0; }
.footer-launched ul {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; align-items: center; gap: .4rem 1.1rem;
}
.footer-launched a {
  color: var(--text); font-size: .8125rem; font-weight: 600;
  text-decoration: underline; text-decoration-thickness: 1.5px;
  text-underline-offset: 3px; text-decoration-color: var(--pop);
}
.footer-launched a:hover { color: var(--accent); text-decoration-color: var(--accent); }
.footer-launched img { display: block; height: 36px; width: auto; }

.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: none; width: 100%;
}
.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);
}

/* Weekly drop: only rendered when pitches are actually waiting. */
.drop {
  display: flex; align-items: baseline; gap: .45rem; flex-wrap: wrap;
  margin: 0 0 1rem; font-size: .9375rem; color: var(--text);
  font-family: var(--mono); letter-spacing: .01em;
  padding: .65rem .9rem; border-radius: var(--radius);
  border: 1px solid var(--accent-line); background: var(--accent-soft);
}
.drop-time { color: var(--accent); font-weight: 600; }
.drop-wait { color: var(--faint); }

/* ---------- 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; }

/*
 * One column, full shell width. Two-column (form | points) left a hole
 * between a short form and a 17rem rail; capping the pitch at 40rem and
 * putting the points underneath left the same hole to the right of the
 * headline. Headline, field, and the three promises now share the 72rem
 * measure, so the right edge of the shell is content, not empty track.
 */
.hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1.75rem;
  align-items: stretch;
  padding: 1.25rem 0 0; margin-bottom: 2.5rem;
}
.hero-main { min-width: 0; max-width: none; }
.hero h1 {
  font-size: clamp(2.2rem, 4.4vw, 3.35rem);
  line-height: 1.05; letter-spacing: -0.042em;
  max-width: none; 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 h1 .h1-line { display: block; }
.hero .lede { font-size: 1.125rem; max-width: 46rem; margin-bottom: 0; }
.hero-form { max-width: none; width: 100%; }
.hero-form input { padding: .85rem 1.05rem; }
.pulse { max-width: none; }
.drop { max-width: none; }

.hero-points {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .75rem;
  align-content: stretch;
}
.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: .9rem 1rem; 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; }

/* 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);
}
.cat-about { margin-top: 3rem; padding-top: 1.75rem; border-top: 1px solid var(--border); }
.cat-about h2 { margin-bottom: .75rem; }
.cat-about .cat-intro { margin-bottom: 0; }

/* 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; }

/* 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 light you press it for dark. */
.theme-toggle .icon-sun { display: none; }
.theme-toggle .icon-moon { display: block; }
:root[data-theme="dark"] .theme-toggle .icon-sun { display: block; }
:root[data-theme="dark"] .theme-toggle .icon-moon { display: none; }
.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: draft ---------- */

/* Shown when a pitch written before sign-in, or before a session lapsed, has
   been filled back in. */
.draft-note {
  padding: .8rem 1rem; border-radius: var(--radius); margin: 0 0 1.5rem;
  background: var(--accent-soft); border: 1px solid var(--accent-line);
  color: var(--text); font-size: .9rem;
}
.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) 55% 30%); background: hsl(var(--mono-h) 70% 86%);
  border-color: hsl(var(--mono-h) 30% 70%);
}
:root[data-theme="dark"] .maker-avatar--mono {
  color: hsl(var(--mono-h) 45% 80%); background: hsl(var(--mono-h) 22% 22%);
  border-color: hsl(var(--mono-h) 22% 30%);
}
.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: 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 .maker-entry .maker-avatar { width: 56px; height: 56px; grid-column: 1; grid-row: 1 / span 3; }
  .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-auto-flow: row; 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; }
  .figures { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .figures dd { font-size: 1.45rem; }
  .hero-points { grid-template-columns: 1fr; }
}

@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 and Makers live in the account menu and the footer on small screens. */
  .site-nav .nav-link[href="/browse"],
  .site-nav .nav-link[href="/makers"] { 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 .maker-entry .maker-avatar { 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); }


/* ==========================================================================
   The noticeboard layer.

   Last in the file so it wins over the quieter rules above it at every width.
   Depth comes from paper shadows, not hard offsets, and outlines stay thin.
   A lean is a transform, so straightening a card never moves its neighbours.
   ========================================================================== */

::selection { background: var(--pop); color: var(--pop-fg); }

body { background-image: var(--dots); background-size: 22px 22px; }

/* Chrome. */
.site-header { border-bottom: var(--line) solid var(--control); }
.site-header::before { background: color-mix(in srgb, var(--surface) 90%, transparent); }
.site-footer { border-top: var(--line) solid var(--control); }
.wordmark { font-weight: 800; letter-spacing: -0.035em; }

h1 { font-weight: 800; letter-spacing: -0.04em; }
h2 { font-weight: 750; }

/* Buttons are pills that press down like a key. */
.btn {
  border: var(--line) solid var(--control); border-radius: var(--radius-pill);
  box-shadow: var(--press); font-weight: 700; padding-inline: 1.15rem;
  transition: transform .08s ease, box-shadow .08s ease, background-color .12s ease, color .12s ease;
}
.btn-sm { padding-inline: .85rem; }
.btn:hover { transform: translateY(-1px); box-shadow: 0 4px 0 var(--press-color); }
.btn:active { transform: translateY(3px); box-shadow: 0 0 0 var(--press-color); }
.btn-ghost { background: var(--surface); color: var(--text); border-color: var(--control); }
.btn-ghost:hover { background: var(--pop); color: var(--pop-fg); border-color: var(--control); }
.btn:disabled, .btn[aria-busy="true"] { transform: none; box-shadow: var(--press); }
.btn:disabled:hover { background: var(--accent); }
.btn-ghost:disabled:hover { background: var(--surface); }
.linkbtn { color: var(--text); font-weight: 600; }

/* Fields: outlined, with a yellow ring while you type. */
input, select, textarea {
  border: var(--line) solid var(--control); border-radius: 12px;
  background: var(--surface); color: var(--text);
  transition: box-shadow .1s ease;
}
input:hover, select:hover, textarea:hover { border-color: var(--control); }
input:focus, select:focus, textarea:focus { outline: none; border-color: var(--control); box-shadow: 0 0 0 3px var(--pop); }
.hsearch input { border: var(--line) solid var(--control); border-radius: var(--radius-pill); }
.hsearch input:focus { background: var(--surface); }

/* Hero. The promise speaks in a second voice, with one word ringed by hand. */
.hero { position: relative; }
.hero h1 { font-size: clamp(2.4rem, 5.4vw, 4.1rem); line-height: 1.05; letter-spacing: -0.045em; }
.h1-promise {
  font-family: ui-serif, "New York", "Iowan Old Style", Charter, Georgia, Cambria, serif;
  font-style: italic; font-weight: 700; letter-spacing: -0.03em;
  color: var(--accent);
}
.ringed { position: relative; white-space: nowrap; }
.ringed::after {
  content: ""; position: absolute; inset: .06em -.22em -.14em -.2em; pointer-events: none;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 80' preserveAspectRatio='none'%3E%3Cpath d='M108 8 C 162 6, 196 24, 193 43 C 190 64, 140 76, 96 73 C 46 70, 6 58, 9 37 C 12 17, 56 7, 122 12' stroke='%23FFD43B' stroke-width='5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E") no-repeat center / 100% 100%;
}
.hero-sticker {
  position: absolute; top: .25rem; right: .5rem;
  width: 7.25rem; height: 7.25rem; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; text-align: center;
  background: var(--pop); color: var(--pop-fg);
  border: var(--line) solid var(--edge); box-shadow: var(--paper);
  font-weight: 800; font-size: 1.05rem; line-height: 1.1; letter-spacing: -0.02em;
  transform: rotate(10deg);
}
@media (max-width: 1000px) { .hero-sticker { display: none; } }
.hero-form input {
  border-width: 2px; border-radius: var(--radius-pill); box-shadow: var(--paper);
  padding: .95rem 1.3rem; font-size: 1.05rem;
}
.hero-form input:focus { box-shadow: 0 0 0 4px var(--pop), var(--paper); }
.hero-form .btn { border-width: 2px; font-size: 1rem; padding-inline: 1.5rem; }

/* The three promises are sticky notes, each a different colour and lean. */
.hero-points { gap: 1.1rem; }
.hero-points li {
  border: 0; border-radius: 3px; color: var(--muted);
  background: hsl(48 var(--note-s) var(--note-l)); box-shadow: var(--paper);
  transform: rotate(-1deg);
}
.hero-points li:nth-child(2) { background: hsl(160 var(--note-s) var(--note-l)); transform: rotate(.8deg); }
.hero-points li:nth-child(3) { background: hsl(205 var(--note-s) var(--note-l)); transform: rotate(-.5deg); }
.point-icon { background: var(--surface); color: var(--text); border: var(--line) solid var(--control); }

/* Status lines read like a ticket stub: a perforated edge. */
.pulse {
  color: var(--muted); background: var(--surface);
  border: var(--line) dashed var(--control); border-radius: var(--radius-pill);
}
.drop { border: var(--line) dashed var(--control); background: var(--accent-soft); }

/* The wall: paper notes, taped up, straightening when you reach for one. */
.wall--rows { gap: 1.6rem 1.25rem; padding-top: .65rem; }
.wall--rows .pitch,
.wall--rows .pitch:last-child {
  overflow: visible;
  background: hsl(var(--card-h, 40) var(--card-s) var(--card-l));
  border: var(--line) solid var(--edge); border-radius: 6px;
  box-shadow: var(--paper);
  transform: rotate(var(--tilt, 0deg));
  transition: transform .18s cubic-bezier(.2, .7, .3, 1.25), box-shadow .18s ease;
}
.wall--rows .pitch::after {
  content: ""; position: absolute; top: -.7rem; left: 50%;
  width: 5.5rem; height: 1.35rem; margin-left: -2.75rem;
  background: var(--tape); pointer-events: none;
  transform: rotate(calc(var(--tilt, 0deg) * -2.5));
}
.wall--rows .pitch:hover,
.wall--rows .pitch:focus-within {
  background: hsl(var(--card-h, 40) var(--card-s) var(--card-l)); border-color: var(--edge);
  transform: rotate(0deg) translateY(-4px); box-shadow: var(--paper-lift);
}
.wall--rows .pitch::before { display: none; }
.wall--rows .pitch:hover .thumb,
.wall--rows .pitch:focus-within .thumb { transform: none; filter: none; border-color: var(--edge); }
.wall--rows .pitch .thumb-mono { background: var(--surface); }
.thumb { border: var(--line) solid var(--edge); border-radius: 8px; }
.thumb-mono { border-color: var(--edge); }
.maker-avatar { border: var(--line) solid var(--edge); }

/* Paid placement is pinned, not taped: a pin, and plain paper. */
.wall--rows .pitch.pitch--sponsored { background: var(--surface); }
.wall--rows .pitch.pitch--sponsored::after {
  width: 14px; height: 14px; margin-left: -7px; top: -7px; border-radius: 50%;
  background: var(--accent); border: var(--line) solid var(--control); transform: none;
}

/* Tags are stickers on the note. */
.sponsor-tag { background: var(--accent); color: var(--accent-fg); border: 1.5px solid var(--control); }
.founder-tag { background: var(--surface); color: var(--text); border: 1.5px solid var(--control); }

/* Index cards: the rail, side panels and boxes that hold one thing. */
.rail-block, .page-aside, .maker-card, .cat-card {
  background: var(--surface);
  border: var(--line) solid var(--edge); border-top: 5px solid var(--accent);
  border-radius: 6px; box-shadow: var(--paper);
}
.rail-block { padding: .9rem 1.1rem 1rem; }
.page-aside { padding: 1.15rem 1.35rem; }
.cat-card { transition: transform .18s cubic-bezier(.2, .7, .3, 1.25), box-shadow .18s ease; }
.cat-card:hover {
  background: var(--surface); border-color: var(--edge); border-top-color: var(--accent);
  transform: translateY(-3px); box-shadow: var(--paper-lift);
}
/* The screenshot is a photo pinned to the board. */
.shot { border: var(--line) solid var(--edge); border-radius: 4px; box-shadow: var(--paper); transform: rotate(-.6deg); }
.fact { border: 1.5px solid var(--control); background: var(--surface); }
.draft-note, .error-banner { border: var(--line) solid var(--edge); box-shadow: var(--paper); }
.draft-note { background: hsl(48 var(--note-s) var(--note-l)); }

/* Chips: a yellow marker on the one you are on. */
.chip { border: var(--line) solid var(--control); background: var(--surface); color: var(--text); font-weight: 600; }
.chip:hover { border-color: var(--control); color: var(--text); background: var(--surface-2); }
.chip[aria-current="page"] { background: var(--pop); color: var(--pop-fg); border-color: var(--control); }
.chip[aria-current="page"] .count { color: var(--pop-fg); }

/* Menus and the theme control. */
.umenu-panel, .navmenu-panel { border: var(--line) solid var(--edge); box-shadow: var(--paper-lift); }
.theme-toggle {
  border: var(--line) solid var(--control); border-radius: 50%;
  background: var(--surface); color: var(--text); box-shadow: var(--press);
}
.theme-toggle:hover { border-color: var(--control); background: var(--pop); color: var(--pop-fg); }
.navmenu-panel .theme-toggle { box-shadow: none; border-radius: var(--radius); }
.navmenu-trigger { border: var(--line) solid var(--control); background: var(--surface); box-shadow: var(--press); }

/*
 * Night. A pastel at low lightness is mud — yellow goes olive, orange goes
 * brown — and a faint tint over dark paper is pale. So at night colour moves
 * to where it can stay bright: a note is dark paper with a band of its own
 * colour along the top and tape to match, and the three sticky notes stay
 * the bright paper they are in daylight, with dark ink on them.
 */
:root[data-theme="dark"] .wall--rows .pitch,
:root[data-theme="dark"] .wall--rows .pitch:last-child,
:root[data-theme="dark"] .wall--rows .pitch:hover,
:root[data-theme="dark"] .wall--rows .pitch:focus-within {
  background: color-mix(in srgb, hsl(var(--card-h, 40) 80% 62%) 10%, var(--surface));
  border-top: 5px solid hsl(var(--card-h, 40) 88% 66%);
}
:root[data-theme="dark"] .wall--rows .pitch::after { background: hsl(var(--card-h, 40) 90% 72% / .5); }
:root[data-theme="dark"] .wall--rows .pitch.pitch--sponsored { background: var(--surface-2); border-top-color: var(--accent); }
:root[data-theme="dark"] .wall--rows .pitch .thumb-mono { background: var(--surface-2); }

:root[data-theme="dark"] .hero-points li { background: hsl(48 96% 70%); color: #463B2A; }
:root[data-theme="dark"] .hero-points li:nth-child(2) { background: hsl(158 60% 68%); color: #1F4537; }
:root[data-theme="dark"] .hero-points li:nth-child(3) { background: hsl(208 92% 78%); color: #1E3A57; }
:root[data-theme="dark"] .hero-points strong { color: #15120F; }
:root[data-theme="dark"] .hero-points .point-icon {
  background: rgba(255, 255, 255, .55); color: #15120F; border-color: rgba(21, 18, 15, .55);
}
:root[data-theme="dark"] .draft-note { background: hsl(48 96% 70%); color: #15120F; border-color: transparent; }
:root[data-theme="dark"] .draft-note .linkbtn { color: #15120F; }

/* Smaller leans on a phone, where a tilted card meets the screen edge. */
@media (max-width: 560px) {
  .wall--rows .pitch, .wall--rows .pitch:last-child { transform: rotate(calc(var(--tilt, 0deg) * .5)); }
  .wall--rows .pitch:hover, .wall--rows .pitch:focus-within { transform: rotate(0deg) translateY(-3px); }
  .hero-points li, .hero-points li:nth-child(2), .hero-points li:nth-child(3) { transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .btn:hover, .btn:active { transform: none; }
  .wall--rows .pitch:hover, .wall--rows .pitch:focus-within { transform: rotate(var(--tilt, 0deg)); }
  .cat-card:hover { transform: none; }
}
