/* SMS Inbox - house design, hand-written, no framework, no build step.
   Adapted from CC-DT_Inventory dt_inventory/web/static/app.css (shell, rail,
   switcher, login card, alerts, buttons, responsive blocks), trimmed to what a
   one-page app uses, plus the inbox section at the end.
   Tokens are the vendored martin-group-design ones (brand/tokens/*.css), linked
   from _head.html ahead of this file.
   Breakpoints: 840 (hamburger) / 640 / 379. No page-level horizontal scroll. */

/* Arial first, no Helvetica Neue: partial Helvetica Neue installs on Windows
   render every weight >= 600 as Bold Condensed Oblique (switcher canonical §0). */
:root {
  --font-sans: Arial, Helvetica, 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 ---------- */
.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; }

/* ---------- 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); }

/* ---------- 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); }
.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%; }

/* ==========================================================================
   App switcher -- nine dots.

   Transcribed from docs/handoffs/switcher-canonical.md (v3, 2026-09-29),
   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-back: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;
}
/* §5b drilled view: the back button stands in for the label with the label's
   exact look, but HUGS its text (margin-right:auto keeps the pill hard right) so
   the hit area is the words, not the row. */
.switcher-back {
  min-width: 0;
  margin: 0 auto 0 0;
  padding: 0;
  border: 0;
  background: none;
  color: var(--mg-text-muted);
  font-family: inherit;
  font-size: 10px;
  line-height: 1.5;
  letter-spacing: 1px;
  text-align: left;
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
}
.switcher-back:hover { color: var(--mg-text); }
/* The label, back buttons and member grids are all server-rendered; JS swaps
   them with the `hidden` attribute, which the display rules here (and the
   <380px `.switcher--head .switcher-grid` rule) would otherwise out-rank. */
.switcher .switcher-panel [hidden] { display: none; }
.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); }
/* §5b group tile: the §5 box as a <button>. The reset keeps the browser's
   button chrome (grey fill, line-height normal, shrink-to-fit, system font) off
   the tile -- and keeps .switcher-app's 11px: never the `font: inherit`
   shorthand here, which would out-specify it. */
button.switcher-app {
  width: 100%;
  margin: 0;
  background: none;
  color: var(--mg-text-2);
  font-family: inherit;
  font-weight: inherit;
  line-height: 1.5;
  cursor: pointer;
}
/* A group holding THIS app: the current tile's tint, but still a live button. */
.switcher-group.has-current {
  background: var(--mg-teal-tint);
  border-color: var(--mg-teal-tint-border);
  color: var(--mg-teal-deep);
  font-weight: 600;
}
.switcher-group.has-current .switcher-icon { color: var(--mg-teal-deep); }
/* Hover is the §5 link-tile trio + icon recolor, and it OVERRIDES the tint:
   button.switcher-group:hover (0,2,1) out-ranks .switcher-group.has-current. */
button.switcher-group:hover { background: var(--mg-row-hover); border-color: var(--mg-teal-tint-border); color: var(--mg-text); }
button.switcher-group:hover .switcher-icon { color: var(--mg-teal-deep); }
/* The trailing "›" drill-in cue; inherits the tile color. */
.switcher-cue { margin-left: 2px; }
/* 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; }

/* ---------- Empty / loading (house defaults; not designed) ---------- */
.empty { padding: 24px; text-align: center; color: var(--mg-text-muted); }
.empty-mark { display: block; font-size: 22px; color: var(--mg-text-faint); margin-bottom: 6px; }
.empty-head { font-weight: 600; color: var(--mg-text); margin-bottom: 2px; }
.empty-detail { font-size: 12px; margin: 0; }
/* An hx-indicator STRIP, not a spinner: this brand barely moves. */
.loading-strip { height: 2px; background: var(--mg-teal); opacity: 0; transition: opacity 80ms linear; }
.htmx-request.loading-strip, .htmx-request .loading-strip { opacity: 1; }
.topbar-logo { display: none; height: 22px; }

/* ---------- Responsive (max-width only) ---------- */
@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; }
  /* ROUND 6 / B4 -- the drawer opens DOWNWARD, as an overlay.
     The phone drawer IS the desktop rail, and the rail is the first child of
     `.shell` while the sticky bar lives inside `.main` further down the DOM.
     As an in-flow block the open rail therefore inserted ~854px of content
     ABOVE the bar; Chrome's scroll anchoring moved the scroll position by the
     same amount to keep the page still, and the menu landed entirely off the
     top of the screen (measured rect top: -1754px at 390x844). Taking it OUT
     of flow is the whole fix: nothing above the bar moves, so there is nothing
     for scroll anchoring to compensate for.
     `--topbar-open-top` is written by nav.js from the bar's measured bottom
     edge, because the bar is 52px at 840 and ~74px at 390 where it wraps to a
     second row (A19). The fallback covers the no-JS-yet frame only. */
  .js-nav.nav-open .sidebar {
    display: flex;
    position: fixed;
    left: 0; right: 0;
    top: var(--topbar-open-top, 52px);
    bottom: 0;
    width: auto; height: auto;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    /* The page behind an overlay must not scroll. `overflow: hidden` on <html>
       (or on <body>, which propagates to it) is the usual scroll lock and it
       CANNOT be used here: it takes the viewport out of the scrolling box, the
       sticky topbar stops sticking, and the bar jumps to its static position --
       measured at 390x844 scrolled to 900px, the bar's rect went from [0, 74]
       to [-900, -826], i.e. the header vanished the moment the menu opened.
       The drawer covers everything below the bar, so every scroll gesture
       lands on it anyway; `contain` is what stops that scroll CHAINING to the
       report underneath once the drawer hits its end. */
    overscroll-behavior: contain;
    z-index: 20;                      /* over .topbar's z-index: 5 content */
    box-shadow: 0 10px 24px rgba(0, 0, 0, .35);
  }
  /* `.nav` is the band that actually scrolls (base rule: flex:1, min-height:0,
     overflow-y:auto), which is what keeps the switcher foot pinned to the
     bottom of the drawer rather than trailing off the end of the links. It is
     the INNER link of the scroll chain, so it states the containment too --
     measured at 360x640, where the 15 links overflow by 235px. */
  .js-nav.nav-open .nav { overscroll-behavior: contain; }
  /* The bar already carries the logo at this width (canonical §2.6), so the
     drawer's own plate is a second copy of it costing 60px of the menu. */
  .sidebar .logo-plate { display: none; }
  .no-js .sidebar { display: flex; }
  .hamburger { display: block; }
  .topbar { padding: 0 12px; }
  .content { padding: 16px 12px 40px; }
  .main { min-height: 100vh; }
}
/* §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; }
}
@media (max-width: 840px) {
  /* Once the rail is behind the hamburger the brand row carries the logo at
     every width (§2.6): logo . nine dots . hamburger, always visible. */
  .topbar-logo { display: block; }
}

/* ==========================================================================
   Login / denied / error extras
   ========================================================================== */
.card-title { margin-bottom: 8px; }
.card-actions { margin-top: 14px; }
.login-alt { text-align: center; margin-top: 10px; }
.login-note { margin-top: 16px; }
.login-dev { color: var(--mg-amber-text); }

/* ==========================================================================
   Inbox: the TeamSMS layout. A number heading, then ONE column of message
   cards, newest first: sender bold, relative age right-aligned, body below,
   then the extracted code large with a copy button.
   ========================================================================== */
.inbox { max-width: 760px; }
.inbox-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px 12px; flex-wrap: wrap; margin-bottom: 10px; }
.inbox-number { font-size: 22px; font-weight: 700; font-variant-numeric: tabular-nums; padding-right: .12em; overflow-wrap: anywhere; }

/* The number filter as chips: phone width only (the rail carries it above 840). */
.num-chips { display: none; flex-wrap: wrap; gap: 6px; }
.num-chip { display: inline-flex; align-items: center; min-height: 44px; padding: 0 12px; background: #fff; border: 1px solid var(--mg-border); border-radius: var(--radius); color: var(--mg-text-2); font-size: 13px; font-variant-numeric: tabular-nums; text-decoration: none; }
.num-chip:hover { border-color: var(--mg-teal-tint-border); color: var(--mg-text); text-decoration: none; }
.num-chip.is-active { background: var(--mg-teal-tint); border-color: var(--mg-teal-tint-border); color: var(--mg-teal-deep); font-weight: 600; }

.inbox-banner { margin-bottom: 10px; }

/* "Data as of ... CT": the house freshness line, one strip above the cards. */
.fresh-strip { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 5px; margin: 0 0 12px; padding: 6px 10px; font-size: 12px; background: var(--mg-strip); border: 1px solid var(--mg-border); border-radius: var(--radius); }
.fresh-strip .stamp-label { color: var(--mg-text-muted); }
.fresh-strip .stamp-value { color: var(--mg-text); font-weight: 700; }
.fresh-sep { color: var(--mg-text-faint); }

.msg-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.msg { background: var(--mg-card); border: 1px solid var(--mg-border); border-radius: var(--radius); padding: 12px 14px; min-width: 0; }
/* A text that landed in the last few minutes: the teal accent, nothing louder. */
.msg.is-fresh { border-left: 3px solid var(--mg-teal); padding-left: 12px; }
.msg-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.msg-sender { font-size: 14px; font-weight: 700; color: var(--mg-text); min-width: 0; overflow-wrap: anywhere; font-variant-numeric: tabular-nums; padding-right: .12em; }
.msg-age { flex: none; font-size: 12px; color: var(--mg-text-muted); white-space: nowrap; cursor: default; }
.msg-to { font-size: 11px; color: var(--mg-text-muted); margin-top: 1px; font-variant-numeric: tabular-nums; }
.msg-body { margin: 6px 0 0; font-size: 14px; color: var(--mg-text); white-space: pre-wrap; overflow-wrap: anywhere; }

.msg-codes { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.code-row { display: inline-flex; align-items: center; gap: 12px; max-width: 100%; padding: 6px 6px 6px 14px; background: var(--mg-teal-tint); border: 1px solid var(--mg-teal-tint-border); border-radius: var(--radius); }
.code-value { font-family: var(--font-mono); font-size: 26px; font-weight: 700; line-height: 1.2; letter-spacing: 2px; color: var(--mg-teal-deep); font-variant-numeric: tabular-nums; cursor: pointer; padding-right: .12em; overflow-wrap: anywhere; }
.copy-btn { flex: none; display: inline-flex; align-items: center; justify-content: center; min-width: 72px; min-height: 36px; padding: 6px 14px; font: inherit; font-family: var(--font-sans); font-size: 13px; font-weight: 700; color: #fff; background: var(--mg-teal); border: 1px solid var(--mg-teal); border-radius: var(--radius); cursor: pointer; transition: background-color 80ms linear, border-color 80ms linear; }
.copy-btn:hover { background: var(--mg-teal-hover); border-color: var(--mg-teal-hover); }
.copy-btn.is-copied { background: var(--mg-teal-deep); border-color: var(--mg-teal-deep); }
.copy-btn.is-failed { background: #fff; color: var(--mg-red); border-color: var(--mg-red-border); }

.msg-more { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 6px 10px; margin-top: 12px; }
.msg-more .btn { color: var(--mg-text-2); font-weight: 600; }
.msg-more-note { font-size: 12px; color: var(--mg-text-muted); }

.messages .empty { padding: 32px 16px; }
.messages .empty-head { display: block; }

@media (max-width: 840px) {
  .num-chips { display: flex; }
  .inbox-head { flex-direction: column; align-items: stretch; }
}
@media (max-width: 640px) {
  .inbox-number { font-size: 20px; }
  .msg { padding: 10px 12px; }
  .msg.is-fresh { padding-left: 10px; }
  .code-row { display: flex; width: 100%; justify-content: space-between; }
  .code-value { font-size: 24px; }
  .copy-btn { min-height: 44px; min-width: 84px; }
}
