/* =============================================================================
   Motion and polish (js/motion.js), loaded after app.css.

   Rules of the layer:
     - Short. 150-450ms for anything that answers a click; nothing on a working screen loops
       except the marks that mean "this is live" (a running job, the now line).
     - Nothing replays on the 20-second refresh. The timeline's entrance runs only when the plan,
       day, horizon or view changes (afterGanttRender in motion.js adds .gantt-enter for that).
     - Nothing moves a box the code measures. Bars arrive by clip-path and opacity, not by scale
       or translate, so fitBlockLabels() and the responsive audit read the same geometry during
       the entrance as after it. Dialogs fade and grow from 97% where they are, never sliding in
       from off-screen, so their actions are on screen from the first frame.
     - prefers-reduced-motion turns all of it off (the last block in this file).
   ============================================================================= */

:root {
  --ease-out: cubic-bezier(.2, .8, .2, 1);
  --ease-spring: cubic-bezier(.3, 1.35, .5, 1);
  /* One status palette for chips, dots, the plant strip and night mode alike. */
  --st-running: #147c41;
  --st-running-bg: #e5f7ed;
  --st-idle: #5c6c81;
  --st-idle-bg: #eef1f5;
  --st-blocked: #c0303c;
  --st-blocked-bg: #ffe5e7;
  --st-offline: #7b899b;
  --st-offline-bg: #f0f2f5;
  --st-waiting: #b4700a;
  --ring-track: #e3ebf3;
}

/* --- the busy bar ------------------------------------------------------------- */
.busy-bar { height: 3px; left: 0; overflow: hidden; pointer-events: none; position: fixed; right: 0; top: 0; z-index: 120; }
.busy-bar::before {
  background: linear-gradient(90deg, transparent, #2f8fe8 30%, #41b6e6 60%, transparent);
  content: ''; height: 100%; left: 0; opacity: 0; position: absolute; top: 0; transform: translateX(-100%); width: 45%;
}
.busy-bar.on::before { animation: busySlide 1.1s var(--ease-out) infinite; opacity: 1; }
.busy-bar.done::before { animation: none; opacity: 0; transition: opacity .3s ease; }
@keyframes busySlide { from { transform: translateX(-100%); } to { transform: translateX(240%); } }

/* --- the timeline's entrance -------------------------------------------------------- */
/* Bars draw in from their start, line by line, a beat apart. clip-path changes no box, so the
   label fitting and every measurement see the bar at its real size throughout. The end state
   is a clip larger than the bar, so its shadow and the new-order ring are never cut off. */
@keyframes barReveal {
  from { clip-path: inset(0 100% 0 0 round 4px); opacity: .25; }
  60%  { opacity: 1; }
  to   { clip-path: inset(-14px -14px -14px -14px); opacity: 1; }
}
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes growX { from { transform: scaleX(0); } to { transform: scaleX(1); } }

#dashboardGantt.gantt-enter .live-track > .planner-block {
  animation: barReveal .55s var(--ease-out) both;
  animation-delay: calc(var(--row-i, 0) * 70ms + var(--bar-i, 0) * 32ms);
}
#dashboardGantt.gantt-enter .live-track > .planner-block.is-spotlit {
  animation: barReveal .55s var(--ease-out) both, spotlit-pulse 1.9s ease-in-out 6;
  animation-delay: calc(var(--row-i, 0) * 70ms + var(--bar-i, 0) * 32ms), .7s;
}
#dashboardGantt.gantt-enter .live-track > .block-flag,
#dashboardGantt.gantt-enter .planned-ghost,
#dashboardGantt.gantt-enter .baseline-ghost { animation: fadeIn .5s ease both; animation-delay: calc(var(--row-i, 0) * 70ms + .25s); }
#dashboardGantt.gantt-enter .live-gantt-row { --row-delay: calc(var(--row-i, 0) * 70ms); }
#dashboardGantt.gantt-enter .line-use em { animation: growX .7s var(--ease-out) both; animation-delay: var(--row-delay); transform-origin: left center; }
#dashboardGantt.gantt-enter .live-elapsed-region { animation: fadeIn .6s ease both; }
/* Live and Planned week swapping: the chart cross-fades, so what moved between the two is seen. */
#dashboardGantt.gantt-swap .live-gantt-row,
#dashboardGantt.gantt-swap .live-gantt-axis { animation: fadeIn .32s ease both; }

/* --- live marks ------------------------------------------------------------------------ */
/* The now line breathes, so it is found at a glance on a wall screen. */
.live-now-line { animation: nowGlow 2.6s ease-in-out infinite; }
@keyframes nowGlow {
  0%, 100% { box-shadow: 0 0 0 1px rgba(224, 67, 61, .18); }
  50% { box-shadow: 0 0 0 1px rgba(224, 67, 61, .22), 0 0 10px 2px rgba(224, 67, 61, .35); }
}
.live-gantt-head .live-now-line::after { box-shadow: 0 2px 8px rgba(224, 67, 61, .35); }

/* A job running now carries a slow sheen, so the work in hand stands out from the work to come.
   The sheen is the bar's ::before, which the live states that use it (overrunning, waiting,
   late start) never share with "running". */
.planner-block.live-running::before,
.planner-block.status-in-progress:not([class*="live-"])::before {
  animation: runSheen 2.8s linear infinite;
  background: linear-gradient(105deg, transparent 0 38%, rgba(255, 255, 255, .26) 50%, transparent 62% 100%);
  background-size: 260% 100%;
  border-radius: inherit;
  content: '';
  inset: 0;
  pointer-events: none;
  position: absolute;
}
@keyframes runSheen { from { background-position: 130% 0; } to { background-position: -130% 0; } }
.planner-block.live-running,
.planner-block.status-in-progress:not([class*="live-"]) { box-shadow: 0 0 0 2px rgba(255, 255, 255, .55), 0 0 0 4px rgba(26, 163, 92, .45), 0 4px 12px rgba(18, 49, 80, .22); }

/* A line running or blocked says so with a pulse in its dot. */
.status-dot.running { animation: dotPulse 2.2s ease-out infinite; }
.status-dot.blocked { animation: dotPulseRed 2.2s ease-out infinite; }
@keyframes dotPulse { 0% { box-shadow: 0 0 0 0 rgba(26, 163, 92, .45); } 70%, 100% { box-shadow: 0 0 0 7px rgba(26, 163, 92, 0); } }
@keyframes dotPulseRed { 0% { box-shadow: 0 0 0 0 rgba(214, 61, 70, .45); } 70%, 100% { box-shadow: 0 0 0 7px rgba(214, 61, 70, 0); } }

/* --- moving a job ---------------------------------------------------------------------- */
.planner-block { transition: box-shadow .18s ease, filter .18s ease; }
.planner-block:not(.is-past-frozen):not(.is-inert):not([data-view-only]):hover { filter: brightness(1.06) saturate(1.05); }
/* Picked up: it lifts off the line. */
.planner-block.dragging {
  box-shadow: 0 16px 34px rgba(7, 25, 48, .38), 0 0 0 2px rgba(255, 255, 255, .85);
  filter: brightness(1.08);
  opacity: .96;
  transform: translateY(-4px) scale(1.02);
  transition: transform .16s var(--ease-spring), box-shadow .16s ease;
}
/* Over a slot it cannot take, it says so before it is dropped. */
.planner-block.dragging.drag-conflict { box-shadow: 0 16px 34px rgba(7, 25, 48, .38), 0 0 0 3px #e0433d, 0 0 18px rgba(224, 67, 61, .55); }
.live-track.drop-target { animation: dropTarget 1.2s ease-in-out infinite; }
@keyframes dropTarget { 0%, 100% { outline-color: #1b79ca; } 50% { outline-color: #7dbbf2; } }
/* Applied: it lands where it now sits. */
.planner-block.just-landed { animation: landed .7s var(--ease-spring); z-index: 4; }
@keyframes landed {
  0% { box-shadow: 0 0 0 0 rgba(65, 182, 230, .9), 0 8px 18px rgba(7, 25, 48, .3); filter: brightness(1.25); }
  100% { box-shadow: 0 0 0 14px rgba(65, 182, 230, 0), 0 3px 8px rgba(18, 49, 80, .16); filter: none; }
}

/* --- the plan goes live ----------------------------------------------------------------- */
.wb-timeline { position: relative; }
.plan-sweep {
  animation: planSweep 1.25s var(--ease-out) forwards;
  background: linear-gradient(90deg, transparent, rgba(65, 182, 230, .0) 10%, rgba(65, 182, 230, .32) 50%, rgba(255, 255, 255, .0) 90%, transparent);
  bottom: 0; left: 0; pointer-events: none; position: absolute; top: 0; width: 28%; z-index: 6;
}
@keyframes planSweep { from { opacity: 1; transform: translateX(-100%); } to { opacity: .2; transform: translateX(380%); } }
.plan-live-burst {
  align-items: center; animation: burstIn .5s var(--ease-spring) both;
  background: linear-gradient(135deg, #0d70db, #0a4f9e); border: 1px solid rgba(255, 255, 255, .25); border-radius: 999px;
  box-shadow: 0 24px 60px rgba(7, 25, 48, .35); color: #fff; display: flex; gap: 12px; left: 50%;
  padding: 12px 22px 12px 12px; pointer-events: none; position: fixed; top: 92px; transform: translateX(-50%); z-index: 70;
}
.plan-live-burst b { font-size: 16px; letter-spacing: .01em; white-space: nowrap; }
.plan-live-burst.leaving { animation: burstOut .45s ease forwards; }
.burst-check {
  align-items: center; animation: checkPop .55s var(--ease-spring) .15s both; background: #1aa35c; border-radius: 50%;
  box-shadow: 0 0 0 0 rgba(26, 163, 92, .6); display: flex; height: 34px; justify-content: center; width: 34px;
}
.burst-check path { animation: checkDraw .45s ease .3s both; stroke-dasharray: 24; stroke-dashoffset: 24; }
@keyframes burstIn { from { opacity: 0; transform: translate(-50%, -14px) scale(.9); } to { opacity: 1; transform: translate(-50%, 0) scale(1); } }
@keyframes burstOut { to { opacity: 0; transform: translate(-50%, -10px) scale(.96); } }
@keyframes checkPop { from { transform: scale(.4); } to { transform: scale(1); box-shadow: 0 0 0 10px rgba(26, 163, 92, 0); } }
@keyframes checkDraw { to { stroke-dashoffset: 0; } }
@media (max-width: 560px) { .plan-live-burst { top: 76px; } .plan-live-burst b { font-size: 14px; } }

/* --- the plant strip ---------------------------------------------------------------------- */
.plant-strip { display: grid; gap: 10px; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); margin: 0 0 12px; }
.plant-strip[hidden] { display: none; }
.ps-tile {
  align-items: center; background: #fff; border: 1px solid var(--line, #e3eaf2); border-left: 3px solid var(--st-idle);
  border-radius: 11px; box-shadow: 0 6px 16px rgba(20, 55, 90, .06); display: flex; gap: 12px; min-width: 0; padding: 10px 12px;
  transition: transform .18s ease, box-shadow .18s ease;
}
.ps-tile:hover { box-shadow: 0 10px 22px rgba(20, 55, 90, .1); transform: translateY(-1px); }
.ps-tile.tone-running { border-left-color: var(--st-running); }
.ps-tile.tone-blocked { border-left-color: var(--st-blocked); }
.ps-tile.tone-offline { border-left-color: var(--st-offline); opacity: .82; }
.ps-ring {
  --p: 0; align-items: center;
  background: radial-gradient(closest-side, #fff 76%, transparent 78% 100%), conic-gradient(var(--ps-ring, #1b79ca) calc(var(--p) * 1%), var(--ring-track) 0);
  border-radius: 50%; display: flex; flex: none; height: 46px; justify-content: center; transition: --p .6s ease; width: 46px;
}
.tone-running .ps-ring { --ps-ring: var(--st-running); }
.tone-blocked .ps-ring { --ps-ring: var(--st-blocked); }
.ps-ring span { color: #23415f; font-size: 11px; font-variant-numeric: tabular-nums; font-weight: 800; }
.ps-ring.is-empty span { color: #9aa7b6; }
.ps-text { display: grid; gap: 2px; min-width: 0; }
.ps-head { align-items: center; display: flex; gap: 8px; min-width: 0; }
.ps-head b { color: #173653; display: block; font-size: 13px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ps-head i { background: var(--st-idle-bg); border-radius: 99px; color: var(--st-idle); flex: none; font-size: 10px; font-style: normal; font-weight: 800; padding: 1px 8px; }
.tone-running .ps-head i { background: var(--st-running-bg); color: var(--st-running); }
.tone-blocked .ps-head i { background: var(--st-blocked-bg); color: var(--st-blocked); }
.tone-offline .ps-head i { background: var(--st-offline-bg); color: var(--st-offline); }
/* By day the Offline tag sits on a tile drawn at .82, which took its grey to 2.5:1; a darker grey reads
   4.8:1 through it (the accessibility audit, 2026-11-08). Night mode's own grey already reads. */
html:not([data-theme="dark"]) .tone-offline .ps-head i { color: #424c56; }
.ps-now { color: #26425f; display: block; font-size: 12px; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ps-text small { color: var(--muted, #5c6b7e); display: block; font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* A phone: one swipeable row, a tile and a bit of the next in view, rather than four squeezed
   tiles that cut every line's name short. */
@media (max-width: 560px) {
  .plant-strip { display: flex; gap: 8px; overflow-x: auto; padding-bottom: 4px; scroll-snap-type: x mandatory; scrollbar-width: none; }
  .plant-strip::-webkit-scrollbar { display: none; }
  .ps-tile { flex: 0 0 min(250px, 78%); gap: 9px; padding: 8px 10px; scroll-snap-align: start; }
  .ps-tile:hover { transform: none; }
  .ps-ring { height: 40px; width: 40px; }
  .ps-ring span { font-size: 10px; }
}

/* --- jump to now ---------------------------------------------------------------------------- */
.now-pill {
  animation: pillIn .25s var(--ease-spring) both; background: #e0433d; border: 0; border-radius: 99px;
  box-shadow: 0 8px 20px rgba(224, 67, 61, .35); color: #fff; cursor: pointer; font: inherit; font-size: 12px; font-weight: 800;
  letter-spacing: .03em; padding: 7px 13px; position: absolute; top: 0; z-index: 7;
}
/* Placed beside the axis by syncNowPill() in motion.js, on the side the now line went off. */
.now-pill[hidden] { display: none; }
.now-pill:hover { background: #c8322c; }
.now-pill:focus-visible { outline: 2px solid var(--ink, #132238); outline-offset: 2px; }
@keyframes pillIn { from { opacity: 0; transform: scale(.85); } to { opacity: 1; transform: none; } }
@media (pointer: coarse) { .now-pill { min-height: var(--tap, 40px); } }

/* --- segmented switches ----------------------------------------------------------------------- */
.segmented { position: relative; }
.segmented > button { position: relative; z-index: 1; }
.segmented > .seg-ind { background: #165fae; border-radius: 6px; box-shadow: 0 3px 8px rgba(22, 95, 174, .3); left: 0; opacity: 0; pointer-events: none; position: absolute; top: 0; z-index: 0; }
.segmented.has-ind > .seg-ind { opacity: 1; }
.segmented.seg-ready > .seg-ind { transition: transform .3s var(--ease-out), width .3s var(--ease-out), height .3s var(--ease-out); }
.segmented.has-ind > button.active { background: transparent; }
.segmented > button:not(.active):hover { color: #1b4f86; }

/* --- the order list and counts ----------------------------------------------------------------- */
.ord-card.just-added { animation: ord-added 2.6s ease-out, ordSlideIn .5s var(--ease-spring); }
@keyframes ordSlideIn { from { opacity: 0; transform: translateX(-14px) scale(.98); } to { opacity: 1; transform: none; } }
.bump { animation: bump .45s var(--ease-spring); }
@keyframes bump { 0% { transform: scale(1); } 40% { transform: scale(1.22); } 100% { transform: scale(1); } }
.batch-count { display: inline-block; transition: background .25s ease, color .25s ease; }
.batch-row { animation: fadeIn .3s ease both; transition: border-color .18s ease, box-shadow .18s ease, transform .18s ease; }
.batch-row:hover { box-shadow: 0 6px 14px rgba(20, 55, 90, .08); transform: translateY(-1px); }

/* --- buttons ------------------------------------------------------------------------------------- */
.primary { transition: transform .14s ease, box-shadow .18s ease, background .18s ease; }
.primary:not(:disabled):hover { box-shadow: 0 9px 20px rgba(13, 103, 207, .28); transform: translateY(-1px); }
.primary:not(:disabled):active { transform: translateY(0) scale(.985); }
.secondary { transition: transform .14s ease, background .15s ease, border-color .15s ease; }
.secondary:not(:disabled):active { transform: scale(.98); }

/* --- pages and dialogs --------------------------------------------------------------------------- */
/* No fill mode: an opacity animation that holds its last frame keeps the page in a stacking context
   of its own, and the maximized timeline -- position: fixed inside it -- was drawn under the sticky
   top bar instead of over it. */
.view.active { animation: fadeIn .28s ease; }
dialog.dialog[open] { animation: dialogIn .2s var(--ease-out) both; transform-origin: 50% 50%; }
dialog.dialog[open]::backdrop { animation: fadeIn .2s ease both; backdrop-filter: blur(2px); }
@keyframes dialogIn { from { opacity: 0; transform: scale(.97); } to { opacity: 1; transform: none; } }
@media (max-width: 560px) { dialog.dialog[open] { transform-origin: 50% 100%; } }
.sections-menu:not(.hidden), .user-menu:not(.hidden), .bell-panel:not(.hidden) { animation: menuIn .16s var(--ease-out) both; transform-origin: top right; }
.sections-menu:not(.hidden) { transform-origin: top left; }
@keyframes menuIn { from { opacity: 0; transform: translateY(-4px) scale(.98); } to { opacity: 1; transform: none; } }

/* --- toasts ------------------------------------------------------------------------------------- */
.toast { cursor: pointer; overflow: hidden; padding-left: 44px; }
.toast::before {
  align-items: center; background: rgba(255, 255, 255, .18); border-radius: 50%; content: 'i'; display: flex; font-size: 12px;
  font-weight: 900; height: 22px; justify-content: center; left: 13px; position: absolute; top: 50%; transform: translateY(-50%); width: 22px;
}
.toast.success::before { content: '✓'; }
.toast.error::before { content: '!'; }
.toast::after { animation: toastLife 5.2s linear forwards; background: rgba(255, 255, 255, .45); bottom: 0; content: ''; height: 3px; left: 0; position: absolute; right: 0; transform-origin: left; }
@keyframes toastLife { from { transform: scaleX(1); } to { transform: scaleX(0); } }
@keyframes toastIn { from { opacity: 0; transform: translateY(14px) scale(.97); } to { opacity: 1; transform: none; } }

/* --- loading ------------------------------------------------------------------------------------- */
/* Before the first state arrives these boxes are empty: they shimmer instead of sitting blank.
   Each is always filled once drawn -- a message when there is nothing to show -- so the shimmer
   can only ever be the moment before the first draw. */
@keyframes shimmer { from { background-position: 180% 0; } to { background-position: -80% 0; } }
#dashboardGantt:empty,
#ordersBoard:empty,
#batchFigures:empty,
#maintenanceLines:empty {
  animation: shimmer 1.4s ease-in-out infinite;
  background: linear-gradient(100deg, #eef3f8 30%, #f8fbfe 50%, #eef3f8 70%);
  background-size: 260% 100%;
  border-radius: 10px;
}
#dashboardGantt:empty { min-height: 300px; }
#ordersBoard:empty { min-height: 220px; }
#batchFigures:empty { min-height: 64px; }
#maintenanceLines:empty { min-height: 200px; }
/* A report's PDF on its way: the preview frame shimmers until it has loaded. */
.report-result.preview-loading .report-preview {
  animation: shimmer 1.4s ease-in-out infinite;
  background: linear-gradient(100deg, #eef3f8 30%, #f8fbfe 50%, #eef3f8 70%);
  background-size: 260% 100%;
}

/* --- empty states ----------------------------------------------------------------------------- */
/* A drawing, not more words: the wording already there says what to do. */
.wb-step-empty, .batch-list .queue-empty, .ord-board .status-clear, .report-empty { position: relative; }
.wb-step-empty::before,
.batch-list .queue-empty::before,
.ord-board .status-clear::before,
.report-empty::before {
  background: center / contain no-repeat;
  content: ''; display: block; height: 46px; margin: 0 auto 10px; opacity: .9; width: 46px;
}
.wb-step-empty::before { display: inline-block; height: 22px; margin: 0 10px 0 0; vertical-align: middle; width: 22px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%237ea8d0' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='4' y='3' width='16' height='18' rx='2'/%3E%3Cpath d='M8 8h8M8 12h8M8 16h5'/%3E%3C/svg%3E"); }
.batch-list .queue-empty::before {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48' fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='7' y='16' width='34' height='22' rx='4' fill='%23eaf4ff' stroke='%237ea8d0' stroke-width='2'/%3E%3Cpath d='M7 27h10l3 5h8l3-5h10' stroke='%237ea8d0' stroke-width='2'/%3E%3Cpath d='M24 6v12M19 13l5 5 5-5' stroke='%231b79ca' stroke-width='2.2'/%3E%3C/svg%3E"); }
.ord-board .status-clear::before {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48' fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='9' y='7' width='26' height='32' rx='3' fill='%23eaf4ff' stroke='%237ea8d0' stroke-width='2'/%3E%3Cpath d='M15 16h14M15 22h14M15 28h8' stroke='%237ea8d0' stroke-width='2'/%3E%3Ccircle cx='33' cy='33' r='7' fill='%23fff' stroke='%231b79ca' stroke-width='2.2'/%3E%3Cpath d='M38 38l4 4' stroke='%231b79ca' stroke-width='2.4'/%3E%3C/svg%3E"); }
.report-empty::before { height: 58px; width: 58px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48' fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 6h17l9 9v27H12z' fill='%23eaf4ff' stroke='%237ea8d0' stroke-width='2'/%3E%3Cpath d='M29 6v9h9' stroke='%237ea8d0' stroke-width='2'/%3E%3Cpath d='M18 34v-6M24 34V22M30 34v-9' stroke='%231b79ca' stroke-width='2.6'/%3E%3C/svg%3E"); }
.ord-board .status-clear { display: grid; justify-items: center; }

/* --- the command palette ------------------------------------------------------------------------- */
.palette-button svg { display: block; }
@media (max-width: 760px) { .palette-button { display: none !important; } }
.palette-dialog { border: 1px solid var(--line, #e3eaf2); border-radius: 16px; box-shadow: 0 30px 80px rgba(7, 25, 48, .35); margin: 12vh auto auto; max-height: 70vh; padding: 0; width: min(640px, calc(100vw - 32px)); }
.palette-dialog[open] { animation: dialogIn .18s var(--ease-out) both; display: flex; flex-direction: column; }
.palette-dialog::backdrop { animation: fadeIn .18s ease both; backdrop-filter: blur(3px); background: rgba(7, 20, 40, .42); }
.palette { display: flex; flex-direction: column; min-height: 0; }
.palette-input-wrap { align-items: center; border-bottom: 1px solid var(--line, #e3eaf2); display: flex; gap: 10px; padding: 14px 16px; }
.palette-input-wrap svg { color: #7b8ea3; flex: none; }
#paletteInput { background: transparent; border: 0; color: var(--ink, #132238); flex: 1; font: inherit; font-size: 16px; min-width: 0; outline: 0; padding: 4px 0; }
.palette-list { list-style: none; margin: 0; max-height: calc(70vh - 110px); overflow-y: auto; padding: 6px; }
.palette-group { color: #6d7f94; font-size: 10px; font-weight: 850; letter-spacing: .1em; padding: 10px 10px 4px; text-transform: uppercase; }
.palette-item { align-items: baseline; border-radius: 9px; cursor: pointer; display: flex; gap: 10px; min-width: 0; padding: 9px 10px; }
.palette-item b { color: #173653; flex: none; font-size: 13px; }
.palette-item small { color: var(--muted, #5c6b7e); font-size: 12px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.palette-item.active { background: #eaf4ff; box-shadow: inset 3px 0 0 #1b79ca; }
.palette-none { color: var(--muted, #5c6b7e); padding: 22px 12px; text-align: center; }
.palette-foot { border-top: 1px solid var(--line, #e3eaf2); color: #7b8ea3; font-size: 11px; margin: 0; padding: 9px 16px; }
.palette-foot kbd { background: #f1f5f9; border: 1px solid #d8e0ea; border-bottom-width: 2px; border-radius: 4px; font: inherit; font-size: 10px; font-weight: 800; margin: 0 2px; padding: 0 5px; }

/* --- the menu under the name: preferences ---------------------------------------------------------- */
.user-menu { width: 196px; }
.menu-prefs { border-top: 1px solid var(--line, #e3eaf2); display: grid; gap: 2px; margin-top: 4px; padding-top: 4px; }
.menu-toggle { align-items: center; border-radius: 7px; color: var(--ink, #10243e); cursor: pointer; display: flex; font-weight: 600; gap: 10px; justify-content: space-between; padding: 8px 10px; }
.menu-toggle:hover { background: #eef3f9; }
.menu-toggle input { appearance: none; background: #cfd9e4; border-radius: 99px; cursor: pointer; flex: none; height: 18px; margin: 0; position: relative; transition: background .2s ease; width: 32px; }
.menu-toggle input::after { background: #fff; border-radius: 50%; box-shadow: 0 1px 3px rgba(0, 0, 0, .25); content: ''; height: 14px; left: 2px; position: absolute; top: 2px; transition: transform .22s var(--ease-spring); width: 14px; }
.menu-toggle input:checked { background: #1b79ca; }
.menu-toggle input:checked::after { transform: translateX(14px); }
.menu-toggle input:focus-visible { outline: 2px solid #1b79ca; outline-offset: 2px; }
@media (pointer: coarse) { .menu-toggle { min-height: var(--tap, 40px); } }

/* --- reduced motion: all of the above stands down ------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  #dashboardGantt.gantt-enter *, #dashboardGantt.gantt-swap *,
  .live-now-line, .planner-block::before, .status-dot.running, .status-dot.blocked,
  .live-track.drop-target, .planner-block.just-landed, .plan-sweep, .plan-live-burst, .burst-check, .burst-check path,
  .now-pill, .ord-card.just-added, .bump, .batch-row, .view.active, dialog.dialog[open], dialog.dialog[open]::backdrop,
  .sections-menu, .user-menu, .bell-panel, .toast, .toast::after, .busy-bar::before,
  #dashboardGantt:empty, #ordersBoard:empty, #batchFigures:empty, #maintenanceLines:empty,
  .report-result.preview-loading .report-preview, .palette-dialog[open], .palette-dialog::backdrop {
    animation: none !important;
  }
  .planner-block.dragging, .primary, .secondary, .ps-tile, .batch-row, .segmented.seg-ready > .seg-ind, .menu-toggle input::after { transition: none !important; }
  .plan-sweep { display: none; }
}

/* The legend's "Planned position" swatch took .planned-ghost's absolute positioning from the
   timeline and sat on top of its own label. In the legend it is an ordinary swatch. */
.legend.planned-ghost { bottom: auto; height: 9px; opacity: 1; position: static; }

/* Holding a view's button to peek at it (bindPeek in motion.js). */
.segmented.is-peeking { box-shadow: 0 0 0 2px #41b6e6, 0 0 14px rgba(65, 182, 230, .45); }
