/* ================ MapLibre Globe Edition ================ */

html, body {
    height: 100%;
    margin: 0;
    padding: 0;
    background: #0a0a0a;
    color: #e0e0e0;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    overflow: hidden;
}

#map {
    position: absolute;
    inset: 0;
}

/* canvas focus ring removed */
.maplibregl-canvas:focus { outline: none; }

/* ===== Top Bar ===== */
.ml-topbar {
    position: absolute;
    top: 12px;
    left: 12px;
    right: 12px;
    height: 48px;
    display: flex;
    align-items: center;
    gap: 12px;
    z-index: 5;
    pointer-events: none;
}
.ml-topbar > * { pointer-events: auto; }

.ml-brand {
    background: rgba(18, 18, 18, 0.85);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    color: #fff;
    text-decoration: none;
    height: 48px;
    padding: 0 16px;
    border-radius: 12px;
    display: flex;
    align-items: center;
    gap: 8px;
    font-weight: 600;
    border: 1px solid rgba(255,255,255,0.08);
    transition: background 0.15s;
}
.ml-brand:hover { background: rgba(40, 40, 40, 0.95); color: #fff; }
.ml-brand .bx { font-size: 1.2rem; }
.ml-brand-text em { font-weight: 400; color: #ff8f1f; font-style: normal; }

.ml-search-wrap {
    /* margin-left:auto pushes the search to the right end of the flex
       row, leaving open space between it and the brand. width:100% +
       max-width gives it room to be useful without taking over the
       whole bar. */
    margin-left: auto;
    width: 100%;
    max-width: 480px;
    position: relative;
    background: rgba(18, 18, 18, 0.85);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border: 1px solid rgba(255,255,255,0.08);
    border-radius: 12px;
    height: 48px;
    display: flex;
    align-items: center;
    padding: 0 14px;
    gap: 10px;
}
.ml-search-wrap .bx { color: #aaa; font-size: 1.2rem; }
.ml-search-wrap input {
    background: transparent;
    border: 0;
    outline: 0;
    color: #fff;
    font-size: 0.95rem;
    width: 100%;
}
.ml-search-wrap input::placeholder { color: #888; }

.ml-search-results {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    right: 0;
    background: rgba(20, 20, 20, 0.96);
    backdrop-filter: blur(12px);
    border: 1px solid rgba(255,255,255,0.08);
    border-radius: 10px;
    max-height: 320px;
    overflow-y: auto;
    display: none;
    z-index: 10;
}
.ml-search-results.show { display: block; }
.ml-search-result {
    padding: 10px 14px;
    cursor: pointer;
    border-bottom: 1px solid rgba(255,255,255,0.04);
    font-size: 0.88rem;
    transition: background 0.1s;
}
.ml-search-result:hover { background: rgba(255, 143, 31, 0.15); }
.ml-search-result:last-child { border-bottom: none; }
.ml-search-result .ml-sr-name { color: #fff; font-weight: 500; }
.ml-search-result .ml-sr-place { color: #999; font-size: 0.8rem; margin-top: 2px; }

.ml-icon-btn {
    width: 48px;
    height: 48px;
    border-radius: 12px !important;
    background: rgba(18, 18, 18, 0.85) !important;
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border: 1px solid rgba(255,255,255,0.08) !important;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}
.ml-icon-btn .bx { font-size: 1.4rem; }

/* ===== Toolbar (right side, beneath the settings button) ===== */
.ml-toolbar {
    position: absolute;
    top: 80px;
    right: 12px;
    background: rgba(18, 18, 18, 0.85);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border: 1px solid rgba(255,255,255,0.08);
    border-radius: 12px;
    padding: 6px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    z-index: 5;
}
.ml-tool {
    position: relative;
    width: 40px;
    height: 40px;
    border: 0;
    background: transparent;
    color: #ddd;
    border-radius: 8px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.12s, color 0.12s;
}
.ml-tool[data-tip]::before {
    content: attr(data-tip);
    position: absolute;
    right: calc(100% + 12px);
    top: 50%;
    transform: translateY(-50%) translateX(6px);
    background: rgba(18, 18, 18, 0.96);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    color: #fff;
    padding: 6px 10px;
    border-radius: 7px;
    font-size: 0.76rem;
    font-weight: 500;
    white-space: nowrap;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.14s ease, transform 0.14s ease;
    border: 1px solid rgba(255, 255, 255, 0.08);
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.4);
    z-index: 100;
}
.ml-tool[data-tip]::after {
    content: '';
    position: absolute;
    right: calc(100% + 6px);
    top: 50%;
    transform: translateY(-50%) translateX(6px);
    width: 0;
    height: 0;
    border-top: 5px solid transparent;
    border-bottom: 5px solid transparent;
    border-left: 6px solid rgba(18, 18, 18, 0.96);
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.14s ease, transform 0.14s ease;
    z-index: 100;
}
.ml-tool[data-tip]:hover::before,
.ml-tool[data-tip]:hover::after {
    opacity: 1;
    transform: translateY(-50%) translateX(0);
}
/* Don't show the regular tip on the shape button while its flyout is
   open — the flyout has its own buttons with their own tooltips. */
.ml-tool-shape.flyout-open::before,
.ml-tool-shape.flyout-open::after { opacity: 0 !important; }
.ml-tool:hover { background: rgba(255,255,255,0.06); color: #fff; }
.ml-tool.active {
    background: #ff8f1f;
    color: #1a1a1a;
}
.ml-tool.disabled {
    color: #555;
    opacity: 0.55;
    cursor: not-allowed;
}
.ml-tool.disabled:hover { background: transparent; color: #555; }

/* ===== Shape flyout / OSM flyout ===== */
.ml-shape-group, .ml-osm-group { position: relative; }
.ml-osm-group #toggleBuildings.flyout-open {
    box-shadow: 0 0 0 2px rgba(255, 143, 31, 0.35);
}
/* osm-toggle inside the flyout shows orange when its feature is on */
.ml-shape-flyout .osm-toggle.active {
    background: #ff8f1f;
    color: #1a1a1a;
}
/* Shape-flyout trigger. Orange only while a drawing shape is the
   active mode — when the user is in pan mode the button drops to a
   regular .ml-tool look so the top-level pan button is the only
   highlighted indicator. */
.ml-tool-shape.active {
    background: #ff8f1f;
    color: #1a1a1a;
}
.ml-tool-shape.active:hover {
    background: #ffa040;
    color: #1a1a1a;
}
.ml-tool-shape.flyout-open {
    box-shadow: 0 0 0 2px rgba(255, 143, 31, 0.35);
}
.ml-tool-shape.active.flyout-open {
    background: #ffa040;
}
/* Apply the bottom-right chevron badge to any toolbar button that has
   the .ml-tool-caret marker — used for both the shape selector and the
   OSM-features flyout trigger. Position:absolute keeps the main icon
   centered in the button while the badge floats in the corner. */
.ml-tool .ml-tool-caret {
    position: absolute;
    right: -2px;
    bottom: -2px;
    width: 14px;
    height: 14px;
    background: #1a1a1a;
    border-radius: 50%;
    border: 1.5px solid #ff8f1f;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #ff8f1f;
    pointer-events: none;
}
.ml-tool .ml-tool-caret .bx { font-size: 0.75rem; }

.ml-shape-flyout {
    position: absolute;
    right: calc(100% + 8px);
    top: 50%;
    transform: translateY(-50%) translateX(8px);
    background: rgba(18, 18, 18, 0.92);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border: 1px solid rgba(255,255,255,0.08);
    border-radius: 12px;
    padding: 6px;
    display: none;
    flex-direction: row;
    gap: 4px;
    z-index: 10;
    box-shadow: 0 8px 24px rgba(0,0,0,0.4);
    opacity: 0;
    transition: opacity 0.16s ease, transform 0.16s ease;
}
.ml-shape-flyout.show {
    display: flex;
    opacity: 1;
    transform: translateY(-50%) translateX(0);
}
.ml-shape-flyout .ml-tool {
    width: 40px;
    height: 40px;
}

/* Tooltips for buttons INSIDE a horizontal flyout flip to "above"
   anchoring. The toolbar default puts tooltips to the left of the
   button (which works at the screen edge), but inside a horizontal
   flyout that overlaps the adjacent button. Anchoring to the top of
   the button keeps each tooltip in clear space above its row. */
.ml-shape-flyout .ml-tool[data-tip]::before {
    right: auto;
    top: auto;
    bottom: calc(100% + 10px);
    left: 50%;
    transform: translate(-50%, 6px);
}
.ml-shape-flyout .ml-tool[data-tip]::after {
    right: auto;
    top: auto;
    bottom: calc(100% + 4px);
    left: 50%;
    border-top: 6px solid rgba(18, 18, 18, 0.96);
    border-left: 5px solid transparent;
    border-right: 5px solid transparent;
    border-bottom: 0;
    transform: translate(-50%, 6px);
}
.ml-shape-flyout .ml-tool[data-tip]:hover::before,
.ml-shape-flyout .ml-tool[data-tip]:hover::after {
    transform: translate(-50%, 0);
}

/* Little arrow connecting flyout to the main button */
.ml-shape-flyout::after {
    content: '';
    position: absolute;
    left: 100%;
    top: 50%;
    transform: translateY(-50%);
    width: 0;
    height: 0;
    border-top: 6px solid transparent;
    border-bottom: 6px solid transparent;
    border-left: 6px solid rgba(18, 18, 18, 0.92);
}
.ml-tool .bx { font-size: 1.4rem; }
.ml-tool-sep {
    height: 1px;
    background: rgba(255,255,255,0.06);
    margin: 4px 6px;
}


/* ===== Status Bar (bottom center) ===== */
.ml-statusbar {
    position: absolute;
    bottom: 12px;
    left: 50%;
    transform: translateX(-50%);
    background: rgba(18, 18, 18, 0.85);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border: 1px solid rgba(255,255,255,0.08);
    border-radius: 8px;
    padding: 6px 14px;
    font-family: "SF Mono", Menlo, monospace;
    font-size: 0.78rem;
    color: #bbb;
    display: flex;
    align-items: center;
    gap: 10px;
    z-index: 5;
    white-space: nowrap;
}
.ml-statusbar .ml-sep {
    width: 1px;
    height: 14px;
    background: rgba(255,255,255,0.1);
}
.ml-statusbar #statusElev { color: #5dd8b6; }
.ml-statusbar #statusArea { color: #ffae5c; }

/* ===== Selection handles (move + resize) ===== */
.ml-handle {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    background: #fff;
    border: 2px solid #ff8f1f;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.35), 0 0 0 1px rgba(0,0,0,0.05);
    display: flex;
    align-items: center;
    justify-content: center;
    color: #ff8f1f;
    cursor: grab;
    user-select: none;
    transition: transform 0.12s ease, box-shadow 0.12s ease, background 0.12s ease;
}
.ml-handle:hover {
    transform: scale(1.1);
    box-shadow: 0 6px 18px rgba(255, 143, 31, 0.55), 0 0 0 1px rgba(0,0,0,0.05);
}
.ml-handle:active { cursor: grabbing; transform: scale(1.05); }
.ml-handle .bx { font-size: 1.05rem; pointer-events: none; }

.ml-handle-move { /* default styling above */ }

.ml-handle-resize {
    background: #ff8f1f;
    color: #fff;
    border-color: #fff;
    cursor: nwse-resize;
}
.ml-handle-resize:hover { background: #ff7a1f; }

.ml-handle-rotate {
    background: #5cb3e8;
    color: #fff;
    border-color: #fff;
    cursor: grab;
}
.ml-handle-rotate:hover { background: #4aa3d8; }
.ml-handle-rotate:active { cursor: grabbing; }

.ml-handle-vertex {
    width: 16px;
    height: 16px;
    background: #fff;
    border: 2px solid #ff8f1f;
    border-radius: 50%;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.4);
    cursor: grab;
}
.ml-handle-vertex:hover { transform: scale(1.25); background: #fff3e6; }
.ml-handle-vertex:active { cursor: grabbing; }

/* ===== Generate Button ===== */
/* Cancel-selection round button sitting just left of the Generate
   pill. Shown only while a selection exists (toggled in sync with
   #generateBtn). Solid neutral so it doesn't compete visually with
   the orange Generate. */
.ml-generate-cancel {
    position: absolute;
    bottom: 64px;
    left: calc(50% - 200px);
    z-index: 6;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    border: 1px solid rgba(255,255,255,0.15);
    background: rgba(18, 18, 18, 0.85);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    box-shadow: 0 6px 18px rgba(0,0,0,0.45);
    transition: transform 0.15s ease, background 0.15s ease;
}
.ml-generate-cancel:hover { background: rgba(40, 40, 40, 0.95); transform: scale(1.06); }
.ml-generate-cancel:active { transform: scale(0.96); }
.ml-generate-cancel .bx { font-size: 1.4rem; pointer-events: none; }

.ml-generate {
    position: absolute;
    left: 50%;
    bottom: 56px;
    transform: translateX(-50%);
    z-index: 6;
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 10px 16px 10px 10px;
    background: linear-gradient(135deg, #ff9a2e 0%, #ff7a1f 55%, #ff5b1c 100%);
    color: #1a1208;
    border: 0;
    border-radius: 18px;
    font-weight: 700;
    letter-spacing: 0.01em;
    cursor: pointer;
    box-shadow:
        0 18px 40px -12px rgba(255, 120, 30, 0.7),
        0 4px 14px rgba(0, 0, 0, 0.35),
        inset 0 1px 0 rgba(255, 255, 255, 0.35),
        inset 0 -1px 0 rgba(0, 0, 0, 0.15);
    transition: transform 0.18s ease, box-shadow 0.18s ease, filter 0.18s ease;
}
.ml-generate::after {
    content: '';
    position: absolute;
    inset: -3px;
    border-radius: 21px;
    background: linear-gradient(135deg, #ffb24a, #ff6a1c);
    z-index: -1;
    filter: blur(14px);
    opacity: 0.55;
    animation: ml-gen-pulse 2.6s ease-in-out infinite;
}
@keyframes ml-gen-pulse {
    0%, 100% { opacity: 0.4; transform: scale(0.98); }
    50%      { opacity: 0.7; transform: scale(1.02); }
}
.ml-generate:hover {
    transform: translateX(-50%) translateY(-2px);
    filter: brightness(1.05);
    box-shadow:
        0 22px 50px -10px rgba(255, 120, 30, 0.85),
        0 6px 18px rgba(0, 0, 0, 0.4),
        inset 0 1px 0 rgba(255, 255, 255, 0.45),
        inset 0 -1px 0 rgba(0, 0, 0, 0.18);
}
.ml-generate:active {
    transform: translateX(-50%) translateY(0);
    filter: brightness(0.97);
}
.ml-generate-icon {
    width: 42px;
    height: 42px;
    border-radius: 12px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: rgba(26, 18, 8, 0.18);
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.12);
}
.ml-generate-icon .bx { font-size: 1.5rem; color: #1a1208; }
.ml-generate-label {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    line-height: 1;
    text-align: left;
}
.ml-generate-kicker {
    font-size: 0.65rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: rgba(26, 18, 8, 0.65);
    margin-bottom: 4px;
}
.ml-generate-text {
    font-size: 1.02rem;
    font-weight: 800;
    letter-spacing: 0.005em;
}
.ml-generate-arrow {
    width: 28px;
    height: 28px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 8px;
    background: rgba(26, 18, 8, 0.16);
    transition: transform 0.18s ease;
}
.ml-generate-arrow .bx { font-size: 1.25rem; color: #1a1208; }
.ml-generate:hover .ml-generate-arrow { transform: translateX(3px); }

/* ===== Settings panel ===== */
.ml-settings {
    background: #121212 !important;
    color: #e0e0e0;
    border-left: 1px solid rgba(255,255,255,0.08) !important;
    width: 380px !important;
}
.ml-settings .offcanvas-header {
    border-bottom: 1px solid rgba(255,255,255,0.06);
}
.ml-section {
    padding: 14px 0;
    border-bottom: 1px solid rgba(255,255,255,0.05);
}
.ml-section:last-child { border-bottom: 0; }
.ml-section-title {
    text-transform: uppercase;
    font-size: 0.7rem;
    letter-spacing: 0.08em;
    color: #ff8f1f;
    font-weight: 600;
    margin-bottom: 10px;
}
.ml-label {
    display: block;
    font-size: 0.8rem;
    color: #bbb;
    margin: 8px 0 4px;
}
.ml-label span {
    color: #fff;
    font-family: "SF Mono", Menlo, monospace;
}

/* ===== Sun position compass ===== */
/* A polar sky-dome view: drag the sun anywhere on the disc to set both
   azimuth (angle from N) and altitude (distance from horizon ring to
   zenith centre) at once. CSS variables drive the sky gradient and sun
   colour, and JS updates them live as the altitude changes — high sun =
   cold blue zenith, low sun = warm orange dawn band. */
.sun-compass {
    /* Sky palette — JS overrides for live altitude-driven shifts. */
    --sky-zenith:  hsl(225, 55%, 8%);
    --sky-mid:     hsl(225, 50%, 16%);
    --sky-horizon: hsl(25, 65%, 24%);

    /* Horizon glow (the warm band under the sun) */
    --glow-inner: hsla(22, 95%, 58%, 0.85);
    --glow-outer: hsla(22, 95%, 58%, 0);
    --glow-opacity: 1;

    /* Sun colour stops */
    --sun-core: hsl(48, 100%, 70%);
    --sun-edge: hsl(28, 90%, 55%);

    /* Halo around the sun */
    --halo-in:  hsla(45, 100%, 70%, 0.55);
    --halo-mid: hsla(30, 95%, 55%, 0.18);
    --halo-out: hsla(30, 95%, 55%, 0);

    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
    margin: 4px 0 6px;
    user-select: none;
    -webkit-user-select: none;
    outline: none;
}
.sun-compass:focus-visible .sun-dome {
    stroke: rgba(255, 143, 31, 0.6);
    stroke-width: 1.5;
}
.sun-compass-svg {
    width: 100%;
    max-width: 260px;
    aspect-ratio: 1 / 1;
    display: block;
    cursor: grab;
    touch-action: none;
    filter: drop-shadow(0 6px 24px rgba(0, 0, 0, 0.55));
}
.sun-compass-svg:active { cursor: grabbing; }

/* Sky dome — soft inner edge so the disc reads as a hemisphere, not a coin */
.sun-dome {
    stroke: rgba(255, 255, 255, 0.08);
    stroke-width: 1;
    transition: stroke 0.18s;
}
.sky-stop.sky-zenith  { stop-color: var(--sky-zenith); }
.sky-stop.sky-mid     { stop-color: var(--sky-mid); }
.sky-stop.sky-horizon { stop-color: var(--sky-horizon); }

/* The horizon glow rotates around the disc centre (via an SVG attr
   transform on the inner <g>) so the warm band always sits under the
   sun. The parent .sun-horizon-clip applies the dome clip-path; keeping
   the rotation and the clip on separate elements avoids browser quirks
   where rotation/blend-modes break clip evaluation. We deliberately do
   not use mix-blend-mode here — it kept escaping the clipping region
   and rendering against the page background. Plain alpha blends fine. */
.sun-horizon-glow {
    opacity: var(--glow-opacity);
    transition: opacity 0.18s ease;
}
.glow-stop.glow-inner { stop-color: var(--glow-inner); }
.glow-stop.glow-outer { stop-color: var(--glow-outer); }

/* Altitude reference rings — barely-there hints, not chrome */
.sun-ring {
    fill: none;
    stroke: rgba(255, 255, 255, 0.10);
    stroke-width: 0.6;
}
.sun-ring-outer { stroke: rgba(255, 255, 255, 0.18); stroke-width: 0.9; }
.sun-ring-30, .sun-ring-60 { stroke-dasharray: 1.6 3; }

.sun-cardinal {
    fill: rgba(255, 255, 255, 0.55);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.08em;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    paint-order: stroke;
    stroke: rgba(0, 0, 0, 0.6);
    stroke-width: 2;
}
.sun-cardinal-primary { fill: #ff8f1f; }

.sun-zenith { fill: rgba(255, 255, 255, 0.35); }

/* Thin radial line from sun toward the centre/zenith — visualises altitude */
.sun-trail {
    stroke: rgba(255, 255, 255, 0.12);
    stroke-width: 0.8;
    stroke-dasharray: 1.5 2.5;
    pointer-events: none;
}

/* Sun orb is positioned by JS via the SVG `transform` attribute on the
   parent <g>; CSS just handles the pulse on the halo (relative to its
   own bbox, so it composes cleanly with the parent translate). */
.sun-orb { pointer-events: none; }
.sun-halo {
    transform-box: fill-box;
    transform-origin: center;
    animation: sunPulse 3.2s ease-in-out infinite;
}
.sun-core-orb {
    filter: drop-shadow(0 0 4px hsla(45, 100%, 65%, 0.7));
}
@keyframes sunPulse {
    0%, 100% { opacity: 0.7; transform: scale(1); }
    50%      { opacity: 1;   transform: scale(1.08); }
}
.halo-stop.halo-in  { stop-color: var(--halo-in); }
.halo-stop.halo-mid { stop-color: var(--halo-mid); }
.halo-stop.halo-out { stop-color: var(--halo-out); }
.sun-stop.sun-core { stop-color: var(--sun-core); }
.sun-stop.sun-edge { stop-color: var(--sun-edge); }

/* Numeric readouts under the disc */
.sun-readouts {
    display: flex;
    align-items: stretch;
    gap: 0;
    width: 100%;
    max-width: 260px;
    background: rgba(255, 255, 255, 0.03);
    border: 1px solid rgba(255, 255, 255, 0.06);
    border-radius: 10px;
    padding: 8px 0;
}
.sun-readout {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 3px;
    padding: 0 10px;
}
.sun-readout-sep {
    width: 1px;
    background: rgba(255, 255, 255, 0.07);
    margin: 4px 0;
}
.sun-val-row {
    display: flex;
    align-items: baseline;
    gap: 6px;
}
.sun-val {
    font-family: "SF Mono", Menlo, monospace;
    font-size: 1.05rem;
    font-weight: 600;
    color: #fff;
    letter-spacing: -0.01em;
}
.sun-dir {
    font-size: 0.7rem;
    font-weight: 600;
    color: #ff8f1f;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}
.sun-sublabel {
    font-size: 0.62rem;
    font-weight: 500;
    color: rgba(255, 255, 255, 0.45);
    text-transform: uppercase;
    letter-spacing: 0.12em;
}

.sun-hidden-range {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* Color picker grid in the settings panel */
.ml-color-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 6px;
    margin-bottom: 10px;
}
.ml-color-row {
    display: flex;
    align-items: center;
    gap: 8px;
    background: rgba(255, 255, 255, 0.03);
    border: 1px solid rgba(255, 255, 255, 0.06);
    border-radius: 7px;
    padding: 5px 8px;
}
.ml-color-row span {
    font-size: 0.78rem;
    color: #cccccc;
    flex: 1;
}
.ml-color-row input[type="color"] {
    -webkit-appearance: none;
    appearance: none;
    width: 30px;
    height: 24px;
    padding: 0;
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 5px;
    background: transparent;
    cursor: pointer;
    flex-shrink: 0;
}
.ml-color-row input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; }
.ml-color-row input[type="color"]::-webkit-color-swatch { border: 0; border-radius: 4px; }
.ml-color-row input[type="color"]::-moz-color-swatch { border: 0; border-radius: 4px; }

/* range slider in dark */
.ml-settings .form-range {
    height: 1.2rem;
}
.ml-settings .form-range::-webkit-slider-thumb {
    background: #ff8f1f;
}
.ml-settings .form-range::-moz-range-thumb {
    background: #ff8f1f;
}

/* bookmarks */
.ml-bookmarks {
    display: flex;
    flex-direction: column;
    gap: 4px;
    max-height: 200px;
    overflow-y: auto;
}
.ml-bookmark {
    background: rgba(255,255,255,0.03);
    border: 1px solid rgba(255,255,255,0.05);
    border-radius: 8px;
    padding: 8px 10px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    cursor: pointer;
    transition: background 0.1s;
}
.ml-bookmark:hover { background: rgba(255, 143, 31, 0.1); border-color: rgba(255, 143, 31, 0.3); }
.ml-bookmark-name { font-size: 0.85rem; color: #fff; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ml-bookmark-del {
    background: transparent;
    border: 0;
    color: #888;
    cursor: pointer;
    padding: 0 4px;
}
.ml-bookmark-del:hover { color: #ff5050; }

/* ===== Modals ===== */
.ml-modal {
    background: #1a1a1a;
    border: 1px solid rgba(255,255,255,0.08);
    border-radius: 16px !important;
    overflow: hidden;
}
.ml-modal .btn-outline-light {
    border-color: rgba(255,255,255,0.12) !important;
    border-radius: 10px !important;
}
.ml-modal .btn-outline-light:hover {
    background: rgba(255,255,255,0.05) !important;
    border-color: rgba(255, 143, 31, 0.4) !important;
}

/* ===== Three.js preview ===== */
.ml-preview { background: #0a0a0a; }
#threeContainer {
    width: 100%;
    height: 100%;
    position: relative;
    background: linear-gradient(180deg, #0a1525 0%, #1a2540 100%);
}
#previewHud {
    position: absolute;
    top: 16px;
    right: 16px;
    display: flex;
    gap: 6px;
    z-index: 10;
    align-items: center;
}
#previewHud .ml-layer-toggles {
    display: flex;
    gap: 4px;
    padding: 4px;
    background: rgba(18, 18, 18, 0.85);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border: 1px solid rgba(255,255,255,0.08);
    border-radius: 10px;
}
#previewHud .prev-toggle {
    width: 34px;
    height: 32px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 7px !important;
    border-color: transparent !important;
    background: transparent !important;
    color: #ccc;
}
#previewHud .prev-toggle:hover {
    background: rgba(255,255,255,0.06) !important;
    color: #fff;
}
#previewHud .prev-toggle.active {
    background: #ff8f1f !important;
    color: #1a1a1a !important;
}
#previewHud .prev-toggle .bx { font-size: 1.1rem; }
#previewHud .ml-hud-sep {
    width: 1px;
    height: 26px;
    background: rgba(255,255,255,0.12);
    margin: 0 2px;
}

/* Mobile preview HUD — the row of [Natural][Basemap][Wireframe][Auto-spin]
   labelled buttons plus the 6-icon layer-toggles pill overflowed the
   right side of the modal on phones. We let the HUD wrap to multiple
   rows, drop the labels on the standalone buttons so they become icon-
   only, hide the separator, and pad clear of the modal header / safe
   area. The buttons keep their orange .active fill so users can see at
   a glance which modes are on. */
@media (max-width: 700px) {
    #previewHud {
        top: 10px;
        right: 10px;
        left: 10px;
        flex-wrap: wrap;
        justify-content: flex-end;
        gap: 6px;
        align-items: stretch;
        pointer-events: none;
    }
    #previewHud > * { pointer-events: auto; }
    #previewHud .ml-hud-sep { display: none; }
    /* Labelled mode buttons → icon-only on small screens. font-size:0
       collapses the text node and the explicit .bx font-size restores
       just the icon. line-height keeps the icon vertically centred
       since Bootstrap's button line-height would otherwise add space. */
    #previewHud > .btn:not(.prev-toggle) {
        font-size: 0 !important;
        line-height: 1 !important;
        padding: 0 !important;
        width: 38px;
        height: 38px;
        min-width: 38px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        background: rgba(18, 18, 18, 0.85) !important;
        border-color: rgba(255,255,255,0.08) !important;
        backdrop-filter: blur(10px);
        -webkit-backdrop-filter: blur(10px);
    }
    #previewHud > .btn:not(.prev-toggle).active {
        background: #ff8f1f !important;
        border-color: #ff8f1f !important;
        color: #1a1a1a !important;
    }
    #previewHud > .btn:not(.prev-toggle) .bx {
        font-size: 1.2rem !important;
        margin: 0 !important;
    }
    /* Layer-toggles pill stays as the existing icon-only group, just a
       hair smaller so two rows of HUD don't crowd the canvas. */
    #previewHud .ml-layer-toggles { padding: 3px; gap: 2px; }
    #previewHud .prev-toggle { width: 32px; height: 32px; }
    #previewHud .prev-toggle .bx { font-size: 1rem; }
    /* When the tile selector becomes visible, give it its own row so
       it never gets squeezed off-screen. */
    #previewHud #prevTileSelector {
        max-width: 100% !important;
        width: 100%;
        flex: 1 1 100%;
        order: 99;
    }
}

/* iOS safe-area padding for the preview HUD (the modal-fullscreen body
   doesn't inherit the topbar's notch padding, so the HUD floats up
   underneath the notch on a landscape iPhone). */
@supports (top: env(safe-area-inset-top)) {
    @media (max-width: 700px) {
        #previewHud { top: max(10px, env(safe-area-inset-top)); }
    }
}

/* ===== Spinner / Loading Modal =====
   The shared root `terraprinter.css` defines `#spinner { display:block;
   background: rgba(0,0,0,0.58); pointer-events:none; z-index:10000 }`
   with id-specificity, which beats plain `.ml-spinner` and made the
   v2 modal render as a block (content collapsing to the top-left flex
   start of `body { display:flex }`). The selectors below use
   `#spinner.ml-spinner` to outrank the root rules. `display` stays
   without !important so the inline `style="display:none"` toggle
   keeps working for showSpinner / hideSpinner. */
#spinner.ml-spinner {
    position: fixed !important;
    top: 0 !important;
    left: 0 !important;
    width: 100vw !important;
    height: 100vh !important;
    height: 100dvh !important;
    margin: 0 !important;
    padding: 0 !important;
    z-index: 99999 !important;
    display: flex;
    align-items: center !important;
    justify-content: center !important;
    flex: 0 0 auto !important;
    background: rgba(8, 8, 10, 0.62) !important;
    pointer-events: auto !important;
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    animation: ml-spinner-fade-in 0.18s ease-out;
}
@keyframes ml-spinner-fade-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}
.ml-spinner-content {
    background: #1a1a1a;
    border-radius: 14px;
    padding: 28px 32px;
    width: min(360px, calc(100vw - 32px));
    text-align: center;
    border: 1px solid rgba(255,255,255,0.1);
    box-shadow: 0 18px 48px rgba(0,0,0,0.6);
}
.ml-spinner-circle {
    width: 44px;
    height: 44px;
    border: 4px solid rgba(255,143,31,0.18);
    border-top-color: #ff8f1f;
    border-radius: 50%;
    animation: ml-spin 0.9s linear infinite;
    margin: 0 auto 16px;
}
@keyframes ml-spin { to { transform: rotate(360deg); } }
.ml-spinner-msg {
    font-size: 0.95rem;
    font-weight: 500;
    color: #f0f0f0;
    margin-bottom: 14px;
    line-height: 1.4;
}
.ml-spinner-progress {
    height: 4px;
    background: rgba(255,255,255,0.08);
    border-radius: 2px;
    overflow: hidden;
}
.ml-spinner-progress > div {
    height: 100%;
    background: #ff8f1f;
    width: 0%;
    transition: width 0.3s;
}

/* ===== Cursor elevation tooltip ===== */
.ml-cursor-elev {
    position: absolute;
    pointer-events: none;
    background: rgba(0,0,0,0.85);
    color: #5dd8b6;
    padding: 4px 8px;
    border-radius: 6px;
    font-family: "SF Mono", Menlo, monospace;
    font-size: 0.75rem;
    z-index: 4;
    transform: translate(12px, -100%);
    white-space: nowrap;
    border: 1px solid rgba(93, 216, 182, 0.3);
}

/* ===== MapLibre Draw style overrides for dark UI ===== */
.maplibregl-ctrl-attrib {
    background: rgba(0,0,0,0.5) !important;
    color: #aaa !important;
}
.maplibregl-ctrl-attrib a { color: #ddd !important; }

/* hide default mapboxgl-draw controls (we have our own toolbar) */
.mapboxgl-ctrl-group { display: none !important; }

/* hover label on multi-tile */
.ml-tile-tooltip {
    position: absolute;
    background: rgba(0,0,0,0.85);
    color: #fff;
    padding: 4px 8px;
    border-radius: 4px;
    font-size: 0.75rem;
    pointer-events: none;
    z-index: 4;
    transform: translate(-50%, -50%);
}

/* ===== SweetAlert2 toasts — match the dark glassmorphism toolbar ===== */
.swal2-popup.swal2-toast {
    background: rgba(18, 18, 18, 0.85) !important;
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border: 1px solid rgba(255,255,255,0.08) !important;
    border-radius: 12px !important;
    box-shadow: 0 8px 24px rgba(0,0,0,0.4) !important;
    color: #fff !important;
    padding: 12px 16px !important;
}
.swal2-popup.swal2-toast .swal2-title {
    color: #fff !important;
    font-weight: 500 !important;
    font-size: 0.95rem !important;
    margin: 0 !important;
    padding: 0 !important;
}
.swal2-popup.swal2-toast .swal2-html-container {
    color: #cfcfcf !important;
    font-size: 0.85rem !important;
}
/* Recolor each icon variant to match the accent palette. Borders +
   inner strokes both have to be overridden — SweetAlert paints the
   ring as a border and the glyph as ::before/::after pseudo-elements. */
.swal2-popup.swal2-toast .swal2-icon {
    border-color: #ff8f1f !important;
    color: #ff8f1f !important;
}
.swal2-popup.swal2-toast .swal2-icon.swal2-success {
    border-color: #7bb867 !important;
    color: #7bb867 !important;
}
.swal2-popup.swal2-toast .swal2-icon.swal2-success [class^='swal2-success-line'],
.swal2-popup.swal2-toast .swal2-icon.swal2-success .swal2-success-ring {
    background-color: #7bb867 !important;
    border-color: #7bb867 !important;
}
.swal2-popup.swal2-toast .swal2-icon.swal2-error {
    border-color: #e57373 !important;
    color: #e57373 !important;
}
.swal2-popup.swal2-toast .swal2-icon.swal2-error [class^='swal2-x-mark-line'] {
    background-color: #e57373 !important;
}
.swal2-popup.swal2-toast .swal2-icon.swal2-warning {
    border-color: #ffb74d !important;
    color: #ffb74d !important;
}

/* Non-toast modals (Swal.fire without {toast:true}) get the same
   surface treatment so e.g. "Area too large" and "Export failed"
   stop looking like a leftover Bootstrap white card. */
.swal2-popup:not(.swal2-toast) {
    background: rgba(20, 20, 20, 0.96) !important;
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border: 1px solid rgba(255,255,255,0.08) !important;
    border-radius: 14px !important;
    color: #fff !important;
}
.swal2-popup:not(.swal2-toast) .swal2-title,
.swal2-popup:not(.swal2-toast) .swal2-html-container { color: #fff !important; }
.swal2-popup:not(.swal2-toast) .swal2-input,
.swal2-popup:not(.swal2-toast) .swal2-textarea {
    background: rgba(0,0,0,0.4) !important;
    color: #fff !important;
    border: 1px solid rgba(255,255,255,0.12) !important;
}
.swal2-popup:not(.swal2-toast) .swal2-confirm {
    background: #ff8f1f !important;
    color: #1a1a1a !important;
    border: 0 !important;
    box-shadow: none !important;
}
.swal2-popup:not(.swal2-toast) .swal2-cancel {
    background: rgba(255,255,255,0.08) !important;
    color: #fff !important;
    border: 0 !important;
}

/* =====================================================================
 * Mobile & touch refinements
 * ===================================================================== */

/* iOS safe-area insets — float the floating UI clear of the notch and
   home indicator. Uses max() so desktop browsers without a nonzero env()
   keep the original 12px values. The toolbar's top tracks the topbar so
   the two never overlap on a notched device. */
@supports (top: env(safe-area-inset-top)) {
    .ml-topbar    { top:    max(12px, env(safe-area-inset-top)); }
    .ml-toolbar   { top:    max(80px, calc(env(safe-area-inset-top) + 68px)); }
    .ml-statusbar { bottom: max(12px, env(safe-area-inset-bottom)); }
    .ml-generate  { bottom: max(56px, calc(env(safe-area-inset-bottom) + 44px)); }
    .ml-generate-cancel { bottom: max(64px, calc(env(safe-area-inset-bottom) + 52px)); }
    .maplibregl-ctrl-bottom-left,
    .maplibregl-ctrl-bottom-right {
        padding-bottom: env(safe-area-inset-bottom);
    }
}

/* Touch devices: tooltips are useless and get sticky on tap (the :hover
   state lingers until the next tap elsewhere). Drop them entirely. */
@media (hover: none) {
    .ml-tool[data-tip]::before,
    .ml-tool[data-tip]::after { display: none !important; }
}

/* Phones — the big rework. The right-side toolbar has 14+ buttons in a
   single column and was running into both the bottom-right zoom buttons
   and the generate pill. We hide MapLibre's nav control (pinch + drag
   are native on touch), compress the toolbar, and tighten the top bar
   and bottom controls to make room. */
@media (max-width: 600px) {
    .ml-brand-text { display: none; }
    .ml-brand { padding: 0 12px; }
    .ml-search-wrap { max-width: none; }
    .ml-statusbar { font-size: 0.68rem; padding: 4px 10px; gap: 6px; }
    .ml-settings { width: 100% !important; }

    /* Topbar — slightly shorter so the toolbar can start higher. */
    .ml-topbar {
        top: 10px;
        left: 10px;
        right: 10px;
        gap: 8px;
        height: 44px;
    }
    .ml-brand, .ml-search-wrap, .ml-icon-btn {
        height: 44px;
    }
    .ml-icon-btn { width: 44px; }
    .ml-search-wrap { padding: 0 12px; gap: 8px; }
    .ml-search-wrap input { font-size: 0.92rem; }

    /* Hide MapLibre's built-in zoom buttons — pinch-to-zoom and the
       two-finger rotate gesture cover the same ground on touch, and the
       buttons collided with the lower half of the right-side toolbar. */
    .maplibregl-ctrl-bottom-right .maplibregl-ctrl-group { display: none; }

    /* Tighter right-side toolbar so 14 buttons fit comfortably above the
       generate pill / status bar even on a 667px-tall iPhone SE. The
       top tracks the safe-area inset so notched phones don't push the
       topbar down onto it. */
    .ml-toolbar {
        top: max(66px, calc(env(safe-area-inset-top, 0px) + 60px));
        right: 8px;
        padding: 4px;
        gap: 2px;
        border-radius: 10px;
    }
    .ml-tool {
        width: 38px;
        height: 38px;
        border-radius: 7px;
    }
    .ml-tool .bx { font-size: 1.05rem; }
    .ml-tool-sep {
        margin: 1px 4px;
        background: rgba(255,255,255,0.06);
        height: 1px;
    }
    /* Caret badge slightly smaller to match the smaller buttons */
    .ml-tool .ml-tool-caret { width: 12px; height: 12px; }
    .ml-tool .ml-tool-caret .bx { font-size: 0.7rem; }

    /* Shape / OSM flyouts: tighter padding so they don't crowd the
       toolbar edge on narrow screens. */
    .ml-shape-flyout { padding: 4px; gap: 2px; }

    /* Generate pill — narrower so it doesn't bleed off the side of a
       small viewport. The cancel circle moves with it. */
    .ml-generate { padding: 8px 14px 8px 8px; gap: 10px; border-radius: 16px; }
    .ml-generate-text   { font-size: 0.95rem; }
    .ml-generate-kicker { font-size: 0.6rem; }
    .ml-generate-icon   { width: 40px; height: 40px; }
    .ml-generate-icon .bx { font-size: 1.3rem; }
    .ml-generate-arrow  { width: 24px; height: 24px; }
    .ml-generate-cancel {
        width: 40px;
        height: 40px;
        left: calc(50% - 170px);
    }

    /* Selection handles — minimum 44×44 for finger taps would be ideal
       but the visuals fight the map at that size. 36 is a reasonable
       compromise on touch. */
    .ml-handle { width: 34px; height: 34px; }
    .ml-handle .bx { font-size: 1rem; }

    /* Sun compass inside the (now full-width) settings sidebar */
    .sun-compass-svg { max-width: 240px; }
    .sun-readouts { max-width: 240px; }
}

/* Very short screens (landscape phones) — drop the toolbar's secondary
   buttons via a "more" toggle would be ideal, but as a stop-gap let the
   toolbar scroll vertically if it overflows the viewport. */
@media (max-height: 520px) {
    .ml-toolbar {
        max-height: calc(100vh - 80px);
        overflow-y: auto;
        scrollbar-width: none;
    }
    .ml-toolbar::-webkit-scrollbar { display: none; }
}
