/* ===== UpTheCut: AdminLTE-inspired shell ===== */

html, body {
    margin: 0;
    padding: 0;
    height: 100%;
    font-family: 'Segoe UI', system-ui, -apple-system, Roboto, sans-serif;
    font-size: 0.95rem;
}

/* ----- Theme tokens ----- */
:root {
    --utc-sidebar-bg: #1f2d3d;
    --utc-sidebar-fg: #c2c7d0;
    --utc-sidebar-fg-active: #fff;
    --utc-sidebar-active-bg: #0d6efd;
    --utc-sidebar-brand-bg: #1a2532;
    --utc-sidebar-width: 200px;
    --utc-sidebar-width-collapsed: 64px;
    --utc-topbar-height: 56px;
    --utc-footer-height: 28px;
    --utc-content-bg: #f4f6f9;
    --utc-content-fg: #212529;
    --utc-card-bg: #ffffff;
    --utc-card-border: rgba(0,0,0,0.08);
    --utc-muted: #6c757d;
}

html[data-bs-theme="dark"] {
    --utc-sidebar-bg: #161e2b;
    --utc-sidebar-fg: #b9c1cb;
    --utc-sidebar-brand-bg: #0f1620;
    --utc-content-bg: #1a2030;
    --utc-content-fg: #e6e8ec;
    --utc-card-bg: #232b3b;
    --utc-card-border: rgba(255,255,255,0.06);
    --utc-muted: #8a93a3;
}

body {
    background: var(--utc-content-bg);
    color: var(--utc-content-fg);
}

/* ----- Boot loading ----- */
.loading-progress {
    position: relative;
    display: block;
    width: 8rem;
    height: 8rem;
    margin: 20vh auto 1rem auto;
}
.loading-progress circle {
    fill: none;
    stroke: var(--utc-sidebar-active-bg);
    stroke-width: 0.6rem;
    transform-origin: 50% 50%;
    transform: rotate(-90deg);
}
.loading-progress circle:last-child {
    stroke: var(--bs-primary, #0d6efd);
    stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
    transition: stroke-dasharray 0.05s ease-in-out;
}
.loading-progress-text {
    position: absolute;
    text-align: center;
    font-weight: bold;
    inset: calc(20vh + 3.25rem) 0 auto 0.2rem;
}
.loading-progress-text:after { content: var(--blazor-load-percentage-text, "Loading"); }

/* Blazor's built-in error UI is suppressed — errors are surfaced via toast/inline panels instead. */
#blazor-error-ui { display: none !important; }

/* ----- Shell layout -----
   Three-row grid: topbar / content / footer. Footer stays visible at every
   breakpoint; only the sidebar layout responds to viewport changes. */
.utc-shell {
    display: grid;
    grid-template-columns: var(--utc-sidebar-width) 1fr;
    grid-template-rows: var(--utc-topbar-height) 1fr var(--utc-footer-height);
    grid-template-areas:
        "sidebar topbar"
        "sidebar content"
        "sidebar footer";
    /* 100vh on mobile browsers includes the collapsing address-bar area,
       so the footer ends up hidden behind it (Edge Android puts the URL
       bar at the bottom). 100dvh follows the real visible viewport. The
       100vh line is the fallback for older engines. */
    height: 100vh;
    height: 100dvh;
    overflow: hidden;
    transition: grid-template-columns 200ms ease;
}
.utc-shell.collapsed { grid-template-columns: var(--utc-sidebar-width-collapsed) 1fr; }

/* ----- Sidebar ----- */
.utc-sidebar {
    grid-area: sidebar;
    background: var(--utc-sidebar-bg);
    color: var(--utc-sidebar-fg);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    box-shadow: 1px 0 4px rgba(0,0,0,0.3);
}
.utc-sidebar-brand {
    height: var(--utc-topbar-height);
    background: var(--utc-sidebar-brand-bg);
    color: #fff;
    display: flex;
    align-items: center;
    padding: 0 1rem;
    /* Wordmark sized to match the 28px icon height; weight 700 thickens
       the strokes so the run-together "UpTheCut" still reads cleanly. */
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: 0;
    white-space: nowrap;
    overflow: hidden;
    border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
.utc-sidebar-brand .utc-brand-icon {
    display: inline-flex;
    align-items: center;
    margin-right: 0.65rem;
}
.utc-sidebar-brand .utc-brand-icon svg {
    width: 28px;
    height: 28px;
    display: block;
}
.utc-shell.collapsed .utc-brand-text { display: none; }

/* Collapsed icon-rail tightening. Without these the brand row's leftover
   margin-right on the icon span (10px) plus the .utc-sidebar-brand's 1rem
   side padding makes the row 70px wide in a 64px column - triggering the
   horizontal scrollbar on .utc-sidebar-nav. Zero the padding and centre
   the icon; do the same for nav-link icons so they line up under the
   brand mark. */
.utc-shell.collapsed .utc-sidebar-brand {
    padding: 0;
    justify-content: center;
}
.utc-shell.collapsed .utc-sidebar-brand .utc-brand-icon {
    margin-right: 0;
}
.utc-shell.collapsed .utc-sidebar-nav .utc-nav-link {
    justify-content: center;
    padding-left: 0;
    padding-right: 0;
}
/* Belt-and-braces: even if some future content briefly overshoots, the
   nav scrolls vertically only - no horizontal scrollbar. */
.utc-sidebar-nav {
    overflow-x: hidden;
}
.utc-sidebar-nav { list-style: none; padding: 0.5rem 0; margin: 0; overflow-y: auto; }
.utc-sidebar-section {
    font-size: 0.7rem;
    text-transform: uppercase;
    color: var(--utc-muted);
    padding: 0.75rem 1rem 0.25rem;
    letter-spacing: 0.08em;
    white-space: nowrap;
}
.utc-shell.collapsed .utc-sidebar-section { visibility: hidden; }
.utc-sidebar-nav .utc-nav-link {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.6rem 1rem;
    color: var(--utc-sidebar-fg);
    text-decoration: none;
    border-left: 3px solid transparent;
    white-space: nowrap;
    transition: background 100ms ease, border-color 100ms ease;
}
.utc-sidebar-nav .utc-nav-link i {
    font-size: 1.05rem;
    width: 1.25rem;
    text-align: center;
    flex-shrink: 0;
}
.utc-sidebar-nav .utc-nav-link:hover {
    background: rgba(255,255,255,0.04);
    color: var(--utc-sidebar-fg-active);
}
.utc-sidebar-nav .utc-nav-link.active {
    color: var(--utc-sidebar-fg-active);
    background: rgba(13,110,253,0.16);
    border-left-color: var(--utc-sidebar-active-bg);
}
.utc-shell.collapsed .utc-sidebar-nav .utc-nav-link span { display: none; }

/* ----- Nav click pulse -----
   Brief blue overlay that fades out over 450ms after a NavLink is tapped.
   Confirms the click without making the user wait for the page transition
   to be the only feedback. Uses a pseudo-element so it stacks cleanly
   over both inactive (transparent) and active (semi-blue) link rows.
   Sidebar.razor adds/removes `.is-pulsing` for the animation duration. */
.utc-sidebar-nav .utc-nav-link { position: relative; }
.utc-sidebar-nav .utc-nav-link.is-pulsing::after {
    content: "";
    position: absolute;
    inset: 0;
    background: var(--utc-sidebar-active-bg);
    pointer-events: none;
    animation: utc-nav-pulse 450ms ease-out forwards;
}
@keyframes utc-nav-pulse {
    0%   { opacity: 0.45; }
    100% { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
    .utc-sidebar-nav .utc-nav-link.is-pulsing::after {
        animation: none;
        opacity: 0;
    }
}

/* ----- Top bar ----- */
.utc-topbar {
    grid-area: topbar;
    background: var(--utc-card-bg);
    color: var(--utc-content-fg);
    border-bottom: 1px solid var(--utc-card-border);
    display: flex;
    align-items: center;
    padding: 0 1rem;
    gap: 0.75rem;
}
.utc-topbar .utc-sidebar-toggle {
    background: none;
    border: 0;
    color: inherit;
    font-size: 1.25rem;
    padding: 0.25rem 0.5rem;
    border-radius: 0.25rem;
    cursor: pointer;
}
.utc-topbar .utc-sidebar-toggle:hover { background: var(--utc-content-bg); }
.utc-topbar .utc-page-title { font-weight: 600; margin: 0 0.5rem; }
.utc-topbar .ms-auto { margin-left: auto; }
.utc-topbar .dropdown-menu { font-size: 0.9rem; }

/* ----- Content area ----- */
.utc-content {
    grid-area: content;
    overflow: auto;
    padding: 1.25rem;
    background: var(--utc-content-bg);
}
.utc-content--flush {
    padding: 0;
}

/* ----- Saved-route card (My Routes page) -----
   Lightweight panel inside the .utc-card so each saved entry feels like
   a distinct row without needing a full nested card chrome. Chips below
   carry the stat snapshot (distance / locks / cruising hours / days). */
.utc-route-card {
    border: 1px solid var(--utc-card-border);
    border-radius: 0.4rem;
    padding: 0.75rem 1rem;
    margin-bottom: 0.75rem;
    background: var(--utc-content-bg);
}
.utc-route-card:last-child { margin-bottom: 0; }
.utc-route-chip {
    display: inline-flex;
    align-items: center;
    font-size: 0.8rem;
    padding: 0.25rem 0.55rem;
    border-radius: 999px;
    background: var(--utc-card-bg);
    border: 1px solid var(--utc-card-border);
    color: var(--utc-content-fg);
    white-space: nowrap;
}

/* ----- Cards ----- */
.utc-card {
    background: var(--utc-card-bg);
    border: 1px solid var(--utc-card-border);
    border-radius: 0.4rem;
    padding: 1rem;
    margin-bottom: 1rem;
}
.utc-card-header {
    font-weight: 600;
    margin: -1rem -1rem 0.75rem -1rem;
    padding: 0.75rem 1rem;
    border-bottom: 1px solid var(--utc-card-border);
}

/* ----- Sign-in screen (Account.razor when anonymous) -----
   Stage fills the .utc-content cell so the card can sit dead-centre
   regardless of viewport height. min-height: 100% leans on the grid
   row sizing the parent — see .utc-content / .utc-shell. The negative
   margin offsets .utc-content's 1.25rem padding so the stage really
   does span edge-to-edge. */
.utc-signin-stage {
    min-height: 100%;
    margin: -1.25rem;
    padding: 1.25rem;
    display: flex;
    align-items: center;
    justify-content: center;
}
.utc-signin-card {
    width: 100%;
    max-width: 24rem;
    padding: 1.75rem 1.75rem 1.5rem;
    margin-bottom: 0;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.25);
}
.utc-signin-brand {
    display: flex;
    flex-direction: column;
    align-items: center;
    margin-bottom: 1.5rem;
}
.utc-signin-brand svg {
    width: 56px;
    height: 56px;
}
.utc-signin-brand .utc-signin-title {
    font-size: 1.15rem;
    font-weight: 600;
    margin-top: 0.5rem;
    color: var(--utc-content-fg);
}
.utc-signin-brand .utc-signin-subtitle {
    font-size: 0.85rem;
    color: var(--utc-muted);
    margin-top: 0.1rem;
}
.utc-signin-card .form-control {
    padding: 0.55rem 0.75rem;
}
.utc-signin-card .btn-primary {
    width: 100%;
    padding: 0.55rem 0.75rem;
    font-weight: 600;
}

/* ----- Footer ----- */
.utc-footer {
    grid-area: footer;
    background: var(--utc-card-bg);
    color: var(--utc-muted);
    border-top: 1px solid var(--utc-card-border);
    font-size: 0.72rem;
    line-height: 1;
    overflow: hidden;
}
.utc-footer-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    height: 100%;
    padding: 0 1rem;
    white-space: nowrap;
}
.utc-footer-brand,
.utc-footer-attr,
.utc-footer-date {
    display: inline-flex;
    align-items: center;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}
.utc-footer-attr {
    flex: 1 1 auto;
    justify-content: center;
}
.utc-footer-attr a {
    color: inherit;
    text-decoration: underline;
    text-decoration-color: rgba(127, 127, 127, 0.3);
    text-underline-offset: 2px;
}
.utc-footer-attr a:hover { text-decoration-color: currentColor; }
.utc-footer-sep { margin: 0 0.4rem; opacity: 0.55; }
.utc-footer-muted { color: var(--utc-muted); }

/* ----- Planner-specific (within shell) ----- */
.planner-layout {
    display: grid;
    grid-template-columns: 360px 1fr;
    /* Fill the .utc-content grid cell exactly. vh-based math used to drift
       by a subpixel against the grid row height once the footer joined the
       shell, causing the content area to scroll. height: 100% trusts the
       grid to size us. */
    height: 100%;
}
.planner-panel {
    background: var(--utc-card-bg);
    border-right: 1px solid var(--utc-card-border);
    padding: 1rem;
    overflow-y: auto;
    color: var(--utc-content-fg);
}
.planner-panel h3 {
    font-size: 0.95rem;
    margin: 0.75rem 0 0.4rem 0;
    color: var(--utc-content-fg);
}
.planner-panel label { display: block; font-size: 0.85rem; margin-top: 0.5rem; color: var(--utc-muted); }
.planner-panel .form-control { background: var(--utc-content-bg); color: var(--utc-content-fg); border-color: var(--utc-card-border); }
.planner-panel .btn-plan { width: 100%; margin-top: 0.75rem; }
.planner-map { width: 100%; height: 100%; }

/* Bottom-sheet drag handle — hidden by default; surfaced only by the mobile
   media query below. Always rendered in the DOM so toggling visibility is a
   pure CSS concern. */
.planner-sheet-handle { display: none; }

.cp-dropdown {
    background: var(--utc-card-bg);
    border: 1px solid var(--utc-card-border);
    border-radius: 0.25rem;
    max-height: 220px;
    overflow-y: auto;
    position: relative;
    z-index: 100;
    margin-top: 2px;
}
.cp-dropdown-item { padding: 0.4rem 0.6rem; cursor: pointer; border-bottom: 1px solid var(--utc-card-border); font-size: 0.85rem; }
.cp-dropdown-item:hover { background: var(--utc-content-bg); }
.cp-dropdown-item:last-child { border-bottom: 0; }

.cp-stats { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; margin: 0.75rem 0; }
.cp-stat { background: var(--utc-content-bg); padding: 0.6rem; border-radius: 0.3rem; text-align: center; border: 1px solid var(--utc-card-border); }
.cp-stat .v { font-size: 1.15rem; font-weight: 600; }
.cp-stat .l { font-size: 0.7rem; color: var(--utc-muted); text-transform: uppercase; letter-spacing: 0.04em; }

.cp-day { background: var(--utc-content-bg); padding: 0.6rem; border-radius: 0.3rem; margin-bottom: 0.4rem; border: 1px solid var(--utc-card-border); }
.cp-day .t { font-weight: 600; font-size: 0.9rem; }
.cp-day .m { font-size: 0.78rem; color: var(--utc-muted); margin-top: 0.15rem; }

.cp-warning {
    background: rgba(245, 158, 11, 0.12);
    color: var(--utc-content-fg);
    padding: 0.6rem 0.75rem;
    border-radius: 0.3rem;
    margin: 0.5rem 0;
    border-left: 3px solid #f59e0b;
    font-size: 0.85rem;
}
.cp-warning a { color: inherit; text-decoration: underline; }

.cp-poi-list { display: flex; flex-wrap: wrap; gap: 0.3rem; margin-bottom: 0.5rem; }
.cp-poi-pill {
    background: var(--utc-content-bg);
    border: 1px solid var(--utc-card-border);
    color: var(--utc-content-fg);
    padding: 0.2rem 0.6rem;
    border-radius: 1rem;
    font-size: 0.75rem;
    cursor: pointer;
    user-select: none;
}
.cp-poi-pill.active {
    background: var(--utc-sidebar-active-bg);
    border-color: var(--utc-sidebar-active-bg);
    color: #fff;
}

.cp-error {
    background: rgba(220, 53, 69, 0.12);
    color: var(--utc-content-fg);
    border-left: 3px solid #dc3545;
    padding: 0.5rem 0.75rem;
    border-radius: 0.3rem;
    margin-top: 0.5rem;
    font-size: 0.85rem;
}

.cp-settings { background: var(--utc-content-bg); padding: 0.5rem; border-radius: 0.3rem; margin-top: 0.5rem; border: 1px solid var(--utc-card-border); }
.cp-settings-toggle { background: transparent; border: 0; color: var(--utc-content-fg); cursor: pointer; padding: 0.25rem 0; font-size: 0.85rem; }

/* ----- Stoppage map markers ----- */
.utc-stoppage-ring {
    animation: utc-stoppage-pulse 1.6s ease-out infinite;
    transform-origin: center;
}
@keyframes utc-stoppage-pulse {
    0%   { stroke-opacity: 0.9; stroke-width: 2; }
    50%  { stroke-opacity: 0.5; stroke-width: 5; }
    100% { stroke-opacity: 0.9; stroke-width: 2; }
}

/* ===== Route alternatives picker ===== */
.cp-alts {
    margin-top: 0.75rem;
    padding: 0.75rem;
    border: 1px solid var(--utc-card-border);
    border-radius: 6px;
    background: var(--utc-card-bg);
}
.cp-alts-title {
    font-weight: 600;
    font-size: 0.85rem;
    color: var(--utc-muted);
    margin-bottom: 0.5rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.cp-alts-list {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}
.cp-alts-chip {
    text-align: left;
    border: 1px solid var(--utc-card-border);
    border-radius: 5px;
    background: transparent;
    padding: 0.5rem 0.65rem;
    cursor: pointer;
    transition: background 0.12s ease, border-color 0.12s ease;
}
.cp-alts-chip:hover {
    background: rgba(13, 110, 253, 0.06);
    border-color: rgba(13, 110, 253, 0.4);
}
.cp-alts-chip.is-selected {
    background: rgba(13, 110, 253, 0.12);
    border-color: #0d6efd;
    box-shadow: inset 0 0 0 1px #0d6efd;
}
.cp-alts-chip-label {
    font-weight: 600;
    font-size: 0.92rem;
    color: var(--utc-content-fg);
}
.cp-alts-chip-meta {
    font-size: 0.78rem;
    color: var(--utc-muted);
    margin-top: 0.1rem;
}

/* ===== Route picker loading / disabled state ===== */
.cp-alts-status {
    font-size: 0.78rem;
    color: var(--utc-muted);
    text-transform: none;
    letter-spacing: 0;
    font-weight: 500;
    display: inline-flex;
    align-items: center;
}
.cp-alts-chip-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}
.cp-alts-chip-spinner {
    width: 0.95rem;
    height: 0.95rem;
    border-width: 0.15rem;
    color: #0d6efd;
    flex-shrink: 0;
}
.cp-alts-chip:disabled {
    cursor: wait;
    opacity: 0.55;
}
.cp-alts-chip.is-loading {
    /* Override the dim from :disabled — this is the chip the user picked
       and we want it readable, not greyed out. */
    opacity: 1;
    border-color: #0d6efd;
    background: rgba(13, 110, 253, 0.08);
}
.cp-alts-chip:disabled:hover {
    /* Suppress hover styling while disabled — Bootstrap chips can otherwise
       look interactive even when nothing happens on click. */
    background: transparent;
    border-color: var(--utc-card-border);
}
.cp-alts-chip.is-loading:disabled:hover {
    background: rgba(13, 110, 253, 0.08);
    border-color: #0d6efd;
}

/* ===== POI pill count styling ===== */
.cp-poi-pill-label { /* keeps the inline flow tidy if we ever wrap */ }
.cp-poi-pill-count {
    margin-left: 0.35rem;
    opacity: 0.7;
    font-size: 0.85em;
    font-variant-numeric: tabular-nums;
}

/* ===== Modern POI map pin ===== */
.utc-poi-pin {
    /* drop-shadow on the wrapper picks up the SVG silhouette properly,
       unlike box-shadow which would frame the bounding rect. */
    filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.35));
    transition: transform 0.15s ease, filter 0.15s ease;
    cursor: pointer;
}
.utc-poi-pin:hover {
    /* Lift on hover so it's clear which pin the tooltip belongs to.
       transform-origin at the tip keeps the pin anchored to its lat/lon. */
    transform: scale(1.15);
    transform-origin: 50% 100%;
    filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.5));
    z-index: 1000;
}

/* Cleaner tooltip styling — slightly larger and a bit darker than Leaflet's
   default so the POI name reads at a glance over busy canal-corridor terrain. */
.utc-poi-tooltip {
    font-size: 0.85rem;
    padding: 6px 10px;
    background: rgba(33, 37, 41, 0.95);
    color: #fff;
    border: none;
    border-radius: 4px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
.utc-poi-tooltip::before {
    /* Tooltip arrow tip — match the dark fill */
    border-top-color: rgba(33, 37, 41, 0.95) !important;
}

/* ----- Map: waterway-authority legend chip (top-right) ----- */
.utc-canal-legend {
    background: rgba(255, 255, 255, 0.92);
    backdrop-filter: blur(4px);
    border: 1px solid rgba(0, 0, 0, 0.12);
    border-radius: 6px;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
    padding: 6px 9px;
    font-size: 0.78rem;
    line-height: 1.3;
    color: #1f2937;
    user-select: none;
}
.utc-canal-legend label {
    display: flex;
    align-items: center;
    gap: 6px;
    cursor: pointer;
    margin: 0;
    padding: 2px 0;
}
.utc-canal-legend label + label { margin-top: 2px; }
.utc-canal-legend input[type="checkbox"] {
    margin: 0;
    cursor: pointer;
}
.utc-canal-swatch {
    display: inline-block;
    width: 14px;
    height: 3px;
    border-radius: 2px;
}
.utc-canal-label { white-space: nowrap; }

/* ----- Map: POI legend control (top-right, shown while a route is loaded) -----
   Styled to match .utc-canal-legend so the two map controls feel like one
   system. Used by mapInterop.js → _ensurePoiLegend. */
.utc-poi-legend {
    background: rgba(255, 255, 255, 0.92);
    backdrop-filter: blur(4px);
    border: 1px solid rgba(0, 0, 0, 0.12);
    border-radius: 6px;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
    padding: 8px 10px;
    font-size: 0.78rem;
    line-height: 1.3;
    color: #1f2937;
    user-select: none;
    min-width: 168px;
    max-height: calc(100vh - 140px);
    overflow-y: auto;
}
/* ----- Map: collapsible legend header (shared by canal + POI legends) -----
   Click the header strip (or the chevron) to collapse the legend body to
   just the title bar; localStorage persists the choice per-legend. First-
   visit default is collapsed on narrow viewports (< 768px) so the legends
   don't eat half the screen on mobile. */
.utc-legend-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    cursor: pointer;
    user-select: none;
    padding-bottom: 4px;
    margin-bottom: 5px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.08);
    color: #111827;
}
.utc-canal-legend.collapsed .utc-legend-header,
.utc-poi-legend.collapsed .utc-legend-header {
    padding-bottom: 0;
    margin-bottom: 0;
    border-bottom: none;
}
.utc-legend-title {
    font-weight: 600;
    font-size: 0.78rem;
}
.utc-legend-toggle {
    background: transparent;
    border: 0;
    padding: 0 2px;
    line-height: 1;
    color: #6b7280;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
}
.utc-legend-toggle i {
    font-size: 0.9rem;
    transition: transform 0.18s ease;
}
.utc-canal-legend.collapsed .utc-legend-toggle i,
.utc-poi-legend.collapsed .utc-legend-toggle i {
    transform: rotate(180deg);
}
.utc-canal-legend.collapsed .utc-legend-body,
.utc-poi-legend.collapsed .utc-legend-body {
    display: none;
}
.utc-poi-legend label {
    display: flex;
    align-items: center;
    gap: 6px;
    cursor: pointer;
    margin: 0;
    padding: 2px 0;
}
.utc-poi-legend label + label { margin-top: 1px; }
.utc-poi-legend input[type="checkbox"] {
    margin: 0;
    cursor: pointer;
    flex: 0 0 auto;
}
.utc-poi-swatch {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    color: #fff;
    font-size: 9px;
    flex: 0 0 auto;
    box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.85) inset;
}
.utc-poi-swatch i { line-height: 1; }
.utc-daystop-swatch { background: #0d9488; }
.utc-waypoint-swatch {
    /* Plain coloured dot — matches the on-map waypoint marker style
       (a coloured circle with a white ring), in miniature. */
    width: 12px;
    height: 12px;
    box-shadow: 0 0 0 2px #ffffff inset, 0 0 0 1px rgba(0, 0, 0, 0.25);
}
.utc-poi-legend-subtitle {
    font-weight: 600;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.4px;
    color: #6b7280;
    margin: 2px 0 3px;
}
.utc-poi-label {
    flex: 1 1 auto;
    white-space: nowrap;
}
.utc-poi-count {
    color: #6b7280;
    font-variant-numeric: tabular-nums;
    flex: 0 0 auto;
}
.utc-poi-legend-divider {
    border-top: 1px solid rgba(0, 0, 0, 0.1);
    margin: 6px 0 4px;
}

/* ===== Boat dimensions panel ===== */
.cp-ftin { display: flex; gap: 4px; }
.cp-ftin input { width: 60px; }
.cp-help { font-size: 0.85em; color: #666; margin: 4px 0; }
.cp-warning-banner { background: #fee; border: 1px solid #c33; color: #900; padding: 8px 12px; margin: 8px 0; border-radius: 4px; }
.cp-warning-banner ul { margin: 4px 0 0 16px; padding: 0; }
.cp-badge-blocked { background: #c33; color: #fff; padding: 2px 6px; border-radius: 3px; font-size: 0.8em; margin-left: 6px; }

/* --- Map Inspector developer popup --- */
/* Compact tabular popup shown when the inspector is enabled and the user
   clicks the planner map. Self-contained styling so it doesn't depend on
   Bootstrap tables loading inside Leaflet's popup container.
   Forced dark colour scheme regardless of theme — the CARTO Voyager basemap
   is always light, so a light-on-light popup is unreadable. Dark slate +
   near-white text gives a strong contrast against the map under any
   theme. */
.utc-inspector-leaflet-popup .leaflet-popup-content-wrapper {
    background: #1a2235;
    color: #e8ecf3;
    border: 1px solid #2f3a55;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.35);
    border-radius: 6px;
}
.utc-inspector-leaflet-popup .leaflet-popup-tip { background: #1a2235; border: 1px solid #2f3a55; }
.utc-inspector-leaflet-popup .leaflet-popup-content { margin: 12px 16px; }
.utc-inspector-leaflet-popup .leaflet-popup-close-button { color: #e8ecf3 !important; }
.utc-inspector-leaflet-popup .leaflet-popup-close-button:hover { color: #ffffff !important; }

/* Lock-popup specs grid. Auto-extracted facts (rise/dimensions/type) from
   CRT_Locks_Public / OSM lock tags. Each cell is a label + value pair —
   the label sits above the value in a small, muted caption style, the
   value below in the popup's normal weight. Wraps to multi-line on narrow
   popups. Hidden entirely when none of the underlying fields have data. */
.utc-lock-specs {
    margin-top: 6px;
    display: flex;
    flex-wrap: wrap;
    gap: 6px 14px;
    padding-top: 6px;
    border-top: 1px solid rgba(0,0,0,.08);
}
.utc-lock-spec {
    display: inline-flex;
    flex-direction: column;
    min-width: 60px;
    line-height: 1.25;
}
.utc-lock-spec > em {
    font-style: normal;
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: #6b7280;
    font-weight: 600;
}
/* OperatingInstructions — upstream-sourced multi-line text. Distinct from
   the operator-curated notes block below so the popup reader can tell at
   a glance what's "official source" vs "operator added on top". */
.utc-lock-instructions {
    margin-top: 6px;
    padding-top: 6px;
    border-top: 1px solid rgba(0,0,0,.08);
    font-size: 0.86rem;
    line-height: 1.4;
    color: #444;
    white-space: pre-line;
}

/* Lock-popup annotations. Each note is a stack of:
   [category badge] [summary in bold]
   [detail body in muted text below].
   Categories supplied by Data/overrides.json — known ones get coloured
   badges; unknown ones fall back to the .utc-lock-note-badge default. */
.utc-lock-notes              { margin-top: 8px; border-top: 1px solid rgba(0,0,0,.08); padding-top: 6px; }
.utc-lock-note               { margin: 6px 0; line-height: 1.35; }
.utc-lock-note-badge {
    display: inline-block;
    padding: 1px 6px;
    margin-right: 4px;
    border-radius: 4px;
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    background: #6b7280;
    color: #ffffff;
    vertical-align: middle;
}
.utc-lock-note-flood-gate         > .utc-lock-note-badge { background: #2563eb; }
.utc-lock-note-manual-operation   > .utc-lock-note-badge { background: #d97706; }
.utc-lock-note-permit-required    > .utc-lock-note-badge { background: #dc2626; }
.utc-lock-note-staircase          > .utc-lock-note-badge { background: #7c3aed; }
.utc-lock-note-advisory           > .utc-lock-note-badge { background: #0891b2; }
.utc-lock-note-detail {
    margin-top: 2px;
    margin-left: 0;
    font-size: 0.86rem;
    color: #555;
}

.utc-inspector-popup { font-size: 0.95rem; min-width: 320px; line-height: 1.4; }
.utc-inspector-coords {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    color: #9ba4b8;
    margin-bottom: 8px;
    font-size: 0.9rem;
}
.utc-inspector-table { width: 100%; border-collapse: collapse; }
.utc-inspector-table th {
    text-align: left;
    font-weight: 600;
    color: #cfd6e8;
    border-bottom: 1px solid #3a4566;
    padding: 4px 8px 4px 0;
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.utc-inspector-table td {
    padding: 6px 8px 6px 0;
    vertical-align: top;
    color: #e8ecf3;
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}
.utc-inspector-table tr:last-child td { border-bottom: none; }
.utc-inspector-table code {
    font-size: 0.9rem;
    background: rgba(255, 255, 255, 0.08);
    padding: 1px 5px;
    border-radius: 3px;
    color: #ffd793;
}
.utc-inspector-table em { color: #9ba4b8; font-style: italic; }
.utc-inspector-table a { color: #6db1ff; text-decoration: none; font-weight: 600; }
.utc-inspector-table a:hover { color: #93c5ff; text-decoration: underline; }
.utc-inspector-popup .badge.bg-secondary { background: #495467 !important; color: #f0f3fa; font-weight: 500; }
.utc-inspector-popup .text-muted { color: #9ba4b8 !important; }
.utc-inspector-popup .text-danger { color: #ff8a8a !important; }

/* --- Map loading overlay (RouteMap.razor) -------------------------------
   The wrapper exists solely to give .planner-map-loading an absolute
   positioning context. We mirror .planner-map's dimensions on the wrapper
   exactly (rather than reducing .planner-map to height:100% inside the
   wrapper) so .planner-map keeps working stand-alone if any other view
   ever uses it without the wrapper. */
.planner-map-wrapper {
    position: relative;
    width: 100%;
    height: 100%;
}

.planner-map-loading {
    position: absolute;
    inset: 0;
    z-index: 1000;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    background: rgba(255, 255, 255, 0.85);
    /* Click-through: Leaflet has nothing actionable underneath us during
       the canal-layer fetch, but a stray scroll/drag shouldn't be eaten
       by the overlay either. backdrop-filter is the visual cherry — older
       browsers gracefully ignore it. */
    pointer-events: none;
    backdrop-filter: blur(2px);
}

.planner-map-loading-text {
    color: var(--utc-muted, #6c757d);
    font-size: 0.9rem;
    font-weight: 500;
}

/* ========================================================================
   Responsive layout — Foundation
   Breakpoints follow Bootstrap 5 defaults so the existing grid utilities
   work without redefining sizes:
     < 768px      Mobile  — sidebar becomes off-canvas drawer
     768–1199px   Tablet  — sidebar defaults to icon-rail; tap to expand
     ≥ 1200px    Desktop — unchanged from existing layout

   `.collapsed` on .utc-shell keeps its existing meaning on desktop (icon-
   rail) but the tablet media query inverts the cascade so the default is
   already rail-mode. `.drawer-open` is a new class used only on mobile.
   ======================================================================== */

/* The mobile backdrop element always renders; visibility + pointer-events
   are gated by the .drawer-open class within the mobile media query. */
.utc-mobile-backdrop {
    display: none;
}

/* ----- Tablet ----- */
@media (min-width: 768px) and (max-width: 1199.98px) {
    .utc-shell {
        /* Default: rail mode (inverts the desktop default) */
        grid-template-columns: var(--utc-sidebar-width-collapsed) 1fr;
    }
    .utc-shell.collapsed {
        /* Toggled: full sidebar */
        grid-template-columns: var(--utc-sidebar-width) 1fr;
    }

    /* Hide labels by default (rail mode); show when expanded */
    .utc-shell .utc-sidebar-section,
    .utc-shell .utc-sidebar-nav .utc-nav-link span,
    .utc-shell .utc-sidebar-brand span {
        display: none;
    }
    .utc-shell.collapsed .utc-sidebar-section,
    .utc-shell.collapsed .utc-sidebar-nav .utc-nav-link span,
    .utc-shell.collapsed .utc-sidebar-brand span {
        display: inline;
        visibility: visible;
    }
}

/* ----- Mobile ----- */
@media (max-width: 767.98px) {
    .utc-shell {
        /* Single column — topbar + content + footer; sidebar overlays as drawer */
        grid-template-columns: 1fr;
        grid-template-rows: var(--utc-topbar-height) 1fr var(--utc-footer-height);
        grid-template-areas:
            "topbar"
            "content"
            "footer";
    }

    .utc-sidebar {
        position: fixed;
        top: 0;
        left: 0;
        bottom: 0;
        width: var(--utc-sidebar-width);
        z-index: 1040;
        transform: translateX(-100%);
        transition: transform 200ms ease;
        box-shadow: none;
    }
    .utc-shell.drawer-open .utc-sidebar {
        transform: translateX(0);
        box-shadow: 0 0 24px rgba(0, 0, 0, 0.45);
    }
    /* Sidebar always shows full labels in the drawer — rail mode doesn't
       make sense for a slide-in panel that the user explicitly opened. */
    .utc-shell .utc-sidebar-section,
    .utc-shell .utc-sidebar-nav .utc-nav-link span,
    .utc-shell .utc-sidebar-brand span {
        display: inline;
        visibility: visible;
    }

    .utc-mobile-backdrop {
        display: block;
        position: fixed;
        inset: 0;
        background: rgba(0, 0, 0, 0.45);
        z-index: 1030;
        opacity: 0;
        pointer-events: none;
        transition: opacity 200ms ease;
    }
    .utc-shell.drawer-open .utc-mobile-backdrop {
        opacity: 1;
        pointer-events: auto;
    }

    /* Touch targets: the hamburger sits at the top-left and must hit the
       44px Apple / Material minimum on phones. */
    .utc-topbar {
        padding: 0 0.5rem;
    }
    .utc-topbar .utc-sidebar-toggle {
        font-size: 1.5rem;
        padding: 0.5rem;
        min-width: 44px;
        min-height: 44px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }
    .utc-topbar .utc-page-title {
        font-size: 1rem;
        margin: 0 0.25rem;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        min-width: 0;
    }

    /* Tighten content padding so cards aren't squashed by the gutter. */
    .utc-content {
        padding: 0.75rem;
    }

    /* ----- Footer: absolute-positioned on mobile -----
       Belt-and-braces: even if the shell grid is in some weird transitional
       state (eg. Android Chrome with a stale cached desktop CSS, or a
       device that reports its viewport just over the breakpoint), pinning
       the footer to the bottom of the shell stops it being squeezed beside
       the sidebar column. The shell already has `position: relative` by
       virtue of being the grid container we're anchoring to. */
    .utc-shell {
        position: relative;
    }
    .utc-footer {
        position: absolute;
        left: 0;
        right: 0;
        bottom: 0;
        height: var(--utc-footer-height);
        z-index: 100;
        width: 100%;
    }
    /* Tighter footer gutter on mobile - 1rem felt cramped at 360px */
    .utc-footer-inner {
        padding: 0 0.75rem;
    }

    /* ----- Planner: bottom-sheet pattern -----
       Map fills the viewport; the form/results panel slides up from the
       bottom over the map. Tap the handle to toggle. The collapsed sheet
       still shows the handle + a one-line summary so the user knows what
       state they're in. */
    .utc-content--flush.planner-layout,
    .utc-content--flush .planner-layout {
        /* Defensive: when Planner sets contentFlush, .utc-content already
           strips its padding (see desktop rules). On mobile the layout
           becomes single-column with the sheet floating above. */
        position: relative;
    }
    .planner-layout {
        grid-template-columns: 1fr;
        position: relative;
    }
    .planner-panel {
        position: absolute;
        left: 0;
        right: 0;
        bottom: 0;
        /* 78% of planner-layout (not 78vh) - on Edge Android the bottom
           URL bar shrinks the planner area enough that 78vh was taller
           than the visible space, leaving no map strip above the sheet
           and letting Leaflet's top controls overlap the sheet handle. */
        max-height: 78%;
        /* Above Leaflet's controls (.leaflet-top has z-index 1000) so the
           zoom buttons and on-map legend don't punch through the sheet
           when it's expanded. Stays below the mobile drawer (1040) and
           its backdrop (1030). */
        z-index: 1010;
        border-right: 0;
        border-top: 1px solid var(--utc-card-border);
        border-radius: 14px 14px 0 0;
        box-shadow: 0 -6px 20px rgba(0, 0, 0, 0.25);
        padding-top: 0;
        transition: transform 240ms ease;
    }
    /* Collapsed: slide down so just the handle row (~56px) stays above
       the footer. translateY uses calc so it auto-adapts when the sheet's
       expanded height changes (long results vs short form). */
    .planner-panel.sheet-collapsed {
        transform: translateY(calc(100% - 56px));
    }

    .planner-sheet-handle {
        display: flex;
        align-items: center;
        gap: 0.6rem;
        padding: 0.65rem 1rem;
        cursor: pointer;
        position: sticky;
        top: 0;
        z-index: 2;
        background: var(--utc-card-bg);
        border-radius: 14px 14px 0 0;
        user-select: none;
        min-height: 44px;
    }
    .planner-sheet-grab {
        flex: 0 0 auto;
        width: 40px;
        height: 4px;
        border-radius: 2px;
        background: var(--utc-muted);
        opacity: 0.55;
    }
    .planner-sheet-summary {
        flex: 1 1 auto;
        font-size: 0.85rem;
        color: var(--utc-content-fg);
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    /* When expanded, centre the grab and hide the summary — the form below
       is already telling the user what state they're in. */
    .planner-panel:not(.sheet-collapsed) .planner-sheet-handle {
        justify-content: center;
    }
    .planner-panel:not(.sheet-collapsed) .planner-sheet-summary {
        display: none;
    }

    /* ----- Tables → card list -----
       Opt-in via `.utc-stack-table` on the <table>. On mobile each row
       becomes a card; each <td> renders as a label/value pair using its
       data-label attribute. Cells with no label (data-label="") just show
       their contents — useful for actions cells. */
    .utc-stack-table thead {
        display: none;
    }
    .utc-stack-table,
    .utc-stack-table tbody,
    .utc-stack-table tr {
        display: block;
        width: 100%;
    }
    .utc-stack-table tr {
        background: var(--utc-card-bg);
        border: 1px solid var(--utc-card-border);
        border-radius: 8px;
        padding: 0.5rem 0.75rem;
        margin-bottom: 0.5rem;
    }
    /* Active-row highlight (used by MyBoat) — keep the Bootstrap colour
       so the active card is visually obvious in the stack. */
    .utc-stack-table tr.table-active {
        outline: 2px solid var(--utc-sidebar-active-bg);
        outline-offset: -2px;
    }
    .utc-stack-table td {
        display: flex;
        justify-content: space-between;
        align-items: center;
        gap: 0.75rem;
        border: none;
        padding: 0.2rem 0;
        text-align: left;
        min-width: 0;
    }
    .utc-stack-table td::before {
        content: attr(data-label);
        font-weight: 600;
        font-size: 0.7rem;
        color: var(--utc-muted);
        text-transform: uppercase;
        letter-spacing: 0.03em;
        flex: 0 0 auto;
    }
    /* Opt-out: an empty data-label suppresses the prefix entirely. Used
       for action-cells where the buttons speak for themselves. */
    .utc-stack-table td[data-label=""]::before {
        content: none;
    }
    .utc-stack-table td[data-label=""] {
        justify-content: flex-end;
        padding-top: 0.4rem;
        border-top: 1px solid var(--utc-card-border);
        margin-top: 0.3rem;
    }

    /* ----- Route alternatives: horizontal scroll strip -----
       The vertical chip stack eats valuable bottom-sheet height. On mobile
       they slide horizontally instead so the user can swipe through the
       options without growing the sheet. */
    .cp-alts-list {
        flex-direction: row;
        overflow-x: auto;
        overflow-y: hidden;
        gap: 0.5rem;
        padding-bottom: 0.35rem;
        scroll-snap-type: x mandatory;
        -webkit-overflow-scrolling: touch;
    }
    .cp-alts-chip {
        flex: 0 0 auto;
        min-width: 150px;
        scroll-snap-align: start;
    }

    /* ----- Leaflet zoom buttons: enlarged for touch -----
       Defaults are 30px squares which are below the 44px target. Bumping
       to 40px keeps them visually balanced with the other map controls
       (canal/POI legend chips) while being a comfortable tap. */
    .leaflet-control-zoom a.leaflet-control-zoom-in,
    .leaflet-control-zoom a.leaflet-control-zoom-out {
        width: 40px;
        height: 40px;
        line-height: 40px;
        font-size: 22px;
    }

    /* Tap-feedback for POI pins. Hover doesn't fire reliably on touch,
       so :active gives a brief lift confirming the tap was registered. */
    .utc-poi-pin:active {
        transform: scale(1.15);
    }
}
