/* ============================================================
   solver-map.css  --  Map infrastructure styles for SolverTech.MapLibre.Blazor
   Extracted from timepoint-analysis app.css.
   ============================================================ */

/* Custom properties are all --solver-map-* prefixed so that linking this
   stylesheet can never clobber a consumer's same-named variables. They stay on
   :root rather than on .solver-map-wrapper because some library-owned elements
   live outside the wrapper: .valhalla-minimap is appended to document.body by
   solver-map.js, so a wrapper-scoped variable would not reach it.
   This stylesheet deliberately sets NO html/body rules -- page font, margin and
   height are the host app's responsibility. */

/* HOST-EMITTED vs LIBRARY-EMITTED SELECTORS -- read before adding a rule.
   `.solver-map-wrapper` and `.solver-map-container` are rendered by Map.razor, i.e. by ONE host.
   A WebView2 bootstrap (webview-host/map.html) or a hand-rolled page emits neither. So a visual
   rule keyed only on those classes silently does nothing outside Blazor -- that is the shape of
   every bug in this family so far (attribution offset, layers panel, zoom readout, font).
   Rule of thumb: a visual declaration must hang off an element solver-map.js itself creates
   (.solver-map-controls, .solver-map-zoom-row, .solver-map-*-btn, .valhalla-*, .vt-*) or off a
   `.maplibregl-map:has(> .solver-map-…)` twin. Keep the `.solver-map-wrapper` selectors only as
   back-compat alternatives alongside such a twin, or for genuinely host-sizing concerns. */
:root {
    /* The library's own typography, in one place. Every library-emitted root repeats it rather
       than relying on inheritance from a host wrapper, so a literal stack would be duplicated
       across a dozen rules. */
    --solver-map-font: system-ui, -apple-system, sans-serif;
    --solver-map-z-panel: 1000;
    --solver-map-z-panel-above: 1001;
    --solver-map-z-overlay: 2000;
    --solver-map-z-minimap: 3000;
    --solver-map-color-dark-text: #1e293b;
    --solver-map-color-muted-text: #475569;
    --solver-map-color-label: #64748b;
    --solver-map-color-faint: #94a3b8;
    --solver-map-color-surface: rgba(255, 255, 255, 0.95);
    --solver-map-color-border: #e2e8f0;
    --solver-map-color-border-strong: #cbd5e1;
    --solver-map-panel-radius: 8px;
    --solver-map-panel-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}

/* ---- Map wrapper ---- */

/* Fills whatever the host element is, instead of assuming it owns the viewport,
   so several maps can sit side by side or next to a sidebar. The host must give
   the parent a resolved height (e.g. height:100vh, or a flex/grid track);
   min-height is only a safety net so a map dropped into an auto-height parent
   still renders something visible instead of collapsing to 0px.
   font-family is declared here rather than on html/body so the library's own
   controls keep their designed typography without restyling the host. Everything
   inside this element is library-owned (Map.razor renders ChildContent OUTSIDE
   the wrapper), and MapLibre popups mount into map.getContainer(), which is the
   .solver-map-container child -- so the locate popup inherits it too.
   Kept for back-compat: since 1.2 the font and the sizing safety net are ALSO declared on the
   library-emitted roots below, so they hold in a host that never renders this element. */
.solver-map-wrapper {
    position: relative;
    width: 100%;
    height: 100%;
    min-height: 300px;
    overflow: hidden;
    font-family: var(--solver-map-font);
}

/* ---- Map container ---- */

.solver-map-container {
    width: 100%;
    height: 100%;
}

/* The library font, for the map subtree MapLibre owns rather than solver-map.js: the locate
   popup's chrome, the compact attribution, MapLibre's own controls. maplibre-gl.css declares
   `font: 12px/20px Helvetica Neue, Arial, …` on .maplibregl-map, which beats any inheritance from
   a host wrapper, so the only way to reach those is a rule on the map element itself. Keyed off
   the two roots solver-map.js appends into map.getContainer() -- the same `:has()` twin technique
   the attribution offset uses -- so it holds in every host by construction and stays inert for a
   plain MapLibre map that merely links this stylesheet.

   Sizing safety net (was .solver-map-wrapper-only until 1.2): min-height keeps a map dropped into
   an auto-height container from collapsing to 0px, and overflow:hidden clips the top-left/top-right
   styles flyout to the map instead of letting it spill onto the host page. Blazor is unaffected --
   .solver-map-wrapper already imposes both and .solver-map-container is height:100% inside it. */
.maplibregl-map:has(> .solver-map-controls),
.maplibregl-map:has(> .solver-map-zoom-row) {
    font-family: var(--solver-map-font);
    min-height: 300px;
    overflow: hidden;
}

/* ---- Zoom row (buttons + live zoom readout) ---- */

/* One vertical column, top-to-bottom `+`, the readout, `−`, anchored bottom-right directly above the
   compact ⓘ attribution and directly below the layers control button, so the whole bottom-right
   corner reads as ONE continuous stack: ⓘ, −, readout, +, layers. solver-map.js appends it straight
   into map.getContainer(), so this rule is keyed off nothing the host renders and holds in every
   host — Blazor wrapper, WebView2 bootstrap or a hand-rolled page — by construction.

   right:10px lines its right edge up with the layers button's edge (both at right:10px); bottom:40px
   = the ⓘ's 10px margin + its 24px collapsed height + a 6px gap, matching the gap the controls stack
   uses internally. The column itself is exactly as wide as one icon button (32px, see
   .solver-map-icon-btn) so every element in the stack shares one width. pointer-events are off on
   the column and back on for its children, so dragging the map across the readout still pans instead
   of dead-zoning a strip above the attribution. */
.solver-map-zoom-row {
    position: absolute;
    bottom: 40px;
    right: 10px;
    width: 32px;
    font-family: var(--solver-map-font);
    z-index: var(--solver-map-z-panel);
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
    pointer-events: none;
}

.solver-map-zoom-row .solver-map-icon-btn {
    pointer-events: auto;
    flex-shrink: 0;
    font-size: 18px;
    font-weight: 600;
    line-height: 1;
    color: var(--solver-map-color-dark-text);
}

/* Reset-view button (top of the column): solver-map.js sets `hidden` while the map faces north
   and lies flat, and the icon button's display:flex would otherwise override the attribute. The
   needle turns with the bearing (inline transform) so the red tip points north on screen. */
.solver-map-zoom-row .solver-map-reset-view[hidden] {
    display: none;
}

.solver-map-reset-view-needle {
    display: block;
    transition: transform 0.1s linear;
}

/* Same box as the icon buttons above/below it (32x32, see .solver-map-icon-btn) so the column has
   one uniform width and the readout looks like a third button in the stack rather than a wider bar
   wedged between two narrower ones. Tabular figures keep the digits from jittering horizontally as
   the value changes (9.0 -> 14.5); the font is a step down from the row's default 13px and the text
   drops its space ('Z10.0' not 'Z 10.0') because at 32px wide there is no room for either. */
.solver-map-zoom-value {
    box-sizing: border-box;
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 11px;
    font-weight: 600;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    color: var(--solver-map-color-dark-text);
    background: rgba(255, 255, 255, 0.92);
    border-radius: 4px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
}

/* ---- Layer controls (anchored to one of four corners) ---- */

.solver-map-controls {
    position: absolute;
    font-family: var(--solver-map-font);
    z-index: var(--solver-map-z-panel);
    display: flex;
    flex-direction: column;
    gap: 6px;
}

/* Corner anchors — default is bottom-right to match the library's original behavior. */
.solver-map-controls--bottom-right {
    bottom: 36px;
    right: 10px;
    align-items: flex-end;
}

.solver-map-controls--bottom-left {
    bottom: 36px;
    left: 10px;
    align-items: flex-start;
}

/* The bottom-right stack shares its column with the zoom row, so it has to start above it whenever
   one is present: 40px (the row's own offset) + 108px (the column's own height — three 32px
   elements plus two 6px gaps between them) + 6px gap = 154px, the same gap the stack uses
   everywhere else, so the layers button sits directly on top of the `+` button. Keyed off the row
   element solver-map.js appends into the map container, so a host that opts the row out with
   config.navigationControl === false keeps the tighter 36px offset with no extra config. */
.maplibregl-map:has(> .solver-map-zoom-row) > .solver-map-controls--bottom-right {
    bottom: 154px;
}

/* While the reset-view button is shown the column is one element taller (32px + 6px gap), and the
   stack above it moves up by the same 38px so the layers button never covers the needle. */
.maplibregl-map:has(> .solver-map-zoom-row > .solver-map-reset-view:not([hidden])) > .solver-map-controls--bottom-right {
    bottom: 192px;
}

.solver-map-controls--top-right {
    top: 10px;
    right: 10px;
    align-items: flex-end;
}

.solver-map-controls--top-left {
    top: 10px;
    left: 10px;
    align-items: flex-start;
}

.solver-map-layers-wrap {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.solver-map-controls--bottom-right .solver-map-layers-wrap,
.solver-map-controls--top-right .solver-map-layers-wrap {
    align-items: flex-end;
}

.solver-map-controls--bottom-left .solver-map-layers-wrap,
.solver-map-controls--top-left .solver-map-layers-wrap {
    align-items: flex-start;
}

/* Expanded panel: vertical anchor flips with the corner so it always grows away from the map edge. */
.solver-map-layers-panel {
    position: absolute;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.solver-map-controls--bottom-right .solver-map-layers-panel {
    bottom: calc(100% + 6px);
    right: 0;
}

.solver-map-controls--bottom-left .solver-map-layers-panel {
    bottom: calc(100% + 6px);
    left: 0;
}

.solver-map-controls--top-right .solver-map-layers-panel {
    top: calc(100% + 6px);
    right: 0;
}

.solver-map-controls--top-left .solver-map-layers-panel {
    top: calc(100% + 6px);
    left: 0;
}

/* font-family is explicit, not inherited: a <button> does not inherit font-family from its
   ancestors, it takes the UA form-control default (Arial), so without this the icon fallback text
   rendered in Arial next to system-ui labels in EVERY host, wrapper or not. */
.solver-map-icon-btn {
    width: 32px;
    height: 32px;
    padding: 4px;
    font-family: var(--solver-map-font);
    background: #fff;
    border: 1px solid rgba(0, 0, 0, 0.08);
    border-radius: 4px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    outline: none;
    transition: background 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}

.solver-map-icon-btn:hover {
    background: #f5f7fa;
}

.solver-map-icon-btn:focus:focus-visible {
    box-shadow: 0 0 2px 2px #0096ff;
}

.solver-map-icon-btn--active {
    background: #e7f1ff;
    border-color: #0096ff;
    box-shadow: 0 0 2px 2px #0096ff;
}

.solver-map-icon-btn--active img,
.solver-map-icon-btn--active svg {
    filter: drop-shadow(0 0 1px rgba(0, 150, 255, 0.8));
}

/* Constrain control icons to the button box. The icons are rendered as
   <img src="*.svg"> and the source SVGs carry a viewBox but no intrinsic
   width/height. Safari (WebKit) then sizes the <img> to the viewBox
   dimensions (e.g. layers.svg -> 122.88x111.96px), overflowing the 32px
   button; Chrome/Firefox clamp it. width/height + object-fit pin the icon
   in every engine, so consumers no longer need a per-app workaround. */
.solver-map-icon-btn img,
.solver-map-icon-btn svg {
    width: 100%;
    height: 100%;
    object-fit: contain;
    display: block;
}

/* Text fallback inside a custom layer button that has no icon (MapLayerDescriptor.Text, or the
   first letter of its title). It has to fill the same box the icons do, otherwise a one-character
   label renders at whatever size the host page's font stack happens to give it - the class was
   emitted by the old Blazor panel too but never had a rule of its own. */
.solver-map-icon-btn-fallback {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
    font-weight: 600;
    line-height: 1;
    color: var(--solver-map-color-dark-text);
    text-transform: uppercase;
    overflow: hidden;
}

/* ---- MapLibre compact attribution button ---- */

/* solver-map.js adds the AttributionControl bottom-right, right below the layers stack.
   MapLibre's collapsed compact button is 24px wide with a 10px margin while the layers
   button above it is 32px wide at right:10px, so the ⓘ sat 4px off the layers button's
   axis. 14px = 10px + (32 - 24) / 2 puts both centers on the same vertical line. The
   margin is kept when the attribution is expanded so the box doesn't jump on toggle;
   the bottom-left mirror covers a consumer that re-adds the control on the left.

   The rule must not hang off .solver-map-wrapper alone: that class is emitted by the Blazor
   package's Map.razor, so a host that mounts solver-map.js on its own page - the WebView2
   bootstrap in webview-host/map.html, or any native host doing the same - never matched it and
   its ⓘ kept MapLibre's default 10px margin, landing 4px right of the layers button's axis
   (measured: layers centre 1238, ⓘ centre 1242). The alignment is a property of the map that
   owns the control, not of the page around it, so it is also keyed off the control root that
   solver-map.js appends into map.getContainer() - present in every host, by construction.
   The .solver-map-wrapper rules stay for the Blazor case with no layers control, where they
   have applied since 1.2 and there is no button to align against either way. */
.solver-map-wrapper .maplibregl-ctrl-bottom-right .maplibregl-ctrl-attrib.maplibregl-compact,
.maplibregl-map:has(> .solver-map-controls--bottom-right) .maplibregl-ctrl-bottom-right .maplibregl-ctrl-attrib.maplibregl-compact,
.maplibregl-map:has(> .solver-map-zoom-row) .maplibregl-ctrl-bottom-right .maplibregl-ctrl-attrib.maplibregl-compact {
    margin: 0 14px 10px 0;
}

.solver-map-wrapper .maplibregl-ctrl-bottom-left .maplibregl-ctrl-attrib.maplibregl-compact,
.maplibregl-map:has(> .solver-map-controls--bottom-left) .maplibregl-ctrl-bottom-left .maplibregl-ctrl-attrib.maplibregl-compact {
    margin: 0 0 10px 14px;
}

/* ---- Style picker flyout (popup card anchored to the style button) ---- */

.solver-map-style-wrap {
    position: relative;
    display: flex;
}

.solver-map-styles-flyout {
    position: absolute;
    top: 0;
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 2px;
    padding: 4px 6px;
    background: var(--solver-map-color-surface);
    border: 1px solid var(--solver-map-color-border);
    border-radius: var(--solver-map-panel-radius);
    box-shadow: var(--solver-map-panel-shadow);
    backdrop-filter: blur(4px);
    animation: solver-map-flyout-in 0.12s ease-out;
    white-space: nowrap;
}

/* On right-anchored corners the flyout opens to the left of the button. */
.solver-map-controls--bottom-right .solver-map-styles-flyout,
.solver-map-controls--top-right .solver-map-styles-flyout {
    right: calc(100% + 6px);
}

/* On left-anchored corners it opens to the right so it stays on-screen. */
.solver-map-controls--bottom-left .solver-map-styles-flyout,
.solver-map-controls--top-left .solver-map-styles-flyout {
    left: calc(100% + 6px);
}

@keyframes solver-map-flyout-in {
    from { opacity: 0; transform: translateX(4px); }
    to { opacity: 1; transform: translateX(0); }
}

.solver-map-controls--bottom-left .solver-map-styles-flyout,
.solver-map-controls--top-left .solver-map-styles-flyout {
    animation-name: solver-map-flyout-in-left;
}

@keyframes solver-map-flyout-in-left {
    from { opacity: 0; transform: translateX(-4px); }
    to { opacity: 1; transform: translateX(0); }
}

/* font-family for the same reason as .solver-map-icon-btn: <button> does not inherit it. */
.solver-map-style-btn {
    padding: 4px 8px;
    font-family: var(--solver-map-font);
    background: transparent;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    font-size: 12px;
    font-weight: 600;
    color: var(--solver-map-color-dark-text);
    transition: text-shadow 0.15s ease, color 0.15s ease;
    white-space: nowrap;
    line-height: 1;
}

.solver-map-style-btn:hover {
    text-shadow: 0 0 4px rgba(0, 150, 255, 0.9), 0 0 1px rgba(0, 150, 255, 0.9);
}

.solver-map-style-btn--active {
    color: #0066b3;
    text-shadow: 0 0 4px rgba(0, 150, 255, 0.9), 0 0 1px rgba(0, 150, 255, 0.9);
}

.solver-map-style-btn:focus-visible {
    outline: none;
    text-shadow: 0 0 4px rgba(0, 150, 255, 0.9), 0 0 1px rgba(0, 150, 255, 0.9);
}

/* ---- Toggle ---- */

.solver-map-toggle {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    color: var(--solver-map-color-muted-text);
    cursor: pointer;
    padding: 1px 0;
}

/* ---- Color dot ---- */

.solver-map-color {
    display: inline-block;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    flex-shrink: 0;
}

/* ---- Divider ---- */

.solver-map-divider {
    border-top: 1px solid var(--solver-map-color-border);
    margin: 4px 0;
}

/* ---- Subtitle ---- */

.solver-map-subtitle {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--solver-map-color-faint);
    margin: 4px 0 4px 0;
}

/* ---- Valhalla split popup ---- */

/* The popup root solver-map.js sets as the popup HTML. It re-declares the font for the same reason
   .vt-tree and .valhalla-minimap do: the popup mounts inside .maplibregl-map, whose vendored
   `font:` shorthand wins over any inheritance, and .valhalla-split-hdr sits outside .vt-tree -- so
   without this the two columns of one popup rendered in two different fonts. */
.valhalla-split {
    display: flex;
    gap: 0;
    font-family: var(--solver-map-font);
    font-size: 12px;
    color: var(--solver-map-color-dark-text);
    min-width: 500px;
}

.valhalla-split-col {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.valhalla-split-hdr {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--solver-map-color-label);
    padding-bottom: 6px;
    border-bottom: 1px solid var(--solver-map-color-border);
    margin-bottom: 6px;
}

.valhalla-split-body {
    max-height: 350px;
    overflow-y: auto;
    padding-right: 6px;
}

.valhalla-split-divider {
    width: 1px;
    background: var(--solver-map-color-border);
    margin: 0 10px;
    flex-shrink: 0;
}

/* ---- Tree viewer ---- */

.vt-tree {
    font-size: 11px;
    font-family: var(--solver-map-font);
    line-height: 1.6;
}

.vt-row {
    white-space: nowrap;
}

.vt-key {
    color: var(--solver-map-color-label);
    font-weight: 600;
}

.vt-val {
    color: var(--solver-map-color-dark-text);
}

.vt-null {
    color: var(--solver-map-color-faint);
    font-style: italic;
}

.vt-toggle {
    cursor: pointer;
    user-select: none;
}

.vt-toggle:hover {
    background: rgba(0, 0, 0, 0.04);
    border-radius: 3px;
}

.vt-btn {
    display: inline-block;
    width: 14px;
    height: 14px;
    line-height: 14px;
    text-align: center;
    font-size: 11px;
    font-weight: 700;
    color: var(--solver-map-color-muted-text);
    background: #f1f5f9;
    border: 1px solid var(--solver-map-color-border-strong);
    border-radius: 3px;
    margin-right: 4px;
    vertical-align: middle;
}

.vt-children {
    padding-left: 16px;
    border-left: 1px solid var(--solver-map-color-border);
    margin-left: 6px;
}

.vt-node {
    margin: 1px 0;
}

.vt-edge-wrap {
    border-radius: 4px;
    transition: background 0.15s;
}

.vt-edge-wrap:hover {
    background: rgba(37, 99, 235, 0.06);
}

/* ---- Minimap overlay ---- */

/* Repeats font-family because solver-map.js appends this element to document.body,
   outside .solver-map-wrapper's inheritance chain. */
.valhalla-minimap {
    display: none;
    position: fixed;
    font-family: var(--solver-map-font);
    top: 50%;
    right: 16px;
    transform: translateY(-50%);
    width: 400px;
    height: 400px;
    z-index: var(--solver-map-z-minimap);
    border-radius: var(--solver-map-panel-radius);
    border: 2px solid #2563eb;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
    background: #f8fafc;
    pointer-events: none;
}

/* ---- Ctrl-lasso menu --------------------------------------------------------------------- */
/* Positioned by solver-map.js at the drag's release point, inside the map container so it clips
   with the map. Same surface, border, radius and font as the layers panel. */
.solver-map-lasso-menu {
    position: absolute;
    z-index: var(--solver-map-z-panel-above);
    min-width: 200px;
    max-width: 280px;
    padding: 6px;
    background: var(--solver-map-color-surface);
    border: 1px solid var(--solver-map-color-border);
    border-radius: var(--solver-map-panel-radius);
    box-shadow: var(--solver-map-panel-shadow);
    font-family: var(--solver-map-font);
    font-size: 13px;
    color: var(--solver-map-color-dark-text);
}

.solver-map-override-tooltip {
    position: absolute;
    display: none;
    z-index: var(--solver-map-z-panel-above);
    max-width: 260px;
    padding: 5px 8px;
    background: var(--solver-map-color-surface);
    border: 1px solid var(--solver-map-color-border);
    border-radius: var(--solver-map-panel-radius);
    box-shadow: var(--solver-map-panel-shadow);
    font-family: var(--solver-map-font);
    font-size: 12px;
    line-height: 1.35;
    color: var(--solver-map-color-dark-text);
    pointer-events: none;
    white-space: nowrap;
}

.solver-map-override-tooltip-title {
    font-weight: 600;
    color: var(--solver-map-color-muted-text);
    margin-bottom: 2px;
}

.solver-map-override-tooltip-profile {
    padding-left: 6px;
}

/* Over a road the tooltip answers per profile: does THIS road get blocked for it. The mark carries
   the colour and the row's text carries the emphasis, so a glance reads the column of marks and a
   second look reads the names. "unknown" is the profile whose travel type the host left empty - it
   was never probed, so neither a tick nor a cross would be true, and it borrows the same grey the
   circle uses for "we could not ask". */
.solver-map-override-tooltip-mark {
    display: inline-block;
    width: 1em;
    font-weight: 600;
}

/* Only the blocked rows carry a mark, and it is the same red diagonal cross the pin and the
   crossed-out road use, so one symbol means one thing across the whole feature: not through here. An
   unblocked row is muted and unmarked - deliberately making no claim about whether that vehicle could
   drive there, only that this avoid location is not what would stop it. The empty mark keeps its
   width so the names stay in one column. */
.solver-map-override-tooltip-profile-unaffected {
    color: var(--solver-map-color-muted-text);
}

.solver-map-override-tooltip-profile-avoided .solver-map-override-tooltip-mark {
    color: #dc2626;
}

.solver-map-override-tooltip-profile-unknown {
    color: var(--solver-map-color-muted-text);
}

.solver-map-override-tooltip-profile-unknown .solver-map-override-tooltip-mark {
    color: var(--solver-map-color-faint);
}

/* Route comparison table inside the override tooltip: swatch, profile, distance, time. The hovered
   route's row is bold so the line under the pointer stands out of the comparison. */
.solver-map-route-table {
    border-collapse: collapse;
    margin-top: 3px;
}

.solver-map-route-row td {
    padding: 1px 6px 1px 0;
    vertical-align: middle;
}

.solver-map-route-row-hovered td {
    font-weight: 600;
}

.solver-map-route-swatch {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    border: 1px solid var(--solver-map-color-border-strong);
}

.solver-map-route-num {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.solver-map-lasso-title {
    padding: 4px 8px 6px;
    font-weight: 600;
    color: var(--solver-map-color-muted-text);
}

.solver-map-lasso-item,
.solver-map-lasso-confirm,
.solver-map-lasso-cancel {
    display: block;
    width: 100%;
    padding: 6px 8px;
    border: 0;
    border-radius: 6px;
    background: transparent;
    text-align: left;
    font: inherit;
    color: inherit;
    cursor: pointer;
}

.solver-map-lasso-item:hover,
.solver-map-lasso-cancel:hover {
    background: var(--solver-map-color-border);
}

.solver-map-lasso-profiles {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 0 4px 6px;
}

.solver-map-lasso-profile {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px;
    cursor: pointer;
}

/* Departure row of the route menu: label above a native datetime-local input, same indent as the
   profile rows so the menu reads as one list. */
.solver-map-lasso-departure {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin: 6px 0 4px;
    font-size: 12px;
    color: var(--solver-map-color-muted-text);
}

.solver-map-lasso-departure input {
    font-family: var(--solver-map-font);
    font-size: 12px;
    padding: 2px 4px;
    border: 1px solid var(--solver-map-color-border-strong);
    border-radius: 4px;
    color: var(--solver-map-color-dark-text);
}

/* the weekday of the picked departure, under the field; empty while the field is empty */
.solver-map-lasso-weekday {
    min-height: 14px;
    font-size: 11px;
    color: var(--solver-map-color-dark-text);
}

.solver-map-lasso-actions {
    display: flex;
    gap: 6px;
}

.solver-map-lasso-confirm {
    background: var(--solver-map-color-dark-text);
    color: #fff;
    text-align: center;
}

.solver-map-lasso-cancel {
    text-align: center;
}

.solver-map-lasso-confirm:disabled {
    opacity: 0.45;
    cursor: default;
}

/* the profile x direction matrix of the ignore checklist and the ignored restriction popup:
   direction codes as column headers, one row per profile, a box under each header */
.solver-map-lasso-matrix {
    display: grid;
    align-items: center;
    column-gap: 12px;
    row-gap: 2px;
    padding: 0 8px 6px;
}

.solver-map-lasso-matrix-head {
    font-size: 11px;
    color: var(--solver-map-color-dark-text);
    text-align: center;
    padding-bottom: 2px;
}

.solver-map-lasso-matrix-name {
    padding: 4px 0;
    white-space: nowrap;
}

.solver-map-lasso-matrix-cell {
    display: flex;
    justify-content: center;
    padding: 4px 0;
    cursor: pointer;
}

.solver-map-lasso-profile-locked {
    opacity: 0.5;
    cursor: default;
}
