/* ============================================================
 * /tile-selector — full-shell dfl wrapper.
 *
 * The page renders a `position: fixed` host that escapes the
 * outer `dmc.Container` wrapper in app.py (which width-caps every
 * page at `size="xl"` with `px="xl"` padding). We pin it to the
 * Mantine AppShell's header offset (top) and navbar offset (left)
 * so the dfl sits flush against the top bar and the sidebar with
 * zero gutter, taking every remaining pixel of the AppShellMain.
 *
 * The AppShell publishes the offsets as CSS vars; the fallbacks
 * match the values configured in app.py
 *   - header={"height": 56}
 *   - navbar={"width": {"base": 280, "lg": 300}, "breakpoint": "sm",
 *             "collapsed": {"mobile": True}}
 * so initial paint is correct even before Mantine evaluates the vars.
 * ============================================================ */

.ts-flush-shell {
    position:           fixed;
    top:                var(--app-shell-header-offset, 56px);
    left:               var(--app-shell-navbar-offset, 0px);
    right:              0;
    bottom:             0;
    z-index:            10;
    background:         var(--mantine-color-body);
    /* Thin chrome line so the dfl reads as its own surface against the
       app-shell, not a continuation of it. */
    border-top:         1px solid var(--mantine-color-default-border);
    border-left:        1px solid var(--mantine-color-default-border);
    overflow:           hidden;
}

/* DashFlexLayout fills its host. The library sets its own absolute layout
   internally — we just need a sized parent. */
.ts-flush-shell > .flexlayout__layout,
.ts-flush-shell > div {
    height: 100%;
    width:  100%;
}

/* Tile-cube preview inside the per-tile dmc.Select trigger: same Mantine
   surface look as the dropdown rows so the chip reads as a contiguous
   control, not two unrelated widgets stacked. */
.ts-tile-card .mantine-Select-input {
    font-size:    12px;
    height:       30px;
    min-height:   30px;
}
.ts-tile-card {
    padding:       6px;
    border-radius: 8px;
    background:    light-dark(
                       var(--mantine-color-gray-0),
                       var(--mantine-color-dark-6)
                   );
    border:        1px solid var(--mantine-color-default-border);
    display:       flex;
    flex-direction:column;
    gap:           6px;
    align-items:   stretch;
}
.ts-tile-card img {
    width:         100%;
    aspect-ratio:  1 / 1;
    object-fit:    cover;
    border-radius: 6px;
    display:       block;
    background:    light-dark(
                       var(--mantine-color-gray-2),
                       var(--mantine-color-dark-7)
                   );
}
.ts-tile-card .ts-tile-coords {
    font-family:   var(--mantine-font-family-monospace, monospace);
    font-size:     10px;
    color:         var(--mantine-color-dimmed);
    text-align:    center;
    line-height:   1.2;
}

/* Card click affordance — the whole card is the source-selection
   hotspot. Subtle pointer + hover lift; the dmc.Select inside still
   captures its own clicks via stopPropagation. */
.ts-tile-card[data-active="false"] {
    cursor: pointer;
    transition: transform 120ms ease, border-color 120ms ease,
                box-shadow 120ms ease;
}
.ts-tile-card[data-active="false"]:hover {
    transform: translateY(-1px);
    border-color: light-dark(
        var(--mantine-color-blue-3),
        var(--mantine-color-blue-7)
    );
}
.ts-tile-card[data-active="true"] {
    border-color: var(--mantine-color-violet-6);
    box-shadow:   0 0 0 2px color-mix(in srgb,
                  var(--mantine-color-violet-6) 28%, transparent);
    background:   light-dark(
                      color-mix(in srgb, var(--mantine-color-violet-1) 36%, transparent),
                      color-mix(in srgb, var(--mantine-color-violet-9) 18%, transparent)
                  );
    position: relative;
}
.ts-tile-card[data-active="true"]::after {
    content: "SOURCE";
    position: absolute;
    top: 4px; right: 4px;
    background: var(--mantine-color-violet-6);
    color: white;
    font-size: 8px;
    font-weight: 700;
    letter-spacing: 0.06em;
    padding: 2px 5px;
    border-radius: 3px;
    pointer-events: none;
    z-index: 2;
}

/* ============================================================
 * Neighbors + Terrain — 3×3 grid.
 * Corners are layout-only placeholders (truly invisible), cardinals
 * (N/E/S/W) show either an existing tile thumb or a Skeleton-N/A
 * picker, source sits in the middle with the violet source ring.
 *
 * Both columns AND rows are `repeat(3, 1fr)` so every cell is a
 * perfect square (the aspect-ratio: 1/1 on the container divides
 * equally). Without the explicit row template the rows auto-size to
 * content and the inner Skeleton heights collapse — the source cell
 * inflated tall while N/S squished thin.
 * ============================================================ */
.ts-neighbor-grid {
    display:               grid;
    grid-template-columns: repeat(3, 1fr);
    grid-template-rows:    repeat(3, 1fr);
    gap:                   8px;
    aspect-ratio:          1 / 1;
    padding:               4px;
    background:            light-dark(
                               var(--mantine-color-gray-1),
                               var(--mantine-color-dark-7)
                           );
    border-radius:         10px;
    border:                1px solid var(--mantine-color-default-border);
}
.ts-neighbor-cell {
    position:       relative;
    border-radius:  8px;
    overflow:       hidden;
    border:         1px solid var(--mantine-color-default-border);
    background:     light-dark(
                        var(--mantine-color-gray-0),
                        var(--mantine-color-dark-6)
                    );
    display:        flex;
    align-items:    stretch;
    justify-content:stretch;
    min-height:     0;
    min-width:      0;
}
.ts-neighbor-cell--corner {
    /* Truly blank — no border, no fill. Just claims the grid slot
       so N/S/E/W keep their cardinal positions around the source. */
    background:     transparent;
    border:         none;
}
.ts-neighbor-cell--source {
    border-color:   var(--mantine-color-violet-6);
    box-shadow:     0 0 0 2px color-mix(in srgb,
                       var(--mantine-color-violet-6) 28%, transparent);
}
.ts-neighbor-cell--missing { display: block; padding: 0; }
.ts-neighbor-cell--missing > .mantine-Skeleton-root,
.ts-neighbor-cell--present > .mantine-Image-root,
.ts-neighbor-cell--gen     > .mantine-Image-root,
.ts-neighbor-cell--source  > .mantine-Image-root {
    width: 100%; height: 100%;
}
/* Direction tag floats over each cardinal cell so the user keeps
   their bearings even when the thumb is colorful. */
.ts-neighbor-dir-tag {
    position:        absolute;
    top:             3px; left: 4px;
    background:      color-mix(in srgb,
                        var(--mantine-color-default) 70%, transparent);
    color:           var(--mantine-color-text);
    backdrop-filter: blur(4px);
    font-size:       9px;
    font-weight:     700;
    padding:         1px 4px;
    border-radius:   3px;
    pointer-events:  none;
    z-index:         2;
}
.ts-neighbor-na {
    position:       absolute; inset: 0;
    display:        flex; flex-direction: column;
    align-items:    center; justify-content: center;
    gap:            2px;
    pointer-events: none;
    color:          var(--mantine-color-dimmed);
}
.ts-neighbor-dir-large { font-size: 22px; font-weight: 800; line-height: 1; }
.ts-neighbor-na-text   { font-size: 11px; opacity: 0.7; }
/* Neighbor outline-picker sits over the bottom of the cell, half-
   opaque so the underlying skeleton/image stays visible. */
.ts-neighbor-cell .ts-neighbor-select {
    position: absolute;
    left: 4px; right: 4px; bottom: 4px;
    z-index: 3;
}
.ts-neighbor-cell .ts-neighbor-select .mantine-Select-input {
    height:     22px;
    min-height: 22px;
    font-size:  10px;
    padding:    0 6px;
    background: color-mix(in srgb,
                  var(--mantine-color-body) 80%, transparent);
    backdrop-filter: blur(6px);
}

/* ============================================================
 * Style References (chips list).
 * ============================================================ */
.ts-ref-list {
    display:               grid;
    grid-template-columns: 1fr;
    gap:                   6px;
    margin-bottom:         4px;
}
.ts-ref-chip {
    display:       flex;
    align-items:   center;
    gap:           8px;
    padding:       6px 8px;
    background:    light-dark(
                       var(--mantine-color-gray-0),
                       var(--mantine-color-dark-6)
                   );
    border:        1px solid var(--mantine-color-default-border);
    border-radius: 8px;
    min-width:     0;
}
.ts-ref-chip-title {
    font-size:     11px;
    font-weight:   600;
    color:         var(--mantine-color-text);
    white-space:   nowrap;
    overflow:      hidden;
    text-overflow: ellipsis;
}
.ts-ref-chip-meta {
    font-size:     10px;
    color:         var(--mantine-color-dimmed);
    white-space:   nowrap;
    overflow:      hidden;
    text-overflow: ellipsis;
}

/* ============================================================
 * Tileset comparison popover — hide the per-leaf kebab button
 * on the Source-Tileset group only.
 *
 * TreeViewPro's `controlsItems` prop gates the slider AND the kebab
 * together for a leaf, so we can't enable just one or the other from
 * Python. The source-leaf still NEEDS its opacity slider; the kebab
 * is the part we want gone (the per-tile actions Select/Download/
 * Remove only make sense for AI generations, not the satellite base).
 *
 * The TreeItem's <li> gets an id like `mui-tree-view-1-grp.source`
 * for the group node and `mui-tree-view-1-src:esri` for the leaf —
 * `[id$="grp.source"]` is the most resilient anchor across nested
 * leaves (no leaf id is hard-coded).
 * ============================================================ */
li[id$="grp.source"] button[aria-label="item actions"] {
    display: none !important;
}

/* ============================================================
 * AI-generation overlay states — preview vs accepted.
 * Both classes are applied to the underlying <img> by the
 * clientside overlay manager (see pages/tile_selector.py's
 * compare clientside_callback). PREVIEW = freshly returned,
 * not yet committed by the user; ACCEPTED = user clicked Accept.
 * ============================================================ */
.ts-compare-overlay--preview {
    /* Subtle cyan dashed outline so you can tell at a glance what's
       newly generated but not yet accepted. */
    outline:        2px dashed var(--mantine-color-cyan-5);
    outline-offset: -2px;
}
.ts-compare-overlay--accepted {
    /* Quiet: no outline. The map should read clean for committed work. */
    outline: none;
}
/* Soften opacity transitions so any brief checkbox-bounce blip (MUI's
   row-click handler firing alongside the checkbox click and briefly
   dropping the leaf from selectedItems) reads as a slight dim rather
   than a hard vanish. Leaflet sets opacity via the inline style attr;
   CSS transitions still apply. */
.ts-compare-overlay {
    transition: opacity 120ms ease;
}

/* ============================================================
 * Association by zoom — cross-zoom reference cards.
 * Click-to-toggle inclusion as an AI-generation reference image
 * for the active source. Teal-highlighted when included.
 * ============================================================ */
.ts-zoom-assoc-card {
    position:       relative;
    padding:        6px;
    border-radius:  8px;
    background:     light-dark(
                        var(--mantine-color-gray-0),
                        var(--mantine-color-dark-6)
                    );
    border:         1px solid var(--mantine-color-default-border);
    display:        flex;
    flex-direction: column;
    gap:            4px;
    cursor:         pointer;
    transition:     transform 120ms ease, border-color 120ms ease,
                    box-shadow 120ms ease, background 120ms ease;
}
.ts-zoom-assoc-card[data-selected="false"]:hover {
    transform:    translateY(-1px);
    border-color: light-dark(
                      var(--mantine-color-blue-3),
                      var(--mantine-color-blue-7)
                  );
}
.ts-zoom-assoc-card[data-selected="true"] {
    border-color: var(--mantine-color-teal-6);
    box-shadow:   0 0 0 2px color-mix(in srgb,
                  var(--mantine-color-teal-6) 28%, transparent);
    background:   light-dark(
                      color-mix(in srgb,
                          var(--mantine-color-teal-1) 36%, transparent),
                      color-mix(in srgb,
                          var(--mantine-color-teal-9) 18%, transparent)
                  );
}
.ts-zoom-assoc-card[data-selected="true"]::after {
    content:        "INCLUDE";
    position:       absolute;
    top:            4px; right: 4px;
    background:     var(--mantine-color-teal-6);
    color:          white;
    font-size:      8px;
    font-weight:    700;
    letter-spacing: 0.06em;
    padding:        2px 5px;
    border-radius:  3px;
    pointer-events: none;
    z-index:        2;
}
.ts-zoom-assoc-coords {
    font-family: var(--mantine-font-family-monospace, monospace);
    font-size:   10px;
    font-weight: 600;
    color:       var(--mantine-color-text);
    text-align:  center;
}
.ts-zoom-assoc-kind {
    font-size:   9px;
    color:       var(--mantine-color-dimmed);
    text-align:  center;
    line-height: 1.1;
}

/* ===================================================================== */
/* Environment-tileset page (/map/create-environment-tileset) overlays.  */
/*                                                                       */
/* The dish silhouette is a SCREEN-FIXED CSS overlay, not map geometry:  */
/* Leaflet renders 256-px tiles, so a fixed-pixel dish spans the same    */
/* tile count at every zoom — exactly how the Petri Dish Evolution game  */
/* floats its fixed-size dish over the panning floor. See the note in    */
/* pages/map/create_environment_tilesets/layout.py.                      */
/* ===================================================================== */

/* Full-pane host; pointer-events: none so map drag + tile-selection     */
/* clicks pass straight through to the Leaflet map beneath.              */
.env-dish-host {
    position:       absolute;
    inset:          0;
    display:        flex;
    align-items:    center;
    justify-content:center;
    pointer-events: none;
    z-index:        450;   /* above tiles, below the topleft map controls */
}

/* The dish lens footprint — clamped near the game dish's ~460-px size    */
/* (≈ 1.8 tiles across), shrinking gracefully on narrow panes.           */
.env-dish {
    position:     relative;
    width:        clamp(240px, 60vmin, 460px);
    aspect-ratio: 1 / 1;
}
.env-dish > div {
    position:      absolute;
    top:           50%;
    left:          50%;
    transform:     translate(-50%, -50%);
    border-radius: 50%;
    box-sizing:    border-box;
}

/* ~8× world wall — the clamp the cell can't swim past. Drawn at a        */
/* tractable on-screen multiple (it overflows the pane and clips, the     */
/* same nested-ring look the game shows when zoomed out).                */
.env-dish__wall {
    width:        210%;
    height:       210%;
    border:       1.5px dashed color-mix(in srgb, var(--mantine-color-harbor-4) 55%, transparent);
    opacity:      0.4;
}

/* The petri glass inset ring (mirrors the game's .tdish-ring).          */
.env-dish__glass {
    width:        86%;
    height:       86%;
    border:       1px solid color-mix(in srgb, var(--mantine-color-harbor-3) 45%, transparent);
    box-shadow:   inset 0 0 38px color-mix(in srgb, var(--mantine-color-harbor-9) 60%, transparent);
}

/* The dish lens — what the player actually sees. The prominent ring.    */
.env-dish__lens {
    width:        100%;
    height:       100%;
    border:       2px solid var(--mantine-color-tidal-5);
    background:   radial-gradient(circle,
                      transparent 60%,
                      color-mix(in srgb, var(--mantine-color-tidal-5) 8%, transparent) 100%);
    box-shadow:   0 0 0 1px color-mix(in srgb, var(--mantine-color-tidal-5) 25%, transparent),
                  inset 0 0 60px color-mix(in srgb, var(--mantine-color-tidal-7) 22%, transparent);
}

/* "player view" tag pinned to the top of the lens ring.                 */
.env-dish__tag {
    position:      absolute;
    top:           -10px;
    left:          50%;
    transform:     translateX(-50%);
    padding:       1px 8px;
    border-radius: 8px;
    font-family:   monospace;
    font-size:     9px;
    letter-spacing:1px;
    text-transform:uppercase;
    color:         var(--mantine-color-tidal-1);
    background:    color-mix(in srgb, var(--mantine-color-tidal-8) 80%, transparent);
    white-space:   nowrap;
}

/* Tiny center crosshair so the author can line tiles up on the lens hub. */
.env-dish__crosshair {
    width:        16px;
    height:       16px;
    border:       none !important;
    background:
        linear-gradient(var(--mantine-color-tidal-4), var(--mantine-color-tidal-4)) center / 1px 100% no-repeat,
        linear-gradient(var(--mantine-color-tidal-4), var(--mantine-color-tidal-4)) center / 100% 1px no-repeat;
    opacity:      0.7;
}

/* Top-right depth gauge stack. pointer-events auto so the gauge's own    */
/* tooltips work; sits clear of the topleft zoom + compare controls.      */
.env-gauge-overlay {
    position:       absolute;
    top:            10px;
    right:          10px;
    z-index:        500;
    display:        flex;
    flex-direction: column;
    align-items:    center;
    gap:            2px;
    padding:        6px 8px;
    border-radius:  12px;
    pointer-events: auto;
    background:     light-dark(
                        color-mix(in srgb, var(--mantine-color-body) 86%, transparent),
                        color-mix(in srgb, var(--mantine-color-harbor-9) 78%, transparent));
    border:         1px solid color-mix(in srgb, var(--mantine-color-harbor-4) 30%, transparent);
    backdrop-filter:blur(3px);
    box-shadow:     0 2px 10px color-mix(in srgb, var(--mantine-color-harbor-9) 30%, transparent);
}
