/* ── Theme tokens ─────────────────────────────────────────────────────────────
   `--veloio-brand` was declared only inside `.kb-root`, so Model Builder had it
   and nothing else did. The feature basemap control needs the same navy for its
   active state, and copying the hex would leave two values free to drift apart.
   Declared once here; korridorbygger.css now points its own `--brand` at it. */
:root {
    --veloio-brand: #063545;
}

/*
 * Viewport-responsive base font size.
 * At 1920px → ~17px  (1080p monitor)
 * At 2560px → ~23px  (1440p monitor)
 * At 3840px → capped at 26px  (4K at 100% OS scaling)
 * At 1366px → floored at 13px (laptop)
 *
 * All DMC/Mantine components use rem internally, so they scale
 * automatically when this root size changes.
 */
html {
    font-size: clamp(13px, 0.9vw, 26px);
    --feature-color: #0ea5c8;
    --feature-muted: #dff5fb;
    --feature-bike: #9ff6df;
}

body {
    margin: 0;
    padding: 0;
}

/* ── Feature shell: top bar, sidebar, and sub-menu ───────────────────────────*/
.feature-shell {
    --feature-color: #0ea5c8;
    --feature-muted: #dff5fb;
    --feature-bike: #9ff6df;
}

.top-bar {
    height: 3rem;
    background: var(--feature-color);
    border-bottom: 1px solid color-mix(in srgb, var(--feature-color) 74%, #000);
    display: flex;
    align-items: center;
    flex-shrink: 0;
    position: relative;
    /* Above the welcome/empty-state overlay (1200), below the admin and auth
     * panels (4500/5000) which are meant to cover everything.
     *
     * This value is load-bearing in a way that is easy to miss: `position:
     * relative` + a z-index makes the top bar a STACKING CONTEXT, so the
     * account menu's own `z-index: 2000` is scoped inside it and the whole bar
     * competes with page content at this one number. At 100 the menu dropped
     * behind the welcome overlay — and the O/D empty state tells the customer
     * to open Vejnet, which lives in that menu, so the page pointed at a
     * control it was itself hiding. */
    z-index: 2000;
}

.brand-logo {
    position: relative;
    width: 9.1rem;
    height: 100%;
    display: flex;
    align-items: center;
    padding: 0 0.7rem;
    flex-shrink: 0;
}
.brand-logo-base {
    width: 5.2rem;
    height: auto;
    display: block;
    filter: brightness(0) invert(1);
}
.brand-logo-rider {
    position: absolute;
    left: 0.7rem;
    width: 5.2rem;
    aspect-ratio: 933.03138 / 299.10922;
    background-color: var(--feature-bike);
    -webkit-mask-image: url('/assets/logo-rider.svg');
    mask-image: url('/assets/logo-rider.svg');
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-size: contain;
    mask-size: contain;
    -webkit-mask-position: center;
    mask-position: center;
    pointer-events: none;
}
.active-module-title {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    color: white;
    font-size: 0.98rem;
    font-weight: 700;
    line-height: 1;
    pointer-events: none;
    white-space: nowrap;
}
.top-actions {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    padding: 0 0.7rem;
    gap: 0.55rem;
}
#top-bar .mantine-SegmentedControl-root {
    background: color-mix(in srgb, var(--feature-color) 72%, #000);
}
#top-bar .mantine-SegmentedControl-label {
    color: rgba(255,255,255,0.82);
}
#top-bar .mantine-SegmentedControl-control[data-active] .mantine-SegmentedControl-label,
#top-bar .mantine-SegmentedControl-input:checked + .mantine-SegmentedControl-label {
    color: #102033;
}

.account-menu-wrap {
    position: relative;
}
.account-menu-btn {
    width: 1.8rem;
    height: 1.8rem;
    border-radius: 999px;
    border: 1px solid rgba(255,255,255,0.5);
    background: rgba(255,255,255,0.16);
    color: white;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    cursor: pointer;
}
.account-menu {
    position: absolute;
    top: 2.25rem;
    right: 0;
    width: 14rem;
    background: white;
    color: #172033;
    border: 1px solid #d8dee6;
    border-radius: 8px;
    box-shadow: 0 14px 36px rgba(15, 23, 42, 0.18);
    padding: 0.6rem;
    z-index: 2000;
}
.account-menu-identity {
    font-size: 0.78rem;
    font-weight: 700;
    line-height: 1.3;
    padding-bottom: 0.45rem;
    border-bottom: 1px solid #e6eaf0;
    overflow-wrap: anywhere;
}
.account-menu-identity div + div {
    color: #64748b;
    font-weight: 500;
}
.account-menu-meta {
    font-size: 0.72rem;
    color: #475569;
    line-height: 1.4;
    padding: 0.5rem 0;
}
.account-menu-item {
    width: 100%;
    border: 0;
    background: #f1f5f9;
    color: #172033;
    border-radius: 6px;
    padding: 0.45rem 0.55rem;
    margin-top: 0.25rem;
    font-weight: 650;
    text-align: left;
    cursor: pointer;
}
.account-menu-item:hover {
    background: #e2e8f0;
}

.auth-screen {
    position: fixed;
    inset: 0;
    z-index: 5000;
    align-items: center;
    justify-content: center;
    padding: clamp(1.25rem, 4vw, 3.5rem);
    overflow: auto;
    isolation: isolate;
}
.bootstrap-auth-screen {
    display: flex;
    z-index: 6000;
    opacity: 1;
    transition: opacity 240ms ease;
    /* Mantine installs these baseline rules when Dash mounts.  Keep the
       lightweight login shell on the same metrics from its first paint so
       hydration cannot change its font or resize its 100%-wide controls. */
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif,
        "Apple Color Emoji", "Segoe UI Emoji";
    line-height: 1.55;
}
.bootstrap-auth-screen,
.bootstrap-auth-screen *,
.bootstrap-auth-screen *::before,
.bootstrap-auth-screen *::after {
    box-sizing: border-box;
}
.bootstrap-auth-screen.bootstrap-auth-leaving {
    opacity: 0;
    pointer-events: none;
}
.bootstrap-login-shell {
    display: grid;
}
.bootstrap-field {
    display: block;
    margin-bottom: 0.75rem;
    color: #102d4f;
    font-size: 0.875rem;
    font-weight: 500;
}
.bootstrap-field span {
    display: block;
    margin-bottom: 0.32rem;
}
.bootstrap-field input {
    width: 100%;
    height: 2.25rem;
    border: 1px solid #cfd9e3;
    border-radius: 8px;
    background: white;
    padding: 0 0.75rem;
    color: #102d4f;
    font: inherit;
    line-height: 1.55;
    outline: none;
    transition: border-color 150ms ease, box-shadow 150ms ease;
}
.bootstrap-field input:focus {
    border-color: #20b99d;
    box-shadow: 0 0 0 3px rgba(32, 200, 168, 0.14);
}
.bootstrap-login-card button {
    width: 100%;
    min-height: 2.5rem;
    border: 0;
    border-radius: 8px;
    background: #08254a;
    color: white;
    font-family: inherit;
    font-size: 0.875rem;
    font-weight: 600;
    line-height: 1.55;
    cursor: pointer;
}
.bootstrap-login-card button:hover {
    background: #0d3565;
}
.bootstrap-login-card button:disabled {
    cursor: wait;
    opacity: 0.78;
}
.bootstrap-resume-message {
    display: none;
    color: #5b7087;
    font-size: 0.88rem;
    text-align: center;
}
.bootstrap-auth-resume .bootstrap-login-shell {
    width: min(31rem, calc(100vw - 3rem));
    grid-template-columns: 1fr;
    justify-items: center;
}
.bootstrap-auth-resume .auth-brand-stage {
    align-items: center;
}
.bootstrap-auth-resume .auth-brand-copy,
.bootstrap-auth-resume .bootstrap-login-card {
    display: none;
}
.bootstrap-auth-resume .bootstrap-resume-message {
    display: block;
    margin-top: 0.8rem;
}
.auth-screen::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 0;
    background:
        radial-gradient(circle at 29% 45%, rgba(32, 200, 168, 0.14), transparent 31rem),
        radial-gradient(circle at 82% 12%, rgba(14, 165, 200, 0.08), transparent 24rem),
        linear-gradient(145deg, #f7fafc 0%, #edf4f7 55%, #f5f8fa 100%);
    opacity: 1;
    transition: opacity 280ms ease 180ms;
}
.auth-screen > * {
    position: relative;
    z-index: 1;
}
.auth-screen.auth-screen-leaving::before {
    opacity: 0;
}
.auth-login-shell {
    width: min(64rem, calc(100vw - 3rem));
    grid-template-columns: minmax(0, 1.15fr) minmax(21rem, 24rem);
    align-items: center;
    gap: clamp(2.5rem, 7vw, 7rem);
}
.auth-login-shell.auth-intro-pending {
    visibility: hidden;
}
.auth-login-shell.auth-intro-ready {
    visibility: visible;
}
.auth-brand-stage {
    min-width: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    text-align: center;
}
.auth-hero-logo {
    width: min(100%, 31rem);
    height: auto;
    display: block;
    transform-origin: top left;
    will-change: transform, opacity;
}
.auth-brand-copy {
    margin-top: 1.15rem;
    padding-left: 0;
}
.auth-brand-title {
    color: #5b7087;
    font-size: clamp(1.02rem, 1.6vw, 1.35rem);
    font-weight: 750;
    letter-spacing: -0.015em;
}
.auth-brand-subtitle {
    max-width: 31rem;
    margin: 0.38rem 0 0;
    color: #5b7087;
    font-size: 0.88rem;
    line-height: 1.55;
}
.auth-card {
    width: min(24rem, calc(100vw - 2.5rem));
    background: white;
    border: 1px solid #d8dee6;
    border-radius: 14px;
    box-shadow: 0 18px 44px rgba(15, 23, 42, 0.14);
    padding: 1.6rem;
}
.auth-login-card {
    width: 100%;
    padding: clamp(1.55rem, 3vw, 2rem);
    border-color: rgba(199, 211, 221, 0.9);
    border-radius: 18px;
    box-shadow:
        0 26px 70px rgba(3, 27, 63, 0.13),
        0 2px 8px rgba(3, 27, 63, 0.05);
}
.auth-login-shell.auth-intro-ready .auth-hero-logo {
    animation: auth-hero-arrive 420ms cubic-bezier(.22, .8, .32, 1) both;
}
.auth-login-shell.auth-intro-ready .auth-brand-copy {
    animation: auth-copy-enter 420ms ease both;
}
.auth-login-shell.auth-intro-ready .auth-login-card {
    animation: auth-card-enter 460ms cubic-bezier(.22, .8, .32, 1) both;
}
.auth-login-shell.auth-intro-handoff .auth-hero-logo,
.auth-login-shell.auth-intro-handoff .auth-brand-copy,
.auth-login-shell.auth-intro-handoff .auth-login-card {
    animation: none;
}
.auth-card-eyebrow {
    margin-bottom: 0.5rem;
    color: #20a98f;
    font-size: 0.68rem;
    font-weight: 800;
    letter-spacing: 0.14em;
}
.auth-card-intro {
    margin: -0.55rem 0 1.25rem;
    color: #64748b;
    font-size: 0.83rem;
    line-height: 1.45;
}
.auth-logo {
    width: 6.8rem;
    display: block;
    margin-bottom: 1rem;
}
.auth-card h2 {
    margin: 0 0 1rem;
    font-size: 1.35rem;
    letter-spacing: -0.02em;
    color: #102d4f;
}
.auth-card .mantine-InputWrapper-root {
    margin-bottom: 0.75rem;
}
.auth-login-card .mantine-Input-input {
    border-color: #cfd9e3;
    border-radius: 8px;
    transition: border-color 150ms ease, box-shadow 150ms ease;
}
.auth-login-card .mantine-Input-input:focus {
    border-color: #20b99d;
    box-shadow: 0 0 0 3px rgba(32, 200, 168, 0.14);
}
.auth-login-card .mantine-Button-root {
    min-height: 2.5rem;
    margin-top: 0.2rem;
    border-radius: 8px;
    background: #08254a;
    transition: transform 140ms ease, background-color 140ms ease, box-shadow 140ms ease;
}
.auth-login-card .mantine-Button-root:hover {
    background: #0d3565;
    box-shadow: 0 8px 20px rgba(3, 27, 63, 0.16);
}
.auth-login-card .mantine-Button-root:active {
    transform: translateY(1px);
}
.auth-error {
    min-height: 1.1rem;
    margin-top: 0.65rem;
    color: #b42318;
    font-size: 0.78rem;
}
.auth-info {
    margin: 0.35rem 0 0.85rem;
    color: #475569;
    font-size: 0.78rem;
    line-height: 1.45;
}
.auth-secondary-link {
    display: block;
    margin-top: 0.8rem;
    color: #0b6f67;
    font-size: 0.8rem;
    text-align: center;
    text-decoration: none;
}
.auth-secondary-link:hover {
    text-decoration: underline;
}

.auth-login-shell.auth-leaving .auth-brand-copy {
    animation: auth-content-leave 220ms ease forwards;
}
.auth-login-shell.auth-leaving .auth-login-card {
    animation: auth-card-leave 260ms ease forwards;
    pointer-events: none;
}
.auth-login-shell.auth-leaving .auth-hero-logo {
    position: relative;
    z-index: 2;
    animation: auth-logo-dock 560ms cubic-bezier(.55, 0, .2, 1) forwards;
}

@keyframes auth-hero-arrive {
    from { opacity: 0; transform: translateY(8px) scale(.975); }
    to { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes auth-copy-enter {
    from { opacity: 0; transform: translateY(8px); }
    to { opacity: 1; transform: translateY(0); }
}
@keyframes auth-card-enter {
    from { opacity: 0; transform: translateY(16px); }
    to { opacity: 1; transform: translateY(0); }
}
@keyframes auth-content-leave {
    to { opacity: 0; transform: translateY(-5px); }
}
@keyframes auth-card-leave {
    to { opacity: 0; transform: translateY(10px); }
}
@keyframes auth-logo-dock {
    0% {
        opacity: 1;
        transform: translate3d(0, 0, 0) scale(1);
    }
    82% {
        opacity: 1;
        transform:
            translate3d(var(--auth-logo-exit-x, 0), var(--auth-logo-exit-y, 0), 0)
            scale(var(--auth-logo-exit-scale, .2));
    }
    100% {
        opacity: 0;
        transform:
            translate3d(var(--auth-logo-exit-x, 0), var(--auth-logo-exit-y, 0), 0)
            scale(var(--auth-logo-exit-scale, .2));
    }
}

@media (max-width: 760px) {
    .auth-screen {
        align-items: flex-start;
        padding: 1.5rem 1rem 2rem;
    }
    .auth-login-shell {
        width: min(27rem, 100%);
        grid-template-columns: 1fr;
        gap: 1.35rem;
        margin: auto 0;
    }
    .auth-brand-stage {
        align-items: center;
        text-align: center;
    }
    .auth-hero-logo {
        width: min(76vw, 20rem);
    }
    .auth-brand-copy {
        margin-top: 0.55rem;
        padding-left: 0;
    }
    .auth-brand-subtitle {
        max-width: 23rem;
    }
    .auth-login-card {
        width: 100%;
    }
}

@media (prefers-reduced-motion: reduce) {
    .auth-hero-logo,
    .auth-brand-copy,
    .auth-login-card,
    .auth-login-shell.auth-intro-ready .auth-hero-logo,
    .auth-login-shell.auth-intro-ready .auth-brand-copy,
    .auth-login-shell.auth-intro-ready .auth-login-card,
    .auth-login-shell.auth-leaving .auth-hero-logo,
    .auth-login-shell.auth-leaving .auth-brand-copy,
    .auth-login-shell.auth-leaving .auth-login-card {
        animation: none;
    }
}
/* A page, not a dialog. It was a floating card with a shadow and a × in the
   corner, which invited the reader to treat it as something that had popped up
   over their work — and then it did not go away when they navigated elsewhere.
   It now fills the content area beside the sidebar and below the top bar, so
   it reads as somewhere you went rather than something that appeared. */
.admin-panel {
    position: fixed;
    top: 3.2rem;
    left: 3.4rem;
    right: 0;
    bottom: 0;
    background: #f6f8fa;
    border-left: 1px solid #e2e8f0;
    z-index: 4500;
    padding: 1.4rem 1.6rem;
    overflow: auto;
}
.admin-panel > * {
    max-width: 96rem;
}
/* The customer picker and the + that creates a new one, on one line. */
.admin-customer-picker {
    display: flex;
    align-items: flex-end;
    gap: 0.4rem;
}
.admin-customer-picker > *:first-child {
    flex: 1;
    min-width: 0;
}
.admin-new-customer-btn {
    flex: 0 0 auto;
    width: 2.15rem;
    height: 2.15rem;
    border: 1px solid #ced4da;
    border-radius: 6px;
    background: #fff;
    color: #1971c2;
    font-size: 1.25rem;
    line-height: 1;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s;
}
.admin-new-customer-btn:hover {
    background: #e7f5ff;
    border-color: #1971c2;
}
.admin-panel-subtitle {
    color: #64748b;
    font-size: 0.78rem;
    margin-top: 0.15rem;
}
.admin-customer-shell {
    display: grid;
    grid-template-columns: 17rem minmax(0, 1fr);
    gap: 1rem;
    align-items: start;
}
.admin-customer-sidebar {
    position: sticky;
    top: 0;
    display: flex;
    flex-direction: column;
    gap: 0.8rem;
    min-width: 0;
}
.admin-customer-summary {
    padding: 0.7rem;
    border-radius: 8px;
    background: #f3f7fa;
    color: #334155;
    font-size: 0.78rem;
}
.admin-customer-summary strong,
.admin-customer-summary div {
    display: block;
}
.admin-create-customer,
.admin-danger-zone {
    border: 1px solid #e2e8f0;
    border-radius: 8px;
    padding: 0.7rem;
}
.admin-create-customer summary,
.admin-danger-zone summary {
    cursor: pointer;
    font-weight: 700;
    color: #172033;
    margin-bottom: 0.75rem;
}
.admin-customer-detail {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    min-width: 0;
}
.admin-customer-hero {
    display: flex;
    justify-content: space-between;
    align-items: start;
    padding: 0.15rem 0.1rem;
}
.admin-customer-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin-top: 0.45rem;
}
.admin-customer-meta span {
    border-radius: 999px;
    padding: 0.2rem 0.52rem;
    background: #edf7f5;
    color: #0f6d61;
    font-size: 0.72rem;
}
.admin-detail-grid,
.admin-users-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
    align-items: start;
}
.admin-field-label {
    color: #334155;
    font-size: 0.78rem;
    font-weight: 600;
    margin-bottom: 0.35rem;
}
.admin-product-list {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.35rem 0.65rem;
    margin: 0.65rem 0 0.85rem;
    color: #172033;
    font-size: 0.78rem;
}
.admin-product-list label {
    display: flex;
    align-items: center;
    gap: 0.38rem;
}
.admin-danger-zone {
    border-color: #fecaca;
    background: #fffafa;
}
.admin-panel-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 0.8rem;
}
.admin-panel h3,
.admin-panel h4 {
    margin: 0;
    color: #172033;
}
.admin-panel h4 {
    font-size: 0.92rem;
    margin-bottom: 0.75rem;
}
.admin-close-btn {
    border: 0;
    background: #f1f5f9;
    color: #172033;
    border-radius: 6px;
    width: 1.8rem;
    height: 1.8rem;
    cursor: pointer;
    font-size: 1.1rem;
}
.admin-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 1rem;
    align-items: start;
}
.admin-column {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}
.admin-section {
    border: 1px solid #e2e8f0;
    border-radius: 8px;
    padding: 0.85rem;
    min-width: 0;
}
.feature-checklist {
    max-height: 16rem;
    overflow: auto;
    border: 1px solid #e2e8f0;
    border-radius: 6px;
    padding: 0.45rem 0.55rem;
    margin: 0.75rem 0;
    font-size: 0.78rem;
    color: #172033;
}
.feature-checklist label {
    display: block;
    margin: 0.28rem 0;
}
.feature-tree {
    max-height: 18rem;
    overflow: auto;
    border: 1px solid #e2e8f0;
    border-radius: 6px;
    padding: 0.35rem 0.55rem;
    margin: 0.75rem 0;
    font-size: 0.78rem;
    color: #172033;
}
.feature-tree-group {
    padding: 0.35rem 0;
    border-bottom: 1px solid #edf2f7;
}
.feature-tree-group:last-child {
    border-bottom: 0;
}
.feature-tree-parent label {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    font-weight: 750;
    margin: 0.1rem 0;
    line-height: 1.2;
}
.feature-tree-children {
    margin-left: 1rem;
    margin-top: 0.25rem;
}
.feature-tree-children label {
    display: flex;
    align-items: center;
    gap: 0.38rem;
    margin: 0.16rem 0;
    line-height: 1.2;
}
.feature-tree input[type="checkbox"],
.admin-single-check input[type="checkbox"] {
    flex: 0 0 auto;
    margin: 0;
}
.admin-single-check {
    margin: 0.75rem 0 0.45rem;
    font-size: 0.78rem;
    color: #172033;
}
.admin-single-check label {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    line-height: 1.2;
}
.invite-output {
    margin-top: 0.75rem;
    font-size: 0.78rem;
    color: #334155;
}

@media (max-width: 760px) {
    .admin-panel {
        top: 3.4rem;
        left: 0.6rem;
        right: 0.6rem;
        bottom: 0.6rem;
        width: auto;
    }
    .admin-grid {
        grid-template-columns: 1fr;
    }
    .admin-customer-shell,
    .admin-detail-grid,
    .admin-users-grid {
        grid-template-columns: 1fr;
    }
    .admin-customer-sidebar {
        position: static;
    }
    .admin-product-list {
        grid-template-columns: 1fr;
    }
    .account-menu {
        right: -0.2rem;
    }
}

.left-sidebar {
    width: 3.25rem;
    flex-shrink: 0;
    background: linear-gradient(180deg, var(--feature-muted), white 16rem);
    border-right: 1px solid #dee2e6;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding-top: 0.5rem;
    padding-bottom: 0.5rem;
    gap: 0.25rem;
    position: relative;
    overflow: hidden;
}
.left-sidebar::before {
    content: "";
    position: absolute;
    left: 0.25rem;
    top: 0.28rem;
    width: calc(3.25rem - 0.45rem);
    height: 3.15rem;
    border-radius: 12px 0 0 12px;
    background: var(--feature-muted);
    z-index: 0;
}
.module-btn {
    width: 2.45rem;
    height: 2.45rem;
    border: 1px solid transparent;
    border-radius: 7px;
    display: flex;
    align-items: center;
    justify-content: center;
    /* Placeholder modules are not navigable. Clickability follows .enabled,
       NOT .active — .active only marks the module currently being viewed, so
       keying the cursor off it made every other module, including the working
       ones, show a "forbidden" cursor. */
    cursor: not-allowed;
    flex-shrink: 0;
    position: relative;
    z-index: 1;
    color: var(--module-color);
}
.module-btn.enabled {
    cursor: pointer;
}
.module-btn.enabled:hover:not(.active) {
    background: color-mix(in srgb, var(--module-color) 10%, white);
    border-color: color-mix(in srgb, var(--module-color) 22%, white);
}
.module-btn.active {
    background: white;
    border-color: color-mix(in srgb, var(--feature-color) 28%, white);
    box-shadow: 0 8px 18px color-mix(in srgb, var(--feature-color) 18%, transparent);
    color: var(--feature-color);
}
.module-btn .sidebar-icon {
    background-color: currentColor;
}
.sidebar-module-separator {
    width: 1.65rem;
    height: 1px;
    margin: 0.18rem 0;
    background: #cfd8df;
    flex-shrink: 0;
    position: relative;
    z-index: 1;
}

.sub-tabs-bar {
    height: 2.5rem;
    background: var(--feature-muted);
    border-bottom: 1px solid color-mix(in srgb, var(--feature-color) 18%, #dfe5ea);
    display: flex;
    align-items: center;
    padding: 0 0.25rem 0 0.72rem;
    flex-shrink: 0;
    position: relative;
    z-index: 10;
}
.sub-tabs-bar::before {
    content: "";
    position: absolute;
    left: -0.02rem;
    top: 0;
    bottom: 0;
    width: 1rem;
    background: var(--feature-muted);
    z-index: 0;
}
.sub-tabs-bar > * {
    position: relative;
    z-index: 1;
}

/* ── Sidebar icon masks ───────────────────────────────────────────────────────
   Each icon is an SVG file used as a CSS mask. The background-color of the
   div shows through the icon shape, giving full colour control in Python.   */
.sidebar-icon {
    display: block;
    width: 1.4rem;
    height: 1.4rem;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-size: contain;
    mask-size: contain;
    -webkit-mask-position: center;
    mask-position: center;
}
.icon-mobility { -webkit-mask-image: url('/assets/icons/mobility.svg');  mask-image: url('/assets/icons/mobility.svg'); }
.icon-greenwave { -webkit-mask-image: url('/assets/icons/greenwave.svg'); mask-image: url('/assets/icons/greenwave.svg'); }
.icon-signalanalysis { -webkit-mask-image: url('/assets/icons/signal-analysis.svg'); mask-image: url('/assets/icons/signal-analysis.svg'); }
.icon-road      { -webkit-mask-image: url('/assets/icons/road.svg');      mask-image: url('/assets/icons/road.svg'); }
.icon-accident  { -webkit-mask-image: url('/assets/icons/accidents.svg'); mask-image: url('/assets/icons/accidents.svg'); }
.icon-od        { -webkit-mask-image: url('/assets/icons/od.svg');        mask-image: url('/assets/icons/od.svg'); }
.icon-feedback  { -webkit-mask-image: url('/assets/icons/feedback.svg');  mask-image: url('/assets/icons/feedback.svg'); }
.icon-cyclistcommunication { -webkit-mask-image: url('/assets/icons/cyclist-communication.svg'); mask-image: url('/assets/icons/cyclist-communication.svg'); }
.icon-modelbuilder { -webkit-mask-image: url('/assets/icons/modelbuilder.svg'); mask-image: url('/assets/icons/modelbuilder.svg'); }
.icon-settings  { -webkit-mask-image: url('/assets/icons/settings.svg');  mask-image: url('/assets/icons/settings.svg'); }
.icon-ai        { -webkit-mask-image: url('/assets/icons/ai.svg');        mask-image: url('/assets/icons/ai.svg'); }

/* ── Sub-tab buttons ─────────────────────────────────────────────────────────*/
.subtab-btn {
    box-sizing: border-box;
    position: relative;   /* sit above .sub-tabs-bar::before left overlay even when */
    z-index: 1;           /* wrapped in a display:contents group (greenwave subtabs) */
    height: calc(100% - 0.45rem);
    margin: 0 0.35rem 0 0;
    padding: 0 0.55rem;
    border: 1px solid #dee2e6;
    border-radius: 5px;
    background: white;
    color: #495057;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    font-size: 0.82em;
    white-space: nowrap;
    transition: background-color 0.15s, border-color 0.15s, color 0.15s;
}
.subtab-btn.active {
    border-color: var(--feature-color);
    background: white;
    color: color-mix(in srgb, var(--feature-color) 78%, #102033);
    font-weight: 600;
}
.subtab-btn:hover:not(.active) {
    background: #f8f9fa;
}
.tab-icon {
    display: block;
    width: 1.1rem;
    height: 1.1rem;
    background-color: #495057;
    flex-shrink: 0;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-size: contain;
    mask-size: contain;
    -webkit-mask-position: center;
    mask-position: center;
    transition: background-color 0.15s;
}
.subtab-btn.active .tab-icon {
    background-color: var(--feature-color);
}
.subtab-label {
    line-height: 1;
}
.icon-tab-analyse       { -webkit-mask-image: url('/assets/icons/tab-analyse.svg');       mask-image: url('/assets/icons/tab-analyse.svg'); }
/* Row action on Prioritering: open the stretch in Tilstandsoverblik. */
.prio-detail-btn {
    border: 1px solid #d9c4a9;
    border-radius: 5px;
    background: #fbfaf8;
    color: #9c6b3f;
    font-size: 0.72rem;
    font-weight: 600;
    padding: 0.1rem 0.4rem;
    cursor: pointer;
    white-space: nowrap;
    transition: background 0.12s, border-color 0.12s;
}
.prio-detail-btn:hover { background: #f3ece3; border-color: #9c6b3f; }

/* The rank number doubles as the jump target — styled as a link so it reads as
   clickable without turning the first column into a row of buttons. */
.prio-rank-btn {
    border: 0;
    background: none;
    padding: 0;
    color: #9c6b3f;
    font-weight: 700;
    font-size: 0.8rem;
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 2px;
    font-variant-numeric: tabular-nums;
}
.prio-rank-btn:hover { color: #6f4a2a; }

/* Fold-out header for the per-route history heatmap on Tilstandsoverblik. */
.road-hist-toggle {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    width: 100%;
    padding: 0.35rem 0.5rem;
    border: 1px solid #e9ecef;
    border-radius: 6px;
    background: #fbfaf8;
    color: #495057;
    font-size: 0.78rem;
    font-weight: 600;
    cursor: pointer;
    text-align: left;
    transition: background 0.12s, border-color 0.12s;
}
.road-hist-toggle:hover { background: #f3ece3; border-color: #d9c4a9; }
.road-hist-toggle.open  { background: #f3ece3; border-color: #d9c4a9; color: #9c6b3f; }
.road-hist-caret {
    display: inline-block;
    font-size: 0.7rem;
    color: #9c6b3f;
    transition: transform 0.15s;
}
.road-hist-caret.open { transform: rotate(90deg); }

/* Vejbeskaffenhed subtabs — one glyph each; they all shared tab-analyse before.
   road-condition = roughness trace over a road, ranking = bars to compare,
   prioritering = a cone (what the ranked stretches turn into), udvikling = trend. */
.icon-tab-road-condition { -webkit-mask-image: url('/assets/icons/tab-road-condition.svg'); mask-image: url('/assets/icons/tab-road-condition.svg'); }
.icon-tab-ranking       { -webkit-mask-image: url('/assets/icons/tab-ranking.svg');       mask-image: url('/assets/icons/tab-ranking.svg'); }
.icon-tab-prioritering  { -webkit-mask-image: url('/assets/icons/tab-prioritering.svg');  mask-image: url('/assets/icons/tab-prioritering.svg'); }
.icon-tab-udvikling     { -webkit-mask-image: url('/assets/icons/tab-udvikling.svg');     mask-image: url('/assets/icons/tab-udvikling.svg'); }
.icon-tab-hastighed     { -webkit-mask-image: url('/assets/icons/tab-hastighed.svg');     mask-image: url('/assets/icons/tab-hastighed.svg'); }
.icon-tab-forsinkelse   { -webkit-mask-image: url('/assets/icons/tab-forsinkelse.svg');   mask-image: url('/assets/icons/tab-forsinkelse.svg'); }
.icon-tab-stop          { -webkit-mask-image: url('/assets/icons/tab-stop.svg');          mask-image: url('/assets/icons/tab-stop.svg'); }
.icon-tab-opbremsninger { -webkit-mask-image: url('/assets/icons/tab-opbremsninger.svg'); mask-image: url('/assets/icons/tab-opbremsninger.svg'); }
.icon-tab-kryds         { -webkit-mask-image: url('/assets/icons/tab-kryds.svg');         mask-image: url('/assets/icons/tab-kryds.svg'); }
.icon-tab-gw-maalt      { -webkit-mask-image: url('/assets/icons/tab-gw-maalt.svg');      mask-image: url('/assets/icons/tab-gw-maalt.svg'); }
.icon-tab-gw-simulering { -webkit-mask-image: url('/assets/icons/tab-gw-simulering.svg'); mask-image: url('/assets/icons/tab-gw-simulering.svg'); }
.icon-tab-gw-optimering { -webkit-mask-image: url('/assets/icons/tab-gw-optimering.svg'); mask-image: url('/assets/icons/tab-gw-optimering.svg'); }
.icon-tab-gw-signaler   { -webkit-mask-image: url('/assets/icons/tab-gw-signaler.svg');   mask-image: url('/assets/icons/tab-gw-signaler.svg'); }
.icon-tab-gw-ruter      { -webkit-mask-image: url('/assets/icons/tab-gw-ruter.svg');      mask-image: url('/assets/icons/tab-gw-ruter.svg'); }

.routes-db-subtab-btn {
    box-sizing: border-box;
    height: calc(100% - 0.45rem);
    margin: 0 0.1rem 0 0.35rem;
    padding: 0 0.55rem;
    border: 1px solid #dee2e6;
    border-radius: 5px;
    background: white;
    color: #495057;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.82em;
    white-space: nowrap;
}
.routes-db-subtab-btn:hover:not(.active) {
    background: #f8f9fa;
}
.routes-db-subtab-btn.active {
    border-color: var(--feature-color);
    color: color-mix(in srgb, var(--feature-color) 78%, #102033);
    font-weight: 600;
}
.routes-db-subtab-btn.active .routes-db-icon {
    background-color: var(--feature-color);
}
.routes-db-icon {
    width: 1.1rem;
    height: 1.1rem;
    background-color: #495057;
    flex-shrink: 0;
    -webkit-mask-image: url('/assets/icons/database.svg');
    mask-image: url('/assets/icons/database.svg');
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-size: contain;
    mask-size: contain;
    -webkit-mask-position: center;
    mask-position: center;
}

/* ── Filter trigger button (in sub-tabs bar) ─────────────────────────────────*/
.filter-trigger-btn {
    box-sizing: border-box;
    height: calc(100% - 0.45rem);
    padding: 0 0.6rem;
    border: 1px solid color-mix(in srgb, var(--feature-color) 22%, #dee2e6);
    border-radius: 5px;
    background: white;
    color: var(--feature-color);
    display: flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.8em;
    white-space: nowrap;
    cursor: pointer;
    user-select: none;
}
.filter-trigger-btn:hover { background: #f0fbfe; }
.filter-trigger-btn.open  { border-color: var(--feature-color); background: #e8f8fd; }
.fp-trigger-text { color: #212529; font-size: 0.95em; }
.fp-caret { font-size: 0.75em; opacity: 0.55; margin-left: 1px; }
.fp-filter-icon {
    width: 1.1rem; height: 1.1rem; flex-shrink: 0;
    background-color: currentColor;
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolygon points='22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolygon points='22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3'/%3E%3C/svg%3E");
    -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
    -webkit-mask-size: contain; mask-size: contain;
}

/* ── Filter dropdown panel ───────────────────────────────────────────────────*/
/* position/display/top/right are set dynamically via clientside callback     */
.filter-dropdown {
    background: white;
    border: 1px solid #dee2e6;
    border-radius: 8px;
    box-shadow: 0 6px 24px rgba(0,0,0,0.13);
    padding: 0.8rem 0.9rem 0.65rem;
    width: 420px;
}
.fp-section-label {
    font-size: 0.67em;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #adb5bd;
    margin-bottom: 0.3rem;
    margin-top: 0.05rem;
}
.fp-label-a { color: var(--feature-color); }
.fp-label-b { color: #b05d00; }

/* 24-hour band */
.hour-band {
    display: flex;
    gap: 2px;
    background: #f3f5f7;
    border-radius: 5px;
    padding: 3px;
    user-select: none;
}
.hour-cell {
    flex: 1;
    height: 24px;
    border-radius: 3px;
    cursor: pointer;
    background: white;
    border: 1px solid #e9ecef;
    transition: background 0.08s, border-color 0.08s;
}
.hour-cell:hover { border-color: #74c6db; background: #e8f8fd; }
.hour-cell.selected { background: var(--feature-color); border-color: #0993b3; }
.hour-cell.selected:hover { background: #0993b3; }

/* ── Vejbeskaffenhed period matrix (year × month) ─────────────────────────── */
/* Sized in rem throughout, NOT px. html sets font-size: clamp(13px, 0.9vw, 26px),
   so text here scales with the viewport while a px panel would not — that
   mismatch is what pushed the grid outside the panel on a wide screen.

   width is fit-content rather than a number: the panel then hugs the grid and
   the 0.9rem side padding is symmetric by construction. A hard width has to
   agree with the grid's total AND with whether the box is content- or
   border-box (Mantine's reset makes it the latter) — get either wrong and the
   grid eats one side's padding, which is exactly what happened at 33.4rem. */
.rq-period-dropdown { width: fit-content; }

.rq-matrix-wrap { margin-bottom: 0.5rem; }

.rq-matrix {
    display: grid;
    /* Fixed rem tracks, not 1fr: an fr track floors at min-content, so a header
       whose text is wider than its share pushes the whole grid past the panel
       instead of shrinking. */
    grid-template-columns: 4.6rem repeat(12, 2.1rem);
    gap: 0.2rem;
}
/* Header row is its own grid; identical columns keep the two aligned. */
.rq-matrix-head { margin-bottom: 0.2rem; }

/* Column headers (month names) and row headers (years) are themselves the
   bulk-select controls, so they look clickable rather than like labels. */
.rq-hdr {
    font-size: 0.63em;
    font-weight: 700;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: #495057;
    background: white;
    border: 1px solid #e9ecef;
    border-radius: 3px;
    display: flex;
    align-items: center;
    justify-content: center;
    height: 1.55rem;
    cursor: pointer;
    user-select: none;
    white-space: nowrap;
    overflow: hidden;
    transition: background 0.08s, border-color 0.08s, color 0.08s;
}
.rq-hdr:hover { border-color: #74c6db; background: #e8f8fd; color: #0a7999; }
/* A header goes solid only when every selectable cell behind it is on. */
.rq-hdr.full { background: var(--feature-color); border-color: #0993b3; color: white; }
.rq-hdr.full:hover { background: #0993b3; }
/* Partly selected: readable at a glance without claiming "all". */
.rq-hdr.partial { background: #d4f0f9; border-color: #74c6db; color: #0a7999; }

/* "Alle data" has to fit the 4.6rem corner on one line — it wrapped and
   clipped at the 0.63em the other headers use. */
.rq-corner { font-size: 0.55em; letter-spacing: 0; }
.rq-year   { font-size: 0.74em; letter-spacing: 0; }

.rq-cell {
    height: 1.55rem;
    border-radius: 3px;
    cursor: pointer;
    background: white;
    border: 1px solid #e9ecef;
    transition: background 0.08s, border-color 0.08s;
}
.rq-cell:hover { border-color: #74c6db; background: #e8f8fd; }
.rq-cell.selected { background: var(--feature-color); border-color: #0993b3; }
.rq-cell.selected:hover { background: #0993b3; }

/* No data in the database for this month — not a choice the user can make. */
.rq-cell.empty {
    background: repeating-linear-gradient(
        45deg, #f8f9fa, #f8f9fa 3px, #f1f3f5 3px, #f1f3f5 6px);
    border-color: #f1f3f5;
    cursor: default;
}
.rq-cell.empty:hover { border-color: #f1f3f5; }

.rq-period-summary {
    font-size: 0.7em;
    color: #868e96;
    margin-bottom: 0.4rem;
    min-height: 1.1em;
}
.rq-period-summary.warn { color: #e8590c; font-weight: 600; }

/* Calendar glyph on the toolbar trigger. */
.rq-period-icon {
    width: 13px;
    height: 13px;
    border: 1.5px solid #495057;
    border-radius: 2px;
    border-top-width: 4px;
    flex: none;
}

.hour-ticks {
    display: flex;
    justify-content: space-between;
    padding: 2px 3px 0;
    font-size: 0.64em;
    color: #adb5bd;
    margin-bottom: 0.35rem;
}
/* Signaler editor */
.signaler-view {
    height: 100%;
    min-height: 0;
}

/* ── Signaler: route, programme and mode, on top of the timings ─────────────
   They were a row across the whole view — map and sheet together — which put
   them nowhere near the sheet they govern. Here they head the panel and stay
   put while the planner scrolls the junctions. */
.signaler-sheet-head {
    display: flex;
    flex-direction: column;
    gap: 0.45rem;
    padding: 0.55rem 0.6rem;
    border: 1px solid #d7dee5;
    border-radius: 8px;
    background: white;
    box-shadow: 0 1px 3px rgba(15, 23, 42, 0.06);
}

.signaler-sheet-head-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
}

/* The route picker is the widest thing here and takes the row to itself; the
   programme, its ± and the mode share the next one. */
.signaler-sheet-head .signaler-route-picker {
    flex: 1 1 auto;
    max-width: none;
}

.signaler-program-wrap {
    /* Wide enough for "Eftermiddag · 15:00–18:00" without truncating, and it
       does NOT grow: the ± belongs beside the programme it edits, and a growing
       picker pushed it across the row (owner, 2026-10-06). */
    flex: 0 1 22rem;
    min-width: 16rem;
}

/* The wrapper grew; the Select inside it did not, which is why widening the
   wrapper alone changed nothing visible. Mantine's root carries its own width. */
.signaler-program-wrap > *,
.signaler-program-wrap .mantine-Select-root,
.signaler-program-wrap .mantine-InputWrapper-root {
    width: 100%;
}

/* Cykel / Bil is a separate choice from which programme is open, so it sits at
   the far end rather than crowding the ±. */
#signaler-mode-select {
    margin-left: auto;
}


.signaler-route-picker {
    flex: 1 1 360px;
    max-width: 520px;
}

/* The veil below is absolute against this. */
.signaler-split {
    position: relative;
}

/* The veil sits INSIDE the map wrapper and fills it, so the spinner is centred
   on the map. It used to try to cover the sheet by overriding `inset` from
   .road-loading-overlay with a left/right/width of its own — the shorthand won,
   and the card ended up floating over the map off-centre. Its own rule now,
   with nothing to fight. */
.signaler-loading-overlay {
    position: absolute;
    inset: 0;
    z-index: 1200;
    display: none;                 /* flipped to flex by the clientside callback */
    align-items: center;
    justify-content: center;
    background: rgba(248, 249, 250, 0.55);
    backdrop-filter: blur(1.5px);
    border-radius: 8px;
    pointer-events: all;
}

/* Zoomed out, the junction labels are hidden by class rather than by
   re-rendering every marker. The tooltip element still exists, so hover still
   shows one — which is the behaviour that was asked for. */
.signaler-map-wrap.sig-labels-hidden .sig-cap-label {
    display: none;
}

/* ── Signaler map toolbar ────────────────────────────────────────────────────
   Modelbygger's own .map-toolbar / .tool-group / .map-tool, which the owner
   named as the baseline. The tools used to be a SegmentedControl in the row
   above the map, where they read as a filter rather than as something you do to
   the map. "Navngiv" is gone: naming happens in the sheet, beside the timings. */
.signaler-map-toolbar {
    position: absolute;
    top: 0.7692rem;
    left: 0.7692rem;
    right: 4.2rem;                 /* clear of the basemap control */
    z-index: 500;
    display: flex;
    gap: 0.4615rem;
    align-items: center;
    pointer-events: none;
    flex-wrap: wrap;
}

.signaler-map-toolbar .tool-group {
    display: flex;
    gap: 0.1538rem;
    padding: 0.2308rem;
    border-radius: 0.6154rem;
    background: rgb(255 255 255 / 96%);
    box-shadow: 0 0.0769rem 0.2308rem rgb(15 30 45 / 18%);
    pointer-events: auto;
}

.signaler-map-toolbar .map-tool {
    height: 2.1538rem;
    display: inline-flex;
    align-items: center;
    gap: 0.4615rem;
    padding: 0 0.6923rem;
    border: 0;
    border-radius: 0.4615rem;
    background: transparent;
    color: #4a5865;
    font: inherit;
    cursor: pointer;
    white-space: nowrap;
}

.signaler-map-toolbar .map-tool:hover { background: #eef2f5; }
.signaler-map-toolbar .map-tool.active { background: var(--veloio-brand, #063545); color: #fff; }
.signaler-map-toolbar .map-tool.icon-only { padding: 0 0.5385rem; }
.signaler-map-toolbar .map-tool:disabled { opacity: 0.4; cursor: default; }
.signaler-map-toolbar .map-tool:disabled:hover { background: transparent; }

.map-tool-icon {
    display: block;
    width: 1.05rem;
    height: 1.05rem;
    background-color: currentColor;
    flex-shrink: 0;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-size: contain;
    mask-size: contain;
    -webkit-mask-position: center;
    mask-position: center;
}

.icon-sig-select   { -webkit-mask-image: url('/assets/icons/sig-select.svg');   mask-image: url('/assets/icons/sig-select.svg'); }
.icon-sig-link     { -webkit-mask-image: url('/assets/icons/sig-link.svg');     mask-image: url('/assets/icons/sig-link.svg'); }
.icon-sig-unlink   { -webkit-mask-image: url('/assets/icons/sig-unlink.svg');   mask-image: url('/assets/icons/sig-unlink.svg'); }
.icon-sig-onesided { -webkit-mask-image: url('/assets/icons/sig-onesided.svg'); mask-image: url('/assets/icons/sig-onesided.svg'); }
.icon-sig-undo     { -webkit-mask-image: url('/assets/icons/sig-undo.svg');     mask-image: url('/assets/icons/sig-undo.svg'); }
.icon-sig-fit      { -webkit-mask-image: url('/assets/icons/sig-fit.svg');      mask-image: url('/assets/icons/sig-fit.svg'); }

/* The instruction box, dark like Modelbygger's .map-hint, shown only once an
   action tool is chosen — "Vælg" needs no instructions. */
.signaler-map-hint {
    max-width: 30rem;
    padding: 0.6154rem 0.8462rem;
    border-radius: 0.5385rem;
    background: rgb(6 53 69 / 94%);
    color: #eaf2f5;
    line-height: 1.4;
    font-size: 0.82rem;
    box-shadow: 0 0.1538rem 0.4615rem rgb(15 30 45 / 25%);
}

/* The map's own positioning context. Without it the basemap control and the
   bottom-left stack are absolute against whatever ancestor happens to be
   positioned: the basemap icons landed on the toolbar, covering "Ensidet" and
   "Navngiv", and the legend fell below the map entirely. Every other feature
   map already had a positioned wrapper, which is why they looked right and this
   one did not. */
.signaler-map-wrap {
    position: relative;
}

/* Bottom-left stack over the Signaler map: the instruction box (when a tool is
   chosen) above the legend. Modelbygger's own .map-legend / .map-hint sit at the
   same inset, so the two editors line up. Clear of the zoom control, which the
   feature-map standard puts bottom right. */
.signaler-map-corner {
    position: absolute;
    bottom: 0.7692rem;
    left: 0.7692rem;
    z-index: 500;
    display: grid;
    gap: 0.4rem;
    justify-items: start;
    max-width: calc(100% - 1.6rem);
    pointer-events: none;
}

.signaler-map-corner > * {
    pointer-events: auto;
}

.signaler-legend {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.75rem;
    padding: 0.6154rem 0.7692rem;
    border-radius: 0.5385rem;
    background: rgb(255 255 255 / 95%);
    box-shadow: 0 0.0769rem 0.2308rem rgb(15 30 45 / 18%);
    color: #495057;
    font-size: 0.74rem;
}

.signaler-legend > span {
    display: inline-flex;
    align-items: center;
    gap: 0.28rem;
}

.sig-dot {
    display: inline-block;
    width: 0.58rem;
    height: 0.58rem;
    border-radius: 999px;
    box-shadow: 0 0 0 2px white, 0 0 0 3px rgba(15, 23, 42, 0.16);
}

.sig-dot-open { background: #f59e0b; }
.sig-dot-ok { background: #16a34a; }
.sig-dot-selected {
    background: transparent;
    border: 2px solid #2563eb;
    box-sizing: border-box;
}

.signaler-map {
    height: 100%;
    width: 100%;
    border-radius: 8px;
    border: 1px solid #d7dee5;
    box-shadow: 0 1px 3px rgba(15, 23, 42, 0.08);
}

.signaler-panel {
    flex: 1 1 auto;
    min-width: 420px;
    height: 100%;
    min-height: 0;
    /* The PANEL does not scroll; the sheet inside it does.
       It used to, and that is what made the sticky column headers useless: they
       stick to the top of whatever scrolls, which was the panel — so they rode
       up UNDER the head card and the route line scrolled through them. One card,
       a fixed head, and the rows moving beneath it (owner, 2026-10-06). */
    display: flex;
    flex-direction: column;
    overflow: hidden;
    border: 1px solid #d7dee5;
    border-radius: 8px;
    background: white;
    box-shadow: 0 1px 3px rgba(15, 23, 42, 0.06);
}

.signaler-panel-empty {
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #868e96;
    font-size: 0.84rem;
}

.signaler-sheet-head {
    position: sticky;
    top: 0;
    z-index: 2;
    background: rgba(255, 255, 255, 0.96);
    backdrop-filter: blur(4px);
    border-bottom: 1px solid #e9ecef;
    padding: 0.58rem 0.65rem;
}

.signaler-sheet-title {
    display: flex;
    align-items: center;
    gap: 0.38rem;
    min-width: 0;
}

.signaler-sheet-count {
    font-size: 0.82rem;
    font-weight: 700;
    color: #212529;
}

.signaler-sheet-route {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: #868e96;
    font-size: 0.72rem;
}

.signaler-lock-btn {
    width: 1.8rem;
    height: 1.8rem;
}

.signaler-lock-icon {
    display: inline-block;
    width: 0.95rem;
    height: 0.95rem;
    background-color: currentColor;
    -webkit-mask: url("/assets/lock-open.svg") center / contain no-repeat;
    mask: url("/assets/lock-open.svg") center / contain no-repeat;
}

.signaler-lock-btn.locked .signaler-lock-icon {
    -webkit-mask-image: url("/assets/lock.svg");
    mask-image: url("/assets/lock.svg");
}

.signaler-sheet-scroll {
    padding: 0.45rem 0.55rem 0.65rem;
    flex: 1 1 auto;
    min-height: 0;          /* without this a flex child refuses to shrink */
    overflow: auto;
}

.signaler-sheet {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
}

.signaler-sheet th {
    position: sticky;
    top: 3.25rem;
    z-index: 1;
    background: white;
    text-align: left;
    font-weight: 700;
    font-size: 0.66rem;
    line-height: 1;
    color: #868e96;
    padding: 0.38rem 0.42rem;
    border-bottom: 1px solid #e9ecef;
    text-transform: uppercase;
}

.signaler-sheet td {
    vertical-align: middle;
    padding: 0.28rem 0.42rem;
    border-bottom: 1px solid #f1f3f5;
}

.signaler-sheet tbody.signaler-jgroup:hover td {
    background: #f8fafc;
}

.signaler-code-cell {
    color: #495057;
    font-size: 0.72rem;
    font-weight: 700;
    white-space: nowrap;
}

.signaler-code-loc {
    color: #adb5bd;
    font-weight: 400;
}

.signaler-time-input input {
    text-align: right;
    padding-left: 0.35rem;
    padding-right: 0.35rem;
}

/* Locked sheet: lighten DMC's default disabled-input grey */
.signaler-sheet input:disabled,
.signaler-sheet input[data-disabled] {
    background-color: #fafbfc;
    color: #adb5bd;
    -webkit-text-fill-color: #adb5bd;
    opacity: 1;
}

.signaler-letter-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.35rem;
    height: 1.35rem;
    border-radius: 999px;
    color: white;
    font-size: 0.72rem;
    font-weight: 800;
    line-height: 1;
    box-shadow: 0 0 0 2px white, 0 1px 4px rgba(15, 23, 42, 0.18);
}

.signaler-letter-badge.ok { background: #16a34a; }
.signaler-letter-badge.open { background: #f59e0b; }

.signaler-note {
    color: #868e96;
    font-size: 0.72rem;
    line-height: 1.35;
    margin-top: 0.55rem;
}

/* Signaler map: permanent junction-letter label on capsules / one-sided markers */
.leaflet-tooltip.sig-cap-label {
    background: rgba(255, 255, 255, 0.92);
    border: 1px solid rgba(15, 23, 42, 0.08);
    box-shadow: 0 1px 4px rgba(15, 23, 42, 0.12);
    font-weight: 700;
    font-size: 0.72rem;
    color: #1f2937;
    padding: 1px 5px;
    border-radius: 4px;
}
.leaflet-tooltip.sig-cap-label::before { display: none; }

.sig-popup {
    min-width: 220px;
    max-width: 280px;
}

.sig-popup-title {
    color: #212529;
    font-size: 0.82rem;
    font-weight: 700;
    margin-bottom: 0.28rem;
}

.sig-popup-text {
    color: #495057;
    font-size: 0.74rem;
    line-height: 1.3;
    margin-bottom: 0.45rem;
}

.sig-popup-status {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.3rem;
    width: 100%;
    border-radius: 7px;
    background: #e6f6ec;
    color: #16a34a;
    font-size: 0.74rem;
    font-weight: 800;
    line-height: 1.1;
    padding: 0.34rem 0.55rem;
    margin-bottom: 0.45rem;
    white-space: normal;
}

.sig-popup-status::before {
    content: "✓";
    font-weight: 900;
}

.sig-popup-hint {
    color: #868e96;
    font-size: 0.68rem;
    line-height: 1.25;
    margin-top: 0.42rem;
}

.fp-presets { display: flex; gap: 0.3rem; flex-wrap: wrap; margin-top: 0.35rem; }

/* Data-scope info badge on Green Wave signal cards */
.gw-info-i {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 15px;
    height: 15px;
    flex: 0 0 auto;
    border-radius: 50%;
    border: 1px solid #adb5bd;
    color: #868e96;
    font-size: 10px;
    font-style: italic;
    font-weight: 700;
    font-family: Georgia, "Times New Roman", serif;
    cursor: help;
    user-select: none;
}
.gw-info-i.filtered {
    border-color: var(--feature-color, #16a34a);
    color: #fff;
    background: var(--feature-color, #16a34a);
}
.fp-preset-btn {
    font-size: 0.71em;
    padding: 2px 9px;
    border: 1px solid #dee2e6;
    border-radius: 20px;
    background: white;
    color: #495057;
    cursor: pointer;
}
.fp-preset-btn:hover { background: #e8f8fd; border-color: #74c6db; color: #0a7999; }
.fp-preset-btn.active { background: var(--feature-color); border-color: #0993b3; color: white; }
.fp-preset-btn.active:hover { background: #0993b3; }

/* Weekday buttons */
.fp-weekday-row { display: flex; gap: 0.28rem; margin-bottom: 0.35rem; }
.fp-day-btn {
    flex: 1;
    height: 28px;
    border: 1px solid #dee2e6;
    border-radius: 5px;
    background: white;
    cursor: pointer;
    font-size: 0.76em;
    font-weight: 500;
    color: #495057;
    display: flex;
    align-items: center;
    justify-content: center;
    user-select: none;
    transition: background 0.08s, border-color 0.08s;
}
.fp-day-btn:hover { border-color: #74c6db; background: #e8f8fd; }
.fp-day-btn.selected { background: var(--feature-color); border-color: #0993b3; color: white; }
.fp-day-btn.weekend { color: #868e96; }
.fp-day-btn.weekend.selected { background: var(--feature-color); color: white; }

/* Divider */
.fp-divider { border: none; border-top: 1px solid #f0f0f0; margin: 0.55rem 0; }

/* Compare toggle row */
.fp-cmp-row {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    margin: 0.25rem 0;
}
.fp-cmp-label { font-size: 0.74em; color: #495057; cursor: pointer; }

/* Action buttons row */
.fp-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.4rem;
    margin-top: 0.55rem;
}

/* ── Route selector: Leaflet-style button + expandable panel ─────────────────*/
.route-select-btn {
    box-sizing: border-box;
    width: 48px;
    height: 48px;
    background: white;
    border: 2px solid color-mix(in srgb, var(--feature-color) 32%, rgba(0,0,0,0.2));
    background-clip: padding-box;
    border-radius: 5px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    user-select: none;
}
.route-select-btn:hover {
    background: color-mix(in srgb, var(--feature-color) 8%, white);
}
.route-select-icon {
    display: block;
    width: 24px;
    height: 24px;
    background-color: var(--feature-color);
    -webkit-mask-image: url('/assets/icons/route-select.svg');
    mask-image: url('/assets/icons/route-select.svg');
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-size: contain;
    mask-size: contain;
    -webkit-mask-position: center;
    mask-position: center;
}
.route-select-panel {
    position: absolute;
    top: 0;
    right: 58px;
    background: white;
    border: none;
    border-radius: 5px;
    width: min(360px, calc(100vw - 120px));
    box-shadow: 0 1px 5px rgba(0,0,0,0.4);
    overflow: hidden;
}
.route-panel-list {
    max-height: 320px;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 6px 10px;
}
.route-panel-list label {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 4px 0;
    font-size: 0.76em;
    cursor: pointer;
    line-height: 1.3;
    white-space: normal;
}
.route-panel-list input {
    flex-shrink: 0;
    accent-color: var(--feature-color);
}
.route-panel-list label span {
    min-width: 0;
    overflow-wrap: anywhere;
}
.route-done-btn {
    box-sizing: border-box;
    width: 100%;
    background: var(--feature-color);
    color: white;
    border: none;
    padding: 7px 0;
    cursor: pointer;
    font-size: 0.82em;
    font-weight: 500;
    text-align: center;
    user-select: none;
}
.route-done-btn:hover {
    background: color-mix(in srgb, var(--feature-color) 86%, #000);
}

/* Remove Leaflet's default focus rectangle on clicked map elements */
path.leaflet-interactive:focus {
    outline: none;
}

/* Prioritering: rank-number badges on the map */
.leaflet-tooltip.prio-rank-tip {
    background: #111;
    color: #fff;
    border: none;
    border-radius: 10px;
    font-weight: 700;
    font-size: 0.72rem;
    padding: 1px 6px;
    box-shadow: 0 1px 3px rgba(0,0,0,0.35);
}
.leaflet-tooltip.prio-rank-tip::before { display: none; }

/* Embedded Street View overlay */
.sv-overlay {
    position: fixed; inset: 0; z-index: 10000;
    background: rgba(15, 23, 42, 0.55);
    display: flex; align-items: center; justify-content: center;
}
.sv-box {
    width: min(900px, 92vw); background: #fff; border-radius: 10px;
    overflow: hidden; box-shadow: 0 10px 40px rgba(0,0,0,0.35);
}
.sv-box-head {
    display: flex; align-items: center; justify-content: space-between;
    padding: 0.5rem 0.8rem; border-bottom: 1px solid #e9ecef;
    font-weight: 700; font-size: 0.85rem; color: #212529;
    cursor: grab; user-select: none;
}
.sv-box-brand { display: flex; align-items: center; gap: 0.5rem; }
.sv-box-logo { height: 18px; width: auto; display: block; }
.sv-embed-head {
    display: flex; align-items: center; gap: 0.5rem;
    margin: 0.6rem 0 0.35rem; font-weight: 700; font-size: 0.8rem; color: #212529;
}
.sv-box-title { font-weight: 700; }
.sv-close-btn {
    border: none; background: #f1f3f5; border-radius: 6px; width: 28px; height: 28px;
    cursor: pointer; font-size: 0.9rem; color: #495057;
}
.sv-close-btn:hover { background: #e9ecef; }

/* ── Vejbeskaffenhed: busy veil over the Tilstandsoverblik map ──────────────
   Shown while route reports are fetched + segments drawn. Translucent so the
   basemap stays readable; pointer-events blocked so clicks can't select a
   segment from a half-built layer. */
.road-loading-overlay {
    position: absolute; inset: 0.3rem; z-index: 1200;
    display: flex; align-items: center; justify-content: center;
    background: rgba(248, 249, 250, 0.55);
    backdrop-filter: blur(1.5px);
    border-radius: 8px;
    pointer-events: all;
    cursor: progress;
}
.road-loading-card {
    display: flex; flex-direction: column; align-items: center; gap: 0.45rem;
    background: #fff; border: 1px solid #dee2e6; border-radius: 10px;
    padding: 1rem 1.6rem;
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.12);
}
.road-loading-title {
    font-size: 0.82rem; font-weight: 700; color: #9c6b3f;
}
.road-loading-spinner {
    width: 26px; height: 26px; border-radius: 50%;
    border: 3px solid #ecdfd2; border-top-color: #9c6b3f;
    animation: road-spin 0.8s linear infinite;
}
@keyframes road-spin { to { transform: rotate(360deg); } }

/* ── Vejbeskaffenhed: disk-usage panel (Data view) ─────────────────────── */
.rq-storage-cards {
    display: flex; flex-wrap: wrap; gap: 0.6rem; margin-bottom: 0.9rem;
}
.rq-storage-card {
    flex: 1 1 165px; min-width: 165px;
    border: 1px solid #e9ecef; border-left: 3px solid #9c6b3f;
    border-radius: 8px; padding: 0.55rem 0.7rem; background: #fff;
}
.rq-storage-card .lbl {
    font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.02em;
    color: #868e96;
}
.rq-storage-card .val {
    font-size: 1.15rem; font-weight: 700; font-variant-numeric: tabular-nums;
    color: #212529;
}
.rq-storage-card .sub { font-size: 0.66rem; color: #adb5bd; }
/* Stacked proportion bar: where the bytes actually sit. */
.rq-storage-bar {
    display: flex; height: 14px; border-radius: 4px; overflow: hidden;
    border: 1px solid #e9ecef; margin-bottom: 0.4rem;
}
.rq-storage-bar > div { height: 100%; }
.rq-storage-legend {
    display: flex; flex-wrap: wrap; gap: 0.9rem; font-size: 0.7rem;
    color: #495057; margin-bottom: 1rem;
}
.rq-storage-legend .dot {
    display: inline-block; width: 9px; height: 9px; border-radius: 2px;
    margin-right: 0.35rem;
}

/* ---- Vejnet (Opsætning → road-network administration) ---- */
.vejnet-banner {
    padding: 8px 10px;
    border-radius: 6px;
    font-size: 12.5px;
    line-height: 1.45;
    margin-bottom: 10px;
}
.vejnet-banner.ok    { background: #e6f6ec; color: #1c6b39; }
.vejnet-banner.warn  { background: #fff2d8; color: #7a4f06; }
.vejnet-banner.error { background: #fdeae6; color: #8c2d1a; }
.vejnet-banner ul    { margin: 6px 0 0; padding-left: 18px; }

.vejnet-current-box {
    padding: 10px 12px;
    border: 1px solid #dce3e9;
    border-radius: 7px;
    background: #fbfcfd;
}
.vejnet-current-label {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: #667382;
}
.vejnet-current-value { font-size: 15px; font-weight: 700; margin-top: 2px; }
.vejnet-current-meta  { font-size: 11.5px; color: #667382; margin-top: 2px; }

.vejnet-history-title {
    margin: 14px 0 6px;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: #667382;
}
.vejnet-history { max-height: 240px; overflow-y: auto; }
.vejnet-row {
    padding: 7px 9px;
    border: 1px solid #edf1f4;
    border-radius: 6px;
    margin-bottom: 5px;
}
.vejnet-row-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}
.vejnet-row-date   { font-size: 12px; font-weight: 600; }
.vejnet-row-detail { font-size: 11.5px; color: #667382; }
.vejnet-row-error  { font-size: 11.5px; color: #8c2d1a; margin-top: 3px; }
.vejnet-row-status {
    padding: 1px 6px;
    border-radius: 4px;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    background: #eef2f5;
    color: #52616f;
}
.vejnet-row-status.current    { background: #e6f6ec; color: #1c6b39; }
.vejnet-row-status.ready      { background: #dff4f2; color: #0b5f63; }
.vejnet-row-status.failed     { background: #fdeae6; color: #8c2d1a; }
.vejnet-row-status.importing  { background: #fff2d8; color: #7a4f06; }
/* Route databases: keep identity visible when the pointer travels from the
   name on the left to the action at the far right. */
.db-route-row { transition: background-color 120ms ease; }
.db-route-row:hover { background: #eef7f6; }
.route-trash { margin-top: .8rem; border-top: 1px solid #dee2e6; padding-top: .65rem; }
.route-trash > summary { cursor: pointer; color: #66727d; font-weight: 650; padding: .35rem .2rem; }
.route-trash[open] > summary { margin-bottom: .35rem; }

/* ── O/D · Punktflow ──────────────────────────────────────────────────────
   Map left, answer right. The panel is fixed-width rather than a percentage:
   the numbers are tabular and must not reflow as the window changes. */
.od-view { display: flex; height: 100%; min-height: 0; }
.od-map-wrap { flex: 1; position: relative; min-width: 0; }
.od-map { width: 100%; height: 100%; }
.od-map-hint {
  position: absolute; left: 12px; bottom: 12px; z-index: 600;
  padding: 6px 10px; border-radius: 5px; max-width: 22rem;
  background: rgb(255 255 255 / 94%); border: 1px solid #cfd8df;
  font-size: 0.78rem; color: #43515d; pointer-events: none;
}
.od-legend {
  position: absolute; right: 12px; bottom: 12px; z-index: 600;
  padding: 7px 10px; border-radius: 5px;
  background: rgb(255 255 255 / 94%); border: 1px solid #cfd8df;
}
.od-legend-title { font-size: 0.68rem; font-weight: 700; letter-spacing: 0.04em;
                   text-transform: uppercase; color: #5d6b78; margin-bottom: 4px; }
.od-legend-ramp { display: flex; gap: 0; }
.od-legend-swatch { width: 26px; height: 9px; }
.od-legend-swatch:first-child { border-radius: 2px 0 0 2px; }
.od-legend-swatch:last-child { border-radius: 0 2px 2px 0; }
.od-legend-scale { display: flex; justify-content: space-between;
                   font-size: 0.68rem; color: #6b7783; margin-top: 3px; }
.od-legend-peak { font-variant-numeric: tabular-nums; font-weight: 600; }

.od-panel {
  width: 320px; flex: 0 0 320px; overflow-y: auto;
  border-left: 1px solid var(--line, #dce3e9); background: #fff;
  padding: 0.75rem 0.9rem;
}
.od-panel-empty { color: #7a8794; font-size: 0.82rem; padding: 0.6rem 0; }
.od-panel-title { font-weight: 700; font-size: 0.92rem; color: #172433;
                  margin-bottom: 0.55rem; }
.od-dir-block {
  border: 1px solid #e4e9ee; border-radius: 6px; background: #fbfcfd;
  padding: 0.6rem; margin-bottom: 0.6rem;
}
.od-dir-line { display: flex; align-items: center; gap: 0.5rem; }
.od-dir-arrow {
  display: inline-block; font-size: 1.35rem; line-height: 1;
  color: #7466d8; font-weight: 700;
}
.od-dir-towards { font-weight: 650; font-size: 0.95rem; color: #172433; }
.od-dir-count {
  font-size: 0.82rem; color: #4a5762; margin-top: 0.15rem;
  font-variant-numeric: tabular-nums;
}
.od-corridor-count { font-size: 0.82rem; font-weight: 600; color: #172433; }
.od-corridor-help { font-size: 0.74rem; color: #6b7783; line-height: 1.45;
                    margin-top: 0.2rem; }
.od-panel-note {
  margin-top: 0.7rem; padding-top: 0.55rem; border-top: 1px solid #eef2f5;
  font-size: 0.7rem; color: #7a8794; line-height: 1.45;
}

/* Blank basemap: Leaflet paints its own grey when no tiles are active, which
   is not "no background" — the spider net needs white under it. */
.od-map .leaflet-container { background: #ffffff; }

/* Direction arrows sit on the clicked point, one per way the road is ridden.
   Grey means "not shown"; either or both can be on. */
.od-arrow-wrap { background: none !important; border: none !important; }
.od-arrow-disc {
  width: 38px; height: 38px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; user-select: none;
  border: 2px solid #fff; box-shadow: 0 1px 4px rgb(15 23 42 / 35%);
  transition: transform 0.1s ease;
}
.od-arrow-disc:hover { transform: scale(1.12); }
/* Selected is the blue of the flow it draws; unselected is plainly grey and
   faded, so which one is active is not a judgement about shade. */
.od-arrow-disc.on  { background: #1d4ed8; }
.od-arrow-disc.off { background: #98a2ad; opacity: 0.75; }
.od-arrow-disc svg { transform-origin: 50% 50%; display: block; }

.od-dir-toggle-row { display: flex; gap: 0.4rem; margin-bottom: 0.5rem; }
.od-dir-chip {
  flex: 1; border: 1px solid #d8dfe6; border-radius: 5px; padding: 0.35rem 0.4rem;
  font-size: 0.76rem; text-align: center; background: #fff; color: #6b7783;
}
.od-dir-chip.on { border-color: #7466d8; background: #f2f0fd; color: #3f3494; font-weight: 650; }
.od-bins { margin-top: 4px; }
.od-bin-row { display: flex; align-items: center; gap: 6px; font-size: 0.7rem; color: #5d6b78; }
.od-bin-swatch { width: 22px; height: 4px; border-radius: 2px; }
.od-map-controls {
  position: absolute; left: 12px; top: 12px; z-index: 600;
  padding: 5px 9px; border-radius: 5px;
  background: rgb(255 255 255 / 94%); border: 1px solid #cfd8df;
}
.od-dir-bikes, .od-dir-passes { font-size: 0.68rem; color: #7a8794; }
.od-gap-note { margin-top: 0.5rem; padding-top: 0.5rem; border-top: 1px solid #eef2f5; }
.od-gap-row { display: flex; align-items: center; gap: 6px; font-size: 0.74rem;
              color: #5d6b78; padding: 1px 0; }
.od-gap-dash { width: 20px; height: 0; border-top: 2px dashed currentColor; }
.od-gap-dash { width: 20px; height: 2px; border-radius: 1px; opacity: 0.85; }


/* The running release, shown in the account menu. Deliberately quiet: it is
   there to be read out in a support call, not to be part of the interface. */


/* A row whose route is on its way to the trash. Applied client-side the moment
   Slet is pressed, so the answer to "did that work?" does not wait for a
   round trip and a table rebuild. The authoritative table replaces the row a
   moment later — and if the delete failed, replaces it with the row intact. */
.row-pending-delete {
    opacity: 0.4;
    transition: opacity 0.12s ease-out;
    pointer-events: none;
}
/* Second cell only — the one holding the route name. It was briefly on the
   first cell too, which put a stray "· flyttes til papirkurv…" in the
   checkbox column with nothing to attach itself to. */
.row-pending-delete td:nth-child(2)::after {
    content: " · flyttes til papirkurv…";
    font-size: 0.72rem;
    font-style: italic;
    color: #868e96;
}

/* ── Basemap control (QA-MSG-0152, aligned QA-MSG-0159) ──────────────────────
   Model Builder's icon-only tools, value for value, taken from
   `.kb-root .tool-group` and `.kb-root .map-tool` rather than re-derived — so
   the two cannot drift apart again.

   No border and no backdrop blur: Model Builder has neither, and the previous
   92%-plus-blur surface is exactly why this control read differently over
   Ortofoto than over Skærmkort. */
.map-basemap-ctl {
    position: absolute;
    top: 0.7692rem;
    right: 0.7692rem;
    z-index: 500;              /* over Leaflet panes, under Mantine overlays */
    display: flex;
    gap: 0.1538rem;
    padding: 0.2308rem;
    border-radius: 0.6154rem;
    background: rgb(255 255 255 / 96%);
    box-shadow: 0 0.0769rem 0.2308rem rgb(15 30 45 / 18%);
    pointer-events: auto;
}
.map-basemap-btn {
    height: 2.1538rem;
    padding: 0 0.5385rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: 0.4615rem;
    background: transparent;
    cursor: pointer;
    transition: background 0.12s ease;
}
.map-basemap-btn:hover { background: #eef2f5; }
/* Navy fill with a white icon, as Model Builder does it. The grey tint this
   replaces was the largest of the differences between the two controls — far
   more visible than the offsets — and was not in QA's original audit. */
.map-basemap-btn.active { background: var(--veloio-brand); }
.map-basemap-btn:focus-visible {
    outline: 2px solid #1c7ed6;
    outline-offset: 1px;
}
.map-basemap-btn .bm-icon {
    width: 1.1538rem;
    height: 1.1538rem;
    display: block;
    background-repeat: no-repeat;
    background-position: center;
    background-size: contain;
    opacity: 0.72;
}
.map-basemap-btn:hover .bm-icon { opacity: 1; }
/* The icons are background-images with a fixed dark stroke, so the active state
   inverts them rather than recolouring — the same trick `.rail-btn.active img`
   uses in Model Builder. */
.map-basemap-btn.active .bm-icon {
    opacity: 1;
    filter: brightness(0) invert(1);
}

.bm-icon.bm-map {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23212529' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14.106 5.553a2 2 0 0 0 1.788 0l3.659-1.83A1 1 0 0 1 21 4.619v12.764a1 1 0 0 1-.553.894l-4.553 2.277a2 2 0 0 1-1.788 0l-4.212-2.106a2 2 0 0 0-1.788 0l-3.659 1.83A1 1 0 0 1 3 19.381V6.618a1 1 0 0 1 .553-.894l4.553-2.277a2 2 0 0 1 1.788 0z'/%3E%3Cpath d='M15 5.764v15'/%3E%3Cpath d='M9 3.236v15'/%3E%3C/svg%3E");
}
.bm-icon.bm-ortho {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23212529' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='18' height='18' x='3' y='3' rx='2' ry='2'/%3E%3Ccircle cx='9' cy='9' r='2'/%3E%3Cpath d='m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21'/%3E%3C/svg%3E");
}
.bm-icon.bm-off {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23212529' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49'/%3E%3Cpath d='M14.084 14.158a3 3 0 0 1-4.242-4.242'/%3E%3Cpath d='M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143'/%3E%3Cpath d='m2 2 20 20'/%3E%3C/svg%3E");
}

/* ── Welcome landing and per-feature empty states ─────────────────────────────
 *
 * Translated from the approved mock-up
 * (qa/.../evidence/welcome-landing-mockup.html). The surface deliberately
 * reuses the login screen's palette and spacing: this is the first thing a
 * customer sees after signing in, and it should read as the same product they
 * just logged into rather than as a blank feature.
 *
 * The overlay sits inside #content-area (position: relative), so the top bar,
 * the sidebar and — for an empty feature — that feature's own sub-tabs all
 * stay where they are.
 */
.welcome-view {
    position: absolute;
    inset: 0;
    overflow: auto;
    /* Above Leaflet. Map panes carry z-index up to 700 and its controls up to
     * 1000, and they are NOT in their own stacking context — a pane would
     * otherwise paint straight through an empty state laid over the map.
     * Well below the modal layer (7500). */
    z-index: 1200;
    background:
        radial-gradient(circle at 88% 4%, rgba(32, 200, 168, 0.12), transparent 28rem),
        linear-gradient(145deg, #f7fafc 0%, #edf4f7 56%, #f5f8fa 100%);
}

.welcome {
    max-width: 70rem;
    margin: 0 auto;
    padding: clamp(1.75rem, 5vw, 4.5rem) clamp(1.4rem, 6vw, 6rem) 4rem;
    color: #102d4f;
}

.welcome-eyebrow {
    color: #20a98f;
    font-size: 0.7rem;
    font-weight: 800;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    margin-bottom: 0.75rem;
}

.welcome-h1 {
    margin: 0;
    color: #08254a;
    font-size: clamp(1.75rem, 4vw, 2.9rem);
    letter-spacing: -0.035em;
    line-height: 1.08;
}

.welcome-lead {
    max-width: 44rem;
    color: #5b7087;
    font-size: 1rem;
    line-height: 1.65;
    margin: 1rem 0 1.75rem;
}

.welcome-intro {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-bottom: 1.75rem;
}

.welcome-mark {
    flex: 0 0 auto;
    width: 3rem;
    height: 3rem;
    border-radius: 50%;
    display: grid;
    place-items: center;
    color: white;
    background: #20a98f;
    font-size: 1.45rem;
    box-shadow: 0 0.45rem 1.1rem rgba(32, 169, 143, 0.21);
}

.welcome-note {
    color: #5b7087;
    font-size: 0.82rem;
    line-height: 1.4;
}

.welcome-note strong {
    display: block;
    color: #173b5e;
    font-size: 0.88rem;
}

.welcome-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14.5rem, 1fr));
    gap: 0.9rem;
}

.welcome-card {
    min-height: 12rem;
    padding: 1.25rem;
    background: #fff;
    border: 1px solid #d8e1e8;
    border-radius: 0.9rem;
    box-shadow: 0 0.5rem 1.5rem rgba(16, 45, 79, 0.05);
    border-top: 4px solid var(--accent);
}

.welcome-card-head {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    margin-bottom: 0.75rem;
}

/* The icon tile. The mask inside it is tinted with background-color, which is
 * how every other Veloio feature icon is coloured — see .sidebar-icon. */
.welcome-card-icon {
    flex: 0 0 auto;
    width: 2.15rem;
    height: 2.15rem;
    border-radius: 0.62rem;
    display: grid;
    place-items: center;
    background: color-mix(in srgb, var(--accent) 12%, white);
}

.welcome-card-icon .sidebar-icon {
    width: 1.25rem;
    height: 1.25rem;
    background-color: var(--accent);
}

.welcome-card-name {
    margin: 0;
    color: #173b5e;
    font-size: 1rem;
    font-weight: 650;
}

.welcome-card-text {
    margin: 0;
    color: #63788c;
    font-size: 0.82rem;
    line-height: 1.55;
}

/* Early access is stated, not implied. O/D is real and grantable but
 * unfinished, and the customer was sold it on that basis. */
.welcome-badge {
    margin-left: auto;
    padding: 0.15rem 0.45rem;
    border-radius: 0.35rem;
    background: color-mix(in srgb, var(--accent) 12%, white);
    color: var(--accent);
    font-size: 0.62rem;
    font-weight: 800;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    white-space: nowrap;
}

.welcome-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1.1rem;
    margin-top: 1.75rem;
    padding: 1.1rem 1.25rem;
    border: 1px solid #cfe0e5;
    border-radius: 0.75rem;
    background: rgba(255, 255, 255, 0.72);
}

.welcome-footer-text {
    margin: 0;
    color: #5b7087;
    font-size: 0.82rem;
    line-height: 1.5;
}

.welcome-cta {
    flex: 0 0 auto;
    border: 0;
    border-radius: 0.5rem;
    padding: 0.7rem 1.05rem;
    color: #fff;
    background: #08254a;
    font-weight: 700;
    font-size: 0.82rem;
    cursor: pointer;
}

.welcome-cta:hover { background: #0d3665; }

/* The per-feature empty state carries that feature's accent and icon so the
 * customer can see which module they are standing in, not just that it is
 * empty. */
.welcome-empty-head {
    display: flex;
    align-items: center;
    gap: 0.85rem;
}

.welcome-empty-head .welcome-card-icon {
    width: 2.9rem;
    height: 2.9rem;
    border-radius: 0.8rem;
}

.welcome-empty-head .welcome-card-icon .sidebar-icon {
    width: 1.7rem;
    height: 1.7rem;
}

.welcome-h1-empty { font-size: clamp(1.5rem, 3.2vw, 2.3rem); }

@media (max-width: 40.6rem) {
    .welcome { padding: 1.7rem 1rem 2.6rem; }
    .welcome-footer { flex-direction: column; align-items: flex-start; }
    .welcome-cta { width: 100%; }
}

/* Sammenligning: the route the user picked.
 *
 * Matches the dark casing the map puts on the same route, so the table and the
 * map agree about what is selected. A left accent bar rather than a background
 * alone, because the first cell already carries the vejindex colour chip and a
 * strong row tint behind it would read as a second, meaningless colour. */
tr.rank-row-selected {
    background: #eef1f4;
    box-shadow: inset 3px 0 0 0 #1a1d20;
}
tr.rank-row-selected td {
    font-weight: 600;
}

/* Street View camera cone on the Tilstandsoverblik map.
 *
 * Sits under the condition marker, which keeps its colour-coded fill: the cone
 * says where you are LOOKING, the circle says what the surface is like there.
 * Hidden until the panorama reports a pose, so it never points at a guess. */
.rq-sv-cone-wrap { background: none !important; border: none !important; }
.rq-sv-cone { pointer-events: none; }
.rq-sv-cone[data-hidden] { display: none; }
.rq-sv-cone svg {
    display: block;
    /* Rotation is written by the pose listener; only the easing lives here, so
     * a slow pan reads as a turn rather than a jump. Short, because the cone
     * must not lag a fast drag. */
    transition: transform 90ms linear;
}

/* ── Nyt i VELOIO — release notes ─────────────────────────────────────────
 *
 * The version sits at the foot of the account menu, quiet until there is
 * something to say. The marker uses the accent, NOT green: green is the good
 * end of the road-condition ramp, and a green dot in the chrome would invite
 * the same misreading the Street View cone colour was picked to avoid. */
.account-menu-version {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    width: 100%;
    background: none;
    border: none;
    border-top: 1px solid #e9ecef;
    margin-top: 0.35rem;
    padding: 0.55rem 0.85rem;
    font: inherit;
    font-size: 0.76rem;
    color: #868e96;
    cursor: pointer;
    text-align: left;
}
.account-menu-version:hover { background: #f1f3f5; color: #343a40; }
.account-version-new {
    background: #c9186b;
    color: #fff;
    font-size: 0.62rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    padding: 0.08rem 0.4rem;
    border-radius: 3px;
}

.release-notes-panel { max-width: 46rem; padding: 0; }
/* `display` is set inline to block by the callback, matching the admin panel.
 * Setting it to flex there laid the header out as a row and collapsed the
 * close button to 0x0 — visible in the DOM, impossible to click. */
.release-notes-panel .admin-panel-header { padding: 1.4rem 1.5rem 0.9rem; }
.release-notes-body { padding: 0 1.5rem 1rem; overflow-y: auto; }
.release-notes-body h1 { font-size: 1.35rem; margin: 0.2rem 0 0.9rem; }
.release-notes-body h2 {
    font-size: 1rem;
    margin: 1.6rem 0 0.2rem;
    padding-bottom: 0.3rem;
    border-bottom: 1px solid #e9ecef;
    color: #495057;
}
.release-notes-body h3 { font-size: 0.95rem; margin: 1.1rem 0 0.3rem; }
.release-notes-body p { margin: 0.4rem 0; line-height: 1.6; font-size: 0.88rem; }
.release-notes-body blockquote {
    margin: 0.9rem 0;
    padding: 0.7rem 1rem;
    background: #fdf6e7;
    border-left: 3px solid #a16207;
    font-size: 0.85rem;
}
.release-notes-body table { border-collapse: collapse; font-size: 0.85rem; margin: 0.8rem 0; }
.release-notes-body td { padding: 0.3rem 0.9rem 0.3rem 0; vertical-align: top; }
.release-notes-history {
    padding: 1rem 1.5rem 1.5rem;
    border-top: 1px solid #e9ecef;
}
.release-notes-history-title {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: #868e96;
    margin-bottom: 0.5rem;
}
.release-note-link {
    display: block;
    background: none;
    border: none;
    padding: 0.35rem 0;
    font: inherit;
    font-size: 0.83rem;
    color: #c9186b;
    cursor: pointer;
    text-align: left;
}
.release-note-link:hover { text-decoration: underline; }

/* ── Vejbeskaffenhed → Database table ─────────────────────────────────────
 *
 * These rules replace inline styles that were serialised onto every cell.
 * Measured before the change: the same `_td` dict appeared 418 times (38
 * routes x 11 cells) and accounted for 50,793 of the table's 120,699 bytes —
 * 42% of a payload re-sent on every rebuild. Sent once now. */
.rq-table { width: 100%; border-collapse: collapse; font-size: 0.8rem; }
.rq-th {
    text-align: left;
    padding: 0.4rem 0.6rem;
    color: #495057;
    border-bottom: 2px solid #dee2e6;
    font-size: 0.72rem;
    white-space: nowrap;
}
.rq-td {
    padding: 0.4rem 0.6rem;
    border-bottom: 1px solid #f1f1f1;
    font-variant-numeric: tabular-nums;
}
.rq-td-name { font-weight: 600; }
.rq-td-dim { color: #868e96; }
.rq-td-nowrap { white-space: nowrap; }
.rq-td-size { color: #495057; white-space: nowrap; }

/* Status pills and row actions in the Database table.
 *
 * These replace dmc.Badge and dmc.Button. Mantine builds each instance's
 * styles at mount, and there were 76 of them per render — measured at ~420 ms
 * per row against 3.9 s for a three-row table. The look is deliberately the
 * same "light" variant: tinted background, saturated text. */
.rq-badge {
    display: inline-block;
    padding: 0.1rem 0.5rem;
    border-radius: 999px;
    font-size: 0.68rem;
    font-weight: 700;
    line-height: 1.5;
    letter-spacing: 0.01em;
    white-space: nowrap;
}
.rq-badge-gray  { background: #f1f3f5; color: #495057; }
.rq-badge-blue  { background: #e7f5ff; color: #1971c2; }
.rq-badge-teal  { background: #e6fcf5; color: #087f5b; }
.rq-badge-red   { background: #fff5f5; color: #c92a2a; }

.rq-btn {
    background: none;
    border: 0;
    border-radius: 4px;
    padding: 0.12rem 0.45rem;
    font: inherit;
    font-size: 0.72rem;
    font-weight: 600;
    cursor: pointer;
}
.rq-btn-red  { color: #c92a2a; }
.rq-btn-blue { color: #1971c2; }
.rq-btn:hover { background: #f1f3f5; }
.rq-btn:focus-visible { outline: 2px solid #1971c2; outline-offset: 1px; }

/* Status pill in the Database table. Replaces dmc.Badge, which is no longer a
 * component per row — see the cell builder in callbacks.py. Deliberately the
 * same "light" look: tinted ground, saturated text. */
.rq-badge {
    display: inline-block;
    padding: 0.1rem 0.5rem;
    border-radius: 999px;
    font-size: 0.68rem;
    font-weight: 700;
    line-height: 1.5;
    white-space: nowrap;
}
.rq-badge-gray { background: #f1f3f5; color: #495057; }
.rq-badge-blue { background: #e7f5ff; color: #1971c2; }
.rq-badge-teal { background: #e6fcf5; color: #087f5b; }
.rq-badge-red  { background: #fff5f5; color: #c92a2a; }
.rq-td-action { text-align: right; white-space: nowrap; }

/* The sidebar gate's browser copy (callbacks.py, "The same rule in the browser")
   names each module a user may not see in the sidebar's class; these rules hide
   its button until, and after, the server gate does the same. Generated from
   layout.SIDEBAR_MODULE_ORDER — a test checks every module has its rule. */
.left-sidebar.gate-hide-mobility [id='{"index":"mobility","type":"module-btn"}']{display:none}
.left-sidebar.gate-hide-road [id='{"index":"road","type":"module-btn"}']{display:none}
.left-sidebar.gate-hide-od [id='{"index":"od","type":"module-btn"}']{display:none}
.left-sidebar.gate-hide-greenwave [id='{"index":"greenwave","type":"module-btn"}']{display:none}
.left-sidebar.gate-hide-modelbuilder [id='{"index":"modelbuilder","type":"module-btn"}']{display:none}
.left-sidebar.gate-hide-signalanalysis [id='{"index":"signalanalysis","type":"module-btn"}']{display:none}
.left-sidebar.gate-hide-accident [id='{"index":"accident","type":"module-btn"}']{display:none}
.left-sidebar.gate-hide-cyclistcommunication [id='{"index":"cyclistcommunication","type":"module-btn"}']{display:none}
.left-sidebar.gate-hide-ai [id='{"index":"ai","type":"module-btn"}']{display:none}
.left-sidebar.gate-hide-settings [id='{"index":"settings","type":"module-btn"}']{display:none}

/* A junction kept without a stop line: the planner's timings survive a redraw,
   and the count says so until the list in Signaler can offer to re-place it. */
.signaler-sheet-unplaced {
  margin-left: .5rem;
  padding: .05rem .45rem;
  border: 1px solid var(--veloio-coral, #d95f4b);
  border-radius: 999px;
  color: var(--veloio-coral, #d95f4b);
  font-size: .78em;
  font-weight: 600;
  white-space: nowrap;
}

/* The sheet, and the status line above it. A column inside #signaler-split,
   whose flex basis the resize handle does not touch — it only sets the width of
   #signaler-map-wrap — so the sheet keeps taking the rest. */
.signaler-panel-col {
  flex: 1 1 auto;
  min-width: 420px;
  height: 100%;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: .35rem;
}

/* the column already carries the minimum, and repeating it here would stop the
   sheet ever being narrower than the column it sits in */
.signaler-panel-col > .signaler-panel {
  min-width: 0;
  flex: 1 1 auto;
}

/* What the next click does, and what is left to decide. Always present while a
   route is open: a line that comes and goes is a line nobody learns to read. */
.signaler-status:empty { display: none; }
.signaler-status {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .8rem;
  flex-wrap: wrap;
  padding: .35rem .7rem;
  border: 1px solid #d7dee5;
  border-radius: .35rem;
  background: #f1f5f9;
  color: #334155;
  font-size: .85em;
}

.signaler-status-left {
  color: #8a3423;
  white-space: nowrap;
}

/* armed to re-place a junction — the one state the planner has to get out of */
.signaler-status-armed {
  background: var(--veloio-coral-soft, #fdeae6);
  border-color: var(--veloio-coral, #d95f4b);
  color: #8a3423;
}

/* the mode control is the primary thing in the toolbar, so it does not shrink
   away behind the pickers when the window is narrow */
.signaler-tool { flex: 0 0 auto; }
.signaler-row.unplaced td { background: var(--veloio-coral-soft, #fdeae6); }
.signaler-letter-badge.unplaced { background: var(--veloio-coral, #d95f4b); color: #fff; }
.signaler-unplaced-note { color: #8a3423; font-size: .85em; }

/* ── Grøn bølge · Ruter ─────────────────────────────────────────────────────
   The service's own route list. Sized in rem like the rest of the app, so it
   scales with the html font-size clamp rather than fighting it.            */
.gwr-view {
    padding: 0.9rem 1.2rem;
    overflow-y: auto;
    height: 100%;
}
.gwr-head { margin-bottom: 0.9rem; }
.gwr-title {
    margin: 0 0 0.25rem;
    font-size: 1.05rem;
    font-weight: 650;
    color: var(--ink, #10242c);
}
.gwr-intro { max-width: 46rem; display: block; }

.gwr-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.86rem;
}
.gwr-table th {
    text-align: left;
    font-weight: 600;
    font-size: 0.72rem;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: #6b7f86;
    padding: 0 0.6rem 0.45rem;
    border-bottom: 1px solid #dfe8ea;
    white-space: nowrap;
}
.gwr-table td {
    padding: 0.55rem 0.6rem;
    border-bottom: 1px solid #eef3f4;
    vertical-align: middle;
}
.gwr-row:hover td { background: #f6fbfa; }
.gwr-name { font-weight: 600; color: var(--ink, #10242c); }
.gwr-dim  { color: #5c7076; white-space: nowrap; }
/* Figures line up down the column; the app uses tabular numerals wherever
   numbers are compared row to row. */
.gwr-num  { font-variant-numeric: tabular-nums; }
.gwr-outstanding { color: #b26a00; font-size: 0.78rem; }
.gwr-action { text-align: right; white-space: nowrap; }

/* A removed route stays listed so it can be brought back, but must not read as
   one that is live: muted, with the state said in words and not by colour
   alone. */
.gwr-row.removed td { opacity: 0.6; }
.gwr-flag {
    margin-left: 0.5rem;
    padding: 0.05rem 0.4rem;
    border-radius: 0.6rem;
    background: #f1dede;
    color: #8a3d3d;
    font-size: 0.68rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

@media (max-width: 40rem) {
    .gwr-view { padding: 0.7rem; }
    .gwr-table { font-size: 0.8rem; }
    .gwr-table th:nth-child(2), .gwr-table td:nth-child(2) { display: none; }
}

/* A stretch still in the build queue. Amber rather than the removed row's red:
   nothing is wrong, it is simply not ready — and the title says what to check. */
.gwr-flag.queued {
    background: #fdf0d9;
    color: #8a5b00;
    cursor: help;
}


/* ── Grøn bølge · Signaler sheet ───────────────────────────────────────────
   The header row stays put while the sheet scrolls. With eight columns and a
   narrow panel the planner scrolls right to reach Varig., and the names
   (Kryds, AG, Stopstreg, …) scrolled away with them — leaving a grid of
   numbers with nothing to say which was which. */
.signaler-sheet thead th {
    position: sticky;
    top: 0;
    z-index: 3;
    background: #fff;
    /* `position: sticky` drops the cell's own borders out of the painted
       layer, so the rule under the header has to be drawn as a shadow. */
    box-shadow: inset 0 -1px 0 #dfe8ea;
}

/* The row whose stop line is selected on the map. A focus ring on one input was
   the only sign before, and with the sheet scrolled right that input was often
   off-screen entirely. */
.signaler-sheet tr.sig-row-selected > td {
    background: #e8f1fd;
}
.signaler-sheet tr.sig-row-selected > td:first-child {
    box-shadow: inset 3px 0 0 #2563eb;
}

/* Vejnavn / side is the stop line's own name and is read-only here: it is set
   in Modelbygger, where the planner can see the stop line while naming it. */
.signaler-aname-cell { white-space: nowrap; }
.signaler-aname { color: #44555b; }

/* "Vis" — the narrowest column, and it must not steal width from the route
   name. Same control and same meaning as Mobility Flow's database view. */
.gwr-show-cell {
    width: 2.5rem;
    text-align: center;
}
