/* Command Center shell.
   Every --cc-* token (colors + spacing/radii/width) now lives in the unified
   theme blocks in index.html :root and flips with [data-theme] on <html>, so
   the whole shell flips light<->dark with the rest of the app. This element
   just consumes them. The old per-shell token block, the legacy-token remaps,
   and the dead [data-cc-theme] stub were removed so there is a SINGLE theme
   mechanism (data-theme). */
.manager-shell {
  min-height: 100dvh;
  background: var(--cc-app);
  color: var(--cc-text);
}

.manager-shell *,
.manager-shell *::before,
.manager-shell *::after {
  box-sizing: border-box;
}

.manager-shell :is(button, a, input, select, textarea):focus-visible {
  outline: 2px solid transparent;
  box-shadow: var(--cc-focus);
}

.s57-shell {
  position: relative;
  display: grid;
  grid-template-columns: var(--cc-sidebar-width) minmax(0, 1fr);
  min-height: 100dvh;
  background: var(--cc-app);
}

.s57-shell__sidebar-region {
  min-width: 0;
  min-height: 100dvh;
  background: var(--cc-sidebar);
}

.s57-shell__workspace {
  min-width: 0;
  height: 100dvh;
  overflow: hidden;
  background: var(--cc-panel);
}

.s57-shell__main {
  height: 100%;
  overflow-x: hidden;
  overflow-y: auto;
  padding: var(--cc-space-6);
  color: var(--cc-text);
}

.s57-page-content {
  min-width: 0;
}

.s57-sidebar {
  position: fixed;
  inset: 0 auto 0 0;
  z-index: 60;
  display: flex;
  flex-direction: column;
  width: var(--cc-sidebar-width);
  min-height: 100dvh;
  overflow: hidden;
  background: var(--cc-sidebar);
  color: var(--cc-sidebar-ink);
  border-right: 1px solid var(--cc-sidebar-border);
}

.s57-sidebar[hidden] {
  display: none;
}

.s57-sidebar__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--cc-space-3);
  min-height: 72px;
  padding: var(--cc-space-4);
  border-bottom: 1px solid var(--cc-sidebar-border);
}

.s57-sidebar__brand {
  font-size: 16px;
  font-weight: 800;
  letter-spacing: -.02em;
}

.s57-sidebar__brand-mark {
  display: inline-grid;
  place-items: center;
  width: 36px;
  height: 36px;
  margin-right: var(--cc-space-3);
  border-radius: var(--cc-radius-sm);
  background: var(--cc-blue-strong);
  color: #fff;
}

.s57-sidebar__items {
  flex: 1;
  overflow-y: auto;
  padding: var(--cc-space-3) var(--cc-space-2);
}

.s57-sidebar__item {
  display: flex;
  align-items: center;
  gap: var(--cc-space-3);
  width: 100%;
  min-height: 44px;
  margin-bottom: var(--cc-space-1);
  padding: 0 var(--cc-space-3);
  border: 0;
  border-left: 3px solid transparent;
  border-radius: 10px;
  background: var(--cc-clear);
  color: var(--cc-sidebar-ink-dim);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  text-align: left;
  cursor: pointer;
  transition: background-color .18s ease, color .18s ease, border-color .18s ease;
}

.s57-sidebar__item:hover {
  background: var(--cc-sidebar-hover);
  color: var(--cc-sidebar-ink);
}

.s57-sidebar__item.is-active {
  border-left-color: var(--cc-blue);
  background: var(--cc-sidebar-active);
  color: var(--cc-sidebar-active-ink);
}

.s57-sidebar__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  flex: 0 0 20px;
}

.s57-sidebar__icon svg {
  width: 19px;
  height: 19px;
}

.s57-sidebar__footer {
  display: grid;
  gap: var(--cc-space-2);
  padding: var(--cc-space-3);
  border-top: 1px solid var(--cc-sidebar-border);
}

.s57-sidebar__footer .s57-button {
  justify-content: flex-start;
  color: var(--cc-sidebar-ink-dim);
  border-color: var(--cc-sidebar-border);
}

.s57-sidebar__close {
  flex: 0 0 44px;
  background: var(--cc-sidebar-hover);
  color: var(--cc-sidebar-ink);
  border-color: var(--cc-sidebar-border);
}

.s57-drawer-backdrop {
  position: fixed;
  inset: 0;
  z-index: 70;
  width: 100%;
  height: 100%;
  border: 0;
  background: var(--overlay-scrim);
  cursor: default;
}

.s57-mobile-header {
  display: none;
  position: sticky;
  top: 0;
  z-index: 45;
  align-items: center;
  gap: var(--cc-space-3);
  min-height: calc(64px + var(--safe-top));
  padding: calc(var(--cc-space-3) + var(--safe-top)) var(--cc-space-4) var(--cc-space-3);
  background: var(--cc-sidebar);
  color: var(--cc-sidebar-ink);
  border-bottom: 1px solid var(--cc-sidebar-border);
}

.s57-mobile-header__title {
  display: flex;
  flex: 1;
  min-width: 0;
  flex-direction: column;
}

.s57-mobile-header__title span {
  color: var(--cc-sidebar-ink-dim);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
}

.s57-mobile-header__title strong {
  overflow: hidden;
  color: var(--cc-sidebar-ink);
  font-size: 17px;
  line-height: 1.25;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.s57-mobile-header__actions {
  display: flex;
  align-items: center;
  gap: var(--cc-space-2);
}

.s57-legacy-mobile-header {
  background: var(--cc-sidebar) !important;
  color: var(--cc-sidebar-ink) !important;
  border-bottom-color: var(--cc-sidebar-border) !important;
}

.s57-legacy-mobile-header :is(h1, p) {
  color: var(--cc-sidebar-ink) !important;
}

.s57-legacy-mobile-header button {
  min-width: 44px;
  min-height: 44px;
  border-color: var(--cc-sidebar-border) !important;
  background: var(--cc-sidebar-hover) !important;
  color: var(--cc-sidebar-ink) !important;
}

.s57-icon-button {
  display: inline-grid;
  place-items: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0;
  border: 1px solid var(--cc-border);
  border-radius: var(--cc-radius-sm);
  background: var(--cc-card);
  color: var(--cc-text);
  font: inherit;
  font-size: 24px;
  line-height: 1;
  cursor: pointer;
}

.s57-mobile-header > .s57-icon-button {
  border-color: var(--cc-sidebar-border);
  background: var(--cc-sidebar-hover);
  color: var(--cc-sidebar-ink);
}

.s57-page-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--cc-space-6);
  margin: 0 auto var(--cc-space-6);
  max-width: 1440px;
}

.s57-page-header__copy {
  min-width: 0;
}

.s57-eyebrow {
  margin: 0 0 var(--cc-space-1);
  color: var(--cc-muted);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .1em;
  text-transform: uppercase;
}

.s57-page-header h1 {
  margin: 0;
  color: var(--cc-text);
  font-size: clamp(24px, 2vw, 32px);
  font-weight: 800;
  letter-spacing: -.035em;
  line-height: 1.1;
}

.s57-page-header__description,
.s57-page-header__aside {
  color: var(--cc-muted);
  font-size: 13px;
}

.s57-page-header__description {
  max-width: 70ch;
  margin: var(--cc-space-2) 0 0;
  line-height: 1.55;
}

.s57-page-header__aside {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--cc-space-2);
  flex-wrap: wrap;
}

.s57-metric,
.s57-card,
.s57-mobile-card,
.s57-photo,
.s57-sensor {
  border: 1px solid var(--cc-border);
  background: var(--cc-card);
  color: var(--cc-text);
  box-shadow: var(--cc-shadow-sm);
}

.s57-metric {
  min-width: 0;
  padding: var(--cc-space-4);
  border-radius: var(--cc-radius-md);
}

.s57-metric__top,
.s57-photo__heading,
.s57-sensor__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--cc-space-2);
}

/* H-6: the stocking photo wall is a 2-up grid on a phone, so a photo card can
   be ~150px wide. The status badge is `white-space: nowrap` (correct in a wide
   row, wrong here) and a label like "detection_failed" ran straight out of the
   card — invisibly, because .s57-shell__main is overflow-x:hidden. Inside a
   photo card the badge wraps instead of escaping, and takes its own line when
   the title needs the width. */
.s57-photo__heading { flex-wrap: wrap; }
.s57-photo__heading h3 { min-width: 0; overflow-wrap: anywhere; }
.s57-photo__heading .s57-status {
  max-width: 100%;
  white-space: normal;
  overflow-wrap: anywhere;
  text-align: center;
}

.s57-metric__top p,
.s57-metric__detail {
  margin: 0;
  color: var(--cc-muted);
  font-size: 11px;
}

.s57-metric__top p {
  font-weight: 800;
  letter-spacing: .06em;
  text-transform: uppercase;
}

.s57-metric__value {
  display: block;
  margin: var(--cc-space-2) 0 var(--cc-space-1);
  font-size: clamp(24px, 3vw, 34px);
  font-variant-numeric: tabular-nums;
  letter-spacing: -.04em;
  line-height: 1;
}

.s57-status {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 28px;
  padding: 4px 9px;
  border: 1px solid currentColor;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 800;
  line-height: 1;
  white-space: nowrap;
}

.s57-tone--neutral { color: var(--cc-muted); }
.s57-tone--info { color: var(--cc-blue); }
.s57-tone--success { color: var(--status-success-ink); }
.s57-tone--warning { color: var(--status-warning-ink); }
.s57-tone--critical { color: var(--status-critical-ink); }

.s57-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--cc-space-2);
  min-height: 44px;
  padding: 0 var(--cc-space-4);
  border: 1px solid transparent;
  border-radius: var(--cc-radius-sm);
  font: inherit;
  font-size: 13px;
  font-weight: 800;
  line-height: 1.2;
  cursor: pointer;
  transition: background-color .18s ease, border-color .18s ease, color .18s ease;
}

/* --cc-blue-strong, not --cc-blue: white on the DARK-theme --cc-blue (#3B82F6)
   measures 3.68:1 against AA's 4.5. The strong token is that same blue one step
   darker (#2563EB dark / #1D4ED8 light) and gives 5.17 / 6.70.
   It is a TOKEN, deliberately, not a `[data-theme="dark"] .selector` override:
   this file forbids per-element theme overrides (see the note near line 1001,
   and tests/theme-machinery.spec.js:108 which fails the build for one). Theme
   differences belong in the token values, in one place. */
.s57-button--primary { background: var(--cc-blue-strong); color: #fff; }
.s57-button--secondary { background: var(--cc-card); color: var(--cc-text); border-color: var(--cc-border); }
.s57-button--quiet { background: transparent; color: var(--cc-muted); border-color: transparent; }
.s57-button--success { background: var(--status-success-bg); color: var(--status-success-ink); }
.s57-button--warning { background: var(--cc-warning); color: #3A2500; }
.s57-button--destructive { background: var(--status-critical-bg); color: var(--status-critical-ink); }

.s57-button:disabled {
  cursor: not-allowed;
  opacity: .48;
}

/* H-1/H-5 (2026-08-13): this ONE rule set now backs every sub-tab strip in the
   manager app — Operations, Settings, Cold Storage, the Staff agenda day
   picker, and (newly) Pricebook, Review Hub and the Performance period
   selector, which each used to hand-roll their own geometry. Changes here are
   felt in all seven places, which is the point. */
.s57-tabs {
  display: flex;
  gap: var(--cc-space-2);
  max-width: 100%;
  margin-bottom: var(--cc-space-4);
  overflow-x: auto;
  overflow-y: hidden;
  /* Hide the scrollbar in both engines: Firefox showed a chrome-coloured track
     over the pills, and iOS never renders one at all — so the bar could never
     be the affordance. The [data-scroll] fade below is the affordance. */
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  /* A horizontal drag on the strip must not chain into the page's own
     scroller (or the browser's back-swipe) once the strip hits its end. */
  overscroll-behavior-x: contain;
  scroll-padding-inline: var(--cc-space-4);
}

.s57-tabs::-webkit-scrollbar { width: 0; height: 0; display: none; }

/* Edge-fade affordance. PillTabs writes data-scroll = none|start|end|both from
   a real scrollWidth/scrollLeft measurement, so a side only fades when content
   is actually hidden on that side. A permanently-masked strip would be
   decoration; this one is a readout. */
.s57-tabs[data-scroll="end"] {
  -webkit-mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 28px), transparent 100%);
  mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 28px), transparent 100%);
}
.s57-tabs[data-scroll="start"] {
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 28px, #000 100%);
  mask-image: linear-gradient(to right, transparent 0, #000 28px, #000 100%);
}
.s57-tabs[data-scroll="both"] {
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 28px, #000 calc(100% - 28px), transparent 100%);
  mask-image: linear-gradient(to right, transparent 0, #000 28px, #000 calc(100% - 28px), transparent 100%);
}

.s57-tabs__tab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
  min-width: max-content;
  min-height: 44px;
  padding: 0 var(--cc-space-4);
  border: 1px solid var(--cc-border);
  border-radius: 999px;
  background: var(--cc-card);
  color: var(--cc-muted);
  font: inherit;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
  scroll-snap-align: center;
}

.s57-tabs__label { white-space: nowrap; }

/* Count badge (Pricebook review queue, Review Hub filters). Reads as a
   secondary number inside the pill, and inverts on the selected pill so it
   stays legible on --cc-blue. */
.s57-tabs__badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--cc-panel);
  color: var(--cc-muted);
  font-family: var(--mono, monospace);
  font-size: 11px;
  font-weight: 700;
  line-height: 18px;
}

.s57-tabs__tab[aria-selected="true"] {
  border-color: var(--cc-blue);
  background: var(--cc-blue-strong);
  color: #fff;
}

.s57-tabs__tab[aria-selected="true"] .s57-tabs__badge {
  /* B-27: a 22%-white pill under white 11px digits measured 3.49 light /
     2.70 dark — the queue COUNT was the least readable thing on the tab.
     Inverted so the count sits on near-solid white in the tab's own blue. */
  background: rgba(255, 255, 255, .92);
  color: var(--cc-blue);
}

/* A tab that is deliberately not yet available (U-8). Not a disabled pill that
   looks like it should work — muted, default cursor, and it carries a "Soon"
   chip so the state is stated, not implied. */
.s57-tabs__tab:disabled,
.s57-tabs__tab[aria-disabled="true"] {
  cursor: default;
  opacity: .55;
  background: transparent;
  border-style: dashed;
}

.s57-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.s57-card {
  overflow: hidden;
  border-radius: var(--cc-radius-md);
}

.s57-card__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--cc-space-4);
  padding: var(--cc-space-4) var(--cc-space-4) 0;
}

.s57-card__header h2,
.s57-mobile-card h3,
.s57-photo h3,
.s57-sensor h3 {
  margin: 0;
  color: var(--cc-text);
  font-size: 15px;
  font-weight: 800;
}

.s57-card__header p,
.s57-mobile-card p {
  margin: var(--cc-space-1) 0 0;
  color: var(--cc-muted);
  font-size: 12px;
}

.s57-card__body {
  padding: var(--cc-space-4);
}

.s57-table-wrap {
  max-width: 100%;
  overflow-x: auto;
  border: 1px solid var(--cc-border);
  border-radius: var(--cc-radius-md);
  background: var(--cc-card);
}

.s57-table {
  width: 100%;
  border-collapse: collapse;
  color: var(--cc-text);
  font-size: 13px;
}

.s57-table caption {
  padding: var(--cc-space-3);
  text-align: left;
  font-weight: 800;
}

.s57-table th,
.s57-table td {
  padding: var(--cc-space-3) var(--cc-space-4);
  border-bottom: 1px solid var(--cc-border);
  text-align: left;
  vertical-align: middle;
}

.s57-table th {
  background: var(--bg3);
  color: var(--cc-muted);
  font-size: 11px;
  letter-spacing: .05em;
  text-transform: uppercase;
}

.s57-table .is-right { text-align: right; }
.s57-table .is-center { text-align: center; }

.s57-mobile-card {
  padding: var(--cc-space-4);
  border-radius: var(--cc-radius-md);
}

.s57-mobile-card__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--cc-space-3);
}

.s57-mobile-card__meta {
  display: grid;
  gap: var(--cc-space-2);
  margin-top: var(--cc-space-3);
  color: var(--cc-muted);
  font-size: 12px;
}

/* H-2 · Pricebook catalog card (mobile). Built on .s57-mobile-card so it
   inherits the design system's surface, border, radius and shadow; only the
   internals are pricebook-specific. */
.pb-card__name {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  /* Two lines, then ellipsis — tapping toggles .is-expanded and shows it all. */
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow-wrap: anywhere;
}
.pb-card__name.is-expanded {
  display: block;
  -webkit-line-clamp: none;
  overflow: visible;
}
.pb-card__name:focus-visible { outline: 2px solid transparent; box-shadow: var(--cc-focus); border-radius: 6px; }

.pb-card__price {
  display: grid;
  justify-items: end;
  gap: 4px;
  flex: 0 0 auto;
  text-align: right;
  /* The price is the answer this screen exists to give. It never wraps and it
     is never clipped — the name yields space to it, not the other way round. */
  white-space: nowrap;
}
.pb-card__retail {
  font-family: var(--mono, monospace);
  font-size: 17px;
  font-weight: 800;
  line-height: 1.1;
}
.pb-card__margin {
  min-width: 54px;
  padding: 2px 8px;
  border-radius: 7px;
  font-family: var(--mono, monospace);
  font-size: 12px;
  font-weight: 800;
  text-align: center;
}
.pb-card__cost {
  font-family: var(--mono, monospace);
  font-size: 11px;
}

.pb-card__meta {
  display: flex;
  align-items: center;
  gap: var(--cc-space-3);
  min-width: 0;
}
.pb-card__chips {
  display: flex;
  align-items: center;
  gap: 7px;
  flex-wrap: wrap;
  min-width: 0;
}
.pb-card__chip {
  padding: 2px 8px;
  border-radius: 5px;
  font-size: 11px;
  font-weight: 800;
  overflow-wrap: anywhere;
}

.pb-card__select {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  padding: 0 12px;
  border: 1px solid var(--cc-border);
  border-radius: 9px;
  color: var(--cc-muted);
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
}

.s57-mobile-card__actions,
.s57-photo__actions,
.s57-sensor__actions {
  display: flex;
  gap: var(--cc-space-2);
  margin-top: var(--cc-space-4);
  flex-wrap: wrap;
}

.s57-overlay {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: grid;
  place-items: center;
  padding: var(--cc-space-4);
  background: var(--overlay-scrim);
}

.s57-dialog,
.s57-lightbox {
  width: min(100%, 680px);
  max-height: min(90dvh, 900px);
  overflow: auto;
  /* H-7: a dialog IS a legitimate scroller, but it sits over the page scroller
     — without this, hitting its end continues the gesture on the dashboard
     behind it. */
  overscroll-behavior: contain;
  border: 1px solid var(--cc-border);
  border-radius: var(--cc-radius-lg);
  background: var(--cc-card);
  color: var(--cc-text);
  box-shadow: var(--cc-shadow-md);
}

.s57-dialog--sm { max-width: 480px; }
.s57-dialog--lg { max-width: 920px; }

.s57-dialog__header,
.s57-lightbox__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--cc-space-4);
  padding: var(--cc-space-4);
  border-bottom: 1px solid var(--cc-border);
}

.s57-dialog__header h2,
.s57-lightbox__header h2 {
  margin: 0;
  color: var(--cc-text);
  font-size: 20px;
}

.s57-dialog__header p {
  margin: var(--cc-space-1) 0 0;
  color: var(--cc-muted);
  font-size: 12px;
}

.s57-dialog__body {
  padding: var(--cc-space-4);
}

.s57-dialog__footer,
.s57-lightbox__controls {
  display: flex;
  justify-content: flex-end;
  gap: var(--cc-space-2);
  padding: var(--cc-space-4);
  border-top: 1px solid var(--cc-border);
}

.s57-overlay--lightbox {
  background: rgba(2, 8, 18, .84);
}

.s57-lightbox {
  width: min(96vw, 1200px);
  background: var(--cc-lightbox-bg);
  color: #fff;
  border-color: rgba(255, 255, 255, .15);
}

.s57-lightbox__header {
  border-bottom-color: rgba(255, 255, 255, .12);
}

.s57-lightbox__header h2 {
  color: #fff;
}

.s57-lightbox__stage {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 320px;
  padding: var(--cc-space-4);
}

.s57-lightbox__stage img {
  display: block;
  width: auto;
  max-width: 100%;
  max-height: 72dvh;
  object-fit: contain;
}

.s57-lightbox__controls {
  border-top-color: rgba(255, 255, 255, .12);
}

.s57-state {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--cc-space-3);
  min-height: 120px;
  padding: var(--cc-space-6);
  color: var(--cc-muted);
  text-align: center;
}
/* U-11: an empty state that owns a CTA has two children on one row. At 320px
   the row squeezed the button into a 4-line sliver next to the message, so the
   action stacks under the copy on a phone instead of competing with it. */
@media (max-width: 480px) {
  .s57-state {
    flex-direction: column;
    min-width: 0;
  }
}

.s57-state h3,
.s57-state p {
  margin: 0;
}

.s57-state h3 {
  color: var(--cc-text);
  font-size: 15px;
}

.s57-state p {
  margin-top: var(--cc-space-1);
  font-size: 13px;
}

.s57-state__spinner {
  width: 20px;
  height: 20px;
  border: 2px solid var(--cc-border);
  border-top-color: var(--cc-blue);
  border-radius: 50%;
  animation: s57-spin .8s linear infinite;
}

.s57-state--error h3 { color: var(--status-critical-ink); }

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

.s57-photo,
.s57-sensor {
  overflow: hidden;
  border-radius: var(--cc-radius-md);
}

.s57-photo__media,
.s57-photo__open {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border: 0;
  background: var(--bg3);
}

.s57-photo__open {
  min-height: 44px;
  padding: 0;
  cursor: zoom-in;
}

.s57-photo__media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.s57-photo__unavailable {
  display: grid;
  place-items: center;
  align-content: center;
  gap: var(--cc-space-2);
  width: 100%;
  height: 100%;
  color: var(--cc-muted);
  font-size: 12px;
  font-weight: 700;
}

.s57-photo__unavailable span:first-child {
  font-size: 32px;
}

.s57-photo__content,
.s57-sensor {
  padding: var(--cc-space-4);
}

.s57-sensor__temperature {
  display: block;
  margin: var(--cc-space-4) 0;
  font-size: 34px;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.04em;
}

.s57-sensor dl {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--cc-space-3);
  margin: 0;
}

.s57-sensor dt {
  color: var(--cc-muted);
  font-size: 11px;
}

.s57-sensor dd {
  margin: var(--cc-space-1) 0 0;
  font-size: 13px;
  font-weight: 700;
}

.s57-sensor__alert {
  margin-top: var(--cc-space-3);
  padding: var(--cc-space-3);
  border: 1px solid rgba(239, 68, 68, .28);
  border-radius: var(--cc-radius-sm);
  background: var(--status-critical-bg);
  color: var(--status-critical-ink);
  font-size: 12px;
  font-weight: 700;
}
/* B-4: STALE is not OUT-OF-RANGE.
   Out-of-range is a measured food-safety alarm and keeps the critical red above.
   Stale means the feed died — the number on screen may look fine and prove
   nothing. Warning tone + a dashed edge so the two are distinguishable at a
   glance and by shape, not by hue alone (colour-blind safe). Tokens only, so
   both themes follow the existing status palette. */
.s57-sensor__alert--warning {
  border: 1px dashed var(--status-warning);
  background: var(--status-warning-bg);
  color: var(--status-warning-ink);
}
.s57-sensor--warning { border-color: var(--status-warning); }
.s57-sensor--warning .s57-sensor__temperature { opacity: .65; }

.s57-mobile-only { display: none !important; }

/* Per-element [data-theme="dark"] .manager-shell overrides removed: the base
   .s57-* rules already consume flip tokens (--cc-*), so inputs and tables theme
   correctly in BOTH light and dark with no dark-only override needed. */

@media (max-width: 1023px) {
  .s57-shell {
    display: block;
  }

  .s57-shell__sidebar-region {
    min-height: 0;
  }

  .s57-shell__workspace {
    height: 100dvh;
  }

  .s57-mobile-header {
    display: flex;
  }

  .s57-sidebar--drawer {
    z-index: 80;
    width: min(320px, 88vw);
    box-shadow: var(--cc-shadow-md);
  }

  .s57-shell__main {
    height: calc(100dvh - 64px - var(--safe-top));
    padding: var(--cc-space-4);
  }

  .s57-legacy-mobile-header {
    margin: calc(var(--cc-space-4) * -1) calc(var(--cc-space-4) * -1) var(--cc-space-4);
  }

  .s57-page-header {
    align-items: flex-start;
  }
}

@media (max-width: 768px) {
  .s57-shell__main {
    padding: var(--cc-space-3);
  }

  .s57-legacy-mobile-header {
    margin: calc(var(--cc-space-3) * -1) calc(var(--cc-space-3) * -1) var(--cc-space-3);
  }

  .s57-page-header {
    display: block;
    margin-bottom: var(--cc-space-4);
  }

  .s57-page-header__aside {
    justify-content: flex-start;
    margin-top: var(--cc-space-3);
  }

  .s57-desktop-only { display: none !important; }
  .s57-mobile-only { display: block !important; }

  .s57-dialog {
    width: 100%;
    max-height: calc(100dvh - var(--cc-space-4) * 2);
  }

  .s57-overlay {
    align-items: end;
    padding: var(--cc-space-2);
  }

  .s57-tabs {
    margin-inline: calc(var(--cc-space-3) * -1);
    padding-inline: var(--cc-space-3);
  }
}

@media (prefers-reduced-motion: reduce) {
  .manager-shell *,
  .manager-shell *::before,
  .manager-shell *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

@media print {
  .s57-sidebar,
  .s57-mobile-header,
  .s57-drawer-backdrop {
    display: none !important;
  }

  .s57-shell,
  .s57-shell__workspace,
  .s57-shell__main {
    display: block;
    height: auto;
    overflow: visible;
    padding: 0;
    background: #fff;
    color: #000;
  }
}

/* Slice 4 — Staff mobile agenda (rendered only at <=768px in place of the weekly grid) */
.staff-agenda {
  display: flex;
  flex-direction: column;
  gap: var(--cc-space-4);
  margin-bottom: var(--cc-space-6);
}

.staff-agenda__coverage {
  display: flex;
  flex-direction: column;
  gap: var(--cc-space-2);
}

.staff-agenda__coverage-title {
  margin: 0;
  font-size: 20px;
  font-weight: 800;
  color: var(--cc-text);
}

.staff-agenda__coverage-badges {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--cc-space-3);
}

.staff-agenda__coverage-hours {
  color: var(--cc-muted);
  font-size: 13px;
  font-weight: 600;
}

.staff-agenda__list {
  display: flex;
  flex-direction: column;
  gap: var(--cc-space-3);
}

.staff-agenda-card h3 {
  display: flex;
  align-items: center;
}

.staff-agenda-card__avatar {
  width: 10px;
  height: 10px;
  margin-right: var(--cc-space-2);
  border-radius: 50%;
  flex: none;
}

/* Slice 4 — Cold Storage live tiles (Store57UI.SensorCard).
   Desktop: a responsive card grid that wraps; mobile (<=768px): stacked. */
.s57-sensor-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: var(--cc-space-3);
}

.s57-sensor__header h3 {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.s57-sensor__status {
  display: inline-flex;
  align-items: center;
  gap: var(--cc-space-2);
  flex-shrink: 0;
}

.s57-sensor__test-badge {
  padding: 2px 6px;
  border-radius: 6px;
  background: var(--status-warning-bg);
  color: var(--status-warning-ink);
  font-size: 9px;
  font-weight: 800;
  letter-spacing: .04em;
}

/* Status dot severity derives only from the tile's existing online signal. */
.s57-sensor__dot {
  width: 9px;
  height: 9px;
  border-radius: 999px;
  flex-shrink: 0;
}

.s57-sensor__dot--good { background: var(--cc-success); }
.s57-sensor__dot--warn { background: var(--cc-warning); }
.s57-sensor__dot--critical { background: var(--cc-critical); }
.s57-sensor__dot--neutral { background: var(--cc-muted); }

/* Explicit "no reading" placeholder — a muted label beside the em-dash, never
   a fabricated temperature. */
.s57-sensor__no-reading {
  display: inline-flex;
  align-items: baseline;
  gap: var(--cc-space-2);
}

.s57-sensor__no-reading-mark { color: var(--cc-muted); }

.s57-sensor__no-reading-text {
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0;
  color: var(--cc-muted);
}

.s57-sensor__meta {
  display: grid;
  gap: var(--cc-space-3);
}

.s57-sensor .s57-sensor__readout {
  grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
}

.s57-sensor__context {
  margin: 0;
  color: var(--cc-muted);
  font-size: 12px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

@media (max-width: 768px) {
  .s57-sensor-grid { grid-template-columns: 1fr; }
}

/* ── Cold Storage readability, 2026-08-24 ────────────────────────────────────
   The tile now leads with the EQUIPMENT name ("Upright Cooler (Gatorade)",
   "Frz/Cooler Drawer 1 (Ice Cream)"), which is far longer than the Govee device
   names it replaced. The old `white-space: nowrap; text-overflow: ellipsis` on
   the header turned those into "Frz/Cooler Drawer 1 (Ice C…" on a 390px phone —
   a title a manager cannot act on. Equipment identity is safety-relevant, so
   the title wraps to its full content instead of using a line clamp that only
   moves the silent-truncation threshold.

   The same applied to __context (now the secondary sensor identity) and to the
   battery note, which is a whole sentence and must never be clipped to
   "Battery level not provi…". */
.s57-sensor__header h3 {
  white-space: normal;
  overflow-wrap: anywhere;
  display: block;
  overflow: visible;
  text-overflow: clip;
  line-height: 1.25;
}

.s57-sensor__context {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
  overflow-wrap: anywhere;
  line-height: 1.35;
}

/* A dd holding a sentence (the battery note, the range caveat) must wrap. */
.s57-sensor dd {
  overflow-wrap: anywhere;
  word-break: break-word;
}

/* Nothing inside a tile may widen the page. minmax(0,…) is the fix for the
   classic grid overflow where a long unbreakable string forces a track wider
   than its container and the whole document scrolls sideways. */
.s57-sensor-grid { grid-template-columns: repeat(auto-fill, minmax(min(200px, 100%), 1fr)); }
.s57-sensor, .s57-sensor__header, .s57-sensor__meta { min-width: 0; max-width: 100%; }
.s57-sensor .s57-sensor__readout { grid-template-columns: repeat(auto-fit, minmax(min(120px, 100%), 1fr)); }
.s57-sensor__alert { overflow-wrap: anywhere; }

/* The header row: schedule copy on the left, Check-now on the right. On a
   narrow phone they stack instead of squeezing the button to nothing, and the
   button keeps a 44px touch target. */
.cs-header { max-width: 100%; }
@media (max-width: 480px) {
  .cs-header { flex-direction: column; align-items: stretch !important; }
  .cs-header > div:last-child { align-items: stretch !important; }
  .cs-header > div:last-child > button { width: 100%; }
  .cs-header > div:last-child > p { text-align: left !important; max-width: 100% !important; }
}

/* Theme control — bottom-left Auto/Dark/Light segmented control in the sidebar
   footer. Sits on the (flipping) sidebar surface, so it reads its own flip
   tokens and looks correct in both themes. */
.s57-theme-control {
  display: flex;
  gap: 2px;
  padding: 3px;
  border: 1px solid var(--cc-sidebar-border);
  border-radius: 10px;
  background: var(--cc-sidebar-hover);
}

.s57-theme-control__opt {
  flex: 1;
  min-height: 34px;
  padding: 0 8px;
  border: 0;
  border-radius: 7px;
  background: transparent;
  color: var(--cc-sidebar-ink-dim);
  font: inherit;
  font-size: 12px;
  font-weight: 700;
  cursor: pointer;
  transition: background-color .15s ease, color .15s ease;
}

.s57-theme-control__opt:hover { color: var(--cc-sidebar-ink); }

.s57-theme-control__opt.is-active {
  background: var(--cc-blue-strong);
  color: #fff;
}

.s57-theme-control__opt:focus-visible {
  outline: 2px solid transparent;
  box-shadow: var(--cc-focus);
}

/* PHONE TAP TARGET. The segmented control measured 82x34 CSS px on every phone
   width audited — under the 44px minimum this app holds itself to, and missed
   by 1.8.82's `min-height:44px` sweep because that rule targets input/select
   and these are <button>s. Raised only under the phone breakpoint, where the
   control lives inside the navigation drawer and has the room; the desktop
   sidebar keeps its compact 34px, which is correct with a mouse and is what the
   surrounding footer is spaced for. */
@media (max-width: 767px) {
  .s57-theme-control__opt { min-height: 44px; }
}

/* ============================================================================
   Command Center overview (v1.8.30 restyle) — one calm ops console.
   Tokens only: every color is a var(--cc-*) / var(--status-*) / var(--bg*) that
   flips with [data-theme]. One accent (--cc-blue). Status colors for status
   only. No raw hex here; accent-filled buttons reuse existing .s57-button--*.
   ========================================================================== */
.cc-ovw {
  max-width: 1320px;
  margin: 0 auto;
  padding-top: var(--cc-space-4);          /* clears the floating freshness bar (desktop) */
  padding-bottom: var(--cc-space-10);
  display: flex;
  flex-direction: column;
  gap: var(--cc-space-6);
  color: var(--cc-text);
}

/* 1 — Header row -------------------------------------------------------------*/
.cc-ovw__header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--cc-space-6);
  flex-wrap: wrap;
}
.cc-ovw__title {
  margin: 0;
  font-size: 22px;
  font-weight: 500;
  letter-spacing: -0.02em;
  line-height: 1.15;
  color: var(--cc-text);
}
.cc-ovw__subtitle {
  display: inline-flex;
  align-items: center;
  gap: var(--cc-space-2);
  margin: var(--cc-space-2) 0 0;
  font-size: 13px;
  font-weight: 400;
  color: var(--cc-muted);
}
.cc-ovw__live-dot {
  width: 7px; height: 7px;
  border-radius: 999px;
  background: var(--status-success);
  box-shadow: 0 0 0 3px var(--status-success-bg);
  flex-shrink: 0;
}
.cc-ovw__filters {
  display: inline-flex;
  align-items: center;
  gap: var(--cc-space-3);
}

/* Date-scope segmented control (Today wired; longer windows honestly disabled) */
.cc-scope {
  display: flex;
  gap: 2px;
  padding: 3px;
  border: 1px solid var(--cc-border);
  border-radius: 10px;
  background: var(--bg3);
  /* U-8: the three scope options plus their Soon chips are wider than a 320px
     phone, and .s57-shell__main is overflow-x:hidden — so "This month" was
     simply gone, not merely off to one side. Three items do not justify a
     hidden scroller, so the strip wraps: nothing is out of reach at any width. */
  max-width: 100%;
  flex-wrap: wrap;
}
.cc-scope__opt { flex: 0 1 auto; }
.cc-scope__opt {
  min-height: 34px;
  padding: 0 12px;
  border: 0;
  border-radius: 7px;
  background: var(--cc-clear);
  color: var(--cc-muted);
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color .15s ease, color .15s ease;
}
.cc-scope__opt:hover:not(:disabled):not(.is-active) { color: var(--cc-text); }
/* S4-10: --cc-blue on the 10%-blue tint measured 4.43:1 at 13px in Light —
   under AA by a hair on the segment the manager reads most ("Today"). The ink
   token is the text-safe twin of the same hue in both themes. */
.cc-scope__opt.is-active { background: var(--status-info-bg); color: var(--status-info-ink); }
/* U-8: a not-yet-built scope is not a broken control. `not-allowed` told the
   manager they had done something wrong; `default` says this is a label. The
   Soon chip states the reason instead of hiding it in a title attribute that
   never appears on a touch device. */
.cc-scope__opt:disabled { opacity: .45; cursor: not-allowed; }
/* LANE D (L3-08): the ONE scope that exists is stated, not offered as a press
   that does nothing. It is a <span>, so it needs the box a <button> got for
   free; disabling the button instead would have greyed out the only live
   segment (see :disabled above) and made the whole group read as broken. */
.cc-scope__opt--current { display: inline-flex; align-items: center; cursor: default; }
.cc-scope__opt--soon {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  cursor: default;
  opacity: 1;
  color: var(--cc-muted);
}
.cc-scope__opt--soon:disabled { cursor: default; opacity: 1; }
.cc-scope__soon {
  padding: 1px 6px;
  border: 1px dashed var(--cc-border);
  border-radius: 999px;
  background: var(--cc-clear);
  color: var(--cc-muted);
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  opacity: .8;
}
.cc-scope__opt:focus-visible { outline: 2px solid var(--cc-clear); box-shadow: var(--cc-focus); }

/* 2 — Prescriptive strip -----------------------------------------------------*/
.cc-strip {
  display: flex;
  align-items: center;
  gap: var(--cc-space-4);
  padding: var(--cc-space-4) var(--cc-space-5);
  border: 1px solid var(--cc-border);
  border-radius: var(--cc-radius-md);
  background: var(--status-info-bg);       /* subtle accent tint — chromatic, flips */
}
.cc-strip__icon {
  display: inline-grid;
  place-items: center;
  width: 40px; height: 40px;
  flex: 0 0 40px;
  border-radius: var(--cc-radius-sm);
  background: var(--cc-card);
  color: var(--cc-blue);
  font-size: 19px;
}
.cc-strip__body { min-width: 0; flex: 1; }
.cc-strip__label {
  margin: 0 0 2px;
  font-size: 12px;
  font-weight: 500;
  /* AUDIT-2026-09-09 (LANE K, R2-10): --cc-blue is a SURFACE blue; as 12px/500
     text on the Next-action strip it measured 4.17:1 against a 4.5:1 floor.
     --status-info-ink is the text-safe pair this stylesheet already uses for
     .cc-chip--info, .cc-attn__sev--info and .cc-scope__opt.is-active. */
  color: var(--status-info-ink);
}
.cc-strip__text {
  margin: 0;
  font-size: 14px;
  font-weight: 400;
  line-height: 1.5;
  color: var(--cc-text);
}
.cc-strip__sub {
  margin: 2px 0 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--cc-muted);
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 1;
  -webkit-box-orient: vertical;
}
.cc-strip__action { flex: 0 0 auto; }

/* 3 — KPI row ----------------------------------------------------------------*/
.cc-kpis {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--cc-space-4);
}
.cc-kpi {
  display: flex;
  flex-direction: column;
  gap: var(--cc-space-2);
  padding: var(--cc-space-5);
  border: 1px solid var(--cc-border);
  border-radius: var(--cc-radius-md);
  background: var(--cc-card);
  box-shadow: var(--cc-shadow-sm);
}
.cc-kpi__label {
  margin: 0;
  font-size: 13px;
  font-weight: 400;
  color: var(--cc-muted);
}
.cc-kpi__value-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--cc-space-3);
}
.cc-kpi__value {
  font-size: 28px;
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  color: var(--cc-text);
}
.cc-kpi__value--muted { color: var(--cc-muted); }
/* Delta chip + sparkline: rendered ONLY when real trend data is supplied.
   No trend feed exists today, so these stay dormant (never fabricated). */
.cc-kpi__delta {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 12px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}
.cc-kpi__delta--up { color: var(--status-success-ink); }
.cc-kpi__delta--down { color: var(--status-critical-ink); }
.cc-kpi__spark { display: flex; align-items: flex-end; gap: 2px; height: 22px; }
.cc-kpi__spark-bar { width: 4px; border-radius: 2px; background: var(--cc-blue); opacity: .55; }
.cc-kpi__detail {
  display: inline-flex;
  align-items: center;
  gap: var(--cc-space-2);
  margin: 0;
  font-size: 12px;
  color: var(--cc-muted);
}
.cc-kpi__dot { width: 7px; height: 7px; border-radius: 999px; flex-shrink: 0; }
.cc-kpi__dot--success { background: var(--status-success); }
.cc-kpi__dot--warning { background: var(--status-warning); }
.cc-kpi__dot--critical { background: var(--status-critical); }
.cc-kpi__dot--neutral { background: var(--cc-muted); }
.cc-kpi__detail--success { color: var(--status-success-ink); }
.cc-kpi__detail--warning { color: var(--status-warning-ink); }
.cc-kpi__detail--critical { color: var(--status-critical-ink); }

/* 4 — Two-column body --------------------------------------------------------*/
.cc-body {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);   /* ~40 / 60 */
  gap: var(--cc-space-4);
  align-items: start;
}
.cc-panel {
  display: flex;
  flex-direction: column;
  min-width: 0;
  border: 1px solid var(--cc-border);
  border-radius: var(--cc-radius-md);
  background: var(--cc-card);
  box-shadow: var(--cc-shadow-sm);
  overflow: hidden;
}
.cc-panel__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--cc-space-3);
  padding: var(--cc-space-4);
  border-bottom: 1px solid var(--cc-border);
}
.cc-panel__title {
  margin: 0;
  font-size: 14px;
  font-weight: 500;
  color: var(--cc-text);
}
.cc-panel__title-row { display: inline-flex; align-items: center; gap: var(--cc-space-2); }
.cc-panel__count {
  min-width: 20px;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--bg3);
  color: var(--cc-muted);
  font-size: 11px;
  font-weight: 500;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.cc-panel__actions { display: inline-flex; align-items: center; gap: var(--cc-space-3); }

/* Needs-attention list */
.cc-attn { display: flex; flex-direction: column; }
.cc-attn__row {
  display: flex;
  gap: var(--cc-space-3);
  align-items: flex-start;
  padding: var(--cc-space-3) var(--cc-space-4);
}
.cc-attn__row + .cc-attn__row { border-top: 1px solid var(--cc-border); }
.cc-attn__dot { width: 9px; height: 9px; border-radius: 999px; margin-top: 5px; flex-shrink: 0; }
.cc-attn__dot--critical { background: var(--status-critical); }
.cc-attn__dot--warning { background: var(--status-warning); }
.cc-attn__dot--info { background: var(--status-info); }
.cc-attn__body { min-width: 0; flex: 1; }
.cc-attn__head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--cc-space-2); }
.cc-attn__title {
  margin: 0;
  font-size: 13px;
  font-weight: 500;
  color: var(--cc-text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cc-attn__sev {
  font-size: 10px;
  font-weight: 500;
  letter-spacing: .04em;
  text-transform: uppercase;
  flex-shrink: 0;
}
.cc-attn__sev--critical { color: var(--status-critical-ink); }
.cc-attn__sev--warning { color: var(--status-warning-ink); }
.cc-attn__sev--info { color: var(--status-info-ink); }
/* C-7 — coalesced alert groups.
   `×18` rides the title (same line, muted, tabular) so the title still
   truncates cleanly at 320px; the unread badge and the state chip are separate
   because they say different things: the badge counts rows nobody has read, the
   chip says whether the CONDITION is still true. All colours are tokens, so both
   themes follow the existing status palette. */
.cc-attn__multi {
  color: var(--cc-muted);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  white-space: nowrap;
}
.cc-attn__unread {
  min-width: 20px;
  padding: 1px 7px;
  border-radius: 999px;
  /* B-29: was #fff on --status-critical = 4.83 light / 3.76 dark. This is the
     same chip family as .cc-attn__state--danger two rules below, which already
     uses the -bg/-ink pair correctly; matched to it. 5.54 / 5.39. */
  background: var(--status-critical-bg);
  color: var(--status-critical-ink);
  font-size: 11px;
  font-weight: 700;
  line-height: 1.5;
  text-align: center;
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}
.cc-attn__state {
  display: inline-block;
  margin-top: 4px;
  padding: 2px 8px;
  border-radius: 999px;
  border: 1px solid var(--cc-border);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .02em;
  white-space: nowrap;
  color: var(--cc-muted);
  background: var(--bg3);
}
.cc-attn__state--danger { color: var(--status-critical-ink); border-color: var(--status-critical); }
.cc-attn__state--warn   { color: var(--status-warning-ink);  border-color: var(--status-warning); }
.cc-attn__state--good   { color: var(--status-success-ink);  border-color: var(--status-success); }
.cc-attn__state--muted  { color: var(--cc-muted); }
/* The header/row action buttons are real write CTAs — S4-1 disables them while a
   POST is in flight, and a disabled control must read as disabled in both themes. */
.cc-linkbtn[disabled] { opacity: .55; cursor: progress; }
.cc-attn__msg {
  margin: 2px 0 0;
  font-size: 12px;
  line-height: 1.45;
  color: var(--cc-muted);
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.cc-attn__actions { display: flex; gap: var(--cc-space-3); margin-top: var(--cc-space-2); }

/* Inline link-buttons (row + panel-header actions) */
.cc-linkbtn {
  border: 0;
  background: var(--cc-clear);
  padding: 2px 0;
  min-height: 28px;
  font: inherit;
  font-size: 12px;
  font-weight: 500;
  color: var(--cc-blue);
  cursor: pointer;
}
.cc-linkbtn:hover { text-decoration: underline; }
.cc-linkbtn--muted { color: var(--cc-muted); }
/* LR-G: a link-button that CLOSES a work item, not one that navigates. It is
   the only tap in this queue that changes state, and .cc-linkbtn is 28px on
   desktop (this file is linked after index.html's inline 44px and re-sets it at
   equal specificity — the same collision §6.6 already documents for mobile), so
   the exit gets its own real target instead of widening every link-button in
   the manager UI. .cc-attn__actions is a stretch flex row, so its siblings
   follow without a rule of their own. */
.cc-linkbtn--exit { min-height: 44px; padding: 8px 0; font-weight: 600; }
.cc-linkbtn:focus-visible { outline: 2px solid var(--cc-clear); box-shadow: var(--cc-focus); border-radius: 6px; }

/* Live feed */
/* H-7: `max-height: 560px; overflow-y: auto` used to live here, unconditionally,
   inside .s57-shell__main which is itself overflow-y:auto. On a phone that
   nested scroller occupied nearly the whole viewport and swallowed the page
   scroll gesture. The panel now renders a short inline list (5 rows) and moves
   the rest into a full-screen dialog, so no clamp is needed at any width. */
.cc-feed { display: flex; flex-direction: column; }

/* The dialog copy is the one place a scroller legitimately remains — the
   .s57-dialog wrapper scrolls — so make sure it never chains its overscroll
   back into the dashboard underneath. */
.cc-feed--full { overscroll-behavior: contain; }

.cc-feed__more {
  display: flex;
  justify-content: center;
  padding: var(--cc-space-3) var(--cc-space-4);
  border-top: 1px solid var(--cc-border);
}
.cc-feed__more .cc-linkbtn { min-height: 44px; font-weight: 700; }
.cc-feed__row {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr) auto;
  gap: var(--cc-space-3);
  align-items: center;
  padding: var(--cc-space-3) var(--cc-space-4);
  transition: background-color .35s ease;
}
.cc-feed__row:nth-child(even) { background: var(--cc-panel); }   /* zebra via token */
.cc-feed__row + .cc-feed__row { border-top: 1px solid var(--cc-border); }
.cc-feed__row.is-new { background: var(--status-success-bg); }
.cc-feed__thumb {
  width: 44px; height: 44px;
  border-radius: var(--cc-radius-sm);
  overflow: hidden;
  border: 1px solid var(--cc-border);
  background: var(--bg3);
  padding: 0;
  display: grid;
  place-items: center;
  cursor: pointer;
}
.cc-feed__thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cc-feed__main { min-width: 0; }
.cc-feed__who {
  margin: 0;
  font-size: 13px;
  font-weight: 500;
  color: var(--cc-text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cc-feed__what {
  margin: 1px 0 0;
  font-size: 12px;
  color: var(--cc-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* H-4: this line asked for `text-overflow: ellipsis` on a FLEX container, and
   text-overflow does not apply to a flex container's anonymous text child — so
   the summary ("Score 90 · 4 gaps detected") was cut mid-word with no ellipsis
   at all, reading as corrupted text rather than as truncation. Block layout
   with an inline icon gives a real ellipsis. */
.cc-feed__metric {
  margin: 2px 0 0;
  display: block;
  min-width: 0;
  font-size: 12px;
  color: var(--cc-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cc-feed__metric > svg,
.cc-feed__metric > span {
  vertical-align: -2px;
  margin-right: var(--cc-space-2);
}
.cc-feed__right { display: grid; justify-items: end; gap: var(--cc-space-2); min-width: 76px; }
.cc-feed__time { font-size: 11px; font-weight: 400; color: var(--cc-muted); white-space: nowrap; }

/* Status chip (feed + inline) */
.cc-chip {
  display: inline-flex;
  align-items: center;
  padding: 3px 8px;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: .02em;
  text-transform: uppercase;
  white-space: nowrap;
}
.cc-chip--success { background: var(--status-success-bg); color: var(--status-success-ink); }
.cc-chip--warning { background: var(--status-warning-bg); color: var(--status-warning-ink); }
.cc-chip--critical { background: var(--status-critical-bg); color: var(--status-critical-ink); }
.cc-chip--info { background: var(--status-info-bg); color: var(--status-info-ink); }
.cc-chip--neutral { background: var(--bg3); color: var(--cc-muted); }
.cc-live-dot {
  width: 8px; height: 8px;
  border-radius: 999px;
  background: var(--status-success);
  display: inline-block;
  animation: cc-pulse 1.6s ease-in-out infinite;
}
@keyframes cc-pulse { 0%,100% { opacity: 1; } 50% { opacity: .35; } }

/* 5 — Empty / loading / error states ----------------------------------------*/
.cc-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--cc-space-2);
  text-align: center;
  padding: var(--cc-space-8) var(--cc-space-4);
}
.cc-state__mark { font-size: 22px; line-height: 1; }
.cc-state__title { margin: 0; font-size: 13px; font-weight: 500; color: var(--cc-text); }
.cc-state__msg { margin: 0; font-size: 12px; color: var(--cc-muted); max-width: 46ch; }
.cc-skel { display: flex; flex-direction: column; gap: var(--cc-space-2); padding: var(--cc-space-3) var(--cc-space-4); }
.cc-skel__row {
  height: 52px;
  border-radius: var(--cc-radius-sm);
  background: var(--bg3);
  animation: cc-shimmer 1.4s ease-in-out infinite alternate;
}
@keyframes cc-shimmer { to { opacity: .55; } }

/* Responsive: 4 -> 2x2 -> 1 KPIs; two columns stack at tablet ----------------*/
@media (max-width: 1023px) {
  .cc-body { grid-template-columns: 1fr; }
  .cc-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 767px) {
  .cc-ovw { padding-top: 0; gap: var(--cc-space-4); }
  .cc-ovw__header { align-items: flex-start; }
  .cc-strip { flex-wrap: wrap; }
  .cc-strip__action { width: 100%; }
  .cc-strip__action .s57-button { width: 100%; }
  .cc-scope__opt, .cc-linkbtn { min-height: 40px; }
}
@media (max-width: 520px) {
  .cc-kpis { grid-template-columns: 1fr; }
}

/* ============================================================================
   6 — MOBILE UX / ICON SYSTEM / BRAND MARK        (uxpass-2026-07-29)
   ----------------------------------------------------------------------------
   Everything below consumes existing tokens only — no new colour values. The
   important choice is the icon-tile palette: it uses the --status-*-bg /
   --status-*-ink PAIRS rather than --green/--yellow/--red/--blue directly.
   Reason (measured, not assumed): as an icon stroke on its own tint tile,
   --green is 2.88:1 and --yellow 2.74:1 in LIGHT mode — both fail 4.5:1. The
   -ink tokens were introduced for exactly this ("Text-safe status inks (WCAG AA
   on light tints)", index.html:121) and measure 5.2-5.8:1 on the same tints in
   both themes. Light is this app's DEFAULT theme, so a dark-only tint would
   have shipped a contrast regression to every manager.
   ========================================================================== */

/* 6.1 — Icon tiles ---------------------------------------------------------- */
.s57-icon-tile {
  width: 26px;
  height: 26px;
  border-radius: 9px;
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  line-height: 0;
}
.s57-icon-tile--lg { width: 30px; height: 30px; }
.s57-icon-tile--accent  { background: var(--status-info-bg);     color: var(--status-info-ink); }
.s57-icon-tile--danger  { background: var(--status-critical-bg); color: var(--status-critical-ink); }
.s57-icon-tile--success { background: var(--status-success-bg);  color: var(--status-success-ink); }
.s57-icon-tile--warn    { background: var(--status-warning-bg);  color: var(--status-warning-ink); }
.s57-icon-tile--muted   { background: var(--bg3);                color: var(--text3); }

/* Spinner for in-flight fetches. Honours prefers-reduced-motion via the
   universal rule in index.html (animation-iteration-count:1). */
.s57-spin { animation: s57-spin 900ms linear infinite; transform-origin: 50% 50%; }
@keyframes s57-spin { to { transform: rotate(360deg); } }

/* 6.2 — Brand lockup ------------------------------------------------------- */
.s57-brand { display: flex; align-items: center; gap: 9px; min-width: 0; flex: 1; }
.s57-brand__mark {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  line-height: 0;
  border-radius: 9px;
  filter: drop-shadow(0 2px 8px var(--orange-glow));
}
.s57-brand__text { min-width: 0; }
.s57-brand__name {
  font-size: 16px;
  font-weight: 800;
  letter-spacing: -.025em;
  line-height: 1.2;
  /* the mobile title well is only ~169px wide at 393px, and the <h1> had no
     ellipsis — a long tab label pushed into the button cluster */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.s57-brand__role {
  display: flex;
  align-items: center;
  gap: 5px;
  margin-top: 1px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  line-height: 1.3;
  white-space: nowrap;
}
/* .s57-legacy-mobile-header :is(h1,p) forces --cc-sidebar-ink with !important,
   which flattened the eyebrow and the title to the SAME ink and destroyed the
   lockup hierarchy. Restore the dim role line; !important is required to beat
   that existing rule at equal specificity. */
.s57-legacy-mobile-header .s57-brand__role { color: var(--cc-sidebar-ink-dim) !important; }
.s57-legacy-mobile-header .s57-brand__name { color: var(--cc-sidebar-ink) !important; }

.s57-livedot {
  width: 5px;
  height: 5px;
  border-radius: var(--pill-radius);
  background: var(--green);
  flex: 0 0 auto;
  animation: s57-pulse 2.4s var(--ease-out) infinite;
}
.s57-livedot--stale { background: var(--text3); animation: none; }
@keyframes s57-pulse {
  0%, 100% { opacity: 1;   transform: scale(1); }
  50%      { opacity: .35; transform: scale(.82); }
}

/* 6.3 — Degraded / notice banner ------------------------------------------- */
.cc-banner {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 11px 12px;
  margin: 0 0 14px;
  border-radius: var(--radius-md);
  background: var(--status-warning-bg);
  border: 1px solid var(--status-warning);
  color: var(--status-warning-ink);
}
.cc-banner__text { font-size: 12px; line-height: 1.5; flex: 1; min-width: 0; }
.cc-banner__text b { font-weight: 700; }
.cc-banner__icon { flex: 0 0 auto; margin-top: 1px; line-height: 0; }
.cc-banner__close {
  flex: 0 0 auto;
  appearance: none;
  min-width: 44px;
  min-height: 44px;
  margin: -11px -12px -11px 0;
  display: grid;
  place-items: center;
  background: transparent;
  border: 0;
  border-radius: var(--radius-control);
  color: inherit;
  cursor: pointer;
  transition: background var(--t-fast) var(--ease-out);
}
.cc-banner__close:hover { background: var(--bg-hover); }
.cc-banner__close:focus-visible { box-shadow: var(--focus-ring); outline: none; }

/* 6.4 — KPI icon slot ------------------------------------------------------- */
.cc-kpi__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--cc-space-2);
}
.cc-kpi__top .cc-kpi__label { flex: 1; min-width: 0; }

/* 6.5 — Manager bottom tab bar --------------------------------------------- */
/* NOT the same component as .bottom-nav. .bottom-nav is the EMPLOYEE app's
   screen-level nav (floating pill + camera FAB, driven by `screen`); it is
   explicitly not rendered while a manager is on the manager screen
   (index.html: `!(isManager && screen === "manager") && ...NavBar`). This bar is
   the MANAGER's tab nav, driven by `tab`/`setTab` — the same state the sidebar
   reads, so there is no second source of truth. They never coexist.
   Breakpoint is 767/768px, NOT 900px: --bottom-nav-height / --content-pad-bottom
   already switch at 767/768, so showing the bar up to 899px would occlude
   content that had zero bottom padding. */
.s57-tabbar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 60;
  display: none;
  align-items: stretch;
  padding: 7px 8px calc(7px + env(safe-area-inset-bottom, 0px));
  padding-left: calc(8px + env(safe-area-inset-left, 0px));
  padding-right: calc(8px + env(safe-area-inset-right, 0px));
  /* Fully opaque fallback FIRST. A translucent bar with no blur is illegible
     over photos, and the Stocking screen is wall-to-wall photos. */
  background: var(--bottom-nav-bg);
  border-top: 1px solid var(--border);
}
@media (max-width: 767px) {
  .s57-tabbar { display: flex; }
}
/* THE TRANSLUCENT-AND-BLURRED OVERRIDE THAT USED TO LIVE HERE IS GONE.
   It set `color-mix(… 86%, transparent)` + `backdrop-filter: blur(22px)
   saturate(180%)` on this bar, and it contradicted the rule directly above it,
   whose own comment says a see-through bar is illegible over the photos the
   Stocking screen is made of. It also made the labels measurably unreadable:
   at 86% opacity the 9.5px label composites against whatever is scrolling
   underneath, and an audit measured 3.71:1 against a 4.5:1 requirement.
   Against the OPAQUE bar the same tokens measure 5.62:1 (light inactive),
   5.17:1 (light active), 6.38:1 (dark inactive) and 5.13:1 (dark active) — so
   removing the translucency fixes the contrast at its cause and needs no
   colour change at all. The employee nav had the identical override removed in
   1.8.82 for the identical reason; this bar was simply missed because it lives
   in this file, which that release never opened. */
.s57-tabbar__item {
  flex: 1;
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--text3);
  font-family: var(--font);
  font-size: 9.5px;
  font-weight: 700;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 7px 2px;
  min-width: 0;
  min-height: 52px;
  border-radius: var(--radius-control);
  cursor: pointer;
  transition: color var(--t-base) var(--ease-out), background var(--t-base) var(--ease-out);
}
.s57-tabbar__item svg { transition: transform var(--t-base) var(--ease-spring); }
.s57-tabbar__item:active svg { transform: scale(.85); }
.s57-tabbar__item.is-active { color: var(--accent); }
.s57-tabbar__item.is-active svg { transform: translateY(-1px); }
.s57-tabbar__item:focus-visible { box-shadow: var(--focus-ring); outline: none; }
.s57-tabbar__label {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Landscape phone: keep 44px targets, drop the labels. aria-label on the button
   carries the accessible name, so hiding the text loses nothing for AT. */
@media (max-height: 480px) and (max-width: 767px) {
  .s57-tabbar__item { min-height: 44px; }
  .s57-tabbar__label { display: none; }
}

/* NARROW PHONES READ THE ALERT, NOT THE FIRST HALF OF IT.
   .cc-attn__title, .cc-feed__what and .cc-feed__metric are single-line
   ellipsis rows, which is the right call for a dense scannable feed and is
   fine from 375px up. At 320 and 360 it stopped being a nicety: measured this
   run, "Gene — register photo missing" lost 54px, "BuzzBallCooler too warm x22"
   lost 44px and "FrozenFoodCooler too warm x2" lost 35px — i.e. the row still
   named who or what, but no longer what was WRONG, which is the only reason the
   row exists.
   Two lines instead of one, using the same -webkit-line-clamp pattern 1.8.82
   already chose for the task title when it hit exactly this problem. Density is
   preserved everywhere it matters: this applies only under the phone
   breakpoint this file already uses (767px), and a row still cannot grow
   unbounded. */
@media (max-width: 767px) {
  .cc-attn__title,
  .cc-feed__what,
  .cc-feed__metric {
    white-space: normal;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow-wrap: anywhere;
  }
}

/* 6.6 — Scroll container must clear the tab bar ---------------------------- */
@media (max-width: 767px) {
  /* .s57-shell__main is the manager scroll container (overflow-y:auto) and had
     only --cc-space-3 (12px) of bottom padding, so the last row of the
     attention queue sat under the new bar. */
  .s57-shell__main { padding-bottom: var(--content-pad-bottom); }
  /* v1.8.50 bumped .cc-linkbtn to 44px in index.html's inline <style>, but this
     file is linked AFTER it and re-set 40px at equal specificity — silently
     undoing the fix on the one viewport where tap targets matter. Restored. */
  .cc-scope__opt, .cc-linkbtn { min-height: 44px; }
}
/* 6.7 — icon alignment in the prescriptive strip -------------------------- */
.cc-strip__label { display: flex; align-items: center; gap: 6px; }

/* 6.8 — metric numerals -----------------------------------------------------
   .cc-kpi__value already had tabular-nums but was still set in the body face,
   so KPI digits did not align with the other metric readouts on the screen
   (.cc-attn__sev, the freshness pill and the temp readouts are all --mono).
   Body copy is deliberately untouched — this is scoped to the metric only. */
.cc-kpi__value { font-family: var(--mono); font-weight: 700; letter-spacing: -.035em; }

/* ── UPDATE PILL (2026-08-13) ─────────────────────────────────────────────
   Lives OUTSIDE [data-testid="manager-freshness-bar"] on purpose. That bar is
   display:none under 768px (index.html:320) — correct for the freshness readout
   and the desktop refresh button, both of which have mobile equivalents, but it
   also meant the "Update available" affordance was unreachable on a phone, and
   the store runs on phones.

   Mobile is the DEFAULT here (no min-width query needed to reach it): a
   toast-like banner pinned above the bottom tab bar, using the same elevated
   card surface and 44px floor as the rest of the mobile shell. At 768px and up
   it collapses back to the small pill that used to sit inside the bar.
   Both themes come free — every colour is a token. */
.s57-update-pill {
  position: fixed;
  z-index: 120;
  left: calc(12px + env(safe-area-inset-left, 0px));
  right: calc(12px + env(safe-area-inset-right, 0px));
  bottom: calc(var(--bottom-nav-height, 0px) + env(safe-area-inset-bottom, 0px) + 12px);
  min-height: 44px;
  padding: 8px 14px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border-radius: 14px;
  background: var(--orange-bg, rgba(234, 88, 12, 0.15));
  /* B-30: the "Update available" banner measured 4.17 light / 4.33 dark — under
     AA on the one message that has to be read before anything else can be
     trusted. The -ink token for this tint already exists and passes: 5.39/6.26.
     The BORDER keeps the fill token; a border has no contrast requirement. */
  color: var(--status-info-ink);
  border: 1px solid var(--orange, #ea580c);
  box-shadow: var(--shadow-lg, 0 12px 40px rgba(0, 0, 0, 0.25));
  font-family: var(--font);
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
  white-space: nowrap;
}
.s57-update-pill__cta {
  margin-left: auto;
  padding: 4px 10px;
  border-radius: 999px;
  /* white on --orange (which resolves to the accent blue) is 3.68:1 in dark;
     the strong token is the same blue one step darker: 5.17 / 6.70. */
  background: var(--cc-blue-strong);
  color: #fff;
  font-size: 12px;
  font-weight: 800;
}
@media (min-width: 768px) {
  /* Back to a pill, in the top-right cluster under the freshness bar. */
  .s57-update-pill {
    left: auto;
    right: calc(env(safe-area-inset-right, 0px) + 12px);
    bottom: auto;
    top: calc(env(safe-area-inset-top, 0px) + 58px);
    min-height: 0;
    padding: 5px 12px;
    border-radius: 999px;
    font-size: 11px;
    box-shadow: none;
  }
  .s57-update-pill__cta { display: none; }
}
@media (prefers-reduced-motion: no-preference) {
  .s57-update-pill { transition: opacity 0.15s ease; }
}

/* ── F-1: per-product copy buttons (Pricebook) ────────────────────────────
   28-32px visually so they never bully the row they share, but the ::after
   below inflates the HIT area to the 44px floor. This is the standard trick
   for dense rows: the target grows, the layout does not. */
.s57-copy-btn { position: relative; }
.s57-copy-btn::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 44px;
  height: 44px;
  transform: translate(-50%, -50%);
}
.s57-copy-btn:hover:not(:disabled) {
  background: var(--bg3);
  color: var(--text);
}
.s57-copy-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
/* Two copy buttons sitting side by side must not have overlapping 44px hit
   boxes, or the second one eats the first. 6px gap + 28px box = 34px pitch,
   so the inflated boxes are clipped to the midpoint between them. */
.s57-copy-btn + .s57-copy-btn::after { left: 60%; width: 38px; }

/* ── S2-4: Cold Storage → Mapping, responsive ─────────────────────────────
   The mapping panel was `gridTemplateColumns: "1fr 1fr"` inline, with no
   isDesktop branch and no media query, so a 320px phone was split into two
   144px columns: the "Reassign to…" select measured 22px wide (chevron only)
   and the action buttons were clipped to "Reas" / "Unass". One column below
   768px; the paired nested scrollers only exist once the two columns do —
   stacked on a phone they would be a scroller inside a scroller. */
.s57-mapping-grid { display: grid; grid-template-columns: 1fr; gap: 16px; }
.s57-mapping-grid__col { min-width: 0; }
@media (min-width: 768px) {
  .s57-mapping-grid { grid-template-columns: 1fr 1fr; }
  .s57-mapping-grid__col { max-height: calc(100dvh - 260px); overflow-y: auto; }
}

/* ── LR-C: manager door identity & correction ──────────────────────────────
   A4-06 — production had no manager-side write for door identity at all: a
   photo the AI could not name was a read-only thumbnail, and Settings →
   Coolers printed the door name as static text. These two controls are the
   missing surfaces. Every token below is an existing --cc-* / --status-* one;
   no new colour is introduced. Both controls keep the 44px touch target the
   .s57-button rule above sets for every other tappable thing in this app. */
.s57-door-fix {
  margin-top: var(--cc-space-3);
  padding-top: var(--cc-space-3);
  border-top: 1px solid var(--cc-border);
  display: grid;
  gap: var(--cc-space-2);
}
.s57-door-fix__current {
  margin: 0;
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-weight: 700;
  color: var(--cc-muted);
  min-width: 0;
  overflow-wrap: anywhere;
}
.s57-door-fix__label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--cc-muted);
}
.s57-door-fix__row {
  display: flex;
  gap: var(--cc-space-2);
  flex-wrap: wrap;
  align-items: center;
}
.s57-door-fix__select {
  flex: 1 1 140px;
  min-width: 0;
  min-height: 44px;
  padding: 0 var(--cc-space-3);
  border-radius: var(--cc-radius-sm);
  border: 1px solid var(--cc-border);
  background: var(--cc-card);
  color: var(--cc-text);
  font: inherit;
  font-size: 13px;
}
.s57-door-fix__save {
  min-height: 44px;
  padding: 0 var(--cc-space-4);
  border-radius: var(--cc-radius-sm);
  border: 1px solid transparent;
  background: var(--cc-blue-strong);
  color: #fff;
  font: inherit;
  font-size: 13px;
  font-weight: 800;
  cursor: pointer;
}
.s57-door-fix__save:disabled { cursor: not-allowed; opacity: .48; }
.s57-door-fix__note {
  margin: 0;
  font-size: 12px;
  font-weight: 600;
  overflow-wrap: anywhere;
}
.s57-door-fix__note--ok { color: var(--status-success-ink); }
.s57-door-fix__note--bad { color: var(--status-critical-ink); }

.s57-door-name {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  min-height: 44px;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--cc-text);
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  text-align: left;
  cursor: pointer;
  min-width: 0;
}
.s57-door-name__text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.s57-door-name__hint { display: inline-flex; color: var(--cc-muted); flex-shrink: 0; }
.s57-door-name-edit { display: grid; gap: var(--cc-space-2); }
.s57-door-name-edit__input {
  width: 100%;
  min-height: 44px;
  padding: 0 var(--cc-space-3);
  border-radius: var(--cc-radius-sm);
  border: 1px solid var(--cc-border);
  background: var(--cc-card);
  color: var(--cc-text);
  font: inherit;
  font-size: 14px;
}
.s57-door-name-edit__row { display: flex; gap: var(--cc-space-2); flex-wrap: wrap; }
.s57-door-name-edit__cancel {
  min-height: 44px;
  padding: 0 var(--cc-space-4);
  border-radius: var(--cc-radius-sm);
  border: 1px solid var(--cc-border);
  background: var(--cc-card);
  color: var(--cc-text);
  font: inherit;
  font-size: 13px;
  font-weight: 800;
  cursor: pointer;
}
.s57-door-name-edit__cancel:disabled { cursor: not-allowed; opacity: .48; }
