/* Inventory Dashboard - house design, hand-written, no framework, no build step.
   Tokens are the vendored martin-group-design ones (brand/tokens/*.css, imported
   below); everything here is layout on top of them.
   Desktop-first; breakpoints 1200 / 900 / 840 (hamburger) / 640 / 379 at the end. */

@import url("brand/tokens/colors.css");
@import url("brand/tokens/typography.css");
@import url("brand/tokens/spacing.css");
@import url("brand/tokens/effects.css");

/* THE ONE TOKEN WE OVERRIDE. The vendored typography.css still leads with
   'Helvetica Neue'; the estate canonical dropped it 2026-09-06 (switcher-
   canonical.md §0) because a machine with a PARTIAL Helvetica Neue install --
   only Condensed / Condensed Oblique faces, and the dev box is one -- renders
   every weight >= 600 as Bold Condensed Oblique. The foot name, the current
   tile and the sign-out pill came out slanted. Overridden here rather than
   edited in the vendored file, so the next token refresh is a clean copy. */
:root {
  --font-sans: Helvetica, Arial, sans-serif;
  --radius: 4px;
  --radius-md: 6px;
  --sidebar-w: 216px;
  --topbar-h: 52px;
  --shadow-float: 0 2px 14px rgba(0, 0, 0, .14);
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body { margin: 0; background: var(--mg-page); color: var(--mg-text); font-family: var(--font-sans); font-size: 13px; line-height: 1.5; }
a { color: var(--mg-teal-deep); text-decoration: none; }
a:hover { color: var(--link-hover); text-decoration: underline; }
h1, h2, h3 { margin: 0; font-weight: 600; line-height: 1.2; }
h1 { font-size: 19px; } h2 { font-size: 16px; } h3 { font-size: 14px; }
p { margin: 0 0 8px; }
.sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.muted { color: var(--mg-text-muted); } .faint { color: var(--mg-text-faint); }
.small { font-size: 12px; } .mono { font-family: var(--font-mono); }
.tabular { font-variant-numeric: tabular-nums; }
.nowrap { white-space: nowrap; }
.right { text-align: right; }

/* ---------- Shell ---------- */
.shell { display: flex; min-height: 100vh; }
/* Viewport-pinned rail (switcher-canonical.md §2): the rail sticks, the CONTENT
   scrolls, and .nav is the one band that scrolls internally -- so the logo plate
   above and the switcher foot below never leave the screen on a long inventory
   table. 100dvh second so it wins where supported. */
.sidebar { width: var(--sidebar-w); flex: 0 0 var(--sidebar-w); background: var(--mg-ink); color: var(--mg-ink-text); display: flex; flex-direction: column; position: sticky; top: 0; z-index: 10; height: 100vh; height: 100dvh; }
.logo-plate { background: #fff; padding: 12px 16px; border-bottom: 3px solid var(--mg-teal); display: flex; align-items: center; gap: 10px; }
.logo-plate img { height: 26px; width: auto; display: block; }
.logo-plate .app-name { font-size: 10px; letter-spacing: 2px; text-transform: uppercase; color: var(--mg-text-2); font-weight: 600; }
.nav { padding: 10px 0; flex: 1; min-height: 0; overflow-y: auto; }
.nav-label { font-size: 10px; letter-spacing: 1px; text-transform: uppercase; color: var(--mg-ink-label); padding: 12px 16px 4px; }
.nav a { display: flex; align-items: center; gap: 10px; padding: 9px 16px; color: var(--mg-ink-text); font-size: 13px; text-decoration: none; border-left: 3px solid transparent; }
.nav a:hover { background: var(--mg-ink-hover); color: var(--mg-ink-text-strong); text-decoration: none; }
.nav a.active { color: #fff; border-left-color: var(--mg-teal); background: var(--mg-ink-hover); }
.nav .glyph { width: 16px; text-align: center; color: var(--mg-ink-muted); }
.nav a.active .glyph { color: var(--mg-teal); }

/* ONE row: the nine-dots mount first, hard against the rail's left edge (that is
   what the asymmetric padding buys), identity beside it -- switcher-canonical.md
   §2. margin-top:auto pins the block to the foot even when .nav is short. The
   canonical font stack is restated because the panel and foot are ESTATE chrome
   and must match the reference even where the body font differs. */
.sidebar-foot {
  margin-top: auto;
  border-top: 1px solid var(--mg-ink-divider);
  padding: 12px 10px 12px 8px;
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: var(--mg-ink-text);
  font-family: Helvetica, Arial, sans-serif;
}
/* Identity is name + email ONLY -- not a link, not a button, no role line, no
   sign-out (canonical §2/§4). min-width:0 is what lets the ellipsis engage
   inside a flex row. */
.sidebar-foot-id { min-width: 0; flex: 1; }
.sidebar-user { font-weight: 600; color: var(--mg-ink-text-strong); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sidebar-email { margin-top: 2px; font-size: 12px; color: var(--mg-ink-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Fallback line, rendered ONLY when the session carries no email. */
.sidebar-scope { margin-top: 2px; font-size: 11px; color: var(--mg-ink-muted); text-transform: capitalize; }

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
/* Consistent header height across every route (canonical §7). */
.topbar { min-height: var(--topbar-h); background: #fff; border-bottom: 1px solid var(--mg-border); display: flex; align-items: center; gap: 12px; padding: 0 24px; position: sticky; top: 0; z-index: 5; }
.topbar h1 { font-size: 17px; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding-right: .12em; }
.topbar .fresh { font-size: 12px; color: var(--mg-text-muted); white-space: nowrap; }
.hamburger { display: none; width: 44px; height: 40px; border: 1px solid var(--mg-border-control); background: #fff; border-radius: var(--radius); cursor: pointer; position: relative; }
.hamburger span, .hamburger span::before, .hamburger span::after { content: ""; position: absolute; left: 12px; width: 18px; height: 2px; background: var(--mg-ink); }
.hamburger span { top: 19px; } .hamburger span::before { top: -6px; left: 0; } .hamburger span::after { top: 6px; left: 0; }
.content { padding: 20px 24px 40px; flex: 1; }
.page-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; margin-bottom: 16px; flex-wrap: wrap; }
.page-head .sub { color: var(--mg-text-muted); font-size: 12px; }
.actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }

/* ---------- Cards / tiles ---------- */
.card { background: var(--mg-card); border: 1px solid var(--mg-border); border-radius: var(--radius); padding: 14px 16px; }
.card + .card, .grid + .card, .card + .grid { margin-top: 16px; }
.card-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 10px; }
.card-head h2 { font-size: 14px; }
.grid { display: grid; gap: 12px; }
.grid > * { min-width: 0; }
.grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.tile { background: #fff; border: 1px solid var(--mg-border); border-radius: var(--radius); padding: 12px 14px; display: block; color: inherit; text-decoration: none; }
.tile:hover { text-decoration: none; border-color: var(--mg-teal-tint-border); background: var(--mg-strip); color: inherit; }
.tile .label { font-size: 11px; letter-spacing: 1px; text-transform: uppercase; color: var(--mg-text-muted); font-weight: 600; }
.tile .value { font-size: 28px; font-weight: 600; line-height: 1.15; margin-top: 4px; font-variant-numeric: tabular-nums; }
.tile .meta { font-size: 12px; color: var(--mg-text-2); margin-top: 6px; }

/* ---------- Badges ---------- */
.badge { display: inline-flex; align-items: center; gap: 4px; padding: 1px 8px; border-radius: 999px; font-size: 11px; font-weight: 600; border: 1px solid transparent; white-space: nowrap; line-height: 1.6; }
.badge.ok, .badge.good, .badge.active { background: var(--mg-green-tint); color: var(--mg-green); border-color: var(--mg-green-border); }
.badge.warn { background: var(--mg-amber-tint); color: var(--mg-amber-text); border-color: var(--mg-amber-border); }
.badge.bad, .badge.inactive { background: var(--mg-red-tint); color: var(--mg-red); border-color: var(--mg-red-border); }
.badge.neutral { background: var(--mg-neutral-tint); color: var(--mg-neutral); border-color: var(--mg-border); }
.badge.teal { background: var(--mg-teal-tint); color: var(--mg-teal-deep); border-color: var(--mg-teal-tint-border); }

/* ---------- Alerts ---------- */
.alert { padding: 8px 12px; border-radius: var(--radius); border: 1px solid; font-size: 13px; margin-bottom: 12px; }
.alert.ok { background: var(--mg-green-tint); border-color: var(--mg-green-border); color: var(--mg-green); }
.alert.warn { background: var(--mg-amber-tint); border-color: var(--mg-amber-border); color: var(--mg-amber-text); }
.alert.error { background: var(--mg-red-tint); border-color: var(--mg-red-border); color: var(--mg-red); }

/* ---------- Tables (house palette; stripe anything over ~4 rows) ---------- */
.table-wrap { overflow-x: auto; }
table.data { width: 100%; border-collapse: collapse; font-size: 13px; }
table.data th { background: var(--mg-table-head); color: var(--mg-text-2); font-size: 11px; letter-spacing: .5px; text-transform: uppercase; text-align: left; padding: 8px 10px; border-bottom: 1px solid var(--mg-border); white-space: nowrap; }
table.data td { padding: 7px 10px; border-bottom: 1px solid var(--mg-border-row); vertical-align: middle; }
table.data tbody tr:nth-child(even) td { background: var(--mg-zebra); }
table.data tbody tr:hover td { background: var(--mg-row-hover); }
/* Identity columns never wrap and never bare-truncate: font-size steps instead. */
td.identity, th.identity { white-space: nowrap; }
tr.is-inactive td { color: var(--mg-text-faint); }

/* ---------- Forms / buttons ---------- */
label.field { display: block; margin-bottom: 12px; }
label.field > span, .field-label { display: block; font-size: 12px; font-weight: 600; color: var(--mg-text-2); margin-bottom: 4px; }
input[type=text], input[type=email], select { width: 100%; font: inherit; font-size: 14px; padding: 8px 10px; border: 1px solid var(--mg-border-control); border-radius: var(--radius); background: #fff; color: var(--mg-text); }
input:focus, select:focus, button:focus-visible, a:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--mg-teal-tint), 0 0 0 3px var(--mg-teal); }
.check { display: flex; align-items: center; gap: 10px; padding: 8px 0; font-size: 14px; }
.check input { width: 20px; height: 20px; margin: 0; accent-color: var(--mg-teal); }
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 6px; font: inherit; font-size: 13px; font-weight: 600; padding: 8px 14px; border-radius: var(--radius); border: 1px solid var(--mg-border-control); background: #fff; color: var(--mg-text); cursor: pointer; text-decoration: none; min-height: 36px; }
.btn:hover { background: var(--mg-strip); text-decoration: none; color: var(--mg-text); }
.btn.primary { background: var(--mg-teal); border-color: var(--mg-teal); color: #fff; }
.btn.primary:hover { background: var(--mg-teal-hover); color: #fff; }
.btn.danger { color: var(--mg-red); border-color: var(--mg-red-border); }
.btn.danger:hover { background: var(--mg-red-tint); }
.btn.sm { padding: 4px 10px; min-height: 28px; font-size: 12px; }
.btn.block { width: 100%; }
.row-form { display: inline-flex; align-items: center; gap: 6px; margin: 0; }
.row-form select { width: auto; font-size: 12px; padding: 3px 6px; min-height: 28px; }
.kv { display: grid; grid-template-columns: max-content 1fr; gap: 4px 14px; font-size: 13px; }
.kv dt { color: var(--mg-text-muted); } .kv dd { margin: 0; }

/* ==========================================================================
   App switcher -- nine dots.

   Transcribed from docs/handoffs/switcher-canonical.md (v2.1, 2026-09-06),
   which is the SINGLE SOURCE OF TRUTH for this component. Every value below is
   either the canonical literal or a --mg-* token whose value is IDENTICAL to it
   (checked one by one: teal #17A38C, teal-deep #0E7C6B, teal-tint #E2F3EF,
   teal-tint-border #B9E0D7, ink-hover #2E3836, ink-text #B9C2BF,
   ink-text-strong #E8ECEA, ink-muted #7E8A86, ink-divider #3A4442,
   row-hover #F6FAF9, text #222927, text-2 #5A6461, text-muted #6B7370,
   border #DDE1DF, card #FFFFFF, the amber trio #8A6D1F/#FBF3D9/#E8D89A,
   radius 4px, radius-md 6px, shadow-float). No "close-enough" token anywhere.

   base_dashboard.html mounts the partial TWICE: .switcher--foot in the dark
   rail foot and .switcher--head in the light topbar. Exactly one is visible at
   any width; the swap lives in the 840px query at the end of this file.
   ========================================================================== */

/* The trigger and its panel share ONE position:relative wrapper -- that wrapper
   is the panel's positioning context, so the panel is never clipped by .nav's
   scroller or any other overflow box (canonical §3; a clipped panel shipped live
   on Fleet 2026-08-23 and rendered tiles with the page bleeding through). */
.switcher { position: relative; display: inline-flex; }

/* --- §1 the dots trigger. The <summary> IS the button, so the marker is
   suppressed and the box is the canonical 6px pad, not a 36px tap square. */
.switcher-btn {
  display: inline-flex;
  padding: 6px;
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: none;
  cursor: pointer;
  list-style: none;
  transition: background-color 80ms linear, color 80ms linear, border-color 80ms linear;
}
.switcher-btn::-webkit-details-marker { display: none; }
/* Nine spans on a 3x3 grid painted with currentColor, so one color change on the
   button recolors all nine dots at once. */
.switcher-glyph { display: grid; grid-template-columns: repeat(3, 3px); gap: 3px; }
.switcher-dot { width: 3px; height: 3px; border-radius: 999px; background: currentColor; }

/* §0 focus ring: :focus-visible ONLY, so a mouse press never draws it. Shared by
   the trigger, the pill and the tile links. */
.switcher-btn:focus-visible,
.switcher-pill:focus-visible,
.switcher-app:focus-visible {
  outline: 2px solid var(--mg-teal);
  outline-offset: 1px;
  border-radius: 3px;
  box-shadow: none;
}

/* Trigger colors are per SURFACE (§1): rest is that surface's own nav-text
   color -- never brand teal at rest, never a filled rest button -- and hover and
   open share ONE treatment. */
.switcher--foot > .switcher-btn { color: var(--mg-ink-text); }
.switcher--foot > .switcher-btn:hover,
.switcher--foot[open] > .switcher-btn,
.switcher--foot.is-open > .switcher-btn { background: var(--mg-ink-hover); color: var(--mg-ink-text-strong); }
.switcher--head > .switcher-btn { color: var(--mg-text-muted); }
.switcher--head > .switcher-btn:hover,
.switcher--head[open] > .switcher-btn,
.switcher--head.is-open > .switcher-btn { background: var(--mg-row-hover); color: var(--mg-text); }

/* --- §3 the panel. One opaque box. No max-height/overflow: it must not scroll
   or clip. */
.switcher-panel {
  position: absolute;
  width: 268px;
  padding: 10px;
  background: var(--mg-card);
  color: var(--mg-text);
  border: 1px solid var(--mg-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-float);
  z-index: 40;
  font-family: Helvetica, Arial, sans-serif;
}
/* Opens UPWARD, left-aligned: at the foot of a pinned rail there is no room
   below. */
.switcher--foot .switcher-panel { bottom: calc(100% + 6px); left: 0; }
/* Opens DOWNWARD, right-anchored: the head mount sits at the bar's right edge,
   so anchoring right is what keeps it on screen. */
.switcher--head .switcher-panel { top: calc(100% + 6px); right: 0; max-width: calc(100vw - 28px); }

/* --- §4 the head row: "Switch Sites" + the sign-out pill. ALWAYS rendered,
   even with an empty app list -- sign-out has to survive a registry failure. */
.switcher-head-row { display: flex; align-items: center; gap: 8px; padding: 0 6px 8px; }
.switcher-head-label {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--mg-text-muted);
  min-width: 0;
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.switcher-signout { margin: 0; flex: none; }
/* The estate's ONE sign-out affordance at every width: the submit button of this
   app's existing POST /auth/logout form. */
.switcher-pill {
  flex: none;
  display: inline-flex;
  align-items: center;
  padding: 3px 10px;
  border: 1px solid var(--mg-teal);
  border-radius: 999px;
  background: var(--mg-teal);
  color: #FFFFFF;
  font-family: inherit;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.5px;
  line-height: 1.5;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
  min-height: 0;
  transition: background-color 80ms linear, color 80ms linear, border-color 80ms linear;
}
.switcher-pill:hover { background: var(--mg-teal-deep); border-color: var(--mg-teal-deep); color: #FFFFFF; }

/* --- §5 the tile grid. */
.switcher-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; }
.switcher-app {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 10px 4px;
  border: 1px solid transparent;
  border-radius: var(--radius);
  font-size: 11px;
  text-align: center;
  transition: background-color 80ms linear, color 80ms linear, border-color 80ms linear;
}
/* Long app names WRAP inside the tile rather than ellipsizing. */
.switcher-name { line-height: 1.2; }
a.switcher-app { color: var(--mg-text-2); text-decoration: none; }
/* The hover trio -- background, border, text -- plus the icon recolor. The global
   a:hover underline is cancelled: a tile is a box, not body copy. */
a.switcher-app:hover { background: var(--mg-row-hover); border-color: var(--mg-teal-tint-border); color: var(--mg-text); text-decoration: none; }
a.switcher-app:hover .switcher-icon { color: var(--mg-teal-deep); }
/* Current app: the same box as its neighbors, tinted and INERT (it renders as a
   div -- nothing to click, nothing to tab to). No hover change. */
.switcher-app.is-current {
  background: var(--mg-teal-tint);
  border-color: var(--mg-teal-tint-border);
  color: var(--mg-teal-deep);
  font-weight: 600;
  cursor: default;
}
.switcher-app.is-current .switcher-icon { color: var(--mg-teal-deep); }
/* The icon slot is the ONLY place registry markup is injected; currentColor on
   the artwork is what lets the tile states recolor it. */
.switcher-icon { width: 26px; height: 26px; display: flex; align-items: center; justify-content: center; color: var(--mg-text-muted); }
.switcher-icon svg { width: 24px; height: 24px; display: block; }
/* No-icon fallback: the app name's first character in the same slot. */
.switcher-letter { font-size: 13px; font-weight: 700; }
/* A maintenance row STAYS a clickable link and gains this badge. */
.switcher-maint {
  display: inline-block;
  margin-top: 2px;
  padding: 2px 6px;
  border: 1px solid var(--mg-amber-border);
  border-radius: 3px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--mg-amber-text);
  background: var(--mg-amber-tint);
}
/* Desktop-first: the head mount is the NARROW-width one, so it is off by default
   and the 840px query swaps the pair. */
.switcher--head { display: none; }

/* ---------- Login / error / not-provisioned ---------- */
.center-page { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 24px; }
.login-card { width: 100%; max-width: 420px; background: #fff; border: 1px solid var(--mg-border); border-radius: var(--radius-md); padding: 24px; }
.login-card .brand { display: flex; flex-direction: column; align-items: center; gap: 8px; margin-bottom: 18px; }
.login-card .brand img { height: 32px; }
.login-card .brand .app { font-size: 10px; letter-spacing: 2px; text-transform: uppercase; color: var(--mg-text-2); font-weight: 600; }

/* ---------- "Coming soon" placeholder ---------- */
.placeholder { text-align: center; padding: 48px 24px; color: var(--mg-text-muted); }
.placeholder .glyph-big { font-size: 34px; color: var(--mg-text-faint); display: block; margin-bottom: 10px; }
.placeholder h2 { font-size: 18px; color: var(--mg-text); margin-bottom: 8px; }

/* ---------- Responsive (end of file, max-width only) ---------- */
@media (max-width: 1200px) {
  .tile .value { font-size: 24px; }
}
@media (max-width: 900px) {
  .grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .grid-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 840px) {
  /* The whole rail -- its switcher foot included -- hides behind the hamburger
     here, so the dots move to the ALWAYS-visible topbar: canonical §2 forbids
     the switcher living inside a collapsed menu. Exactly one mount is visible at
     any width, which is also what keeps ONE sign-out pill on screen. */
  .switcher--head { display: inline-flex; }
  .switcher--foot { display: none; }
  /* The freshness stamp eats the width the title and the dots need on a phone. */
  .topbar .fresh { display: none; }
  .shell { display: block; }
  .sidebar { position: static; width: auto; height: auto; display: none; flex-direction: column; }
  .js-nav .sidebar { display: none; }
  .js-nav.nav-open .sidebar { display: flex; }
  .no-js .sidebar { display: flex; }
  .hamburger { display: block; }
  .topbar { padding: 0 12px; }
  .content { padding: 16px 12px 40px; }
  .main { min-height: 100vh; }
}
@media (max-width: 640px) {
  .grid-4, .grid-3, .grid-2 { grid-template-columns: minmax(0, 1fr); }
}
/* §3: under 380px the header panel narrows so it stays fully on screen -- the
   268px box would overhang -- and the grid drops to 2 columns. */
@media (max-width: 379px) {
  .switcher--head .switcher-panel { width: 208px; }
  .switcher--head .switcher-grid { grid-template-columns: repeat(2, 1fr); }
}
/* Chrome never prints (canonical §6): the switcher is not page content. */
@media print {
  .switcher, .no-print { display: none; }
}
