/* ============================================================================
 * Crew listing — v4 type variant
 * Ported from Sigrix_new/marketplace/Marketplace - Listing Crew v4.html
 *
 * The shell this sits on is `css/sx-listing-v4.css`, which the page loads
 * first. That prototype's stylesheet is byte-identical to the skill and
 * persona ones for all 430 lines of the shell, and adds one "Type variants —
 * crew" block — this file is that block, minus the parts of it the live
 * listing has no data behind or the shell already owns (see
 * docs/design_sync_log.md for what was refused and why).
 *
 * The accent is declared at (0,2,1) — `body.listing-v4-page.crew-listing-page`
 * — rather than at the shell's (0,1,1), so it wins on specificity and not on
 * which sheet the browser happened to parse last.
 *
 * Six blocks the prototype declares are deliberately absent:
 *
 *   .mono-title      declared in the prototype and rendered by nothing in it
 *                    (the crew hero's <h1> is a plain `.ig-title` — a crew has
 *                    a display name, not a directory name). `sx-listing-skill.css`
 *                    already declares it, and a selector in two variant sheets
 *                    resolves by parse order, which is the one thing the v4
 *                    split exists to prevent.
 *   .ig-owner-stats  the prototype restates these under "shared v4 parts kept
 *   .ig-files        for this type" because each prototype page is standalone.
 *   .ig-file*        Here they are the shell's, and the shell is what this page
 *                    loads first — restating them would be the same two-sheet
 *                    collision.
 *   .cr-cost/.cr-note the shell's `.ig-tok-cost` / `.ig-tok-note` are the same
 *                    component to within 2px of padding. Section 04 renders
 *                    those instead, so the cost cards stay one component across
 *                    all four v4 types rather than two that drift.
 *   .ig-kind--crew   the shell's `.ig-kind` already reads `--ig-accent`, which
 *                    the block below overrides — so the modifier would be a
 *                    class that styles nothing. Same refusal the persona sheet
 *                    made for `.ig-kind--persona`.
 *   .sxr-* / .sx-search  the prototype's Option B nav flyout. `components/sx_nav.html`
 *                    owns the live nav; these rules would dress markup this
 *                    page never emits.
 * ==========================================================================*/

body.listing-v4-page.crew-listing-page {
  /* The first v4 prototype to ship a light accent that actually clears AA.
     The other three are authored at data-theme="dark" only, so their light
     value had to be derived (skill #0B6E9F, persona #8C5600); this one
     declares `.sx[data-theme="light"]{--crew:#6248D8}` beside its dark
     #9B8CFF, and both measure clean against all three surfaces a chip lands
     on *and* their own 14% tint over each:

       #6248D8  6.11 / 5.86 / 5.75:1 on --sx-surface / --sx-bg / --sx-surface-2
                4.96 / 4.78 / 4.69:1 on its own tint over each
       #9B8CFF  6.43 / 7.02 / 5.97:1 and 5.20 / 5.83 / 4.78:1 dark

     So both are the prototype's own values, unmoved. Measured, not assumed —
     see tests/test_crew_listing_v4_page.py, which runs the same six readings
     the persona page's contrast test does.

     The page and the card agree on the hue. They did not at first: this page
     shipped purple while `--sx-lt-crew` was still the teal #7CE3D4 that card
     dots, nav glyphs and the type hub painted, because repainting every crew
     card is a marketplace-wide decision rather than a detail-page port. That
     decision was taken on 2026-09-19 and `--sx-lt-crew` is #9B8CFF — the same
     value this page's dark accent uses, and the one the design repo's Browse
     page has always given a crew chip.

     They are still two tokens answering two questions — `--ig-accent` is "what
     colour is this page", `--sx-lt-crew` is "which type is this card" — and the
     skill page is the live reminder that the answers can differ (green card
     dot, blue page accent). Matching here is a fact about crew, not a rule. */
  --ig-accent: #6248d8;
  --ig-accent-soft: color-mix(in srgb, var(--ig-accent) 14%, transparent);
  --ig-accent-line: color-mix(in srgb, var(--ig-accent) 34%, transparent);
  --ig-accent-ink: #ffffff;
  --ig-hero-glow-b: color-mix(in srgb, var(--ig-accent) 8%, transparent);

  /* The specialist mark. The prototype paints members with `var(--persona)`
     (#7CE3D4) so the roster reads two-toned: the manager in the crew accent,
     the members in the teal. That teal is a dark-theme value like every other
     prototype literal — 1.42:1 on white — and this page writes it as *text*
     (`.cr-who--spec`, the `.cr-when` routing pill). The shell already measured
     this exact hue for its own default accent, so the pair is reused rather
     than re-derived: #0C7065 light / #7CE3D4 dark, 5.96 / 5.72 / 5.62:1 and
     4.87 / 4.69 / 4.60:1 on tint. Its own token, not `--ig-accent`, because
     the whole point of the roster is that the two colours differ. */
  --cr-member: #0c7065;
  --cr-member-soft: color-mix(in srgb, var(--cr-member) 16%, transparent);
  --cr-member-line: color-mix(in srgb, var(--cr-member) 40%, transparent);
}

[data-theme="dark"] body.listing-v4-page.crew-listing-page {
  /* Only the literals restate. `--ig-accent-soft` / `-line`, `--ig-hero-glow-b`
     and the two `--cr-member` derivations are written as `var(...)` above, so
     they re-resolve against whichever value wins on this same element — the
     `--pp-accent` rule in CLAUDE.md. */
  --ig-accent: #9b8cff;
  --ig-accent-ink: #0c0a18;
  --cr-member: #7ce3d4;
}


/* ── section jump nav ────────────────────────────────────────────────────
   Replaces the v2 page's tab strip. The tabs hid four of the six sections
   behind a click and took the page's content out of one scroll; this names
   every section in document order and leaves all of them rendered, so the
   page is one document a buyer can scroll, search and deep-link into.

   `top` matches the site header's height, as the v2 crew page's own sticky
   tab strip did. */
.cr-jump {
  position: sticky;
  top: 60px;
  z-index: 20;
  background: color-mix(in srgb, var(--sx-bg) 86%, transparent);
  backdrop-filter: blur(14px) saturate(120%);
  -webkit-backdrop-filter: blur(14px) saturate(120%);
  border-bottom: 1px solid var(--sx-line);
}
.cr-jump-in {
  display: flex;
  align-items: center;
  gap: 2px;
  height: 46px;
  overflow-x: auto;
  scrollbar-width: none;
}
.cr-jump-in::-webkit-scrollbar {
  display: none;
}
.cr-jump a {
  padding: 6px 11px;
  border-radius: 8px;
  font-family: var(--ig-mono);
  font-size: 11px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--sx-text-3);
  white-space: nowrap;
  text-decoration: none;
}
.cr-jump a:hover {
  background: var(--sx-surface-2);
  color: var(--sx-text);
}
.cr-jump a:focus-visible {
  outline: 2px solid var(--ig-accent);
  outline-offset: 2px;
}
.cr-jump .cr-jump-cta {
  margin-left: auto;
  padding-left: 16px;
  flex: none;
}


/* ── the routed run ──────────────────────────────────────────────────────
   One captured run, drawn as the turn-by-turn exchange it was: the request,
   the manager's routing decision, the specialist's answer. The hero shows the
   runnable crew's run and section 03 the compiled chat fallback's — the same
   component both times, because the claim being made is that the two agree. */
.cr-run {
  border: 1px solid var(--sx-line);
  border-radius: 16px;
  background: var(--sx-bg-2);
  overflow: hidden;
}
.cr-run-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 11px 16px;
  border-bottom: 1px solid var(--sx-line);
  font-family: var(--ig-mono);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--sx-text-3);
}
.cr-run-head .live {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--ig-ok-text);
  letter-spacing: 0.1em;
}
.cr-turn {
  display: grid;
  grid-template-columns: 30px minmax(0, 1fr);
  gap: 13px;
  padding: 16px;
}
.cr-turn + .cr-turn {
  border-top: 1px solid var(--sx-line);
}
.cr-turn--out {
  background: var(--sx-surface);
}
.cr-who {
  width: 30px;
  height: 30px;
  border-radius: 9px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--ig-mono);
  font-size: 10.5px;
  font-weight: 600;
  border: 1px solid var(--sx-line-2);
  background: var(--sx-surface-2);
  color: var(--sx-text-2);
  flex: none;
}
.cr-who--mgr {
  background: var(--ig-accent-soft);
  border-color: var(--ig-accent-line);
  color: var(--ig-accent);
}
.cr-who--spec {
  background: var(--cr-member-soft);
  border-color: var(--cr-member-line);
  color: var(--cr-member);
}
.cr-turn .role {
  display: block;
  font-family: var(--ig-mono);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--sx-text-3);
  margin-bottom: 7px;
}
.cr-msg {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.62;
  color: var(--sx-text-2);
  text-wrap: pretty;
  white-space: pre-wrap;
}
.cr-msg + .cr-msg {
  margin-top: 10px;
}
.cr-msg strong {
  color: var(--sx-text);
  font-weight: 600;
}
/* A rendered answer. Models reply in markdown, so the transcript renders it
   (`services.user_richtext`) and the block styling comes from `.rt-body` in
   `sx-richtext.css`, which this page already loads for the reviews panel.
   Only two things differ here, so only those two are restated.

   `white-space` first: `.cr-msg` is `pre-wrap` because a plain answer's
   newlines are all it has, but a rendered one arrives as real `<p>` and `<br>`
   elements — leaving `pre-wrap` on would count every source newline twice and
   double the gap between paragraphs. (The comment thread hit exactly this;
   see the note above `.pc-body` in `sx-comments.css`.)

   Then the scale: `.rt-body` is sized for a review column at 15px, and this is
   a 13.5px chat bubble, so its heading and code sizes are pulled down to the
   bubble's own. Everything else — list indents, blockquote rule, link colour —
   is inherited rather than re-declared. */
.cr-msg--rich {
  white-space: normal;
  font-size: 13.5px;
  color: var(--sx-text-2);
}
.cr-msg--rich h4 {
  margin: 13px 0 5px;
  font-size: 13.5px;
  font-weight: 700;
  color: var(--sx-text);
}
.cr-msg--rich > :first-child {
  margin-top: 0;
}
.cr-msg--rich code,
.cr-msg--rich pre {
  font-size: 12px;
}
/* The routing decision, stated as a chip rather than prose: it is the one
   line of the transcript that is the product. */
.cr-route {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 11px;
  padding: 5px 11px;
  border-radius: 999px;
  border: 1px solid var(--ig-accent-line);
  background: var(--ig-accent-soft);
  color: var(--ig-accent);
  font-family: var(--ig-mono);
  font-size: 11px;
  letter-spacing: 0.04em;
}
.cr-foot {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 12px 16px;
  border-top: 1px dashed var(--sx-line-2);
  font-size: 12.5px;
  color: var(--sx-text-3);
}
.cr-foot svg {
  flex: none;
  color: var(--sx-text-3);
}


/* ── the owned panel (section 02, with access) ───────────────────────────
   The shell's `.ig-open` frame holds a *text* artifact on every other v4
   type, between a head and a foot that both bring their own padding. This
   type has no text to open — what an owner needs is the way in — so the
   middle is a lede plus the shell's own `.ig-incl` inventory, and all this
   variant adds is the padding the missing `.ig-pre` would have carried. The
   26px sides are the shell's, matched so head, body and foot line up. */
.cr-open-body {
  padding: 22px 26px 6px;
}
.cr-open-lede {
  margin: 0 0 6px;
  font-size: 14px;
  line-height: 1.6;
  color: var(--sx-text-2);
  text-wrap: pretty;
}
/* The roster jump sits opposite the owned tick, so it reads as the secondary
   half of the head rather than as a third button beside the foot's pair. */
.cr-open .ig-open-head .ig-jump {
  flex: none;
}


/* ── the roster ──────────────────────────────────────────────────────────
   A manager above its members, joined by a rail. Every row is a link, because
   every member is a published listing in its own right — which is the fact the
   section exists to make. */
.cr-mgr {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 16px;
  align-items: center;
  padding: 18px 20px;
  border: 1px solid color-mix(in srgb, var(--ig-accent) 32%, var(--sx-line));
  border-radius: 16px;
  background: linear-gradient(
    140deg,
    color-mix(in srgb, var(--ig-accent) 13%, var(--sx-surface)) 0%,
    var(--sx-surface) 64%
  );
  text-decoration: none;
  color: inherit;
}
.cr-av {
  width: 38px;
  height: 38px;
  border-radius: 11px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--ig-mono);
  font-size: 13px;
  font-weight: 600;
  flex: none;
  background: var(--sx-surface-2);
  border: 1px solid var(--sx-line-2);
  color: var(--sx-text-2);
}
.cr-av--mgr {
  background: var(--ig-accent-soft);
  border-color: var(--ig-accent-line);
  color: var(--ig-accent);
}
.cr-role {
  display: block;
  font-family: var(--ig-mono);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--sx-text-3);
  margin-bottom: 5px;
}
.cr-mgr h3 {
  font-family: var(--ig-display);
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 0 0 5px;
}
.cr-mgr p {
  margin: 0;
  font-size: 13px;
  line-height: 1.55;
  color: var(--sx-text-2);
  max-width: 70ch;
  text-wrap: pretty;
}
.cr-tail {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: none;
}

/* The rail is decoration only — it draws the manager-to-members join the grid
   already states in markup order, so it carries aria-hidden and no text.

   The prototype hard-codes three members and positions three drop lines at
   16.66% / 50% / 83.33%, which are exactly the card centres *for three*. A live
   crew has as many members as the seller linked, so those literals point at the
   gaps between cards for any other count — two members drew a line down the
   middle of the space between them.

   So the rail keeps only what does not depend on the count: the manager's stub
   and a bar across the row. Each drop line is drawn by the card it belongs to
   (`.cr-mem::before`), which is centred on itself and therefore right for every
   count. The bar is hidden for a lone member, where a full-width line above one
   card reads as a mistake rather than as a join. */
.cr-rail {
  position: relative;
  height: 30px;
}
.cr-rail::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 0;
  width: 1px;
  height: 16px;
  background: var(--sx-line-2);
}
.cr-rail::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 15px;
  height: 1px;
  background: var(--sx-line-2);
}
.cr-rail:has(+ .cr-members > .cr-mem:only-child)::after {
  display: none;
}
.cr-rail:has(+ .cr-members > .cr-mem:only-child)::before {
  height: 30px;
}

.cr-members {
  display: grid;
  /* auto-fit, not `repeat(3, 1fr)`: the prototype has exactly three members and
     a live crew has however many the seller linked, so a fixed three left a
     two-member roster with an empty third of the row. `minmax(0, …)` because a
     bare `1fr` floors at min-content (CLAUDE.md). */
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
  gap: 14px;
  position: relative;
}
/* Each card draws its own drop line up to the rail's bar — centred on itself,
   so it is correct for any member count. */
.cr-mem::before {
  content: "";
  position: absolute;
  top: -15px;
  left: 50%;
  width: 1px;
  height: 15px;
  background: var(--sx-line-2);
}
.cr-mem {
  position: relative;
}
.cr-mem {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 17px 18px;
  border: 1px solid var(--sx-line);
  border-radius: 14px;
  background: var(--sx-surface);
  transition: border-color 0.15s, transform 0.12s;
  text-decoration: none;
  color: inherit;
}
.cr-mem:hover {
  border-color: var(--sx-line-2);
  transform: translateY(-2px);
}
.cr-mem-top {
  display: flex;
  align-items: center;
  gap: 11px;
}
.cr-mem h4 {
  font-family: var(--ig-display);
  font-size: 15.5px;
  font-weight: 700;
  letter-spacing: -0.018em;
  margin: 0;
}
.cr-mem p {
  margin: 0;
  font-size: 13px;
  line-height: 1.55;
  color: var(--sx-text-2);
  text-wrap: pretty;
}
/* The trigger condition, which is what the manager actually routes on. Its
   own pill rather than a line of the description, because it is the only
   part of a member card a buyer reads to predict behaviour. */
.cr-when {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  align-self: flex-start;
  min-height: 23px;
  padding: 3px 10px;
  border-radius: 7px;
  border: 1px solid var(--sx-line-2);
  background: var(--sx-bg-2);
  font-family: var(--ig-mono);
  font-size: 10.5px;
  line-height: 1.45;
  letter-spacing: 0.06em;
  color: var(--cr-member);
  text-wrap: pretty;
}
.cr-when b {
  flex: none;
  align-self: flex-start;
  color: var(--sx-text-3);
  font-weight: 400;
  letter-spacing: 0.14em;
}
.cr-mem-foot {
  margin-top: auto;
  padding-top: 12px;
  border-top: 1px solid var(--sx-line);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  font-family: var(--ig-mono);
  font-size: 11px;
  color: var(--sx-text-3);
}
.cr-mem-foot .go {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: var(--ig-brand);
  font-weight: 500;
}
.cr-mem:hover .cr-mem-foot .go {
  text-decoration: underline;
}
.cr-fallthrough {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin-top: 18px;
  padding: 13px 17px;
  border: 1px dashed var(--sx-line-2);
  border-radius: 13px;
  font-size: 13px;
  line-height: 1.55;
  color: var(--sx-text-3);
}
.cr-fallthrough svg {
  flex: none;
  margin-top: 2px;
  color: var(--sx-text-3);
}


@media (max-width: 1080px) {
  .cr-members {
    grid-template-columns: minmax(0, 1fr);
  }
  /* One column, so the bar joins nothing and the stub reaches the first card
     on its own. */
  .cr-rail::after {
    display: none;
  }
  .cr-rail::before {
    height: 30px;
  }
  .cr-mem::before {
    display: none;
  }
}
@media (max-width: 760px) {
  .cr-mgr {
    grid-template-columns: auto minmax(0, 1fr);
    row-gap: 12px;
  }
  .cr-tail {
    grid-column: 1 / -1;
  }
  .cr-jump {
    top: 56px;
  }
}
