/* ================ 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 {
    /* Logo + wordmark only — no pill/button chrome. A drop shadow keeps it
       legible over bright satellite imagery. */
    color: #fff;
    text-decoration: none;
    height: 48px;
    display: flex;
    align-items: center;
    gap: 9px;
    font-weight: 600;
    transition: opacity 0.15s;
}
.ml-brand:hover { color: #fff; opacity: 0.85; }
.ml-brand-logo {
    height: 38px;
    width: auto;
    display: block;
    filter: drop-shadow(0 2px 4px rgba(0,0,0,0.55));
}
.ml-brand-text {
    font-size: 1.2rem;
    letter-spacing: 0.01em;
    white-space: nowrap;
    text-shadow: 0 1px 3px rgba(0,0,0,0.7);
}
.ml-brand-stack { display: flex; flex-direction: column; line-height: 1.1; }
.ml-brand-tagline {
    font-size: 0.6rem;
    font-weight: 400;
    color: rgba(255,255,255,0.75);
    white-space: nowrap;
    text-shadow: 0 1px 3px rgba(0,0,0,0.7);
}
.ml-brand-text em { font-weight: 700; color: #ff8f1f; font-style: normal; }
/* Static (non-link) brand lockup — used in the 3D preview header. */
.ml-brand-static { cursor: default; }
.ml-brand-static:hover { opacity: 1; }
.ml-preview-subtitle {
    margin-left: 14px;
    padding-left: 14px;
    border-left: 1px solid rgba(255,255,255,0.16);
    color: #9aa0a6;
    font-size: 0.9rem;
    font-weight: 500;
}
/* Buy-me-a-coffee support button. */
.ml-coffee { display: flex; align-items: center; flex: 0 0 auto; transition: transform .12s ease; }
.ml-coffee:hover { transform: translateY(-1px); }
.ml-coffee img { height: 38px; width: auto; display: block; border-radius: 8px; }
/* Settings-panel variant — pinned to the top-right of the sidebar header,
   just left of the close button. margin-left:auto pushes it past the (blank)
   offcanvas title so it hugs the right edge. The soft yellow halo + slow
   breathing pulse are there to catch the eye without being obnoxious. */
.ml-coffee-panel {
    margin-left: auto;
    margin-right: 10px;
    border-radius: 8px;
    box-shadow: 0 0 0 0 rgba(255, 221, 0, 0.45);
    animation: coffeePulse 3.6s ease-in-out infinite;
}
.ml-coffee-panel img { height: 34px; }
.ml-coffee-panel:hover { animation-play-state: paused; box-shadow: 0 0 14px 2px rgba(255, 221, 0, 0.45); }
@keyframes coffeePulse {
    0%, 70%, 100% { box-shadow: 0 0 0 0 rgba(255, 221, 0, 0.0); }
    35%           { box-shadow: 0 0 12px 2px rgba(255, 221, 0, 0.40); }
}
@media (prefers-reduced-motion: reduce) {
    .ml-coffee-panel { animation: none; }
}
/* Header variant — inline next to the 3D-preview brand. */
.ml-coffee-header { margin-left: 18px; }
.ml-coffee-header img { height: 34px; }
@media (max-width: 600px) {
    .ml-coffee-header { display: none; }
    .ml-coffee-panel img { height: 30px; }
}

.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; }

/* Hide the gear while the settings panel is open — it would sit redundantly
   next to the open sidebar. JS toggles .settings-open on <body> from the
   offcanvas show/hide events; !important wins over the inline display the
   selection-draw handlers set. (Avoids :has() for older-browser support.) */
body.settings-open #openSettings { display: none !important; }

/* ===== Toolbar (right side, beneath the settings button) ===== */
.ml-toolbar {
    position: absolute;
    /* Starts below the floating support button (which sits under the gear). */
    top: 118px;
    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: 5px;
    display: flex;
    flex-direction: column;
    gap: 3px;
    z-index: 5;
}
.ml-tool {
    position: relative;
    width: 34px;
    height: 34px;
    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.2rem; }
.ml-tool-sep {
    height: 1px;
    background: rgba(255,255,255,0.06);
    margin: 3px 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; }

/* ===== Custom-building edit handles (teal, to distinguish from the
   orange print-area handles when both are on screen) ===== */
.ml-handle-bldg { border-color: #15e0c8; color: #15c8b2; }
.ml-handle-bldg:hover { box-shadow: 0 6px 18px rgba(21, 224, 200, 0.5), 0 0 0 1px rgba(0,0,0,0.05); }
.ml-handle-bldg.ml-handle-resize { background: #15c8b2; color: #fff; border-color: #fff; }
.ml-handle-bldg.ml-handle-resize:hover { background: #11b39f; }
.ml-handle-bldg.ml-handle-rotate { background: #15c8b2; color: #fff; border-color: #fff; }
.ml-handle-bldg.ml-handle-rotate:hover { background: #11b39f; }
.ml-handle-bldg.ml-handle-vertex { border-color: #15e0c8; background: #fff; }
.ml-handle-bldg.ml-handle-vertex:hover { background: #e6fffb; }

/* ===== Custom-building draw tools (in the settings panel) ===== */
.cb-tools { display: flex; flex-wrap: wrap; gap: 8px; }
.cb-tool {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 11px;
    border-radius: 8px;
    border: 1px solid rgba(255,255,255,0.16);
    background: rgba(255,255,255,0.04);
    color: #e8e8ea;
    font-size: 0.8rem;
    cursor: pointer;
    transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}
.cb-tool:hover { background: rgba(255,255,255,0.1); border-color: rgba(255,255,255,0.28); }
.cb-tool .bx { font-size: 1.05rem; }
.cb-tool.active { background: #ff8f1f; border-color: #ff8f1f; color: #fff; }

/* Building list rows: selected row gets a teal ring; inline height input. */
.cb-row.active { border-color: #15e0c8; box-shadow: 0 0 0 1px #15e0c8 inset; }
.cb-row .cb-h { width: 62px; flex: 0 0 auto; }

/* On-building height handle — drag up/down to change the extrusion height.
   Stacked up/down chevrons; ns-resize cursor; teal like the other building
   handles. A live "Nm" badge appears above it while dragging. */
.ml-handle-height {
    flex-direction: column;
    line-height: 0.5;
    cursor: ns-resize;
    touch-action: none;
}
.ml-handle-height .bx { font-size: 0.72rem; display: block; }
.ml-handle-height .cb-height-badge {
    position: absolute;
    bottom: calc(100% + 6px);
    left: 50%;
    transform: translateX(-50%);
    background: #15c8b2;
    color: #fff;
    font-size: 0.72rem;
    font-weight: 600;
    line-height: 1;
    padding: 3px 6px;
    border-radius: 6px;
    white-space: nowrap;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.1s ease;
}
.ml-handle-height.dragging .cb-height-badge { opacity: 1; }

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

/* ===== Sea-floor relief (bathymetry) prominent toggle =====
   Promoted out of the Print settings into a standalone card at the top of the
   panel so it reads as a primary mode switch, not a buried checkbox. */
.ml-bathy {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 2px 0 16px;
    padding: 12px 14px;
    background: linear-gradient(135deg, rgba(28,72,112,0.55), rgba(18,18,18,0.35));
    border: 1px solid rgba(92,179,232,0.35);
    border-radius: 12px;
    cursor: pointer;
    transition: border-color .15s ease, background .15s ease;
}
.ml-bathy:hover { border-color: rgba(92,179,232,0.6); background: linear-gradient(135deg, rgba(28,72,112,0.7), rgba(18,18,18,0.4)); }
.ml-bathy-ico { font-size: 1.7rem; color: #5cb3e8; flex: 0 0 auto; }
.ml-bathy-copy { display: flex; flex-direction: column; flex: 1 1 auto; min-width: 0; }
.ml-bathy-title { font-weight: 600; font-size: 0.92rem; color: #fff; }
.ml-bathy-sub { font-size: 0.72rem; color: #9aa7b3; line-height: 1.3; margin-top: 2px; }
.ml-bathy .form-check-input {
    flex: 0 0 auto;
    width: 2.6em;
    height: 1.4em;
    margin: 0;
    float: none;
    cursor: pointer;
    background-color: rgba(255,255,255,0.12);
    border-color: rgba(255,255,255,0.25);
}
.ml-bathy .form-check-input:checked { background-color: #5cb3e8; border-color: #5cb3e8; }
.ml-bathy .form-check-input:focus { box-shadow: 0 0 0 0.2rem rgba(92,179,232,0.35); border-color: #5cb3e8; }

/* ===== Settings accordions =====
   The panel groups ~17 control sections into collapsible <details> blocks so
   the offcanvas is scannable instead of one long scroll. Sharp, flat styling:
   hairline dividers, an orange icon + edge accent on the active group, and a
   quick reveal on open. JS-toggled sub-sections (#sunSection, #puzzleSettings,
   #minecraftSettings, #multiAcc) keep their ids and live inside these bodies. */
.ml-acc {
    border-bottom: 1px solid rgba(255,255,255,0.07);
}
.ml-acc-head {
    list-style: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 13px 2px;
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: #cfcfcf;
    user-select: none;
    position: relative;
    transition: color .15s ease, background .15s ease;
}
.ml-acc-head::-webkit-details-marker { display: none; }
.ml-acc-head::marker { content: ""; }
.ml-acc-head:hover { color: #fff; }
.ml-acc-head:focus-visible { outline: 2px solid #ff8f1f; outline-offset: -2px; }
.ml-acc-ico {
    font-size: 1.1rem;
    color: #8a8a8a;
    width: 20px;
    text-align: center;
    flex: 0 0 auto;
    transition: color .15s ease;
}
.ml-acc-chev {
    margin-left: auto;
    font-size: 1.15rem;
    color: #6f6f6f;
    transition: transform .2s ease, color .15s ease;
}
.ml-acc[open] > .ml-acc-head { color: #fff; }
.ml-acc[open] > .ml-acc-head .ml-acc-ico { color: #ff8f1f; }
.ml-acc[open] > .ml-acc-head .ml-acc-chev { transform: rotate(180deg); color: #ff8f1f; }
/* Orange edge accent on the open group, flush to the panel's left edge. */
.ml-acc-head::before {
    content: "";
    position: absolute;
    left: -16px;
    top: 0;
    bottom: 0;
    width: 2px;
    background: #ff8f1f;
    transform: scaleX(0);
    transform-origin: left;
    transition: transform .18s ease;
}
.ml-acc[open] > .ml-acc-head::before { transform: scaleX(1); }
.ml-acc-body {
    padding: 2px 0 14px;
    animation: mlAccReveal .2s ease;
}
@keyframes mlAccReveal {
    from { opacity: 0; transform: translateY(-5px); }
    to   { opacity: 1; transform: translateY(0); }
}
/* Sections nested in an accordion drop their own outer rule + heavy padding;
   their .ml-section-title becomes a lightweight sub-label within the group. */
.ml-acc-body .ml-section {
    padding: 6px 0 2px;
    border-bottom: 0;
}
.ml-acc-body .ml-section .ml-section-title {
    color: #9a9a9a;
    font-size: 0.66rem;
}

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

/* Surface-colour live legend (filled at Generate) */
.sc-legend {
    background: rgba(255, 255, 255, 0.03);
    border: 1px solid rgba(255, 255, 255, 0.06);
    border-radius: 7px;
    padding: 6px 8px;
    font-size: 0.78rem;
    color: #cccccc;
}
.sc-legend-title { font-weight: 600; color: #ffffff; margin-bottom: 4px; }
.sc-legend-row { display: flex; align-items: center; gap: 8px; padding: 2px 0; }
.sc-legend-sw {
    width: 14px; height: 14px; border-radius: 3px; flex-shrink: 0;
    border: 1px solid rgba(255, 255, 255, 0.25);
}
.sc-legend-name { flex: 1; min-width: 0; }
.sc-legend-pct { font-variant-numeric: tabular-nums; color: #ffffff; }
.sc-legend-merged { opacity: 0.6; font-style: italic; }
.sc-legend-note { margin-top: 4px; color: rgba(255, 255, 255, 0.5); font-size: 0.72rem; }

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

/* Gallery — one-click famous locations, two-column chip grid */
.ml-gallery {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 6px;
}
.ml-gallery-item {
    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;
    gap: 8px;
    cursor: pointer;
    transition: background 0.1s, border-color 0.1s;
    text-align: left;
}
.ml-gallery-item:hover { background: rgba(255, 143, 31, 0.1); border-color: rgba(255, 143, 31, 0.3); }
.ml-gallery-emoji { font-size: 1.05rem; line-height: 1; }
.ml-gallery-name { font-size: 0.8rem; color: #fff; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

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

/* ===== Themed On/Off toggle switch =====
   Applied to the settings On/Off buttons (Flat model, Trees, Frame, Label,
   Contours). The button keeps its existing JS wiring — it flips `.active`
   and swaps its text between "On"/"Off" — while this styling turns it into a
   sliding pill switch. The knob is an ::after that translates on `.active`;
   the label sits opposite the knob and swaps sides with it. */
.ml-switch {
    position: relative;
    flex: 0 0 auto;
    width: 74px;
    height: 30px;
    border-radius: 999px;
    border: 1px solid rgba(255,255,255,0.12);
    background: rgba(255,255,255,0.10);
    color: #9aa0a6;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    cursor: pointer;
    padding: 0 12px 0 30px;   /* off: text right, knob space on the left */
    text-align: right;
    line-height: 28px;
    -webkit-appearance: none;
    appearance: none;
    transition: background 0.18s ease, color 0.18s ease, border-color 0.18s ease;
}
.ml-switch::after {
    /* Sized/positioned against the padding box (72×28 after the 1px
       borders). A 22px knob leaves a clean 3px margin on every side and
       nests in both rounded caps. */
    content: "";
    position: absolute;
    top: 3px;
    left: 3px;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 1px 3px rgba(0,0,0,0.45);
    transition: transform 0.18s ease;
}
.ml-switch:hover { border-color: rgba(255,143,31,0.5); }
.ml-switch:focus-visible {
    outline: none;
    box-shadow: 0 0 0 0.2rem rgba(255,143,31,0.35);
}
.ml-switch.active {
    background: #ff8f1f;
    border-color: #ff8f1f;
    color: #1a1a1a;
    text-align: left;
    padding: 0 30px 0 12px;   /* on: text left, knob space on the right */
}
.ml-switch.active::after { transform: translateX(44px); }  /* 72 − 22 − 3 − 3 (padding box) */

/* ===== How-to button (top bar) ===== */
.ml-howto-btn {
    width: auto !important;
    padding: 0 14px !important;
    gap: 8px;
    color: #fff !important;
}
.ml-howto-btn .bx { font-size: 1.3rem; color: #ff8f1f; }
.ml-howto-label { font-size: 0.9rem; font-weight: 600; white-space: nowrap; }
@media (max-width: 600px) {
    .ml-howto-btn { width: 44px !important; padding: 0 !important; }
    .ml-howto-label { display: none; }
}

/* ===== How-to guided tour modal ===== */
.htu-modal { position: relative; }
.htu-close { position: absolute; top: 14px; right: 16px; z-index: 3; opacity: 0.7; }
.htu-close:hover { opacity: 1; }
.htu-body {
    padding: 44px 34px 6px;
    text-align: center;
    min-height: 320px;
}
.htu-step { animation: htuFade 0.3s ease; }
@keyframes htuFade {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: none; }
}
.htu-icon {
    width: 84px; height: 84px;
    margin: 0 auto 22px;
    border-radius: 22px;
    display: flex; align-items: center; justify-content: center;
    background: linear-gradient(145deg, rgba(255,143,31,0.22), rgba(255,143,31,0.05));
    border: 1px solid rgba(255,143,31,0.35);
    color: #ff8f1f;
}
.htu-icon .bx { font-size: 2.6rem; }
.htu-icon-lg { width: 96px; height: 96px; }
.htu-icon-lg .bx { font-size: 3rem; }
.htu-icon-go {
    background: linear-gradient(145deg, rgba(59,130,246,0.25), rgba(59,130,246,0.06));
    border-color: rgba(59,130,246,0.4);
    color: #4d9bff;
}
.htu-title { color: #fff; font-weight: 700; margin-bottom: 12px; font-size: 1.35rem; }
.htu-text  { color: #c7ccd1; font-size: 0.98rem; line-height: 1.55; margin-bottom: 14px; }
.htu-text strong { color: #fff; }
.htu-tip {
    color: #9aa0a6; font-size: 0.85rem;
    display: inline-flex; align-items: center; gap: 6px;
    background: rgba(255,255,255,0.04);
    border-radius: 10px; padding: 8px 14px; margin: 0;
}
.htu-tip .bx { color: #ff8f1f; font-size: 1rem; }
.htu-chips {
    display: flex; flex-wrap: wrap; gap: 8px;
    justify-content: center; margin-bottom: 16px;
}
.htu-chip {
    display: inline-flex; align-items: center; gap: 6px;
    background: rgba(255,255,255,0.06);
    border: 1px solid rgba(255,255,255,0.1);
    border-radius: 999px; padding: 6px 12px;
    font-size: 0.82rem; color: #dfe3e7;
}
.htu-chip .bx { font-size: 1rem; color: #ff8f1f; }
.htu-footer {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px; padding: 14px 24px 22px;
}
.htu-dots { display: flex; gap: 7px; }
.htu-dot {
    width: 8px; height: 8px; border-radius: 50%;
    background: rgba(255,255,255,0.22);
    transition: all 0.2s; cursor: pointer; border: 0; padding: 0;
}
.htu-dot.active { background: #ff8f1f; width: 22px; border-radius: 4px; }
.htu-nav { display: flex; gap: 8px; }
.htu-skip { color: #9aa0a6 !important; text-decoration: none; padding: 0 4px; font-size: 0.85rem; }
.htu-skip:hover { color: #fff !important; }
@media (max-width: 600px) {
    .htu-body { padding: 40px 20px 4px; min-height: 300px; }
    .htu-footer { padding: 12px 16px 18px; }
}

/* ===== Support / donate modal ===== */
.sup-modal { position: relative; }
.sup-close { position: absolute; top: 14px; right: 16px; z-index: 3; opacity: 0.6; }
.sup-close:hover { opacity: 1; }
.sup-body { padding: 34px 32px 4px; text-align: center; }
.sup-icon {
    width: 74px; height: 74px; margin: 0 auto 16px;
    display: flex; align-items: center; justify-content: center;
    border-radius: 50%;
    background: linear-gradient(135deg, rgba(255,221,0,0.22), rgba(255,143,31,0.14));
    border: 1px solid rgba(255,221,0,0.32);
}
.sup-icon .bx { font-size: 2.4rem; color: #ffdd00; }
.sup-title { color: #fff; font-weight: 700; font-size: 1.25rem; line-height: 1.35; margin-bottom: 12px; }
.sup-text { color: #c7ccd1; font-size: 0.95rem; line-height: 1.55; margin-bottom: 16px; }
.sup-text-sm { font-size: 0.88rem; color: #a9b0b7; }
.sup-stats {
    display: flex; gap: 10px; margin: 0 0 16px;
}
.sup-stat {
    flex: 1 1 0; min-width: 0;
    padding: 12px 10px;
    background: rgba(255,255,255,0.04);
    border: 1px solid rgba(255,255,255,0.07);
    border-radius: 12px;
}
.sup-stat-num { display: block; font-size: 1.35rem; font-weight: 700; color: #ff8f1f; line-height: 1.1; }
.sup-stat-label { display: block; font-size: 0.74rem; color: #9aa0a6; margin-top: 4px; line-height: 1.3; }
.sup-cta {
    display: inline-flex; align-items: center; justify-content: center;
    transition: transform .12s ease, box-shadow .12s ease;
    border-radius: 10px;
}
.sup-cta img { height: 52px; width: auto; display: block; border-radius: 10px; }
.sup-cta:hover { transform: translateY(-2px); box-shadow: 0 8px 20px rgba(255,221,0,0.28); }
.sup-note { margin: 10px 0 0; font-size: 0.75rem; color: #7f868d; display: flex; align-items: center; justify-content: center; gap: 6px; }
.sup-note .bx { font-size: 0.9rem; }
.sup-footer {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px; padding: 18px 26px 20px; margin-top: 16px;
    border-top: 1px solid rgba(255,255,255,0.06);
}
.sup-never {
    display: flex; align-items: center; gap: 8px;
    font-size: 0.82rem; color: #9aa0a6; cursor: pointer; margin: 0;
}
.sup-never:hover { color: #d5d9dd; }
.sup-never .form-check-input { margin: 0; flex: 0 0 auto; cursor: pointer; }
@media (max-width: 600px) {
    .sup-body { padding: 30px 20px 4px; }
    .sup-title { font-size: 1.1rem; }
    .sup-footer { padding: 14px 18px 18px; }
    .sup-cta img { height: 46px; }
}

/* ===== 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;
}
#previewHud .ml-hud-brightness {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 0 10px;
    height: 31px;
    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;
    color: #ccc;
}
#previewHud .ml-hud-brightness .bx { font-size: 1.05rem; }
#previewHud .ml-hud-brightness input[type="range"] {
    width: 90px;
    accent-color: #ff8f1f;
}

/* 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(118px, calc(env(safe-area-inset-top) + 106px)); }
    .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, .ml-brand-tagline { 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(106px, calc(env(safe-area-inset-top, 0px) + 96px));
        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; }
}

/* ===== World switcher (Earth / Mars / Moon) ===== */
.ml-world .ml-icon-btn {
    width: auto;
    padding: 0 12px;
    gap: 6px;
    color: #fff;
}
.ml-world .ml-icon-btn .bx { font-size: 1rem; opacity: 0.7; }
#worldIcon { font-size: 1.15rem; line-height: 1; }
.ml-world-label { font-size: 0.9rem; font-weight: 600; white-space: nowrap; }
.ml-world-menu { min-width: 9rem; }
@media (max-width: 600px) {
    .ml-world-label { display: none; }
    .ml-world .ml-icon-btn { padding: 0 8px; }
}
/* Mars / Moon: hide controls that only have Earth data (OSM, sea floor, land cover). */
body.tp-offworld .tp-earth-only { display: none !important; }
body.tp-offworld #previewHud .ml-layer-toggles,
body.tp-offworld #previewHud .ml-layer-toggles + .ml-hud-sep { display: none !important; }

/* "Printed it? Add a photo" — shown once, a few days after a download. */
.ml-photo-nudge {
    position: fixed; left: 50%; top: 72px; transform: translateX(-50%); z-index: 1060;
    width: max-content; max-width: calc(100vw - 32px); height: auto;
    display: flex; align-items: center; gap: 10px; padding: 8px 8px 8px 14px;
    background: rgba(20, 20, 20, 0.94); color: #fff; border: 1px solid rgba(255, 143, 31, 0.45);
    border-radius: 12px; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45); font-size: 0.88rem;
}
.ml-photo-nudge > .bx { color: #ff8f1f; font-size: 1.2rem; }
.ml-photo-nudge .btn { white-space: nowrap; }
.ml-photo-nudge-x { background: none; border: 0; color: rgba(255, 255, 255, 0.6); font-size: 1.3rem; line-height: 1; padding: 0 4px; }
.ml-photo-nudge-x:hover { color: #fff; }
@media (max-width: 600px) { .ml-photo-nudge { top: 64px; font-size: 0.8rem; } }

/* Saved presets row (top of the settings panel). */
.ml-presets {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 0 0 16px;
    padding: 8px 10px;
    border: 1px solid rgba(255,255,255,0.12);
    border-radius: 12px;
    background: rgba(255,255,255,0.03);
}
.ml-presets-ico { font-size: 1.25rem; color: rgba(255,255,255,0.6); }
.ml-presets .form-select { flex: 1 1 auto; min-width: 0; }
.ml-presets .btn { flex: 0 0 auto; padding: 2px 8px; }

/* =====================================================================
   UI refresh (2026-10): sharper, quieter chrome.
   One graphite surface + one hairline, sentence-case headings, small
   muted help text, tabular numbers, and orange reserved for "selected"
   and the one primary action. Overrides only — delete this block to
   roll back.
   ===================================================================== */
:root {
    --tp-surface: rgba(22, 24, 27, 0.92);
    --tp-surface-solid: #16181b;
    --tp-raised: #1f2226;
    --tp-line: rgba(255, 255, 255, 0.09);
    --tp-line-strong: rgba(255, 255, 255, 0.16);
    --tp-text: #ecebe8;
    --tp-muted: #9ea2a8;
    --tp-accent: #ff8f1f;
    --tp-accent-tint: rgba(255, 143, 31, 0.14);
    --tp-radius: 10px;
}

/* Floating chrome: same surface, same hairline, same radius everywhere. */
.ml-search-wrap,
.ml-icon-btn,
.ml-toolbar,
.ml-statusbar {
    background: var(--tp-surface) !important;
    border: 1px solid var(--tp-line) !important;
    border-radius: var(--tp-radius) !important;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.28);
}
.ml-search-wrap input::placeholder { color: var(--tp-muted); }

/* Toolbar: "selected" is an orange icon on a faint tint, not a solid
   block, so six active tools no longer shout over the map. */
.ml-toolbar { padding: 4px; gap: 2px; }
.ml-tool { color: #c9cbce; border-radius: 7px; }
.ml-tool.active,
.ml-tool-shape.active,
.ml-shape-flyout .osm-toggle.active {
    background: var(--tp-accent-tint);
    color: var(--tp-accent);
    box-shadow: inset 0 0 0 1px rgba(255, 143, 31, 0.35);
}
.ml-tool-shape.active:hover,
.ml-tool-shape.active.flyout-open { background: rgba(255, 143, 31, 0.22); color: var(--tp-accent); }
.ml-tool-sep { background: var(--tp-line); }

/* Status bar: one muted colour, proportional figures that don't jiggle. */
.ml-statusbar {
    font-family: inherit;
    font-variant-numeric: tabular-nums;
    font-size: 0.76rem;
    color: var(--tp-muted);
    padding: 5px 12px;
}
.ml-statusbar #statusElev,
.ml-statusbar #statusArea { color: var(--tp-text); }
.ml-statusbar .ml-sep { background: var(--tp-line-strong); }

/* Generate: still the one bold thing on screen — solid, flat, no glow. */
.ml-generate {
    background: var(--tp-accent);
    border-radius: 12px;
    padding: 8px 14px 8px 8px;
    gap: 12px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
}
.ml-generate::after { display: none; }
.ml-generate:hover {
    filter: none;
    background: #ff9c38;
    box-shadow: 0 10px 28px rgba(0, 0, 0, 0.4);
}
.ml-generate-icon { width: 38px; height: 38px; border-radius: 9px; box-shadow: none; background: rgba(26, 18, 8, 0.14); }
.ml-generate-kicker {
    text-transform: none;
    letter-spacing: 0;
    font-size: 0.72rem;
    font-weight: 600;
    margin-bottom: 3px;
}
.ml-generate-text { font-weight: 700; font-size: 1rem; }
.ml-generate-arrow { background: transparent; }
.ml-generate-cancel {
    background: var(--tp-surface) !important;
    border: 1px solid var(--tp-line) !important;
}

/* Settings panel */
.ml-settings,
#settingsPanel {
    background: var(--tp-surface-solid) !important;
    color: var(--tp-text);
}
.ml-settings .offcanvas-header { border-bottom: 1px solid var(--tp-line); }

/* Group headings: sentence case, no tracking, a calm weight. */
.ml-acc { border-bottom: 1px solid var(--tp-line); }
.ml-acc-head {
    text-transform: none;
    letter-spacing: 0;
    font-size: 0.92rem;
    font-weight: 600;
    color: #d6d7d9;
    padding: 12px 2px;
}
.ml-acc-ico { color: var(--tp-muted); }
.ml-acc-chev { color: #6c7076; }
.ml-acc[open] > .ml-acc-head .ml-acc-chev { color: var(--tp-muted); }

/* Sub-section titles inside a group: small, sentence case, muted. */
.ml-section-title,
.ml-acc-body .ml-section .ml-section-title {
    text-transform: none;
    letter-spacing: 0;
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--tp-text);
    margin-bottom: 6px;
}
.ml-acc-body .ml-section { padding: 8px 0 4px; }

/* Labels + values: values in the text colour with even-width digits,
   not a monospace island. */
.ml-label { font-size: 0.8rem; color: var(--tp-muted); margin: 10px 0 2px; }
.ml-label span {
    font-family: inherit;
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    color: var(--tp-text);
}

/* Help text was body-size; make it a quiet footnote. */
.ml-settings .ml-help,
#settingsPanel .ml-help {
    font-size: 0.76rem !important;
    line-height: 1.45;
    color: var(--tp-muted) !important;
}

/* Range sliders: thin track, small solid thumb. */
.ml-settings .form-range,
#settingsPanel .form-range { height: 1.1rem; }
.ml-settings .form-range::-webkit-slider-runnable-track,
#settingsPanel .form-range::-webkit-slider-runnable-track { height: 3px; background: var(--tp-line-strong); border-radius: 2px; }
.ml-settings .form-range::-webkit-slider-thumb,
#settingsPanel .form-range::-webkit-slider-thumb { width: 14px; height: 14px; margin-top: -5.5px; background: var(--tp-accent); border: 0; box-shadow: 0 0 0 3px var(--tp-surface-solid); }
.ml-settings .form-range::-moz-range-track,
#settingsPanel .form-range::-moz-range-track { height: 3px; background: var(--tp-line-strong); border-radius: 2px; }
.ml-settings .form-range::-moz-range-thumb,
#settingsPanel .form-range::-moz-range-thumb { width: 14px; height: 14px; background: var(--tp-accent); border: 0; }

/* Segmented buttons (terrain style, sources, edges): selected = tint,
   not an inverted white block. */
#settingsPanel .btn-group > .btn-outline-light {
    border-color: var(--tp-line-strong);
    color: #c9cbce;
    font-weight: 500;
}
#settingsPanel .btn-group > .btn-outline-light:hover { background: rgba(255, 255, 255, 0.05); color: #fff; }
#settingsPanel .btn-group > .btn-outline-light.active {
    background: var(--tp-accent-tint);
    border-color: rgba(255, 143, 31, 0.55);
    color: var(--tp-accent);
}

/* Form controls in the panel share the raised surface + hairline. */
#settingsPanel .form-select,
#settingsPanel .form-control {
    background-color: var(--tp-raised);
    border-color: var(--tp-line-strong);
    color: var(--tp-text);
    border-radius: 7px;
}

/* Top-of-panel rows: flatten the bathymetry card and presets box into
   plain rows separated by the same hairline as the groups. */
.ml-bathy {
    background: transparent;
    border: 0;
    border-bottom: 1px solid var(--tp-line);
    border-radius: 0;
    padding: 10px 2px 14px;
    margin: 0;
}
.ml-bathy:hover { background: transparent; border-color: var(--tp-line); }
.ml-bathy-ico { font-size: 1.35rem; }
.ml-bathy-sub { color: var(--tp-muted); }
.ml-presets {
    border: 0;
    border-bottom: 1px solid var(--tp-line);
    border-radius: 0;
    background: transparent;
    padding: 10px 2px;
    margin: 0;
}
.ml-presets-ico { color: var(--tp-muted); font-size: 1.1rem; }

/* Keyboard focus stays visible on everything interactive. */
.ml-tool:focus-visible,
.ml-icon-btn:focus-visible,
.ml-generate:focus-visible,
#settingsPanel .btn:focus-visible {
    outline: 2px solid var(--tp-accent);
    outline-offset: 2px;
}

/* Phones: give the search box room — smaller round buttons, tighter gaps. */
@media (max-width: 600px) {
    .ml-topbar { gap: 6px; left: 8px; right: 8px; }
    .ml-icon-btn { width: 40px !important; height: 40px !important; }
    .ml-icon-btn .bx { font-size: 1.2rem; }
    .ml-search-wrap { height: 40px; padding: 0 10px; min-width: 0; flex: 1 1 auto; }
    .ml-world .ml-world-label, .ml-world .bx-chevron-down { display: none; }
    .ml-toolbar { right: 8px; }
}
@media (max-width: 600px) {
    .ml-generate { padding: 6px 12px 6px 6px; gap: 10px; }
    .ml-generate-text { white-space: nowrap; font-size: 0.95rem; }
    .ml-generate-icon { width: 34px; height: 34px; }
}

/* ---- Brand everywhere (2026-10-20) ----
   The top-bar brand never shrinks under the search box; the settings panel
   carries its own copy (it covers the top-bar one when open); and phones get
   a two-row top bar so the name + tagline fit beside the icon buttons. */
.ml-topbar > .ml-brand { flex-shrink: 0; }
.ml-search-wrap { min-width: 0; }
/* Docked sidebar: it shows the brand, so the top bar starts right of it. */
body.settings-docked #topBar { left: calc(var(--tp-panel-w, 0px) + 12px); }
body.settings-docked #topBar > .ml-brand { display: none; }
/* Slide-over panel: the panel has its own brand; the top-bar one is
   covered on the left-hand variant, so hide it to avoid a half-visible copy. */
body.settings-open:not(.settings-docked) #topBar > .ml-brand { visibility: hidden; }
.ml-settings .offcanvas-title { margin: 0; flex: 0 1 auto; min-width: 0; }
.ml-brand-panel { height: auto; }
.ml-brand-panel .ml-brand-logo { height: 34px; }
.ml-brand-panel .ml-brand-text { font-size: 1.1rem; }

@media (max-width: 600px) {
    .ml-topbar {
        flex-wrap: wrap;
        height: auto;
        row-gap: 8px;
    }
    .ml-topbar > .ml-brand { order: 0; padding: 0 2px; height: 40px; }
    .ml-brand-text, .ml-brand-tagline { display: block; }
    .ml-topbar .ml-brand-logo { height: 30px; }
    .ml-topbar .ml-brand-text { font-size: 1.05rem; }
    .ml-topbar > .ml-world { order: 1; margin-left: auto; }
    .ml-topbar > .ml-icon-btn,
    .ml-topbar > .dropdown,
    .ml-topbar > *:not(.ml-brand):not(.ml-search-wrap) { order: 1; }
    .ml-topbar > .ml-search-wrap { order: 2; flex: 1 0 100%; margin-left: 0; height: 40px; }
    .ml-toolbar { top: max(116px, calc(env(safe-area-inset-top, 0px) + 106px)); }
}

/* Export dialog: a visible close button (phones have no Esc key, and the
   backdrop is easy to miss), and sentence-case section headings. */
.ml-modal { position: relative; }
.ml-modal-close {
    position: absolute;
    top: 14px;
    right: 14px;
    z-index: 2;
    width: 1.1em;
    height: 1.1em;
    padding: 8px;
    border-radius: 8px;
    opacity: 0.7;
}
.ml-modal-close:hover { opacity: 1; background-color: rgba(255,255,255,0.08); }
#exportModal .text-uppercase {
    text-transform: none !important;
    letter-spacing: 0;
    font-size: 0.9rem;
    color: var(--tp-text) !important;
}
/* Mid widths: the docked sidebar is only ~300 px, so tighten its header
   so the brand and the Donate button sit side by side without touching. */
@media (min-width: 601px) and (max-width: 1199px) {
    .ml-settings .offcanvas-header { padding-left: 14px; padding-right: 12px; gap: 8px; }
    .ml-brand-panel { gap: 7px; }
    .ml-brand-panel .ml-brand-logo { height: 28px; }
    .ml-brand-panel .ml-brand-text { font-size: 0.98rem; }
    .ml-brand-panel .ml-brand-tagline { font-size: 0.56rem; }
    .ml-coffee-panel { margin-right: 0; }
    .ml-coffee-panel img { height: 28px; }
}
/* Same as body.settings-docked, but pure CSS so it's right from the first
   paint (the JS check only runs once the map has loaded, which briefly
   showed the brand twice). Mirrors terraprinter.css: the sidebar docks at
   ≥992px with width max(25%, 300px). */
@media (min-width: 992px) {
    #topBar { left: calc(max(25vw, 300px) + 12px); }
    #topBar > .ml-brand { display: none; }
    #openSettings { display: none !important; }   /* the sidebar is always open here */
}

/* Dialog buttons: the theme flips outline-light text to black on hover
   (it expects a white fill), but our hover keeps the dark fill — so the
   label vanished. Keep it light on hover / focus / press. */
.ml-modal .btn-outline-light:hover,
.ml-modal .btn-outline-light:focus-visible,
.ml-modal .btn-outline-light:active,
.ml-modal .btn-outline-light.active,
.ml-modal .btn-outline-light.show {
    color: #fff !important;
    background: rgba(255, 255, 255, 0.07) !important;
}

/* STL split button: narrow caret beside the STL tile. */
.ml-split .ml-split-toggle { flex: 0 0 26px !important; max-width: 26px; padding-left: 0; padding-right: 0; }
.ml-split .ml-split-toggle::after { margin-left: 0; }
.ml-modal .dropdown-menu { border: 1px solid var(--tp-line-strong); border-radius: 10px; }
.ml-modal .dropdown-item { font-size: 0.85rem; display: flex; align-items: center; gap: 6px; }

/* Export dialog mini preview */
.ml-mini-preview {
    position: relative;
    border-radius: 12px;
    overflow: hidden;
    border: 1px solid var(--tp-line);
    background: #0f1115;
}
.ml-mini-preview canvas {
    display: block;
    width: 100%;
    height: 210px;
    cursor: grab;
    touch-action: pan-y;   /* vertical swipes still scroll the dialog */
}
.ml-mini-preview canvas:active { cursor: grabbing; }
.ml-mini-hint {
    position: absolute;
    left: 10px;
    bottom: 10px;
    font-size: 0.72rem;
    color: rgba(255, 255, 255, 0.75);
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.7);
    pointer-events: none;
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
.ml-mini-open {
    position: absolute;
    right: 10px;
    bottom: 10px;
    background: var(--tp-accent) !important;
    color: #1a1208 !important;
    border: 0 !important;
    font-weight: 600;
    border-radius: 8px !important;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 5px 10px;
}
.ml-mini-open:hover { background: #ff9c38 !important; }
@media (max-width: 600px) { .ml-mini-preview canvas { height: 180px; } }

/* =====================================================================
   Export dialog (2026-10-20 redesign): header → preview → one primary
   download → other formats → save → contents → estimate.
   ===================================================================== */
.ml-export .modal-body { padding: 18px 20px 20px; }
.ml-exp-head { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 12px; }
.ml-exp-head-text { flex: 1 1 auto; min-width: 0; }
.ml-exp-title {
    font-size: 1.15rem;
    font-weight: 700;
    color: var(--tp-text);
    margin: 0 0 3px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.ml-exp-sub {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 12px;
    font-size: 0.8rem;
    color: var(--tp-muted);
    font-variant-numeric: tabular-nums;
}
.ml-exp-health { display: inline-flex; align-items: center; gap: 4px; }
.ml-exp-health.is-ok { color: #7ddc7d; }
.ml-exp-health.is-warn { color: #ffb454; }
.ml-exp-close { flex: 0 0 auto; margin-top: 2px; opacity: 0.7; }
.ml-exp-close:hover { opacity: 1; }

.ml-export .ml-mini-preview { margin-bottom: 16px; }

.ml-exp-section { margin-bottom: 14px; }
.ml-exp-h {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--tp-muted);
    margin: 0 0 8px;
    text-transform: none;
    letter-spacing: 0;
}

/* Primary download */
.ml-exp-primary {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 11px 14px;
    background: var(--tp-accent) !important;
    color: #1a1208 !important;
    border: 0 !important;
    border-radius: 10px !important;
    text-align: left;
}
.ml-exp-primary:hover { background: #ff9c38 !important; }
.ml-exp-primary:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.ml-exp-primary > .bx { font-size: 1.5rem; }
.ml-exp-primary-text { display: flex; flex-direction: column; line-height: 1.2; }
.ml-exp-primary-label { font-weight: 700; font-size: 0.98rem; }
.ml-exp-primary-sub { font-size: 0.75rem; opacity: 0.75; font-weight: 500; }

/* Secondary formats */
.ml-exp-formats { display: grid; grid-template-columns: 1.3fr 1fr 1fr; gap: 8px; margin-top: 8px; }
.ml-exp-formats .ml-split { width: 100%; }
.ml-exp-fmt { font-weight: 600; font-size: 0.85rem; padding: 7px 0; }
.ml-exp-formats .ml-split .ml-exp-fmt { flex: 1 1 auto; }

.ml-exp-tiles { margin-top: 10px; }
.ml-exp-tiles-head { font-size: 0.78rem; color: var(--tp-muted); margin-bottom: 6px; }
.ml-exp-extra { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.ml-exp-extra:empty { display: none; }
.ml-exp-extra .btn { flex: 1 1 auto; }

/* Selects in the dialog */
.ml-export .form-select {
    background-color: var(--tp-raised);
    border-color: var(--tp-line-strong);
    color: var(--tp-text);
    border-radius: 7px;
}

/* Save / Saved panel from account/app.js: a quiet bar, not a banner */
#exportModal .tpa-export-panel {
    background: rgba(255, 255, 255, 0.035) !important;
    border: 1px solid var(--tp-line) !important;
    border-radius: 10px !important;
    padding: 10px 12px !important;
    margin-bottom: 14px !important;
    gap: 10px !important;
}
#exportModal .tpa-export-panel .tpa-panel-icon { font-size: 1.25rem; align-self: flex-start; margin-top: 1px; }
#exportModal .tpa-export-panel .small { font-size: 0.8rem; }
#exportModal .tpa-saved-actions { margin-top: 8px; }
/* Save is secondary to Download 3MF: orange outline, not a second solid
   orange block. */
#exportModal .tpa-export-panel .btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    white-space: nowrap;
    text-shadow: none !important;
    flex-shrink: 0;
}
#exportModal .tpa-export-panel .btn-primary,
#exportModal .tpa-export-panel .btn-primary:focus {
    background: transparent !important;
    border: 1px solid rgba(255, 143, 31, 0.6) !important;
    color: var(--tp-accent) !important;
    font-weight: 600;
    box-shadow: none !important;
}
#exportModal .tpa-export-panel .btn-primary:hover {
    background: var(--tp-accent-tint) !important;
    border-color: var(--tp-accent) !important;
    color: #ffb15c !important;
}

/* What's in it */
.ml-exp-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 14px; }
.ml-exp-chips:empty { display: none; }
.ml-exp-chip {
    display: inline-flex;
    align-items: baseline;
    gap: 5px;
    padding: 3px 9px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.05);
    font-size: 0.75rem;
    color: var(--tp-muted);
}
.ml-exp-chip-val { color: var(--tp-text); font-weight: 600; font-variant-numeric: tabular-nums; }

/* Estimate */
.ml-exp-estimate {
    border-top: 1px solid var(--tp-line);
    padding-top: 14px;
}
.ml-exp-est-head { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.ml-exp-est-head .ml-exp-h { flex: 1 1 auto; }
.ml-exp-est-head .form-select { width: auto; min-width: 84px; }
.ml-exp-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.ml-exp-stat {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 9px 10px;
    border-radius: 9px;
    background: rgba(255, 255, 255, 0.035);
}
.ml-exp-stat-val { font-size: 1.02rem; font-weight: 700; color: var(--tp-text); font-variant-numeric: tabular-nums; }
.ml-exp-stat-label { font-size: 0.72rem; color: var(--tp-muted); }
.ml-exp-foot { font-size: 0.7rem; color: var(--tp-muted); opacity: 0.75; margin-top: 8px; }

@media (max-width: 600px) {
    .ml-export .modal-body { padding: 14px 14px 16px; }
    .ml-exp-stat-val { font-size: 0.95rem; }
}
/* Let the save button drop under the text when space is short (long
   translations) instead of squeezing the sentence into a narrow column. */
#exportModal .tpa-export-panel { flex-wrap: wrap; }
#exportModal .tpa-export-panel > .flex-grow-1 { flex: 1 1 220px; }
#exportModal .tpa-export-panel > .btn { margin-left: auto; }

/* ---- About section (2026-10-20) ---- */
.ml-about-lead { font-size: 0.86rem; color: var(--tp-text); line-height: 1.45; margin: 0 0 4px; }
.ml-about-data { font-size: 0.74rem; color: var(--tp-muted); line-height: 1.45; margin: 0 0 12px; }
.ml-about-lang { display: flex; align-items: center; gap: 8px; margin-bottom: 12px; }
.ml-about-lang > .bx { color: var(--tp-muted); font-size: 1.1rem; }

.ml-about-explore { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-bottom: 12px; }
.ml-about-explore a {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    padding: 10px 4px;
    border: 1px solid var(--tp-line);
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.03);
    color: var(--tp-text);
    text-decoration: none;
    font-size: 0.8rem;
    font-weight: 600;
    transition: border-color .15s, background .15s;
}
.ml-about-explore a .bx { font-size: 1.25rem; color: var(--tp-accent); }
.ml-about-explore a:hover { border-color: rgba(255, 143, 31, 0.45); background: rgba(255, 255, 255, 0.05); color: #fff; }

.ml-about-links { border-top: 1px solid var(--tp-line); margin-bottom: 12px; }
.ml-about-links > a,
.ml-about-links > button {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 10px 2px;
    background: none;
    border: 0;
    border-bottom: 1px solid var(--tp-line);
    color: var(--tp-text);
    text-decoration: none;
    font-size: 0.84rem;
    text-align: left;
    cursor: pointer;
}
.ml-about-links .bx:first-child { font-size: 1.1rem; color: var(--tp-muted); width: 20px; text-align: center; }
.ml-about-links span { flex: 1 1 auto; }
.ml-about-chev { color: #5f6368; font-size: 1.1rem; transition: transform .15s, color .15s; }
.ml-about-links > a:hover,
.ml-about-links > button:hover { color: #fff; }
.ml-about-links > a:hover .ml-about-chev,
.ml-about-links > button:hover .ml-about-chev { color: var(--tp-accent); transform: translateX(2px); }
.ml-about-links > a:focus-visible,
.ml-about-links > button:focus-visible,
.ml-about-explore a:focus-visible { outline: 2px solid var(--tp-accent); outline-offset: 2px; }

.ml-about-foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 2px 6px;
    font-size: 0.72rem;
    color: var(--tp-muted);
    margin: 0;
}
.ml-about-foot a { color: var(--tp-muted); text-decoration: none; }
.ml-about-foot a:hover { color: var(--tp-text); text-decoration: underline; }

/* Featured print card: sentence-case label to match the panel. */
#tpFeaturedPrint .tpfp-label { text-transform: none; letter-spacing: 0; font-size: 0.74rem; }

/* About: five explore tiles — three on top, two wider below. */
.ml-about-explore { grid-template-columns: repeat(6, 1fr); }
.ml-about-explore a { grid-column: span 2; }
.ml-about-explore a:nth-child(n+4) { grid-column: span 3; flex-direction: row; justify-content: center; gap: 6px; }

/* Small "learn more" links inside a settings section. */
.ml-context-link {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    margin-top: 10px;
    font-size: 0.78rem;
    color: var(--tp-accent);
    text-decoration: none;
}
.ml-context-link:hover { color: #ffb15c; text-decoration: underline; }
.ml-context-link::after { content: "\2197"; font-size: 0.75em; opacity: 0.8; }   /* ↗ opens a new tab */
