/* 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 {
  /* 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. */
  --mark-glyph:       #C7C9C4;
  --mark-glyph-hover: #E7E8E4;

  /* 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"] {
  --bg-page:        #EDEBE4;
  --surface-card:   #F5F3EC;
  --surface-raised: #FFFFFF;
  --border-hairline:#D4D1C6;
  --border-strong:  #B5B2A6;
  --text-body:      #1C1E1A;
  --text-muted:     #5C6157;
  --text-faint:     #8A8E83;
  --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. */
  --mark-glyph:       #5F636A;
  --mark-glyph-hover: #3A3D36;
}

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

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

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

.hero__caption {
  margin-top: 2rem;
  font-size: .9rem;
  font-style: italic;
  color: var(--muted);
}

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

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

.panel--wide { max-width: 46rem; }

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

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

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

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

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

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

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

.search__form { display: flex; 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; }

/* 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;
}
.ode--plain p { font-size: 1.15rem; font-style: italic; }
.ode--plain cite {
  display: block;
  margin-top: .6rem;
  font-style: normal;
  font-size: var(--micro-size);
  color: var(--muted);
}

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

.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); }
.footer-links .sep { color: var(--border-strong); 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;
}

.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;
}
.rules li b { 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);
}

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