/* ============================================================
 * /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;
}
