 body:has(.wc-login-e110ca0)::before {
     content: "''";
     position: absolute;
     top: 0;
     inset-inline-start: 0;
     width: 100%;
     height: 100%;
     background: white url("/Login-background.jpg") repeat fixed center center / cover;
     z-index: -1;
 }

/* The login card is a viewport-relative width so the background art stays visible. */
.wc-dialog-e110ca0 {
    width: 80vw;
}

/* The enrollment QR arrives as inline SVG with its own fixed dimensions. */
.wc-qr-e110ca0 {
    display: flex;
    justify-content: center;
    margin-block: 1rem;
}

.wc-secret-e110ca0 {
    font-family: var(--bs-font-monospace);
    word-break: break-all;
    user-select: all;
}


body:has(.wc-recover-619f671)::before {
    content: "''";
    position: absolute;
    top: 0;
    inset-inline-start: 0;
    width: 100%;
    height: 100%;
    background: white url("/Login-background.jpg") repeat fixed center center / cover;
    z-index: -1;
}

.wc-dialog-619f671 {
    width: 80vw;
    max-width: 480px;
}


/* The shared mantiq_utils Multiselect as a facet filter. Its trigger shell is a
   Bootstrap .form-control.form-select and its portaled menu a .dropdown-menu, so
   the field and dropdown skins in bins/cloud/styles/theme/ paint both; below is
   only what those can't express. The menu lives under <body>, so `.filterMenu`
   reaches it through `menu_class`. Bootstrap's own classes are reached through
   :global() — stylance must not hash them. */
.wc-filterSelect-14b3dff {
    width: 100%;
}

/* The trigger is a .btn (mono caps from the button skin), sized to the
   sidebar's small search field beside it. Four classes deliberately: the theme
   files' own `.btn` block lands at (0,3,2) inside its donut and takes these
   tokens back at anything lower. */
.wc-filterSelect-14b3dff .form-control.form-select .btn {
    --bs-btn-padding-y: 0.38rem;
    --bs-btn-padding-x: 0.6rem;
    --bs-btn-font-size: 0.7rem;
}

/* Caret cue that the trigger opens a menu; flips while the menu is open. Drawn
   on the button, so the shell's stock chevron goes. The extra
   .form-control.form-select hop outranks the component's own
   `button.dropdownToggle::after` positioning rule (an unrotated
   translateY(-50%)), which would otherwise win the transform. The chevron is
   a clip-path, not logical borders: inline borders flip under RTL while a
   rotation stays physical, which would lay the arrow sideways. */
.wc-filterSelect-14b3dff .form-select {
    background-image: none;
}

.wc-filterSelect-14b3dff .form-control.form-select button::after {
    content: "";
    position: absolute;
    inset-inline-end: 0.65rem;
    inset-block-start: 50%;
    width: 0.55rem;
    height: 0.4rem;
    background: var(--fl-faint);
    clip-path: polygon(50% 100%, 0% 38%, 14% 22%, 50% 66%, 86% 22%, 100% 38%);
    transform: translateY(-50%);
    transition: transform var(--fl-dur-fast) var(--fl-ease);
}

.wc-filterSelect-14b3dff .form-control.form-select button[aria-expanded="true"]::after {
    transform: translateY(-50%) rotate(180deg);
}

/* Focus lands on the inner button, not the shell: the field focus ring goes on
   the shell, and the vendored button's own Bootstrap-blue one goes. The extra
   .form-select hop is specificity, not targeting — the theme files' resting
   `.form-control` border sits at (0,3,2) and keeps its colour at anything
   lower. */
.wc-filterSelect-14b3dff .form-control.form-select:focus-within {
    border-color: var(--fl-copper);
    box-shadow: 0 0 0 0.2rem rgba(var(--fl-copper-rgb), 0.25);
}

.wc-filterSelect-14b3dff .form-control.form-select button:focus {
    outline: none;
    box-shadow: none;
}

/* The portaled menu: lifted over the page, mono type. */
.wc-filterMenu-14b3dff {
    box-shadow: 0 18px 40px rgba(0, 0, 0, 0.55);
    color: var(--fl-dim);
    font-family: var(--fl-mono);
    font-size: 0.72rem;
}

/* Pin the component's check-mark column tight — with the table's auto layout
   it otherwise stretches and shoves every row's content toward the middle. */
.wc-filterMenu-14b3dff td:first-child {
    width: 1.6rem;
    text-align: center;
}

.wc-filterMenu-14b3dff a {
    color: inherit;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}


/* erp's `company_logo.css` values verbatim: height-capped, natural width — a wide
   logo stays wide, it is never squeezed into a square. */
.wc-companyLogo-5cf487b {
    display: inline-block;
    vertical-align: middle;
    max-height: 45px;
}


.wc-chartContainer-4126477 {
    width: 100%;
    height: 100%;
    max-height: 500px;
    padding-bottom: 4.75rem;
    overflow: clip;

    .wc-chart-4126477 {
        display: flex;
        height: 100%;
        position: relative;
        padding-inline-start: var(--space-12);

        .wc-yAxis-4126477 {
            position: absolute;
            inset-inline-start: 0;
            top: 0;
            bottom: 0;
            width: 50px;
            display: flex;
            flex-direction: column;
            justify-content: space-between;
            align-items: flex-end;
            padding-inline-end: 10px;
        }

        .wc-yLabel-4126477 {
        }

        .wc-bars-4126477 {
            flex: 1;
            display: flex;
            align-items: flex-end;
            gap: var(--space-1);
        }

        .wc-barWrapper-4126477 {
            flex: 1;
            display: flex;
            flex-direction: row;
            align-items: end;
            justify-content: center;
            position: relative;
            height: 100%;

            .wc-bar-4126477 {
                width: 100%;
                height: 0%;
                max-width: 10vw;
                background-color: var(--bs-danger);
                transition: all var(--transition-slow);
                min-height: 2px;
                border-radius: var(--bs-border-radius) var(--bs-border-radius) 0
                    0;
            }

            .wc-bar-4126477.wc-selected-4126477 {
                background-color: #991b1b;
            }

            .wc-barValue-4126477 {
                display: none;
            }

            .wc-barLabel-4126477 {
                position: absolute;
                transform: rotate(-45deg);
                white-space: nowrap;
                bottom: -3.5rem;
                inset-inline-start: 50%;
                margin-inline-start: -4rem;
                transform-origin: center;
                color: var(--bs-secondary);
            }

            .wc-barLabel-4126477.wc-hideLabel-4126477 {
                display: none;
            }

            .wc-barLabel-4126477.wc-isMonday-4126477 {
                color: var(--bs-body-color);
                font-weight: bold;
            }

            &:hover {
                font-weight: bold;
                z-index: 1;

                .wc-bar-4126477 {
                    background-color: var(--bs-danger-bg-subtle);
                    border: solid var(--bs-danger-border-subtle)
                        var(--bs-border-width);
                }

                .wc-barValue-4126477,
                .wc-barLabel-4126477 {
                    position: absolute;
                    display: block;
                    inset-inline-start: auto;
                    inset-inline-end: 0;
                    transform: translateX(100%);
                    z-index: 2;
                    white-space: nowrap;
                    padding: var(--space-1);
                    background-color: var(--bs-secondary-bg-subtle);
                    border: solid var(--bs-secondary-border-subtle)
                        var(--bs-border-width);
                    border-radius: var(--bs-border-radius);
                }

                .wc-barLabel-4126477.wc-hideLabel-4126477 {
                    display: block;
                    color: var(--bs-body-color);
                }

                .wc-barLabel-4126477.wc-isMonday-4126477 {
                    font-weight: 700;
                }

                .wc-barValue-4126477 {
                    top: 0px;
                }

                .wc-barLabel-4126477 {
                    bottom: 2rem;
                }
            }

            &.wc-secondHalf-4126477:hover {
                .wc-barValue-4126477,
                .wc-barLabel-4126477 {
                    transform: none;
                    margin-inline-end: 100%;
                }
            }
        }
    }
}


.wc-chartContainer-49b824f {
    height: 500px;
}


.wc-chart-53f6d17 {
    height: 200px;
}

.wc-userSearchField-53f6d17 {
    min-width: 10ex;
}

.wc-exceptionMessage-53f6d17 {
    max-width: 75%;
    overflow: hidden;
    text-overflow: ellipsis;
}


.wc-noteSearchField-828d682 {
    min-width: 10ex;
}

.wc-noteCell-828d682 {
    max-width: 35%;
    overflow: hidden;
    text-overflow: ellipsis;
}

.wc-messageCell-828d682 {
    max-width: 35%;
    overflow: hidden;
    text-overflow: ellipsis;
}


.wc-expandRows-ea965e8 {
    .wc-query-ea965e8 {
        white-space: pre;
    }
}

.wc-compactRows-ea965e8 {
    .wc-query-ea965e8 {
        max-height: 1.5em;
        display: block;
        overflow: hidden;
        text-overflow: ellipsis;
    }
}


.wc-expandRows-b43b1fc {
    .wc-query-b43b1fc {
        white-space: pre;
    }
}

.wc-compactRows-b43b1fc {
    .wc-query-b43b1fc {
        max-height: 1.5em;
        display: block;
        overflow: hidden;
        text-overflow: ellipsis;
    }
}


.wc-expandRows-ae67231 {
    .wc-query-ae67231 {
        white-space: pre;
    }
}

.wc-compactRows-ae67231 {
    .wc-query-ae67231 {
        max-height: 1.5em;
        display: block;
        overflow: hidden;
        text-overflow: ellipsis;
    }
}


/* `.page-wrap` paints its hairline-grid backdrop at z 0 and clips overflow (see
   bins/cloud/styles/utilities.css), so the page body must sit above it and own its
   scrolling. */
.wc-pageBody-c7cffb7 {
    position: relative;
    z-index: 1;
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    scrollbar-gutter: stable;
}

/* Inlined from erp's shared PageHeaderBreadcrumb component (cloud has no
   layout crate; the breadcrumb markup lives directly in read.rs). */
.wc-pageHeaderBreadcrumb-c7cffb7 {
    font-size: 1.75rem;
    --bs-breadcrumb-divider: var(--pageHeaderDivider, ">");

    a:not(:hover) {
        text-decoration: none;
    }

    li > svg[role="graphics-symbol"],
    li > a > svg[role="graphics-symbol"] {
        margin-inline-end: var(--space-2);
    }

    li > a > img {
        margin-inline-end: var(--space-2);
    }
}

table.wc-bugDetails-c7cffb7 {
    th {
        white-space: nowrap;
    }

    td {
        width: 100%;
    }
}

.wc-stackTrace-c7cffb7 {
    font-family: monospace;
    margin-bottom: 0;
}

.wc-copyIcon-c7cffb7 {
    position: fixed;
    padding-inline-start: var(--space-2);
    margin-top: var(--space-1);
    opacity: 0;
    transition: opacity 0.3s ease-in-out;

    a:hover & {
        opacity: 1;
    }
}


/* `.page-wrap` paints its hairline-grid backdrop at z 0 (see
   bins/cloud/styles/utilities.css) and clips overflow, so the tab bar and tab
   content must sit above it and own their scrolling. */
.wc-tabBar-42bccff {
    position: relative;
    z-index: 1;
}

.wc-tabContent-42bccff {
    position: relative;
    z-index: 1;
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    /* Reserve the scrollbar's width up front: without this, the vertical
       scrollbar appearing shrinks the content box after layout and full-width
       children overflow by exactly the scrollbar width → a useless horizontal
       scrollbar. */
    scrollbar-gutter: stable;
}


.wc-deviceImage-f0f040d {
    max-width: 100%;
    object-fit: cover;
}


/* Inline logo container inside the device form's company SingleSelect options —
   erp's `company_select.css` `.iconContainer` values: fixed width, height-capped,
   contained (never cropped). */
.wc-logoThumb-1211d37 {
    display: inline-block;
    text-align: center;
    margin-inline-end: 0.35em;

    img,
    svg {
        width: 1.5rem;
        max-height: 1.5rem;
        object-fit: contain;
    }
}


.wc-noDashboard-1db1697 {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 4rem 1rem;
    text-align: center;
    color: #8a8a8a;
}

.wc-noDashboardTitle-1db1697 {
    font-size: 1.1rem;
    color: #ccc;
}

.wc-noDashboardHint-1db1697 {
    max-width: 34rem;
    font-size: 0.9rem;
}


/* Wingman's root is `position:absolute; inset:0`, so it fills this relative flex-fill box below
   the playback controls. */
.wc-replayWingmanWrap-10dca00 {
    flex-grow: 1;
    position: relative;
    overflow: auto;
    min-height: 0;
}

/* Full-viewport column under the navbar: the session picker sits on top and the
   replay Wingman takes the rest. */
.wc-historyPage-10dca00 {
    height: calc(100vh - 57px);
    display: flex;
    flex-direction: column;
}

/* The recording picker reads as a form control, not a full-width band. */
.wc-sessionPicker-10dca00 {
    max-width: 32rem;
}


.wc-deviceUiContainer-8d438ee {
    flex-grow: 1;
    height: calc(100vh - 57px);
    overflow: hidden;
    transform: translateY(0);
    position: relative;
    /* Flex row: the optional RemotePilotPanel docks as a left sidebar, the .wingmanEmbed wrapper
       fills the rest. On the plain Dashboard there's no panel, so the wrapper takes the full width. */
    display: flex;
    flex-direction: row;
}

/* Wingman's root is `position:absolute; inset:0`, so it fills its nearest positioned ancestor:
   this relative flex-fill box confines it to the area beside the pilot panel instead of covering
   the whole container. */
.wc-wingmanEmbed-8d438ee {
    position: relative;
    flex: 1 1 0;
    min-width: 0;
    min-height: 0;
    overflow: hidden;
}


/* Fleet updates page — table specifics layered over the shared console theme. */

/* Single full-width column (this page is a table, not the console's master-detail
   split — `.list-col` would clamp it to ~320px). */
.wc-fullCol-2b8fb9e {
    flex: 1 1 auto;
    min-width: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

.wc-pathMono-2b8fb9e {
    font-family: var(--fl-mono);
    font-size: 0.78rem;
    max-width: 22rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    display: inline-block;
    vertical-align: bottom;
}

.wc-subtle-2b8fb9e {
    color: var(--fl-faint);
    font-size: 0.75rem;
}

.wc-releaseSelect-2b8fb9e {
    background: transparent;
    color: var(--fl-dim);
    border: 1px solid var(--fl-hair);
    border-radius: 6px;
    padding: 0.25rem 0.45rem;
    font-size: 0.82rem;
    max-width: 14rem;
}

.wc-releaseSelect-2b8fb9e:disabled {
    opacity: 0.5;
}

/* Connected agent — green live dot. */
.wc-dotLive-2b8fb9e {
    background: var(--fl-green);
    box-shadow: 0 0 0 3px rgba(var(--fl-green-rgb), 0.18);
}

.wc-nameCell-2b8fb9e {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}


/* Operator pilot panel: a fixed-width control sidebar docked left of the full-viewport Wingman
   telemetry dashboard (see device_ui.css — deviceUiContainer is a flex row, the panel is the first
   child, Wingman fills the rest). Dark to match the dashboard. */
.wc-rpPanel-74c77b4 {
    flex: 0 0 16rem;
    height: 100%;
    box-sizing: border-box;
    overflow-y: auto;
    padding: 0.75rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    background: #11151c;
    color: #e8edf2;
    border-inline-end: 1px solid #2a323d;
    font-size: 0.95rem;
}

.wc-rpPanel-74c77b4 h3 {
    margin: 0;
    font-size: 0.95rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: #cc987a;
}

.wc-rpRow-74c77b4 {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    align-items: center;
}

.wc-rpRow-74c77b4 input {
    flex: 1 1 5rem;
    min-width: 0;
    padding: 0.3rem 0.45rem;
    border-radius: 0.4rem;
    border: 1px solid #2a323d;
    background: #0b0e12;
    color: #e8edf2;
}

.wc-rpPanel-74c77b4 button {
    flex: 1 1 auto;
    padding: 0.4rem 0.6rem;
    border-radius: 0.45rem;
    border: 1px solid #2a323d;
    background: #1b2230;
    color: #e8edf2;
    cursor: pointer;
    transition: background-color var(--fl-dur-fast) var(--fl-ease), opacity var(--fl-dur-fast) var(--fl-ease);
}

.wc-rpPanel-74c77b4 button:hover:not(:disabled) {
    background: #283142;
}

.wc-rpPanel-74c77b4 button:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

/* SAFE STATE / TRIP — always-available safety actions, visually distinct. */
.wc-rpSafe-74c77b4 {
    background: #7a1f1f;
    border-color: #b33;
    color: #fff;
    font-weight: 700;
}

.wc-rpSafe-74c77b4:hover:not(:disabled) {
    background: #9b2a2a;
}

.wc-rpStatus-74c77b4 {
    margin: 0;
    min-height: 1.1em;
    font-size: 0.85rem;
    word-break: break-word;
}

.wc-rpOffline-74c77b4 {
    color: var(--bs-danger, #e0563f);
    font-weight: 600;
}


/* Foiler "Console" sidebar row: glass panel, copper accent on hover/selection, mono meta.
   Inherits the --fl-* palette from .dashboard. */

/* Row + (for a selected device with no map marker) the expanded info card below it. The
   card must live outside .row — its `overflow: hidden` would clip anything inside. */
.wc-item-b0cdb5e {
    display: flex;
    flex-direction: column;
    gap: 0.45rem;
}

.wc-row-b0cdb5e {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.6rem;
    width: 100%;
    padding: 0.65rem 0.75rem;
    text-align: start;
    border: 1px solid var(--fl-panel-bd);
    border-radius: 0.85rem;
    background: var(--fl-panel);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
    color: var(--fl-text);
    overflow: hidden;
    transition: border-color var(--fl-dur) var(--fl-ease), background-color var(--fl-dur) var(--fl-ease), box-shadow var(--fl-dur) var(--fl-ease), transform var(--fl-press) var(--fl-ease);
}

/* The selectable area (thumb + name + live meta). A transparent, reset button so the whole
   left of the row drives the shared map selection, while the cockpit link stays a sibling
   (no nested interactive elements). */
.wc-selectArea-b0cdb5e {
    display: flex;
    align-items: center;
    gap: 0.8rem;
    flex: 1 1 auto;
    min-width: 0;
    padding: 0;
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    text-align: start;
    cursor: pointer;
}

/* Online-only "Remote" pill: the cockpit entry point, shown only for connected devices.
   In flow — the name and the meta ellipse against its real width, so a short locale
   costs nothing and a wide one only pays on its own row. */
.wc-cockpit-b0cdb5e {
    flex: 0 0 auto;
    align-self: center;
    display: inline-flex;
    align-items: center;
    line-height: 1;
    padding: 0.24rem 0.5rem;
    /* The 0.14em tracking trails the last glyph; widen the start padding to match
       so the label sits optically centred. */
    padding-inline-start: calc(0.5rem + 0.14em);
    border-radius: 0.5rem;
    border: 1px solid var(--fl-copper);
    background: var(--fl-key-bg);
    color: var(--fl-copper);
    font-family: var(--fl-mono);
    font-size: 0.6rem;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    text-decoration: none;
    white-space: nowrap;
    transition: background-color var(--fl-dur) var(--fl-ease), color var(--fl-dur) var(--fl-ease);
}

.wc-cockpit-b0cdb5e[aria-disabled="true"] {
    border-color: var(--fl-hair);
    color: var(--fl-faint);
}

.wc-cockpit-b0cdb5e:not([aria-disabled="true"]):hover {
    background: var(--fl-copper);
    color: #0b0e12;
}

/* Entrance: the roster resolves in one go, so without this the whole fleet snaps into
   existence at once. `backwards` (not `both`) is deliberate — `both` would keep the final
   keyframe applied afterwards, and an animation's `transform: none` outranks the `:active`
   press below. `backwards` only holds the *first* keyframe during the delay and then lets
   the ordinary cascade take over again. */
.wc-row-b0cdb5e {
    animation: rowIn var(--fl-dur-slow) var(--fl-ease) backwards;
}

/* Hand-rolled stagger: CSS has no index arithmetic, and passing one in would mean an inline
   style per row. Eight steps is enough to read as a cascade; below the fold nobody is
   watching, so later rows simply share the last delay. */
.wc-item-b0cdb5e:nth-child(2) .wc-row-b0cdb5e {
    animation-delay: calc(1 * var(--fl-stagger));
}

.wc-item-b0cdb5e:nth-child(3) .wc-row-b0cdb5e {
    animation-delay: calc(2 * var(--fl-stagger));
}

.wc-item-b0cdb5e:nth-child(4) .wc-row-b0cdb5e {
    animation-delay: calc(3 * var(--fl-stagger));
}

.wc-item-b0cdb5e:nth-child(5) .wc-row-b0cdb5e {
    animation-delay: calc(4 * var(--fl-stagger));
}

.wc-item-b0cdb5e:nth-child(6) .wc-row-b0cdb5e {
    animation-delay: calc(5 * var(--fl-stagger));
}

.wc-item-b0cdb5e:nth-child(7) .wc-row-b0cdb5e {
    animation-delay: calc(6 * var(--fl-stagger));
}

.wc-item-b0cdb5e:nth-child(n + 8) .wc-row-b0cdb5e {
    animation-delay: calc(7 * var(--fl-stagger));
}

@keyframes rowIn {
    from {
        opacity: 0;
        transform: translateY(8px);
    }

    to {
        opacity: 1;
        transform: none;
    }
}

/* Copper status spine, lit on hover/selection. */
.wc-row-b0cdb5e::before {
    content: "";
    position: absolute;
    inset-inline-start: 0;
    top: 0;
    bottom: 0;
    width: 3px;
    background: var(--fl-copper);
    opacity: 0;
    transition: opacity var(--fl-dur) var(--fl-ease);
}

.wc-row-b0cdb5e:hover {
    background: var(--fl-key-bg-hover);
    border-color: var(--fl-key-bd);
}

.wc-row-b0cdb5e:hover::before {
    opacity: 0.5;
}

.wc-row-b0cdb5e:active {
    transform: translateY(1px);
}

/* Mirrors :hover exactly, but driven by the shared hover signal — so pointing at this
   device's marker on the map lights its row the same way pointing at the row does. */
.wc-hovered-b0cdb5e {
    background: var(--fl-key-bg-hover);
    border-color: var(--fl-key-bd);
}

.wc-hovered-b0cdb5e::before {
    opacity: 0.5;
}

.wc-selected-b0cdb5e {
    border-color: var(--fl-copper);
    background: var(--fl-key-bg-hover);
    box-shadow: 0 0 0 1px var(--fl-copper), 0 10px 30px rgba(0, 0, 0, 0.45);
}

.wc-selected-b0cdb5e::before {
    opacity: 1;
}

/* Positioning context for the presence badge — the corner rounding lives on the
   image itself so the badge can overhang the corner unclipped. */
.wc-thumb-b0cdb5e {
    position: relative;
    flex: 0 0 auto;
    width: 46px;
    height: 46px;
    border-radius: 0.6rem;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--fl-key-bg);
    border: 1px solid var(--fl-hair);
    color: var(--fl-faint);
    font-size: 1.15rem;
}

.wc-thumb-b0cdb5e img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: calc(0.6rem - 1px);
}

/* Container: its inline size is the space actually left for name + meta once the
   thumb and the (optional) pill are served — the sacrifice thresholds below adapt
   per row, pill-aware. */
.wc-body-b0cdb5e {
    flex: 1 1 auto;
    min-width: 0;
    container: devicebody / inline-size;
}

.wc-name-b0cdb5e {
    font-weight: 600;
    font-size: 0.98rem;
    line-height: 1.2;
    letter-spacing: 0.01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    color: var(--fl-text);
}

/* One line, prioritised: each segment declares how it may give way (the sacrifice
   ladder below); the overflow clip is a backstop for browsers without container
   queries — nominally nothing ever overflows. */
.wc-meta-b0cdb5e {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin-top: 0.28rem;
    white-space: nowrap;
    overflow: hidden;
    font-family: var(--fl-mono);
    font-size: 0.66rem;
    font-weight: 500;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--fl-faint);
}

.wc-dot-b0cdb5e {
    display: inline-block;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    flex: 0 0 auto;
}

.wc-live-b0cdb5e {
    background: var(--fl-green);
    box-shadow: 0 0 0 3px rgba(var(--fl-green-rgb), 0.18);
}

/* Liveness badge on the thumbnail's corner (presence convention): the solid ring
   detaches the dot from the photo; the live halo still draws outside the ring. */
.wc-presence-b0cdb5e {
    position: absolute;
    inset-block-end: -2px;
    inset-inline-end: -2px;
    width: 13px;
    height: 13px;
    border: 2px solid var(--fl-bg-2);
}

.wc-sep-b0cdb5e {
    flex: 0 0 auto;
    opacity: 0.4;
}

/* Course + speed as one atomic block: a truncated number is worse than an absent
   one, so the segment never shrinks — it drops whole at the container threshold
   below (the map markers and the popup still carry the telemetry). */
.wc-motion-b0cdb5e {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    flex: 0 0 auto;
}

.wc-heading-b0cdb5e {
    display: inline-flex;
    align-items: center;
    font-size: 0.62rem;
    color: var(--fl-copper);
}

/* Type tag: the meta's only elastic segment. The glyph is the guaranteed type
   marker — the fleet is heterogeneous — and never shrinks; only the text label
   ellipses, down to its floor. */
.wc-kind-b0cdb5e {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    flex: 0 1 auto;
    min-width: 0;
}

.wc-kind-b0cdb5e svg {
    flex: 0 0 auto;
}

.wc-kindLabel-b0cdb5e {
    flex: 0 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    /* Floor ≈ one glyph + ellipsis: the label degrades into a hint, not noise. */
    min-width: 1.2em;
}

/* Sacrifice ladder, discrete steps: below ~150px of body the motion segment goes —
   identity (name + dot) and the type are not available anywhere else at a glance. */
@container devicebody (max-width: 150px) {
    .wc-motion-b0cdb5e {
        display: none;
    }
}

/* Second step: the type keeps only its glyph. */
@container devicebody (max-width: 100px) {
    .wc-kindLabel-b0cdb5e {
        display: none;
    }
}


/* Foiler "Console" device info card + key-style action buttons. Inherits the --fl-*
   palette from .dashboard. Used geo-anchored on the map (FleetMapPopup) and expanded
   below a sidebar row (DeviceListItem) for devices with no position marker. */
.wc-popup-cf8be29 {
    position: relative;
    min-width: 248px;
    padding: 0.85rem 0.95rem 0.8rem;
    border-radius: 0.85rem;
    border: 1px solid var(--fl-panel-bd);
    background: rgba(var(--fl-glass-rgb), 0.86);
    -webkit-backdrop-filter: blur(14px);
    backdrop-filter: blur(14px);
    color: var(--fl-text);
    box-shadow: 0 30px 80px rgba(0, 0, 0, 0.6);
    pointer-events: auto;
    /* Entrance only, and it comes for free: CesiumOverlay's anchor is non-reactive, so
       selecting a device re-mounts this card and the animation replays. There is no matching
       exit — an unmount can't be delayed here without holding a stale anchor. */
    animation: popupIn var(--fl-dur-slow) var(--fl-ease) both;
    transform-origin: 50% 100%;
}

@keyframes popupIn {
    from {
        opacity: 0;
        transform: translateY(6px) scale(0.97);
    }

    to {
        opacity: 1;
        transform: none;
    }
}

/* Signature corner ticks (lock-screen .card). */
.wc-tick-cf8be29 {
    position: absolute;
    width: 11px;
    height: 11px;
    border: 1px solid var(--fl-copper);
    opacity: 0.6;
}

.wc-tl-cf8be29 {
    top: 7px;
    inset-inline-start: 7px;
    border-inline-end: 0;
    border-bottom: 0;
}

.wc-tr-cf8be29 {
    top: 7px;
    inset-inline-end: 7px;
    border-inline-start: 0;
    border-bottom: 0;
}

.wc-bl-cf8be29 {
    bottom: 7px;
    inset-inline-start: 7px;
    border-inline-end: 0;
    border-top: 0;
}

.wc-br-cf8be29 {
    bottom: 7px;
    inset-inline-end: 7px;
    border-inline-start: 0;
    border-top: 0;
}

.wc-popupHead-cf8be29 {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.6rem;
}

.wc-popupName-cf8be29 {
    font-weight: 600;
    font-size: 1rem;
    letter-spacing: 0.01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    color: var(--fl-text);
}

.wc-popupClose-cf8be29 {
    border: none;
    background: none;
    color: var(--fl-faint);
    font-size: 1.15rem;
    line-height: 1;
    padding: 0 0.15rem;
    cursor: pointer;
    transition: color var(--fl-dur) var(--fl-ease);
}

.wc-popupClose-cf8be29:hover {
    color: var(--fl-copper);
}

.wc-popupMeta-cf8be29 {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    margin-top: 0.45rem;
    font-family: var(--fl-mono);
}

/* ── Telemetry read-out ──────────────────────────────────────────────────────────────────
   A two-column grid of label/value pairs. Cells are emitted only for values the device
   actually reported, so the card is short for a bare position fix and full for a live boat,
   without ever showing a column of dashes. */
.wc-readout-cf8be29 {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.3rem 0.7rem;
    margin-top: 0.6rem;
    padding-top: 0.55rem;
    border-top: 1px solid var(--fl-hair);
}

.wc-cell-cf8be29 {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.5rem;
    min-width: 0;
}

.wc-cellLabel-cf8be29 {
    font-family: var(--fl-mono);
    font-size: 0.56rem;
    font-weight: 600;
    letter-spacing: 0.18em;
    color: var(--fl-faint);
}

.wc-cellValue-cf8be29 {
    font-family: var(--fl-mono);
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    color: var(--fl-text);
}

.wc-popupActions-cf8be29 {
    display: flex;
    gap: 0.45rem;
    margin-top: 0.75rem;
}

.wc-popupActions-cf8be29 > * {
    flex: 1 1 0;
}


/* Foiler "Console" map frame. Inherits the --fl-* palette from .dashboard.
   Sizing mirrors erp's Map2 view: a flex column whose CesiumMap child grows with a
   min-height floor — robust where `position:absolute; inset:0` collapses if any ancestor's
   height isn't definite. The markers are DOM (fleet_map/vessel_marker.css); the anchored
   info card is the shared DevicePopup (device_popup.css). */
.wc-mapContainer-755bc42 {
    position: relative;
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    border-radius: 1rem;
    overflow: hidden;
    border: 1px solid var(--fl-panel-bd);
    background: var(--fl-bg);
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.4), 0 20px 60px rgba(0, 0, 0, 0.45);
}

.wc-map-755bc42 {
    width: 100%;
    flex: 1 1 auto;
    min-height: 300px;
}

/* Grade the raster tiles into the console's warm-dark palette. Deeper and flatter than the
   old nudge, so the copper and green marker accents stay the brightest things on screen —
   the map is the backdrop, the fleet is the subject. */
.wc-map-755bc42 canvas {
    filter: saturate(0.82) brightness(0.88) contrast(1.06) hue-rotate(-4deg);
}

/* Edge fade. Without it the graded raster still reads as a photograph dropped into a panel;
   with it the map dissolves into the dashboard's radial background at the corners.
   Click-through, and stacked above the marker layer's own context so the fade covers
   markers near the frame too. */
.wc-vignette-755bc42 {
    position: absolute;
    inset: 0;
    z-index: 3;
    pointer-events: none;
    border-radius: 1rem;
    background: radial-gradient(120% 100% at 50% 50%, transparent 55%, rgba(10, 9, 7, 0.5) 100%);
    box-shadow: inset 0 0 90px rgba(10, 9, 7, 0.5);
}


/* Fleet dashboard — foiler "Console" aesthetic (glass panels, copper accents,
   mono labels), inspired by the foiler_ui lock screen. The --fl-* palette tokens
   are defined on the body theme class (bins/cloud/styles/theme/) and inherit down
   here, into the sidebar rows, and the map popup. Self-contained: the cloud app
   doesn't ship the foiler fonts, so the mono labels fall back to a system
   monospace. */
.wc-dashboard-71abd30 {
    position: relative;
    flex: 1 1 auto;
    display: flex;
    padding: 1rem;
    min-height: 0;
    overflow: hidden;
    color: var(--fl-text);
    font-family: "Hanken Grotesk", system-ui, -apple-system, sans-serif;
    background: radial-gradient(140% 110% at 80% 50%, var(--fl-bg-2), var(--fl-bg) 70%);
    /* Cross-crate contract: the floating fleet dock's width, and the clearance the
       map HUD (fleet_map/map_hud.css) adds to its inset-inline-start so the dock
       never covers its status strip. Custom properties inherit into the map. */
    --fleet-dock-inline-size: clamp(320px, 24vw, 360px);
    /* Panel + collapse tab (2rem, 0.75rem gaps each side) — the HUD strip starts past both. */
    --fleet-dock-clearance: calc(var(--fleet-dock-inline-size) + 3.5rem);
}

/* Faint instrument grid, masked to fade at the edges (lock-screen .bgGrid). */
.wc-dashboard-71abd30::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    opacity: 0.5;
    background-image: linear-gradient(var(--fl-hair) 1px, transparent 1px), linear-gradient(90deg, var(--fl-hair) 1px, transparent 1px);
    background-size: 46px 46px;
    -webkit-mask-image: radial-gradient(85% 85% at 50% 50%, #000, transparent 92%);
    mask-image: radial-gradient(85% 85% at 50% 50%, #000, transparent 92%);
}

.wc-mapPane-71abd30 {
    position: relative;
    z-index: 1;
    flex: 1 1 auto;
    min-width: 0;
    min-height: 0;
    /* flex column so the FleetMap (.mapContainer) can grow to fill — erp's Map2 pattern. */
    display: flex;
    flex-direction: column;
}

/* Floating fleet dock, overlaid on the full-width map. z-index 2 beats .mapPane
   (z-index 1, a stacking context), so the dock paints above all of the map's own
   chrome. pointer-events: none on the wrapper — only the panel and the toggle take
   the pointer, everywhere else still drags the map. */
.wc-dock-71abd30 {
    position: absolute;
    z-index: 2;
    /* 1rem dashboard padding + the HUD's 0.75rem inset + the map frame's 1px border
       (the HUD is positioned inside it), so the collapse tab shares the HUD strip's
       exact line. */
    inset-block: calc(1.75rem + 1px);
    inset-inline-start: 1.75rem;
    inline-size: var(--fleet-dock-inline-size);
    /* A dragged width is remembered per browser and outlives the window it was
       chosen in, so cap it against the dashboard: the map has to stay usable
       when the same browser later opens a narrower window. */
    max-inline-size: 60%;
    display: flex;
    flex-direction: column;
    pointer-events: none;
}

/* Drag strip for the dock's width, on the panel's inner trailing edge and inside
   its padding, so it never reaches the content. Anchored to the panel and not to
   the dock: the dock is stretched to the full dashboard height by its own
   `inset-block`, while the panel is only as tall as its list, so a grip measured
   against the dock would hang far below the card. */
.wc-dockGrip-71abd30 {
    position: absolute;
    inset-block: 0;
    inset-inline-end: 0;
    display: flex;
    --resize-bar-width: 0.75rem;
    /* The bar rides the card's edge rather than standing in for a gap, so the
       filet sits against that edge and the rest of the strip is grab area. */
    --resize-bar-line-align: flex-end;
}

/* Glass panel. More opaque than --fl-panel: it floats over the map raster, not
   over the dashboard's calm background (same reason as the map popup). */
.wc-panel-71abd30 {
    pointer-events: auto;
    /* Containing block for the drag grip, so the grip is exactly as tall as the
       card. */
    position: relative;
    display: flex;
    flex-direction: column;
    min-block-size: 0;
    max-block-size: 100%;
    overflow: hidden;
    padding: 0.9rem 0.9rem 0.4rem;
    border: 1px solid var(--fl-panel-bd);
    border-radius: var(--radius-2xl);
    background: rgba(var(--fl-glass-rgb), 0.78);
    -webkit-backdrop-filter: blur(14px);
    backdrop-filter: blur(14px);
    box-shadow: 0 30px 80px rgba(0, 0, 0, 0.55);
    transition: opacity var(--fl-dur) var(--fl-ease), scale var(--fl-dur) var(--fl-ease), translate var(--fl-dur) var(--fl-ease),
        max-block-size var(--fl-dur) var(--fl-ease), visibility 0s linear 0s;
}

/* Collapse tab, riding the panel's outer edge — same 2rem key format as the HUD's
   camera controls, top-aligned with the dock so it sits on the HUD strip's line. */
.wc-dockToggle-71abd30 {
    pointer-events: auto;
    position: absolute;
    inset-block-start: 0;
    inset-inline-start: calc(100% + 0.75rem);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    inline-size: 2rem;
    block-size: 2rem;
    font-size: 0.78rem;
    padding: 0;
    border-radius: 0.55rem;
    border: 1px solid var(--fl-key-bd);
    background: rgba(var(--fl-glass-rgb), 0.72);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
    color: var(--fl-dim);
    cursor: pointer;
    box-shadow: 0 10px 24px rgba(0, 0, 0, 0.4);
    transition: inset-inline-start var(--fl-dur) var(--fl-ease), background-color var(--fl-dur) var(--fl-ease),
        border-color var(--fl-dur) var(--fl-ease), color var(--fl-dur) var(--fl-ease);
}

.wc-dockToggle-71abd30:hover {
    border-color: var(--fl-copper);
    color: var(--fl-text);
    background: var(--fl-key-bg-hover);
}

.wc-dockToggle-71abd30 svg {
    transition: rotate var(--fl-dur) var(--fl-ease);
}

/* Pull-pill label, shown on the narrow layout only. */
.wc-dockToggleLabel-71abd30 {
    display: none;
}

@media (min-width: 768px) {
    /* Collapsed: only the tab (2rem + 0.75rem gap) stays at the edge; the HUD strip
       slides back. */
    .wc-dashboardPanelClosed-71abd30 {
        --fleet-dock-clearance: 2.75rem;
    }

    /* visibility (delayed to the end of the fade) removes the hidden panel from
       hit-testing and the a11y tree without unmounting it — search text and list
       scroll survive the collapse. */
    .wc-dashboardPanelClosed-71abd30 .wc-panel-71abd30 {
        visibility: hidden;
        opacity: 0;
        scale: 0.98;
        transition: opacity var(--fl-dur) var(--fl-ease), scale var(--fl-dur) var(--fl-ease), visibility 0s linear var(--fl-dur);
    }

    .wc-dashboardPanelClosed-71abd30 .wc-dockToggle-71abd30 {
        inset-inline-start: 0;
    }

    /* The chevron's rotation is physical, so RTL needs the explicit flip. */
    .wc-dashboardPanelClosed-71abd30 .wc-dockToggle-71abd30 svg {
        rotate: 180deg;
    }

    [dir="rtl"] .wc-dockToggle-71abd30 svg {
        rotate: 180deg;
    }

    [dir="rtl"] .wc-dashboardPanelClosed-71abd30 .wc-dockToggle-71abd30 svg {
        rotate: 0deg;
    }
}

/* Below md the dock becomes a bottom sheet and the tab a centred pull pill. The
   collapsed default is pure CSS (neither state class present), so the
   server-rendered markup is correct without any browser measurement. */
@media (max-width: 767.98px) {
    .wc-dashboard-71abd30 {
        padding: 0.5rem;
        /* The sheet sits at the bottom — the HUD strip keeps its corner. */
        --fleet-dock-clearance: 0rem;
    }

    .wc-dock-71abd30 {
        inset-block: auto 1rem;
        inset-inline: 1rem;
        inline-size: auto;
        max-inline-size: none;
        max-block-size: min(58dvh, 30rem);
    }

    /* The sheet spans the viewport, so there is no inline edge to drag. The
       stored width is simply not read here — `.dock` above drops it. */
    .wc-dockGrip-71abd30 {
        display: none;
    }

    .wc-dockToggle-71abd30 {
        position: static;
        align-self: center;
        inline-size: auto;
        block-size: auto;
        margin-block-end: 0.5rem;
        padding: 0.45rem 0.9rem;
        border-radius: 999px;
        font-family: var(--fl-mono);
        font-size: 0.68rem;
        font-weight: 600;
        letter-spacing: 0.14em;
        text-transform: uppercase;
    }

    .wc-dockToggleLabel-71abd30 {
        display: inline;
    }

    /* Collapsed (the default): the sheet's box collapses too, so the pill drops to
       the bottom edge instead of hovering above an invisible sheet. */
    .wc-panel-71abd30 {
        visibility: hidden;
        opacity: 0;
        translate: 0 0.5rem;
        max-block-size: 0;
        padding-block: 0;
        border-width: 0;
        transition: opacity var(--fl-dur) var(--fl-ease), translate var(--fl-dur) var(--fl-ease),
            max-block-size var(--fl-dur) var(--fl-ease), padding var(--fl-dur) var(--fl-ease), visibility 0s linear var(--fl-dur);
    }

    .wc-dashboardPanelOpen-71abd30 .wc-panel-71abd30 {
        visibility: visible;
        opacity: 1;
        translate: 0;
        max-block-size: 100%;
        padding-block: 0.9rem 0.4rem;
        border-width: 1px;
        transition: opacity var(--fl-dur) var(--fl-ease), translate var(--fl-dur) var(--fl-ease),
            max-block-size var(--fl-dur) var(--fl-ease), padding var(--fl-dur) var(--fl-ease), visibility 0s linear 0s;
    }

    /* Vertical chevrons (no RTL flip needed): collapsed points up, open points down. */
    .wc-dockToggle-71abd30 svg {
        rotate: 90deg;
    }

    .wc-dashboardPanelOpen-71abd30 .wc-dockToggle-71abd30 svg {
        rotate: -90deg;
    }
}


/* Map chrome: status strip (top-left) and camera controls (top-right).

   The wrapper spans the map but is click-through, so only the two clusters take the pointer
   — everything between them still pans the map. */
.wc-hud-e3f1cd1 {
    position: absolute;
    inset-block: 0.75rem auto;
    /* --fleet-dock-clearance: set by the home dashboard (home.css) when its fleet
       panel floats over the map's inline-start corner; it inherits down to here.
       Defaults to 0 for any other host of the map. */
    inset-inline: calc(0.75rem + var(--fleet-dock-clearance, 0rem)) 0.75rem;
    transition: inset-inline-start var(--fl-dur) var(--fl-ease);
    z-index: 4;
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 0.75rem;
    pointer-events: none;
}

/* ── Status strip ───────────────────────────────────────────────────────────────────────
   What the map is currently showing, in the console's mono voice. Counts come from the
   markers themselves, so the strip can never disagree with what is on screen. */
.wc-status-e3f1cd1 {
    display: flex;
    align-items: baseline;
    gap: 0.4rem;
    /* Same 2rem line as the camera keys and the fleet dock's collapse tab — content-derived
       height sits a hair off and reads as a size mismatch next to them. */
    block-size: 2rem;
    padding: 0.34rem 0.7rem;
    border-radius: 0.6rem;
    border: 1px solid var(--fl-panel-bd);
    background: rgba(var(--fl-glass-rgb), 0.72);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
    box-shadow: 0 12px 30px rgba(0, 0, 0, 0.45);
    pointer-events: auto;
}

.wc-statusValue-e3f1cd1 {
    font-family: var(--fl-mono);
    font-size: 0.82rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    color: var(--fl-text);
}

.wc-statusLive-e3f1cd1 {
    color: var(--fl-green);
}

.wc-statusLabel-e3f1cd1 {
    font-family: var(--fl-mono);
    font-size: 0.58rem;
    font-weight: 600;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--fl-faint);
}

.wc-statusSep-e3f1cd1 {
    width: 1px;
    align-self: stretch;
    margin: 0 0.15rem;
    background: var(--fl-hair);
}

/* Poll heartbeat. The element is re-created on each fetch, so the animation replays once
   per poll and then rests — a steady flash means data is flowing, a frozen dot means it
   has stopped. Single-shot on purpose: an infinite pulse would keep reassuring after the
   poll had died. */
.wc-beat-e3f1cd1 {
    align-self: center;
    width: 7px;
    height: 7px;
    margin-inline-end: 0.15rem;
    border-radius: 50%;
    background: var(--fl-copper);
    animation: beat var(--fl-dur-slow) var(--fl-ease) 1;
}

@keyframes beat {
    0% {
        opacity: 0.35;
        box-shadow: 0 0 0 0 rgba(var(--fl-copper-rgb), 0.5);
    }

    35% {
        opacity: 1;
        box-shadow: 0 0 0 5px rgba(var(--fl-copper-rgb), 0);
    }

    100% {
        opacity: 0.35;
        box-shadow: 0 0 0 0 rgba(var(--fl-copper-rgb), 0);
    }
}

/* ── Camera controls ────────────────────────────────────────────────────────────────────
   Key-style buttons, same language as the popup's actions and the console's keypad. */
.wc-controls-e3f1cd1 {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    pointer-events: auto;
}

.wc-ctrl-e3f1cd1 {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    padding: 0;
    border-radius: 0.55rem;
    border: 1px solid var(--fl-key-bd);
    background: rgba(var(--fl-glass-rgb), 0.72);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
    color: var(--fl-dim);
    font-size: 0.78rem;
    cursor: pointer;
    box-shadow: 0 10px 24px rgba(0, 0, 0, 0.4);
    transition: background-color var(--fl-dur) var(--fl-ease), border-color var(--fl-dur) var(--fl-ease), color var(--fl-dur) var(--fl-ease),
        transform var(--fl-press) var(--fl-ease);
}

.wc-ctrl-e3f1cd1:hover:not(:disabled) {
    border-color: var(--fl-copper);
    color: var(--fl-text);
    background: var(--fl-key-bg-hover);
}

.wc-ctrl-e3f1cd1:active:not(:disabled) {
    transform: translateY(1px);
}

.wc-ctrl-e3f1cd1:disabled {
    opacity: 0.4;
    cursor: default;
}

/* Follow armed: the same copper "this is on" the console uses for a selected row. */
.wc-ctrlOn-e3f1cd1 {
    border-color: var(--fl-copper);
    background: var(--fl-copper);
    color: var(--fl-on-copper);
}

.wc-ctrlOn-e3f1cd1:hover:not(:disabled) {
    background: var(--fl-copper-bright);
    color: var(--fl-on-copper);
}


/* The DOM marker layer, stretched over the Cesium canvas.

   `pointer-events: none` is the important part: the layer covers the whole map, so anything
   but a hit-testable marker must let drags, wheel zoom and Cesium's own picking pass straight
   through. Individual markers opt back in (vessel_marker.css). */
.wc-layer-3880a1e {
    position: absolute;
    inset: 0;
    z-index: 2;
    overflow: hidden;
    pointer-events: none;
}


/* One vessel marker. Console palette throughout — a live marker is exactly the sidebar's
   live green, a selected one exactly a selected row's copper.

   Two custom properties are written by the paint loop (overlay_layer.rs), never by CSS:
     --marker-course  the interpolated course, as an angle
     --marker-moving  1 while the device is under way, 0 otherwise
   Everything below is free to read them. */

/* The positioner: the paint loop owns its `transform` and `display`. Nothing else may set
   either, which is why the visual lives one level down. Hidden until the first paint places
   it, so a marker never flashes at the map's top-left corner on mount. */
.wc-positioner-362dd90 {
    position: absolute;
    top: 0;
    inset-inline-start: 0;
    display: none;
    will-change: transform;
}

.wc-marker-362dd90 {
    position: absolute;
    top: 0;
    inset-inline-start: 0;
    width: 34px;
    height: 34px;
    /* Seat the marker on its anchor, and scale from there. */
    transform: translate(-50%, -50%) scale(var(--marker-scale, 1));
    transition: transform var(--fl-dur) var(--fl-ease);
    /* The layer is click-through; the marker itself is not. Kept to the glyph's own box so
       a drag that starts a few pixels away still pans the map. */
    pointer-events: auto;
    cursor: pointer;
    color: var(--fl-faint);
}

.wc-live-362dd90 {
    color: var(--fl-green);
}

.wc-offline-362dd90 {
    color: var(--fl-faint);
    opacity: 0.72;
}

.wc-hovered-362dd90,
.wc-selected-362dd90 {
    --marker-scale: 1.14;
    z-index: 1;
}

/* ── The hull ────────────────────────────────────────────────────────────────────────────
   `currentColor` is what makes liveness a one-line colour change instead of a second SVG.
   The dark outline keeps the glyph legible over pale coastline and bright sea alike. */
.wc-glyph-362dd90 {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    fill: currentColor;
    stroke: rgba(10, 9, 7, 0.85);
    stroke-width: 1.4;
    stroke-linejoin: round;
    /* No transition: the course is already interpolated frame-by-frame upstream, so easing
       it here would fight the tween and lag every turn. */
    transform: rotate(var(--marker-course, 0deg));
    filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.55));
}

/* Heading-less contact: smaller, and never rotated. */
.wc-glyphDot-362dd90 {
    transform: none;
    scale: 0.7;
}

/* ── Ambient liveness ping ───────────────────────────────────────────────────────────────
   Only lit on live devices. The duration/iteration tokens are what reduced motion switches
   off (bins/cloud/styles/main.css) — no separate media query needed here. */
.wc-ping-362dd90 {
    position: absolute;
    inset: 0;
    border-radius: 50%;
    border: 1px solid currentColor;
    opacity: 0;
    pointer-events: none;
}

.wc-live-362dd90 .wc-ping-362dd90 {
    animation: ping var(--fl-ping-dur) var(--fl-ease) var(--fl-ping-iter);
}

@keyframes ping {
    0% {
        transform: scale(0.6);
        opacity: 0.55;
    }

    70% {
        opacity: 0;
    }

    100% {
        transform: scale(2.1);
        opacity: 0;
    }
}

/* ── Wake ────────────────────────────────────────────────────────────────────────────────
   A short taper trailing the hull, shown only while the device is actually under way. It is
   drawn from the marker's own course, so it needs no position history to look right. */
.wc-wake-362dd90 {
    position: absolute;
    inset-inline-start: 50%;
    top: 50%;
    width: 5px;
    height: 30px;
    border-radius: 3px;
    background: linear-gradient(to bottom, currentColor, transparent 88%);
    /* Rotate about the marker's centre first, then push the taper out behind the hull. */
    transform: translate(-50%, 0) rotate(var(--marker-course, 0deg)) translateY(6px);
    transform-origin: 50% 0;
    opacity: calc(var(--marker-moving, 0) * 0.42);
    transition: opacity var(--fl-dur-slow) var(--fl-ease);
    pointer-events: none;
}

/* ── Selection ring ──────────────────────────────────────────────────────────────────────
   Replaces the old second billboard layer: same copper as a selected sidebar row, and it
   scales with the marker instead of being a separate GPU image that had to be kept in sync. */
.wc-ring-362dd90 {
    position: absolute;
    inset: -11px;
    border-radius: 50%;
    border: 2px solid var(--fl-copper);
    background: rgba(var(--fl-copper-rgb), 0.14);
    box-shadow: 0 0 18px rgba(var(--fl-copper-rgb), 0.35);
    opacity: 0;
    transform: scale(0.7);
    transition: opacity var(--fl-dur) var(--fl-ease), transform var(--fl-dur) var(--fl-ease);
    pointer-events: none;
}

.wc-selected-362dd90 .wc-ring-362dd90 {
    opacity: 1;
    transform: scale(1);
}

/* Hover shows a fainter version of the same ring, so pointing at a marker previews what
   clicking it will select. */
.wc-hovered-362dd90 .wc-ring-362dd90 {
    opacity: 0.45;
    transform: scale(0.92);
}

/* ── Hover label ─────────────────────────────────────────────────────────────────────────
   The affordance the billboard map had no way to offer: name + speed on hover, without
   having to click through to the popup. */
.wc-label-362dd90 {
    position: absolute;
    inset-inline-start: 50%;
    bottom: calc(100% + 12px);
    display: flex;
    align-items: baseline;
    gap: 0.45rem;
    max-width: 15rem;
    padding: 0.22rem 0.5rem;
    border-radius: 0.45rem;
    border: 1px solid var(--fl-panel-bd);
    background: rgba(var(--fl-glass-rgb), 0.88);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    box-shadow: 0 10px 26px rgba(0, 0, 0, 0.5);
    white-space: nowrap;
    opacity: 0;
    transform: translate(-50%, 4px);
    transition: opacity var(--fl-dur-fast) var(--fl-ease), transform var(--fl-dur-fast) var(--fl-ease);
    pointer-events: none;
}

/* Not shown while selected — the popup is already saying all of this, right there. */
.wc-hovered-362dd90:not(.wc-selected-362dd90) .wc-label-362dd90 {
    opacity: 1;
    transform: translate(-50%, 0);
}

.wc-labelName-362dd90 {
    font-size: 0.76rem;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    color: var(--fl-text);
}

.wc-labelSpeed-362dd90 {
    font-family: var(--fl-mono);
    font-size: 0.62rem;
    letter-spacing: 0.1em;
    color: var(--fl-faint);
}
