/* FlingList stylesheet.
 *
 * Self-contained on purpose -- no CDN, no framework, no third-party request at
 * page load. An earlier draft loaded Tailwind and daisyUI from two CDNs; their
 * component layers disagreed and .btn-primary rendered with no background.
 *
 * The font is served from our own origin for the same reason it matters on this
 * particular site: a Google Fonts <link> tells fonts.gstatic.com the Referer of
 * every visitor on every page view. For a personals board whose pitch is "your
 * address is never shared", handing a third party a per-visitor log of which
 * pages were read is the wrong default. static/fonts holds two woff2 subsets
 * (Inter, SIL OFL 1.1, licence alongside them); latin-ext only downloads when a
 * glyph needs it.
 *
 * Palette: deep teal, warm sand, one amber accent. Chosen to look like nothing
 * else in the category -- incumbents default to pink and red.
 *
 * Conventions:
 *   - every colour is a token; nothing hard-codes a hex outside :root
 *   - one easing curve and two durations, so motion feels like one system
 *   - all motion is wrapped by prefers-reduced-motion at the bottom
 */

/* ---------------------------------------------------------------- fonts --- */

@font-face {
  font-family: "Inter var";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/inter-latin.65850a373e25.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter var";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/inter-latin-ext.01ba6c2a184b.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ---------------------------------------------------------------- tokens -- */

:root {
  /* ink */
  --ink:          #14171a;
  --ink-soft:     #555f5c;
  --ink-faint:    #8a938f;

  /* ground */
  --bg:           #faf9f6;
  --bg-tint:      #f3f1ea;
  --surface:      #ffffff;
  --surface-2:    #fbfaf7;
  --line:         #e3e0d7;
  --line-soft:    #eeece4;

  /* brand */
  --primary:      #16524f;
  --primary-hov:  #0e403e;
  --primary-ink:  #f6f8f6;
  --primary-wash: #e7f0ee;
  --accent:       #bd6a2e;
  --accent-wash:  #fbf1e7;

  /* status */
  --ok:    #1f6346;  --ok-bg:   #e9f3ed;
  --warn:  #8a5d00;  --warn-bg: #fcf4e3;
  --err:   #9a2b2b;  --err-bg:  #fcefed;

  /* form */
  --radius:    10px;
  --radius-sm: 7px;
  --radius-lg: 16px;
  --maxw:      64rem;
  --maxw-read: 40rem;

  --shadow-sm: 0 1px 2px rgba(14, 24, 22, .05);
  --shadow:    0 1px 2px rgba(14, 24, 22, .05), 0 6px 16px -6px rgba(14, 24, 22, .10);
  --shadow-lg: 0 2px 4px rgba(14, 24, 22, .05), 0 16px 36px -12px rgba(14, 24, 22, .16);
  --ring:      0 0 0 3px color-mix(in srgb, var(--primary) 28%, transparent);

  --ease:   cubic-bezier(.32, .72, 0, 1);
  --fast:   120ms;
  --normal: 220ms;

  color-scheme: light;
}

/* Dark values live in one custom property block applied by two selectors: the
 * system preference (unless the visitor has explicitly chosen light) and the
 * explicit choice of dark. Keeping the values in a @media-free list would mean
 * repeating them; keeping them in the media query only would break the toggle. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --ink:          #e9e7e1;
    --ink-soft:     #a2a9a5;
    --ink-faint:    #727975;
    --bg:           #101312;
    --bg-tint:      #161a19;
    --surface:      #191d1c;
    --surface-2:    #1e2322;
    --line:         #2c3230;
    --line-soft:    #232827;
    --primary:      #5fbdb5;
    --primary-hov:  #7ad0c8;
    --primary-ink:  #07201e;
    --primary-wash: #16302d;
    --accent:       #e09257;
    --accent-wash:  #2b2117;
    --ok:    #6cc49b;  --ok-bg:   #15271f;
    --warn:  #d4a63c;  --warn-bg: #292213;
    --err:   #e38b84;  --err-bg:  #2a1a19;
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
    --shadow:    0 1px 2px rgba(0, 0, 0, .4), 0 6px 16px -6px rgba(0, 0, 0, .5);
    --shadow-lg: 0 2px 4px rgba(0, 0, 0, .4), 0 16px 36px -12px rgba(0, 0, 0, .6);
    color-scheme: dark;
  }
}
:root[data-theme="dark"] {
  --ink: #e9e7e1; --ink-soft: #a2a9a5; --ink-faint: #727975;
  --bg: #101312; --bg-tint: #161a19; --surface: #191d1c; --surface-2: #1e2322;
  --line: #2c3230; --line-soft: #232827;
  --primary: #5fbdb5; --primary-hov: #7ad0c8; --primary-ink: #07201e;
  --primary-wash: #16302d; --accent: #e09257; --accent-wash: #2b2117;
  --ok: #6cc49b; --ok-bg: #15271f; --warn: #d4a63c; --warn-bg: #292213;
  --err: #e38b84; --err-bg: #2a1a19;
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
  --shadow:    0 1px 2px rgba(0, 0, 0, .4), 0 6px 16px -6px rgba(0, 0, 0, .5);
  --shadow-lg: 0 2px 4px rgba(0, 0, 0, .4), 0 16px 36px -12px rgba(0, 0, 0, .6);
  color-scheme: dark;
}

/* ------------------------------------------------------------- elements --- */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scrollbar-gutter: stable;
}

body {
  margin: 0;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  color: var(--ink);
  font-family: "Inter var", ui-sans-serif, -apple-system, BlinkMacSystemFont,
               "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  font-size: 16px;
  line-height: 1.55;
  font-feature-settings: "cv11" 1;   /* single-storey g, closer to Inter Display */
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

::selection { background: color-mix(in srgb, var(--primary) 26%, transparent); }

a { color: inherit; }

.link {
  color: var(--primary);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  text-decoration-color: color-mix(in srgb, var(--primary) 40%, transparent);
  transition: text-decoration-color var(--fast) var(--ease), color var(--fast) var(--ease);
}
.link:hover { color: var(--primary-hov); text-decoration-color: currentColor; }
.link-plain { text-decoration: none; }
.link-plain:hover { text-decoration: underline; text-underline-offset: 3px; }

h1, h2, h3 {
  margin: 0;
  line-height: 1.15;
  font-weight: 620;
  letter-spacing: -0.021em;
  text-wrap: balance;
}
h1 { font-size: clamp(1.75rem, 1.35rem + 1.6vw, 2.35rem); }
h2 { font-size: 1.1875rem; letter-spacing: -0.015em; }
h3 { font-size: 1rem; letter-spacing: -0.01em; }
p { margin: 0; text-wrap: pretty; }

code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.875em;
  background: var(--bg-tint);
  border: 1px solid var(--line-soft);
  border-radius: 5px;
  padding: 1px 5px;
}

:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

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

.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: 16px;
}
@media (min-width: 640px) { .wrap { padding-inline: 24px; } }

main.wrap { flex: 1; padding-block: 28px 56px; }

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

.site-header {
  position: sticky;
  top: 0;
  z-index: 30;
  background: color-mix(in srgb, var(--bg) 80%, transparent);
  backdrop-filter: saturate(180%) blur(12px);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid color-mix(in srgb, var(--line) 70%, transparent);
}
.site-header .bar { display: flex; align-items: center; gap: 8px; height: 60px; }

.brand {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-weight: 650;
  font-size: 1.0625rem;
  letter-spacing: -0.03em;
  text-decoration: none;
  margin-right: 4px;
  white-space: nowrap;
}
/* Scoped to .brand-text: a bare "Fling" text node would otherwise become its
 * own flex item and pick up the flex gap, splitting the wordmark in two. */
.brand .brand-text span { color: var(--primary); }
/* The mark is an inline <svg> carrying its own brand colours, so it needs no
 * theming here -- only sizing and the hover nudge. */
.brand .brand-mark {
  width: 26px;
  height: 26px;
  flex: none;
  display: block;
  border-radius: 7.3px;            /* matches the artwork's rx, so the shadow hugs it */
  box-shadow: var(--shadow-sm);
  transition: transform var(--normal) var(--ease);
}
.brand:hover .brand-mark { transform: rotate(-6deg) scale(1.07); }

.site-header .bar { position: relative; }
.site-nav { margin-left: auto; display: flex; align-items: center; gap: 2px; }
.nav-links { display: flex; align-items: center; gap: 2px; }

.nav-burger {
  display: none;
  width: 34px; height: 34px;
  place-items: center;
  border: 1px solid transparent;
  border-radius: 999px;
  background: transparent;
  color: var(--ink-soft);
  cursor: pointer;
  padding: 0;
  transition: background-color var(--fast) var(--ease), color var(--fast) var(--ease);
}
.nav-burger:hover { background: var(--bg-tint); color: var(--ink); }
.nav-burger svg { width: 19px; height: 19px; }

/* Below 640px the same markup becomes a dropdown panel. Five nav items plus a
 * theme toggle do not fit a 375px header -- without this the toggle is clipped
 * off the right edge. */
@media (max-width: 639px) {
  .nav-burger { display: grid; }
  .nav-links {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    left: auto;
    min-width: 190px;
    display: none;
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    padding: 7px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow-lg);
  }
  .nav-links.is-open { display: flex; animation: nav-in 160ms var(--ease); }
  .nav-links .btn { width: 100%; justify-content: flex-start; box-shadow: none; }
  .nav-links .inline-form { display: block; }
}
@keyframes nav-in {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}

.theme-toggle {
  width: 34px; height: 34px;
  display: grid; place-items: center;
  border: 1px solid transparent;
  border-radius: 999px;
  background: transparent;
  color: var(--ink-soft);
  cursor: pointer;
  padding: 0;
  transition: background-color var(--fast) var(--ease), color var(--fast) var(--ease);
}
.theme-toggle:hover { background: var(--bg-tint); color: var(--ink); }
.theme-toggle svg { width: 17px; height: 17px; }
.theme-toggle .i-moon { display: none; }
:root[data-theme="dark"] .theme-toggle .i-moon { display: block; }
:root[data-theme="dark"] .theme-toggle .i-sun { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .i-moon { display: block; }
  :root:not([data-theme="light"]) .theme-toggle .i-sun { display: none; }
}

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

.site-footer {
  border-top: 1px solid var(--line);
  background: var(--bg-tint);
  margin-top: auto;
}
.site-footer .wrap {
  padding-block: 26px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 22px;
  font-size: 0.875rem;
  color: var(--ink-soft);
}
.site-footer a { text-decoration: none; }
.site-footer a:hover { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
.site-footer .spacer { margin-left: auto; }
.site-footer .age-pill {
  margin-left: auto;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  padding: 3px 10px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink-soft);
}

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

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  padding: 9px 16px;
  min-height: 40px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow-sm);
  font: inherit;
  font-weight: 560;
  font-size: 0.9375rem;
  letter-spacing: -0.005em;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color var(--fast) var(--ease),
              border-color var(--fast) var(--ease),
              color var(--fast) var(--ease),
              box-shadow var(--fast) var(--ease),
              transform var(--fast) var(--ease);
}
.btn:hover { border-color: color-mix(in srgb, var(--ink-faint) 70%, transparent); box-shadow: var(--shadow); }
.btn:active { transform: translateY(1px); box-shadow: var(--shadow-sm); }

.btn-primary {
  background: var(--primary);
  border-color: color-mix(in srgb, var(--primary) 80%, #000);
  color: var(--primary-ink);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .14), var(--shadow-sm);
}
.btn-primary:hover {
  background: var(--primary-hov);
  border-color: color-mix(in srgb, var(--primary-hov) 80%, #000);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .14), var(--shadow);
}

.btn-ghost { background: transparent; border-color: transparent; color: var(--ink-soft); box-shadow: none; }
.btn-ghost:hover { background: var(--bg-tint); border-color: transparent; color: var(--ink); box-shadow: none; }

.btn-sm { min-height: 34px; padding: 6px 13px; font-size: 0.875rem; border-radius: var(--radius-sm); }
.btn-xs { min-height: 28px; padding: 3px 10px; font-size: 0.8125rem; border-radius: 6px; }
.btn-lg { min-height: 46px; padding: 11px 22px; font-size: 1rem; border-radius: var(--radius); }
.btn-danger { color: var(--err); }
.btn-danger:hover { background: var(--err-bg); border-color: color-mix(in srgb, var(--err) 35%, transparent); }
.btn-block { width: 100%; }
.btn .arrow { transition: transform var(--normal) var(--ease); }
.btn:hover .arrow { transform: translateX(3px); }

/* --------------------------------------------------------------- badges --- */

.badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 9px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink-soft);
  font-size: 0.75rem;
  font-weight: 560;
  line-height: 1.55;
  white-space: nowrap;
}
.badge-mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.03em;
}
.badge-primary { background: var(--primary); border-color: var(--primary); color: var(--primary-ink); }
.badge-wash { background: var(--primary-wash); border-color: transparent; color: var(--primary); }
.badge-lg { padding: 5px 13px; font-size: 0.8125rem; }
.badge-ok   { background: var(--ok-bg);   border-color: transparent; color: var(--ok); }
.badge-warn { background: var(--warn-bg); border-color: transparent; color: var(--warn); }
.badge-err  { background: var(--err-bg);  border-color: transparent; color: var(--err); }
a.badge { text-decoration: none; cursor: pointer; transition: all var(--fast) var(--ease); }
a.badge:hover { border-color: var(--primary); color: var(--primary); background: var(--primary-wash); }
a.badge-primary:hover { color: var(--primary-ink); background: var(--primary-hov); border-color: var(--primary-hov); }

/* ---------------------------------------------------------------- chips --- */

/* The category filter row. Scrolls sideways on a phone rather than wrapping to
 * four lines and pushing the feed below the fold. The mask fades the right edge
 * so it reads as "there is more", without a scrollbar. */
.chip-row {
  display: flex;
  gap: 6px;
  overflow-x: auto;
  scrollbar-width: none;
  padding: 2px 16px 10px;
  margin-inline: -16px;
  scroll-snap-type: x proximity;
}
.chip-row::-webkit-scrollbar { display: none; }
@media (min-width: 640px) {
  .chip-row { flex-wrap: wrap; overflow: visible; padding-inline: 0; margin-inline: 0; }
}

.chip {
  flex: none;
  scroll-snap-align: start;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 6px 13px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink-soft);
  font-size: 0.8125rem;
  font-weight: 560;
  letter-spacing: 0.01em;
  text-decoration: none;
  box-shadow: var(--shadow-sm);
  transition: background-color var(--fast) var(--ease),
              border-color var(--fast) var(--ease),
              color var(--fast) var(--ease);
}
.chip-mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.75rem; }
.chip:hover { color: var(--ink); border-color: var(--ink-faint); }
.chip.is-active {
  background: var(--primary);
  border-color: color-mix(in srgb, var(--primary) 80%, #000);
  color: var(--primary-ink);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .14), var(--shadow-sm);
}

/* --------------------------------------------------------------- alerts --- */

.alert {
  display: flex;
  gap: 10px;
  padding: 11px 14px;
  border-radius: var(--radius-sm);
  font-size: 0.9375rem;
  border: 1px solid var(--line);
  border-left-width: 3px;
  background: var(--surface);
  margin-bottom: 8px;
}
.alert-error   { background: var(--err-bg);  border-color: color-mix(in srgb, var(--err) 25%, transparent);  border-left-color: var(--err);  color: var(--err); }
.alert-warning { background: var(--warn-bg); border-color: color-mix(in srgb, var(--warn) 25%, transparent); border-left-color: var(--warn); color: var(--warn); }
.alert-success { background: var(--ok-bg);   border-color: color-mix(in srgb, var(--ok) 25%, transparent);   border-left-color: var(--ok);   color: var(--ok); }
/* Informational rather than a warning: the brand colour, and the body text
 * colour rather than the accent, because unlike the other three this one is
 * several sentences long and accent-coloured paragraphs are hard to read. */
.alert-info {
  background: color-mix(in srgb, var(--primary) 7%, transparent);
  border-color: color-mix(in srgb, var(--primary) 22%, transparent);
  border-left-color: var(--primary);
  color: var(--ink-soft);
  display: block;
  line-height: 1.55;
}
.alert-info strong { color: var(--ink); }

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

.field { margin-bottom: 18px; }
.label { display: block; font-weight: 560; font-size: 0.875rem; margin-bottom: 6px; letter-spacing: -0.005em; }
.help  { font-size: 0.8125rem; color: var(--ink-faint); margin-top: 6px; }
.error { font-size: 0.8125rem; color: var(--err); margin-top: 6px; font-weight: 500; }

.input, .textarea, .select {
  width: 100%;
  padding: 10px 13px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 0.9375rem;
  box-shadow: var(--shadow-sm);
  transition: border-color var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}
.input::placeholder, .textarea::placeholder { color: var(--ink-faint); }
.textarea { min-height: 170px; resize: vertical; line-height: 1.6; }
.select { appearance: none; padding-right: 36px;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 18px) 55%, calc(100% - 13px) 55%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
/* One-time code entry. Tabular figures and wide tracking so a 6-digit code
 * can be read back character by character against the text message, which is
 * the one thing this field is ever used for. */
.input-code {
  font-variant-numeric: tabular-nums;
  font-size: 1.375rem;
  letter-spacing: 0.32em;
  text-align: center;
  padding: 13px 13px;
}
.input-code::placeholder { letter-spacing: 0.32em; }

.input:focus, .textarea:focus, .select:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: var(--ring);
}

fieldset { border: 0; padding: 0; margin: 0; }
legend { font-weight: 560; font-size: 0.875rem; padding: 0; }
.choice {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  font-size: 0.9375rem;
  margin-top: 10px;
  padding: 9px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  cursor: pointer;
  transition: border-color var(--fast) var(--ease), background-color var(--fast) var(--ease);
}
.choice:hover { border-color: var(--ink-faint); }
.choice input { margin-top: 4px; accent-color: var(--primary); flex: none; }
.choice:has(input:checked) { border-color: var(--primary); background: var(--primary-wash); }

/* ------------------------------------------------------------- utilities -- */

.stack > * + * { margin-top: 16px; }
.row { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.row-between { display: flex; gap: 16px; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; }
.muted { color: var(--ink-soft); }
.faint { color: var(--ink-faint); }
.small  { font-size: 0.875rem; }
.xsmall { font-size: 0.8125rem; }
.prose { max-width: var(--maxw-read); }
.lede { font-size: 1.0625rem; color: var(--ink-soft); max-width: var(--maxw-read); }
.nums { font-variant-numeric: tabular-nums; }
.mt-1 { margin-top: 6px; }  .mt-2 { margin-top: 12px; }
.mt-3 { margin-top: 20px; } .mt-4 { margin-top: 34px; }
.mt-5 { margin-top: 52px; } .mt-6 { margin-top: 20px; }

.divider { border: 0; border-top: 1px solid var(--line); margin: 0; }

.crumbs {
  font-size: 0.8125rem;
  color: var(--ink-faint);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-bottom: 10px;
}
.crumbs a { text-decoration: none; transition: color var(--fast) var(--ease); }
.crumbs a:hover { color: var(--primary); }
.crumbs .sep { opacity: .5; }

.section-label {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 0.6875rem;
  font-weight: 650;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-faint);
}
.section-label::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line);
}

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

.hero {
  position: relative;
  padding: 44px 0 40px;
  isolation: isolate;
}
/* One soft wash behind the headline. Cheap depth, no image, and it sits behind
 * the text via z-index so it never intercepts a click. */
.hero::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -40px -50vw 0;
  background:
    radial-gradient(60% 70% at 22% 10%, color-mix(in srgb, var(--primary) 13%, transparent), transparent 70%),
    radial-gradient(45% 60% at 82% 0%,  color-mix(in srgb, var(--accent) 10%, transparent),  transparent 70%);
  pointer-events: none;
}
.hero h1 { max-width: 22ch; }
.hero .accent { color: var(--primary); }

.hero-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 28px;
  margin-top: 28px;
  padding-top: 22px;
  border-top: 1px solid var(--line);
}
.stat { display: flex; flex-direction: column; gap: 1px; }
.stat .n {
  font-size: 1.375rem;
  font-weight: 640;
  letter-spacing: -0.025em;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.stat .k {
  font-size: 0.6875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--ink-faint);
}

/* ------------------------------------------------------------ city grid --- */

.grid-cards {
  display: grid;
  gap: 8px;
  grid-template-columns: minmax(0, 1fr);
  margin-top: 16px;
}
@media (min-width: 560px)  { .grid-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 900px)  { .grid-cards { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.card-link {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 13px 15px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  text-decoration: none;
  font-weight: 540;
  font-size: 0.9375rem;
  overflow: hidden;
  transition: border-color var(--fast) var(--ease),
              box-shadow var(--fast) var(--ease),
              transform var(--fast) var(--ease);
}
.card-link::before {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 3px;
  background: var(--primary);
  transform: scaleY(0);
  transform-origin: center;
  transition: transform var(--normal) var(--ease);
}
.card-link:hover {
  border-color: color-mix(in srgb, var(--primary) 45%, var(--line));
  box-shadow: var(--shadow);
  transform: translateY(-1px);
}
.card-link:hover::before { transform: scaleY(1); }
.card-link .count {
  font-size: 0.75rem;
  color: var(--ink-faint);
  flex: none;
  font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------- region intro --- */

/* Constrained to the reading measure rather than the full grid: a region
 * intro is prose, and prose set to a 1100px container is unreadable. Sits
 * between the <h1> and the category chips, so its bottom margin is the only
 * gap before the chip row -- which carries its own 2px top padding for the
 * focus ring, hence 14px here and not 20px. */
.region-intro {
  max-width: var(--maxw-read);
  margin-top: 10px;
  margin-bottom: 14px;
  color: var(--ink-soft);
}
.region-intro p { margin: 0; }
.region-intro p + p { margin-top: 10px; }

/* ----------------------------------------------------------------- feed --- */

/* minmax(0, 1fr) rather than a bare 1fr or an implicit auto column: both of
 * those take a min track size of auto, so a card's min-content width (the
 * nowrap title) can push the track wider than the viewport. At 375px that
 * overflowed the page by 131px. */
.feed {
  list-style: none;
  margin: 18px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 8px;
}

.feed > li { display: contents; }

.feed a.post-card {
  display: block;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  text-decoration: none;
  transition: border-color var(--fast) var(--ease),
              box-shadow var(--fast) var(--ease),
              transform var(--fast) var(--ease);
}
.feed a.post-card:hover {
  border-color: color-mix(in srgb, var(--primary) 40%, var(--line));
  box-shadow: var(--shadow);
  transform: translateY(-1px);
}

.post-card .title-row {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
}
.post-card .title {
  font-weight: 560;
  font-size: 0.9375rem;
  letter-spacing: -0.008em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.post-card .snippet {
  margin-top: 5px;
  font-size: 0.875rem;
  color: var(--ink-soft);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.post-card .meta {
  margin-top: 9px;
  font-size: 0.75rem;
  color: var(--ink-faint);
  display: flex;
  align-items: center;
  gap: 7px;
  flex-wrap: wrap;
}
/* Separators come from CSS so the template can omit any field -- an absent
 * location or age never leaves a stray middot behind. */
.post-card .meta .bit + .bit::before { content: "·"; margin-right: 7px; opacity: .45; }
.post-card .meta .when { margin-left: auto; font-variant-numeric: tabular-nums; }

.pager { display: flex; justify-content: center; margin-top: 24px; }

.empty {
  margin-top: 24px;
  padding: 52px 24px;
  text-align: center;
  border: 1px dashed var(--line);
  border-radius: var(--radius-lg);
  background: var(--surface-2);
  color: var(--ink-soft);
}
.empty .btn { margin-top: 16px; }

/* ---------------------------------------------------------- post detail --- */

.post-head { display: flex; align-items: center; gap: 11px; flex-wrap: wrap; }
.post-head h1 { font-size: clamp(1.4rem, 1.2rem + 1vw, 1.75rem); flex: 1; min-width: 0; }

.post-meta {
  display: grid;
  gap: 2px 16px;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  margin-top: 22px;
  padding: 16px 18px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-2);
  font-size: 0.9375rem;
}
@media (min-width: 640px) { .post-meta { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 2px 12px; } }
.post-meta > div { padding-block: 4px; }
.post-meta dt {
  font-size: 0.625rem;
  font-weight: 650;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--ink-faint);
}
.post-meta dd { margin: 3px 0 0; font-weight: 520; }

.post-body {
  margin-top: 26px;
  max-width: var(--maxw-read);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  font-size: 1.0625rem;
  line-height: 1.7;
}

.note {
  margin-top: 22px;
  padding: 12px 14px;
  border-radius: var(--radius-sm);
  background: var(--bg-tint);
  border: 1px solid var(--line-soft);
  font-size: 0.8125rem;
  color: var(--ink-soft);
  max-width: var(--maxw-read);
}

/* ---------------------------------------------------------------- table --- */

.table { width: 100%; border-collapse: collapse; font-size: 0.9375rem; margin-top: 20px; }
.table th {
  text-align: left;
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-faint);
  font-weight: 650;
  padding: 0 10px 9px;
  border-bottom: 1px solid var(--line);
}
.table td { padding: 12px 10px; border-bottom: 1px solid var(--line-soft); vertical-align: middle; }
.table tbody tr { transition: background-color var(--fast) var(--ease); }
.table tbody tr:hover { background: var(--surface-2); }
.table .right { text-align: right; white-space: nowrap; }
.table-scroll { overflow-x: auto; margin-inline: -16px; padding-inline: 16px; }
@media (min-width: 640px) { .table-scroll { margin-inline: 0; padding-inline: 0; } }

.inline-form { display: inline; }

/* --------------------------------------------------------------- prose ---- */

.prose h1 { margin-bottom: 10px; }
.prose h2 { margin-top: 30px; margin-bottom: 8px; font-size: 1.0625rem; }
.prose p + p { margin-top: 12px; }
.prose ul { margin: 12px 0 0; padding-left: 20px; }
.prose li + li { margin-top: 6px; }
.prose p, .prose li { color: var(--ink-soft); }
.prose strong { color: var(--ink); font-weight: 600; }

/* ------------------------------------------------------------- narrow ----- */

.narrow { max-width: 26rem; }
.medium { max-width: 34rem; }

/* ------------------------------------------------- reduced motion ------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .card-link:hover, .feed a.post-card:hover, .btn:active { transform: none; }
}

/* Honeypot field (listings/forms.py BotTrapMixin).
   Positioned off-canvas rather than display:none or visibility:hidden on
   purpose: the scrapers worth catching skip inputs that are hidden by those
   two properties, precisely because they know the trick. This keeps the field
   in the layout and in the accessibility tree's "present but off screen"
   state, while aria-hidden and tabindex=-1 keep it away from screen readers
   and keyboard tabbing, so no real user can reach it by accident. */
.trap-field {
  position: absolute !important;
  left: -9999px !important;
  top: auto !important;
  width: 1px !important;
  height: 1px !important;
  overflow: hidden !important;
}

/* "or" rule between the password form and the Google button
   (listings/templates/listings/_google_button.html). A line with the word
   sitting in a gap, drawn with two flex-grown pseudo-elements rather than a
   background image, so it follows --line in both themes. */
.or-divider {
  display: flex;
  align-items: center;
  gap: 12px;
  color: var(--ink-faint);
  font-size: 0.8125rem;
  text-transform: lowercase;
}
.or-divider::before,
.or-divider::after {
  content: "";
  flex: 1 1 auto;
  height: 1px;
  background: var(--line);
}

/* A disabled input is still readable, not greyed into illegibility. The one
   place this appears is the email box on the Google signup form, where the
   value is the whole point of showing the field -- the member needs to see
   which address they are about to sign up with. */
.input:disabled {
  background: var(--bg-tint);
  color: var(--ink-soft);
  cursor: default;
}

/* ------------------------------------------------------- staff dashboard --- */
/* Only loaded pages behind is_staff use these, but they live here rather than
   in a second stylesheet: one file is the whole point of this project's
   front end, and a separate internal stylesheet would be the first thing to
   drift out of step with the tokens above. */

.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 10px;
}
.tile {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  text-decoration: none;
  color: inherit;
}
a.tile { transition: border-color var(--fast) var(--ease), box-shadow var(--fast) var(--ease); }
a.tile:hover { border-color: var(--primary); box-shadow: var(--shadow); }
.tile .n { font-size: 1.5rem; font-weight: 600; letter-spacing: -0.02em; line-height: 1.1; }
.tile .k { font-size: 0.8125rem; color: var(--ink-soft); }
/* A queue tile with something in it is tinted rather than badged: the whole
   tile is the signal, and at a glance "is there anything amber on this page"
   is the question an operator is actually asking. */
.tile-warn { background: var(--warn-bg); border-color: color-mix(in srgb, var(--warn) 28%, transparent); }
.tile-warn .n, .tile-warn .k { color: var(--warn); }

.delta { font-size: 0.75rem; font-weight: 560; margin-top: 2px; }
.delta-good { color: var(--ok); }
.delta-bad  { color: var(--err); }

/* The chart. Two bars per day in a flex row, sized by an inline height
   percentage the view computed -- no canvas, no library, no script. */
.chart {
  display: flex;
  align-items: flex-end;
  gap: 3px;
  height: 140px;
  padding: 10px 12px 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow-x: auto;
}
.chart-col { flex: 1 1 0; min-width: 14px; display: flex; flex-direction: column; height: 100%; }
.chart-col .bars { flex: 1; display: flex; align-items: flex-end; gap: 2px; }
.bar { flex: 1; min-height: 2px; border-radius: 2px 2px 0 0; display: block; }
.bar-posts   { background: var(--primary); }
.bar-signups { background: var(--accent); }
.chart-day {
  font-size: 0.625rem;
  color: var(--ink-faint);
  text-align: center;
  padding-top: 4px;
  font-variant-numeric: tabular-nums;
}
.key { display: inline-flex; align-items: center; gap: 5px; }
.swatch { width: 9px; height: 9px; border-radius: 2px; display: inline-block; }
.swatch-posts   { background: var(--primary); }
.swatch-signups { background: var(--accent); }

.panel-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 24px; }

/* One post awaiting a decision. Bordered as a card because the body is shown
   in full and the eye needs the boundary between one post and the next. */
.queue-item {
  padding: 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}
.queue-body {
  font-size: 0.9375rem;
  line-height: 1.65;
  color: var(--ink-soft);
  white-space: normal;
  overflow-wrap: anywhere;   /* an unbroken 6000-character "word" must not widen the page */
}
.queue-body p + p { margin-top: 10px; }
.queue-flags {
  padding: 10px 12px;
  background: var(--err-bg);
  border-left: 3px solid var(--err);
  border-radius: var(--radius-sm);
}
.queue-flags ul { margin: 6px 0 0; padding-left: 18px; }
.queue-flags li + li { margin-top: 4px; }
