/* Holotype UI — library.css
   Library tiles + lineage strip, result-reveal juice, modals,
   chromosome-painting strip, locus annotation, loci-at-a-glance,
   footer.
   Part 7/7 of the former styles.css; files are linked
   from index.html in order, so the cascade is unchanged. */

        /* ---- Library panel + lineage strip ---- */

        /* ---- Library tiles — small specimen plates ----
           Each saved creature renders as a hairline-rule mini-plate.
           Hover lifts the tile and brightens the rule to copper. The
           collected library now reads as a row of mounted specimens
           rather than a generic image grid. */
        .library-panel { margin-top: 28px; }
        /* Page intro — distinguishes Library (your private collection) from
           Stable (battle roster) and Pool (shared). */
        .library-intro,
        .pool-intro {
            font-family: var(--font-serif);
            font-style: italic;
            font-size: 13.5px;
            color: var(--ink-muted);
            line-height: 1.55;
            margin: 2px 0 14px;
            max-width: 64ch;
        }
        .pool-intro { margin-bottom: 16px; }
        /* Shared accenting for the three role intros: the page's own name in
           copper, the OTHER two roles italicised — teaches the relationship
           between Library / Stable / Pool at a glance. */
        .library-intro strong,
        .stable-blurb strong,
        .pool-intro strong {
            color: var(--copper);
            font-weight: 600;
            font-style: normal;
        }
        .library-intro em,
        .stable-blurb em,
        .pool-intro em {
            font-style: normal;
            color: var(--ink);
            font-weight: 500;
        }
        /* Filter/sort controls bar. */
        .library-controls {
            display: flex;
            flex-wrap: wrap;
            align-items: center;
            gap: 10px 16px;
            margin: 0 0 16px;
            padding: 10px 12px;
            background: var(--bg-vellum);
            border: 1px solid var(--rule);
            border-radius: 2px;
        }
        .library-controls[hidden] { display: none; }
        .library-controls .lib-ctl {
            display: inline-flex;
            align-items: center;
            gap: 7px;
            font-family: var(--font-serif);
            font-size: 11px;
            text-transform: uppercase;
            letter-spacing: 0.1em;
            color: var(--ink-faint);
            font-feature-settings: "smcp", "lnum";
        }
        .library-controls .lib-search,
        .library-controls select {
            font-family: var(--font-sans);
            font-size: 13px;
            padding: 6px 9px;
            background: var(--bg-ink);
            border: 1px solid var(--rule-strong);
            border-radius: 1px;
            color: var(--ink);
        }
        .library-controls .lib-search {
            flex: 1 1 160px;
            min-width: 130px;
            text-transform: none;
        }
        .library-controls .lib-search:focus,
        .library-controls select:focus {
            outline: none;
            border-color: var(--copper);
            box-shadow: 0 0 0 2px var(--copper-dim);
        }
        .library-controls input[type="range"] {
            width: 110px;
            accent-color: var(--copper);
        }
        .library-controls .lib-filter-val {
            font-family: var(--font-serif);
            font-size: 12px;
            color: var(--ink);
            font-variant-numeric: tabular-nums lining-nums;
            min-width: 34px;
        }
        .library-controls .lib-count {
            margin-left: auto;
            font-family: var(--font-serif);
            font-size: 12px;
            font-style: italic;
            color: var(--ink-muted);
        }
        .library-grid {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
            gap: 14px;
            margin-top: 14px;
        }
        /* Empty-library field note on the dedicated Library page. */
        .library-empty {
            margin: 18px 0 0;
            font-size: 17px;
            color: var(--ink-pen);
            line-height: 1.6;
        }
        /* Tile material (border + scored bevel + parchment ground) now comes
           from the shared .fj-plate kit (added in the tile render). Only the
           tile's image-clipping + interaction props stay here; the hover lift
           is rebuilt from the kit's plate tokens. */
        .library-tile {
            overflow: hidden;
            cursor: pointer;
            position: relative;
            transition:
                border-color var(--motion-quick),
                transform var(--motion-quick),
                box-shadow var(--motion-quick);
        }
        .library-tile:hover {
            border-color: var(--copper);
            box-shadow: var(--plate-inset), var(--plate-shadow);
            transform: translateY(-2px);
        }
        /* Picker single-select highlight (createCreatureBrowser getSelectedId).
           An OUTSET ring — the tile's overflow:hidden would clip an inset one
           behind the image. */
        .library-tile.is-selected {
            border-color: var(--gold-leaf);
            box-shadow: 0 0 0 2px var(--gold-leaf),
                        0 6px 18px rgba(0, 0, 0, 0.4);
        }
        /* "parent" badge on the mate-partner picker (top-right corner). */
        .library-tile .tile-parent-tag {
            position: absolute;
            top: 6px;
            right: 6px;
            z-index: 2;
            padding: 2px 7px;
            border-radius: 2px;
            background: var(--bg-ink);
            color: var(--gold-leaf);
            font-family: var(--font-serif);
            font-size: 9.5px;
            text-transform: uppercase;
            letter-spacing: 0.14em;
            box-shadow: 0 1px 4px rgba(0, 0, 0, 0.5);
        }
        /* The shared selected-creature chip (Pool + review-modal): a thumbnail +
           name + "Change" affordance that opens the createCreatureBrowser picker. */
        .creature-chip {
            display: inline-flex;
            align-items: center;
            gap: 8px;
            padding: 5px 12px 5px 5px;
            border: 1px solid var(--rule);
            border-radius: 999px;
            background: var(--bg-vellum);
            color: var(--text);
            cursor: pointer;
            font-family: inherit;
            font-size: 13px;
            transition: border-color var(--motion-quick);
        }
        .creature-chip:hover { border-color: var(--copper); }
        .creature-chip .creature-chip-img {
            width: 28px;
            height: 28px;
            border-radius: 50%;
            object-fit: cover;
            background: var(--bg-ink);
        }
        .creature-chip .creature-chip-img[hidden] { display: none; }
        .creature-chip .creature-chip-name { font-weight: 600; }
        .creature-chip .creature-chip-caret {
            color: var(--copper);
            font-size: 11px;
            text-transform: uppercase;
            letter-spacing: 0.1em;
        }
        /* The portrait + its overlaid seals (power, rarity). */
        .tile-figure {
            position: relative;
            line-height: 0;
        }
        .tile-figure img {
            display: block;
            width: 100%;
            aspect-ratio: 1;
            object-fit: cover;
            background: var(--bg-ink);
            border-bottom: 1px solid var(--rule);
        }
        /* A soft scrim along the foot of the portrait so the power seal + rarity
           pips stay legible over any creature. */
        .tile-figure::after {
            content: "";
            position: absolute;
            left: 0;
            right: 0;
            bottom: 0;
            height: 38%;
            pointer-events: none;
            background: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.42));
        }
        /* RARITY — gem pips, bottom-left, count = rank, colour = tier. */
        /* RARITY — gem pips on a dark pill (matched to the power seal) so they
           stay legible over any portrait; count = rank, colour = tier. */
        .tile-rarity {
            position: absolute;
            left: 6px;
            bottom: 5px;
            z-index: 2;
            display: flex;
            align-items: center;
            gap: 1px;
            height: 18px;
            padding: 0 7px;
            border-radius: 9px;
            background: radial-gradient(circle at 38% 32%,
                rgba(40, 34, 24, 0.92), rgba(18, 15, 10, 0.94));
            box-shadow:
                0 0 0 1px rgba(201, 139, 86, 0.55),
                0 1px 4px rgba(0, 0, 0, 0.6),
                inset 0 1px 0 rgba(255, 236, 200, 0.2);
            font-size: 9px;
            line-height: 1;
            letter-spacing: 0.5px;
            color: var(--ink-faint);            /* common — faint pewter */
        }
        .tile-rarity.rarity-uncommon { color: #d8c79c; }
        .tile-rarity.rarity-rare {
            color: var(--copper-hover);
            text-shadow: 0 0 6px rgba(214, 160, 122, 0.5);
        }
        .tile-rarity.rarity-mythic {
            color: var(--gold-leaf);
            text-shadow: 0 0 7px var(--gold-leaf-glow);
        }
        /* POWER — a small struck seal, bottom-right, gold headline number. */
        .tile-power {
            position: absolute;
            right: 6px;
            bottom: 5px;
            z-index: 2;
            min-width: 26px;
            height: 26px;
            padding: 0 5px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-radius: 50%;
            background: radial-gradient(circle at 38% 32%,
                rgba(40, 34, 24, 0.92), rgba(18, 15, 10, 0.94));
            box-shadow:
                0 0 0 1px rgba(201, 139, 86, 0.7),
                0 1px 4px rgba(0, 0, 0, 0.6),
                inset 0 1px 0 rgba(255, 236, 200, 0.25);
        }
        .tile-power-num {
            font-family: var(--font-serif);
            font-weight: 700;
            font-size: 14px;
            line-height: 1;
            color: var(--gold-leaf);
            font-variant-numeric: tabular-nums lining-nums;
            text-shadow: 0 1px 1px rgba(0, 0, 0, 0.6);
        }
        /* Cream paper "notes" pinned to the specimen card — the subtitle slip
           and the stat slip, in the same paper-label treatment as the cabinet
           drawer labels (cream stock, dark ink, hairline holder, soft drop). */
        .tile-note {
            position: relative;
            margin-top: 9px;
            padding: 5px 7px 4px;
            background: #efe7d2;
            color: #3a2c18;
            border: 1px solid rgba(120, 92, 52, 0.55);
            border-radius: 2px;
            box-shadow:
                0 1px 3px rgba(0, 0, 0, 0.45),
                inset 0 0 0 1px rgba(255, 250, 240, 0.5);
        }
        /* A tiny pin tacking the note to the card — small + unobtrusive,
           top-centre, peeking just above the slip's edge with a soft drop. The
           head colour varies per specimen (the `.pin-0..3` class on the tile
           supplies `--pin-grad`) so the grid reads like a varied pinboard;
           brass is the fallback. */
        .tile-note::before {
            content: "";
            position: absolute;
            top: -3px;
            left: 50%;
            width: 5px;
            height: 5px;
            margin-left: -2.5px;
            border-radius: 50%;
            background: var(--pin-grad,
                radial-gradient(circle at 34% 30%, #edc78c, #6e4f29 82%));
            box-shadow: 0 1px 1.5px rgba(0, 0, 0, 0.6);
            z-index: 1;
        }
        /* The portrait pins (one per upper corner) are .specimen-pin elements
           rendered into .tile-figure — see base.css for the shared head. They
           match the note pins' size + per-specimen colour. */
        /* Subtitle slip — the coat · build descriptor, the collector's caption.
           The ellipsis lives on the inner <span> so the note box itself never
           clips the pin that peeks above its top edge. */
        .tile-subtitle {
            font-family: var(--font-serif);
            font-style: italic;
            font-size: 11px;
            line-height: 1.2;
            text-align: center;
            text-transform: capitalize;
        }
        .tile-subtitle span {
            display: block;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }
        /* Stat slip — the five field measurements as numbers (labels over
           values), high values underlined for emphasis. */
        .tile-stats {
            display: grid;
            grid-template-columns: repeat(5, 1fr);
            gap: 1px 3px;
            text-align: center;
            font-family: var(--font-serif);
            font-variant-numeric: tabular-nums lining-nums;
        }
        .tile-stat-k {
            font-size: 8px;
            font-weight: 600;
            letter-spacing: 0.04em;
            text-transform: uppercase;
            color: #8a7252;
        }
        .tile-stat-v { font-size: 12.5px; line-height: 1.15; color: #3a2c18; }
        .tile-stat-v.is-high {
            font-weight: 700;
            text-decoration: underline;
            text-decoration-thickness: 1px;
            text-underline-offset: 2px;
            color: #5a3a18;
        }
        /* User-selected cosmetic frame — the same five frames as the close-up
           card, drawn as an inset double rule in the frame colour so it reads
           inside the parchment edge. */
        .library-tile.frame--gilt      { outline: 3px double #c9a227; outline-offset: -4px; }
        .library-tile.frame--obsidian  { outline: 3px double #6b6b78; outline-offset: -4px; }
        .library-tile.frame--verdigris { outline: 3px double #5f8a72; outline-offset: -4px; }
        .library-tile.frame--oxblood   { outline: 3px double #7b2d2a; outline-offset: -4px; }
        .library-tile.frame--bone      { outline: 3px double #d8cdb0; outline-offset: -4px; }
        .library-tile-meta {
            padding: 10px 12px 12px;
            font-size: 13px;
            font-family: var(--font-sans);
        }
        .library-tile-meta .tile-name {
            font-family: var(--font-serif);
            font-weight: 500;
            font-size: 15px;
            color: var(--ink);
            letter-spacing: 0.005em;
        }
        .library-tile-meta .tile-summary {
            color: var(--ink-muted);
            font-size: 12px;
            margin-top: 2px;
        }
        /* Owner attribution chip — small monospace tag, copper for
           the user's own creatures. */
        .library-tile-meta .tile-owner {
            display: inline-block;
            margin-top: 6px;
            font-size: 10px;
            padding: 1px 6px;
            border-radius: 2px;
            background: transparent;
            border: 1px solid var(--rule);
            color: var(--ink-faint);
            font-family: var(--font-mono);
            letter-spacing: 0.04em;
            max-width: 100%;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            vertical-align: middle;
        }
        .library-tile-meta .tile-owner.is-mine {
            background: var(--copper-dim);
            border-color: var(--copper);
            color: var(--copper);
            font-weight: 600;
        }
        /* Pool toggle — small-caps serif "Submit to registry" pill.
           Off = hairline outline; on = filled copper ("In registry"). */
        .tile-pool-toggle {
            display: block;
            margin-top: 8px;
            width: 100%;
            padding: 6px 8px;
            font-family: var(--font-serif);
            font-size: 10px;
            letter-spacing: 0.18em;
            text-transform: uppercase;
            font-feature-settings: "smcp", "lnum";
            background: transparent;
            color: var(--ink-faint);
            border: 1px solid var(--rule);
            border-radius: 1px;
            cursor: pointer;
            text-align: center;
            transition: background var(--motion-quick),
                        color var(--motion-quick),
                        border-color var(--motion-quick);
        }
        .tile-pool-toggle:hover {
            border-color: var(--copper);
            color: var(--copper);
        }
        .tile-pool-toggle.is-on {
            background: var(--copper-dim);
            color: var(--copper);
            border-color: var(--copper);
            font-weight: 600;
        }
        .tile-pool-toggle:disabled {
            opacity: 0.55;
            cursor: wait;
        }
        /* Library grid section headers — "Your specimens" and
           "Other expeditions". Serif small-caps eyebrow with a
           hairline rule running across the row. */
        .library-section-header {
            grid-column: 1 / -1;
            font-family: var(--font-serif);
            font-size: 10.5px;
            text-transform: uppercase;
            letter-spacing: 0.22em;
            color: var(--copper);
            margin: 18px 0 6px;
            padding-bottom: 6px;
            border-bottom: 1px solid var(--rule);
            font-feature-settings: "smcp", "lnum";
        }
        .library-section-header:first-child { margin-top: 0; }

        /* ---- Stable (battle roster) ----
           Reuses .library-tile for the plates; adds a lineup-position
           badge, dashed empty slots showing remaining capacity, and an
           add/remove pill that mirrors the pool toggle. */
        .stable-header { margin-bottom: 4px; }
        .stable-count {
            font-family: var(--font-serif);
            font-size: 15px;
            color: var(--copper);
            font-variant-numeric: tabular-nums lining-nums;
            letter-spacing: 0.04em;
        }
        .stable-blurb {
            font-family: var(--font-serif);
            font-style: italic;
            color: var(--ink-muted);
            font-size: 14px;
            line-height: 1.55;
            margin: 4px 0 16px;
            max-width: 62ch;
        }
        .stable-team {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
            gap: 14px;
            margin-top: 12px;
        }
        /* The bench is now a creature-browser host (controls bar + a
           .library-grid inside), not a grid itself. Its grid matches the
           Library's; this just spaces the controls bar from the title. */
        .stable-bench-browse {
            margin-top: 8px;
        }
        .stable-bench-browse .library-controls {
            margin-top: 0;
        }
        .stable-bench-title {
            font-family: var(--font-serif);
            font-size: 10.5px;
            text-transform: uppercase;
            letter-spacing: 0.22em;
            color: var(--copper);
            margin: 26px 0 4px;
            padding-bottom: 6px;
            border-bottom: 1px solid var(--rule);
            font-feature-settings: "smcp", "lnum";
        }
        /* Empty roster slot — a dashed plate marking remaining capacity. */
        .stable-slot-empty {
            border: 1px dashed var(--rule-strong);
            border-radius: 1px;
            min-height: 132px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: var(--ink-faint);
            font-family: var(--font-serif);
            font-style: italic;
            font-size: 13px;
            letter-spacing: 0.04em;
        }
        /* Lineup-position badge on a rostered tile (1 = first to defend). */
        .stable-pos {
            position: absolute;
            top: 6px;
            left: 6px;
            z-index: 2;
            width: 22px;
            height: 22px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-radius: 50%;
            background: var(--copper);
            color: var(--bg-ink);
            font-family: var(--font-serif);
            font-size: 12px;
            font-weight: 700;
            font-variant-numeric: lining-nums;
            box-shadow: 0 1px 4px rgba(0, 0, 0, 0.5);
        }
        /* Add / Remove pill — same chrome as the pool toggle. */
        .tile-stable-toggle {
            display: block;
            margin-top: 8px;
            width: 100%;
            padding: 6px 8px;
            font-family: var(--font-serif);
            font-size: 10px;
            letter-spacing: 0.18em;
            text-transform: uppercase;
            font-feature-settings: "smcp", "lnum";
            background: transparent;
            color: var(--ink-faint);
            border: 1px solid var(--rule);
            border-radius: 1px;
            cursor: pointer;
            text-align: center;
            transition: background var(--motion-quick),
                        color var(--motion-quick),
                        border-color var(--motion-quick);
        }
        .tile-stable-toggle:hover {
            border-color: var(--copper);
            color: var(--copper);
        }
        .tile-stable-toggle.is-on {
            background: var(--copper-dim);
            color: var(--copper);
            border-color: var(--copper);
            font-weight: 600;
        }
        .tile-stable-toggle:disabled {
            opacity: 0.5;
            cursor: not-allowed;
            border-color: var(--rule);
            color: var(--ink-faint);
            background: transparent;
        }
        .stable-empty-note {
            grid-column: 1 / -1;
            font-family: var(--font-serif);
            font-style: italic;
            color: var(--ink-muted);
            font-size: 14px;
            padding: 10px 2px;
        }

        .lineage-strip {
            margin-top: 16px;
            padding: 14px 18px;
            background: var(--copper-dim);
            border-left: 3px solid var(--copper);
            border-radius: 1px;
            font-family: var(--font-hand);
            font-size: 17px;
            color: var(--ink-pen);
            line-height: 1.32;
        }
        .lineage-strip strong {
            color: var(--ink);
            font-weight: 600;
        }
        .lineage-strip a {
            color: var(--copper);
            text-decoration: none;
            margin-left: 6px;
        }
        /* Discovery payoff — the post-mating/starter "you unlocked N
           alleles" strip. Gold-leaf accent so it reads as a reward,
           set apart from the copper lineage strip just below it. */
        .discovery-strip {
            margin: 0 0 18px;
            padding: 14px 18px;
            background: var(--gold-leaf-glow);
            border-left: 3px solid var(--gold-leaf);
            border-radius: 1px;
            color: var(--ink);
        }
        .discovery-strip.is-tappable { cursor: pointer; }
        .discovery-strip-title {
            font-family: var(--font-hand);
            font-size: 20px;
            font-weight: 600;
            color: var(--gold-leaf);
            margin: 0 0 6px;
        }
        .discovery-strip-chips {
            display: flex;
            flex-wrap: wrap;
            gap: 6px;
        }
        .discovery-chip {
            font-size: 12px;
            padding: 3px 9px;
            background: var(--copper-dim);
            border: 1px solid var(--copper);
            border-radius: 2px;
            color: var(--ink);
        }

        /* ---- Result reveal ("juice") ----
           After a 1–3 min wait the result should land as a moment: the
           card settles in, the rarity label stamps, the portrait fades,
           the discovery chips cascade. All gated on prefers-reduced-
           motion — reduced-motion players get an instant paint. */
        @media (prefers-reduced-motion: no-preference) {
            @keyframes card-reveal {
                from { opacity: 0; transform: translateY(16px) scale(0.985); }
                to   { opacity: 1; transform: translateY(0) scale(1); }
            }
            .genome-card.card-revealing {
                animation: card-reveal 460ms cubic-bezier(0.2, 0.7, 0.2, 1);
            }
            @keyframes rarity-stamp {
                0%   { opacity: 0; transform: scale(1.7); }
                55%  { opacity: 1; }
                100% { opacity: 1; transform: scale(1); }
            }
            .genome-card.card-revealing .rarity-label {
                transform-origin: right center;
                animation: rarity-stamp 520ms cubic-bezier(0.2, 0.8, 0.2, 1)
                           200ms both;
            }
            @keyframes img-reveal {
                from { opacity: 0; }
                to   { opacity: 1; }
            }
            #result-image.img-revealing {
                animation: img-reveal 420ms ease-out;
            }
            @keyframes discovery-chip-in {
                from { opacity: 0; transform: translateY(6px); }
                to   { opacity: 1; transform: translateY(0); }
            }
            .discovery-strip-chips .discovery-chip {
                animation: discovery-chip-in 360ms ease-out both;
            }
            .discovery-strip-chips .discovery-chip:nth-child(2) { animation-delay: 70ms; }
            .discovery-strip-chips .discovery-chip:nth-child(3) { animation-delay: 140ms; }
            .discovery-strip-chips .discovery-chip:nth-child(4) { animation-delay: 210ms; }
            .discovery-strip-chips .discovery-chip:nth-child(5) { animation-delay: 280ms; }
            .discovery-strip-chips .discovery-chip:nth-child(n+6) { animation-delay: 340ms; }
        }

        /* ---- Modals ---- */

        .modal-backdrop {
            position: fixed;
            inset: 0;
            background: rgba(0, 0, 0, 0.6);
            display: flex;
            align-items: center;
            justify-content: center;
            z-index: 100;
        }
        .modal-backdrop[hidden] { display: none; }
        /* The shared creature picker can open OVER another modal (the inbox
           review modal), so it sits above the standard backdrop layer. Its
           controls bar wraps gracefully at the narrower modal width. */
        .modal-backdrop--picker { z-index: 200; }
        .modal-backdrop--picker .creature-browser-controls { flex-wrap: wrap; }
        #creature-picker-host .library-grid { max-height: 56vh; overflow-y: auto; }
        /* Entrance: the backdrop fades and the dialog settles up into place
           whenever it's shown (display none→flex restarts the animation).
           Gated on reduced-motion. */
        @media (prefers-reduced-motion: no-preference) {
            .modal-backdrop:not([hidden]) {
                animation: modal-backdrop-in 180ms ease-out;
            }
            .modal-backdrop:not([hidden]) .modal {
                animation: modal-pop-in var(--motion-base)
                    cubic-bezier(0.2, 0.7, 0.2, 1) both;
            }
        }
        @keyframes modal-backdrop-in { from { opacity: 0; } to { opacity: 1; } }
        @keyframes modal-pop-in {
            from { opacity: 0; transform: translateY(10px) scale(0.985); }
            to   { opacity: 1; transform: none; }
        }
        /* Modal — framed parchment dialog with the same hairline
           double-rule chrome as the result card. */
        .modal {
            background: var(--bg-vellum);
            border: 1px solid var(--rule-strong);
            box-shadow:
                inset 0 0 0 4px var(--bg-vellum),
                inset 0 0 0 5px var(--rule),
                0 12px 32px rgba(0, 0, 0, 0.5);
            border-radius: 2px;
            padding: 28px 32px;
            min-width: 360px;
            max-width: 520px;
            /* Never exceed the viewport. A tall dialog (the discovery-point
               wallet #vp-modal, the review-proposal modal) would otherwise
               overflow symmetrically out of the centred backdrop — which does
               NOT scroll — and push its .modal-actions footer off both the top
               and bottom edges on short / landscape windows (iPad landscape),
               leaving the confirm/close buttons unclickable. Cap the height and
               let the dialog scroll INSIDE its own frame so the footer is always
               reachable. (The fixed-size tutorial modal overrides this with its
               own height; see .modal.tutorial-modal-content.) */
            max-height: 92vh;
            overflow-y: auto;
        }
        .modal h3 {
            font-family: var(--font-serif);
            font-size: 22px;
            font-weight: 500;
            margin: 0 0 6px;
            padding-bottom: 10px;
            border-bottom: 1px solid var(--rule);
            color: var(--ink);
        }
        .modal p {
            font-family: var(--font-serif);
            font-style: italic;
            color: var(--ink-muted);
            font-size: 14px;
            margin: 12px 0 18px;
            line-height: 1.55;
        }
        .modal input[type="text"],
        .modal input[type="email"],
        .modal input[type="search"],
        .modal input[type="url"],
        .modal input[type="number"],
        .modal select,
        .modal textarea {
            width: 100%;
            box-sizing: border-box;
            padding: 10px 14px;
            margin-bottom: 14px;
            font-family: var(--font-sans);
            background: var(--bg-ink);
            border: 1px solid var(--rule-strong);
            border-radius: 1px;
            color: var(--ink);
            font-size: 14px;
            /* Fields are carved-in wells (shared --well-inset), matching the
               .fj-well kit + the mate-stage name field. */
            box-shadow: var(--well-inset);
            transition: border-color var(--motion-quick),
                        box-shadow var(--motion-quick);
        }
        .modal input[type="text"]:focus,
        .modal input[type="email"]:focus,
        .modal input[type="search"]:focus,
        .modal input[type="url"]:focus,
        .modal input[type="number"]:focus,
        .modal select:focus,
        .modal textarea:focus {
            outline: none;
            border-color: var(--copper);
            box-shadow: var(--well-inset), 0 0 0 2px var(--copper-dim);
        }
        .modal-error {
            background: var(--oxblood-bg);
            border: 1px solid var(--oxblood);
            color: var(--ink);
            padding: 10px 14px;
            border-radius: 1px;
            font-family: var(--font-serif);
            font-style: italic;
            font-size: 13px;
            margin-bottom: 14px;
        }
        .modal-actions {
            display: flex;
            justify-content: flex-end;
            gap: 10px;
            margin-top: 6px;
        }
        /* Wider modal variant — gives the partner-picker grid a stable
           width to divide (a definite width, not content-sized). */
        .modal--wide {
            max-width: 560px;
            width: min(560px, 92vw);
        }
        /* (The bespoke .mate-partner-grid/.mate-partner-tile picker was retired
           when the mate-partner flow moved to the shared createCreatureBrowser
           picker — see #creature-picker-modal / .library-tile.) */
        .locus-meta {
            color: var(--text-muted);
            font-size: 13px;
            font-variant-numeric: tabular-nums;
        }
        .locus-notes {
            color: var(--text-muted);
            font-size: 13px;
            margin-bottom: 10px;
        }
        .sequence-block {
            background: var(--surface-2);
            border: 1px solid var(--border);
            border-radius: 1px;
            font-family: var(--font-mono);
            font-size: 12px;
            line-height: 1.5;
            padding: 12px;
            max-height: 180px;
            overflow: auto;
            word-break: break-all;
            white-space: pre-wrap;
            color: var(--text);
        }
        /* Slim, period-neutral scrollbar for the sequence plate. */
        .sequence-block::-webkit-scrollbar { width: 9px; height: 9px; }
        .sequence-block::-webkit-scrollbar-track { background: transparent; }
        .sequence-block::-webkit-scrollbar-thumb {
            background: var(--rule-strong);
            border-radius: 0;
        }
        /* Sequence segment coloring.

           For de-novo (image-derived) alleles we render plain text — no
           provenance to attribute. For mated offspring, we render four
           colors keyed off `provenance_segments[].parental_homolog` and
           the offspring's allele slot:

             allele A (from "mother", parent_genomes[0]):
               homolog A → coral   (color 1)
               homolog B → amber   (color 2)
             allele B (from "father", parent_genomes[1]):
               homolog A → cyan    (color 3)
               homolog B → violet  (color 4)

           Pairing the colors by parent (warm = mom, cool = dad) makes
           it easy to see at a glance which side of the family a
           recombinant tract came from. The four hues are all distinct
           from the teal accent so they don't collide with UI chrome.
        */
        .seq-prov { color: var(--text); }
        /* Four-tone provenance palette in the Field-Journal range —
           one hue per grandparental homolog, all distinguishable on
           the bone/ink ground without breaking the journal voice. */
        .seq-prov.prov-c1 { color: var(--copper); }   /* mother homolog A — copper */
        .seq-prov.prov-c2 { color: var(--brass); }    /* mother homolog B — brass  */
        .seq-prov.prov-c3 { color: var(--sage); }     /* father homolog A — sage   */
        .seq-prov.prov-c4 { color: var(--oxblood-soft); }         /* father homolog B — softened oxblood */

        /* ---- Chromosome-painting strip ----
           The headline visual of each allele: a horizontal bar of the
           allele's whole length, split into provenance segments (a
           crossover reads as a colour change at a boundary) with de
           novo mutations marked as gold ticks. Glanceable without
           reading a base of DNA. Same palette as the .seq-prov text. */
        .chromo-paint {
            display: block;
            width: 100%;
            height: 19px;
            margin: 4px 0 7px;
            /* a faint inked frame around the painted chromosome */
            outline: 1px solid var(--rule-strong);
        }
        .paint-c0 { fill: #6b6356; }            /* de-novo — single origin */
        .paint-c1 { fill: var(--copper); }
        .paint-c2 { fill: var(--brass); }
        .paint-c3 { fill: var(--sage); }
        .paint-c4 { fill: var(--oxblood-soft); }
        .paint-tick { fill: var(--gold-leaf); }
        /* Mutation-tick swatch for the legend line. */
        .legend-tick {
            display: inline-block;
            width: 3px;
            height: 11px;
            background: var(--gold-leaf);
            vertical-align: -1px;
            margin-right: 2px;
        }
        /* Collapsible "read the full sequence" detail — the DNA letters
           are demoted to detail; the painting strip carries the story. */
        .seq-detail { margin: 2px 0 4px; }
        .seq-detail > summary {
            font-family: var(--font-serif);
            font-style: italic;
            font-size: 13px;
            color: var(--copper);
            cursor: pointer;
            list-style: none;
            padding: 2px 0;
        }
        .seq-detail > summary::-webkit-details-marker { display: none; }
        .seq-detail > summary::before {
            content: "› ";   /* rotates a quarter-turn when open */
            display: inline-block;
            transition: transform var(--motion-quick);
        }
        .seq-detail[open] > summary::before { transform: rotate(90deg); }
        .seq-detail > summary:hover { color: var(--copper-hover); }

        /* De novo point mutations introduced during gametogenesis.
           Composes with .seq-prov color classes (so the parental-homolog
           color survives), adds a glowing accent outline + thick under-
           border so a mutated base reads as "different" at any zoom
           without competing with the four-color provenance shading.
           Tooltip on hover shows the original→mutant base swap. */
        .mutated-base {
            background: rgba(212, 175, 55, 0.20);
            border-bottom: 2px solid var(--gold-leaf);
            border-radius: 1px;
            padding: 0 1px;
            font-weight: 700;
            box-shadow: 0 0 4px var(--gold-leaf-glow);
        }

        /* Allele-row badge that signals "this allele picked up N de novo
           mutations during the meiosis that built it." Sits next to the
           recombinant/passthrough badge in the header. Gold-leaf
           treatment hints that mutations are the rare, prized event. */
        .mutation-badge {
            display: inline-block;
            margin-left: 6px;
            padding: 1px 8px;
            border-radius: 1px;
            background: rgba(212, 175, 55, 0.16);
            color: var(--gold-leaf);
            font-family: var(--font-serif);
            font-size: 10.5px;
            font-weight: 600;
            letter-spacing: 0.14em;
            text-transform: uppercase;
            font-feature-settings: "smcp", "lnum";
            border: 1px solid rgba(212, 175, 55, 0.5);
        }

        .locus-actions {
            margin-top: 8px;
            display: flex;
            gap: 8px;
            font-size: 13px;
        }
        .locus-actions button {
            background: none;
            border: none;
            color: var(--accent);
            cursor: pointer;
            padding: 4px 0;
            font: inherit;
            font-size: 13px;
        }
        .locus-actions button:hover {
            color: var(--accent-hover);
        }

        /* ---- Locus annotation (about this gene + cross-species) ---- */

        /* "About this gene" gloss — a printed margin note, not a
           raised UI panel: faint copper wash, a copper hairline rule,
           serif text, square corners. Sits in keeping with the
           field-journal page rather than reading as a web card. */
        .locus-summary {
            background: var(--copper-dim);
            border-left: 2px solid var(--copper);
            border-radius: 0;
            padding: 9px 13px;
            color: var(--ink-muted);
            font-family: var(--font-serif);
            font-size: 13.5px;
            line-height: 1.55;
            margin-bottom: 14px;
        }
        .locus-summary > div + div { margin-top: 5px; }
        .locus-summary strong {
            color: var(--copper);
            font-weight: 600;
            font-feature-settings: "smcp";
        }

        /* ---- Loci at a glance (Observations page) ----
           A compact field-journal index of the genome's loci so the
           Observations leaf carries a genetic synopsis, not just the
           visible-trait grid. */
        .loci-glance-synopsis {
            font-family: var(--font-serif);
            font-style: italic;
            font-size: 14px;
            color: var(--ink-muted);
            margin: 0 0 10px;
            line-height: 1.5;
        }
        /* A responsive grid of tappable infographic cards — one per locus.
           Each shows the allele(s) present, what they encode, and a de-novo
           badge; clicking jumps to that locus in the Loci tab. */
        .loci-glance {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(232px, 1fr));
            gap: 10px;
            list-style: none;
            margin: 0;
            padding: 0;
        }
        .lg-card {
            display: block;
            width: 100%;
            text-align: left;
            font: inherit;
            color: var(--ink);
            cursor: pointer;
            background: var(--bg-vellum);
            border: 1px solid var(--rule);
            border-left: 3px solid var(--rule-strong);  /* category accent */
            border-radius: 2px;
            padding: 9px 11px;
            transition: border-color var(--motion-quick),
                        box-shadow var(--motion-quick),
                        transform var(--motion-quick);
        }
        .lg-card:hover,
        .lg-card:focus-visible {
            outline: none;
            border-color: var(--copper);
            box-shadow: 0 3px 12px rgba(0, 0, 0, 0.28);
            transform: translateY(-1px);
        }
        .lg-card--pigment    { border-left-color: var(--copper); }
        .lg-card--structure  { border-left-color: var(--brass); }
        .lg-card--morphology { border-left-color: var(--sage); }
        .lg-card-head {
            display: flex;
            align-items: center;
            gap: 7px;
            margin-bottom: 6px;
        }
        .lg-dot {
            width: 8px;
            height: 8px;
            border-radius: 50%;
            flex: none;
        }
        .lg-dot--pigment    { background: var(--copper); }
        .lg-dot--structure  { background: var(--brass); }
        .lg-dot--morphology { background: var(--sage); }
        .lg-name {
            font-family: var(--font-serif);
            font-weight: 600;
            font-size: 14.5px;
            color: var(--ink);
        }
        .lg-zyg {
            font-family: var(--font-serif);
            font-size: 9.5px;
            letter-spacing: 0.08em;
            text-transform: uppercase;
            font-feature-settings: "smcp", "lnum";
            color: var(--ink-muted);
        }
        /* De-novo mutation badge — gold, like the rest of the mutation accents. */
        .lg-mut {
            margin-left: auto;
            font-family: var(--font-serif);
            font-size: 10px;
            color: var(--gold-leaf);
            background: rgba(212, 175, 55, 0.16);
            border: 1px solid rgba(212, 175, 55, 0.5);
            border-radius: 2px;
            padding: 1px 6px;
            white-space: nowrap;
            font-feature-settings: "lnum";
        }
        .lg-alleles { display: flex; flex-direction: column; gap: 3px; }
        .lg-allele { font-size: 12px; line-height: 1.42; }
        .lg-allele-name {
            font-family: var(--font-mono);
            font-size: 11px;
            color: var(--copper);
            margin-right: 5px;
        }
        /* A mutated allele's name reads gold + carries a ✦ (added in JS). */
        .lg-allele.is-mutated .lg-allele-name { color: var(--gold-leaf); }
        .lg-allele-encodes { color: var(--ink-muted); }
        /* Mendelian dominance marker — a small glyph + small-caps label chip
           per allele, colour-coded by class (hover gives the full meaning). */
        .lg-dom {
            display: inline-flex;
            align-items: center;
            gap: 3px;
            margin-right: 6px;
            padding: 0 4px;
            border: 1px solid var(--rule);
            border-radius: 2px;
            font-family: var(--font-serif);
            font-size: 8.5px;
            letter-spacing: 0.06em;
            text-transform: uppercase;
            font-feature-settings: "smcp", "lnum";
            vertical-align: 1px;
            white-space: nowrap;
            color: var(--ink-muted);
        }
        .lg-dom-glyph { font-size: 8px; line-height: 1; }
        .lg-dom--dominant    { color: var(--copper); border-color: var(--copper); }
        .lg-dom--recessive   { color: var(--ink-faint); }
        .lg-dom--co_dominant { color: var(--sage); border-color: var(--sage); }
        .lg-dom--incomplete  { color: var(--brass); border-color: var(--brass); }

        .cross-species {
            margin-top: 12px;
            font-size: 13px;
        }
        /* Variant-similarity caption — a serif italic note, not a
           sans-serif UI label. */
        .cs-header {
            font-family: var(--font-serif);
            font-style: italic;
            color: var(--text-muted);
            margin-bottom: 8px;
        }
        /* Cross-species similarity — a ruled figure table, matching the
           species-mix table. The JS-emitted .cs-track/.cs-fill drop out. */
        .cs-bar {
            display: flex;
            align-items: baseline;
            justify-content: space-between;
            gap: 14px;
            padding: 4px 2px;
            border-bottom: 1px solid var(--rule);
        }
        .cs-bar:last-child { border-bottom: 0; }
        .cs-bar .cs-label {
            font-family: var(--font-serif);
            font-size: 14px;
            color: var(--ink);
        }
        .cs-bar.is-self .cs-label {
            font-weight: 600;
            color: var(--copper);
        }
        .cs-bar .cs-track { display: none; }
        .cs-bar .cs-pct {
            font-family: var(--font-serif);
            font-size: 14px;
            color: var(--ink-muted);
            font-variant-numeric: tabular-nums lining-nums;
            text-align: right;
        }
        .cs-bar.is-self .cs-pct { color: var(--copper); }

        /* ---- Footer (downloads + hash) ---- */

        .result-footer {
            display: flex;
            justify-content: space-between;
            align-items: center;
            gap: 16px;
            flex-wrap: wrap;
        }
        .result-footer-actions {
            display: flex;
            gap: 8px;
            flex-wrap: wrap;
        }
        .image-hash {
            font-family: ui-monospace, "SF Mono", Menlo, monospace;
            font-size: 12px;
            color: var(--text-faint);
        }

        /* The disclaimer rides on the camp scene at the very bottom of
           the viewport, clear of the book. */
        footer.foot {
            position: fixed;
            left: 0;
            right: 0;
            bottom: 3px;
            z-index: 2;
            color: rgba(232, 220, 196, 0.34);
            font-family: var(--font-serif);
            font-style: italic;
            font-size: 11px;
            text-align: center;
            letter-spacing: 0.02em;
            pointer-events: none;
        }

        /* ---- Starter-deck picker (one-time onboarding) ---- */
        .deck-picker-modal { max-width: 720px; width: min(720px, 94vw); }
        .deck-picker-intro {
            font-family: var(--font-serif);
            font-style: italic;
            color: var(--ink-muted);
            margin: 0 0 16px;
        }
        .deck-grid {
            display: grid;
            grid-template-columns: repeat(2, minmax(0, 1fr));
            gap: 14px;
            max-height: 60vh;
            overflow-y: auto;
            scrollbar-gutter: stable;
            padding: 2px;
        }
        @media (max-width: 560px) {
            .deck-grid { grid-template-columns: 1fr; }
        }
        .deck-card {
            display: flex;
            flex-direction: column;
            gap: 8px;
            background: var(--bg-ink);
            border: 1px solid var(--rule-strong);
            padding: 12px;
            text-align: left;
        }
        .deck-card-name {
            font-family: var(--font-serif);
            font-size: 17px;
            color: var(--copper);
        }
        .deck-card-blurb {
            font-family: var(--font-serif);
            font-size: 12px;
            line-height: 1.45;
            color: var(--ink-muted);
            min-height: 50px;
        }
        /* Preview thumbnails — minmax(0,1fr) lets the cells shrink below the
           images' intrinsic width instead of overflowing the card. */
        .deck-preview-grid {
            display: grid;
            grid-template-columns: repeat(4, minmax(0, 1fr));
            gap: 4px;
        }
        .deck-preview-grid img {
            display: block;
            width: 100%;
            aspect-ratio: 1 / 1;
            object-fit: cover;
            background: var(--bg-vellum);
            border: 1px solid var(--rule);
        }
        .deck-card-claim {
            margin-top: 4px;
            align-self: stretch;
        }
        /* Generate-page teaser → opens the deck picker while unclaimed. A
           prominent banner (creature thumbnail + copy + CTA) at the foot of the
           starter plate, so the free-deck on-ramp is hard to miss. */
        .deck-claim-chip {
            display: flex;
            align-items: center;
            gap: 14px;
            width: 100%;
            max-width: 430px;
            margin: 24px auto 0;
            padding: 12px 16px;
            text-align: left;
            background: linear-gradient(180deg,
                rgba(201, 139, 86, 0.16), rgba(201, 139, 86, 0.06));
            border: 1px solid var(--copper);
            border-radius: 4px;
            cursor: pointer;
            box-shadow:
                inset 0 1px 0 rgba(232, 220, 196, 0.10),
                0 4px 14px rgba(0, 0, 0, 0.40);
            transition: border-color var(--motion-quick),
                        background var(--motion-quick),
                        transform var(--motion-quick);
        }
        .deck-claim-chip:hover {
            border-color: var(--copper-hover);
            background: linear-gradient(180deg,
                rgba(201, 139, 86, 0.24), rgba(201, 139, 86, 0.11));
            transform: translateY(-1px);
        }
        .deck-claim-thumb {
            flex: none;
            width: 54px;
            height: 54px;
            object-fit: cover;
            border-radius: 3px;
            background: #efe8d6;   /* cream while loading (matches the frames) */
            box-shadow: 0 0 0 1px var(--rule-strong), 0 2px 5px rgba(0, 0, 0, 0.45);
        }
        .deck-claim-body { display: flex; flex-direction: column; gap: 2px; flex: 1 1 auto; }
        .deck-claim-title {
            font-family: var(--font-serif);
            font-size: 15px;
            color: var(--ink);
        }
        .deck-claim-sub {
            font-family: var(--font-serif);
            font-size: 12px;
            font-style: italic;
            color: var(--ink-muted);
            line-height: 1.35;
        }
        .deck-claim-cta {
            flex: none;
            font-family: var(--font-serif);
            font-size: 12.5px;
            font-weight: 600;
            letter-spacing: 0.10em;
            text-transform: uppercase;
            font-feature-settings: "smcp", "lnum";
            color: var(--brass);
        }
        .deck-claim-chip[hidden] { display: none; }

        /* ---- Cosmetic frame picker (#97) ----
           The opener (#card-frame-btn) now lives in the card-actions row as a
           glyph button (.card-action-btn, styled in card.css). */
        .frame-modal-content { max-width: 460px; width: min(460px, 92vw); }
        .frame-modal-intro {
            font-family: var(--font-serif);
            font-size: 13px;
            color: var(--ink-muted);
            margin: 0 0 14px;
        }
        .frame-modal-bal { color: var(--gold-leaf); }
        .frame-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
            gap: 10px;
            margin-bottom: 6px;
        }
        .frame-swatch {
            display: flex;
            flex-direction: column;
            align-items: stretch;
            gap: 6px;
            background: var(--bg-ink);
            border: 1px solid var(--rule-strong);
            padding: 10px 8px;
            cursor: pointer;
            text-align: center;
            transition: border-color var(--motion-quick), box-shadow var(--motion-quick);
        }
        .frame-swatch:hover:not(:disabled) { border-color: var(--copper); }
        .frame-swatch.is-on {
            border-color: var(--copper);
            box-shadow: 0 0 0 2px var(--copper-dim);
        }
        .frame-swatch:disabled { opacity: 0.4; cursor: not-allowed; }
        .frame-swatch-chip {
            height: 26px;
            border-radius: 2px;
            border: 1px solid rgba(0, 0, 0, 0.45);
        }
        .frame-swatch-label {
            font-family: var(--font-serif);
            font-size: 13px;
            color: var(--ink);
        }
        .frame-swatch-cost { font-size: 11px; color: var(--gold-leaf); }
