/* --------- App wide scrollbar style ---------- */
* {
    scrollbar-width: thin;
    scrollbar-color: #c3c8cf transparent;
}

    *::-webkit-scrollbar {
        width: 4px;
    }

    *::-webkit-scrollbar-thumb {
        background: #c3c8cf;
        border-radius: 99999px;
    }

    *::-webkit-scrollbar-track {
        background: transparent;
    }

    *::-webkit-scrollbar-thumb:hover {
        background: #919499;
    }


/* ── CreateUserPopup: narrow modal for email step ───────────────────────── */
.modal-sm-custom {
    max-width: 400px;
}

/* ----------------------- App Loader START ----------------------- */

.loader-container {
  overflow: hidden;
  max-width: 100vw;
  background-color: white;
  color: black;
}

.loader-wrapper {
  height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.loader-spinner-div {
  display: flex;
  margin: 1rem;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  margin-right: calc(1rem * 0);
  margin-left: calc(1rem * calc(1 - 0));
}

.loader-spinner {
  height: 5.5rem;
  width: 5.5rem;
  animation: spin 1s linear infinite;
  border-radius: 9999px;
  border-width: 6.5px;
  border-style: solid;
  border-color: currentColor;
  border-top-color: transparent;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

/* --- Snowflake loader ---------------------------------------------------
   Shape follows the brand mark in snow-manager-logo.svg: six thick, round-
   capped arms, each carrying a single long V of prongs that leaves off at
   35 degrees from the arm 45% of the way out and stops short of the tip, so
   the arm ends in the same bare rounded point the logo does.

   It grows the way a real crystal does: a seed nucleates, the arms extend
   outward at a constant rate, and a prong only starts sprouting at the exact
   moment the arm tip passes its attachment point. Nothing is ever drawn
   detached from the crystal, and the prongs advance at the same speed as the
   arm they came off. All parts share one 2.8s timeline, so the phases cannot
   drift apart. */

.wm-flake {
  display: block;
  color: #80c6ea;
}

.wm-flake-body {
  animation: wm-flake-cycle 2.8s linear infinite;
  transform-box: fill-box;
  transform-origin: center;
}

.wm-flake-seed {
  stroke-width: 4.4;
  animation: wm-flake-seed 2.8s linear infinite;
  transform-box: fill-box;
  transform-origin: center;
}

.wm-flake-arm,
.wm-flake-v {
  /* 1 unit "on", 2 units "off" against pathLength="1": an offset of 1 keeps
     the whole stroke — round cap included — outside the visible span. */
  stroke-dasharray: 1 2;
  stroke-dashoffset: 1;
}

.wm-flake-arm {
  stroke-width: 5.5;
  animation: wm-flake-arm 2.8s linear infinite;
}

.wm-flake-v {
  stroke-width: 5.1;
  animation: wm-flake-v 2.8s linear infinite;
}

/* Seed nucleates first, then holds — the arm junction swallows it. */
@keyframes wm-flake-seed {
  0% { transform: scale(0); }
  3% { transform: scale(1.25); }
  5%, 100% { transform: scale(1); }
}

/* Primary arms: constant growth rate from 3% to 46% of the cycle, so a point
   at distance d along the 38-unit arm is reached at 3% + 43% * (d / 38). */
@keyframes wm-flake-arm {
  0%, 3% { stroke-dashoffset: 1; }
  46%, 100% { stroke-dashoffset: 0; }
}

/* Prongs branch at d = 17.86 (23.2%) and grow at the arm's own rate, so
   their 15.19 units take 17.2% of the cycle and finish just before the tip
   lands. Their ends sit at 0.83 of the arm at 16 degrees off its axis, which
   is where the logo puts them. */
@keyframes wm-flake-v {
  0%, 23.2% { stroke-dashoffset: 1; }
  40.4%, 100% { stroke-dashoffset: 0; }
}

/* Finished crystal holds, then dissipates as one piece before the next seed. */
@keyframes wm-flake-cycle {
  0%, 84% { opacity: 1; transform: scale(1); }
  97%, 100% { opacity: 0; transform: scale(1.06); }
}

@media (prefers-reduced-motion: reduce) {
  .wm-flake-body,
  .wm-flake-seed,
  .wm-flake-arm,
  .wm-flake-v {
    animation: none;
  }

  .wm-flake-arm,
  .wm-flake-v {
    stroke-dashoffset: 0;
  }
}

/* ----------------------- App Loader END ----------------------- */

.validation-star {
  color: red;
}

.character-counter {
  font-size: 12px !important;
  font-weight: 500 !important;
  line-height: 16px !important;
  letter-spacing: -0.2px !important;
  color: #5F6E85 !important;
}

.icon-button-div {
  display: flex !important;
  flex-direction: row !important;
  justify-content: center !important;
  align-items: center !important;
  text-align: center !important;
  gap: 8px !important;
}

/* Tooltip shown while hovering a labelled map shape (zone/route name).
   WMMap's scoped css gives every popup the big location-card chrome (16px radius,
   translucent gradient, 20px padding), so this must out-specify it back to a plain
   solid little bubble whose tip actually touches it. */
.mapboxgl-popup.wm-shape-tip .mapboxgl-popup-content {
    padding: 4px 10px !important;
    font-size: 12px;
    font-weight: 600;
    color: #1E293B;
    background: #FFFFFF !important;
    border: none !important;
    border-radius: 6px !important;
    box-shadow: 0 2px 8px rgba(15, 23, 42, 0.18) !important;
    pointer-events: none;
}

.mapboxgl-popup.wm-shape-tip .mapboxgl-popup-tip {
    border-top-color: #FFFFFF;
    border-bottom-color: #FFFFFF;
}

.mapboxgl-popup.wm-shape-tip {
    pointer-events: none;
    z-index: 5;
}

/* "(not sent to subcontractors)" qualifier on the internal-comment label. */
.internal-note-hint {
    font-weight: 400;
    font-size: 12px;
    color: #5F6E85;
}


/* ----------------------- Unhandled error banner (SM-186) -----------------------
   Blazor resolves #blazor-error-ui by id and sets an inline `display: block` on it when
   a client exception goes unhandled, so the id and the hidden-by-default rule below are
   load-bearing — and the layout has to live on an inner wrapper, because that inline
   `block` would otherwise win over any `display: flex` set here.

   Themed off the app's own tokens rather than the Blazor template's yellow bar: white
   card, --wm-card-radius, --wm-card-shadow, --danger for the accent, Plus Jakarta Sans
   inherited from body. */

#blazor-error-ui {
    display: none;
    position: fixed;
    left: 50%;
    bottom: 24px;
    transform: translateX(-50%);
    width: calc(100% - 32px);
    max-width: 560px;
    z-index: 1080;
}

.wm-error-inner {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 16px 16px 16px 20px;
    background: var(--wm-card-bg, #ffffff);
    border: 1px solid rgba(223, 41, 23, .18);
    border-radius: var(--wm-card-radius, 20px);
    /* Clips the accent bar below to the rounded corner instead of letting a
       border-left curve away from the card edge. */
    overflow: hidden;
    box-shadow: var(--wm-card-shadow, 0 20px 20px -12px rgba(30, 41, 59, .18));
    font-size: 14px;
    line-height: 1.4;
    color: var(--dark-txt, #1E293B);
}

    .wm-error-inner::before {
        content: "";
        position: absolute;
        left: 0;
        top: 0;
        bottom: 0;
        width: 4px;
        background: var(--danger, #B82213);
    }

.wm-error-icon {
    display: flex;
    flex: 0 0 auto;
    margin-top: 1px;
    color: var(--danger, #B82213);
}

.wm-error-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    flex: 1 1 auto;
    min-width: 0;
}

    .wm-error-text strong {
        font-weight: 600;
    }

    .wm-error-text > span {
        color: var(--gray-txt, #475569);
    }

#blazor-error-ui .reload {
    flex: 0 0 auto;
    align-self: center;
    padding: 8px 16px;
    border-radius: 999px;
    background: var(--danger, #B82213);
    color: #ffffff;
    font-weight: 600;
    white-space: nowrap;
}

    #blazor-error-ui .reload:hover,
    #blazor-error-ui .reload:focus-visible {
        background: #b92112;
        color: #ffffff;
    }

#blazor-error-ui .dismiss {
    flex: 0 0 auto;
    align-self: flex-start;
    margin: -4px -4px 0 0;
    padding: 0 6px;
    font-size: 22px;
    line-height: 1;
    color: var(--gray-txt-2, #5F6E85);
    cursor: pointer;
}

    #blazor-error-ui .dismiss:hover,
    #blazor-error-ui .dismiss:focus-visible {
        color: var(--dark-txt, #1E293B);
    }

/* Narrow screens: the pill would squeeze the message to two words, so drop it onto its own
   full-width row. The dismiss goes to the corner rather than into the flex flow — wrapped
   inline it lands on a line of its own between the message and the button, reading as a
   stray glyph. The icon keeps its row with the text (flex-basis, not auto) so it cannot
   orphan onto a line above the heading. */
@media (max-width: 480px) {
    #blazor-error-ui {
        left: 8px;
        right: 8px;
        bottom: 8px;
        width: auto;
        transform: none;
    }

    .wm-error-inner {
        flex-wrap: wrap;
        row-gap: 12px;
        padding-right: 40px;
    }

    .wm-error-text {
        flex: 1 1 0;
    }

    #blazor-error-ui .reload {
        flex: 1 1 100%;
        text-align: center;
        order: 3;
    }

    #blazor-error-ui .dismiss {
        position: absolute;
        top: 10px;
        right: 12px;
        margin: 0;
        padding: 0;
    }
}

/* ---- Worktype chips ----
   One colour per worktype, the same on the dispatch list and inside the dispatch sidebar.
   The slot is assigned per tenant by WorkTypeChips.AssignSlots (system worktypes first, then
   creation order), so "Salting" and "Snow removal & Salting" always sit on two different
   hues. Global rather than scoped because three components share the classes. */
.wt-chip {
    display: inline-flex;
    align-items: center;
    padding: 1px 7px;
    border-radius: 8px;
    font-size: 12px;
    font-weight: 700;
    line-height: 18px;
    white-space: nowrap;
    background: #1E293B14;
    color: #1E293B;
}

.wt-chip p {
    margin: 0;
    color: inherit;
    font: inherit;
}

.wt-slot-0 { background: #5263FF1F; color: #363AF5; }
.wt-slot-1 { background: #409B3F1F; color: #296C28; }
.wt-slot-2 { background: #F59E0B29; color: #B45309; }
.wt-slot-3 { background: #06B1F11F; color: #0075AA; }
.wt-slot-none { background: #1E293B14; color: #1E293B; }

.wt-mix {
    flex-wrap: wrap;
}

/* The small chip: the mix line under a zone, contractor or route title. */
.wt-chip-sm {
    padding: 0 6px;
    border-radius: 6px;
    font-size: 11px;
    line-height: 16px;
}

.wt-mix-compact {
    flex-wrap: nowrap;
    gap: 4px;
    white-space: nowrap;
}

.wt-mix-dot {
    color: #94A3B8;
    font-size: 11px;
    font-weight: 700;
    line-height: 16px;
}

/* Above the stop list the chips are buttons on the stop filter: the selected worktype
   wears a ring, the others fade, and a second click on the selected one lifts the
   filter. Same colours, so the button is still the chip. */
.wt-chip-btn {
    border: 0;
    cursor: pointer;
    font: inherit;
    font-size: 12px;
    font-weight: 700;
    line-height: 18px;
    transition: opacity 0.15s ease, box-shadow 0.15s ease;
}

.wt-chip-btn:hover {
    box-shadow: inset 0 0 0 1px currentColor;
}

.wt-chip-btn:focus-visible {
    outline: 2px solid #4A55E1;
    outline-offset: 2px;
}

.wt-chip-selected {
    box-shadow: inset 0 0 0 1.5px currentColor;
}

.wt-chip-btn.wt-chip-selected:hover {
    box-shadow: inset 0 0 0 1.5px currentColor;
}

.wt-chip-dim {
    opacity: 0.45;
}

@media (prefers-reduced-motion: reduce) {
    .wt-chip-btn {
        transition: none;
    }
}

/* The row under the sidebar's status tabs: the dispatch-wide mix on the left, the
   stop filter button on the right. It keeps the panel's inset and breathing room from
   the tab strip above and whatever banner follows. */
.stop-filter-row {
    margin-top: 0;
    padding: 10px 16px;
    min-height: 34px;
}

/* The zone view moves the Filter button into its title line, so a zone dispatch whose stops
   share one work type leaves this row with nothing in it. */
.stop-filter-row:empty {
    display: none;
}

/* The snow-depth box, wherever a dispatch asks for one (create popups, the two detail
   sliders, the stop modal, the completion dialog). Same shape as the rule-panel inputs
   so it reads as the platform's own control instead of a browser default. */
.wm-depth-input {
    width: 84px;
    height: 36px;
    padding: 6px 10px;
    background-color: var(--white);
    border: 1px solid #1e293b1f;
    border-radius: 10px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
    font-family: "Plus Jakarta Sans", sans-serif;
    font-size: 13px;
    font-weight: 600;
    color: var(--dark-txt);
    outline: none;
}

.wm-depth-input:focus {
    box-shadow: 0 0 0 0.2rem #dce0ff;
}

.wm-depth-input:disabled {
    opacity: 0.6;
}

.wm-depth-unit {
    font-size: 13px;
    font-weight: 600;
    color: var(--dark-txt);
}
