/*
 * FIELDSETS-LAYOUT.CSS - Pure layout structure
 * NO colors, NO theming - just grids, spacing, responsive
 * Part of fieldsets split - see 009_FIELDSET_CSS_SPLIT.md
 * Updated: 2025-12-27 - New 3-column entity layouts
 */

/* ═══════════════════════════════════════════════════════════════════
   LAYOUT CONTAINERS
   ═══════════════════════════════════════════════════════════════════ */

/* .carousel-container REMOVED — the class was in no template, JS or view (dead since
   whatever markup used it went away). Its `padding: 1rem 0 0` looked exactly like a
   header gap in the stylesheet and sent us chasing it as the cause of a real one, so
   it's worse than clutter. Don't reintroduce a wrapper rule without markup to match. */

/* --layout-gap: THE single dial for the standalone layout rhythm. Defined on
   the page ROOT so everything below reads it — the .container-fluid wrapper's
   header gap, .entity-form's side padding, and every inter-fieldset/column gap.
   One line retunes the whole page (desktop + mobile). */
body.aurora-standalone {
    /* ONE portrait dial. The gallery (logged in), the gallery (pre-login) and chat each
       had their own — with different shapes, one carrying a +13svh roster reserve — and
       they all converged here once the preview became a grid measuring the same thing:
       viewport − this = the preview fieldset's height, 1:1. Three numbers that have to
       agree by hand is three chances to drift; one number can't. */
    --mobile-chrome: 181px;
    --layout-gap: 0;   /* EXPERIMENT: was 10px. Remove the grid rhythm entirely (side
                          padding + header/preview/footer gap + inter-fieldset gaps) and
                          lean on each fieldset's own padding — preview stretches border
                          to border, tabs overhang into the workspace. */
}

.entity-form {
    /* Side padding + own gap read the dial. The .container-fluid wrapper's side
       padding is zeroed just below so this is the only side gap. */
    padding: 0 var(--layout-gap);
    display: flex;
    flex-direction: column;
    gap: var(--layout-gap);
}

/* The form's wrapper (scoped via :has so admin / other container-fluids are
   untouched): side padding zeroed so .entity-form's is the only side gap, and
   the top gap below the site header reads the dial too — replaces the old
   hardcoded inline padding-top (gallery) / pt-4 (scene) on the change_forms. */
.container-fluid:has(.entity-form) {
    padding-top: var(--layout-gap);
    padding-left: 0;
    padding-right: 0;
}

/* ═══════════════════════════════════════════════════════════════════
   NEW 3-COLUMN ENTITY LAYOUT (Card-aligned)
   Row 1: Scene row (full width)
   Row 2: Preview | Attributes+Other | Identity (3 columns)
   Row 3: Technical (collapsed)
   ═══════════════════════════════════════════════════════════════════ */

/* Simple 2-column: Preview | Everything else */
.entity-2col {
    display: grid;
    grid-template-columns: 1fr minmax(0, 500px);  /* Preview flexible, fields up to 500px */
    gap: var(--layout-gap);   /* the layout dial (see .entity-form) */
    align-items: start;
}

/* Gallery flavor: search bar lives INSIDE preview-fieldset above
   the cards, pips moved below the cards (standalone-carousel.css).
   entity-fields has nothing on gallery; collapse to single column
   so the preview owns the whole width — otherwise the grid reserves
   up to 500px for an empty column and the carousel ends up cramped
   beside dead space. */
.entity-2col--gallery {
    grid-template-columns: 1fr;
}
.entity-2col--gallery .entity-fields {
    display: none;
}

/* Gallery reserves MORE desktop fill chrome than the scene/editor pages:
   its control surface carries the search bar + transport the others don't,
   so the strip must give that row room or it'd push the search off the
   bottom. --card-zoom is kept for the mobile gallery (desktop ignores it —
   the strip uses a definite fill height; see standalone-carousel.css). */
/* DEFINED ON .entity-2col--gallery, NOT on .carousel-standalone. The carousel is a
   DESCENDANT of the preview fieldset, and custom properties inherit DOWN only — so a
   chrome set there is invisible to the fieldset that now anchors off it (it silently
   took the 260px fallback while the card, being inside the carousel, used the real
   value: box and card computing from different numbers). Set it above the fieldset and
   both read the same one; it still inherits down to the carousel unchanged. */
.entity-2col--gallery {
    --card-zoom: 0.8;
    /* The gallery reserves NOTHING for the roster strip. It's row 3 of the preview
       grid, an `auto` track that sizes itself and collapses when there are no slots,
       so both galleries (logged in / out) share this one number. */
    --carousel-chrome: 207px;   /* desktop: viewport − this = the preview fieldset's height. 1:1. */
}

/* (The empty-roster reclaim lived here: the old model RESERVED the roster's height,
   so a logged-out visitor with no slot cards needed a second chrome number to take it
   back. The grid's roster track is `auto` and the empty strip is display:none'd in
   standalone-carousel.css, so it collapses on its own — both galleries share ONE
   number now, and the strip still "sucks back" into view the moment a slot lands.) */

/* Scene / chat pages carry a header face-tabs row (image/scene/memory/chat) that
   the gallery lacks. That row grows the header, so reserve its height in the fill
   chromes or the card clips off the bottom. On DESKTOP the same reserve feeds BOTH
   the carousel chrome AND the chat fieldset chrome (standalone-carousel.css) via
   --face-tabs-reserve, so the preview column + chat fieldset stay equal-height /
   bottom-aligned like before the row existed. Scene-only via :has(.aurora-header__
   scene-tabs) (the row renders only there); landscape hides the row (fieldsets-
   base.css). Portrait --mobile-chrome + reclaim live in the media query below. */
body:has(.aurora-header__scene-tabs) {
    --face-tabs-reserve: 34px;   /* was 40; face-tab buttons shortened 42 → 36px */
    /* 271 → 209 (−50 down, −12 to close the skew over the chat fieldset) → 219 (+10
       back up to clear scrollbars) → 218 (−1, final skew: preview sat 1px high).
       → 233: +15 up, the same lift the landscape strip + gallery needed (the pip row
       above the strip was never paid for). The chat column's own offset
       (standalone-carousel.css ~2750) takes the same +15 → 84, so the 233−84=149 diff
       (the real toolbar+gaps height the chat column lacks) is preserved. */
    --carousel-chrome: calc(180px + var(--face-tabs-reserve));   /* scene/chat/editor:
       viewport − this = the preview fieldset's height. 1:1. The chat COLUMN has its own
       dial (standalone-carousel.css); move both to shift the pair, one alone to correct
       a skew between them. */
}

/* Portrait scene-page reclaim. The card is HEIGHT-bound (width follows), and its
   back-face builder tags were clipping in the smaller card — so tighten the layout
   rhythm + header and let --mobile-chrome shrink IN STEP, and the card grows into
   the space. Scene-only + portrait; desktop (perfect) and gallery untouched. Nudge
   these together: if the card clips, raise --mobile-chrome; if a gap opens, lower it. */
@media (max-width: 700px) {
    body:has(.aurora-header__scene-tabs) {
        --layout-gap: 0;                       /* EXPERIMENT: was 5px — tight everywhere */
    }
    body:has(.aurora-header__scene-tabs) .aurora-header__strip {
        padding-top: 0.2rem;                   /* was 0.3rem — ~2px off above/below the title row */
        padding-bottom: 0.2rem;
    }
    body:has(.aurora-header__scene-tabs) .aurora-header__scene-tabs .aurora-header__nav-btn {
        height: 30px;                          /* toolbar Create/Discover height (was 36) */
    }
}

/* Preview column - let Django handle sizing.
   gap matches .entity-fields' 0.75rem so when the gallery transport
   bar renders as a sibling of the preview fieldset (gallery layout),
   they're spaced the same as the chat/gen-settings stack on the
   other pages instead of butting up against each other. */
.entity-2col .entity-preview {
    display: flex;
    flex-direction: column;
    gap: var(--layout-gap);   /* the layout dial */
    min-width: 0;
    /* Paint ABOVE the fields column. The chat fieldset runs past the toolbar, and grid
       items otherwise paint in DOM order — .entity-fields comes second, so the chat
       covered the footer tabs and the preview's controls. This lifts the whole preview
       column (card + generate, toolbar + its tabs) over it in one place.
       NO position:relative — a grid item takes z-index on its own. Adding it here made
       the legacy `.entity-preview { position:sticky; top:1rem }` rule below suddenly
       BITE: sticky offsets nothing at rest, but relative + top:1rem shoved the whole
       column down 16px on every page. */
    z-index: 1;
}

.entity-2col .entity-preview .fieldset {
    /* Content-sized by default (mobile + gallery, whose strip uses a definite
       fill height). The scene/editor/chat preview fieldset flexes on desktop
       (below) so the carousel fills the page. */
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
}

/* Desktop carousel fill: ALL layouts now use a DEFINITE strip height
   (standalone-carousel.css: viewport − --carousel-chrome). The non-gallery
   pages used to flex-fill here, but that height-chain collapsed the cards to
   pips; they share the gallery's robust definite-height path now. The preview
   column + fieldset stay content-height (default) and wrap the definite strip —
   no flex-fill setup needed. Non-gallery --carousel-chrome defaults to 260px
   (the calc fallback); set it explicitly below if chat/editor need to differ. */

.entity-2col .entity-preview .preview-image {
    flex: 1;
    min-height: 300px;
}

.entity-2col .entity-preview .preview-image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Fields column - stacks naturally */
.entity-2col .entity-fields {
    display: flex;
    flex-direction: column;
    gap: var(--layout-gap);   /* the layout dial */
    min-width: 0;  /* Allow shrinking */
}

/* Scene row - 4 inline fields like card Row 1 */
.scene-row-fieldset {
    margin-bottom: 0;
}

.scene-row-grid {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr 2fr;
    gap: 0.75rem;
}

/* Main 3-column grid - matches card Row 2 */
.entity-main-grid {
    display: grid;
    grid-template-columns: 1fr 2fr 1fr;
    gap: 1rem;
    align-items: start;
}

/* Preview column — the old `position: sticky; top: 1rem` is GONE. It was stale from the
   3-column layout (the column is full-height anchored now, so there was nothing to stick
   to) AND it was a live trap: sticky offsets nothing at rest, so the top:1rem sat inert
   until something else set position, at which point the whole column dropped 16px on
   every page. Don't reintroduce a position here without a top/bottom to match. */

/* Middle column - attributes + other entity picker */
.entity-middle {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

/* 2x3 attribute grid - 2 columns everywhere for consistency
   Desktop matches mobile - simpler maintenance */
.attr-grid-2x3 {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    grid-template-rows: repeat(3, auto);
    gap: 0.5rem;
}

/* v9.0: 3x2 attribute grid - 3 columns, 2 rows for character attributes
   Row 1: Hair, Eyes, Outfit (color + style)
   Row 2: Hair elements, Face elements, Outfit elements */
.attr-grid-3x2 {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-template-rows: repeat(2, auto);
    gap: 0.5rem;
}

/* v9.0: 1x3 attribute grid - single row of 3 equal columns (hair, eye, outfit) */
.attr-grid-1x3 {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0.5rem;
}

/* Compact fieldsets in attr grid - anchor content to bottom for alignment */
.attr-grid-2x3 .fieldset--compact,
.attr-grid-3x2 .fieldset--compact,
.attr-grid-1x3 .fieldset--compact {
    display: flex;
    flex-direction: column;
}

/* Title stays at top, content area grows and pushes Select2 to bottom */
.attr-grid-2x3 .fieldset--compact > :not(h2):last-child,
.attr-grid-3x2 .fieldset--compact > :not(h2):last-child,
.attr-grid-1x3 .fieldset--compact > :not(h2):last-child {
    margin-top: auto; /* Push last element (Select2) to bottom */
}

/* Identity column - char or env fieldsets stacked */
.entity-identity {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

/* ═══════════════════════════════════════════════════════════════════
   LEGACY LAYOUTS (kept for compatibility)
   ═══════════════════════════════════════════════════════════════════ */

.form-row-2col {
    display: grid;
    grid-template-columns: 2fr 1fr;
    gap: 1rem;
    align-items: start;
}

.form-stack {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.form-preview {
    position: sticky;
    top: 1rem;
}

.appearance-grid-6col {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 0.75rem;
}


/* ═══════════════════════════════════════════════════════════════════
   FIELD LAYOUT
   ═══════════════════════════════════════════════════════════════════ */

.field-row {
    display: flex;
    gap: 0.5rem;
    margin-bottom: 0.5rem;
    min-width: 0;
}

.field-row:last-child {
    margin-bottom: 0;
}

.field-row .field {
    flex: 1;
    margin-bottom: 0;
    min-width: 0;
}

/* ── 2-column fieldset grid ──
   Left: stacked short fields   Right: tall fields spanning full height
   Used by Character (name/race/gender/age | mood/activity)
   and Environment (location/style/tech | description)                */

.fieldset-2col {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.5rem;
    margin-bottom: 0.5rem;
}

.fieldset-2col .field {
    margin-bottom: 0;
    min-width: 0;
}

/* Character form: thumbnail anchored to the height of the field stack
   beside it. NO fixed widths anywhere — the chain is:
     fields stack to a height → row stretches both children to that height
       → thumb's height matches → aspect-ratio (2/3) sets thumb's width
   So whatever fields land on the right (mood + activity today, anything
   else tomorrow), the image is dictated by their combined height and
   sizes itself accordingly. The image MAY occupy up to 50% of the
   row but only takes what its aspect needs at the row's height. */
.char-row-with-thumb {
    /* Two-column grid: thumb left, mood+activity top-right, description
       bottom-right. In portrait (default), thumb spans both rows so it
       stretches the full height of mood+activity+description. When the
       loaded image is landscape/square (.is-wide), thumb collapses to
       row 1 only — capped by mood+activity stack height — and the
       description spans the full width below. JS toggles .is-wide from
       syncThumbAspect when naturalWidth >= naturalHeight. */
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-areas:
        "thumb stack"
        "thumb description";
    gap: 0.5rem;
    margin-bottom: 0.5rem;
    align-items: stretch;
}

.char-row-with-thumb.is-wide {
    grid-template-areas:
        "thumb stack"
        "description description";
}

.char-thumb {
    /* Grid row height is dictated by the stack/description columns
       (sized by content); the thumb fills that height via height: 100%
       and derives its width from aspect-ratio. Default 2/3 (SD portrait)
       for the placeholder state; once an image loads, JS reads
       naturalWidth/Height and overrides via style.aspectRatio so
       portrait, landscape, and square uploads all shape the wrapper
       correctly. The img inside is absolutely positioned so its
       intrinsic pixel dimensions can't drag the row taller than the
       fields want. container-type: size lets the mini generate-card
       scale --card-zoom against the wrapper's actual rendered size. */
    grid-area: thumb;
    height: 100%;
    aspect-ratio: var(--thumb-aspect, 2 / 3);
    position: relative;
    border-radius: 6px;
    overflow: hidden;
    /* Backdrop revealed behind the card mid-flip — same recipe as
       .llm-prompt-block / .field--bevel (chat-input.css) so the card
       reads as sitting on the exact surface the Activity / Description
       fields use. border-radius:6px above already matches that recipe;
       keep both in sync if the bevel surface ever changes. */
    background: linear-gradient(
        225deg,
        color-mix(in srgb, var(--secondary) 16%, var(--card-base)) 0%,
        color-mix(in srgb, var(--primary) 16%, var(--card-base)) 100%
    );
    border: 1px solid rgba(255, 255, 255, 0.06);
    box-shadow:
        inset 0 3px 6px rgba(0, 0, 0, 0.5),
        inset 0 1px 0 rgba(0, 0, 0, 0.3),
        0 1px 0 rgba(255, 255, 255, 0.04);
    container-type: size;
    cursor: pointer;
}

.char-thumb img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* Mini generate card — scales --card-zoom proportionally to the
   thumb's smaller dimension (320px reference matches the carousel
   card width where the original generate-card was tuned). Clamped so
   the button stays readable at small sizes and never grows past 1×. */
.char-thumb .generate-card {
    --card-zoom: clamp(0.25, calc(min(100cqi, 100cqb) / 320px), 0.8);
}

/* ── Thumb flip ──────────────────────────────────────────────────────
   Reuses the carousel's CSS 3D flip (cf. .flip-container /
   .strip-card.flipped in standalone-carousel.css), scoped + retuned for
   the small thumb: same perspective, easing and 0.6s timing, but the
   thumb keeps its own 6px radius / subtle border framing the flip and we
   stay decoupled from carousel-CSS load order. .char-thumb is the sizing
   parent (its overflow:hidden clips to the rounded frame); .char-thumb-
   flip owns the 3D. The set-avatar button lives inside .flip-front, so
   backface-visibility hides it with the image when flipped — it never
   floats over the back generate-card. .flipped on .char-thumb toggles
   it, exactly like .flipped on a centered .strip-card. */
.char-thumb-flip {
    position: absolute;
    inset: 0;
    perspective: 1200px;
    transform-style: preserve-3d;
}

.char-thumb-flip > .flip-front,
.char-thumb-flip > .flip-back {
    position: absolute;
    inset: 0;
    box-sizing: border-box;
    backface-visibility: hidden;
    border-radius: 6px;
    overflow: hidden;
    transition: transform 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}

.char-thumb-flip > .flip-front { transform: rotateY(0deg); }
.char-thumb-flip > .flip-back  { transform: rotateY(180deg); }

.char-thumb.flipped .char-thumb-flip > .flip-front { transform: rotateY(-180deg); }
.char-thumb.flipped .char-thumb-flip > .flip-back  { transform: rotateY(0deg); }

/* Set-avatar button overlay — top-left of the thumb so "capture this
   as the avatar" reads where the avatar lives. Sits above the img and
   above the mini generate-card. Rectangular to echo the camera icon's
   own proportions; translucent dark backing keeps the icon legible
   over any image color. */
.char-thumb .fs-toggle-btn--set-avatar {
    position: absolute;
    top: 0.35rem;
    left: 0.35rem;
    z-index: 10;
    width: 2rem;
    height: 1.4rem;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, 0.55);
    border: 1px solid rgba(255, 255, 255, 0.18);
    border-radius: 4px;
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
}

/* Thin-line camera (Feather family — matches the aspect/lock orbs).
   No baseline nudge now that it's an SVG, not an emoji glyph: the
   button and .fs-toggle-btn-icon both flex-center, and the global
   .fs-toggle-btn-icon svg { display:block } kills descender slack, so
   it sits dead-centre on its own. */
.char-thumb .fs-toggle-btn--set-avatar .fs-toggle-btn-icon svg {
    width: 0.95rem;
    height: 0.95rem;
}

.char-mini-stack {
    grid-area: stack;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.char-description {
    grid-area: description;
    min-width: 0;
}

.char-mini-stack .field,
.char-description .field {
    margin-bottom: 0;
}


/* Race / Gender / Age inline below the character switcher row. Equal
   thirds; each field collapses naturally to fit. The identity (I) toggle
   sits at the end, aligned to the input baseline — it's the visual
   handle for greying out these three fields. */
.char-identity-row {
    display: flex;
    align-items: flex-end;
    gap: 0.5rem;
    margin-bottom: 0.5rem;
}

.char-identity-row .field {
    flex: 1 1 0;
    min-width: 0;
    margin-bottom: 0;
}

/* Keep the toggle button at its natural 32×28 size; align with inputs. */
.char-identity-row > .fs-toggle-btn--identity {
    flex: 0 0 auto;
}

/* Read-only identity display on clones: matches input height + padding
   but reads as a value, not a field. Dimmer text + muted background
   communicates "not editable here". Owner-side editing happens via
   cec-edit on the source, validated at crystallize. */
.identity-readonly {
    padding: 0.3rem 0.5rem;
    background: color-mix(in srgb, currentColor 6%, transparent);
    border: 1px solid color-mix(in srgb, currentColor 12%, transparent);
    border-radius: 4px;
    font-size: 0.875rem;
    color: color-mix(in srgb, currentColor 70%, transparent);
    min-height: 1.5rem;
    line-height: 1.3;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ═══════════════════════════════════════════════════════════════════
   TECH STACK - Stacked rows for Settings fieldset
   ═══════════════════════════════════════════════════════════════════ */

.tech-stack {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.tech-row {
    display: grid;
    gap: 0.5rem;
}

.tech-row--single {
    grid-template-columns: 1fr;
}

.tech-row--2col {
    grid-template-columns: 1fr 1fr;
}

.tech-row--3col {
    grid-template-columns: 1fr 1fr 1fr;
}

.tech-value {
    display: block;
    padding: 0.5rem;
    font-size: 0.85rem;
    color: rgba(255, 255, 255, 0.7);
    background: rgba(0, 0, 0, 0.3);
    border: 1px solid rgba(255, 255, 255, 0.15);
    border-left: 3px solid rgba(var(--neutral-rgb), 0.4);
    border-radius: 4px;
}

.tech-link {
    display: block;
    padding: 0.5rem;
    font-size: 0.8rem;
    color: var(--accent);
    background: rgba(0, 0, 0, 0.3);
    border: 1px solid rgba(255, 255, 255, 0.15);
    border-left: 3px solid color-mix(in srgb, var(--accent) 40%, transparent);
    border-radius: 4px;
    word-break: break-all;
    text-decoration: none;
    transition: all 0.2s ease;
}

.tech-link:hover {
    background: rgba(0, 0, 0, 0.4);
    border-left-color: var(--accent);
    color: color-mix(in srgb, var(--accent) 85%, white);
}

/* Legacy - keep for compatibility */
.tech-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 0.75rem;
}

/* ═══════════════════════════════════════════════════════════════════
   RESPONSIVE
   ═══════════════════════════════════════════════════════════════════ */

@media (max-width: 1600px) {
    /* Large desktop - keep 3-col but narrower */
    .entity-main-grid {
        grid-template-columns: minmax(200px, 1fr) 2fr 1fr;
    }
}

@media (max-width: 1400px) {
    /* Medium desktop - legacy grids adjust */
    .appearance-grid-6col {
        grid-template-columns: repeat(3, 1fr);
    }
}

@media (max-width: 1200px) {
    /* Smaller desktop - collapse to 2 columns */
    .entity-main-grid {
        grid-template-columns: 1fr 2fr;
    }
    
    .entity-identity {
        grid-column: 1 / -1;
        display: grid;
        grid-template-columns: 1fr 1fr;
    }
    
    .scene-row-grid {
        grid-template-columns: 1fr 1fr 2fr;
    }
    
    .scene-row-grid > :first-child {
        grid-column: span 1;
    }
}

@media (max-width: 1000px) {
    /* Tablet - stack layout when fields would be too narrow */
    .entity-2col {
        grid-template-columns: 1fr;
    }

    /* DESKTOP-ONLY chat column. Stacked, the right-hand chat fieldset drops BELOW
       the carousel — a swipe away that you scroll through. On mobile chat is a flip
       away on the card (.strip-card .flip-chat), so the column is redundant. Hide
       the COLUMN chat only (requires .entity-fields; the card-flip chat lives in
       .entity-preview, untouched). The editor's other .entity-fields still show. */
    .entity-2col .entity-fields .fieldset--chat {
        display: none;
    }
    
    .entity-2col .entity-preview {
        width: 100%;   /* position:static dropped — nothing to undo now the sticky is gone */
    }
    
    .entity-main-grid {
        grid-template-columns: 1fr;
    }
    
    .entity-preview {
        order: -1;   /* position:static dropped — nothing to undo now the sticky is gone */
    }
    
    .entity-identity {
        grid-template-columns: 1fr;
    }
    
    .form-row-2col {
        grid-template-columns: 1fr;
    }
    
    .form-preview {
        position: static;
        order: -1;
    }
    
    .appearance-grid-6col {
        grid-template-columns: repeat(2, 1fr);
    }
    
    
    .tech-grid {
        grid-template-columns: repeat(2, 1fr);
    }
    
    .scene-row-grid {
        grid-template-columns: 1fr 1fr;
    }
}

@media (max-width: 768px) {
    /* attr-grid-2x3 already 2 columns - no change needed */

    /* Preview fieldset fills the viewport when scrolled to */
    .entity-2col .entity-preview .fieldset {
        padding: 2px;
    }
}

@media (max-width: 600px) {
    /* ENFORCE 2 COLUMNS MINIMUM for attribute grids */
    /* attr-grid-2x3 already 2 columns - legacy grid adjusts */
    .appearance-grid-6col {
        grid-template-columns: 1fr 1fr;
    }
    
    /* v9.0: 1x3 grid stacks vertically on small screens */
    .attr-grid-1x3 {
        grid-template-columns: 1fr;
    }
    
    /* v9.0: 3x2 grid becomes 2 columns on mobile (2 cols x 3 rows) */
    .attr-grid-3x2 {
        grid-template-columns: repeat(2, 1fr);
        grid-template-rows: repeat(3, auto);
    }
    
    .scene-row-grid {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 500px) {
    .tech-grid {
        grid-template-columns: 1fr;
    }
    
    .tech-row--2col,
    .tech-row--3col {
        grid-template-columns: 1fr;
    }
}

/* ═══════════════════════════════════════════════════════════════════
   MOBILE - Reduce padding to maximize card space
   ═══════════════════════════════════════════════════════════════════ */

@media (max-width: 768px) {
    /* Django admin content area */
    #content {
        padding: 0 !important;
    }

    #content-main {
        padding: 0 !important;
    }

    /* Spacing is fully unified to a single 10px rhythm in the base now (side
       padding + all inner/fieldset gaps), so there's no mobile-specific spacing
       left here — one set, everywhere. (The gradient-band leak the old zeroing
       guarded against can't happen: mobile paints a solid card-base +
       body{min-height:0} sizes to content.) */

    /* Body sizes to content — no 100vh floor — so the gradient
       paints only the form area. Below the form, html's solid
       card-base shows through (set in fieldsets-base.css) instead
       of the slot-11-tinted gradient bottom. */
    body.aurora-standalone {
        min-height: 0;
    }

    .fieldset {
        padding: 0.5rem;
        border-radius: 6px;
    }

    /* Flush stays flush — no padding override from above */
    .fieldset--flush {
        padding: 0;
    }
}