/* create-pet.css: The Prism Observatory create-pet workbench. */
/* ===== CREATE PET WORKBENCH =====
   Celestial-Workbench-style layout: labeled trays for identity/species/colors/
   markings on the left, a sticky live-preview + cost "receipt" on the right: 
   see docs/ux-direction-set.md direction 3. The one signature element is the
   forge preview itself (radial containment field + a charging ring while a
   composite is in flight); everything else stays quiet and reuses existing
   tokens/patterns rather than introducing new color or decoration. */
.create-pet-intro { max-width: 640px; }
.create-pet-intro p { color: var(--text-secondary); }
.create-pet-eyebrow {
    margin: 0 0 6px;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.14em;
    font-size: 0.78em;
    font-weight: 700;
}

.create-pet-form { max-width: none; }

.workbench-grid {
    display: grid;
    grid-template-columns: 1fr 320px;
    gap: 24px;
    align-items: start;
}

.workbench-main { display: flex; flex-direction: column; gap: 20px; min-width: 0; }

.workbench-section {
    background: var(--bg-surface);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    padding: 18px 20px;
}
.workbench-section input[type="text"] { max-width: 420px; }

/* Every tray shares one header treatment: a hairline rule with a short
   gradient accent, so the page reads as one designed surface rather than a
   stack of generic bordered boxes. Repeated restrained motif, not a glow. */
.workbench-section-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    position: relative;
    padding-bottom: 10px;
    margin-bottom: 14px;
    border-bottom: 1px solid var(--border-subtle);
}
.workbench-section-header::after {
    content: '';
    position: absolute;
    left: 0;
    bottom: -1px;
    width: 28px;
    height: 2px;
    background: var(--gradient-primary);
}
.workbench-section-title { margin: 0; font-size: 1.05em; font-weight: 700; color: var(--text-primary); }
.workbench-section-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
.workbench-action-status { color: var(--color-success-text); font-size: 0.78em; }
.marking-count { color: var(--text-muted); font-weight: 500; font-size: 0.85em; }
.randomizer-options {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px 14px;
    margin: -2px 0 14px;
    color: var(--text-secondary);
    font-size: 0.82em;
}
.randomizer-count,
.randomizer-toggle { display: flex; align-items: center; gap: 6px; }
.randomizer-count input[type="number"] { width: 4.2rem; min-height: 34px; }
.randomizer-toggle { cursor: pointer; }
.randomizer-help { color: var(--text-muted); }

/* Species picker: radio cards styled like the parent-pick-card pattern
   elsewhere in the site. Radio input is visually hidden but stays
   keyboard-focusable, with the checked/focus states surfaced on the card via
   :has() rather than JS, so it degrades to a normal fieldset without Alpine. */
.species-picker-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
    gap: 10px;
}
.species-pick-card {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    padding: 14px 8px;
    border: 2px solid var(--border-color);
    border-radius: var(--radius-md);
    background: var(--bg-subtle);
    cursor: pointer;
    text-align: center;
}
.species-pick-card input[type="radio"] {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
}
@media (hover: hover) { .species-pick-card:hover { border-color: var(--color-primary); } }
.species-pick-card:has(input:checked) { border-color: var(--color-primary); background: var(--bg-hover); }
.species-pick-card:has(input:focus-visible) { outline: 2px solid var(--color-primary); outline-offset: 2px; }
/* Dormant until picked, then "charges" into the same gradient-medallion
   language as .default-avatar (profile identity badges): a species becomes
   a chosen material, not just a highlighted option. */
.species-pick-sigil {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    border: 1px solid var(--border-color);
    background: var(--bg-surface);
    color: var(--text-muted);
    font-weight: 700;
    font-size: 0.95em;
}
.species-pick-card:has(input:checked) .species-pick-sigil {
    background: var(--gradient-primary);
    border-color: transparent;
    color: var(--text-inverse);
}
.species-pick-name { font-weight: 600; color: var(--text-primary); font-size: 0.9em; }
.species-pick-cost { font-size: 0.78em; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.species-pick-cost--free { color: var(--color-success-text); font-weight: 600; }
/* Says why an off-list species costs Prisms while a free forge is available. The
   card stays fully pickable: the note prices it, it doesn't gate it. */
.species-pick-note { font-size: 0.7em; color: var(--text-muted); text-align: center; line-height: 1.2; }

/* Colors laid out as material samples: the native swatch itself is the
   sample, with a plain hex caption beneath it: no second colored chip
   competing for the same job (and unreadable for light hues like white). */
.color-material-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    gap: 14px;
}
/* .color-material is a <div> (not a <label>): the global label flex is no longer
   inherited, so set it explicitly. See create_pet.html for why it can't be a label. */
.color-material { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
.color-material-label { font-size: 0.8em; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted); }
.color-material input[type="color"] {
    width: 56px;
    height: 40px;
    padding: 0;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    background: var(--bg-surface);
    cursor: pointer;
}
.color-material-hex { font-size: 0.78em; color: var(--text-secondary); font-variant-numeric: tabular-nums; }

/* Desktop-only custom colour popover, REPLACING the native OS colour popup on desktop
   (it exposes only RGB boxes with no pastable hex field on some browsers). On touch the
   native <input type="color"> stays the swatch, byte-identical to before; on desktop it is
   hidden as the value store and a custom swatch button opens this popover instead. Gated on
   a 1024px minimum plus `hover: hover`, so phones and tablets are untouched. The popover reuses
   the barracks .pet-group-manage-menu (toggler + click-outside + Escape, un-animated); its
   own guarded :hover is the only one involved, so the hover-sweep is unaffected.
   `.color-swatch-wrap` is the position:relative containing block for the absolute popover.
   Guards: pets/test_create_pet_ui.py::ColorPopover*, game/test_css_positioning.py. */
.color-swatch-wrap { position: relative; display: inline-flex; align-items: center; gap: 6px; }
.color-swatch-btn { display: none; }   /* the desktop-only trigger (hidden on touch) */
.color-swatch-btn:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }
.color-control .color-native-swatch {
    width: 56px;
    height: 40px;
    padding: 0;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    background: var(--bg-surface);
    cursor: pointer;
}
.color-control .color-native-swatch.color-swatch-btn--marking { width: 32px; height: 28px; }

/* The popover panel: an elevated card on the page's own tokens (radius/shadow/elevated
   surface like the nav dropdowns), a live preview + hex on top, an even RGB grid below. */
.color-popover {
    /* Explicit width, not just min-width: the panel is position:absolute, so without it
       the number inputs' intrinsic (max-content) width sizes the whole popover far wider
       than intended. With a fixed width the minmax(0,1fr) RGB columns share it evenly. */
    width: 236px;
    padding: 13px;
    gap: 11px;
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    background: var(--bg-elevated);
}
.color-popover__cap {
    font-family: var(--font-mono);
    font-size: 0.62rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-muted);
}
.color-popover__hex { display: flex; flex-direction: column; gap: 5px; }
.color-popover__top { display: flex; flex-direction: row; align-items: center; gap: 8px; margin: 0; }
.color-popover__preview {
    width: 36px;
    height: 36px;
    flex-shrink: 0;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border-color);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.06);
}
/* minmax(0, 1fr), not 1fr: a number input's default intrinsic width would otherwise
   inflate each column (and the whole popover) well past the min-width. */
.color-popover__rgb { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.color-popover__ch { flex-direction: column; align-items: stretch; gap: 4px; margin: 0; }
.color-popover__ch .color-popover__cap { text-align: center; }
.color-hex-input {
    flex: 1;
    min-width: 0;
    padding: 6px 9px;
    line-height: 1.3;
    font-family: var(--font-mono);
    font-size: 0.9rem;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}
.color-rgb-input {
    width: 100%;
    padding: 6px 4px;
    line-height: 1.3;
    text-align: center;
    font-family: var(--font-mono);
    font-size: 0.9rem;
}
/* Clean centred numbers: drop the spinner buttons (keyboard ↑/↓ still steps). */
.color-rgb-input::-webkit-inner-spin-button,
.color-rgb-input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.color-rgb-input { -moz-appearance: textfield; appearance: textfield; }

@media (min-width: 1024px) and (hover: hover) and (pointer: fine) {
    /* Desktop only: hide the native swatch, show the custom button that opens the
       iOS-inspired picker. Tablets and phones retain the OS picker. */
    .color-control .color-native-swatch { display: none; }
    .color-swatch-btn {
        display: inline-block;
        width: 56px;
        height: 40px;
        padding: 0;
        border: 1px solid var(--border-color);
        border-radius: var(--radius-sm);
        cursor: pointer;
        transition: border-color 0.12s ease, box-shadow 0.12s ease;
    }
    .color-swatch-btn:hover { border-color: var(--color-primary); box-shadow: 0 0 0 3px var(--bg-hover); }
    .color-swatch-btn--marking { width: 32px; height: 28px; }
}

.color-control-label { color: var(--text-secondary); }
.color-picker-popover {
    position: fixed;
    z-index: 100;
    width: 270px;
    max-width: calc(100vw - 24px);
    max-height: calc(100dvh - 24px);
    overflow-y: auto;
    overscroll-behavior: contain;
    box-sizing: border-box;
    padding: 12px;
    gap: 10px;
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    background: var(--bg-elevated);
}
.color-picker__topline { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.color-picker__topline strong { font-size: .84rem; color: var(--text-primary); }
.color-picker__tabs {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 3px;
    padding: 3px;
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-pill);
    background: var(--bg-subtle);
}
.color-picker__tab {
    min-height: 32px;
    padding: 5px 6px;
    border: 0;
    border-radius: var(--radius-pill);
    background: transparent;
    color: var(--text-muted);
    font-size: .75rem;
    font-weight: 700;
    cursor: pointer;
}
@media (hover: hover) { .color-picker__tab:hover { color: var(--text-primary); } }
.color-picker__tab.is-active {
    background: var(--bg-elevated);
    color: var(--text-primary);
    box-shadow: var(--shadow-sm);
}
.color-picker__tab:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 1px; }
.color-picker__mode { display: flex; flex-direction: column; gap: 12px; }
.color-picker__subtabs {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 3px;
    padding: 3px;
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-pill);
    background: var(--bg-subtle);
}
.color-picker__subtab {
    min-height: 30px;
    padding: 4px 6px;
    border: 0;
    border-radius: var(--radius-pill);
    background: transparent;
    color: var(--text-muted);
    font-family: var(--font-mono);
    font-size: .7rem;
    font-weight: 700;
    cursor: pointer;
}
@media (hover: hover) { .color-picker__subtab:hover { color: var(--text-primary); } }
.color-picker__subtab.is-active {
    background: var(--bg-elevated);
    color: var(--text-primary);
    box-shadow: var(--shadow-sm);
}
.color-picker__subtab:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 1px; }
.color-picker__grid {
    display: grid;
    grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: 8px;
}
.color-picker__grid-swatch {
    aspect-ratio: 1;
    min-width: 0;
    padding: 0;
    border: 2px solid transparent;
    border-radius: 50%;
    box-shadow: inset 0 0 0 1px rgb(0 0 0 / 25%);
    cursor: pointer;
    transition: transform .12s ease, box-shadow .12s ease;
}
@media (hover: hover) { .color-picker__grid-swatch:hover { transform: scale(1.08); } }
.color-picker__grid-swatch.is-selected {
    box-shadow: 0 0 0 2px var(--bg-elevated), 0 0 0 4px var(--color-primary);
}
.color-picker__grid-swatch:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }
.color-picker__sliders { display: flex; flex-direction: column; gap: 10px; }
.color-picker__slider-row {
    display: grid;
    grid-template-columns: 42px minmax(0, 1fr) 54px;
    align-items: center;
    gap: 8px;
    margin: 0;
}
.color-picker__slider-row .color-popover__cap { letter-spacing: .04em; }
.color-picker__slider-row input[type="range"] { width: 100%; min-width: 0; margin: 0; }
.color-picker__slider-row .color-rgb-input { width: 54px; }
.color-picker__slider--r { accent-color: #ff3b30; }
.color-picker__slider--g { accent-color: #34c759; }
.color-picker__slider--b { accent-color: #0a84ff; }
.color-picker__slider--h { accent-color: #af52de; }
.color-picker__slider--s { accent-color: #34c759; }
.color-picker__slider--l { accent-color: #ff9500; }
.color-picker__spectrum {
    position: relative;
    height: 140px;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    background:
        linear-gradient(to bottom, transparent 0%, #000 100%),
        linear-gradient(to right, #fff 0%, hsl(var(--picker-hue) 100% 50%) 100%);
    cursor: crosshair;
    touch-action: none;
}
.color-picker__spectrum:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 3px; }
.color-picker__spectrum-thumb {
    position: absolute;
    width: 18px;
    height: 18px;
    transform: translate(-50%, -50%);
    border: 2px solid #fff;
    border-radius: 50%;
    box-shadow: 0 0 0 1px rgb(0 0 0 / 70%), 0 1px 4px rgb(0 0 0 / 45%);
    pointer-events: none;
}
.color-picker__hue { display: flex; flex-direction: column; gap: 5px; margin: 0; }
.color-picker__hue input[type="range"] {
    width: 100%;
    height: 18px;
    margin: 0;
    border-radius: var(--radius-pill);
    accent-color: var(--color-primary);
    background: linear-gradient(to right, #f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00);
}
.color-picker__precise { display: flex; flex-direction: column; gap: 10px; }
.color-picker__hex { display: flex; flex-direction: column; gap: 5px; margin: 0; }
.color-picker__hex .color-hex-input { width: 100%; }

@media (max-width: 1024px), (hover: none), (pointer: coarse) {
    .color-picker-popover { max-width: calc(100vw - 24px); }
}

@media (max-height: 680px) and (min-width: 1024px) and (hover: hover) and (pointer: fine) {
    .color-picker-popover { padding: 10px; gap: 8px; }
    .color-picker__mode { gap: 8px; }
    .color-picker__spectrum { height: 120px; }
    .color-picker__grid { gap: 6px; }
    .color-picker__sliders { gap: 7px; }
}

/* Markings as cards, echoing pet_detail's .marking-row treatment. */
.marking-card {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    background: var(--bg-subtle);
    border: 1px solid var(--border-color);
    border-left: 3px solid var(--border-color);
    border-radius: var(--radius-sm);
    padding: 10px 12px;
    margin-top: 10px;
}
.marking-card select { flex: 1 1 140px; }
.marking-swatch { display: flex; align-items: center; gap: 6px; }
.marking-swatch input[type="color"] {
    width: 32px;
    height: 28px;
    padding: 0;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    background: var(--bg-surface);
    cursor: pointer;
}
.marking-hex { font-size: 0.78em; color: var(--text-secondary); font-variant-numeric: tabular-nums; }
.marking-opacity { flex-direction: row; align-items: center; gap: 6px; font-size: 0.85em; color: var(--text-secondary); }
.marking-opacity input[type="range"] { width: 100px; }
/* Per-row action cluster (reorder ↑/↓ + randomize 🎲 + remove), pushed to the row's end. */
.marking-actions { display: flex; align-items: center; gap: 8px; margin-left: auto; }
.marking-dice { line-height: 1; }
/* Marking reorder (creation page only). The ⠿ drag handle is desktop-only because
   HTML5 drag never fires on touch: the ↑/↓ nudge buttons are the touch/keyboard path
   and stay on every device. `.drag-handle` (shared) supplies the look; this only gates
   its visibility. Guard: pets/test_create_pet_ui.py::MarkingReorderTests. */
.marking-drag-handle { display: none; }
@media (hover: hover) { .marking-drag-handle { display: inline-flex; align-items: center; } }
.marking-card--drag-source { opacity: 0.55; }
.marking-reorder-hint { margin: 0 0 4px; font-size: 0.8em; color: var(--text-muted); }
/* Touch floor for the reorder nudges: .reorder-nudge__btn's own 22px beats the global
   :where(button) coarse floor, so restate it here, same as the dressing room does. */
@media (pointer: coarse) { .marking-actions .reorder-nudge__btn { width: 44px; height: 44px; } }

/* Sticky aside: the live composite is the primary object on the page. */
.workbench-aside {
    display: flex;
    flex-direction: column;
    gap: 16px;
    position: sticky;
    top: calc(var(--header-height) + 20px);
}
.preview-frame {
    background: var(--bg-surface);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    padding: 16px;
    text-align: center;
}
/* The signature moment: a quiet containment field (a faint radial
   vignette) that "charges" with a conic ring while a
   composite is in flight, and gives the finished pet a soft glow: the one
   place on this page glow is earned, per the workbench direction's own rule
   to reserve it for a genuinely actionable/rewarding state. */
.preview-canvas {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 260px;
    background: radial-gradient(ellipse at center, var(--bg-hover) 0%, var(--bg-subtle) 70%);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    margin-bottom: 10px;
    overflow: hidden;
    transition: opacity 0.15s ease;
}
.preview-canvas::before {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    border: 2px solid transparent;
    background: conic-gradient(var(--color-primary), var(--color-primary-dark), var(--color-primary)) border-box;
    -webkit-mask: linear-gradient(#000 0 0) padding-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
    mask-composite: exclude;
    opacity: 0;
    animation: preview-charge 1.4s linear infinite;
}
.preview-canvas.htmx-request { opacity: 1; }
.preview-canvas.htmx-request::before { opacity: 1; }
@keyframes preview-charge { to { transform: rotate(1turn); } }
.preview-canvas img {
    max-width: 100%;
    height: auto;
    border-radius: var(--radius-sm);
    filter: drop-shadow(0 0 16px var(--color-primary));
}
.preview-placeholder { color: var(--text-muted); font-size: 0.85em; padding: 0 12px; margin: 0; }
/* The Prism purchase page's "preview a reward on your pet" box sits in a
   full-width .panel, not a two-pane grid cell like .mw-compare gives the
   Mutation Workshop's own .preview-canvas: without a cap here the box (and
   the single 500x500 image inside it) stretched across the whole panel,
   leaving a bare strip of the box's own background on one side. Centering it
   at its own natural image size, the same as the box the image actually
   fills, is what "tightens" it back up. */
.bonus-item-preview-canvas { max-width: 500px; width: 100%; margin: 0 auto; }
/* Pairs the charging-ring animation with a text status: the ring alone is a
   motion-only signal, and reduced-motion users only get a static ring. */
.preview-compositing-label {
    margin: 8px 0 0;
    text-align: center;
    font-size: 0.78em;
    color: var(--text-muted);
    visibility: hidden;
}
/* Keyed to the shared .preview-canvas class, not one page's container id: this
   was #pet-preview-container (create_pet's id), so the Mutation Workshop's own
   #pet-mutation-preview-container never matched and its aria-live status stayed
   permanently hidden, leaving the ring as the only in-flight signal. */
.preview-canvas.htmx-request + .preview-compositing-label { visibility: visible; }
.preview-refresh-btn { width: 100%; justify-content: center; }
.preview-rate-note {
    margin: 8px 0 0;
    color: var(--text-muted);
    font-size: 0.72em;
    text-align: center;
}

