/* ============================================================
   MASAR SCADA — polish.css
   The last stylesheet loaded, and deliberately so.

   Everything here is cross-cutting: motion, focus, scrollbars,
   selection, empty states, hover behaviour. These are the things
   that are wrong in the same way on every screen when they are wrong
   at all, so they are fixed in one place rather than re-decided in
   each page's stylesheet.

   Three rules govern it:

     · One easing curve and one duration scale. Interfaces that use
       six different curves feel assembled rather than designed.
     · Motion earns its place or it goes. Nothing moves to be pretty;
       it moves to show where something came from.
     · All of it is off for anyone who asked their system for less
       motion. That is not an edge case — it is a setting people turn
       on because movement makes them ill.
   ============================================================ */

:root {
  --ease: cubic-bezier(.4, 0, .2, 1);
  --ease-out: cubic-bezier(.16, 1, .3, 1);
  --t-1: .12s;   /* state change on a control you are touching */
  --t-2: .2s;    /* something appearing or leaving */
  --t-3: .32s;   /* a panel travelling across the screen */
}

/* ============================================================
   1 · MOTION
   ============================================================ */
@keyframes pageIn {
  from { opacity: 0; transform: translateY(7px) }
  to { opacity: 1; transform: none }
}
@keyframes fadeIn { from { opacity: 0 } to { opacity: 1 } }
@keyframes riseIn {
  from { opacity: 0; transform: translateY(10px) scale(.985) }
  to { opacity: 1; transform: none }
}

/* A page arrives from slightly below — the direction you scrolled to
   reach it. Short enough that it never delays the first read. */
#main > .page { animation: pageIn var(--t-2) var(--ease-out) both }
/* the map is the exception: animating a Leaflet container mid-mount
   makes it measure itself against a transformed box and land offset */
#main > .page.flush { animation: fadeIn var(--t-1) linear both }

.modal { animation: riseIn var(--t-2) var(--ease-out) both }
.toast { animation: riseIn var(--t-2) var(--ease-out) both }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  .veh .halo, .mreq.breach, .mm-stop.cur, .dot.pulse { animation: none !important }
}

/* ============================================================
   2 · FOCUS

   One ring, on everything, and only for keyboard users. An operator
   working a console by keyboard has to be able to see where they
   are; a mouse user should never see a ring at all.
   ============================================================ */
:where(button, a, input, select, textarea, [tabindex], summary):focus-visible {
  outline: 2px solid var(--b500);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}
.nav-item:focus-visible { outline-offset: -2px }
.gcard:focus-visible, .lcard:focus-visible, .cm-row:focus-visible { outline-offset: -2px }
/* a ring is enough; the box-shadow ring on top of it doubles the mark */
:where(button, a):focus:not(:focus-visible) { outline: none }

/* ============================================================
   3 · SCROLLBARS

   Thin, themed, and the same everywhere. Chrome's default light
   scrollbar sitting inside a dark panel is the single most common
   way a dark theme gives itself away.
   ============================================================ */
* { scrollbar-width: thin; scrollbar-color: var(--line-2) transparent }
::-webkit-scrollbar { width: 9px; height: 9px }
::-webkit-scrollbar-track { background: transparent }
::-webkit-scrollbar-thumb {
  background: var(--line-2); border-radius: 100px;
  border: 2px solid transparent; background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover { background: var(--dim); background-clip: padding-box }
::-webkit-scrollbar-corner { background: transparent }

::selection { background: color-mix(in srgb, var(--b500) 26%, transparent); color: var(--ink) }

/* ============================================================
   4 · INTERACTIVE SURFACES

   A card that does something on click should say so before it is
   clicked, and a card that does nothing should never pretend.
   ============================================================ */
.card { transition: border-color var(--t-1) var(--ease), box-shadow var(--t-1) var(--ease) }
.card-h { min-height: 50px }

.btn, .icon-btn, .chip, .tag, .nav-item, .seg button, .fchip {
  transition: background var(--t-1) var(--ease), color var(--t-1) var(--ease),
              border-color var(--t-1) var(--ease), box-shadow var(--t-1) var(--ease),
              transform var(--t-1) var(--ease);
}
.btn:active:not(:disabled) { transform: translateY(.5px) }
.btn:disabled, .btn[disabled] { opacity: .5; cursor: not-allowed }

/* rows that navigate get a leading rule on hover, so the eye can
   follow the row across a wide table without losing the line */
.vrow, .svr, .ops-r, .cn-r, .dvu-r, .mrow, .cm-row, .ts-item, .dr-al {
  position: relative;
}
.vrow::before, .svr:not(.head)::before, .ops-r::before, .dvu-r::before {
  content: ''; position: absolute; inset: 0 auto 0 0; width: 0;
  background: var(--b600); border-radius: 0 2px 2px 0;
  transition: width var(--t-1) var(--ease);
}
.vrow:hover::before, .svr:not(.head):hover::before,
.ops-r:hover::before, .dvu-r:hover::before { width: 2px }
html[dir="rtl"] .vrow::before, html[dir="rtl"] .svr:not(.head)::before,
html[dir="rtl"] .ops-r::before, html[dir="rtl"] .dvu-r::before {
  inset: 0 0 0 auto; border-radius: 2px 0 0 2px;
}

/* ============================================================
   5 · EMPTY STATES

   An empty panel should say what would be there and why it is not.
   The old state was 40px of padding around one grey sentence, which
   read as a rendering failure rather than as "nothing to show".
   ============================================================ */
.empty {
  padding: 30px 22px; gap: 9px;
  animation: fadeIn var(--t-2) var(--ease) both;
}
.empty .e-ic {
  width: 40px; height: 40px; border-radius: 13px;
  background: var(--surface-3); color: var(--dim);
  display: grid; place-items: center;
}
.empty b { font-size: 13px; color: var(--text); font-weight: 600 }
.empty span:not(.e-ic) { font-size: 11.5px; color: var(--muted); max-width: 260px; line-height: 1.6 }

/* ============================================================
   6 · TABLE AND LIST RHYTHM
   ============================================================ */
/* every sticky header in the product sits on an opaque surface with a
   hairline under it — a translucent one lets rows ghost through */
.svr.head, .cn-r.head, .dz-r.head, .cl-r.head, .svc-cat.head, .ops-sec, .rcls-r.head {
  background: var(--surface);
  box-shadow: 0 1px 0 var(--line);
}
tbody tr, .vrow, .svr, .cn-r, .dvu-r { transition: background var(--t-1) var(--ease) }

/* numbers line up in columns or they are not worth tabulating */
.mono, [class*="-n"], .cn-r b, .dz-n, .gc-nums b, .ws-nums b, .h-v {
  font-variant-numeric: tabular-nums;
}

/* ============================================================
   7 · THE MAP HUD

   The panels over the map are the thing an operator looks past all
   day. They should recede until wanted: a touch more translucency, a
   softer edge, and no shadow heavy enough to read as a separate
   window sitting on the city.
   ============================================================ */
.glass {
  border-radius: 13px;
  transition: box-shadow var(--t-2) var(--ease);
}
.hud-stats { padding: 0 }
.h-v { letter-spacing: -.6px }
.h-l { letter-spacing: .03em }

/* the fleet row: identity first, then who and where, then the number
   that changes — three weights, one per question */
.vrow .vr-1 b { letter-spacing: -.1px }
.vrow .vr-bar { height: 3px; border-radius: 100px; overflow: hidden; background: var(--surface-3) }
.vrow .vr-bar i { transition: width var(--t-3) var(--ease) }
.vrow.on { background: var(--b50) }
body.dark .vrow.on { background: rgba(37, 99, 235, .14) }

/* ============================================================
   8 · TOASTS
   ============================================================ */
.toast {
  border-radius: 11px;
  box-shadow: var(--sh-3);
  backdrop-filter: saturate(1.4) blur(10px);
}
.toast.out { animation: fadeIn var(--t-2) var(--ease) reverse both }

/* ============================================================
   9 · FORM CONTROLS
   ============================================================ */
input, select, textarea { transition: border-color var(--t-1) var(--ease), box-shadow var(--t-1) var(--ease) }
input::placeholder, textarea::placeholder { color: var(--dim) }
select { cursor: pointer }
input[type="range"] { cursor: grab }
input[type="range"]:active { cursor: grabbing }

/* ============================================================
   10 · PRINT

   Somebody will print a scorecard for a contract meeting. Give them
   a page rather than a screenshot of a dark console.
   ============================================================ */
@media print {
  .side, .top, .scopebar, .chatfab, .chatdock, .alarmDrawer, .toasts,
  .hud, .fp-wrap, .mapkey-btn, .wstabs, .settabs { display: none !important }
  #app { grid-template-columns: 1fr; grid-template-areas: "main" }
  body, .card { background: #fff !important; color: #000 !important; box-shadow: none !important }
  .card { border: 1px solid #ccc !important; break-inside: avoid }
  a[href]::after { content: '' }
}

/* a good-news empty is a different message from a missing one */
.empty.ok .e-ic { background: var(--ok-bg); color: var(--ok) }
