  /* ============================================================
     Vally Explore — light theme tokens (data-section='explore')
     ============================================================ */
  :root {
    /* surfaces */
    --bg-page:        #f6f6f8;
    --bg-card:        #ffffff;
    --bg-card-hover:  #f1f1f4;
    --bg-card-active: #e9e9ee;

    /* borders */
    --border:        rgba(20, 20, 30, 0.09);
    --border-strong: rgba(20, 20, 30, 0.16);

    /* text */
    --text-primary:   #1a1a1f;
    --text-secondary: rgba(20, 20, 30, 0.60);
    --text-muted:     rgba(20, 20, 30, 0.42);

    /* explore accent — violet */
    --accent:         #6d4dff;
    --accent-text:    #6d4dff;
    --accent-bg:      rgba(124, 92, 255, 0.20);
    --accent-bg-2:    rgba(124, 92, 255, 0.28);

    /* semantic */
    --success: #1f9d6b;
    --warning: #b9791a;
    --danger:  #e5484d;

    /* glow (explore) */
    --glow-a: rgba(124, 92, 255, 0.14);
    --glow-b: rgba(167, 145, 255, 0.10);

    /* shape + depth */
    --radius-card: 12px;
    --radius-btn:  8px;
    --shadow-sm: 0 1px 2px rgba(20,20,30,.06), 0 1px 3px rgba(20,20,30,.08);
    --shadow-md: 0 6px 18px rgba(20,20,30,.12), 0 2px 6px rgba(20,20,30,.08);
    --shadow-pop: 0 14px 40px rgba(20,20,30,.18), 0 3px 10px rgba(20,20,30,.10);

    --mono: ui-monospace, 'SF Mono', 'Söhne Mono', Menlo, monospace;
  }

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

  body {
    font-family: 'Maven Pro', system-ui, sans-serif; font-size: 14px; line-height: 1.5;
    color: var(--text-primary); background: var(--bg-page); min-height: 100vh;
    -webkit-font-smoothing: antialiased;
  }

  /* thin scrollbars, vally style */
  * { scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
  *::-webkit-scrollbar { width: 6px; height: 6px; }
  *::-webkit-scrollbar-track { background: transparent; }
  *::-webkit-scrollbar-thumb { background-color: var(--border-strong); border-radius: 99px; }
  *::-webkit-scrollbar-thumb:hover { background-color: var(--text-muted); }

  /* ---------- Top bar ---------- */
  .topbar {
    display: flex; align-items: center; gap: 12px;
    background: var(--bg-card); border-bottom: 1px solid var(--border);
    padding: 0 28px; height: 60px;
  }
  .brand { display: flex; align-items: center; gap: 9px; font-size: 16px; }
  .brand-logo { height: 17px; width: auto; display: block; fill: var(--text-primary); }
  .brand .app { font-weight: 500; color: var(--text-secondary); font-size: 14px; }
  /* Identity control — shows who you are signed in as; click to sign out */
  .me-btn {
    margin-left: auto;
    display: inline-flex; align-items: center; gap: 8px; font-family: inherit;
    font-size: 13px; font-weight: 600; color: var(--text-secondary);
    background: var(--bg-card-hover); border: 1px solid var(--border); border-radius: 99px;
    padding: 4px 12px 4px 5px; cursor: pointer;
    transition: background-color .12s ease, border-color .12s ease, color .12s ease;
  }
  .me-btn:hover { background: var(--bg-card-active); border-color: var(--border-strong); color: var(--text-primary); }
  .me-btn.empty { color: var(--accent-text); padding: 5px 13px; gap: 6px; }
  .me-btn.empty i { font-size: 15px; }
  /* The one global action — a quiet accent pill in the corner, sized like the
     identity control. Hidden pre-auth (revealApp/hideApp), like the fab. */
  .btn-add {
    display: inline-flex; align-items: center; gap: 6px; font-family: inherit;
    font-size: 13px; font-weight: 600; color: var(--accent-text);
    background: var(--accent-bg); border: none; border-radius: 99px;
    padding: 7px 14px; cursor: pointer; white-space: nowrap; transition: opacity .14s ease;
  }
  .btn-add:hover { opacity: .85; }
  .btn-add i { font-size: 15px; }
  /* display:inline-flex would otherwise beat the hidden attribute. */
  .btn-add[hidden] { display: none; }
  @media (max-width: 620px) { .btn-add span { display: none; } .btn-add { padding: 7px 9px; } }
  .me-av {
    width: 26px; height: 26px; border-radius: 50%; flex-shrink: 0;
    background: var(--accent); color: #fff; font-size: 10px; font-weight: 700;
    display: grid; place-items: center;
  }

  .wrap { position: relative; max-width: 1180px; margin: 0 auto; padding: 32px 28px 80px; }

  /* ---------- Hero glow (static, explore vibe) ---------- */
  .hero-fx { position: absolute; inset: 0 0 auto 0; height: 360px; overflow: hidden; z-index: 0; pointer-events: none; }
  .glow { position: absolute; inset: 0; filter: blur(52px); }
  .glow.a { background: radial-gradient(55% 38% at 40% 40%, var(--glow-a), transparent 78%); }
  .glow.b { background: radial-gradient(28% 42% at 70% 28%, var(--glow-b), transparent 78%); }

  .wrap > *:not(.hero-fx) { position: relative; z-index: 1; }


  /* ---------- Buttons (soft accent — vally primary) ---------- */
  .btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 6px;
    font-family: inherit; font-size: 14px; font-weight: 600;
    border: none; border-radius: var(--radius-btn); cursor: pointer;
    transition: opacity .14s ease, background-color .14s ease, color .14s ease;
    height: 40px; padding: 0 16px; white-space: nowrap;
  }
  .btn-primary { background: var(--accent-bg); color: var(--accent-text); }
  .btn-primary:hover { opacity: .9; }

  /* ---------- Filter chips (status / build) ---------- */
  .chip {
    display: inline-flex; align-items: center; gap: 6px;
    font-family: inherit; font-size: 12.5px; font-weight: 500;
    background: var(--bg-card); color: var(--text-secondary);
    border: 1px solid var(--border); border-radius: 99px;
    padding: 6px 13px; cursor: pointer; transition: all .12s ease;
  }
  .chip:hover { background: var(--bg-card-hover); color: var(--text-primary); }
  /* An active chip is the only thing telling you the board is filtered, so it
     wears its own state colour (--chip-tone, set per chip in renderChips —
     green on Solved, amber on On hold, accent otherwise) as a ring around the
     word, not just a faint wash. */
  .chip.on {
    --chip-tone: var(--accent-text);
    background: color-mix(in srgb, var(--chip-tone) 14%, var(--bg-card));
    border-color: color-mix(in srgb, var(--chip-tone) 55%, transparent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--chip-tone) 16%, transparent);
    color: color-mix(in srgb, var(--chip-tone) 88%, #000);
    font-weight: 700;
  }
  .chip.on:hover { background: color-mix(in srgb, var(--chip-tone) 20%, var(--bg-card)); }
  /* live count inside a stage chip — how many cases sit at that stage */
  .chip-n { font-size: 11px; font-weight: 600; color: var(--text-muted); }
  .chip.on .chip-n { color: inherit; opacity: .8; }

  .toolbar { display: flex; flex-direction: column; align-items: stretch; gap: 12px; margin: 20px 0 22px; }

  /* ---------- Search (signature rounded pill) ---------- */
  .search {
    width: 100%; display: flex; align-items: center; gap: 12px;
    background: var(--bg-card); border: 1px solid var(--border);
    border-radius: 99px; padding: 8px 8px 8px 18px; box-shadow: var(--shadow-sm);
    transition: border-color .14s ease, box-shadow .14s ease;
  }
  .search:focus-within { border-color: var(--accent); box-shadow: var(--shadow-md); }
  .search .spark { color: var(--accent-text); font-size: 19px; flex-shrink: 0; }
  .search input {
    flex: 1; min-width: 0; border: none; outline: none; font-family: inherit;
    font-size: 14.5px; color: var(--text-primary); background: transparent;
  }
  .search input::placeholder { color: var(--text-muted); }
  .search .go {
    display: grid; place-items: center; flex-shrink: 0;
    width: 34px; height: 34px; border-radius: 99px; border: none; cursor: pointer;
    background: var(--accent-bg); color: var(--accent-text);
    font-size: 16px; transition: opacity .14s ease;
  }
  .search .go:hover { opacity: .9; }
  .status-chips { display: flex; gap: 6px; flex-wrap: wrap; }
  .status-chips + .status-chips { margin-top: 2px; }

  /* ---------- Portfolio distribution (unified overview) ---------- */
  .portfolio {
    background: var(--bg-card); border: 1px solid var(--border);
    border-radius: var(--radius-card); box-shadow: var(--shadow-sm);
    padding: 16px 18px 14px; margin-bottom: 22px;
  }
  .pf-head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 13px; }
  .pf-title { font-size: 15px; font-weight: 700; letter-spacing: -.01em; }
  .pf-count { font-size: 12.5px; color: var(--text-secondary); }
  .pf-clear {
    margin-left: auto; display: inline-flex; align-items: center; gap: 5px;
    font-family: inherit; font-size: 12px; font-weight: 500;
    color: var(--accent-text); background: transparent; border: none; cursor: pointer; padding: 2px 2px;
  }
  .pf-clear:hover { text-decoration: underline; }
  /* the bar: one continuous object, value-chain + functions softly grouped */
  .pf-bar { display: flex; align-items: stretch; height: 30px; }
  .pf-grp { display: flex; gap: 2px; min-width: 0; }
  .pf-gap { flex: 0 0 12px; }
  .seg {
    border: none; padding: 0; cursor: pointer; min-width: 7px;
    border-radius: 3px; transition: opacity .14s ease, box-shadow .12s ease;
  }
  .seg:hover { opacity: .85; }
  .seg.dim { opacity: .26; }
  .seg.on { box-shadow: 0 0 0 2px var(--bg-card), 0 0 0 4px var(--text-primary); }
  .pf-glabels { display: flex; justify-content: space-between; margin-top: 7px; }
  .pf-glabels span {
    font-size: 10px; font-weight: 700; letter-spacing: .07em;
    text-transform: uppercase; color: var(--text-muted);
  }
  .pf-legend { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-top: 14px; }
  .pf-legsep { width: 1px; height: 18px; background: var(--border-strong); margin: 0 5px; }
  .leg {
    display: inline-flex; align-items: center; gap: 7px;
    font-family: inherit; font-size: 12.5px; font-weight: 500; color: var(--text-secondary);
    background: transparent; border: 1px solid transparent; border-radius: 99px;
    padding: 4px 11px; cursor: pointer; transition: background-color .12s ease, color .12s ease;
  }
  .leg:hover { background: var(--bg-card-hover); color: var(--text-primary); }
  .leg.on { background: var(--accent-bg); color: var(--accent-text); font-weight: 600; }
  .leg .dot { width: 9px; height: 9px; border-radius: 99px; border: 1.5px solid transparent; flex-shrink: 0; }
  .leg .ln { font-size: 11px; font-weight: 600; color: var(--text-muted); }
  .leg.on .ln { color: var(--accent-text); opacity: .75; }
  .leg.zero { color: var(--text-muted); }
  .leg.zero .ln { color: var(--warning); }

  /* What the search's relevance cut held back, and the way to lift it. Quiet by
     design — it is a footnote to the results, not a banner above them. */
  .search-note {
    font-size: 11.5px; color: var(--text-muted);
    display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
    margin: -8px 0 14px;
  }

  /* ---------- Grid ---------- */
  .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 14px; }

  .card {
    position: relative;
    display: flex; flex-direction: column; gap: 12px;
    background: var(--bg-card);
    border: 1px solid color-mix(in srgb, var(--card-accent, var(--border)) 30%, var(--bg-card));
    border-radius: var(--radius-card); padding: 16px;
    box-shadow: var(--shadow-sm);
    cursor: pointer; transition: background-color .15s ease;
  }
  .card:hover { background: var(--bg-card-hover); }

  /* ---------- A card with a solution available ----------
     The whole card carries it — a green wash and a green glow instead of the
     grey shadow — so "done" is visible across the grid before a single word is
     read. The green is the only mark: a corner check on top of it read as a
     second, separate signal and confused people. The area colour lives in the
     icon next to the id; that's what says WHICH part of the business this
     belongs to. */
  .card.done {
    background: color-mix(in srgb, var(--success) 5%, var(--bg-card));
    border-color: color-mix(in srgb, var(--success) 26%, transparent);
    box-shadow: 0 2px 6px color-mix(in srgb, var(--success) 14%, transparent),
                0 8px 22px color-mix(in srgb, var(--success) 20%, transparent);
  }
  .card.done:hover { background: color-mix(in srgb, var(--success) 10%, var(--bg-card)); }

  .card-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
  .card-top-tags { display: inline-flex; align-items: center; gap: 6px; min-width: 0; }
  .cid-wrap { display: inline-flex; align-items: center; gap: 7px; min-width: 0; }
  .area-ic { font-size: 15px; line-height: 1; color: var(--card-accent, var(--text-muted)); flex-shrink: 0; }
  .cid { font-family: var(--mono); font-size: 11px; font-weight: 500; letter-spacing: .01em; color: var(--text-muted); }

  /* soft-tinted category pill */
  .area-tag {
    font-size: 11px; font-weight: 600; padding: 3px 10px; border-radius: 99px;
    white-space: nowrap; max-width: 200px; overflow: hidden; text-overflow: ellipsis;
  }

  .card h3 { font-size: 15px; font-weight: 600; line-height: 1.35; letter-spacing: -0.01em; }
  .card .desc {
    font-size: 13px; color: var(--text-secondary); line-height: 1.5; margin-top: 4px;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  }
  .card-body { margin-bottom: 0; }

  .cl { display: inline-flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 500; color: var(--text-muted); }
  .cl .d { width: 7px; height: 7px; border-radius: 99px; background: var(--border-strong); }
  .cl.klar { color: var(--success); } .cl.klar .d { background: var(--success); }

  /* ---------- Stage rail on a grid card ----------
     Four segments, one per ladder stage, + where the case stands. Replaces the
     two clarity chips that used to sit here: those said something about progress
     but never connected to the status the card showed. */
  .srail { display: flex; flex-direction: column; gap: 6px; }
  .srail-bar { display: flex; gap: 3px; }
  .srail-seg { flex: 1; height: 3px; border-radius: 99px; background: var(--border-strong); }
  .srail-seg.done { background: var(--success); }
  .srail-seg.at   { background: var(--accent); }
  .srail-lbl { display: flex; align-items: baseline; gap: 6px; font-size: 11px; font-weight: 600; color: var(--text-secondary); }
  .card.parked .srail-seg.done, .card.parked .srail-seg.at { background: var(--warning); }

  /* Two vote buttons plus the status pill can outgrow one row on a narrow
     card — the actions then wrap onto their own line, still right-aligned. */
  .card-foot {
    margin-top: auto; display: flex; align-items: center; justify-content: space-between;
    flex-wrap: wrap; gap: 8px; padding-top: 12px; border-top: 1px solid var(--border);
  }
  .pill {
    display: inline-flex; align-items: center; gap: 6px;
    font-size: 12px; font-weight: 500; color: var(--text-secondary);
  }
  .pill .dot { width: 7px; height: 7px; border-radius: 99px; }
  /* Solved is the one state worth spotting from across the grid, so its label
     carries the colour instead of only its dot. */
  .pill-done {
    color: var(--success); font-weight: 600;
    background: color-mix(in srgb, var(--success) 12%, transparent);
    border-radius: 99px; padding: 3px 10px 3px 8px; margin-left: -4px;
  }
  .foot-actions { display: flex; align-items: center; gap: 6px; margin-left: auto; }
  .act {
    display: inline-flex; align-items: center; gap: 5px;
    font-family: inherit; font-size: 12px; font-weight: 500;
    color: var(--text-secondary); background: transparent;
    border: none; border-radius: var(--radius-btn);
    padding: 5px 9px; cursor: pointer; transition: background-color .12s ease, color .12s ease;
  }
  .act:hover { background: var(--bg-card-active); color: var(--text-primary); }
  .act.on { color: var(--accent-text); font-weight: 600; }
  .act.on:hover { background: var(--accent-bg); color: var(--accent-text); }
  .act i { font-size: 14px; }
  /* On a card the vote buttons wear the detail view's pill look — a border
     says "clickable" where a bare label read as a badge. */
  .foot-actions .act {
    border: 1px solid var(--border); border-radius: 99px; padding: 4px 11px;
    transition: background-color .12s ease, color .12s ease, border-color .12s ease;
  }
  .foot-actions .act:hover { border-color: var(--border-strong); }
  .foot-actions .act.on { background: var(--accent-bg); border-color: transparent; }
  /* the high-impact flavour goes warm instead of accent, like .react-btn.hi.on */
  .act.hi.on { color: var(--warning); font-weight: 600; }
  .act.hi.on:hover { color: var(--warning); background: rgba(185,121,26,.16); }
  .foot-actions .act.hi.on { background: rgba(185,121,26,.16); }

  /* Passive status badges on a card — icon-only, no action, no border: the
     border is what separates the clickable buttons from these. */
  .card-badges { display: inline-flex; align-items: center; gap: 3px; margin-right: 2px; }
  .cbadge { display: inline-grid; place-items: center; width: 22px; height: 22px; border-radius: 6px; font-size: 13.5px; }
  .cbadge.onit { color: var(--text-muted); }

  .empty {
    grid-column: 1 / -1; padding: 48px; text-align: center; color: var(--text-muted);
    background: var(--bg-card); border: 1px dashed var(--border-strong); border-radius: var(--radius-card);
  }
  .grid-loading {
    grid-column: 1 / -1; display: flex; align-items: center; justify-content: center;
    gap: 12px; padding: 64px; color: var(--text-secondary); font-size: 14px;
  }

  /* ---------- Detail modal ---------- */
  .ov { position: fixed; inset: 0; background: rgba(20,20,30,.42); display: none; align-items: flex-start; justify-content: center; padding: 40px 16px; z-index: 50; overflow-y: auto; }
  .ov.open { display: flex; }
  /* When previewing a possible duplicate, the detail modal sits ON TOP of the
     still-open create form; a darker scrim makes the layering read clearly. */
  .ov.peek { z-index: 60; background: rgba(20,20,30,.58); }
  .peek-bar { position: sticky; top: -4px; z-index: 1; display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
    margin: -4px -4px 16px; padding: 11px 14px; border-radius: 12px;
    background: var(--accent-bg); border: 1px solid var(--accent); }
  .peek-bar .btn { white-space: nowrap; }
  .peek-note { font-size: 13px; color: var(--accent-text); font-weight: 600; }

  /* The adopt confirm sits ABOVE the peeked card (60); identity always tops all. */
  #ov-adopt.ov { z-index: 70; background: rgba(20,20,30,.62); }
  /* The auth gate sits above everything and is opaque — nothing behind it is
     usable until you are signed in. Unlike the working overlays (which start
     at the top so long content can scroll), the gate is one short card and
     centers in the window. */
  #ov-auth.ov  { z-index: 90; background: rgba(12,12,18,.94); align-items: center; }
  #modal-auth  { max-width: 420px; }

  /* Tab strip for sign in / create account / reset code. */
  .auth-tabs { display:flex; gap:4px; margin-bottom:18px; border-bottom:1px solid var(--border); }
  .auth-tab {
    appearance:none; background:none; border:0; border-bottom:2px solid transparent;
    color:var(--text-secondary); font:inherit; font-size:13px; padding:8px 10px;
    cursor:pointer; margin-bottom:-1px;
  }
  .auth-tab:hover { color: var(--text-primary); }
  .auth-tab.on { color: var(--accent-text); border-bottom-color: var(--accent-text); }
  .auth-note { font-size:12.5px; line-height:1.5; color:var(--text-secondary); margin-bottom:16px; }
  .auth-ok   { font-size:12.5px; line-height:1.5; color:var(--accent-text); margin-bottom:12px; }
  .auth-busy { opacity:.6; pointer-events:none; }
  /* Footer row: the quiet secondary action on the left, the primary CTA right.
     "Forgot your password?" lives here rather than as a tab — it is a rare
     errand, not one of the two things people come to this screen to do. */
  .auth-foot { display:flex; align-items:center; justify-content:space-between; gap:10px; margin-top:16px; }
  .auth-link {
    appearance:none; background:none; border:0; padding:0; cursor:pointer;
    font:inherit; font-size:12px; color:var(--text-secondary); text-decoration:underline;
    text-underline-offset:2px;
  }
  .auth-link:hover { color: var(--text-primary); }
  /* SSO gate: when Microsoft sign-in is configured it is the ONLY way in, so
     the button is the gate's single, unmissable action. It follows Microsoft's
     own sign-in-button convention (light field, four-square logo, plain
     wording) so it reads as "the familiar company login", not as another
     button of ours. */
  .btn-ms {
    display:flex; align-items:center; justify-content:center; gap:10px; width:100%;
    appearance:none; cursor:pointer; padding:9px 14px; border-radius:8px;
    border:1px solid var(--border); background:var(--bg-card);
    color:var(--text-primary); font:inherit; font-size:13px;
  }
  .btn-ms:hover { border-color: var(--text-secondary); }
  .btn-ms-solo { padding:12px 14px; font-size:13.5px; }
  .auth-solo-title { text-align:center; margin:8px 0 22px; }
  .auth-loading { display:flex; justify-content:center; padding:34px 0 26px; }

  /* Pre-auth: the board must not be visible, even for a frame, before we know
     who the viewer is. #app starts hidden and is revealed only once /api/cases
     has answered with real data. Without this the grid, toolbar and portfolio
     bar paint first and are briefly readable behind the gate. */
  #app { visibility: hidden; }
  #app.ready { visibility: visible; }

  /* ---------- Decision bar (adopt / return fork when reviewing a match) ---------- */
  .decision-bar { position: sticky; top: -4px; z-index: 1; margin: -4px -4px 16px;
    padding: 13px 14px; border-radius: 12px; background: var(--accent-bg); border: 1px solid var(--accent); }
  .decision-q { font-size: 13.5px; font-weight: 700; color: var(--accent-text);
    display: flex; align-items: center; gap: 8px; margin-bottom: 11px; }
  .decision-actions { display: flex; gap: 10px; flex-wrap: wrap; }
  .decision-actions .btn { flex: 1; min-width: 150px; }
  /* The two branches read as opposites: neutral "back" vs filled-accent "adopt". */
  .decision-adopt { background: var(--accent); color: #fff; }
  .decision-adopt:hover { filter: brightness(1.06); }
  .decision-adopt:disabled { opacity: .6; cursor: default; }
  .decision-note { font-size: 11.5px; color: var(--accent-text); opacity: .82; margin-top: 9px; }

  /* Adopt confirm panel internals */
  .adopt-consequence { font-size: 13px; color: var(--text-secondary); line-height: 1.5; margin-bottom: 18px; }
  .adopt-consequence b { color: var(--text-primary); font-weight: 700; }
  .adopt-lbl { font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
    color: var(--text-muted); margin-bottom: 8px; }
  .adopt-opt { font-weight: 500; letter-spacing: 0; text-transform: none; color: var(--text-muted); }
  .adopt-support { margin-bottom: 16px; }
  .adopt-note { width: 100%; font-family: inherit; font-size: 13px; color: var(--text-primary);
    background: var(--bg-card); border: 1px solid var(--border-strong); border-radius: 10px;
    padding: 10px 12px; resize: vertical; }
  .adopt-note:focus { outline: none; border-color: var(--accent); }
  .adopt-err:empty { display: none; }
  .adopt-err { margin-top: 8px; }
  .adopt-actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 18px; }

  /* Notes / additions — free-text remark, distinct from a "solution" (no seal icon). */
  .sol.note { border-left: 2px solid var(--accent); padding-left: 10px; }
  .note-txt { font-size: 12.5px; color: var(--text-primary); line-height: 1.45; }
  .modal {
    background: var(--bg-card); border: 1px solid var(--border); border-radius: 16px;
    width: 100%; max-width: 540px; box-shadow: var(--shadow-pop);
    padding: 24px 24px 20px; position: relative;
    animation: pop-in .16s ease both;
  }
  @keyframes pop-in { from { opacity: 0; transform: translateY(4px) scale(.985); } to { opacity: 1; transform: none; } }
  .modal .x {
    position: absolute; top: 16px; right: 16px; display: grid; place-items: center;
    width: 30px; height: 30px; background: transparent; border: none; border-radius: var(--radius-btn);
    font-size: 20px; color: var(--text-muted); cursor: pointer; transition: background-color .12s ease, color .12s ease;
  }
  .modal .x:hover { background: var(--bg-card-hover); color: var(--text-primary); }

  /* ---------- Detail modal: the case on the left, its ladder on the right ------
     Only the DETAIL modal is wide; identity/adopt keep the 540px single column,
     and the create form keeps its own .modal.wide. Column widths are fixed
     rather than fractional: the rail holds short labels, so letting it grow with
     the viewport would just stretch whitespace.

     HOW THE RAIL STAYS ALIGNED. Each rung and the section it grades are given
     the SAME explicit grid row (.r1 … .r4, set by railRungs() and openModal()),
     so a rung is level with its own fields for free — the row is as tall as
     whichever of the two is taller, and nothing is measured in JS. That is why
     there is no resize handler here: reflow is the browser's problem.

     row-gap MUST stay 0. The connector line between two dots is drawn by the
     upper rung and reaches into the next row (negative `bottom` below); a row
     gap would put a hole in the ladder. Sections space themselves with
     padding-top instead. */
  .modal.detail { max-width: 800px; }
  .m-cols {
    display: grid; grid-template-columns: minmax(0, 1fr) 216px;
    column-gap: 22px; row-gap: 0;
    --rung-top: 18px;   /* shared by .m-sec and .rstep so dot and heading line up */
  }
  .m-head { grid-column: 1; grid-row: 1; min-width: 0; padding-bottom: var(--rung-top); }
  /* Bottom-aligned: row 1 is as tall as the title + reactions, and a "Status"
     label pinned to the top of it floats a long way from the ladder it names.
     Sitting it at the foot of the row puts it directly above the first rung. */
  .rail-top { grid-column: 2; grid-row: 1; align-self: end; padding-bottom: 6px; }
  /* Left column: one block of fields per ladder stage. padding-top is load-bearing
     — it is what lines a section's first heading up with its rung's dot, so the
     dot offset below is derived from it. padding-bottom only has to look right:
     without it a section's last element (an "I'm on it" button, the foot of the
     share-a-solution form) sits directly on the next section's rule. Matching the
     two keeps the air above and below each divider even. */
  .m-sec {
    grid-column: 1; min-width: 0;
    padding-top: var(--rung-top); padding-bottom: var(--rung-top);
    border-top: 1px solid var(--border);
  }
  /* A section that opens with a .u-item instead of a .sec-lbl would start 14px
     lower than its rung's dot, because .u-item carries a top margin meant for
     stacking siblings. Drop it on the first one so every section's first line of
     text starts level with its dot. */
  .m-sec > .u-item:first-child { margin-top: 0; }
  .m-tail {
    grid-column: 1 / -1; grid-row: 6;
    padding-top: var(--rung-top); border-top: 1px solid var(--border);
  }
  .m-sec.r1, .rstep.r1 { grid-row: 2; }
  .m-sec.r2, .rstep.r2 { grid-row: 3; }
  .m-sec.r3, .rstep.r3 { grid-row: 4; }
  .m-sec.r4, .rstep.r4 { grid-row: 5; }

  /* ---------- The status rail ----------
     Deliberately spare: four rungs, a dot and a name each, no card around them.
     The accent rung is the one the case is working TOWARD, and it is the only
     one that carries any text — the list of things it still needs. There is no
     second state label; the highlighted rung is the state. */
  .rmap-lbl { font-size: 10.5px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--text-muted); }
  .rstep { grid-column: 2; position: relative; padding-left: 22px; padding-top: var(--rung-top); }
  /* The dot, level with the section heading opposite it — both are pushed down by
     --rung-top, but an absolutely positioned dot ignores its own padding, so the
     offset has to be added back by hand. */
  .rstep::before {
    content: ""; position: absolute; left: 0; top: calc(var(--rung-top) + 3px);
    width: 11px; height: 11px;
    border-radius: 99px; background: var(--bg-card);
    box-shadow: inset 0 0 0 2px var(--border-strong);
  }
  /* The connector down to the next dot. It has to leave its own grid row to get
     there: the next dot sits --rung-top + 3px BELOW the row boundary, so the line
     overshoots by exactly that much. Depends on row-gap being 0. */
  .rstep::after {
    content: ""; position: absolute; left: 5px; width: 1px;
    top: calc(var(--rung-top) + 16px);
    bottom: calc(-1 * (var(--rung-top) + 3px));
    background: var(--border-strong);
  }
  /* `.last` is set by railRungs(), not `:last-child` — the rungs are siblings of
     the case's own sections now, so the final rung is nowhere near last in DOM. */
  .rstep.last::after { display: none; }
  .rstep.done::before { background: var(--success); box-shadow: inset 0 0 0 2px var(--success); }
  .rstep.done::after  { background: var(--success); }
  .rstep.at::before   { background: var(--accent); box-shadow: 0 0 0 3px var(--accent-bg), inset 0 0 0 2px var(--accent); }
  .rstep-t { font-size: 12.5px; font-weight: 700; color: var(--text-secondary); letter-spacing: -.005em; }
  .rstep.done .rstep-t { color: var(--text-primary); }
  .rstep.at .rstep-t { color: var(--accent-text); }
  /* A parked case: the ladder is paused, so every rung steps back. `.parked` is
     set on each rung individually — there is no rail wrapper to hang it on. */
  .rstep.parked .rstep-t { color: var(--text-muted); }
  .rstep.parked.done::before, .rstep.parked.at::before { background: var(--warning); box-shadow: inset 0 0 0 2px var(--warning); }
  .rstep.parked.done::after { background: var(--warning); }
  .rpark {
    font-size: 11.5px; line-height: 1.45; color: var(--warning);
    background: rgba(185,121,26,.10); border: 1px solid rgba(185,121,26,.28);
    border-radius: 9px; padding: 8px 9px; margin-bottom: 12px;
  }
  .rpark b { display: flex; align-items: center; gap: 5px; font-weight: 700; margin-bottom: 3px; }

  .m-top { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; padding-right: 36px; }
  .m-title { font-size: 19px; font-weight: 700; line-height: 1.28; letter-spacing: -.015em; }
  .m-divider { height: 1px; background: var(--border); margin: 16px 0 14px; }
  .sec-lbl { font-size: 11px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--text-muted); margin-bottom: 10px; }
  .blk { margin-top: 12px; }
  .blk-head { display: flex; align-items: center; gap: 8px; margin-bottom: 5px; }
  .blk-lbl { font-size: 10.5px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--accent-text); }
  .blk-head .cl { margin-left: auto; }
  .blk-txt { font-size: 13.5px; color: var(--text-primary); line-height: 1.5; }
  .blk-txt.open-note { color: var(--text-muted); font-style: italic; }

  .pair { display: flex; gap: 10px; margin-top: 12px; }
  .pair .col { flex: 1; border-radius: 12px; padding: 12px 13px; }
  .pair .ist { background: var(--bg-card-hover); border: 1px solid var(--border); }
  .pair .ziel { background: var(--accent-bg); border: 1px solid transparent; }
  .col-lbl { font-size: 9.5px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase; margin-bottom: 6px; }
  .ist .col-lbl { color: var(--text-secondary); }
  .ziel .col-lbl { color: var(--accent-text); }
  .col-txt { font-size: 12.5px; color: var(--text-primary); line-height: 1.5; }

  .u-item { margin-top: 14px; }
  .u-txt { font-size: 13px; color: var(--text-primary); line-height: 1.5; }
  .m-tags { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 6px; }
  .tag {
    font-size: 11px; font-weight: 500; padding: 3px 10px; border-radius: 99px;
    border: 1px solid var(--border); color: var(--text-muted);
  }
  .tag-scope { border-color: var(--accent); color: var(--accent-text); font-weight: 600; }
  .tag-tool { border-color: var(--border-strong); color: var(--text-secondary); cursor: pointer; }
  .tag-tool:hover { border-color: var(--accent); color: var(--accent-text); }
  /* Small customer-facing marker on grid cards */
  .scope-tag {
    display: inline-flex; align-items: center; gap: 4px; flex-shrink: 0;
    font-size: 10.5px; font-weight: 600; padding: 3px 9px; border-radius: 99px;
    background: var(--accent-bg); color: var(--accent-text); white-space: nowrap;
  }
  .scope-tag i { font-size: 12px; }
  .avars { display: flex; margin-top: 6px; }
  .av {
    width: 28px; height: 28px; border-radius: 50%; margin-left: -7px; border: 2px solid var(--bg-card);
    background: var(--accent); color: #fff; font-size: 10px; font-weight: 700;
    display: flex; align-items: center; justify-content: center;
  }
  .av:first-child { margin-left: 0; }
  .av.more { background: var(--accent-bg); color: var(--accent-text); }
  /* Creator chip in the detail head — small-caps caption + a lone avatar,
     pushed to the row's right edge. The avatar is not part of a stack, so the
     overlap margin must not apply. */
  .m-owner { margin-left: auto; display: flex; align-items: center; gap: 7px; flex-shrink: 0; cursor: default; }
  .m-owner-lbl { font-size: 10px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--text-muted); white-space: nowrap; }
  .m-owner .av { margin-left: 0; }
  .m-owner .av.imported { background: var(--accent-bg); color: var(--accent-text); }
  .m-owner .av.imported i { font-size: 14px; }

  /* Copy-link in the modal head — icon only, in the same muted register as
     .cid, so it reads as metadata until hovered. The title/aria-label carry
     what it does. */
  .copy-link {
    display: inline-flex; align-items: center; justify-content: center;
    width: 24px; height: 24px; color: var(--text-muted);
    background: none; border: 1px solid var(--border); border-radius: 99px;
    cursor: pointer; flex-shrink: 0; padding: 0;
  }
  .copy-link i { font-size: 14px; }
  .copy-link:hover { color: var(--text-primary); border-color: var(--border-strong); background: var(--bg-card-hover); }

  /* ---------- Detail: reaction controls, named lists, solutions ---------- */
  .m-react { display: flex; flex-wrap: wrap; gap: 8px; margin: 12px 0 2px; }
  .react-btn {
    display: inline-flex; align-items: center; gap: 6px; font-family: inherit;
    font-size: 13px; font-weight: 600; color: var(--text-secondary);
    background: var(--bg-card-hover); border: 1px solid var(--border);
    border-radius: 99px; padding: 7px 14px; cursor: pointer;
    transition: background-color .12s ease, color .12s ease, border-color .12s ease;
  }
  .react-btn:hover { color: var(--text-primary); }
  .react-btn i { font-size: 16px; }
  .react-btn .rc { font-variant-numeric: tabular-nums; opacity: .75; }
  .react-btn.on { background: var(--accent-bg); border-color: transparent; color: var(--accent-text); }
  .react-btn.hi.on { background: rgba(185,121,26,.16); color: var(--warning); }

  /* Inline identity strip — makes it explicit that reactions/comments are
     attributed and that nothing here is anonymous. */
  .react-as { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-top: 9px; font-size: 11.5px; color: var(--text-muted); }
  .react-as b { color: var(--text-secondary); font-weight: 600; }
  .react-as.none { color: var(--warning); }
  .react-as.none i { font-size: 14px; }
  .link-btn { font-family: inherit; font-size: inherit; font-weight: 700; color: var(--accent-text);
    background: none; border: none; padding: 0; cursor: pointer; text-decoration: underline; }
  .react-as.none .link-btn { color: var(--warning); }

  .named-row { display: flex; align-items: center; gap: 10px; margin-top: 8px; }
  .named-lbl { font-size: 10px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--text-muted); min-width: 96px; }

  .sol { border: 1px solid var(--border); border-radius: 10px; padding: 10px 12px; margin-top: 8px; }
  .sol-head { display: flex; align-items: center; gap: 7px; font-size: 13px; font-weight: 600; }
  .sol-head i { color: var(--success); flex-shrink: 0; }
  .sol-head a { color: var(--accent-text); text-decoration: none; word-break: break-all; }
  .sol-head a:hover { text-decoration: underline; }
  .sol-note { font-size: 12.5px; color: var(--text-primary); line-height: 1.45; margin-top: 5px; }
  .sol-by { font-size: 11px; color: var(--text-muted); margin-top: 6px; }
  .sol-empty { font-size: 12.5px; color: var(--text-muted); margin-top: 4px; }
  .sol-form { margin-top: 10px; display: flex; flex-direction: column; gap: 8px; }
  .sol-form input, .sol-form textarea {
    font-family: inherit; font-size: 13px; color: var(--text-primary);
    background: var(--bg-card-hover); border: 1px solid var(--border);
    border-radius: 8px; padding: 8px 10px; resize: vertical;
  }
  .sol-form input:focus, .sol-form textarea:focus { outline: none; border-color: var(--accent); }
  .sol-actions { display: flex; align-items: center; justify-content: flex-end; gap: 10px; }
  .sol-err { margin-right: auto; font-size: 12px; color: var(--danger); }
  .sol-as { font-size: 11px; color: var(--text-muted); }
  .sol-err:empty + .sol-as { margin-right: auto; }
  .sol-as b { color: var(--text-secondary); font-weight: 600; }
  .sol-as.none { color: var(--warning); }
  /* The identity strip closes the tail; give it the footer spacing the author
     line used to have (the author itself now lives in the head as .m-owner). */
  .m-tail .react-as { margin-top: 16px; }
  .m-pill {
    display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 600;
    padding: 4px 11px; border-radius: 99px; background: var(--accent-bg); color: var(--accent-text);
  }

  /* ---------- Similar / related cases ---------- */
  .sim-block { margin-top: 4px; }
  .sim-block.warn {
    background: rgba(185,121,26,.10); border: 1px solid rgba(185,121,26,.30);
    border-radius: 12px; padding: 12px 13px; margin-bottom: 16px;
  }
  .sim-head { display: flex; align-items: flex-start; gap: 9px; margin-bottom: 9px; }
  .sim-head i { font-size: 16px; flex-shrink: 0; margin-top: 1px; }
  .sim-block.warn .sim-head i { color: var(--warning); }
  .sim-block:not(.warn) .sim-head i { color: var(--accent-text); }
  .sim-title-lbl { font-size: 12px; font-weight: 700; color: var(--text-primary); line-height: 1.35; }
  .sim-block.warn .sim-title-lbl { color: var(--warning); }
  .sim-sub { font-size: 11.5px; color: var(--text-secondary); line-height: 1.4; margin-top: 1px; }
  .sim-list { display: flex; flex-direction: column; gap: 6px; }
  .sim-row {
    display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
    background: var(--bg-card); border: 1px solid var(--border); border-radius: 10px;
    padding: 8px 10px; cursor: pointer; transition: background-color .12s ease, border-color .12s ease;
  }
  .sim-row:hover { background: var(--bg-card-hover); border-color: var(--border-strong); }
  .sim-main { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
  .sim-id { font-size: 10px; font-weight: 700; letter-spacing: .04em; color: var(--text-muted); }
  .sim-title { font-size: 12.5px; font-weight: 600; color: var(--text-primary); line-height: 1.35;
    overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
  /* Why the two look alike, in the model's words (api/similar → lib/verify).
     A sentence naming what they share tells you more than the percentage does. */
  .sim-reason { font-size: 11.5px; color: var(--text-secondary); line-height: 1.35; margin-top: 2px; }
  .sim-meta { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
  /* An archived match is worth flagging, not hiding: it means we already looked
     at this and set it aside. */
  .sim-flag {
    font-size: 10px; font-weight: 700; letter-spacing: .03em; text-transform: uppercase;
    color: var(--text-muted); border: 1px solid var(--border-strong);
    border-radius: 99px; padding: 1px 7px; white-space: nowrap;
  }
  .sim-pct {
    font-size: 11px; font-weight: 700; color: var(--accent-text);
    background: var(--accent-bg); border-radius: 99px; padding: 2px 8px; white-space: nowrap;
  }
  .sim-loading { font-size: 12px; color: var(--text-muted); display: flex; align-items: center; gap: 7px; }
  .sim-loading i { font-size: 14px; animation: sim-spin 1s linear infinite; }
  @keyframes sim-spin { to { transform: rotate(360deg); } }
  /* "we're searching" row above the create form */
  .sim-check { margin-bottom: 16px; }

  /* Found matches — made deliberately prominent so it isn't scrolled past. */
  .sim-block.warn.big {
    padding: 16px; margin-bottom: 18px;
    box-shadow: 0 0 0 3px rgba(185,121,26,.08);
  }
  .sim-block.warn.big .sim-head i { font-size: 22px; }
  .sim-block.warn.big .sim-title-lbl { font-size: 14px; }
  .sim-block.warn.big .sim-sub { font-size: 12.5px; }

  /* Nothing similar found — green reassurance that encourages adding. Only ever
     shown when the check ran and genuinely returned no match. */
  .sim-block.ok {
    background: rgba(31,157,107,.10); border: 1px solid rgba(31,157,107,.30);
    border-radius: 12px; padding: 12px 13px; margin-bottom: 16px;
  }
  .sim-block.ok .sim-head { margin-bottom: 0; }
  .sim-block.ok .sim-head i { color: var(--success); }
  .sim-block.ok .sim-title-lbl { color: var(--success); }

  /* Neutral panel, used for two things that are both "no alarm, but read this":
     the check couldn't run, and there is related-but-not-duplicate work. Neither
     the amber warning nor the green all-clear, because neither claim is true. */
  .sim-block.info {
    background: var(--bg-card); border: 1px solid var(--border);
    border-radius: 12px; padding: 12px 13px; margin-bottom: 16px;
  }
  .sim-block.info .sim-head i { color: var(--text-muted); }
  /* No list under it → the head is the whole panel, so drop its bottom gap. */
  .sim-block.info .sim-head:last-child { margin-bottom: 0; }

  /* ---------- New use case modal ---------- */
  .modal.wide { max-width: 620px; }
  .m-sub { font-size: 13px; color: var(--text-secondary); line-height: 1.5; margin: 2px 0 16px; padding-right: 36px; }

  /* segmented control (Offload / manual) */
  .seg {
    display: flex; gap: 4px; padding: 4px; margin-bottom: 18px;
    background: var(--bg-card-hover); border: 1px solid var(--border); border-radius: 10px;
  }
  .seg button {
    flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 7px;
    font-family: inherit; font-size: 13px; font-weight: 600; color: var(--text-secondary);
    background: transparent; border: none; border-radius: 7px; padding: 9px 12px; cursor: pointer;
    transition: background-color .14s ease, color .14s ease, box-shadow .14s ease;
  }
  .seg button i { font-size: 15px; }
  .seg button.on { background: var(--bg-card); color: var(--accent-text); box-shadow: var(--shadow-sm); }

  /* offload / brain-dump pane */
  /* ---------- Offload = chat with an AI colleague ---------- */
  .chat { border: 1px solid var(--border-strong); border-radius: 14px; overflow: hidden; background: var(--bg-card); }
  .chat-head {
    display: flex; align-items: center; gap: 10px; padding: 11px 14px;
    border-bottom: 1px solid var(--border); background: var(--bg-card-hover);
  }
  .chat-ava {
    width: 34px; height: 34px; border-radius: 50%; flex-shrink: 0; display: grid; place-items: center;
    background: var(--accent-bg); color: var(--accent-text); font-size: 17px;
  }
  .chat-name { font-size: 13.5px; font-weight: 700; display: flex; align-items: center; gap: 7px; }
  .chat-badge {
    font-size: 9.5px; font-weight: 700; letter-spacing: .04em; color: var(--accent-text);
    background: var(--accent-bg); border-radius: 5px; padding: 1px 5px;
  }
  .chat-status { font-size: 11.5px; color: var(--text-secondary); display: flex; align-items: center; gap: 6px; margin-top: 1px; }
  .chat-status .dot { width: 7px; height: 7px; border-radius: 50%; background: #22c55e; box-shadow: 0 0 0 2px rgba(34,197,94,.22); }
  .chat-body {
    padding: 16px 14px; display: flex; flex-direction: column; gap: 10px;
    background: var(--bg-page); min-height: 96px;
  }
  .msg { display: flex; gap: 8px; align-items: flex-end; max-width: 100%; }
  .msg.out { flex-direction: row-reverse; }
  .msg-ava {
    width: 26px; height: 26px; border-radius: 50%; flex-shrink: 0; display: grid; place-items: center;
    background: var(--accent-bg); color: var(--accent-text); font-size: 13px;
  }
  .bubble { font-size: 13.5px; line-height: 1.5; padding: 9px 13px; border-radius: 14px; max-width: 80%; word-break: break-word; }
  .msg.in .bubble { background: var(--bg-card); border: 1px solid var(--border); border-bottom-left-radius: 5px; color: var(--text-primary); }
  .msg.out .bubble { background: var(--accent-text); color: #fff; border-bottom-right-radius: 5px; white-space: pre-wrap; }
  .bubble.typing { display: inline-flex; gap: 4px; align-items: center; padding: 12px 13px; }
  .bubble.typing span { width: 6px; height: 6px; border-radius: 50%; background: var(--text-muted); animation: typing 1.2s infinite; }
  .bubble.typing span:nth-child(2) { animation-delay: .18s; }
  .bubble.typing span:nth-child(3) { animation-delay: .36s; }
  @keyframes typing { 0%,60%,100% { transform: translateY(0); opacity: .35; } 30% { transform: translateY(-3px); opacity: 1; } }
  .chat-composer {
    display: flex; align-items: flex-end; gap: 8px; padding: 9px 10px 9px 14px;
    border-top: 1px solid var(--border); background: var(--bg-card); transition: box-shadow .14s ease;
  }
  .chat-composer:focus-within { box-shadow: inset 0 2px 0 -1px var(--accent-bg-2); }
  .brain {
    flex: 1; min-height: 38px; max-height: 168px; resize: none; overflow-y: auto;
    font-family: inherit; font-size: 14px; line-height: 1.5;
    color: var(--text-primary); background: transparent; border: none; padding: 8px 0;
  }
  .brain:focus { outline: none; }
  .brain::placeholder { color: var(--text-muted); }
  .chat-send {
    width: 38px; height: 38px; flex-shrink: 0; border-radius: 50%; border: none; cursor: pointer;
    background: var(--accent-text); color: #fff; display: grid; place-items: center; font-size: 16px;
    transition: opacity .12s ease, transform .12s ease;
  }
  .chat-send:hover { opacity: .9; }
  .chat-send:active { transform: scale(.94); }
  .offload-actions { display: flex; align-items: center; gap: 10px; margin-top: 12px; flex-wrap: wrap; }
  .btn-ghost-sm {
    font-family: inherit; font-size: 12.5px; font-weight: 500; color: var(--text-secondary);
    background: transparent; border: 1px solid var(--border-strong); border-radius: 99px;
    padding: 7px 13px; cursor: pointer; transition: all .12s ease;
  }
  .btn-ghost-sm:hover { background: var(--bg-card-hover); color: var(--text-primary); }
  .offload-note { font-size: 11.5px; color: var(--text-muted); }

  .thinking { display: flex; align-items: center; gap: 11px; padding: 22px 4px; color: var(--text-secondary); font-size: 14px; }
  .spinner {
    width: 20px; height: 20px; border-radius: 50%; flex-shrink: 0;
    border: 2.5px solid var(--accent-bg-2); border-top-color: var(--accent); animation: spin .8s linear infinite;
  }
  @keyframes spin { to { transform: rotate(360deg); } }

  .gen-banner {
    display: flex; align-items: center; gap: 9px; font-size: 12.5px; line-height: 1.45;
    background: var(--accent-bg); color: var(--accent-text); border-radius: 10px; padding: 10px 13px; margin-bottom: 16px;
  }
  .gen-banner.warn { background: rgba(185,121,26,.12); color: var(--warning); }
  .gen-banner i { font-size: 16px; flex-shrink: 0; }

  /* Transient toast for action errors (reactions have no inline error slot). */
  .toast {
    position: fixed; left: 50%; bottom: 24px; transform: translate(-50%, 12px);
    display: flex; align-items: center; gap: 9px; max-width: min(92vw, 460px);
    font-size: 13px; font-weight: 500; line-height: 1.4;
    padding: 11px 15px; border-radius: 10px; box-shadow: var(--shadow-pop);
    background: var(--bg-card); border: 1px solid var(--border); color: var(--text-primary);
    opacity: 0; pointer-events: none; transition: opacity .16s ease, transform .16s ease; z-index: 200;
  }
  .toast.show { opacity: 1; transform: translate(-50%, 0); }
  /* The tints are mixed over the opaque card colour, not alpha over the page —
     the toast floats above modals, and an alpha background lets the text
     underneath bleed through the message. */
  .toast.err { background: color-mix(in srgb, var(--danger) 12%, var(--bg-card)); border-color: var(--danger); color: var(--danger); }
  .toast.ok  { background: color-mix(in srgb, var(--success) 12%, var(--bg-card)); border-color: var(--success); color: var(--success); }
  .toast i { font-size: 17px; flex-shrink: 0; }

  /* ---------- Feedback button (bottom right, every screen) ----------
     Deliberately at z-index 40, BELOW every overlay (.ov is 50, up to #ov-auth at
     90): with a modal open the button sits dimmed behind the scrim and is
     unclickable, which is exactly what we want — no JS needed to hide it.
     The toast above is z-index 200 but has pointer-events:none, so a toast draws
     over the button for its 4.2s while clicks still reach it. The media query
     only stops the two overlapping visually on a narrow window.
     It is hidden until revealApp(), so it never paints over the sign-in gate. */
  .fab {
    position: fixed; right: 24px; bottom: 24px; z-index: 40;
    display: grid; place-items: center; width: 48px; height: 48px;
    background: var(--accent); color: #fff;
    border: none; border-radius: 50%; cursor: pointer;
    box-shadow: var(--shadow-md);
    transition: transform .12s ease, box-shadow .12s ease, filter .12s ease;
  }
  /* display:grid would otherwise beat the hidden attribute. */
  .fab[hidden] { display: none; }
  .fab i { font-size: 22px; }
  .fab:hover { filter: brightness(1.06); box-shadow: var(--shadow-pop); transform: translateY(-1px); }
  .fab:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 3px; }
  @media (max-width: 620px) { .fab { bottom: 84px; } }   /* clears the toast band */

  /* ---------- First-login onboarding: welcome modal + guided tour ----------
     The tour layer sits at z-index 80 — the free rung between #ov-adopt (70)
     and #ov-auth (90). It must draw OVER the detail modal it opens (two tour
     steps live inside it), but a session expiry mid-tour still puts the auth
     gate on top of everything. The welcome modal itself is a plain .ov at 50,
     like every other modal — it never stacks with anything. */

  /* Welcome modal extras */
  .welcome-art { margin: 2px 0 14px; }
  .welcome-art svg { display: block; width: 100%; height: auto; }
  .welcome-points { list-style: none; margin: 14px 0 20px; display: grid; gap: 12px; }
  .welcome-points li { display: flex; gap: 10px; align-items: flex-start; font-size: 13px; line-height: 1.5; color: var(--text-secondary); }
  .welcome-points li b { color: var(--text-primary); font-weight: 600; }
  .welcome-points li i { font-size: 17px; color: var(--accent-text); flex-shrink: 0; margin-top: 2px; }
  .welcome-actions { display: flex; justify-content: flex-end; gap: 10px; padding-top: 16px; border-top: 1px solid var(--border); }

  /* Topbar replay button — a round, quiet sibling of .me-btn. */
  .tour-replay {
    display: grid; place-items: center; width: 30px; height: 30px; flex-shrink: 0;
    font-size: 16px; color: var(--text-secondary);
    background: var(--bg-card-hover); border: 1px solid var(--border); border-radius: 50%;
    cursor: pointer; transition: background-color .12s ease, border-color .12s ease, color .12s ease;
  }
  .tour-replay:hover { background: var(--bg-card-active); border-color: var(--border-strong); color: var(--text-primary); }
  /* display:grid would otherwise beat the hidden attribute. */
  .tour-replay[hidden] { display: none; }
  /* The refresh button shares .tour-replay's look; while its fetch is in
     flight the icon spins and further clicks are ignored (disabled). */
  .tour-replay.spinning i { animation: refresh-spin .8s linear infinite; }
  .tour-replay:disabled { cursor: default; }
  @keyframes refresh-spin { to { transform: rotate(360deg); } }

  /* The tour layer: a transparent full-viewport click-blocker (the tour is
     look-don't-touch, and a box-shadow alone is not hit-testable), one spot
     div whose giant box-shadow paints the dim AROUND the highlighted element
     — nothing paints over the element itself, so it stays crisp — and the
     tooltip card. All geometry is set by positionTour(); the transitions make
     the spot glide between steps, and .no-anim turns them off while the
     tracking loop follows a scrolling target (chasing through a transition
     looks like rubber-banding). */
  #tour-layer { position: fixed; inset: 0; z-index: 80; }
  #tour-layer[hidden] { display: none; }
  .tour-spot {
    position: fixed; top: 50%; left: 50%; width: 0; height: 0;
    border-radius: 12px;
    box-shadow: 0 0 0 200vmax rgba(20,20,30,.55);
    outline: 2px solid var(--accent); outline-offset: 2px;
    /* One eased glide per step change — fast out of the blocks, soft landing.
       The tracking loop suppresses this via .no-anim while it follows a
       scrolling target frame by frame. */
    transition: top .45s cubic-bezier(.22,.85,.3,1), left .45s cubic-bezier(.22,.85,.3,1),
                width .45s cubic-bezier(.22,.85,.3,1), height .45s cubic-bezier(.22,.85,.3,1);
  }
  .tour-tip {
    position: fixed; top: 50%; left: 50%; width: 320px; max-width: calc(100vw - 32px);
    background: var(--bg-card); border: 1px solid var(--border); border-radius: 14px;
    box-shadow: var(--shadow-pop); padding: 14px 16px;
    /* The tip never glides across the screen — it fades out, is re-placed
       while invisible, and fades back in (showTourStep's choreography). */
    transition: opacity .17s ease, transform .17s ease;
  }
  .tour-tip.out { opacity: 0; transform: translateY(6px); pointer-events: none; }
  #tour-layer .no-anim { transition: none; }
  .tour-tip-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
  .tour-count { font-size: 10.5px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--text-muted); }
  .tour-skip {
    font-family: inherit; font-size: 11.5px; font-weight: 500; color: var(--text-muted);
    background: none; border: none; cursor: pointer; padding: 2px 4px; border-radius: 4px;
  }
  .tour-skip:hover { color: var(--text-primary); }
  .tour-tip h4 { font-size: 15px; font-weight: 700; margin: 0 0 4px; }
  .tour-tip p { font-size: 12.5px; line-height: 1.55; color: var(--text-secondary); margin: 0 0 12px; }
  .tour-actions { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
  .tour-dots { display: flex; gap: 5px; }
  .tour-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--border-strong); }
  .tour-dot.on { background: var(--accent); }
  .tour-btns { display: flex; gap: 8px; }

  /* form */
  .nf-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px 14px; }
  .nf { display: flex; flex-direction: column; gap: 5px; }
  .nf.full { grid-column: 1 / -1; }
  .nf label { font-size: 10.5px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--text-muted); }
  .nf label .req { color: var(--danger); }
  .nf-hint { font-size: 11.5px; line-height: 1.5; color: var(--text-secondary); margin-top: 5px; }
  .nf-hint b { font-weight: 600; color: var(--text-primary); }
  /* a required dropdown still on its "Select…" placeholder reads as empty, not chosen */
  .nf select:has(option[value=""]:checked) { color: var(--text-muted); }
  .nf input, .nf select, .nf textarea {
    font-family: inherit; font-size: 13.5px; color: var(--text-primary);
    background: var(--bg-card); border: 1px solid var(--border-strong); border-radius: 8px;
    padding: 9px 11px; width: 100%; transition: border-color .14s ease, box-shadow .14s ease;
  }
  .nf textarea { resize: vertical; min-height: 62px; line-height: 1.5; }
  .nf input:focus, .nf select:focus, .nf textarea:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-bg); }
  .nf .clarity { display: inline-flex; align-items: center; gap: 6px; font-size: 11.5px; font-weight: 500; color: var(--text-secondary); cursor: pointer; text-transform: none; letter-spacing: 0; }
  .nf .clarity input { width: auto; }
  /* Data & tools tag input */
  .tagbox {
    display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
    background: var(--bg-card); border: 1px solid var(--border-strong); border-radius: 8px;
    padding: 7px 9px; min-height: 40px; cursor: text; transition: border-color .14s ease, box-shadow .14s ease;
  }
  .tagbox:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-bg); }
  .tagchip {
    display: inline-flex; align-items: center; gap: 4px; font-size: 12px; font-weight: 600;
    background: var(--accent-bg); color: var(--accent-text); border-radius: 6px; padding: 3px 4px 3px 9px;
  }
  .tagchip-x {
    border: none; background: transparent; color: var(--accent-text); cursor: pointer;
    font-size: 15px; line-height: 1; padding: 0 3px; border-radius: 4px; opacity: .7;
  }
  .tagchip-x:hover { opacity: 1; background: var(--accent-bg-2); }
  .tag-input { flex: 1 1 120px; min-width: 120px; border: none !important; background: transparent !important;
    padding: 3px 2px !important; box-shadow: none !important; width: auto !important; }
  .tag-input:focus { outline: none; box-shadow: none !important; }
  .tag-suggest { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
  .tag-sg {
    font-family: inherit; font-size: 11.5px; font-weight: 500; color: var(--text-secondary);
    background: var(--bg-card); border: 1px dashed var(--border-strong); border-radius: 99px;
    padding: 3px 10px; cursor: pointer; transition: all .12s ease;
  }
  .tag-sg:hover { border-style: solid; border-color: var(--accent); color: var(--accent-text); }
  .tag-sg.added { border-style: solid; border-color: var(--accent); background: var(--accent-bg);
    color: var(--accent-text); cursor: default; }
  /* Always-on hint: the placeholder disappears exactly when the user needs to
     know how to commit a tag, so the how-to lives outside the input. */
  .tag-help { font-size: 11.5px; line-height: 1.5; color: var(--text-secondary); margin-top: 7px;
    text-transform: none; letter-spacing: 0; }
  .tag-help.live { color: var(--accent-text); font-weight: 500; }
  .tag-help kbd {
    font-family: inherit; font-size: 10.5px; font-weight: 600; color: var(--text-primary);
    background: var(--bg-card-hover); border: 1px solid var(--border-strong);
    border-bottom-width: 2px; border-radius: 4px; padding: 1px 5px; margin: 0 1px;
  }
  .nf-err { font-size: 12px; color: var(--danger); margin-top: 4px; min-height: 0; }
  .nf-foot { display: flex; align-items: center; justify-content: flex-end; gap: 10px; margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--border); }
  .btn-soft { background: var(--bg-card-hover); color: var(--text-secondary); }
  .btn-soft:hover { background: var(--bg-card-active); color: var(--text-primary); }
  .btn-danger { background: rgba(229,72,77,.12); color: var(--danger); }
  .btn-danger:hover { opacity: .9; }

  /* ---------- Filters bar (scope + build, multi-select) ---------- */
  .filters-wrap { display: inline-flex; }
  .filters-btn {
    display: inline-flex; align-items: center; gap: 6px;
    font-family: inherit; font-size: 13px; font-weight: 600; color: var(--text-secondary);
    background: var(--bg-card); border: 1px solid var(--border); border-radius: 99px;
    height: 32px; padding: 0 13px; cursor: pointer;
    transition: background-color .14s ease, border-color .14s ease, color .14s ease;
  }
  .filters-btn i { font-size: 15px; }
  /* The pill is also used as a LINK now (the topbar's way into /admin, and
     /admin's way back). Nothing else in this file resets anchors, so without
     this it would render underlined and in the browser's link blue. */
  a.filters-btn { text-decoration: none; }
  .filters-btn:hover { border-color: var(--border-strong); color: var(--text-primary); }
  .filters-btn.on { border-color: var(--accent); color: var(--accent-text); }
  .filters-btn.has-active { background: var(--accent-bg); border-color: transparent; color: var(--accent-text); }
  .filters-count {
    display: none; min-width: 17px; height: 17px; padding: 0 4px; border-radius: 99px;
    background: var(--accent); color: #fff; font-size: 10px; font-weight: 700;
    align-items: center; justify-content: center;
  }
  .filters-count.show { display: inline-flex; }
  /* Inline expanding bar: normal flow, so it pushes the grid down instead of
     overlaying (and can never be covered by a card). */
  .filters-bar {
    display: flex; flex-wrap: wrap; gap: 14px 30px; align-items: flex-start;
    margin: -8px 0 20px; padding: 15px 17px;
    background: var(--bg-card); border: 1px solid var(--border); border-radius: 14px;
  }
  .filters-bar[hidden] { display: none; }
  .filter-group { display: flex; flex-direction: column; gap: 9px; }
  /* Thin divider between the two filter groups (stretches to the bar's height). */
  .filter-sep { align-self: stretch; width: 1px; background: var(--border-strong); }
  .filter-lbl {
    font-size: 11px; font-weight: 700; letter-spacing: .04em;
    text-transform: uppercase; color: var(--text-muted);
  }

  /* ---------- Archive review toggle (quiet, foot of the board) ---------- */
  .board-foot { display: flex; justify-content: center; margin: 26px 0 6px; }
  .arch-toggle {
    display: inline-flex; align-items: center; justify-content: center; gap: 6px;
    height: 30px; min-width: 30px; padding: 0 9px;
    font-family: inherit; font-size: 12.5px; font-weight: 600;
    color: var(--text-muted); background: transparent;
    border: 1px solid transparent; border-radius: 99px; cursor: pointer;
    transition: color .14s ease, background-color .14s ease, border-color .14s ease;
  }
  .arch-toggle i { font-size: 15px; }
  .arch-toggle:hover { color: var(--text-secondary); background: var(--bg-card-hover); }
  .arch-toggle.on {
    color: var(--danger); border-color: rgba(229,72,77,.28); background: rgba(229,72,77,.06);
  }

  /* ---------- Archive ("not relevant anymore") ---------- */
  /* Quiet collapsed control at the foot of the detail view. */
  .arch-box { margin-top: 18px; }
  .arch-box.collapsed { padding-top: 14px; border-top: 1px solid var(--border); }
  .arch-open { color: var(--text-muted); font-size: 12.5px; display: inline-flex; align-items: center; gap: 6px; }
  .arch-open:hover { color: var(--danger); }
  /* Expanded reason form + the archived banner share a boxed look. */
  .arch-box.open, .arch-box.archived {
    padding: 13px 14px; border-radius: 12px;
    border: 1px solid rgba(229,72,77,.28); background: rgba(229,72,77,.06);
  }
  .arch-box.archived { margin-bottom: 4px; }
  .arch-head { display: flex; align-items: center; gap: 7px; font-size: 12.5px; font-weight: 700; color: var(--danger); }
  .arch-head i { font-size: 15px; }
  .arch-hint { font-size: 12px; color: var(--text-secondary); margin: 6px 0 8px; }
  .arch-box.open textarea {
    width: 100%; font-family: inherit; font-size: 13px; color: var(--text-primary);
    background: var(--bg-card); border: 1px solid var(--border);
    border-radius: 8px; padding: 8px 10px; resize: vertical; margin-bottom: 8px;
  }
  .arch-box.open textarea:focus { outline: none; border-color: var(--danger); }
  .arch-reason { font-size: 13.5px; color: var(--text-primary); margin: 7px 0 6px; font-style: italic; }
  .arch-reason::before, .arch-reason::after { content: '“'; }
  .arch-reason::after { content: '”'; }
  .arch-meta { font-size: 11.5px; color: var(--text-muted); }
  .arch-restore { margin-top: 11px; height: 34px; font-size: 13px; }
  /* Archived cards in the review view read as muted. */
  .card.archived { opacity: .72; }
  .card.archived:hover { opacity: 1; }
  .card.archived .card-foot .pill { color: var(--text-muted); }
  /* A parked card is NOT hidden — it stays in the portfolio, visibly paused. */
  .card.parked { opacity: .82; }
  .card.parked:hover { opacity: 1; }
  .card.parked .card-foot .pill { color: var(--warning); }

  /* ---------- Assessment panel (admins only) ----------
     The first surface that EDITS an existing case, so it is deliberately set
     apart from the read-only body: its own framed box, collapsed until asked
     for. Lifts into the admin panel as one block when that arrives. */
  .asx { margin-top: 14px; border: 1px dashed var(--border-strong); border-radius: 12px; padding: 12px 13px; }
  .asx-head { display: flex; align-items: center; gap: 8px; }
  .asx-head .asx-t { font-size: 10.5px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--accent-text); }
  .asx-who { font-size: 11px; color: var(--text-muted); margin-left: auto; }
  .asx-open { margin-top: 10px; display: flex; flex-direction: column; gap: 11px; }
  /* :not(.asx-check) — a checkbox row is also a <label>, and must not inherit the
     uppercase block styling meant for field captions. */
  .asx-f > label:not(.asx-check) { display: block; font-size: 10.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--text-muted); margin-bottom: 5px; }
  /* :not([type=checkbox]) — a checkbox must not be stretched to 100% width and
     given text-input padding; it lives in an .asx-check row instead. */
  .asx-f textarea, .asx-f input:not([type=checkbox]), .asx-f select {
    width: 100%; font-family: inherit; font-size: 13px; color: var(--text-primary);
    background: var(--bg-card); border: 1px solid var(--border-strong); border-radius: 9px;
    padding: 8px 10px; resize: vertical;
  }
  .asx-f textarea { min-height: 62px; }
  .asx-f textarea:focus, .asx-f input:not([type=checkbox]):focus, .asx-f select:focus { outline: none; border-color: var(--accent); }
  .asx-two { display: flex; gap: 10px; }
  .asx-two > * { flex: 1; min-width: 0; }
  .asx-check { display: flex; align-items: flex-start; gap: 7px; font-size: 12.5px; color: var(--text-primary); cursor: pointer; }
  .asx-check input { margin-top: 2px; accent-color: var(--accent); }
  .asx-check span small { display: block; color: var(--text-muted); font-size: 11px; margin-top: 1px; }
  .asx-actions { display: flex; flex-wrap: wrap; gap: 9px; justify-content: flex-end; align-items: center; }
  .asx-err:empty { display: none; }
  .asx-park { margin-left: 0; margin-right: auto; }
  /* "Assessing as …" takes its own line so Cancel/Save stay side by side. */
  .asx-actions .sol-as { flex: 1 1 100%; text-align: right; }

  @media (max-width: 760px) {
    /* No room for a second column, so the grid is switched off entirely — which
       makes every .r1….r4 row assignment inert in one go, no overrides needed.
       DOM order then does the right thing: each rung falls immediately above the
       section it grades and reads as that section's heading. The connectors go,
       because there is nothing below a rung to connect to any more. */
    .m-cols { display: block; }
    .m-head { margin-bottom: 18px; }
    .rstep::after { display: none; }
    /* The section divider moves onto the RUNG, so the rule falls above the rung
       instead of between the rung and the fields it introduces — otherwise each
       rung reads as a footer for the section before it. */
    .m-sec { border-top: none; padding-top: 0; }
    .rstep {
      border-top: 1px solid var(--border);
      padding-top: var(--rung-top); padding-bottom: 14px;
    }
    /* The rail's own "Status" heading is redundant once the rungs are inline
       captions rather than a column of their own. */
    .rail-top .rmap-lbl { display: none; }
    .rail-top:not(.parked) { display: none; }
  }

  @media (max-width: 720px) {
    /* Groups stack — drop the vertical divider so it isn't a stray sliver. */
    .filter-sep { display: none; }
    .nf-grid { grid-template-columns: 1fr; }
  }
