/* Daggermen — base stylesheet.
 *
 * Design direction carried over from the concept render: near-black base,
 * coyote and olive, signal-orange used sparingly. Rugged and understated —
 * explicitly NOT a tactical gear shop.
 *
 * No @import and no remote fonts: the CSP forbids remote assets, and a member
 * on a bad connection should not wait on a font before reading anything.
 */

/* ---- Design tokens ----------------------------------------------------- *
 *
 * Taken from the Stand Easy design system (tokens/colors.css,
 * tokens/typography.css). These values are the source of truth — they were
 * chosen there, not here, and hand-tuning one of them in this file is how the
 * site drifts away from the system it is supposed to be following.
 *
 * The short names below (--bg, --ink, --line …) are kept as aliases because
 * every rule in this stylesheet already uses them. They now resolve to the
 * design system's values rather than my earlier approximations, so the whole
 * site picks up the real palette without a rewrite.
 */

:root {
  /* SAYS WHICH WORLD THIS IS to the browser itself, not just to our own
     rules. Without it a native select, a date picker, a scrollbar and the
     form controls the browser draws for us all render light on a dark page —
     which is the same class of mismatch as the one above, one layer further
     down. It follows the attribute, so the toggle moves it too. */
  color-scheme: dark;

  /* base palette */
  --ink-0:   #0B0C0B;   /* near-black base */
  --ink-1:   #171A16;   /* surface */
  --ink-2:   #1F231D;   /* raised surface */
  --hairline:#282C26;
  --bone:    #E8E6E0;   /* primary text on dark */
  --coyote:  #A8825C;
  --olive:   #4A5240;
  --signal:  #D2531F;   /* CTAs, focus and live states ONLY */
  --signal-hover: #E05F28;

  /* Gold — the brand accent, per docs/DEVELOPMENT-PLAN.md §1. Structural
     work only: headings, rules, icons, and which nav item you are on.
     NOT interchangeable with --signal, and the split is measured, not
     taste. On this background gold reads at 8.10:1 against orange's 4.66,
     so it is the better colour for anything that is text or a thin rule.
     Under a white button label it collapses to 2.42:1 and is unusable —
     which is exactly why the buttons stayed orange rather than the whole
     palette moving across. Put gold on a filled control and it will need
     a dark label; see .btn--primary before reaching for it. */
  --brand:       #C9A227;
  --brand-hover: #DCB63C;

  /* The mark itself, per docs/DEVELOPMENT-PLAN.md §1: silver, not the CTA
     accent — a dagger, not a button. #C7C9C4 is that section's "silver
     (alternate accent, used for wallet foil)" value, reused here rather than
     invented fresh so the mark and the merch stay the same metal.

     THE LIGHT THEME USES TITANIUM BLACK instead — see the [data-theme]
     block below. The concept sheet offers the mark in three finishes and
     the site uses two of them, one per theme, rather than tinting one
     finish until it is legible. The favicon keeps the silver in both,
     because its plate is always dark. */
  --mark-glyph:       #C7C9C4;
  --mark-glyph-hover: #E7E8E4;

  /* The map needs its own two, and they are not --surface-card and
     --surface-raised. Those two are a card on a page and sit about one step
     apart, which on a world map means the continents nearly vanish into the
     ocean — the reference the human supplied works precisely because land,
     sea and "somewhere with stories" are three obviously different things.
     So: a sea darker than any surface on the site, and a land well clear of
     it. --coyote is the third tone and is left to the rule that draws it. */
  --map-sea:  #0A0D10;
  --map-land: #333A33;

  /* semantic — dark, the default */
  --bg-page:        var(--ink-0);
  --surface-card:   var(--ink-1);
  --surface-raised: var(--ink-2);
  --border-hairline: var(--hairline);
  --border-strong:  #3A4036;
  --text-body:      var(--bone);
  --text-muted:     #8F948A;
  --text-faint:     #6B7065;
  --accent:         var(--signal);
  --accent-hover:   var(--signal-hover);
  --accent-fg:      #FFF3EC;
  --tag-fg:         var(--coyote);
  --tag-border:     #4E4232;
  --ok:             #7C8A5E;   /* verified / approved */
  /* Moved off #C9A227 when that became --brand: "under review" and "this is
     the brand" must not be the same colour. Shifted 10deg warmer and well
     down in saturation so the two are separable at a glance, not just by
     eyedropper. 6.48:1 here. */
  --warn:           #C08A3E;   /* under review */
  --link:           var(--coyote);
  --link-hover:     var(--bone);
  --focus-ring:     #D2531F66;

  /* aliases used throughout this stylesheet */
  --bg:       var(--bg-page);
  --surface:  var(--surface-card);
  --ink:      var(--text-body);
  --ink-soft: #C6C4BC;
  --muted:    var(--text-muted);
  --line:     var(--border-hairline);
  --line-lit: var(--border-strong);
  --danger:   #C2412D;

  /* type — system stacks only, no downloaded faces */
  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --font-mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
  --font-body: var(--font-sans);

  --display-weight: 800;
  --display-tracking: .02em;
  --display-xl: clamp(40px, 7vw, 84px);
  --display-l: 32px;
  --display-m: 22px;

  --label-size: 11px;
  --label-tracking: .14em;

  --body-size: 18px;
  --body-line: 1.65;
  --body-measure: 68ch;
  --small-size: 15px;
  --micro-size: 13px;

  --measure: 60rem;
  --radius: 2px;
}

/* On a wide monitor a 60rem column leaves the hero headline hugging the left
   third of the window with a great deal of photograph to the right of it,
   which reads as the page being off-centre even though it is not. Widening
   the container on large screens fills the space without turning body copy
   into a wall — the reading measure is capped separately, by --body-measure
   on .lede and the yarn body. */
@media (min-width: 78rem) {
  :root { --measure: 72rem; }
}
@media (min-width: 100rem) {
  :root { --measure: 82rem; }
}

/* The concept carries a light/dark toggle. The tokens for it are defined here
   so the palette is complete; the control itself is not built yet. */
[data-theme="light"] {
  color-scheme: light;

  --bg-page:        #EDEBE4;
  --surface-card:   #F5F3EC;
  --surface-raised: #FFFFFF;
  --border-hairline:#D4D1C6;
  --border-strong:  #B5B2A6;
  --text-body:      #1C1E1A;
  --text-muted:     #5C6157;
  /* Darkened from #8A8E83, which was 2.80:1 on this theme's cream. It carries
     real sentences — the Q&A sign-off among them — not just hairlines, and
     2.80 is below the 4.5 small text needs. #686B63 is 4.55. */
  --text-faint:     #686B63;
  /* And the same story again for coyote. #A8825C is 2.93:1 here and it
     carries every .eyebrow on the site, the footer's support link and the
     scope labels on a yarn — all of them small text. #816446 is 4.58 and is
     the same colour walked down, not a different one. See the note on
     --brand directly below: this theme has had to do this twice, which is
     why the raw palette values must not be used directly on a themed
     surface. */
  --coyote:         #816446;
  --accent:         #BC4413;
  --accent-hover:   #A53C10;
  --tag-fg:         #7A5A38;
  --tag-border:     #C9BCA9;
  --ok:             #5C6B3E;
  /* Same story as the mark's silver: #C9A227 is 2.03:1 on this theme's cream
     and unreadable, so the gold darkens rather than the brand changing hue.
     4.81:1 clears normal body text, which it has to — --brand carries
     .inline-link here, not just headings and rules. */
  --brand:          #7A6410;
  --brand-hover:    #5E4D0C;
  --warn:           #8A5A1E;   /* browner, to clear the darkened gold above */
  --link:           #7A5A38;
  --link-hover:     #1C1E1A;
  --focus-ring:     #BC441366;

  --ink-soft:       #3A3D36;
  --signal:         var(--accent);

  /* #C7C9C4 silver has ~1.4:1 contrast against this theme's cream page
     background — nearly invisible. Darkened to a steel/gunmetal tone that
     clears 5:1, still read as "the same metal" as the dark-theme silver,
     just the shaded side of it rather than the lit side. */
  /* TITANIUM BLACK, per the concept sheet's third finish — the human's
     call: silver on the dark theme, titanium on the light one, which is how
     the same mark is actually made in metal.

     #33383D rather than something nearer black, and the reason is the
     wordmark beside it. --text-body here is #1C1E1A, a WARM near-black; a
     cool near-black mark at #2C3034 sits at 1.26:1 against it and stops
     reading as metal at all — it just looks like more type. This is 1.42:1
     against the text and 9.92:1 against the page, so it is unmistakably a
     dark finish and still unmistakably not lettering. */
  --mark-glyph:       #33383D;
  --mark-glyph-hover: #1E2226;

  /* Same three tones, inverted: a pale sea, a land that reads as paper
     rather than as another page background, and coyote on top of both. */
  --map-sea:  #DCE0DE;
  --map-land: #B9BDB4;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  background: var(--bg);
  color: var(--ink);
  font: 400 var(--body-size)/var(--body-line) var(--font-body);
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
}

/* ---- Layout ------------------------------------------------------------ */

.wrap {
  width: 100%;
  max-width: var(--measure);
  margin: 0 auto;
  padding: 2rem 1.5rem;
}

.site-body { flex: 1; display: flex; flex-direction: column; }

/* The masthead carries its own column; main is full width so a page can
   reach the window edges. Padding is halved vertically because the column's
   default 2rem is tuned for body content, not a header bar. */
.masthead.wrap { padding-top: 1.5rem; padding-bottom: 1.5rem; }

/* ---- Masthead ---------------------------------------------------------- */

.masthead {
  /* Positioned so the menu panel can hang off IT rather than off the little
     button that opens it — anchored to the button, a 20rem panel starts
     wherever the word "Menu" happens to end and runs off the left of the
     screen. */
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}

/* The mark is a drawn blade plus the wordmark, locked up as one unit.
   See app/templates/_mark.html for why it is not the † glyph any more. */
.mark {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  color: var(--ink);
  text-decoration: none;
}

.mark__glyph {
  width: 1.7rem;
  height: 1.7rem;
  flex: none;             /* never let flex squash the blade out of proportion */
  color: var(--mark-glyph);   /* the paths fill with currentColor */
}

/* The grip wrap lines are cut in the page background, not the mark's own
   colour — they read as the fill missing there, not as a stroke drawn on
   top of it. var(--bg) is what makes that work in both themes; the favicon
   hardcodes the same idea since it has no stylesheet to read from. */
.mark__wrap { stroke: var(--bg); }

.mark__word {
  font-size: 1.25rem;
  font-weight: 700;
  letter-spacing: .2em;
  text-transform: uppercase;
  /* Letter-spacing is applied after the last letter too, so the wordmark sits
     visually off-centre in its own box and the lockup looks lopsided against
     anything to its right. Pull the phantom space back off. */
  margin-right: -.2em;
}

/* The blade is the only thing that moves, and only slightly. A logo that
   animates on hover reads as a startup; this should read as a door. */
.mark:hover .mark__glyph,
.mark:focus-visible .mark__glyph { color: var(--mark-glyph-hover); }

/* WRAPS. It did not, and that was the worst bug on the site: five controls
   at a 5.5rem minimum plus gaps is ~470px that could not break, so EVERY
   page scrolled sideways on EVERY phone in portrait — 228px of it on a
   390px handset. Clean from 667px up, which is why turning a phone
   landscape appeared to fix the site and why the fault survived so long.

   .masthead already wrapped, so the mark and the nav could stack; the nav's
   own contents could not, which is the half that mattered. */
.nav {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: .6rem;
}

/* Every control in the masthead is framed identically.
 *
 * A link, a submit button and a toggle are three different elements doing the
 * same job up here, and left to their defaults they look like three different
 * kinds of thing — one framed, two bare. Same box for all of them. */
.nav a,
.nav .linklike,
.theme-toggle {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: var(--label-size);
  font-weight: 400;
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  line-height: 1.2;
  color: var(--text-muted);
  background: transparent;
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius);
  padding: .45rem .7rem;
  /* Sized for the longest label so the row never reflows — the toggle alone
     would otherwise resize between LIGHT and DARK on every click. */
  min-width: 5.5rem;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
}

.nav a:hover, .nav a:focus-visible,
.nav .linklike:hover, .nav .linklike:focus-visible,
.theme-toggle:hover, .theme-toggle:focus-visible {
  color: var(--text-body);
  border-color: var(--border-strong);
}

/* On a phone the masthead is the whole width, so the controls share it out
   evenly instead of wrapping into a ragged stack with a hole on the right.
   Reads as a deliberate row of controls rather than as a menu that ran out
   of room.

   min-width drops but does not go to zero: it is what stops the toggle
   resizing between LIGHT and DARK on every press, and 4rem still holds both.
   A long handle is allowed to ellipsis rather than force the row wider —
   nobody needs to read their own handle off the masthead. */
@media (max-width: 32rem) {
  .masthead { gap: .75rem; }
  .nav { justify-content: flex-start; }

  .nav a,
  .nav .linklike,
  .theme-toggle {
    min-width: 4rem;
    flex: 1 1 auto;
    /* Vertical padding is set for the TARGET, not the label. These came out
       at 30px measured on a handset; a finger pad is about 45px across, and
       anything under ~44 is a control you hit on the second try. That miss
       rate is most of what makes a site feel cheap on a phone, and it costs
       nothing to fix. */
    padding: .85rem .5rem;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}

/* ---- Type -------------------------------------------------------------- */

.eyebrow {
  font-family: var(--font-mono);
  font-size: .7rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--coyote);
}
.eyebrow .sep { color: var(--line-lit); margin: 0 .55em; }

/* An eyebrow that is a link. It inherits the label's colour rather than
   taking the site's link colour — at this size a second colour reads as a
   mistake — so the underline is the whole affordance, and it is offset far
   enough not to collide with the tracking. */
.eyebrow__link {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: .35em;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--line-lit);
}
.eyebrow__link:hover,
.eyebrow__link:focus-visible {
  color: var(--brand);
  text-decoration-color: var(--brand);
}

h1 {
  font-size: var(--display-xl);
  line-height: .95;
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  text-transform: uppercase;
  max-width: 14ch;
}

h2 {
  font-size: 1.4rem;
  font-weight: 700;
  letter-spacing: -.01em;
}

.lede { max-width: 46ch; color: var(--ink-soft); font-size: 1.06rem; }

a { color: var(--ink); }

/* ---- Components -------------------------------------------------------- */

.badge {
  display: inline-flex;
  align-items: center;
  gap: .7rem;
  font-family: var(--font-mono);
  font-size: .78rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  border: 1px solid var(--line);
  border-left: 3px solid var(--brand);
  padding: .85rem 1.15rem;
  background: var(--surface);
  align-self: flex-start;
}
.badge--verified { border-left-color: var(--olive); }
.badge--warning  { border-left-color: var(--danger); }

.btn {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: .76rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  padding: .85rem 1.4rem;
  border: 1px solid var(--line-lit);
  border-radius: var(--radius);
  background: transparent;
  color: var(--ink);
  text-decoration: none;
  cursor: pointer;
}
.btn:hover, .btn:focus-visible { border-color: var(--muted); }
.btn--primary {
  background: var(--signal);
  border-color: var(--signal);
  color: #fff;
  font-weight: 700;
}
.btn--primary:hover, .btn--primary:focus-visible { filter: brightness(1.08); }

/* Outlined rather than filled. Declining someone is not the button the eye
   should land on first. */
.btn--danger { border-color: var(--danger); color: #F08A6C; }
.btn--danger:hover, .btn--danger:focus-visible { background: var(--danger); color: #fff; }

.inline-link {
  color: var(--ink);
  text-decoration: none;
  border-bottom: 1px solid var(--brand);
  padding-bottom: 1px;
}
.inline-link:hover, .inline-link:focus-visible { color: var(--brand); }

/* A button that has to live inside a form (logout is a POST) but should read
   as one of the nav links beside it. */
.nav-form { display: inline; }
.linklike {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: var(--muted);
  cursor: pointer;
}
.linklike:hover, .linklike:focus-visible { color: var(--ink); }

/* ---- Home -------------------------------------------------------------- */

.home {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 2.5rem 0 3rem;
}
.home .eyebrow { margin-bottom: 1.75rem; }
.home .lede    { margin-top: 1.75rem; }
.home .badge   { margin-top: 2.5rem; }
.home .contact { margin-top: 2.25rem; font-size: .95rem; color: var(--muted); }

.home__actions { margin-top: 2.5rem; display: flex; flex-wrap: wrap; gap: .8rem; }

/* --------------------------------------------------------------------------
   "Watch the promo", under the hero buttons.

   TYPE, NOT A BUTTON, AND THAT IS THE POINT. It sits below a filled orange
   primary and an outlined secondary, and it must not read as a third of the
   same thing at any width — so it has no frame, no uppercase, and the body
   font. Nothing here changes at a breakpoint because there is nothing that
   needs to: one short line is already the smallest this can be, which is why
   it needed no icon-only variant to survive a phone.

   NO RUNNING TIME BESIDE IT ANY MORE. It was there so somebody knew what
   they were agreeing to before spending the data, which is a fair argument
   and lost to a better one: on the single link whose job is to make somebody
   curious, the length is the least interesting fact available, and nothing
   downloads before play regardless. The .home__watch-meta rule went with it
   rather than being left behind for the next person to wonder about.
   -------------------------------------------------------------------------- */
.home__watch {
  margin-top: 1.1rem;
  display: flex;
  align-items: center;
  gap: .6rem;
  flex-wrap: wrap;
}
.home__watch-link {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  color: var(--bone);
  text-decoration: none;
  border-bottom: 1px solid var(--hairline);
  padding-bottom: 1px;
}
.home__watch-link:hover,
.home__watch-link:focus-visible { border-bottom-color: var(--brand); }
.home__watch-glyph { width: 1.15rem; height: 1.15rem; color: var(--brand); flex: none; }

/* --------------------------------------------------------------------------
   The promo page.

   THE FRAME IS RESERVED BEFORE THE POSTER LOADS. aspect-ratio on the element
   itself, so the page does not jump when the image arrives and again when
   somebody presses play — a 1080-square video dropping into a collapsed box
   shoves everything below it down the screen, which on a phone means the
   paragraph somebody was reading moves while they read it.

   Square is why this is the cut that goes on the site: it fills the column
   at any width without letterboxing, where the wide cut would band the top
   and bottom on a phone and the vertical one would run off the bottom of a
   desktop screen.
   -------------------------------------------------------------------------- */
.promo { margin: 2rem 0 1rem; }
.promo__video {
  display: block;
  width: 100%;
  max-width: 46rem;
  aspect-ratio: 1 / 1;
  height: auto;
  background: var(--ink-1);
  border: 1px solid var(--hairline);
  border-radius: 2px;
}
/* The sign-off on /about. Set apart from the paragraph above it so it reads
   as a signature rather than another sentence, and in the mono face the rest
   of the site uses for anything that is a label rather than prose.

   HE SIGNS IT "Daggerman", SINGULAR, AND THAT IS THE POINT of the page:
   somebody who has just read a man's own account of why he built this is
   looking at a handle, exactly as every member here does. */
/* The trader line, when there is one. Small and last: it is there because a
   site taking subscriptions needs it, not because a reader came for it. */
.about__legal {
  margin-top: 2rem;
  font-size: var(--small-size);
  color: var(--muted);
}

.about__signature {
  /* Overrides the inherited .thename__body paragraph spacing: a signature
     sits closer to what it signs than two paragraphs sit to each other. */
  margin-top: 1.6rem;
  font-family: var(--font-mono);
  font-size: .82rem;
  letter-spacing: .12em;
  color: var(--brand);
}

/* The call to action under the film. Closer to the video than a new section
   would be, because it is answering the last shot rather than starting a new
   thought. */
.promo__after { margin-top: 1.2rem; }

.promo__note {
  margin-top: .7rem;
  max-width: 46rem;
  font-family: var(--font-mono);
  font-size: .74rem;
  letter-spacing: .08em;
  color: var(--muted);
}

.home__latest { padding-bottom: 3rem; }
.home__section {
  font-family: var(--font-mono);
  font-size: .72rem;
  font-weight: 400;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--coyote);
  margin-bottom: 1.25rem;
}
.home__more { margin-top: 1.5rem; font-size: .95rem; }

/* The four-step explainer, shown only while there is nothing published this
   visitor can see. An empty feed reads as a broken site. */
.steps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 1.75rem 2rem;
  border-top: 1px solid var(--line);
  padding-top: 1.75rem;
}
.step__n {
  font-family: var(--font-mono);
  font-size: .7rem;
  letter-spacing: .18em;
  color: var(--brand);
  margin-bottom: .5rem;
}
.step__t { font-weight: 700; margin-bottom: .35rem; }
.step__d { font-size: .92rem; color: var(--muted); }

@media (max-width: 480px) {
  .home { padding: 1.5rem 0 2rem; }
  h1 { max-width: 100%; }
}

/* ---- Banner ------------------------------------------------------------ */

/* A cinematic strip above the headline, cycling through the banner frames.
 *
 * aspect-ratio rather than a fixed height, so the box is the right size before
 * the image decodes and the headline below it never jumps. The frames are
 * stacked and cross-faded by app/static/js/banner.js — which does nothing
 * under prefers-reduced-motion, so the CSS has to leave the first frame
 * visible on its own. */

/* ---- Full-bleed hero --------------------------------------------------- */

/* The photograph IS the background and the headline sits on it.
 *
 * No negative margins and no vw. `main` is full width now (see base.html), so
 * the hero is an ordinary block that fills it. The previous version broke out
 * of the column with `margin-left: calc(50% - 50vw); width: 100vw`, which put
 * it 8px wider than the document and 8px left of everything centred above it,
 * because vw counts the scrollbar and the centred column does not. */
.hero {
  position: relative;
  width: 100%;
  min-height: min(78vh, 40rem);
  display: flex;
  align-items: center;
  overflow: hidden;
  background: #07080A;
}

.hero__frames { position: absolute; inset: 0; }

/* The hero needs a far heavier scrim than the contained strip: body copy sits
   directly on the photograph, and the frames rotate — so it has to hold up
   over whichever one is showing, not just the darkest. Weighted to the left,
   where the text is, leaving the subject on the right legible. */
.hero .banner__scrim {
  background:
    linear-gradient(90deg,
      rgba(11, 12, 11, .94) 0%,
      rgba(11, 12, 11, .86) 30%,
      rgba(11, 12, 11, .55) 60%,
      rgba(11, 12, 11, .30) 100%),
    linear-gradient(180deg,
      rgba(11, 12, 11, .55) 0%,
      rgba(11, 12, 11, 0) 35%,
      rgba(11, 12, 11, .75) 100%);
}

@media (max-width: 700px) {
  /* No room to dodge the subject on a phone — darken the lot. */
  .hero .banner__scrim {
    background: linear-gradient(180deg,
      rgba(11, 12, 11, .82) 0%,
      rgba(11, 12, 11, .72) 50%,
      rgba(11, 12, 11, .88) 100%);
  }
}

.hero__content {
  position: relative;      /* above the frames and the scrim */
  width: 100%;
  max-width: var(--measure);
  margin: 0 auto;
  padding: 4rem 1.5rem;
}

/* The hero sits on a dark photograph in BOTH themes, so its text must NOT
   follow the theme. Without this the light theme paints a dark headline onto
   a dark scrim and the whole hero disappears — which it duly did.
   Re-declaring the tokens here rather than hard-coding colours, so anything
   inside the hero that uses them inherits the right ones. */
.hero__content {
  --text-body:  var(--bone);
  --text-muted: #8F948A;
  --ink:        var(--bone);
  --ink-soft:   #C6C4BC;
  --muted:      #8F948A;
  --line-lit:   #3A4036;
  color: var(--bone);
}

.hero__content .eyebrow { margin-bottom: 1.5rem; }
.hero__content .lede    { margin-top: 1.5rem; }

/* Where the name comes from, on the hero.
 *
 * Sits between the buttons and the photo caption, held to one measure so it
 * breaks over two lines rather than running the width of a desktop hero. The
 * gold rule on the left is the same device the site uses for a quoted line —
 * it marks this as an aside about the site rather than another claim in the
 * pitch. */
.hero__origin {
  margin-top: 2rem;
  padding-left: .9rem;
  border-left: 2px solid var(--brand);
  max-width: 46ch;
  font-size: .95rem;
  line-height: 1.6;
  color: var(--muted);
}
.hero__origin a { color: inherit; text-decoration: none; }
.hero__origin a:hover,
.hero__origin a:focus-visible { color: var(--bone); }
.hero__origin b { color: var(--brand); font-weight: 700; }

/* ---- The name ---------------------------------------------------------- */
/* Set like a page of writing rather than a page of interface: one column, no
   cards, no panel. It is the site's own story and it should read the way the
   yarns do. */

.thename { max-width: var(--body-measure); padding: 3rem 0 1rem; }

.thename__eyebrow {
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--muted);
}

.thename__title {
  margin-top: .8rem;
  font-size: var(--display-l);
  line-height: 1.05;
  letter-spacing: -.01em;
}

.thename__lede {
  margin-top: .9rem;
  font-size: 1.2rem;
  color: var(--brand);
}

.thename__body { margin-top: 2.5rem; }
.thename__body p { margin-bottom: 1.4rem; font-size: 1.05rem; line-height: 1.75; color: var(--ink-soft); }

/* The two lines the page is actually for. Bigger and in the body colour, so
   they land as statements rather than as more paragraph. */
.thename__hit {
  font-size: 1.3rem !important;
  line-height: 1.5 !important;
  color: var(--text-body) !important;
}

/* The honest caveat. Set back and quieter than the rest — it is a
   qualification, and dressing it up as a headline would be its own kind of
   dishonesty. */
.thename__aside {
  padding-left: .9rem;
  border-left: 2px solid var(--border-strong);
  font-size: .95rem !important;
  color: var(--muted) !important;
}

.thename__heading {
  margin: 2.75rem 0 1.4rem;
  font-size: var(--display-m);
  line-height: 1.2;
}

.thename .home__actions { margin-top: 2.5rem; }

.thename__source {
  margin-top: 3rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--line);
  font-size: var(--small-size);
  color: var(--text-muted);
}

@media (max-width: 32rem) {
  .thename { padding-top: 2rem; }
  .thename__hit { font-size: 1.15rem !important; }
}

@media (max-width: 560px) {
  .hero { min-height: 0; }
  .hero__content { padding: 3rem 1.5rem; }
}

/* ---- Contained banner strip -------------------------------------------- */
/* Kept for anywhere that wants the frames without the full-bleed treatment. */

.banner {
  position: relative;
  aspect-ratio: 1916 / 821;
  min-height: 11rem;
  max-height: 26rem;
  margin-bottom: 3rem;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  /* Shows for the moment before the first frame decodes. Without it the strip
     is a bright hole in a near-black page. */
  background: #07080A;
}

.banner__frame {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 1.4s ease-in-out;
}
.banner__frame.is-live { opacity: 1; }

.banner__frame img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Darkens the top and bottom edges so the strip reads as part of the page
   rather than a photograph pasted onto it. */
.banner__scrim {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(
    180deg,
    rgba(11, 12, 11, .45) 0%,
    rgba(11, 12, 11, 0) 30%,
    rgba(11, 12, 11, 0) 55%,
    rgba(11, 12, 11, .85) 100%
  );
}

@media (prefers-reduced-motion: reduce) {
  .banner__frame { transition: none; }
}

@media (max-width: 480px) {
  .banner { margin-bottom: 2rem; }
}

/* ---- Panels and forms -------------------------------------------------- */

.panel {
  max-width: 34rem;
  padding: 3.5rem 0 3rem;
}
.panel h2 { margin-bottom: 1rem; }
.panel .lede { margin-bottom: 1.75rem; }
.panel .badge { margin-bottom: 1.5rem; }

.form { display: flex; flex-direction: column; gap: 1.5rem; margin-top: 1.75rem; }

.field { display: flex; flex-direction: column; gap: .4rem; }
fieldset.field { border: none; padding: 0; margin: 0; }
fieldset.field legend.field__label { padding: 0; }
.field__checkboxes { display: flex; flex-direction: column; gap: .5rem; margin-top: .3rem; }

.field__label {
  font-family: var(--font-mono);
  font-size: .72rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--coyote);
}

.field__hint { font-size: .85rem; color: var(--muted); }

/* For the small number of places where a break mid-token reads as damage
   rather than as wrapping — a date range, a phone number. */
.nowrap { white-space: nowrap; }

/* Every other field on the registration form is required, so the one that is
   not has to say so where the eye already is — on the label, not three lines
   down in the hint. */
.field__optional {
  margin-left: .5rem;
  font-size: var(--micro-size);
  letter-spacing: var(--label-tracking);
  color: var(--text-faint);
}

/* Warnings against a specific box, not buried in a policy page. The first
   free-text field on this site sets the tone for every one after it. */
.field__hint--warning {
  color: var(--ink-soft);
  border-left: 2px solid var(--coyote);
  padding-left: .8rem;
}

.field input,
.field select,
.field textarea {
  font: inherit;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line-lit);
  border-radius: var(--radius);
  padding: .8rem .9rem;
  width: 100%;
}
.field textarea { resize: vertical; min-height: 6rem; line-height: 1.6; }

.field input:focus-visible,
.field select:focus-visible,
.field textarea:focus-visible { border-color: var(--signal); }

/* Two year boxes reading as one control. */
.field-pair { display: flex; align-items: center; gap: .75rem; }
.field-pair input { max-width: 7rem; }
.field-pair__sep { color: var(--muted); font-size: .9rem; }

/* Errors are announced in red AND in words. Colour alone fails for the
   colour-blind, and this audience skews older. */
.field__error, .form-error { color: #F08A6C; font-size: .88rem; }

.form-error {
  border-left: 3px solid var(--danger);
  background: var(--surface);
  padding: .85rem 1.1rem;
  margin-bottom: 1.5rem;
}

.form .btn { align-self: flex-start; }

.form-aside { margin-top: 2rem; font-size: .92rem; color: var(--muted); }

.detail {
  margin-top: 2rem;
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: .5rem 1.5rem;
  font-size: .92rem;
}
.detail dt {
  font-family: var(--font-mono);
  font-size: .7rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted);
  align-self: center;
}
.detail dd { color: var(--ink-soft); }

/* STACKED ON A PHONE. `max-content 1fr` is right at a reading width and
   wrong at 358px: "Unit badge" is a wide label, and what is left for the
   value is a ribbon four words across. Three lines of hint text down a 9rem
   column is unreadable, and this list carries the hints on /me — the page
   that explains what a member's own account can do. Label on its own line,
   value under it, whole width. */
@media (max-width: 34rem) {
  .detail {
    grid-template-columns: 1fr;
    gap: 0;
  }
  .detail dt { margin-top: 1.1rem; }
  .detail dt:first-of-type { margin-top: 0; }
  .detail dd { margin-top: .25rem; }
}

/* ---- Yarns ------------------------------------------------------------- */

.panel--wide { max-width: 46rem; }
/* A ledger of five columns needs more than a reading measure. 34rem wraps
   every heading onto three lines and turns a scannable table into a wall. */
.panel--ledger { max-width: 60rem; }

.feed { padding: 3rem 0; }
.feed__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 2.5rem;
}

.card {
  display: flex;
  gap: 1.25rem;
  padding: 1.25rem 0;
  border-top: 1px solid var(--line);
}
.card:last-child { border-bottom: 1px solid var(--line); }

.card__cover {
  flex: none;
  width: 8rem;
  height: 6rem;
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--surface);
}
.card__cover img { width: 100%; height: 100%; object-fit: cover; display: block; }

.card__body h3 { font-size: 1.15rem; font-weight: 700; }
.card__body h3 a { color: var(--ink); text-decoration: none; }
.card__body h3 a:hover, .card__body h3 a:focus-visible { color: var(--brand); }

.card__meta {
  margin-top: .35rem;
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
}
.card__meta .sep { color: var(--line-lit); margin: 0 .1em; }
.card__scope { color: var(--coyote); }

.card__excerpt { margin-top: .6rem; color: var(--ink-soft); font-size: .95rem; }

@media (max-width: 560px) {
  .card { flex-direction: column; }
  .card__cover { width: 100%; height: 9rem; }
}

/* ---- One yarn ---------------------------------------------------------- */

.yarn { max-width: 42rem; padding: 3rem 0; }
.yarn__title {
  font-size: clamp(1.7rem, 4.5vw, 2.6rem);
  line-height: 1.1;
  font-weight: 800;
  letter-spacing: -.01em;
}
.yarn__meta {
  margin-top: .9rem;
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted);
}
.yarn__meta .sep { color: var(--line-lit); }
.yarn__scope { color: var(--coyote); }

/* app.markup renders a fixed, small set of tags (p, ul, ol, li, strong, em,
   br) — see app/markup.py. No pre-wrap needed: paragraph breaks are real <p>
   elements now, not whitespace the browser is asked to preserve. */
.yarn__body {
  margin-top: 2rem;
  font-size: 1.05rem;
  line-height: 1.75;
  color: var(--ink-soft);
}
.yarn__body p { margin: 0 0 1.1em; }
.yarn__body p:last-child { margin-bottom: 0; }
.yarn__body ul, .yarn__body ol { margin: 0 0 1.1em; padding-left: 1.4em; }
.yarn__body li { margin-bottom: .35em; }

.yarn__tags {
  margin-top: 1rem;
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
}
/* The chip. Shared with a Standing By listing's badges, which are the same
   thing doing the same job — a small, quiet label — and had no business
   growing a second look. */
.yarn__tags .tag,
.sb-listing__badges .tag {
  font-family: var(--font-mono);
  font-size: .66rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--coyote);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: .25rem .7rem;
}
.yarn__warning {
  margin-top: 1rem;
  font-size: .85rem;
  font-weight: 600;
  color: var(--danger);
}

.yarn__photos { margin-top: 2.5rem; display: grid; gap: 1.25rem; }
.shot img {
  width: 100%;
  height: auto;
  display: block;
  border-radius: var(--radius);
  background: var(--surface);
}
.shot figcaption { margin-top: .5rem; font-size: .85rem; color: var(--muted); }

.yarn__actions { margin-top: 3rem; padding-top: 2rem; border-top: 1px solid var(--line); }
.yarn__actions .field__hint { margin-top: .75rem; }

/* The OPSEC block. Loud on purpose — this is the one piece of copy on the
   site whose absence causes real-world harm, and it sits against the box
   rather than in a policy page nobody opens. */
.opsec {
  margin: 1.5rem 0 2rem;
  padding: 1.15rem 1.35rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 3px solid var(--danger);
  border-radius: var(--radius);
}
.opsec__title {
  font-family: var(--font-mono);
  font-size: .7rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: #F08A6C;
  margin-bottom: .7rem;
}
.opsec ul { margin: 0; padding-left: 1.1rem; }
.opsec li { font-size: .92rem; color: var(--ink-soft); margin-bottom: .4rem; }
.opsec li:last-child { margin-bottom: 0; }

.field input[type="file"] { padding: .6rem; font-size: .9rem; }

/* ---- Admin queue ------------------------------------------------------- */

.admin { padding: 3rem 0; }
.admin > .lede { margin-bottom: 2rem; }
.admin__section { margin-top: 3.5rem; margin-bottom: 1rem; }
.admin .badge, .admin .form-error { margin-bottom: 2rem; }

.empty { color: var(--muted); padding: 2rem 0; }

.admin-nav {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  margin-bottom: 2rem;
  padding-bottom: 1.25rem;
  border-bottom: 1px solid var(--line);
}
.admin-nav a {
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--text-muted);
  text-decoration: none;
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius);
  padding: .45rem .8rem;
}
.admin-nav a:hover, .admin-nav a:focus-visible {
  color: var(--text-body);
  border-color: var(--border-strong);
}

.review__check { margin-top: .85rem; font-size: var(--small-size); color: var(--ink-soft); }
.review__check input { margin-right: .45rem; }

.yarn__report {
  margin-top: 2.5rem;
  font-size: var(--small-size);
  color: var(--text-muted);
}

.ledger__decision--suspended { color: var(--warn); }
.ledger__decision--removed,
.ledger__decision--upheld    { color: #F08A6C; }
.ledger__decision--active    { color: var(--ok); }
.ledger__decision--open      { color: var(--warn); }
.ledger__decision--dismissed { color: var(--text-muted); }

/* One card per person waiting. Wide, because the notes field is the thing the
   decision actually turns on and it should not be read through a slot. */
.review {
  border: 1px solid var(--line);
  border-left: 3px solid var(--coyote);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 1.5rem;
  margin-bottom: 1.5rem;
}

.review__head { display: flex; flex-wrap: wrap; align-items: baseline; gap: .5rem 1rem; }
.review__head h3 { font-size: 1.2rem; letter-spacing: .02em; }

.review__meta {
  font-family: var(--font-mono);
  font-size: .7rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted);
}
.review__flag { color: var(--coyote); font-weight: 400; }

.review .detail { margin-top: 1.25rem; }

.review__notes {
  margin-top: 1.25rem;
  padding: 1rem 1.15rem;
  background: var(--bg);
  border-left: 2px solid var(--line-lit);
  color: var(--ink-soft);
  white-space: pre-wrap;  /* they typed paragraphs; show paragraphs */
}

.review__prior {
  margin-top: 1rem;
  font-size: .88rem;
  color: var(--muted);
}
.review__prior-label {
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--coyote);
  margin-right: .5rem;
}

.review__decide { margin-top: 1.5rem; }
.review__decide textarea {
  font: inherit;
  color: var(--ink);
  background: var(--bg);
  border: 1px solid var(--line-lit);
  border-radius: var(--radius);
  padding: .7rem .85rem;
  width: 100%;
  margin-top: .5rem;
  resize: vertical;
}
.review__decide textarea:focus-visible { border-color: var(--signal); }

.review__actions { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: 1rem; }

.unverified { color: var(--muted); font-style: italic; }

/* ---- Ledger ------------------------------------------------------------ */

.ledger {
  width: 100%;
  border-collapse: collapse;
  font-size: .9rem;
}
.ledger th, .ledger td {
  text-align: left;
  padding: .6rem .8rem;
  border-bottom: 1px solid var(--line);
}
.ledger th {
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 400;
}
.ledger td { color: var(--ink-soft); }

/* A ledger is columns of facts and there is no honest way to reflow one onto
   a phone — dropping columns hides the fact somebody came to check. So it
   scrolls sideways inside its own box instead, which keeps the PAGE from
   scrolling sideways. That distinction is the whole rule: wide content is
   allowed, a document wider than the window is not.

   All four admin ledgers get this, not only the newest — approvals, members
   and the member record had the same overflow and nobody had measured them
   on a phone. */
@media (max-width: 48rem) {
  .ledger {
    display: block;
    overflow-x: auto;
    white-space: nowrap;
    -webkit-overflow-scrolling: touch;
  }
}
.ledger__decision { font-family: var(--font-mono); font-size: .78rem; }
.ledger__decision--approved  { color: var(--coyote); }
.ledger__decision--rejected  { color: #F08A6C; }
.ledger__decision--more_info { color: var(--muted); }

/* The theme toggle is styled with the rest of the masthead controls, up in
   the Masthead section — it is one of them, not a special case. */

/* ---- Service marks ----------------------------------------------------- */

.svc { width: 1.5rem; height: 1.5rem; display: block; }

/* Column gap tightened from 2.25rem when First Responders made this ten
   items. Measured rather than eyeballed: at 2.25rem the row needs 1179px
   against the 1104px this column is ever given (--measure caps, so a wider
   monitor does not help), which wrapped Lest We Forget onto a line of its
   own. 1.5rem brings it to 1071px and the row holds together. Narrower
   viewports still wrap, which is fine — an orphan on the widest layout was
   the part that read as a mistake. */
.branches {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
  margin: 0;
  padding: 0;
}

.branch {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .5rem;
  color: var(--tag-fg);
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
}
/* The glyph carries the colour; the word underneath stays quiet. */
.branch span { color: var(--text-muted); }

/* ---- Legal ------------------------------------------------------------- */

.legal { max-width: var(--body-measure); padding: 3rem 0; }
.legal h1 { font-size: var(--display-l); line-height: 1.15; letter-spacing: -.01em; }
.legal h2 {
  margin-top: 2.5rem;
  margin-bottom: .75rem;
  font-size: 1.1rem;
  letter-spacing: 0;
}
.legal p, .legal li { color: var(--ink-soft); font-size: var(--small-size); }
.legal p { margin-bottom: .9rem; }
.legal ul { margin: 0 0 1rem 1.1rem; }
.legal li { margin-bottom: .45rem; }
.legal code {
  font-family: var(--font-mono);
  font-size: .85em;
  color: var(--coyote);
}
.legal__version {
  margin-top: .5rem;
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--text-muted);
}
.legal .lede { margin: 1.5rem 0 2rem; }

/* Deliberately not a one-line tickbox. The clause it agrees to assigns
   ownership of everything they post, and it should read like something. */
.field--check { margin-top: .5rem; }
.check {
  display: flex;
  align-items: flex-start;
  gap: .7rem;
  font-size: var(--small-size);
  color: var(--ink-soft);
  cursor: pointer;
}
.check input {
  flex: none;
  width: 1.1rem;
  height: 1.1rem;
  margin-top: .15rem;
  accent-color: var(--signal);
}

/* ---- Member profile ---------------------------------------------------- */
/* Meant to feel earned rather than decorated. The weight comes from scale
   and restraint — a big flag, the mark at size, display type — not from
   ornament. CLAUDE.md rules out the stencil-and-camo register, and this
   audience reads that as costume anyway. */

/* TWO COLUMNS, and the second one is the point of this whole block. The
   page was a 68ch measure against half a screen of nothing, which is what
   made it read as an admin form: a member's own page had no presence on it
   anywhere. The reading column keeps its measure exactly as it was — that
   number is about legibility and does not move — and the space beside it
   becomes the rail.

   72rem, not 100%: the rail has to sit BESIDE the text, close enough to
   read as one page. Let the grid run to the full width of a 27" monitor and
   the two columns end up a hand-span apart with a canyon down the middle,
   which is a worse answer than the empty space it replaced. */
.profile {
  max-width: 72rem;
  padding: 2.5rem 0 3rem;
  display: grid;
  grid-template-columns: minmax(0, var(--body-measure)) minmax(0, 1fr);
  gap: 0 3.5rem;
  align-items: start;
}
.profile__main { min-width: 0; }

/* ---- The rail ---------------------------------------------------------- */

.profile__rail {
  position: sticky;
  /* Clear of the sticky header. It scrolls with a long list of yarns rather
     than sliding away — the mark and the member's number are the two things
     that should still be on screen at the bottom of the page. */
  top: 5.5rem;
  display: grid;
  justify-items: center;
  gap: 1.4rem;
  padding-top: 1rem;
  text-align: center;
}

/* THE MARK, AT SIZE. Standing on the page, not on a card: .mark__wrap cuts
   the grip rings in var(--bg), so a surface behind it turns the coil into
   four visible scratches of the wrong colour.

   Full strength rather than a watermark. A 13% wash is what the flag on the
   hero does — that one sits BEHIND text and has to. This one has the column
   to itself, and the ask was to see the dagger from the concept sheet, not
   to hint at it. */
.profile__dagger .mark__glyph {
  width: min(15rem, 100%);
  height: auto;
  aspect-ratio: 1;
}

/* THE BADGE, WHERE THE MARK WOULD BE. Its plate is always dark, in both
   themes: media.py composites transparency onto the dark page colour before
   the JPEG is written, so a cut-out badge arrives with a near-black ground
   already baked in. Framed deliberately rather than left to look like a
   stray rectangle on the light theme — the favicon keeps its silver for the
   same reason, its plate being always dark too. */
.profile__crest { margin: 0; display: grid; justify-items: center; gap: .7rem; }
.profile__crest-img {
  width: min(13rem, 100%);
  height: auto;
  aspect-ratio: 1;
  object-fit: contain;
  background: #0B0C0B;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: .9rem;
}
.profile__crest-note {
  display: block;
  margin-top: .45rem;
  font-family: var(--font-body, inherit);
  font-size: var(--small-size);
  letter-spacing: normal;
  text-transform: none;
  color: var(--text-muted);
  line-height: 1.55;
}
.badge-mine__caption {
  margin-top: .35rem;
  font-size: var(--small-size);
  line-height: 1.6;
  color: var(--text-muted);
}

.profile__crest-label {
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted);
  max-width: 15rem;
  line-height: 1.5;
}

/* The membership card in the rail. NAMED .tier-card, NOT .membership:
   that class already belongs to the /membership page's container, and a
   second definition of it put a border and a background on that page's
   whole body. Not gold, and not styled like the founding number above it:
   one of those was earned by turning up and the other was bought, and a
   paid marker dressed as an earned one teaches people to read the earned
   ones as bought. */
.tier-card {
  width: 100%;
  max-width: 15rem;
  padding: .9rem 1rem;
  background: var(--surface-card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  text-align: left;
}
.tier-card__label {
  margin: 0;
  font-family: var(--font-mono);
  font-size: .62rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--muted);
}
.tier-card__tier {
  margin: .2rem 0 0;
  font-size: 1.15rem;
  font-weight: 600;
  color: var(--ink);
}
.tier-card__tier--free { color: var(--ink-soft); font-weight: 500; }
.tier-card__note {
  margin: .35rem 0 0;
  font-size: var(--micro-size);
  line-height: 1.5;
  color: var(--muted);
}
.tier-card__orders {
  margin: .7rem 0 0;
  padding-top: .7rem;
  border-top: 1px solid var(--line);
  font-size: var(--small-size);
}

.profile__number {
  display: grid;
  gap: .15rem;
  margin: 0;
}
.profile__number-label {
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--brand);
}
/* The one fact on this page that can never be earned again. Given the size
   to match. */
.profile__number-n {
  font-size: 2.6rem;
  line-height: 1;
  font-weight: 700;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.profile__number-of {
  font-size: var(--micro-size);
  line-height: 1.5;
  color: var(--muted);
  max-width: 15rem;
}

/* The short account. Rules between the rows rather than a boxed table —
   a bordered grid of label/value pairs is the exact thing that reads as an
   admin screen, which is what this page was being marked down for. */
.record {
  width: 100%;
  max-width: 15rem;
  margin: 0;
  display: grid;
  gap: 0;
}
.record__row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  padding: .55rem 0;
  border-top: 1px solid var(--line);
}
.record__row:last-child { border-bottom: 1px solid var(--line); }
.record dt {
  font-family: var(--font-mono);
  font-size: .66rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted);
}
.record dd {
  margin: 0;
  font-size: 1.15rem;
  font-weight: 600;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
/* The countries figure goes to the map. Underlined it read as a defect —
   a single digit with a rule under it looks like a typo, not a link — so
   the affordance waits for the hover. */
.record dd a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid transparent;
}
.record dd a:hover,
.record dd a:focus-visible { border-bottom-color: var(--brand); }

.profile__admin {
  margin: 0;
  font-size: var(--small-size);
  color: var(--muted);
}

/* ONE COLUMN, and the rail goes underneath. Below this width the reading
   measure is the whole screen and there is no space beside it to fill —
   which is the only reason the rail exists. */
@media (max-width: 64rem) {
  .profile {
    max-width: var(--body-measure);
    grid-template-columns: minmax(0, 1fr);
    gap: 2.5rem;
  }
  .profile__rail {
    position: static;
    padding-top: 0;
  }
  /* Smaller down here. Full size under the text it belongs beside is a
     billboard, not a mark. */
  .profile__dagger .mark__glyph { width: 8rem; }
  .profile__crest-img { width: 8rem; }
}

.profile__hero {
  position: relative;
  padding: 2rem 1.75rem;
  background: var(--surface-card);
  border: 1px solid var(--line);
  border-left: 3px solid var(--brand);
  border-radius: var(--radius);
  overflow: hidden;
}

/* The flag, big, sitting behind the identity block rather than beside it.
   Low opacity so it reads as a field the name sits on, not a sticker.

   It bleeds off the right edge decisively rather than being clipped a few
   pixels in — a flag cut mid-star reads as a mistake, one running off the
   panel reads as intent. The mask fades the leading edge so it does not
   simply stop against the text. */
.profile__flag {
  position: absolute;
  top: 50%;
  right: -2.5rem;
  transform: translateY(-50%);
  font-size: 11rem;
  line-height: 1;
  opacity: .18;
  pointer-events: none;
  user-select: none;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 45%);
  mask-image: linear-gradient(to right, transparent, #000 45%);
}
/* THE PHONE IS A DIFFERENT PROBLEM, not a smaller version of this one.
   Measured at 390px: the watermark had nowhere to go but underneath the
   handle, where a 13%-opacity flag behind wrapped text is not a proud flag,
   it is a smudge — and the New Zealand flag being mostly dark blue made it
   read as a rendering fault.

   So on a handset the flag comes out from behind the type and is simply
   shown, at full opacity, beside the country it belongs to. Smaller in
   pixels than the watermark and far more present, which is the thing that
   was actually being asked for.

   The hero stacks at the same breakpoint: the mark and the display type
   cannot share 390px minus padding, and the handle was clipping against the
   panel edge. */
.profile__identity { position: relative; }

.profile__avatar-row { display: flex; align-items: center; gap: 1.1rem; }
.profile__avatar {
  width: 5rem;
  height: 5rem;
  flex: none;
  border-radius: 50%;
  object-fit: cover;
  background: var(--surface-raised);
  border: 2px solid var(--brand);
}
.profile__avatar--mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--brand);
}
.profile__avatar--mark .svc { width: 2.6rem; height: 2.6rem; }

.profile__handle {
  font-size: var(--display-l);
  line-height: 1.05;
  letter-spacing: -.01em;
}
.profile__where {
  margin-top: .3rem;
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted);
}
.profile__verified { color: var(--ok); }

.profile__service {
  margin-top: 1.25rem;
  padding-top: 1rem;
  border-top: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: .72rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--coyote);
}
.profile__service--withheld { color: var(--muted); }

.profile__bio { margin-top: 2rem; font-size: 1.05rem; line-height: 1.7; color: var(--ink-soft); }
.profile__bio p + p { margin-top: 1em; }

@media (max-width: 34rem) {
  .profile__flag { display: none; }

  .profile__hero { padding: 1.5rem 1.25rem; }

  .profile__avatar-row {
    flex-direction: column;
    align-items: flex-start;
    gap: .9rem;
  }

  /* Down from --display-l. It clipped at the panel edge, and a name running
     off its own box is the one thing a profile must not do. */
  .profile__handle { font-size: 26px; }

  /* Room to wrap without the dot separators stranding a single word, and
     the era ranges kept whole — "2003–" over "2014" reads as damage. */
  .profile__where,
  .profile__service { line-height: 1.7; }
  .profile__service { word-spacing: .05em; }
}

/* The inline flag, shown only where the watermark is not. Full opacity and
   its own line: this is the "bigger flag, I want them to be proud" ask,
   which a background wash at 13% was never going to satisfy on a phone. */
.profile__flag-inline { display: none; }
@media (max-width: 34rem) {
  .profile__flag-inline {
    display: block;
    margin-bottom: .6rem;
    font-size: 2.6rem;
    line-height: 1;
  }
}

/* NOTE ON PLACEMENT: this block sits AFTER every rule it overrides, and has
   to. A media query carries no extra specificity, so against a base rule of
   equal weight the winner is whichever comes last in the file. Put above,
   .profile__avatar-row's align-items:center beat the flex-start here and the
   hero rendered centred on a phone while measuring no differently — the same
   trap the share row hit. */

.profile__section { margin-top: 2.75rem; }
.profile__section-title {
  font-family: var(--font-mono);
  font-size: .72rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 1rem;
}

/* Badges. Gold, because gold is reserved for the brand and for things
   somebody earned — never the CTA orange, which means "press this". */
.badges {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
  gap: .8rem;
}
.badge-chip {
  padding: .8rem 1rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 2px solid var(--brand);
  border-radius: var(--radius);
}
.badge-chip__label {
  display: block;
  font-family: var(--font-mono);
  font-size: .7rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--brand);
}
.badge-chip__note {
  display: block;
  margin-top: .35rem;
  font-size: var(--micro-size);
  color: var(--muted);
  line-height: 1.45;
}
/* The two that are hardest to get, called out. */
.badge-chip--founding, .badge-chip--verified { border-left-width: 3px; }

/* The next mark up. Quiet on purpose: no bar, no percentage, no "4 to go".
   It is a fact about what exists, sitting under the ones already earned —
   the moment it becomes a meter it becomes a chore, and this audience did
   not come here for a chore. */
.profile__next {
  margin-top: 1rem;
  font-size: var(--small-size);
  color: var(--muted);
}
.profile__next-label {
  font-family: var(--font-mono);
  font-size: .64rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--muted);
  margin-right: .5rem;
}
.profile__next b { color: var(--ink-soft); }

/* The empty state, on their own page. An invitation, not a status line. */
.profile__invite {
  padding: 1.6rem 1.5rem;
  background: var(--surface-card);
  border: 1px solid var(--line);
  border-left: 3px solid var(--brand);
  border-radius: var(--radius);
}
.profile__invite-line {
  margin: 0;
  font-size: 1.1rem;
  line-height: 1.5;
  color: var(--ink);
}
.profile__invite-note {
  margin: .6rem 0 1.2rem;
  font-size: var(--small-size);
  line-height: 1.65;
  color: var(--muted);
}

.profile__yarns { list-style: none; margin: 0; padding: 0; display: grid; gap: .7rem; }
.profile__yarn-meta {
  margin-left: .5rem;
  font-family: var(--font-mono);
  font-size: .64rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
}

/* ---- The Muster -------------------------------------------------------- */

.muster { max-width: var(--body-measure); padding: 3rem 0; }
.muster__title {
  margin-top: .5rem;
  font-size: var(--display-l);
  line-height: 1.1;
  letter-spacing: -.01em;
}
.muster__section {
  margin-top: 3rem;
  font-family: var(--font-mono);
  font-size: .72rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--muted);
}
.muster__note { margin-top: 1rem; font-size: var(--small-size); color: var(--muted); }

.muster__list { margin-top: 2rem; display: grid; gap: 1.75rem; }

.posting__title { font-size: 1.1rem; line-height: 1.3; }
.posting__title a, .posting__headline a { color: var(--ink); text-decoration: none; }
.posting__title a:hover, .posting__title a:focus-visible { color: var(--brand); }
.posting__headline { font-size: var(--display-m); line-height: 1.2; }
.posting__meta {
  margin-top: .35rem;
  font-family: var(--font-mono);
  font-size: .66rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
}
.posting__excerpt { margin-top: .5rem; font-size: var(--small-size); color: var(--ink-soft); }
.posting--full { padding: 2rem 0 3rem; max-width: var(--body-measure); }

/* The licensing declaration and the contact both get a box. On this page
   they are the two things somebody has to actually read before acting, and
   in flowing prose they would be skimmed past. */
.posting__licence, .posting__contact, .review__licence {
  margin-top: 2rem;
  padding: 1rem 1.25rem;
  background: var(--surface-card);
  border-left: 3px solid var(--brand);
  border-radius: var(--radius);
}
.posting__licence-label {
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: .4rem;
}
.posting__licence-note { margin-top: .6rem; font-size: var(--micro-size); color: var(--muted); }

.muster__mine-list { list-style: none; margin: 1rem 0 0; padding: 0; display: grid; gap: .6rem; }
.posting__status {
  font-family: var(--font-mono);
  font-size: .62rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: .1rem .5rem;
  margin-left: .4rem;
}
.posting__status--live { color: var(--ok); border-color: var(--ok); }
.posting__status--rejected, .posting__status--removed { color: var(--danger); border-color: var(--danger); }
.posting__status--submitted { color: var(--warn); border-color: var(--warn); }

.muster__rule-list { margin: 1rem 0 0 1.2rem; color: var(--ink-soft); }
.muster__rule-list li { margin-bottom: .6rem; }

/* The line the board signs off with. Bigger and in the body colour so it
   lands as a statement rather than as one more note. */
.muster__hit {
  margin-top: 1.8rem;
  font-size: 1.2rem;
  line-height: 1.5;
  color: var(--text-body);
}

/* §7's footer line. Loud on purpose — the tone IS the deterrent. */
.muster__disclaimer {
  margin-top: 2rem;
  padding: 1rem 1.25rem;
  background: var(--surface);
  border-left: 3px solid var(--danger);
  border-radius: var(--radius);
  font-size: var(--small-size);
  color: var(--ink-soft);
}

.admin__section { margin-top: 3rem; }

/* ---- SITREP ------------------------------------------------------------ */

.sitrep { max-width: var(--body-measure); padding: 3rem 0; }
.sitrep__title {
  margin-top: .5rem;
  margin-bottom: 1.25rem;
  font-size: var(--display-l);
  line-height: 1.1;
  letter-spacing: -.01em;
}
.sitrep__note { margin-top: 1.5rem; font-size: var(--small-size); color: var(--muted); }

/* The OPSEC block already shouts; on this page it carries prose as well as a
   list, so the paragraphs need spacing the shared rule does not give them. */
.opsec p + ul { margin-top: .8rem; }
.opsec__close { margin-top: .9rem; }

/* ---- The landing hook -------------------------------------------------- */
/* Shown to signed-out readers at the foot of a public yarn — the page every
   share button lands on. Allowed to be the loudest thing after the writing
   itself, and no louder: it sits under somebody's account of a bad night, so
   it is a bordered panel rather than a coloured slab. */

.hook {
  margin-top: 3rem;
  padding: 2rem 2rem 2.25rem;
  background: var(--surface-card);
  border: 1px solid var(--border-hairline);
  border-left: 3px solid var(--brand);
  border-radius: var(--radius);
}

.hook__eyebrow {
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--brand);
}

/* The heading as a link. No permanent underline: at this size a rule under
   two lines of display type is a heavy thing to carry on every page, and the
   button directly beneath already says the block is actionable. Colour and an
   underline arrive together on hover and on keyboard focus, so it is never
   colour alone doing the work. */
.hook__link {
  color: inherit;
  text-decoration: none;
}
.hook__link:hover,
.hook__link:focus-visible {
  color: var(--brand);
  text-decoration: underline;
  text-underline-offset: .18em;
  text-decoration-thickness: 1px;
}

.hook__title {
  margin-top: .8rem;
  font-size: var(--display-m);
  line-height: 1.25;
  max-width: 30ch;
}

.hook__body { margin-top: .9rem; color: var(--ink-soft); max-width: 56ch; }
.hook .home__actions { margin-top: 1.5rem; }

/* The same block at the foot of the front page. More air above it than the
   version on a yarn, because there it follows one person's writing and here
   it follows a grid of cards — a card list runs out rather than ending, and
   without the gap this reads as one more card. */
.hook--home { margin-top: 4rem; margin-bottom: 1rem; }
.hook--home .hook__body + .hook__body { margin-top: 1rem; }
.hook__note { margin-top: 1.25rem; font-size: var(--small-size); color: var(--muted); }

/* ---- Send a yarn by email ---------------------------------------------- */

.sendmail { max-width: 44rem; }

.sendmail__preview { margin-top: 2.5rem; }

/* The preview is an iframe so the message's own table layout and inline
   styles cannot collide with this stylesheet in either direction. Given a
   fixed height with its own scroll rather than sized to content: an email is
   long, and it should sit in the page as a thing being examined rather than
   pushing the form off the top of the screen. */
.sendmail__frame {
  margin-top: .75rem;
  width: 100%;
  height: 32rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--ink-0);
}

/* ---- Moderator removal ------------------------------------------------- */
/* The most destructive control on a yarn page, so it is folded away behind a
   summary rather than sitting open next to the writing. Reaching it should
   be a decision. */

.yarn__moderate {
  margin-top: 2.5rem;
  padding: 1rem 1.25rem;
  border: 1px solid var(--danger);
  border-radius: var(--radius);
  background: var(--surface-card);
}
.yarn__moderate > summary {
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--danger);
}
.yarn__moderate form { margin-top: 1.25rem; }
.yarn__moderate textarea { width: 100%; }

.removed__list { list-style: none; margin: 2rem 0 0; padding: 0; display: grid; gap: 1rem; }
.removed__item {
  padding: 1.1rem 1.25rem;
  background: var(--surface-card);
  border: 1px solid var(--border-hairline);
  border-left: 3px solid var(--danger);
  border-radius: var(--radius);
}
.removed__title { font-weight: 700; }
.removed__meta { margin-top: .3rem; font-size: var(--small-size); color: var(--muted); }

/* The reason is the point of the page, so it is body-weight rather than
   fine print. */
.removed__reason {
  margin-top: .75rem;
  padding-left: .9rem;
  border-left: 2px solid var(--border-strong);
  color: var(--ink-soft);
}
.removed__reason--missing { color: var(--muted); font-style: italic; }
.removed__actions { margin-top: 1rem; }

/* ---- Salute ------------------------------------------------------------ */
/* A mark of respect, not a like. See yarns/_salute.html and §4 of the plan.
   Sits above the share row and is allowed to be the more prominent of the
   two — it belongs to the writing, where sharing belongs to the reader.

   Gold, not the orange CTA. This is not the action the page is pushing you
   towards; it is a thing you do because you meant it. */

.salute {
  margin-top: 2.5rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .9rem 1.25rem;
}

.salute__btn {
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  padding: .6rem 1.1rem;
  background: transparent;
  color: var(--brand);
  border: 1px solid var(--brand);
  border-radius: var(--radius);
  font: inherit;
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color .12s ease, color .12s ease;
}
.salute__btn:hover,
.salute__btn:focus-visible { background: var(--brand); color: var(--ink-0); }

/* Saluted: filled, so the state is carried by more than colour alone —
   aria-pressed says it to a screen reader, the fill says it to everyone
   else, and neither depends on telling gold from grey. */
.salute__btn--on { background: var(--brand); color: var(--ink-0); }
.salute__btn--on:hover,
.salute__btn--on:focus-visible { background: var(--brand-hover); }

/* The 🫡 character, not an SVG. Sized in px rather than em so it does not
   inherit the button's small uppercase label size, and given its own
   line-height so a tall emoji glyph cannot stretch the button. */
.salute__mark {
  flex: none;
  font-size: 20px;
  line-height: 1;
}

.salute__note { font-size: var(--small-size); color: var(--muted); }

/* The author's own figure. Quiet by design — it is a fact they are entitled
   to, not a score the page is celebrating. */
.salute__count { font-size: var(--small-size); color: var(--ink-soft); }
.salute__only-you {
  margin-left: .5rem;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--text-faint);
}

/* ---- Share ------------------------------------------------------------- */
/* Text labels, not brand logos — see yarns/_share.html. Built to read as one
   quiet row rather than eight competing badges: this sits under somebody's
   account of a bad night, and it should not be the loudest thing on it. */

.share {
  margin-top: 2.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
}
.share__label {
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--muted);
}
.share__list {
  list-style: none;
  margin: .8rem 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
}
.share__link {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
  text-decoration: none;
  background: none;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: .4rem .7rem;
  cursor: pointer;
  /* Matches .btn, so the copy button and the links are one row of controls
     rather than a button that has wandered in from another design. */
  font-weight: inherit;
}
/* Thumb-sized on a handset. This is the one row on a yarn page somebody taps
   while holding the phone one-handed, and 33px is a control you hit on the
   second try. Kept here rather than with the masthead's mobile rules: the
   base .share__link is defined below those, and a tie on specificity is
   settled by source order. */
@media (max-width: 32rem) {
  .share__link { padding: .8rem 1rem; }
  .share__list { gap: .5rem; }
}

.share__link:hover,
.share__link:focus-visible {
  color: var(--brand);
  border-color: var(--brand);
}

/* ---- Search ------------------------------------------------------------ */

.nav__search { display: inline-flex; align-items: center; gap: .4rem; }
.nav__search-glyph { width: .95rem; height: .95rem; flex: none; }

/* The reply marker on the handle in the masthead.
 *
 * Gold, not the orange CTA — see the token block at the top of this file. This
 * is a fact about your account, not the action the page is pushing you
 * towards, and orange here would put a live-looking alert on every page for
 * something as ordinary as somebody answering you.
 *
 * A filled pill rather than a coloured dot: colour alone is not a signal, and
 * the number is the part that tells you whether it is worth opening now. The
 * screen-reader text lives inside it because "ruckman 3" read aloud is not a
 * sentence. */
.nav__badge {
  display: inline-block;
  min-width: 1.25rem;
  margin-left: .45rem;
  padding: 0 .3rem;
  background: var(--brand);
  color: var(--ink-0);
  border-radius: 1rem;
  font-size: var(--micro-size);
  line-height: 1.25rem;
  text-align: center;
  vertical-align: baseline;
}

.search { max-width: var(--body-measure); padding: 3rem 0; }
.search__title { font-size: var(--display-l); line-height: 1.1; letter-spacing: -.01em; }

/* WRAPS, because this row is not always two things. On /search it is a field
   and a button and fits anywhere; on /admin/email it is a field, a SELECT and
   a button, and a native select carries an intrinsic width it will not give
   up — 304px of it, which pushed that page 120px sideways on a 360px phone.
   The one page on the site that scrolled horizontally, and it was this. */
.search__form {
  display: flex;
  flex-wrap: wrap;
  gap: .6rem;
  margin-top: 1.5rem;
}
.search__form input {
  flex: 1;
  font: inherit;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: .7rem .9rem;
  min-width: 0;   /* or a long value stretches the flex item past its parent */
}
.search__form input:focus-visible { border-color: var(--signal); }
.search__form .btn { flex: none; }

/* The select, framed like the field beside it. Left native it was a system
   control sitting in the middle of the site's own, and it is the element
   that would not shrink. */
.search__form select {
  flex: 1 1 9rem;
  min-width: 0;
  font: inherit;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: .7rem .9rem;
}
.search__form select:focus-visible { border-color: var(--signal); }

/* On a phone each control takes the width. Three of them shoulder to
   shoulder at 360px leaves none of them wide enough to read — the handle
   field came out four characters across.

   Named element by element rather than as `.search__form > *`: the rules
   above are `.search__form input` and `.search__form select`, which carry a
   type selector and therefore beat a universal one. The tidier version
   silently did nothing. */
@media (max-width: 34rem) {
  .search__form input,
  .search__form select,
  .search__form .btn { flex: 1 1 100%; }
}

/* type="search" is kept for the semantics and for the mobile keyboard, but
   WebKit draws its own clear button in a fixed system blue that cannot be
   recoloured and reads as somebody else's UI dropped onto the page. Hidden
   rather than restyled: there is no cross-browser way to colour it, and the
   field is one word long. */
.search__form input::-webkit-search-cancel-button,
.search__form input::-webkit-search-decoration {
  -webkit-appearance: none;
  appearance: none;
}

.search__scope { margin-top: .75rem; font-size: var(--micro-size); color: var(--muted); }
.search__count {
  margin-top: 2rem;
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--muted);
}

.search__results { margin-top: 1rem; display: grid; gap: 1.75rem; }

.hit { display: flex; gap: 1.15rem; align-items: flex-start; }
.hit__photo { flex: none; width: 5.5rem; }
.hit__photo img {
  width: 100%;
  height: 4rem;
  object-fit: cover;
  display: block;
  border-radius: var(--radius);
  background: var(--surface);
}
.hit__body { flex: 1; min-width: 0; }
.hit__title { font-size: 1.05rem; line-height: 1.3; }
.hit__title a { color: var(--ink); text-decoration: none; }
.hit__title a:hover, .hit__title a:focus-visible { color: var(--brand); }
.hit__meta {
  margin-top: .35rem;
  font-family: var(--font-mono);
  font-size: .66rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
}
.hit__excerpt { margin-top: .5rem; font-size: var(--small-size); color: var(--ink-soft); }

/* The matched words. A background tint rather than a colour swap, so a hit
   in the middle of a sentence is findable without the sentence turning into
   a ransom note. */
.hit__excerpt mark {
  background: color-mix(in srgb, var(--brand) 26%, transparent);
  color: inherit;
  border-radius: 2px;
  padding: 0 .15em;
}

/* ---- Branch dedication ------------------------------------------------- */
/* Optional, per branch — see the include in yarns/branch.html. Sits between
   the service nav and the feed, so it introduces the page without pushing
   the actual stories below the fold. */

.dedication {
  max-width: var(--body-measure);
  margin: 2rem 0 2.5rem;
  padding: 1.5rem 0 0;
  border-top: 1px solid var(--line);
  color: var(--ink-soft);
}
.dedication__label {
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--brand);
}
.dedication__lead {
  margin-top: .9rem;
  font-size: 1.15rem;
  color: var(--ink);
}
.dedication p + p { margin-top: 1rem; }
.dedication__aside { font-size: var(--small-size); color: var(--muted); }

/* ---- Families ---------------------------------------------------------- */

.families__head { max-width: var(--body-measure); padding: 3rem 0 1rem; }
.families__title {
  margin-top: 1.5rem;
  font-size: var(--display-l);
  line-height: 1.1;
  letter-spacing: -.01em;
}
.families__note { margin-top: 1.15rem; color: var(--ink-soft); }

/* The memorial ode sits on a photograph and is centred against it. This one
   carries a page with no hero image behind it, so it needs its own rule to
   sit against rather than borrowing one it does not have. */
.ode--plain {
  margin-top: 1.5rem;
  padding-left: 1.25rem;
  border-left: 2px solid var(--brand);
  text-align: left;
}
/* Layout only. Type and colour for this variant are set after `.ode p`,
   further down — putting them here loses to source order. */
.ode--plain p { font-style: italic; }
.ode--plain cite {
  display: block;
  font-style: normal;
  font-size: var(--micro-size);
}

/* ---- Support ----------------------------------------------------------- */

.support { max-width: 46rem; padding: 3rem 0; }
.support__title { font-size: var(--display-l); line-height: 1.1; letter-spacing: -.01em; }
.support .lede { margin-top: 1rem; }

/* The one thing on the page that must be read even by someone skimming. */
.support__urgent {
  margin-top: 1.75rem;
  padding: 1rem 1.25rem;
  background: var(--surface-card);
  border-left: 3px solid var(--signal);
  border-radius: var(--radius);
  color: var(--text-body);
}

.support__country { margin-top: 3rem; }
.support__country h2 { font-size: var(--display-m); }
.support__emergency {
  margin-top: .35rem;
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--text-muted);
}
.support__emergency b { color: var(--signal); }

.support__list { list-style: none; margin: 1.25rem 0 0; padding: 0; display: grid; gap: 1rem; }

.svc-item {
  padding: 1.1rem 1.25rem;
  background: var(--surface-card);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius);
}
.svc-item__name { font-weight: 700; }
.svc-item__tag {
  margin-left: .5rem;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--tag-fg);
  border: 1px solid var(--tag-border);
  border-radius: var(--radius);
  padding: .15rem .4rem;
  vertical-align: 2px;
}

/* Big, and a link, so it can be tapped without being read out first. */
.svc-item__number { margin-top: .5rem; font-size: 1.35rem; font-weight: 700; }
.svc-item__number a { color: var(--signal); text-decoration: none; }
.svc-item__number a:hover, .svc-item__number a:focus-visible { text-decoration: underline; }

.svc-item__alt { margin-top: .35rem; font-size: var(--small-size); color: var(--text-muted); }
.svc-item__alt b { color: var(--text-body); }
.svc-item__detail { margin-top: .5rem; font-size: var(--small-size); color: var(--ink-soft); }

/* The words about why the page exists. Set as prose, wider than a caption and
   narrower than the page, because somebody who has stopped to read this is
   reading rather than scanning. */
.support__words { margin-top: 2rem; max-width: 60ch; }
.support__words p {
  margin-bottom: 1.1rem;
  font-size: 1.05rem;
  line-height: 1.75;
  color: var(--ink-soft);
}
.support__words-hit {
  color: var(--text-body) !important;
  padding-left: .9rem;
  border-left: 2px solid var(--coyote);
}

/* The country picker. A plain GET form with a real submit button — if one
   page on this site has to work with script broken or still loading, it is
   this one. The row wraps rather than shrinking the control: a select
   squeezed to nothing on a phone is a select nobody can use. */
.support__pick {
  margin-top: 2.5rem;
  padding-top: 2rem;
  border-top: 1px solid var(--line);
}
.support__pick-row {
  margin-top: .6rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .8rem;
}
.support__pick select {
  font: inherit;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line-lit);
  border-radius: var(--radius);
  padding: .8rem .9rem;
  min-width: 14rem;
  flex: 1 1 14rem;
  max-width: 22rem;
}
.support__pick select:focus-visible { border-color: var(--signal); }

.support__none {
  margin-top: 2.5rem;
  font-size: var(--small-size);
  color: var(--text-muted);
}

/* The countries with no checked numbers. Quieter than a listed country —
   it is an admission, not an offering. */
.support__wanted {
  margin-top: 3.5rem;
  padding-top: 2rem;
  border-top: 1px solid var(--line);
}
.support__wanted h2 {
  font-size: var(--display-m);
  color: var(--muted);
}
.support__wanted p {
  margin-top: 1rem;
  font-size: var(--small-size);
  line-height: 1.7;
  color: var(--text-muted);
  max-width: 62ch;
}

.support__warning {
  margin-top: 3rem;
  padding: 1rem 1.25rem;
  border-left: 3px solid var(--warn);
  background: var(--surface-card);
  font-size: var(--small-size);
  color: var(--ink-soft);
}

.support .fine-print { margin-top: 2rem; }

/* ---- Chip in ----------------------------------------------------------- */
/* Sits next to Support in this file because the two pages are related and
   must never merge: /support is crisis lines and carries no money ask. See
   the docstring on the route in app/routes/public.py.

   The page's whole job is to keep two things visibly apart — paying for the
   server, and giving to a charity we never touch. So the layout does the
   separating: each is a boxed block with its own heading, rather than two
   paragraphs a reader could run together. */

.chip-in { max-width: 46rem; padding: 3rem 0; }
.chip-in__title { font-size: var(--display-l); line-height: 1.1; letter-spacing: -.01em; }
.chip-in .lede { margin-top: 1rem; }

.chip-in__block {
  margin-top: 2.5rem;
  padding: 1.5rem 1.5rem 1.75rem;
  background: var(--surface-card);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius);
}

/* Gold, because this is structural — a heading, not a control. The rule
   above it does the same job the boxes do: says "a different thing starts
   here". */
.chip-in__heading {
  font-size: var(--display-m);
  color: var(--brand);
  padding-bottom: .75rem;
  border-bottom: 1px solid var(--border-hairline);
}

.chip-in__block p { margin-top: 1.1rem; }

/* The sentences a reader would skip and later wish they had not: that this
   is not a tax-deductible donation, and that the charity money never comes
   near us. Set apart rather than emphasised in colour — red or orange here
   would read as an alarm on a page that is not an emergency. */
.chip-in__plain {
  padding-left: 1rem;
  border-left: 2px solid var(--border-strong);
  color: var(--ink-soft);
  font-size: var(--small-size);
}
.chip-in__plain b { color: var(--text-body); }

.chip-in__block .home__actions { margin-top: 1.5rem; }

.chip-in__note { margin-top: .75rem; font-size: var(--small-size); color: var(--muted); }

/* Outside the boxes, quieter than the ask, and last on the page — it is a
   way out for somebody who came here to give and found they needed help
   instead. */
.chip-in__aside {
  margin-top: 2rem;
  font-size: var(--small-size);
  color: var(--muted);
}

.chip-in__charities {
  list-style: none;
  margin: 1.5rem 0 0;
  padding: 0;
  display: grid;
  gap: .85rem;
}
.chip-in__charities li {
  padding: .9rem 1.1rem;
  background: var(--surface-raised);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius);
}
.chip-in__charities .chip-in__note { display: block; margin-top: .3rem; }

/* The empty state is the normal state here, not a failure, so it is not
   styled as one — .empty's default padding would leave a hole in the box. */
.chip-in__block .empty { padding: 1.25rem 0 .25rem; }

/* Honeypot: out of sight, out of the accessibility tree, still fillable by a
   bot. Not display:none — some bots skip those. */
.hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ---- Footer ------------------------------------------------------------ */

.site-footer { border-top: 1px solid var(--line); }

.footer-links {
  margin-top: 1.5rem;
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
}
.footer-links a { color: var(--text-muted); text-decoration: none; }
.footer-links a:hover, .footer-links a:focus-visible { color: var(--text-body); }
/* --text-faint, not --border-strong: this is a printed character somebody
   reads past, not a rule. On the light theme the border colour put it at
   1.78:1, which is a smudge rather than a separator. */
.footer-links .sep { color: var(--text-faint); margin: 0 .6em; }
/* Marked out from its neighbour. It is the one link on the site somebody may
   need to find quickly and without reading the rest. */
.footer-links__support { color: var(--coyote) !important; }
.footer-links__support:hover, .footer-links__support:focus-visible { color: var(--signal) !important; }

/* .tag-row / .tag-row--nations lived here and styled the five-nation row in
   the footer. Both removed with it — they had no other user, and dead
   selectors are how a stylesheet stops being readable. */

/* The footer links are inline text in a wrapped row, which measures 12px tall
   on a handset — the smallest tap target on the site, and one of them is the
   mental health support link. Given vertical room on mobile only; a mouse
   pointer does not need it, and on a desktop it would just loosen the row. */
@media (max-width: 32rem) {
  .footer-links { line-height: 1.4; }
  .footer-links a { display: inline-block; padding: .55rem 0; }
}

.fine-print {
  margin-top: 1.5rem;
  font-size: .82rem;
  color: var(--muted);
  max-width: 52ch;
}

/* ---- Accessibility ----------------------------------------------------- */

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

.skip-link {
  position: absolute;
  left: -9999px;
}
.skip-link:focus {
  left: 1rem;
  top: 1rem;
  z-index: 100;
  background: var(--signal);
  color: #fff;
  padding: .6rem 1rem;
}

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* ---- Lest We Forget ---------------------------------------------------- */

/* The ode sits in its own quiet band above everything else. Full width and
   unhurried on purpose — this page should not open like a feed. */
/* The ode sits on the photograph. It is the first thing on the page and it
   should stop somebody, not introduce something. */
.remember {
  position: relative;
  overflow: hidden;
  border-bottom: 1px solid var(--line);
  min-height: min(72vh, 34rem);
  display: flex;
  align-items: center;
  text-align: center;
  background: #0A0806;
}

.remember__photo { position: absolute; inset: 0; }
.remember__photo img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Heavier than the front-page hero needs to be. That photograph is dark to
   begin with; this one is a sunrise, and cream text on an orange sky is
   unreadable without real weight behind it. Darkest through the middle band
   where the verse sits, easing off top and bottom so the poppies and the sky
   still carry. */
.remember__scrim {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(180deg,
      rgba(10, 8, 6, .55) 0%,
      rgba(10, 8, 6, .78) 35%,
      rgba(10, 8, 6, .78) 65%,
      rgba(10, 8, 6, .55) 100%),
    radial-gradient(80% 60% at 50% 50%, rgba(10, 8, 6, .35), transparent 70%);
}

.remember__inner { position: relative; }

/* Fixed light regardless of theme — it is on a photograph in both. */
.remember .eyebrow { color: #D8B48A; margin-bottom: 2rem; }

.ode { margin: 0; }
.ode p {
  font-size: clamp(1.1rem, 2.4vw, 1.6rem);
  line-height: 1.95;
  /* Not var(--text-body): in the light theme that is near-black, and this
     text sits on a photograph in both themes. Same trap that made the front
     page hero vanish when the toggle was added. */
  color: #F4F1EA;
  font-style: italic;
  text-shadow: 0 1px 12px rgba(10, 8, 6, .8);
}
.ode cite {
  display: block;
  margin-top: 1.75rem;
  color: #C9C3B6;
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  font-style: normal;
}

/* ---- The ode WITHOUT a photograph under it -----------------------------
   The block above is written for Lest We Forget, where the words sit on an
   image in both themes — hence the fixed near-white and the drop shadow,
   which are correct there and wrong anywhere else.

   Families uses the same element on the ordinary page background. Its
   overrides live further up this file, and `.ode--plain p` and `.ode p`
   have identical specificity, so the LATER one won and the quote inherited
   photograph colours: pale text on bone, all but invisible in the light
   theme, with a shadow doing nothing but blurring it.

   Restated here, after the rules they correct, which is the only reason
   they take effect. The colours are the page's own, so this follows the
   theme like every other piece of text. */
.ode--plain p {
  font-size: 1.15rem;
  line-height: 1.7;
  color: var(--text-body);
  text-shadow: none;
}
.ode--plain cite {
  margin-top: .6rem;
  color: var(--text-muted);
}

.remember__intro { max-width: var(--body-measure); padding: 3.5rem 0 2.5rem; }
.remember__title { font-size: var(--display-l); line-height: 1.15; }
.remember__intro .lede { margin-top: 1.25rem; }
.remember__note { margin-top: 1rem; color: var(--text-muted); font-size: var(--small-size); }

/* margin-top because this grid does not always follow a text block with its
   own bottom spacing. On the SITREP pages it follows the action button
   directly and sat flush against it — measured at a 0px gap, which reads as
   the button overlapping the first card. Adjacent margins collapse, so the
   pages that already had room are unaffected. */
.remember__list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr));
  gap: 1.5rem;
  margin-top: 2.5rem;
  padding-bottom: 3rem;
}

/* Deliberately not called a card. */
.stone {
  border: 1px solid var(--border-hairline);
  border-top: 3px solid var(--coyote);
  border-radius: var(--radius);
  background: var(--surface-card);
  overflow: hidden;
}
.stone__photo { display: block; aspect-ratio: 4 / 3; background: var(--bg); }
.stone__photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.stone__body { padding: 1.15rem 1.25rem; }
.stone__body h2 { font-size: 1.1rem; }
.stone__body h2 a { color: var(--text-body); text-decoration: none; }
.stone__body h2 a:hover, .stone__body h2 a:focus-visible { color: var(--brand); }
.stone__years {
  margin-top: .3rem;
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  color: var(--coyote);
}
.stone__excerpt { margin-top: .7rem; font-size: var(--small-size); color: var(--ink-soft); }
.stone__by { margin-top: .8rem; font-size: var(--micro-size); color: var(--text-muted); }

.remember__closing {
  max-width: var(--body-measure);
  padding: 2rem 0 3.5rem;
  font-size: var(--small-size);
  color: var(--text-muted);
}

/* ---- House rules ------------------------------------------------------- */

.rules { margin: 2rem 0 0 1.2rem; padding: 0; }
.rules li {
  margin-bottom: 1.5rem;
  font-size: var(--small-size);
  color: var(--ink-soft);
  line-height: 1.7;
}
/* The rule's OWN LINE, which is the first bold in each item and nothing
   else. Written as `.rules li b` when every rule had exactly one, so the
   day a rule needed a bold mid-sentence it was thrown onto a line of its
   own in heading colour — which is what happened to rule 7 and what it
   looked like: a stray fragment between two halves of a sentence. */
.rules li > b:first-child {
  display: block;
  color: var(--text-body);
  margin-bottom: .3rem;
  font-size: 1rem;
}
.rules__closing {
  margin-top: 2.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
  font-size: var(--small-size);
  color: var(--text-muted);
}

/* The ask at the foot of the rules. NO card and no background — the .hook
   panel used on the front page is meant to be loud, and a slab of marketing
   under a page of rules would undercut the plain tone the rules depend on.
   A hairline, a line of text, one button. */
.rules__after {
  margin-top: 3rem;
  padding-top: 2rem;
  border-top: 1px solid var(--line);
}
.rules__after-eyebrow {
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--brand);
}
.rules__after-line {
  margin-top: .8rem;
  font-size: 1.05rem;
  line-height: 1.7;
  color: var(--ink-soft);
  max-width: 56ch;
}
.rules__after .home__actions { margin-top: 1.5rem; }
.rules__after-note {
  margin-top: 1.5rem;
  font-size: var(--small-size);
  line-height: 1.6;
  color: var(--text-muted);
  max-width: 60ch;
}

/* ---- Branch pages ------------------------------------------------------ */

.branch-head { display: flex; align-items: center; gap: .75rem; }
.branch-head__mark { color: var(--coyote); width: 1.6rem; height: 1.6rem; }

.branch-nav {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  margin-bottom: 2rem;
  padding-bottom: 1.25rem;
  border-bottom: 1px solid var(--line);
}
.branch-nav a {
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--text-muted);
  text-decoration: none;
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius);
  padding: .4rem .7rem;
}
.branch-nav a:hover, .branch-nav a:focus-visible {
  color: var(--text-body);
  border-color: var(--border-strong);
}
.branch-nav a.is-current { color: var(--brand); border-color: var(--brand); }

/* Thumb-sized on a handset. This row is the only way to filter the Muster
   or move between branch pages on a phone, and it measured 33px — the same
   second-try miss as the masthead and the share row. */
@media (max-width: 32rem) {
  .branch-nav { gap: .45rem; }
  .branch-nav a { padding: .8rem .8rem; }
}

/* The footer marks are links now, so they need to look like it on hover
   without turning the row into a wall of underlines. */
.branch a {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .5rem;
  color: inherit;
  text-decoration: none;
}
.branch a:hover .svc, .branch a:focus-visible .svc { color: var(--brand); }
.branch a:hover span, .branch a:focus-visible span { color: var(--text-body); }

/* Lest We Forget sits with the service marks but is not one of them: a rule
   and the coyote tone separate it without pushing it out of the row. */
.branch--remember { margin-left: 1.25rem; }
.branch--remember .svc { color: var(--coyote); }
.branch--remember span { color: var(--coyote); }
.branch--remember a:hover .svc, .branch--remember a:focus-visible .svc { color: var(--brand); }

/* ---- Sidebar shell ----------------------------------------------------- */

/* Desktop gets a persistent sidebar; below 64rem it is hidden entirely and
   the masthead and footer carry the same destinations. Nothing lives ONLY in
   the sidebar, so hiding it cannot make a page unreachable. */
.shell { flex: 1; display: flex; align-items: flex-start; }

/* min-width: 0 is load-bearing. A flex child defaults to min-width: auto, so
   without it any wide thing inside — a hero, a table — refuses to shrink and
   pushes the whole layout wider than the window. */
.site-body { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.sidebar {
  flex: none;
  width: 15rem;
  position: sticky;
  top: 0;
  /* height, not max-height. With max-height the rail stopped wherever its
     last link did and the surface colour ended in mid-page, which reads as a
     panel floating on the layout rather than an edge of it. Full height means
     the background and the border run the whole way down whatever the page
     is doing. */
  height: 100vh;
  overflow-y: auto;
  padding: 1.5rem 1rem 2rem;
  border-right: 1px solid var(--line);
  background: var(--surface-card);
}

.sidebar__heading {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--text-faint);
  margin: 1.5rem 0 .5rem .7rem;
}
.sidebar__heading:first-child { margin-top: 0; }

.sidebar__link {
  display: flex;
  align-items: center;
  gap: .7rem;
  padding: .5rem .7rem;
  border-radius: var(--radius);
  font-size: var(--micro-size);
  color: var(--text-muted);
  text-decoration: none;
}
.sidebar__link:hover, .sidebar__link:focus-visible {
  color: var(--text-body);
  background: var(--surface-raised);
}
.sidebar__link .svc { width: 1.15rem; height: 1.15rem; flex: none; color: var(--coyote); }
/* Links with no glyph line up with the ones that have. */
.sidebar__link > span:only-child { padding-left: 1.85rem; }

/* Where you are. A persistent nav that looks identical on every page is
   just a list; this is the part that makes it worth keeping on screen. */
.sidebar__link[aria-current="page"] {
  color: var(--text-body);
  background: var(--surface-raised);
  box-shadow: inset 2px 0 0 var(--brand);
}
.sidebar__link[aria-current="page"] .svc { color: var(--brand); }

.sidebar__link--remember .svc,
.sidebar__link--remember span { color: var(--coyote); }
.sidebar__link--support span { color: var(--coyote); }

@media (max-width: 64rem) {
  .sidebar { display: none; }
  .shell { display: block; }
}

/* ---- The menu, below 64rem ---------------------------------------------
   A <details>. No script opens it, which matters because below 64rem it is
   the only route to The Vault, The Muster, Standing By, The Gouge, Told Out
   Loud and the map. Its contents come from _sections.html — the same file
   the rail reads. */

.menu { display: none; }

.menu__button {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  padding: .5rem .8rem;
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--text-body);
  background: transparent;
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius);
  cursor: pointer;
  list-style: none;            /* the default disclosure triangle */
  -webkit-tap-highlight-color: transparent;
}
.menu__button::-webkit-details-marker { display: none; }
.menu__glyph { width: 1.05rem; height: 1.05rem; flex: none; }
.menu[open] .menu__button {
  color: var(--ink);
  border-color: var(--brand);
}
/* The three bars become a cross when it is open, so the button says what
   pressing it will do rather than what it did. */
.menu[open] .menu__glyph path:nth-child(1) { d: path("M6 6l12 12"); }
.menu[open] .menu__glyph path:nth-child(2) { opacity: 0; }
.menu[open] .menu__glyph path:nth-child(3) { d: path("M18 6L6 18"); }

/* Anchored to the masthead rather than to the button, so it is the width of
   the page and not the width of the word "Menu". Overlaid rather than pushed
   in flow: a long list would otherwise shove the page down by its own height
   every time somebody looked at it. */
.menu__panel {
  position: absolute;
  top: calc(100% + .6rem);
  right: 0;
  z-index: 40;
  width: min(20rem, calc(100vw - 2rem));
  max-height: calc(100vh - 8rem);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: .8rem;
  background: var(--surface-card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 18px 40px rgba(0, 0, 0, .45);
  text-align: left;
}
.menu__nav { display: block; }
/* The rail's own link styling, restyled from here rather than by giving the
   shared partial a second set of class names. */
.menu .sidebar__link {
  width: 100%;
  font-size: var(--small-size);
  /* 44px targets. A finger pad is about that wide and this is the one
     control on the site that is only ever used with a thumb. */
  padding: .65rem .7rem;
  text-align: left;
  background: transparent;
  border: 0;
  cursor: pointer;
}
.menu .sidebar__heading { margin: 1.1rem 0 .3rem .7rem; }
.menu .sidebar__heading:first-child { margin-top: .2rem; }
.menu__logout { margin: 0; }
.menu__theme { font: inherit; color: var(--text-muted); }
/* The script writes "Dark"/"Light"; in a sentence it wants neither. */
.menu__theme [data-theme-label] { text-transform: lowercase; }

@media (max-width: 64rem) {
  .menu { display: inline-block; }
  /* Everything the menu now carries. What is left is the mark and the way
     to the rest of the site — one row, on any phone. */
  .nav__wide { display: none !important; }
}

/* ONE ROW AT 360px, which is the commonest Android width and the one this
   stopped fitting on first. The wordmark is the widest thing in the row and
   it is the only thing here that can give ground without losing meaning. */
@media (max-width: 34rem) {
  .masthead.wrap { padding-top: 1.1rem; padding-bottom: 1.1rem; }
  .mark__glyph { width: 1.45rem; height: 1.45rem; }
  .mark__word { font-size: 1.05rem; letter-spacing: .15em; }
  .menu__panel { width: calc(100vw - 2rem); }
}


/* ---- Comments ---------------------------------------------------------- */
/* A conversation, not a comment section. The visual weight sits with the
   words: no cards, no avatars, no vote arrows, no nesting — a rule down the
   left and the handle above it, so a thread reads as a series of people
   speaking rather than a scoreboard.
 *
 * Nothing here is counted publicly beyond the heading. The salute is the
 * thing §4 forbids comparing; "4 replies" describes a conversation and is
 * allowed to be plain.
 */

.comments {
  margin-top: 3rem;
  padding-top: 2rem;
  border-top: 1px solid var(--line);
}

.comments__title {
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--muted);
}

.comments__list {
  list-style: none;
  margin: 1.5rem 0 0;
  padding: 0;
  display: grid;
  gap: 2rem;
}

.comment {
  padding-left: 1rem;
  border-left: 2px solid var(--border-hairline);
}

.comment__meta {
  font-size: var(--small-size);
  color: var(--muted);
}
.comment__who {
  color: var(--coyote);
  text-decoration: none;
  font-weight: 700;
}
.comment__who:hover, .comment__who:focus-visible { color: var(--brand); }

/* A notch below .yarn__body's 1.05rem, on purpose. The story is the thing on
   this page; a reply that sets at the same size as the writing it is replying
   to reads as a second story rather than an answer to the first. */
.comment__body {
  margin-top: .55rem;
  font-size: 1rem;
  line-height: 1.65;
  color: var(--ink-soft);
}
.comment__body p { margin: 0 0 1em; }
.comment__body p:last-child { margin-bottom: 0; }
.comment__body ul, .comment__body ol { margin: 0 0 1em; padding-left: 1.4em; }
.comment__body li { margin-bottom: .35em; }

.comment__actions {
  margin-top: .8rem;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .5rem 1.25rem;
}

/* Withdraw is a form button, and it must not look like one. Taking your own
   words back is not a call to action the page is pushing. */
.comment__quiet {
  padding: 0;
  background: none;
  border: 0;
  font: inherit;
  font-size: var(--small-size);
  color: var(--text-muted);
  text-decoration: underline;
  text-underline-offset: .2em;
  cursor: pointer;
}
.comment__quiet:hover, .comment__quiet:focus-visible { color: var(--text-body); }

/* Reporting stays shut until somebody means it. A live one-tap report beside
   every reply in an argument is a weapon; two deliberate steps is most of
   what stops it being used as one. */
.comment__report > summary,
.comment__moderate > summary {
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: var(--micro-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--text-faint);
}
.comment__report > summary:hover,
.comment__report > summary:focus-visible { color: var(--text-body); }
.comment__report .form { margin-top: 1rem; max-width: 38rem; }
.comment__report textarea, .comment__report select { width: 100%; }

.comment__moderate {
  margin-top: 1rem;
  padding: .7rem .9rem;
  border: 1px solid var(--danger);
  border-radius: var(--radius);
  background: var(--surface-card);
}
.comment__moderate > summary { color: var(--danger); }
.comment__moderate > summary:hover,
.comment__moderate > summary:focus-visible { color: #F08A6C; }
.comment__moderate form { margin-top: 1rem; }
.comment__moderate textarea { width: 100%; }

.comments__form { margin-top: 2.5rem; max-width: 46rem; }
.comments__form textarea { width: 100%; }
.comments__note {
  margin-top: 2rem;
  font-size: var(--small-size);
  color: var(--muted);
}

/* Mobile. AFTER the rules above on purpose — a media query carries no extra
   specificity, so against an equal-weight base rule it is source order that
   decides, and this file has been bitten by that twice. */
@media (max-width: 32rem) {
  .comments__list { gap: 1.5rem; }
  .comment { padding-left: .8rem; }
  /* Tap targets. The withdraw link is the one thing here somebody reaches
     for on a phone, and an underlined word is not a target. */
  .comment__quiet { padding: .4rem 0; }
  .comment__report > summary,
  .comment__moderate > summary { padding: .4rem 0; }
}

/* Replies waiting on the account page. Not a notification centre — a short
   list of what came back, with the conversation itself left where it
   belongs. See member/me.html. */
.replies { list-style: none; margin: 1.25rem 0 0; padding: 0; display: grid; gap: 1.1rem; }
.replies__item {
  padding-left: .9rem;
  border-left: 2px solid var(--border-hairline);
}
.replies__meta { font-size: var(--small-size); color: var(--muted); }
.replies__body { margin-top: .35rem; color: var(--ink-soft); }

/* ---- Email: the ledger and the previews -------------------------------- */
/* Two admin pages doing two jobs — one says a message went, the other says
   what it says. Neither keeps a body; see app/maillog.py. */

.mono-sm {
  font-family: var(--font-mono);
  font-size: var(--micro-size);
  color: var(--text-muted);
}
.muted { color: var(--text-muted); }

/* The preview frame. The email is a whole document with its own inline
   styles, so it lives in an iframe rather than being pasted into this page —
   given a white ground because that is what a mail client puts behind it, and
   these emails are dark panels that would otherwise float on nothing. */
.mailpreview__frame {
  display: block;
  width: 100%;
  height: 78vh;
  min-height: 30rem;
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius);
  background: #fff;
}

/* The plain-text part, shown as text. pre, because the line breaks in it are
   deliberate — this file has twice been bitten by a phrase wrapped through
   the middle, and seeing the real breaks is how that gets caught. */
.mailpreview__text {
  margin-top: 1rem;
  padding: 1.25rem;
  overflow-x: auto;
  background: var(--surface-raised);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius);
  font-family: var(--font-mono);
  font-size: var(--micro-size);
  line-height: 1.7;
  color: var(--ink-soft);
  white-space: pre-wrap;
  word-break: break-word;
}

@media (max-width: 32rem) {
  .mailpreview__frame { height: 60vh; }
}

/* ---- The member's flag ------------------------------------------------- */
/*
 * A national flag, and only that. Not a branch, not a unit, not a service
 * badge — where somebody is from is theirs to fly, where they served is
 * identifying, and several nations restrict exactly that for former
 * SF personnel. See the non-negotiables in CLAUDE.md.
 *
 * The glyph is the emoji flag the profile already uses. Worth knowing: Chrome
 * and Edge on WINDOWS do not render regional-indicator emoji as flags and
 * fall back to the two letters — "US" rather than the stars and stripes.
 * Everything here is sized and spaced so that fallback still reads as
 * deliberate rather than broken, which is why the country NAME sits under it
 * rather than the flag being left to speak alone.
 */

.me { display: grid; gap: 2rem; align-items: start; }

/* Two columns only when there is genuinely room. Below this the flag drops
   under the account rather than being squeezed into a margin. */
@media (min-width: 62rem) {
  .me {
    grid-template-columns: minmax(0, 34rem) 1fr;
    gap: 3rem;
  }
  .me__flag { padding-top: 6rem; }
}

.me__flag {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: .6rem;
}

/* Big. This is the one place on the site that is allowed to shout, and it is
   shouting about the member rather than about us. */
.me__flag-glyph {
  /* The floor matters more than the ceiling. On a phone this sits under the
     account details rather than beside them, so anything under about 8rem
     arrives as a small icon at the end of a list instead of the moment it is
     meant to be. */
  font-size: clamp(8rem, 20vw, 11rem);
  line-height: 1;
  /* A flag emoji carries its own colour; the shadow is what stops it floating
     on the near-black ground without a horizon. */
  filter: drop-shadow(0 6px 18px rgba(0, 0, 0, .55));
}

.me__flag-name {
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--coyote);
}

/* No country set. A quiet way to fix it, not a hole and not a nag. */
.me__flag--empty { padding: 2rem 0; }
.me__flag-ask {
  max-width: 22ch;
  font-size: var(--small-size);
  line-height: 1.6;
  color: var(--text-muted);
}

/* ---- Writing over your own flag ---------------------------------------- */
/*
 * The compose box, with the member's flag under the writing. Faint enough to
 * be atmosphere rather than decoration competing with the text — the whole
 * point of this screen is the words, and anything that makes them harder to
 * read has failed however good it looks.
 *
 * The wrapper carries the surface colour so the textarea can go transparent
 * over the flag. Keep those two together: a textarea with its own background
 * simply hides the thing it is supposed to sit on.
 */

.writeon {
  position: relative;
  background: var(--surface);
  border-radius: var(--radius);
}

.writeon__flag {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: clamp(7rem, 26vw, 15rem);
  line-height: 1;
  opacity: .07;
  pointer-events: none;
  user-select: none;
  overflow: hidden;
}

.writeon textarea {
  position: relative;
  background: transparent;
}

/* Light theme: the same opacity that reads as a whisper on near-black is a
   smudge on bone, so it comes down rather than being left to taste. */
/* THE ATTRIBUTE, NEVER THE MEDIA QUERY. There was a
   @media (prefers-color-scheme: light) block here doing the same thing, and
   it was a real bug rather than a redundancy: it fired on the BROWSER's
   claim, not on the theme actually being shown, so a dark page in a browser
   announcing light — which is every page opened from inside the Facebook app
   — got the light theme's watermark opacity. One source of truth, and it is
   the same one every other rule in this file reads. */
:root[data-theme="light"] .writeon__flag { opacity: .05; }

/* Anybody who has asked their system for more contrast has asked for exactly
   the opposite of a watermark under body text, so it goes entirely rather
   than being faded further. prefers-contrast, NOT prefers-reduced-motion —
   nothing here moves, and reaching for the motion query because it is the
   familiar one would be answering a question nobody asked. */
@media (prefers-contrast: more) {
  .writeon__flag { display: none; }
}

/* ---- Still being built -------------------------------------------------- */
/* The Muster is live and free while it is finished, and will not stay free.
   Coyote rather than the signal orange: this is a standing fact about the
   section, not an alert — something that shouts on every visit stops being
   read by the third one. */

.underway {
  margin: 2rem 0 0;
  padding: 1.1rem 1.35rem;
  background: var(--surface-card);
  border: 1px solid var(--border-hairline);
  border-left: 3px solid var(--coyote);
  border-radius: var(--radius);
  max-width: 60ch;
}
.underway__title {
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--coyote);
}
.underway p + p,
.underway__title + p {
  margin-top: .6rem;
  font-size: var(--small-size);
  line-height: 1.7;
  color: var(--ink-soft);
}

/* ---- The Vault --------------------------------------------------------- */
/* Borrows .thename's page shape — this is writing about writing and should
   read the way a yarn does, not the way a settings panel does. Only the
   illustrated control below is its own. */

.vault .underway { margin: 2.5rem 0; }

/* An ILLUSTRATION of the release control, not the control. Inert spans, not
   buttons: a real button that does nothing teaches somebody the site is
   broken rather than unfinished. */
.vault__demo {
  margin: 2rem 0 2.5rem;
  padding: 0;
}
.vault__demo-label {
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--muted);
}
.vault__demo-box {
  margin-top: .8rem;
  padding: 1.25rem 1.4rem 1.4rem;
  background: var(--surface-card);
  border: 1px solid var(--border-hairline);
  border-left: 3px solid var(--coyote);
  border-radius: var(--radius);
}
.vault__demo-title {
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--text-body);
}
.vault__demo-meta {
  margin-top: .25rem;
  font-family: var(--font-mono);
  font-size: var(--micro-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--coyote);
}
.vault__demo-actions {
  margin-top: 1.1rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .6rem .8rem;
}

/* Deliberately flat: outlined, muted, and with no hover state at all. It
   should read as a picture of a control rather than one somebody can press. */
.vault__demo-btn {
  display: inline-block;
  padding: .55rem 1rem;
  border: 1px solid var(--line-lit);
  border-radius: var(--radius);
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--text-muted);
}
.vault__demo-note { font-size: var(--small-size); color: var(--text-faint); }

.vault__demo-caption {
  margin-top: .9rem;
  font-size: var(--small-size);
  line-height: 1.7;
  color: var(--text-muted);
  max-width: 58ch;
}

/* ---- A form specimen ---------------------------------------------------- */
/* The Standing By form, shown as a numbered list of what it asks rather than
   as a form. Inert on purpose: a real field somebody can type into, on a page
   about a feature that does not exist, collects nothing and teaches them the
   site is broken. */

.specimen__list {
  margin: 0;
  padding-left: 1.4rem;
  display: grid;
  gap: 1.1rem;
}
.specimen__field { color: var(--ink-soft); }
.specimen__label {
  font-size: 1rem;
  font-weight: 700;
  color: var(--text-body);
}
.specimen__opt {
  margin-left: .5rem;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--text-faint);
}
.specimen__hint {
  margin-top: .25rem;
  font-size: var(--small-size);
  line-height: 1.6;
  color: var(--text-muted);
  max-width: 62ch;
}
.specimen__options {
  margin-top: .5rem;
  display: flex;
  flex-wrap: wrap;
  gap: .35rem;
}
.specimen__opt-chip {
  display: inline-block;
  padding: .25rem .6rem;
  border: 1px solid var(--line-lit);
  border-radius: var(--radius);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* ---- Standing By: a member's own listings ------------------------------ */
.standing-by__about { margin-top: 3.5rem; padding-top: 2.5rem; border-top: 1px solid var(--line); }

.sb-mine { margin-top: 3rem; }
.sb-card {
  margin-top: 1rem;
  padding: 1.1rem 1.35rem;
  background: var(--surface-card);
  border: 1px solid var(--border-hairline);
  border-left: 3px solid var(--coyote);
  border-radius: var(--radius);
}
.sb-card__title { font-weight: 700; color: var(--text-body); }
.sb-card__meta { margin-top: .3rem; font-size: var(--small-size); color: var(--muted); }
.sb-card__status {
  font-family: var(--font-mono);
  font-size: var(--micro-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
}
.sb-card__status--live      { color: var(--ok); }
.sb-card__status--submitted { color: var(--warn); }
/* Passed by a person and waiting on the add-on. Gold rather than the amber
   of 'submitted': nothing is pending on us any more, it is the member's
   move. See migration 042. */
.sb-card__status--approved  { color: var(--brand); }
.sb-card__status--declined  { color: #F08A6C; }
.sb-card__status--withdrawn { color: var(--text-muted); }
.sb-card__note {
  margin-top: .7rem;
  padding-left: .9rem;
  border-left: 2px solid var(--border-strong);
  font-size: var(--small-size);
  line-height: 1.6;
  color: var(--ink-soft);
}

/* Actions on your own listing: links and the withdraw form on one line, the
   form inline because a block-level <form> would push "Pull it back" onto a
   row of its own and make it look like the primary thing to do. It is not. */
.sb-card__actions {
  margin-top: .8rem;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .5rem .8rem;
  font-size: var(--small-size);
}
.sb-card__actions form { display: inline; }
.sb-card__hint {
  margin-top: .6rem;
  font-size: var(--small-size);
  line-height: 1.6;
  color: var(--text-faint);
}

/* The one paragraph the rules turn on. Set apart from the notes around it
   without being shouted — it is the reason the list reads the way it does. */
.sb-discretion {
  margin-top: 1.6rem;
  padding-left: .9rem;
  border-left: 2px solid var(--coyote);
  font-size: .95rem;
  line-height: 1.7;
}

/* ---- Standing By: a member previewing their own listing ---------------- */
.sb-preview__state { margin-top: 1.2rem; font-size: var(--small-size); color: var(--muted); }
.sb-preview__rule {
  margin: 2.4rem 0;
  border: 0;
  border-top: 1px solid var(--line);
}
.sb-preview__note {
  margin-top: 1.2rem;
  font-size: var(--small-size);
  line-height: 1.6;
  color: var(--text-faint);
}

/* The listing itself, drawn as the board will draw it. Bordered so it reads
   as a thing on a page rather than as the page. */
.sb-listing {
  padding: 1.6rem 1.75rem;
  background: var(--surface-card);
  border: 1px solid var(--border-hairline);
  border-left: 3px solid var(--coyote);
  border-radius: var(--radius);
}
.sb-listing__who {
  margin-top: 1.8rem;
  padding-top: 1.2rem;
  border-top: 1px solid var(--border-hairline);
}
.sb-listing__handle { margin-top: .4rem; font-weight: 700; color: var(--text-body); }
.sb-listing__service { margin-top: .2rem; font-size: var(--small-size); color: var(--muted); }
.sb-listing__bio { margin-top: .7rem; line-height: 1.7; color: var(--ink-soft); }
.sb-listing__badges { margin-top: .8rem; display: flex; flex-wrap: wrap; gap: .4rem; }

/* Drawn, not pressable — the board it belongs to does not exist yet, and a
   real button here would send two people real mail from a preview. Same
   treatment as .vault__demo-btn and for the same reason. */
.sb-listing__btn {
  display: inline-block;
  margin-top: .4rem;
  padding: .55rem 1rem;
  border: 1px solid var(--line-lit);
  border-radius: var(--radius);
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--text-muted);
}

/* ---- The Vault --------------------------------------------------------- */
.vault-board { padding-bottom: 1rem; }
.vault-entry .eyebrow { margin-bottom: .8rem; }
.vault-release {
  margin-top: 2.5rem;
  padding: 1rem 1.25rem;
  border: 1px solid var(--border-hairline);
  border-left: 3px solid var(--brand);
  border-radius: var(--radius);
  background: var(--surface-card);
}
.vault-release > summary {
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--brand);
}
.vault-release form { margin-top: 1.25rem; }
.vault-release select { max-width: 28rem; }


/* ---- The Q&A -----------------------------------------------------------
   Accordions are <details>, not script: keyboard access and in-page find
   come free, and a site with no build step should not grow a bundle to
   open a paragraph. Same reasoning as the report and moderation blocks on
   a yarn.

   Laid out like the Muster's rule list rather than like a marketing FAQ —
   the questions ARE the headings, and the page is read by somebody
   deciding whether to trust us rather than somebody being sold to. */

.qa { max-width: var(--body-measure); padding: 3rem 0; }
.qa__set { margin-top: 3rem; }
.qa__set .muster__section { margin-bottom: .4rem; }

.qa__item { border-bottom: 1px solid var(--border-hairline); }
.qa__item > summary {
  cursor: pointer;
  padding: 1rem .2rem;
  font-size: 1.02rem;
  line-height: 1.5;
  color: var(--text-body);
  /* The marker is the only ornament on the page; the browser's default
     triangle is fine and is what a reader already knows how to read. */
  list-style-position: outside;
}
.qa__item > summary:hover,
.qa__item > summary:focus-visible { color: var(--text-body); }
.qa__item[open] > summary { color: var(--text-body); font-weight: 600; }

.qa__answer {
  padding: 0 .2rem 1.4rem;
  max-width: 40rem;
  color: var(--ink-soft);
}
.qa__answer p { margin-bottom: .9rem; line-height: 1.75; }
.qa__answer p:last-child { margin-bottom: 0; }
.qa__answer ul { margin: 0 0 .9rem 1.1rem; }
.qa__answer li { margin-bottom: .45rem; line-height: 1.7; }
.qa__answer b { color: var(--text-body); }

/* The watching line inside an answer: it is quoted here, not shouted, so
   it loses the panel treatment it has at the foot of a board. */
.qa__answer .muster__disclaimer { margin: 0 0 .9rem; }

.qa__ask { margin-top: 4rem; }
.qa__sign-off {
  margin-top: 2.5rem;
  font-style: italic;
  font-size: var(--small-size);
  color: var(--text-faint);
}


/* ---- Membership: the two side by side ---------------------------------
   Two cards, not a comparison grid with ticks and crosses. A row of crosses
   against the free column would be a sales tactic pointed at people who are
   mostly never going to pay, and the free column is the one this site is
   actually for. */

/* Wider than the reading measure, and only here. Two columns of prose at
   68ch total is two columns of about thirty characters each, which reads
   like a phone screen cut in half. The prose on the page keeps the normal
   measure — see the rules under it. */
.membership { max-width: min(58rem, 100%); }
.membership .lede,
.membership .underway,
.membership .qa__answer { max-width: 44rem; }
.membership .qa__item > summary { max-width: 44rem; }

.tiers {
  margin-top: 2.5rem;
  display: grid;
  gap: 1.25rem;
  grid-template-columns: 1fr 1fr;
  align-items: start;
}
@media (max-width: 46rem) {
  .tiers { grid-template-columns: 1fr; }
}

/* THE FREE COLUMN STAYS PUT WHILE THE PAID ONE SCROLLS.

   The two are never going to be the same height and should not be: one is a
   list of seven things, the other is a list, a price, a checkout and an
   offer. Top-aligned, that left a column of nothing beside the free card for
   most of the page — which is what "unbalanced" was describing.

   Sticky rather than padded out. There is nothing more to say about the free
   membership, and inventing some to fill the space would be the worst of the
   available answers. This way the free column is still on screen while
   somebody reads what the paid one adds, which is also the honest comparison
   — you are looking at what you already have while you read what you would
   be buying.

   Only where there are two columns, and only when the card is short enough
   to sit still without hiding its own foot. */
@media (min-width: 46.001rem) {
  .tiers > .tier:first-child {
    position: sticky;
    top: 5.5rem;
  }
}

/* The money terms, under both columns. Not part of what either membership
   gets you — the currency, the refund position, and the two charges that
   are not this membership at all. */
.terms {
  margin-top: 1.6rem;
  padding: 1.2rem 1.4rem;
  background: var(--surface);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius);
}
.terms__line {
  margin: 0;
  font-size: var(--small-size);
  line-height: 1.65;
  color: var(--text-muted);
}
.terms__line + .terms__line { margin-top: .9rem; }
.terms__line b { color: var(--text-body); }

.tier {
  padding: 1.6rem 1.75rem;
  background: var(--surface-card);
  border: 1px solid var(--border-hairline);
  border-left: 3px solid var(--line-lit);
  border-radius: var(--radius);
}
/* The paid one is marked, not glorified: one accent edge, no glow, no
   "most popular" flag on a thing nobody can buy. */
.tier--paid { border-left-color: var(--coyote); }

.tier__name {
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--text-muted);
}
.tier__price {
  margin-top: .3rem;
  font-size: 1.6rem;
  line-height: 1.2;
  color: var(--text-body);
}
.tier--paid .tier__price { color: var(--coyote); }

.tier__line {
  margin-top: .8rem;
  font-size: var(--small-size);
  line-height: 1.7;
  color: var(--ink-soft);
}

.tier__list { margin: 1.3rem 0 0 1.1rem; }
.tier__list li { margin-bottom: .7rem; line-height: 1.65; color: var(--ink-soft); }

/* What a line actually is today. Quieter than the claim above it, because
   it is the qualification on that claim and hiding it would be the whole
   problem with pages like this. */
.tier__state {
  display: block;
  margin-top: .2rem;
  font-size: var(--small-size);
  color: var(--text-faint);
}

.tier__foot {
  margin-top: 1.4rem;
  padding-top: 1rem;
  border-top: 1px solid var(--border-hairline);
  font-size: var(--small-size);
  line-height: 1.6;
  color: var(--text-faint);
}

/* ---- The membership note on the registration form ---------------------- */
.join-tiers {
  margin: 1.6rem 0 2rem;
  padding: 1.1rem 1.35rem;
  background: var(--surface-card);
  border: 1px solid var(--border-hairline);
  border-left: 3px solid var(--coyote);
  border-radius: var(--radius);
  font-size: var(--small-size);
  line-height: 1.7;
  color: var(--ink-soft);
}
.join-tiers__title {
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--coyote);
  margin-bottom: .5rem;
}
.join-tiers__link { margin-top: .7rem; }


/* ---- Unit badges -------------------------------------------------------
   Shown small and square, on a plain ground. Deliberately no frame, glow or
   ribbon around it: the badge is somebody's real unit mark and dressing it
   up in site chrome is the exact thing the policy says this site does not
   do with them. */

.badge-img {
  width: 64px;
  height: 64px;
  object-fit: contain;
  border-radius: var(--radius);
  background: var(--surface-sunk, var(--surface-card));
}
.badge-img--large { width: 120px; height: 120px; }
/* Beside a handle in a byline. Baseline-shifted so it sits with the text
   rather than pushing the line taller. */
.badge-img--inline {
  width: 28px;
  height: 28px;
  vertical-align: -.55em;
  margin-right: .35rem;
}

.badge-mine { margin-top: 2rem; }
.badge-mine__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.1rem;
  margin-top: 1rem;
}
.badge-mine__label { font-weight: 700; color: var(--text-body); }
.badge-mine__vis { margin-top: 1.4rem; }
.badge-mine__remove { margin-top: 1rem; }

.badge-rules { margin-top: 2.5rem; }
.badge-live {
  padding: 1rem 0;
  border-bottom: 1px solid var(--border-hairline);
}
.badge-live form { margin-left: auto; display: flex; gap: .5rem; }

.profile__badge {
  margin-top: 1.2rem;
  display: flex;
  align-items: center;
  gap: .8rem;
}
.profile__badge-label { font-size: var(--small-size); color: var(--muted); }

/* The one list an administrator reads before deciding. Set apart because it
   is a checklist, not prose. */
.admin-checklist {
  margin: 1.2rem 0 0 1.1rem;
  font-size: var(--small-size);
  line-height: 1.7;
  color: var(--ink-soft);
}
.admin-checklist li { margin-bottom: .4rem; }


/* ---- Turned away from a Tier 1 feature --------------------------------
   Not styled as an error. Being told a feature is paid is not a mistake
   somebody made, and a red alert box would read as one — this is the site
   answering a question they just asked by clicking. */
.tier-locked {
  /* Capped, because this partial is included both inside a page's own
     measure (the Muster, Standing By) and directly under the content block
     (the Vault), where it would otherwise run the full width of a desktop
     and read as a site-wide banner rather than an answer to what was just
     clicked. */
  max-width: var(--body-measure);
  margin: 0 0 2rem;
  padding: 1.2rem 1.4rem;
  background: var(--surface-card);
  border: 1px solid var(--border-hairline);
  border-left: 3px solid var(--coyote);
  border-radius: var(--radius);
  line-height: 1.7;
  color: var(--ink-soft);
}
.tier-locked__title {
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--coyote);
  margin-bottom: .5rem;
}
.tier-locked .home__actions { margin-top: 1rem; }


/* ---- Audio yarns -------------------------------------------------------
   A recording is the yarn, not a decoration on it, so the block sits at the
   top of the page in the same weight as the writing below it. No waveform
   graphic: the browser's own player is the one control every reader already
   knows how to work, and a drawn waveform on a page whose audio is not
   loaded yet is a picture of data we do not have. */

.audio-block {
  margin: 0 0 2rem;
  padding: 1.2rem 1.4rem;
  background: var(--surface-card);
  border: 1px solid var(--border-hairline);
  border-left: 3px solid var(--brand, var(--coyote));
  border-radius: var(--radius);
}
.audio-block__label {
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--coyote);
  margin-bottom: .8rem;
}
.audio-block p { line-height: 1.7; color: var(--ink-soft); }
.audio-block--locked { border-left-color: var(--line-lit); }
.audio-block--waiting { border-left-color: var(--warn); }

.audio-player {
  width: 100%;
  max-width: 32rem;
  margin-top: .4rem;
  /* The browser's own control, on purpose: it is the one player every reader
     already knows how to work, it keeps the keyboard and screen-reader
     behaviour the platform provides, and a hand-built one would be a pile of
     script to reimplement a pause button.

     Chromium and WebKit draw it as a white pill, which on near-black is a
     headlight. Inverted back into the page, and ONLY on the dark theme —
     under the light theme the native control is already right, and inverting
     it there would produce a black bar on bone. */
  filter: invert(0.9) hue-rotate(180deg);
}
/* Same fix as .writeon__flag: the media query that was here answered the
   browser rather than the page. This one was half-hidden because the
   [data-theme="dark"] rule below out-specified it — which is worse, not
   better, since it meant the bug only showed on the default theme, where
   there is no attribute to win the argument. */
:root[data-theme="light"] .audio-player { filter: none; }
:root[data-theme="dark"] .audio-player { filter: invert(0.9) hue-rotate(180deg); }

/* ---- Recording one ----------------------------------------------------- */
.voice-options {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .9rem;
  margin-top: .6rem;
}
@media (max-width: 40rem) {
  .voice-options { grid-template-columns: 1fr; }
}
.voice-option {
  display: block;
  padding: 1rem 1.1rem;
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius);
  cursor: pointer;
}
.voice-option input[type="radio"] {
  /* The same accent every other control on the site uses. Left at the
     browser default it comes out system blue, which is the one colour this
     palette does not contain. */
  accent-color: var(--signal);
  width: 1.1rem;
  height: 1.1rem;
}
.voice-option:hover { border-color: var(--line-lit); }
.voice-option:focus-within { border-color: var(--coyote); }
.voice-option__name {
  display: block;
  margin: .4rem 0 .3rem;
  font-weight: 700;
  color: var(--text-body);
}
.voice-option__note {
  display: block;
  font-size: var(--small-size);
  line-height: 1.6;
  color: var(--muted);
}

.recorder {
  margin-top: 1rem;
  padding: 1rem 1.1rem;
  background: var(--surface-card);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius);
}
.recorder__btn { margin-right: .8rem; }
.recorder__timer {
  font-family: var(--font-mono);
  font-size: var(--small-size);
  color: var(--text-body);
}
.recorder__cap { color: var(--text-faint); }
.recorder__note {
  margin-top: .8rem;
  font-size: var(--small-size);
  line-height: 1.6;
  color: var(--text-faint);
}
.recorder__preview { width: 100%; max-width: 32rem; margin-top: .9rem; }

/* The marker on a card whose yarn was spoken. Same weight as the photo
   count beside it: a fact about the yarn, not a badge to chase. */
.card__spoken {
  font-family: var(--font-mono);
  font-size: var(--micro-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--coyote);
}


/* ---- Show the password you are typing ---------------------------------
   Built by app/static/js/reveal.js, so none of this exists without it. The
   button sits INSIDE the field's border rather than beside it: a control
   that looks like part of the box cannot be mistaken for the submit button,
   which on a login form is the mistake that matters. */
.reveal {
  display: flex;
  align-items: stretch;
  background: var(--surface);
  border: 1px solid var(--line-lit);
  border-radius: var(--radius);
}
.reveal:focus-within { border-color: var(--signal); }

/* The input gives up its own frame to the wrapper, so the two do not draw
   two borders around one control. */
.field .reveal input {
  flex: 1;
  min-width: 0;
  border: none;
  background: transparent;
  border-radius: 0;
}
.field .reveal input:focus-visible { border-color: transparent; outline: none; }

.reveal__btn {
  flex: none;
  padding: 0 .9rem;
  background: transparent;
  border: none;
  border-left: 1px solid var(--border-hairline);
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--text-muted);
}
.reveal__btn:hover,
.reveal__btn:focus-visible { color: var(--coyote); }


/* ---- Prices ------------------------------------------------------------
   The annual figure leads and the monthly sits under it: the page should
   not ask somebody to compare two numbers before they know what either
   buys. */
.tier__per {
  display: inline;
  margin-left: .4rem;
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--text-muted);
}
.tier__alt {
  margin-top: .35rem;
  font-size: var(--small-size);
  color: var(--muted);
}

/* ---- The way in --------------------------------------------------------
   THE MARKUP FOR THIS BLOCK SHIPPED AND THE STYLING DID NOT. .tier__buy,
   .tier__buyform, .tier__buyfoot and .tier__addon were all invented in the
   template and none of them had a single rule, so the two buttons and the
   add-on rendered as browser defaults — on the one page that asks somebody
   for money, which is the worst page on the site to look unfinished. */
.tier__buy { margin-top: 1.3rem; }

.tier__buyform {
  display: flex;
  flex-wrap: wrap;
  gap: .6rem;
  align-items: center;
}

/* THE ADD-ON SITS ABOVE THE BUTTONS, on its own full-width row, because it
   changes what both of them do. Underneath, it would read as a footnote to a
   decision already taken — and it is a second recurring charge, so it has to
   be read before the press rather than after it. */
.tier__addon {
  flex: 0 0 100%;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: .7rem;
  align-items: start;
  margin-bottom: .3rem;
  padding: .8rem .9rem;
  background: var(--surface-raised);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius);
  font-size: var(--small-size);
  line-height: 1.6;
  color: var(--text-body);
  cursor: pointer;
}
/* Keyboard users get the same affordance as the border-colour hover, since
   the box itself is the label and the input inside it is what takes focus. */
.tier__addon:focus-within { border-color: var(--signal); }

/* Deliberately larger than the 13px default. A checkbox that turns on a
   recurring charge must not be a control somebody can miss beside a
   paragraph of text — being charged for something you did not see is the
   complaint this whole block exists to avoid. */
.tier__addon input {
  width: 1.1rem;
  height: 1.1rem;
  margin: .15rem 0 0;
  accent-color: var(--brand);
  cursor: pointer;
}

.tier__buyfoot {
  margin-top: .7rem;
  font-size: var(--small-size);
  line-height: 1.6;
  color: var(--text-muted);
}

/* The First 500. Set apart because it is a price rather than a feature, and
   because it is the one thing on the page carrying a number that goes down —
   which is exactly the thing that must not look like a countdown timer on a
   shopping site. No red, no urgency, no ticking. */
.first-500 {
  margin-top: 1.4rem;
  padding: 1.1rem 1.25rem;
  /* --surface-raised, which the light theme redefines. --surface-sunk does
     not exist and the fallback resolved to the page colour, which put this
     block on the same ground as everything around it. */
  background: var(--surface-raised);
  border: 1px solid var(--border-hairline);
  border-left: 3px solid var(--brand);
  border-radius: var(--radius);
}
.first-500__name {
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--brand);
}
.first-500__price {
  margin-top: .3rem;
  font-size: 1.5rem;
  line-height: 1.2;
  /* --text-body, NOT --bone. --bone is the raw near-white from the base
     palette and does not flip with the theme, so in light mode this was
     near-white on cream — the price, the one number on the block, was the
     one thing on the page you could not read. Semantic tokens only. */
  color: var(--text-body);
}
.first-500__count {
  margin-top: .5rem;
  font-family: var(--font-mono);
  font-size: var(--small-size);
  color: var(--text-body);
}
.first-500__count b { color: var(--brand); }
.first-500__note {
  margin-top: .7rem;
  font-size: var(--small-size);
  line-height: 1.65;
  color: var(--text-faint);
}

/* --------------------------------------------------------------------------
   Expressing interest on a Muster listing
   ------------------------------------------------------------------------ */
.posting__interest {
  margin: 1.6rem 0 0;
  padding: 1.1rem 1.2rem;
  border: 1px solid var(--border-hairline);
  border-radius: 4px;
  background: var(--surface-raised);
}
.posting__interest form { margin: 0 0 .6rem; }
.posting__interest-said {
  margin: 0;
  font-weight: 600;
}
.posting__interest-list {
  list-style: none;
  margin: .4rem 0 .8rem;
  padding: 0;
}
.posting__interest-list li {
  padding: .35rem 0;
  border-bottom: 1px solid var(--border-hairline);
}
.posting__interest-list li:last-child { border-bottom: 0; }
.posting__interest-when { color: var(--text-muted); font-size: .9rem; }

/* The Tier 1 marker on a profile. Gold, because it is structural rather than
   a call to action, and deliberately quieter than .profile__verified — one
   was checked by a person, the other was paid for, and the page must not
   make them look like two rungs of the same ladder. */
.profile__tier1 {
  color: var(--brand);
  font-size: .82rem;
  letter-spacing: .06em;
  text-transform: uppercase;
}

/* The fee terms on the Muster compose form. Sits directly above the button
   that agrees to them — a fee somebody reads after pressing send is a fee
   they did not agree to. */
.fee-terms {
  margin: 1.6rem 0 1.4rem;
  padding: 1.1rem 1.2rem;
  border: 1px solid var(--border-hairline);
  border-left: 3px solid var(--brand);
  border-radius: 4px;
  background: var(--surface-raised);
}
.fee-terms__label {
  margin: 0 0 .5rem;
  font-size: .78rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--brand);
}
.fee-terms p { margin: 0 0 .7rem; }
.fee-terms p:last-child { margin-bottom: 0; }
.fee-terms__list {
  margin: .6rem 0 0;
  padding-left: 1.1rem;
}
.fee-terms__list li { margin: 0 0 .5rem; }
.fee-terms__list li:last-child { margin-bottom: 0; }

/* A member's place in the first 500, on their own page. Gold and set in the
   same small caps as the other structural marks — it is a fact about them,
   not a call to action, and it must not read like something bought. */
.founding-number {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: .5rem;
  margin: 1rem 0 0;
  padding: .8rem 1rem;
  border: 1px solid var(--border-hairline);
  border-left: 3px solid var(--brand);
  border-radius: 4px;
  background: var(--surface-raised);
}
.founding-number__mark {
  font-size: .78rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--brand);
}
.founding-number__n {
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--text-body);
}
.founding-number__of {
  font-size: .9rem;
  color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   A note about --bone, after finding five headlines invisible in light mode
   --------------------------------------------------------------------------
   --bone (#E8E6E0) is a RAW PALETTE VALUE. It does not follow the theme. On
   the dark theme --text-body resolves to it, so writing --bone looks correct
   and tests correct — and then the light theme paints near-white text onto
   cream and the words disappear entirely. The Vault's headline, the Q&A's
   open question, the Standing By sign-off, the price on the free membership
   and the First 500 figure were all doing exactly that at about 1.05:1,
   which is not "hard to read", it is not there.

   So: on anything sitting on a themed surface, use --text-body. --bone
   belongs only where the surface is dark in BOTH themes — .hero__content,
   which re-declares the tokens for that reason and says so.

   tools/check_contrast.py walks the pages and prints anything under 3:1. */

/* The First 500's second price, under its headline one. Same relationship as
   .tier__alt to .tier__price — the year is the alternative, not the offer. */
.first-500__alt {
  margin-top: .2rem;
  font-size: .95rem;
  color: var(--text-muted);
}

/* A quieter note under a fee block — a clarification, not a term. */
.fee-terms__note {
  margin-top: .8rem;
  font-size: .92rem;
  color: var(--text-muted);
}

/* The First 500, on the registration page. Deliberately quieter than the
   block on /membership — that page is selling the tier, this one is telling
   somebody what is waiting after a person has read their request. */
.join-first-500 {
  margin: 1.2rem 0 1.6rem;
  padding: 1rem 1.15rem;
  border: 1px solid var(--border-hairline);
  border-left: 3px solid var(--brand);
  border-radius: 4px;
  background: var(--surface-raised);
}
.join-first-500__title {
  margin: 0 0 .45rem;
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--brand);
}
.join-first-500 p { margin: 0; line-height: 1.65; }
.join-first-500__note {
  margin-top: .6rem !important;
  font-size: .9rem;
  color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   The Gouge
   ------------------------------------------------------------------------ */

/* The scope statement, above every box somebody writes in. Loud enough to be
   read once and quiet enough not to shout on the fortieth visit. */
.gouge-scope {
  margin: 0 0 1.2rem;
  padding: .85rem 1.1rem;
  /* The hairline matters on the light theme: --surface-raised is white
     there, and without a border this was a slab floating on cream rather
     than a callout. Same treatment as .fee-terms. */
  border: 1px solid var(--border-hairline);
  border-left: 3px solid var(--brand);
  border-radius: 4px;
  background: var(--surface-raised);
  line-height: 1.65;
}

.gouge-list { margin-top: 1.6rem; }
.gouge-row {
  padding: 1rem 0;
  border-bottom: 1px solid var(--border-hairline);
}
.gouge-row:last-child { border-bottom: 0; }
.gouge-row__cat {
  margin: 0 0 .25rem;
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--brand);
}
.gouge-row__title { margin: 0; font-size: 1.1rem; line-height: 1.4; }
.gouge-row__title a { color: var(--text-body); text-decoration: none; }
.gouge-row__title a:hover { text-decoration: underline; }
.gouge-row__meta {
  margin: .3rem 0 0;
  font-size: var(--small-size);
  color: var(--text-muted);
}

.gouge-thread { max-width: var(--measure); margin: 0 auto; }
.gouge-answers { margin-top: 2.4rem; }
.gouge-answer {
  padding: 1.2rem 0;
  border-top: 1px solid var(--border-hairline);
}
.gouge-answer--hidden { opacity: .55; }
.gouge-answer__meta {
  margin: 0 0 .5rem;
  font-size: var(--small-size);
  color: var(--text-muted);
}
.gouge-answer__actions { margin: .6rem 0 0; }
.gouge-link { margin: .7rem 0 0; word-break: break-all; }

.gouge-compose { margin-top: 2.4rem; }

.gouge-report { margin-top: 1rem; }
.gouge-report > summary {
  cursor: pointer;
  font-size: var(--small-size);
  color: var(--text-muted);
}
.gouge-report[open] > summary { margin-bottom: .8rem; }

/* The support numbers. Shown to everybody in this category and triggered by
   nothing anybody typed — see the templates. */
.gouge-support {
  margin: 2rem 0 0;
  padding: 1.1rem 1.25rem;
  border: 1px solid var(--border-hairline);
  border-left: 3px solid var(--signal);
  border-radius: 4px;
  background: var(--surface-raised);
}
.gouge-support__title {
  margin: 0 0 .5rem;
  font-weight: 700;
  color: var(--text-body);
}
.gouge-support p { margin: 0; line-height: 1.7; }

.gouge-about { margin-top: 3rem; }
.gouge-admin__excerpt {
  margin: .6rem 0;
  padding: .7rem .9rem;
  background: var(--surface-card);
  border-radius: 4px;
  line-height: 1.6;
  white-space: pre-wrap;
}
.admin-set { margin-top: 2.4rem; }

/* The six categories with what each is for. A definition list because that
   is what it is — a term and its meaning — and it reads as one on a screen
   reader without any help. */
.gouge-cats { margin: 1rem 0 0; }
.gouge-cats__row {
  padding: .8rem 0;
  border-bottom: 1px solid var(--border-hairline);
}
.gouge-cats__row:last-child { border-bottom: 0; }
.gouge-cats__name {
  margin: 0 0 .2rem;
  font-weight: 700;
  color: var(--text-body);
}
.gouge-cats__about {
  margin: 0;
  line-height: 1.65;
  color: var(--text-muted);
}

/* A note somebody has to actually see. Same shape as the Muster's
   disclaimer, gold rather than red: this is "your question will not get
   answered", not "you will be removed". It was a .field__hint under the
   textarea and the human went looking for it and could not find it. */
.gouge-note {
  margin: 0 0 .9rem;
  padding: .85rem 1.1rem;
  border: 1px solid var(--border-hairline);
  border-left: 3px solid var(--brand);
  border-radius: 4px;
  background: var(--surface-raised);
  font-size: var(--small-size);
  line-height: 1.65;
  color: var(--text-body);
}

/* --------------------------------------------------------------------------
   Where a yarn happened
   ------------------------------------------------------------------------ */

.places__warn {
  margin: .7rem 0;
  padding: .8rem 1rem;
  border: 1px solid var(--border-hairline);
  border-left: 3px solid var(--warn);
  border-radius: 4px;
  font-size: var(--small-size);
  line-height: 1.65;
  color: var(--text-body);
}
/* The country we ticked for them. Marked out from the hints around it
   because a default they do not notice is a default they did not agree to —
   it has to read as something that has already happened, not as advice. */
.places__mine {
  margin: .7rem 0;
  padding: .8rem 1rem;
  border: 1px solid var(--border-hairline);
  border-left: 3px solid var(--accent);
  border-radius: 4px;
  font-size: var(--small-size);
  line-height: 1.65;
  color: var(--text-body);
}
.places__search {
  width: 100%;
  margin: .8rem 0 .6rem;
}
/* Bounded and scrolling: 249 checkboxes inline would bury every field under
   it, and the search box is the way through the list rather than the scroll
   bar. */
.places__groups {
  max-height: 19rem;
  overflow-y: auto;
  padding: .6rem .8rem;
  border: 1px solid var(--border-hairline);
  border-radius: 4px;
  background: var(--surface-card);
}
.places__group + .places__group { margin-top: 1rem; }
.places__group-name {
  margin: 0 0 .35rem;
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--brand);
}
/* At the cap the rest go quiet rather than a press being swallowed with no
   explanation. See app/static/js/places.js. */
.places__row.is-disabled { opacity: .4; }
.places__none { margin: .6rem 0; color: var(--text-muted); }

.tag--place { border-color: var(--coyote); }

/* --------------------------------------------------------------------------
   The map
   ------------------------------------------------------------------------ */

.worldmap {
  position: relative;
  margin: 1.6rem 0 .8rem;
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius);
  background: var(--surface-card);
  overflow: hidden;
}
.worldmap__frame { display: block; background: var(--map-sea); }
.worldmap__svg {
  display: block;
  width: 100%;
  height: auto;
  touch-action: none;        /* the script handles dragging */
  cursor: grab;
}
.worldmap.is-dragging .worldmap__svg { cursor: grabbing; }

/* The sea is the card, the land is a shade up from it, and a country with
   something to read is gold. Three tones and no more: the reference map the
   human supplied works because the marked places are the only bright thing
   on it. */
.worldmap__land {
  fill: var(--map-land);
  stroke: var(--map-sea);
  stroke-width: 0.4;
  vector-effect: non-scaling-stroke;   /* borders stay hairlines when zoomed */
  transition: fill .12s ease;
}
.worldmap__land.is-tagged { fill: var(--coyote); }
.worldmap__hit:hover .worldmap__land,
.worldmap__hit:focus-visible .worldmap__land {
  fill: var(--brand);
  outline: none;
}
.worldmap__hit:focus-visible .worldmap__land {
  stroke: var(--brand-hover);
  stroke-width: 1.2;
}

.worldmap__tools {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
  padding: .6rem .8rem;
  border-top: 1px solid var(--border-hairline);
}
.worldmap__btn {
  min-width: 2.2rem;
  padding: .35rem .7rem;
  font-family: var(--font-mono);
  font-size: var(--small-size);
  color: var(--text-body);
  background: var(--surface-raised);
  border: 1px solid var(--border-hairline);
  border-radius: 3px;
  cursor: pointer;
}
.worldmap__btn:hover, .worldmap__btn:focus-visible {
  border-color: var(--brand);
  color: var(--brand);
}
.worldmap__hint { font-size: var(--small-size); color: var(--text-muted); }

.worldmap__key {
  display: flex;
  align-items: center;
  gap: .5rem;
  font-size: var(--small-size);
  color: var(--text-muted);
}
.worldmap__swatch {
  width: .85rem;
  height: .85rem;
  border-radius: 2px;
  display: inline-block;
}
.worldmap__swatch--tagged { background: var(--coyote); }

.worldmap__places { margin-top: 2.4rem; }
.worldmap__list {
  list-style: none;
  margin: .8rem 0 0;
  padding: 0;
  columns: 2;
  column-gap: 2rem;
}
@media (min-width: 60rem) { .worldmap__list { columns: 3; } }
.worldmap__list li {
  break-inside: avoid;
  padding: .3rem 0;
  display: flex;
  justify-content: space-between;
  gap: .6rem;
}
.worldmap__list .is-current { font-weight: 700; color: var(--brand); }
.worldmap__n {
  font-family: var(--font-mono);
  font-size: var(--small-size);
  color: var(--text-muted);
}
/* ---- The map on a phone -------------------------------------------------
   A world map is small at 358px and there is no clever way round that, so it
   gets the only thing that actually helps: every pixel of the screen. Edge
   to edge, and the tools sized for a thumb rather than a mouse. */
@media (max-width: 34rem) {
  /* Out through the page's own gutters — .wrap's 1.5rem, matched here. */
  .worldmap {
    margin-left: -1.5rem;
    margin-right: -1.5rem;
    border-left: 0;
    border-right: 0;
    border-radius: 0;
  }
  .worldmap__tools { padding: .55rem .9rem; }
  /* 44px targets. Zooming a map is the one thing on this page done entirely
     with a thumb, and a 30px button next to another 30px button is two
     mis-taps in a row. */
  .worldmap__btn {
    min-width: 2.9rem;
    min-height: 2.75rem;
    font-size: 1rem;
  }
  /* The hint takes the second line rather than squeezing the buttons. */
  .worldmap__hint { flex: 1 0 100%; }

  /* ONE column, down from two. This list is the map's own index and the part
     of the page that works best on a phone; two columns at 170px each turns
     "Bosnia and Herzegovina" into three lines and halves the tap target for
     no gain. */
  .worldmap__list { columns: 1; }
}

.worldmap__results { margin-top: 2.8rem; }

/* Redaction. The block character does the work; this only keeps it from
   being read as a word — no letter-spacing, and the same colour as the
   text so it reads as words removed rather than as an object. */
.yarn__redact { margin: 1.4rem 0; }
.yarn__redact > summary {
  cursor: pointer;
  font-size: var(--small-size);
  color: var(--text-muted);
}
.yarn__redact[open] > summary { margin-bottom: .8rem; }
.yarn__redacted-note {
  margin: 1rem 0;
  font-size: var(--small-size);
  color: var(--text-muted);
}

/* The admin's own record of what has been done to somebody else's writing. */
.admin-list { list-style: none; margin: 1rem 0 0; padding: 0; }
.admin-list__row {
  padding: 1rem 0;
  border-bottom: 1px solid var(--border-hairline);
}
.admin-list__row:last-child { border-bottom: 0; }

/* ---- Your orders -------------------------------------------------------
   What a member is paying for, and what they have lodged. Deliberately NOT
   a receipts page: this site keeps no amounts for a membership and no
   invoices, so the page says what it knows and hands off to the provider
   for the rest. See app/payments.py::portal_url. */

.orders { max-width: var(--body-measure); padding: 3rem 0; }
.orders__title { font-size: var(--display-l); line-height: 1.1; }
.orders__how {
  margin-top: 1.4rem;
  padding: .9rem 1.1rem;
  background: var(--surface-card);
  border: 1px solid var(--line);
  border-left: 3px solid var(--brand);
  border-radius: var(--radius);
  font-size: var(--small-size);
  line-height: 1.65;
  color: var(--text-body);
}
.orders__section { margin-top: 2.75rem; }
.orders__heading {
  font-family: var(--font-mono);
  font-size: .72rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 1rem;
}
.orders__card {
  padding: 1.3rem 1.4rem;
  background: var(--surface-card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.orders__what { margin: 0; font-size: 1.5rem; font-weight: 700; color: var(--ink); }
.orders__what--free { font-weight: 500; color: var(--ink-soft); }
.orders__facts { margin: 1rem 0 0; display: grid; gap: .6rem; }
.orders__facts > div { display: grid; grid-template-columns: 7rem 1fr; gap: 1rem; }
.orders__facts dt {
  font-family: var(--font-mono);
  font-size: .66rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted);
  padding-top: .2rem;
}
.orders__facts dd { margin: 0; font-size: var(--small-size); line-height: 1.6; color: var(--ink-soft); }
.orders__manage { margin-top: 1.3rem; display: grid; gap: .6rem; justify-items: start; }
.orders__ask {
  margin-top: 1.3rem;
  font-size: var(--small-size);
  line-height: 1.65;
  color: var(--muted);
}
.orders__note { margin-top: .8rem; font-size: var(--small-size); line-height: 1.65; color: var(--muted); }

.orders__list { list-style: none; margin: 0; padding: 0; display: grid; gap: .9rem; }
.orders__row {
  padding: 1rem 1.1rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.orders__row-title { margin: 0; font-weight: 600; color: var(--ink); }
.orders__row-meta {
  margin: .3rem 0 0;
  font-family: var(--font-mono);
  font-size: .64rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
}
.orders__row-fee { margin: .6rem 0 0; font-size: var(--small-size); line-height: 1.6; color: var(--ink-soft); }
.orders__back { margin-top: 2.5rem; font-size: var(--small-size); }

@media (max-width: 34rem) {
  .orders__facts > div { grid-template-columns: 1fr; gap: .15rem; }
}

/* ---- Chipping in --------------------------------------------------------
   Four amounts and a box. Built to read like the rest of the site rather
   than like a fundraising widget: no thermometer, no suggested-amount
   nudging, no "most people give", nothing that tells the person reading it
   what somebody else thought they should pay. */

.chip { margin-top: 1.8rem; }

.chip__amounts {
  margin: 0;
  padding: 0;
  border: 0;
}
.chip__legend {
  padding: 0;
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--muted);
}
.chip__amount {
  position: relative;
  display: inline-flex;
  margin: .7rem .6rem 0 0;
}
/* The radio itself is off screen rather than display:none — hidden that way
   it stops being focusable, and the keyboard is how half of this is used. */
.chip__amount input {
  position: absolute;
  opacity: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  cursor: pointer;
}
.chip__figure {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* 44px, and wide enough that "$25.00" never touches the frame. */
  min-width: 5.5rem;
  min-height: 2.9rem;
  padding: 0 1rem;
  font-family: var(--font-mono);
  font-size: 1rem;
  color: var(--text-body);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.chip__amount input:checked + .chip__figure {
  color: var(--ink);
  border-color: var(--brand);
  box-shadow: inset 0 0 0 1px var(--brand);
}
/* Focus is drawn on the frame, since the control that has it is invisible. */
.chip__amount input:focus-visible + .chip__figure {
  outline: 2px solid var(--signal);
  outline-offset: 2px;
}

.chip__other { margin-top: 1.6rem; }
.chip__other-label {
  display: block;
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--muted);
}
.chip__other-row {
  display: flex;
  align-items: stretch;
  gap: .5rem;
  margin-top: .5rem;
  max-width: 14rem;
}
.chip__sign {
  display: inline-flex;
  align-items: center;
  font-family: var(--font-mono);
  font-size: 1.05rem;
  color: var(--muted);
}
.chip__input {
  flex: 1;
  min-width: 0;
  font-family: var(--font-mono);
  font-size: 1.05rem;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: .65rem .8rem;
}
.chip__input:focus-visible { border-color: var(--signal); outline: none; }
.chip__bounds {
  margin-top: .5rem;
  font-size: var(--micro-size);
  line-height: 1.55;
  color: var(--muted);
}
/* The opt-in. Framed rather than left as a bare tick, because it is the one
   control on this page that changes what leaves the site — everything else
   only changes how much. */
.chip__mark {
  display: flex;
  align-items: flex-start;
  gap: .7rem;
  margin-top: 1.6rem;
  padding: .9rem 1rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  font-size: var(--small-size);
  line-height: 1.6;
  color: var(--muted);
  cursor: pointer;
}
.chip__mark input { margin-top: .25rem; flex: none; }
.chip__mark b { color: var(--text-body); }

.chip__go { margin-top: 1.6rem; }

/* On a phone the amounts take the row two at a time rather than wrapping
   one orphan onto a line of its own. */
@media (max-width: 34rem) {
  .chip__amounts { display: grid; grid-template-columns: 1fr 1fr; gap: .6rem; }
  .chip__legend { grid-column: 1 / -1; }
  .chip__amount { margin: 0; }
  .chip__figure { width: 100%; }
  .chip__other-row { max-width: none; }
  .chip__go { width: 100%; }
}

/* ---- What the scan noticed ---------------------------------------------
   Three lists on one page, and the welfare one must not look like the other
   two. It is not a moderation queue and a moderator arriving at three in the
   morning should be able to tell at a glance. */

.watch__set { margin-top: 2.5rem; }
.watch__n {
  margin-left: .5rem;
  font-family: var(--font-mono);
  font-size: var(--small-size);
  color: var(--muted);
}
/* The welfare list is marked in the colour reserved for the support page and
   Lest We Forget, never the warning red — nobody on it has done anything
   wrong. */
.watch__set--welfare .watch__row { border-left-color: var(--coyote); }
.watch__set--opsec .watch__row { border-left-color: var(--brand); }

.watch__aside {
  margin: 0 0 1rem;
  padding: .8rem 1rem;
  background: var(--surface-card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  font-size: var(--small-size);
  line-height: 1.65;
  color: var(--text-muted);
}

.watch__list { list-style: none; margin: 0; padding: 0; display: grid; gap: .8rem; }
.watch__row {
  padding: .9rem 1.1rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 3px solid var(--line-lit);
  border-radius: var(--radius);
}
.watch__meta {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--small-size);
  color: var(--text-muted);
}
.watch__meta b { color: var(--text-body); text-transform: uppercase; letter-spacing: .08em; }
.watch__go { margin: .5rem 0 0; font-size: var(--small-size); }
.watch__clear {
  margin-top: .8rem;
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
}
.watch__clear input {
  flex: 1 1 14rem;
  min-width: 0;
  font: inherit;
  font-size: var(--small-size);
  color: var(--ink);
  background: var(--surface-card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: .5rem .7rem;
}
@media (max-width: 34rem) {
  .watch__clear input, .watch__clear .btn { flex: 1 1 100%; }
}

/* --------------------------------------------------------------------------
   The consent prompt.

   Fixed to the bottom rather than a modal over the page: nobody is stopped
   from reading a yarn by a question about measurement. It does not dim the
   site, it does not trap focus, and it is not shown again once answered.

   BOTH BUTTONS ARE THE SAME BUTTON. No primary orange on "Count me in" and
   no grey on "No thanks" — see _consent.html for why that matters here more
   than on most sites.
   -------------------------------------------------------------------------- */
/* A class rule beats the browser's [hidden] every time, so the banner would
   otherwise be on the screen before the script has read the answer — and on
   for a reader who said no months ago. */
.consent[hidden] { display: none; }
.consent {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 60;
  padding: .9rem 1rem calc(.9rem + env(safe-area-inset-bottom));
  background: var(--surface-card);
  border-top: 1px solid var(--line);
  box-shadow: 0 -8px 24px rgba(0, 0, 0, .28);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: .6rem 1.4rem;
}
.consent__body {
  margin: 0;
  max-width: 46rem;
  font-size: var(--small-size);
  line-height: 1.5;
  color: var(--text-body);
}
.consent__buttons {
  margin: 0;
  display: flex;
  gap: .5rem;
}
/* On a phone the buttons go full width and side by side, because a thumb
   reaching the bottom of the screen is the whole point of putting it there. */
@media (max-width: 40rem) {
  .consent { flex-direction: column; align-items: stretch; }
  .consent__buttons { width: 100%; }
  .consent__buttons .btn { flex: 1 1 0; }
}

/* --------------------------------------------------------------------------
   Tier 1 asked for at registration.

   A fieldset rather than a styled div, because it is a real group of radios
   and a screen reader should hear it as one. Deliberately quiet: this is a
   question on a form, not an upsell panel, and the page it sits on is the
   one where somebody has least reason to trust us yet.
   -------------------------------------------------------------------------- */
.join-tier {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1rem 1.1rem;
  margin: 0 0 1.25rem;
  background: var(--surface-card);
}
.join-tier legend {
  padding: 0 .4rem;
}
.join-tier .check {
  display: flex;
  gap: .6rem;
  align-items: flex-start;
  padding: .55rem 0;
  line-height: 1.5;
}
.join-tier .check + .check {
  border-top: 1px solid var(--line);
}
.join-tier .check input {
  margin-top: .25rem;
  flex: 0 0 auto;
}
.join-tier .field__hint {
  display: block;
  margin: 0 0 .6rem;
}
.join-tier .field__hint:last-of-type {
  margin: .7rem 0 0;
}

/* What an applicant asked for, on the approval queue. No colour and no
   weight beyond the term itself — see the comment in admin/queue.html. */
.review__want {
  margin: 0 0 .8rem;
  padding: .55rem .7rem;
  font-size: var(--small-size);
  line-height: 1.5;
  color: var(--text-body);
  background: var(--surface-sunk, var(--surface-card));
  border-left: 2px solid var(--line);
  border-radius: 0 var(--radius) var(--radius) 0;
}

/* --------------------------------------------------------------------------
   The SITREP wire — what a reader sees.

   Set apart from the yarns below it on purpose. Everything else on a SITREP
   page is a member writing what they saw; this is other people's reporting,
   condensed and cited. Running the two together without a visible line
   between them would be the worst thing this feature could do.
   -------------------------------------------------------------------------- */
.wire {
  margin: 2rem 0;
  padding: 1.2rem 1.3rem;
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent, #C9A227);
  border-radius: var(--radius);
  background: var(--surface-card);
}
.wire__eyebrow {
  margin: 0 0 .3rem;
  font-family: var(--font-mono);
  font-size: var(--small-size);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.wire__title { margin: 0 0 .7rem; font-size: 1.3rem; line-height: 1.3; }
.wire__what,
.wire__foot {
  margin: 0 0 .9rem;
  font-size: var(--small-size);
  line-height: 1.55;
  color: var(--text-muted);
}
.wire__foot { margin: 1rem 0 0; }
.wire__intro { margin: 0 0 .9rem; line-height: 1.6; }
.wire__list { margin: 0; padding-left: 1.1rem; }
.wire__item { margin: 0 0 .75rem; line-height: 1.6; }
/* The citation is quieter than the claim but never hidden — an unattributed
   bullet about a war is one nobody can check. */
.wire__cite {
  display: block;
  margin-top: .15rem;
  font-size: var(--small-size);
  color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   Reviewing a draft. Claim on the left, the source text beside it.

   Two columns on a desk, stacked on a phone — and stacked in the right
   order, claim first, so the thing being checked is above the thing it is
   checked against.
   -------------------------------------------------------------------------- */
.draftline {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
  margin: 0 0 1rem;
  padding: .9rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-card);
}
.draftline.is-off { opacity: .55; }
.draftline__claim { display: flex; gap: .6rem; align-items: flex-start; }

/* The drop button, at the end of the row with the tick and the text.

   QUIET, AND DELIBERATELY NOT RED. It removes a candidate a cron job scraped
   off a news feed an hour ago, not anything a member wrote and not anything
   anybody has read — dressing it as a destructive action would teach the
   reviewer to hesitate over the one control on this page they are meant to
   use freely. It is the same weight as the tick beside it. */
.draftline__drop {
  flex: none;
  align-self: flex-start;
  color: var(--muted);
}
.draftline__drop:hover,
.draftline__drop:focus-visible { color: var(--bone); border-color: var(--muted); }

@media (max-width: 40rem) {
  /* On a phone the row is tick, text, button across about 340px, and the
     button is what gets squeezed to nothing. Let it drop under instead. */
  .draftline__claim { flex-wrap: wrap; }
  .draftline__drop { margin-left: auto; }
}
.draftline__field { flex: 1 1 auto; min-width: 0; }
.draftline__field textarea {
  width: 100%;
  font: inherit;
  line-height: 1.5;
  color: var(--ink);
  background: var(--surface-sunk, var(--bg));
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: .5rem .6rem;
  resize: vertical;
}
.draftline__meta,
.draftline__cite {
  margin: .4rem 0 0;
  font-size: var(--small-size);
  color: var(--text-muted);
}
.draftline__cite { margin: 0 0 .4rem; }
.draftline__source {
  min-width: 0;
  padding-left: 1rem;
  border-left: 1px solid var(--line);
}
.draftline__excerpt {
  margin: 0;
  font-size: var(--small-size);
  line-height: 1.55;
  color: var(--text-body);
  max-height: 11rem;
  overflow-y: auto;
}
.draftline__actions {
  display: flex;
  flex-wrap: wrap;
  gap: .6rem;
  margin: 1.2rem 0;
}
@media (max-width: 52rem) {
  .draftline { grid-template-columns: 1fr; }
  .draftline__source {
    padding-left: 0;
    padding-top: .8rem;
    border-left: 0;
    border-top: 1px solid var(--line);
  }
}

/* The source list and the queue. */
.admin-table { width: 100%; border-collapse: collapse; margin: 1rem 0; }
.admin-table th,
.admin-table td {
  text-align: left;
  padding: .6rem .5rem;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}
.admin-table tr.is-off { opacity: .5; }
.admin-table .small,
.inline-link.small { font-size: var(--small-size); }
.inline-form { display: inline-block; margin: 0 0 0 .4rem; }
@media (max-width: 40rem) {
  .admin-table, .admin-table tbody, .admin-table tr, .admin-table td {
    display: block;
    width: 100%;
  }
  .admin-table thead { display: none; }
  .admin-table tr { border-bottom: 1px solid var(--line); padding: .5rem 0; }
  .admin-table td { border: 0; padding: .2rem 0; }
}
