/* ============================================================================
 * 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 page's accent is the style guide v2 layer's brand indigo
 * (css/sx-listing-sg-v2.css). The crew's own violet is its kind chip's and its
 * manager's, as the prototype paints them, 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 layer's `.ig-kind` already reads `--ig-kind-ink`,
 *                    which the block below states — 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 manager's mark. The prototype paints the manager, its route chip and
     its card in the crew's violet (`--crew`), which the style guide v2 block
     leaves alone, so they keep it while the rest of the page takes the
     layer's brand accent. It is the prototype's own light value, which
     clears AA against all three surfaces a chip lands on *and* its 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

     It is the page's accent no longer: the page and the card agreed on the
     hue (`--sx-lt-crew` is #9B8CFF too), and the style guide now gives a page
     one brand accent and a type's colour to its chip and to what the
     prototype paints in it. Measured, not assumed — see
     tests/test_crew_listing_v4_page.py. */
  --cr-manager: #6248d8;
  --cr-manager-soft: color-mix(in srgb, var(--cr-manager) 14%, transparent);
  --cr-manager-line: color-mix(in srgb, var(--cr-manager) 34%, transparent);

  /* The specialist mark. The prototype paints members with `var(--persona)`,
     which its style guide v2 block makes the brand indigo, so the roster
     reads two-toned: the manager in the crew's violet, the members in the
     page's accent. Its own token rather than `--ig-accent` at each use,
     because the whole point of the roster is that the two colours differ,
     and a member's ink is one place to say so. */
  --cr-member: var(--ig-accent);
  --cr-member-soft: color-mix(in srgb, var(--cr-member) 16%, transparent);
  --cr-member-line: color-mix(in srgb, var(--cr-member) 40%, transparent);

  /* The kind chip: ink, ring and tint. The style guide v2 layer draws the
     chip; each type says what colour it is. The prototype states both themes
     (`#5B21B6` in light, `#D8CCFF` in dark), and the light ink reads 7.49:1 at
     its lowest, on its own tint, so both are ported as drawn. */
  --ig-kind-ink: #5b21b6;
  --ig-kind-line: rgba(120, 100, 255, 0.28);
  --ig-kind-soft: rgba(120, 100, 255, 0.08);
}

[data-theme="dark"] body.listing-v4-page.crew-listing-page {
  /* Only the literals restate. The manager's and the members' tints and lines
     are written as `var(...)` above, so they re-resolve against whichever
     value wins on this same element — the `--pp-accent` rule in CLAUDE.md —
     and `--cr-member` follows the layer's dark accent. */
  --cr-manager: #9b8cff;
  --ig-kind-ink: #d8ccff;
  --ig-kind-line: rgba(155, 140, 255, 0.3);
  --ig-kind-soft: rgba(155, 140, 255, 0.08);
}


/* ── 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(--cr-manager-soft);
  border-color: var(--cr-manager-line);
  color: var(--cr-manager);
}
.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(--cr-manager-line);
  background: var(--cr-manager-soft);
  color: var(--cr-manager);
  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(--cr-manager) 32%, var(--sx-line));
  border-radius: 16px;
  background: linear-gradient(
    140deg,
    color-mix(in srgb, var(--cr-manager) 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(--cr-manager-soft);
  border-color: var(--cr-manager-line);
  color: var(--cr-manager);
}
.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;
  }
}
