/* ══════════════════════════════════════════════════════════════════
   Repo Library — apps.runmai.app/repos
   Reuses the Work Hub design language. rp-card / rr-* / wt-dropdown /
   wk-tab-picker rules are ported verbatim from vo-app-work (work.css +
   report-review.js injected styles) so this matches Work exactly.

   ⚠️ HOUSE RULE ON CORNERS — read this before adding a `border-radius`.
   Tyler, twice now: *"I don't like how you have all the circular, round stuff.
   Just delete that. Yes, our buttons are round — that's what we want for SOME
   buttons, but not for everything."* So:
     • BUTTONS are rounded rectangles — 10px (.rm-btn), 8px for a small one.
     • LABELS, CHIPS, PLAQUES, BADGES, COUNTS and BARS are 3–8px. Never 999px.
       A capsule reads as a bubble floating on the page; these sit on it.
     • A LOGO IS NEVER CROPPED ROUND. A wordmark in a circle is an unreadable
       smudge, and most of ours are wordmarks.
   Four things stay round, on purpose, and they are the whole exception list:
   a status DOT (a dot is a dot), a PERSON'S FACE, a SPINNER, and the scrollbar
   thumb. If you are reaching for 50% on anything else, it is one of the four or
   it is wrong.
   ══════════════════════════════════════════════════════════════════ */

/* ── Work design tokens (subset needed by the ported components) ── */
.repos-page{
  --f:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
  --ink:#161616; --ink2:#525252; --ink3:#8d8d8d; --ink4:#c6c6c6;
  --surf:#ffffff; --border:#e0e0e0; --border-s:#f4f4f4;
  --radius:16px; --radius-sm:10px;
  --c-blue:var(--wt-theme-primary,#649954);
  font-family:var(--f); color:var(--ink);
  /* One place to say where anything sticky stops. MEASURED in this hub
     2026-07-30: `.ai-topnav` computes `position:relative` (styles.css declares
     sticky, something later overrides it) and scrolls away, so there is nothing
     overhead to clear — 14px, not the 76px `.ph-sidebar` reserves. If the
     topnav is ever genuinely sticky again this is the only number to change,
     and 76px is the value to match. */
  --rp-stick:14px;
}

.repos-page{ padding:2px 0 40px; }

/* ── The one reason position:sticky was a no-op on this page ──────────────
   base.css sets `overflow-y:auto` on BOTH html and body. Any overflow value
   other than visible/clip makes an element a scroll CONTAINER, and a sticky
   descendant anchors to its nearest scroll container — so every sticky rule in
   the document anchored to <body>, which has no constrained height and
   therefore never scrolls. The rail rendered in the right place and then rode
   the page down. No error, no warning, and no amount of tuning `top:` fixes it.
   `overflow-x:clip` still kills a rogue sideways scrollbar without creating a
   scroll container. ⚠️ Leave `html` alone — html IS the viewport scroller, and
   overriding it there removes the page scrollbar the platform standard wants. */
body{ overflow-y:visible; overflow-x:clip; }

/* ══ TWO-COLUMN SHELL, AND THE RAIL DOWN THE LEFT ═══════════════════════════
   ⚠️ THE RAIL IS A LIST, NOT A STACK OF CARDS. Tyler: *"the left-side views
   could look better… I don't like how it's circular. Really clean it all up."*
   Three things were wrong and only one of them was decoration:

   1. THE LABEL WRAPPED. Every item was a bare flex row with the label as an
      anonymous text node, so "Static Web Apps" — once it carried a finding
      badge AND the bill — broke onto three lines with both plaques floating
      beside the middle one. A rail item is ONE LINE, always: the label
      truncates and the numbers keep their place. That is the whole fix, and it
      is why the width went up 20px rather than the font coming down.
   2. THE ACTIVE MARKER WAS A FLOATING LOZENGE — a 4px stub, rounded on one
      end, hanging 12px outside the item. Squared and flush now, which is what
      a rail marker is: an edge, not an object.
   3. RADII. 16px on the card and 10px on every item read as bubbles inside a
      bubble. The card is 12px, items are 8px, plaques 4–5px — the house rule
      at the top of this file, applied here too. */
/* ⚠️ 256, AND THE NUMBER IS MEASURED. The binding item is "Static Web Apps"
   carrying BOTH a finding badge and the monthly bill: the label needs 97px and
   at 248 it was handed 95, so it ellipsed to "Static Web …" — the one label on
   the page you least want abbreviated. 256 (plus the tightened badge margin
   below) leaves ~10px of slack in the system fallback font, and more in Inter.
   If another number is ever added to a rail item, re-measure; do not guess. */
.repos-shell{ display:grid; grid-template-columns:256px minmax(0,1fr); gap:20px; align-items:start; }
.repos-sidebar{ position:sticky; top:var(--rp-stick,14px); background:var(--surf); border:1px solid var(--border);
  border-radius:12px; padding:10px 10px 12px; box-shadow:0 1px 2px rgba(0,0,0,.04);
  /* If the rail is ever taller than the screen it scrolls itself, so the bottom
     of it stays reachable instead of being stranded off the top of the viewport. */
  max-height:calc(100vh - var(--rp-stick,14px) - 14px); overflow-y:auto; overscroll-behavior:contain; }
.repos-sidebar .ph-sb-label{ font-size:10px; font-weight:800; letter-spacing:.8px; color:var(--ink4);
  text-transform:uppercase; padding:8px 8px 6px; }
.repos-sb-rule{ height:1px; background:var(--border-s); margin:10px 2px 2px; }
.repos-nav{ display:flex; flex-direction:column; gap:1px; }
/* ⚠️ `white-space:nowrap` + `overflow:hidden` is load-bearing, not tidying —
   without it the label wraps and takes the badges with it (see note above). */
.repos-sidebar .ph-sb-item{ display:flex; align-items:center; gap:9px; width:100%; text-align:left;
  padding:8px 10px; border-radius:8px; border:1px solid transparent; background:transparent;
  color:var(--ink2); font:inherit; font-size:13px; font-weight:600; cursor:pointer; position:relative;
  white-space:nowrap; overflow:hidden; line-height:1.35; }
.repos-sidebar .ph-sb-item:hover{ background:var(--border-s); color:var(--ink); }
/* ⚠️ THE WEIGHT DOES NOT CHANGE ON SELECT. Bolding the active label re-measures
   the row, so the widest item ("Static Web Apps" + finding + bill) fitted when
   idle and ellipsed the moment you clicked it — the label went to "Static Web
   A…" on the one view you were looking at. The tint, the colour and the edge
   bar carry the state; the text stays exactly the same size it was. */
.repos-sidebar .ph-sb-item.is-active{ background:color-mix(in srgb,var(--c-blue) 10%,transparent);
  color:var(--c-blue); }
.repos-sidebar .ph-sb-item.is-active::before{ content:''; position:absolute; left:0; top:0; bottom:0;
  width:3px; border-radius:0; background:var(--c-blue); }
/* The only thing in the row allowed to shrink. See the markup note in
   buildShell(): a bare text node cannot, which is why this element exists. */
.repos-sidebar .ph-sb-txt{ flex:1 1 auto; min-width:0; overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap; }
.repos-sidebar .ph-sb-icon{ display:inline-flex; flex:0 0 auto; opacity:.85; }
.repos-sidebar .ph-sb-item.is-active .ph-sb-icon{ opacity:1; }
.repos-sidebar .ph-sb-icon svg{ width:15px; height:15px; }
.repos-co-dot{ width:9px; height:9px; border-radius:3px; flex:0 0 auto; }
/* The count never shrinks and never wraps — it is the reason the label
   truncates rather than the other way round. `.ph-sb-txt` takes the free space
   now, so no auto margin is needed to push these to the right. */
.repos-cnt{ flex:0 0 auto; padding-left:8px;
  font-size:11.5px; font-weight:700; color:var(--ink4); font-variant-numeric:tabular-nums; }
.repos-sidebar .ph-sb-item:hover .repos-cnt{ color:var(--ink3); }
.repos-sidebar .ph-sb-item.is-active .repos-cnt{ color:var(--c-blue); }
.repos-main{ min-width:0; }

/* in the SPA, repos mode hides the marketplace browse sidebar (we render our own) */
body[data-view-mode="repos"] .ph-sidebar{ display:none !important; }
body[data-view-mode="repos"] .ph-hub{ grid-template-columns:minmax(0,1fr) !important; }

@media(max-width:900px){ .repos-shell{ grid-template-columns:1fr; } .repos-sidebar{ position:static; } }

/* ── Page intro + breadcrumb ── */
.repos-crumb{ display:flex; align-items:center; gap:8px; margin:2px 4px 14px;
  font-size:13px; color:var(--ink3); font-weight:600; }
.repos-crumb button{ background:none; border:none; color:var(--c-blue); font:inherit;
  font-weight:700; cursor:pointer; padding:0; }
.repos-crumb .sep{ color:var(--ink4); }
/* An active scope/filter is a chip you can take off without leaving the view. */
.repos-crumb button i{ font-style:normal; font-size:11px; opacity:.6; margin-left:1px; }
.repos-crumb button:hover i{ opacity:1; }
.repos-crumb button.is-chip{ display:inline-flex; align-items:center; gap:4px; padding:3px 9px; border-radius:7px;
  color:var(--_ac,var(--c-blue)); background:color-mix(in srgb,var(--_ac,var(--c-blue)) 11%,transparent); font-size:12px; }
.repos-crumb button.is-chip:hover{ background:color-mix(in srgb,var(--_ac,var(--c-blue)) 18%,transparent); }
/* How old is everything on this page — the honest footnote to every count. */
.repos-fresh{ margin-left:auto; font-size:11px; font-weight:700; color:var(--ink3);
  background:var(--border-s); border-radius:6px; padding:3px 10px; white-space:nowrap; cursor:help; }
.repos-fresh.is-stale{ background:#fef3c7; color:#92400e; }

/* ── Scorecards (ax-card primitives come from ax-containers.css) ── */
.ax-card{ cursor:pointer; }

/* ── Toolbar: company picker + search + sort ── */
.repos-toolbar{ display:flex; align-items:center; gap:12px; flex-wrap:wrap; margin:2px 4px 4px; }
/* The Companies grid is four cards. Searching and sorting them is theatre —
   the controls did nothing there, so they don't appear there. */
.repos-toolbar.is-gridmode .repos-search,
.repos-toolbar.is-gridmode .repos-sortdd{ display:none; }
.repos-search{ display:inline-flex; align-items:center; gap:8px; flex:1; min-width:220px;
  border:1px solid var(--border); border-radius:10px; padding:8px 13px; background:#fff;
  transition:border-color .15s, box-shadow .15s; }
.repos-search:focus-within{ border-color:var(--c-blue); box-shadow:0 0 0 3px color-mix(in srgb,var(--c-blue) 14%,transparent); }
.repos-search svg{ flex:0 0 auto; stroke:var(--ink3); }
.repos-search input{ border:0; outline:0; background:transparent; font:inherit; font-size:13px; width:100%; color:var(--ink); }
.repos-sort{ background:#fff; border:1px solid var(--border); border-radius:10px; padding:8px 12px;
  font:inherit; font-size:13px; font-weight:600; color:var(--ink2); cursor:pointer; }

/* Type chips were a 40-bubble wall — replaced by the search box + the active
   filter bar at the bottom of this file (.repos-filterbar / .repos-fpill). */

/* ── Band header inside the grid ──────────────────────────────────────────
   The bands come from the sort (repos.js SORTS[].band), so this header is the
   same shape whether it says "Updated this week" or "MRG": a dot in the band's
   colour, the label, a rule, and the count. Sticky, so while you scroll a long
   band you can still see which one you are in. */
.repos-grouphd{ grid-column:1/-1; display:flex; align-items:center; gap:9px; margin:14px 2px 0;
  font-size:11.5px; font-weight:800; letter-spacing:.5px; text-transform:uppercase; color:var(--ink2);
  position:sticky; top:var(--rp-stick,14px); z-index:3; padding:8px 4px;
  background:linear-gradient(180deg,#fff 62%,rgba(255,255,255,0)); }
.repos-grouphd:first-child{ margin-top:0; }
.repos-grouphd .dot{ width:8px; height:8px; border-radius:50%; background:var(--_ac,#94a3b8);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--_ac,#94a3b8) 16%,transparent); flex:0 0 auto; }
.repos-grouphd .lb{ color:var(--_ac,var(--ink2)); }
.repos-grouphd .ln{ flex:1; height:1px; background:var(--border-s); }
.repos-grouphd .n{ color:var(--ink3); font-weight:800; font-variant-numeric:tabular-nums;
  background:var(--border-s); border-radius:6px; padding:2px 8px; letter-spacing:0; }

/* ════ Ported from work.css:2243+ — report card grid + card ════ */
.rp-overview-grid{ display:grid; grid-template-columns:repeat(3,1fr); gap:16px; padding:18px 4px; }
@media(max-width:1100px){ .rp-overview-grid{ grid-template-columns:repeat(2,1fr); } }
@media(max-width:700px){ .rp-overview-grid{ grid-template-columns:1fr; } }
/* The card body carries a WASH of the product's own colour (--rp-card-c is
   familyAccent(), the same hue as the chip on the picture and the 3px strip
   under it). 4% — far too faint to read as "a coloured card", just enough that
   a shelf of 45 repos isn't 45 identical white rectangles and your eye can tell
   two builds of the same tool belong together. Still basically white. */
.rp-card{ --rp-card-wash:color-mix(in srgb, var(--rp-card-c,#6366f1) 4%, var(--surf));
  background:var(--rp-card-wash); border:1px solid var(--border,#e2e8f0); border-radius:var(--radius,14px);
  overflow:hidden; display:flex; flex-direction:column; cursor:pointer;
  transition:border-color .22s, box-shadow .22s, transform .22s;
  box-shadow:0 1px 3px rgba(0,0,0,.04), 0 4px 12px rgba(0,0,0,.02); position:relative; }
.rp-card:hover{ border-color:color-mix(in srgb, var(--rp-card-c,#6366f1) 40%, var(--border));
  box-shadow:0 8px 32px rgba(0,0,0,.10), 0 2px 8px color-mix(in srgb, var(--rp-card-c) 12%, transparent);
  transform:translateY(-3px); }
.rp-card-thumb{ position:relative; height:154px; overflow:hidden; display:flex; align-items:center; justify-content:center; }
.rp-card-thumb::after{ content:''; position:absolute; bottom:0; left:0; right:0; height:3px; z-index:5;
  background:var(--rp-card-c,#6366f1); opacity:.85; }
.rp-card-body{ padding:12px 14px 8px; display:flex; flex-direction:column; gap:5px; flex:1; }
.rp-card-name{ font-size:13px; font-weight:700; color:var(--ink); line-height:1.3; margin-top:1px; }
.rp-card-slug{ font-size:11px; color:var(--ink3); font-family:ui-monospace,"Cascadia Code",Consolas,monospace; margin-top:-2px; }
.rp-card-info{ display:flex; flex-wrap:wrap; gap:4px; margin-top:4px; }
.rp-card-pill{ display:inline-flex; align-items:center; gap:3px; font-size:9px; font-weight:600; color:var(--ink3);
  /* mixed over the card's wash, not over white — so the pill keeps the same
     step up from its background that it had on a plain white card. */
  background:color-mix(in srgb, var(--rp-card-c,#64748b) 8%, var(--rp-card-wash,var(--surf)));
  border:1px solid color-mix(in srgb, var(--rp-card-c,#64748b) 12%, var(--border));
  border-radius:5px; padding:2px 6px; line-height:1.3; }
.rp-card-foot{ display:flex; align-items:center; gap:8px; margin-top:auto; padding:9px 12px 9px 14px; border-top:1px solid var(--border-s,#f1f5f9); }
.rp-card-foot-date{ flex:1; min-width:0; font-size:10.5px; color:var(--ink3); font-weight:600; display:inline-flex; align-items:center; gap:6px; overflow:hidden; }
/* ⚠️ The version label was a BARE TEXT NODE in this flex row, so at a narrow
   card width it wrapped onto a second line ("v1 —" / "Live demo") and shoved
   the row to 42px while the chip after it was clipped mid-word. One line, one
   ellipsis — the full label is on the card's popup either way. */
.rp-card-vlbl{ min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
/* ── the two controls in the footer, told apart ───────────────────────────
   ⚠️ THESE USED TO BE THE SAME BUTTON TWICE. Both were 11.5px/800 text with a
   small glyph and no ground, sitting side by side — so "Send" and "Open" read
   as one undifferentiated pair and the card's whole footer was grey text with
   two green words in it. Tyler: *"the send button: everything just needs to
   look better on those card interfaces."*
   SEND is the deed the shelf exists for, so it is the only thing in the footer
   with a shape: a tinted pill in the brand, quiet at rest and filling in on
   hover. OPEN is a place to go, so it stays a link and gives up its weight. */
.rp-card-foot-open{ display:inline-flex; align-items:center; gap:4px; font-size:11.5px; font-weight:700;
  color:var(--ink3); white-space:nowrap; text-decoration:none; padding:4px 7px; border-radius:7px;
  transition:background .16s, color .16s; }
.rp-card-foot-open svg{ width:12px; height:12px; opacity:.75; }
.rp-card-foot-open:hover{ background:color-mix(in srgb,var(--c-blue) 10%,transparent); color:var(--c-blue); }
.rp-card-foot-open:hover svg{ opacity:1; }
.rp-card-send{ display:inline-flex; align-items:center; gap:5px; font:inherit;
  font-size:11.5px; font-weight:700; cursor:pointer; white-space:nowrap;
  color:color-mix(in srgb, var(--c-blue) 72%, #0b1a12);
  background:color-mix(in srgb, var(--c-blue) 11%, #fff);
  border:1px solid color-mix(in srgb, var(--c-blue) 26%, #fff);
  padding:4px 10px; border-radius:8px;
  transition:background .16s, border-color .16s, color .16s; }
.rp-card-send svg{ width:12px; height:12px; }
.rp-card-send:hover{ background:var(--c-blue); border-color:var(--c-blue); color:#fff; }
.sdot{ width:7px; height:7px; border-radius:50%; flex:0 0 auto; }
.rr-tag--swa{ background:#f1f5f9; color:#64748b; border:1px solid #e8edf3;
  font-family:ui-monospace,"Cascadia Code",Consolas,monospace; font-size:10px; }

/* ══ WHICH TOOL IS THIS — the one colour on the card ══════════════════════
   The top-left of the picture used to carry a solid "OUR BUILD" plaque in the
   classification's colour. Nearly every card said the same word, so the
   loudest thing in the library was also the least informative, and the company
   pill below it was already answering "who is this for".
   What belongs here instead is the PRODUCT: *"the main thing that sets it
   apart that we should be having colours for is the product that it is. Every
   product gets its own colour."* So the chip is white and quiet, and the
   product's colour arrives as a mark on it — the same colour on every build of
   that tool, on this card, on the shelf header, and on the Products page. */
.rp-prod{ position:absolute; top:10px; left:10px; z-index:4; display:inline-flex; align-items:center; gap:6px;
  max-width:calc(100% - 20px); font-size:10.5px; font-weight:800; letter-spacing:.15px; color:#1c2b22;
  background:rgba(255,255,255,.93); border-radius:7px; padding:4px 9px 4px 7px;
  box-shadow:0 2px 8px rgba(15,23,42,.13), 0 0 0 1px color-mix(in srgb,var(--_pc,#64748b) 24%,rgba(15,23,42,.05));
  backdrop-filter:blur(4px); white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  transition:transform .22s cubic-bezier(.22,1,.36,1); }
.rp-prod i{ flex:0 0 auto; width:9px; height:9px; border-radius:3px; background:var(--_pc,#64748b);
  box-shadow:0 0 0 2px color-mix(in srgb,var(--_pc,#64748b) 18%,transparent); }
/* the build count, and only when there IS more than one build to compare */
.rp-prod b{ font-weight:800; font-variant-numeric:tabular-nums; color:var(--_pc,#64748b);
  background:color-mix(in srgb,var(--_pc,#64748b) 11%,#fff); border-radius:4px; padding:1px 5px; margin-left:1px; }
.rp-card:hover .rp-prod{ transform:translateY(-1px); }

/* top-right: only what is WRONG (or brand new) */
.rp-flags{ position:absolute; top:10px; right:10px; z-index:4; display:flex; gap:5px; }
.rp-flag{ font-size:9.5px; font-weight:900; letter-spacing:.4px; text-transform:uppercase;
  border-radius:6px; padding:3px 7px; backdrop-filter:blur(3px); }
.rp-flag.is-pub{ background:rgba(254,226,226,.94); color:#b91c1c; }
.rp-flag.is-empty{ background:rgba(255,255,255,.92); color:#475569; }
.rp-flag.is-new{ background:rgba(220,252,231,.95); color:#15803d; }

/* the scrim: everything below reads over any screenshot */
.rp-thumb-scrim{ position:absolute; left:0; right:0; bottom:0; height:62px; z-index:2; pointer-events:none;
  background:linear-gradient(180deg,rgba(9,17,12,0),rgba(9,17,12,.62)); opacity:0; transition:opacity .2s; }
.rr-thumb--app.has-shot .rp-thumb-scrim{ opacity:1; }

/* ══ Whose app is this — bottom-left, on the picture ══════════════════════
   The company mark used to be a 17px chip crammed into the footer next to the
   version string. It is the second thing you want to know about a repo, so it
   gets the corner of the picture: the real logo on a white ground (a logo on
   its own brand colour is unreadable) plus the name. */
.rp-co{ position:absolute; left:10px; bottom:12px; z-index:4; display:inline-flex; align-items:center; gap:7px;
  max-width:calc(100% - 20px); padding:4px 10px 4px 4px; border-radius:8px;
  background:rgba(255,255,255,.94); box-shadow:0 2px 10px rgba(15,23,42,.16), 0 0 0 1px rgba(15,23,42,.05);
  backdrop-filter:blur(4px); transition:transform .22s cubic-bezier(.22,1,.36,1); }
.rp-card:hover .rp-co{ transform:translateY(-2px); }
.rp-co b{ font-size:11px; font-weight:800; color:#1c2b22; letter-spacing:.1px;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.rp-co-logo{ width:22px; height:22px; border-radius:6px; flex:0 0 auto; overflow:hidden;
  display:flex; align-items:center; justify-content:center; background:#fff;
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--_ac,#649954) 26%,transparent); }
.rp-co-logo img{ width:100%; height:100%; object-fit:contain; padding:2px; box-sizing:border-box; }

/* ══ The app's own logo — bottom-RIGHT, opposite the company ══════════════
   *"Anything can have a logo if added; it would show up in the bottom right of
   the picture in the cards."* The company mark answers "whose is this"; this
   answers "which app is this", and a demo wears its product's mark because that
   is the one a client recognises.
   ⚠️ EMPTY UNTIL A LOGO ACTUALLY LOADS. The plate is drawn by `.is-on` only
   (mountThumbMark adds it on the image's own load event), so a build with no
   logo anywhere has nothing in the corner — not a white square waiting on a
   404. Same reason it is only ever laid over a SCREENSHOT: with no shot the
   thumbnail already is the logo. */
.rr-thumb-mark{ position:absolute; right:10px; bottom:12px; z-index:4;
  width:34px; height:34px; border-radius:9px; display:none; place-items:center; overflow:hidden;
  background:rgba(255,255,255,.94); box-shadow:0 2px 10px rgba(15,23,42,.18), 0 0 0 1px rgba(15,23,42,.06);
  backdrop-filter:blur(4px); transition:transform .22s cubic-bezier(.22,1,.36,1); }
.rr-thumb-mark.is-on{ display:grid; animation:rrMarkIn .24s ease both; }
.rr-thumb-mark img{ width:100%; height:100%; object-fit:contain; padding:3px; box-sizing:border-box; display:block; }
.rp-card:hover .rr-thumb-mark{ transform:translateY(-2px); }
@keyframes rrMarkIn{ from{ opacity:0; transform:scale(.9) } to{ opacity:1; transform:none } }

/* ══ …unless it is a demo, which is for nobody ════════════════════════════
   *"For demos, it's not for a company; it's just a demo."* So the pill that
   answers "whose is this" says Demo — and it is the only tag left on a card.
   Very faint on purpose: a white pill with the demo blue in the mark, the word
   and the hairline, never a block of colour. Same faintness, other colour, as
   the "ours" plaque in the popup. */
.rp-co.is-demo{ padding-right:11px;
  box-shadow:0 2px 10px rgba(15,23,42,.14), 0 0 0 1px rgba(14,165,233,.34); }
.rp-co.is-demo b{ color:#0b6fa8; font-size:10px; letter-spacing:.7px; text-transform:uppercase; }
.rp-demo-glyph{ background:linear-gradient(180deg,#f4fbff,#e3f3fd) !important;
  color:#0ea5e9; box-shadow:inset 0 0 0 1px rgba(14,165,233,.3) !important; }
.rp-demo-glyph svg{ width:12px; height:12px; margin-left:1px; }

/* ══ The gap, said out loud ══════════════════════════════════════════════
   A card with only an app icon (or nothing) looked finished. It is not — the
   library is supposed to show what the app looks like INSIDE. So anything
   without a real screenshot wears a plain note asking for one. Run
   `npm run sync:shots` and it goes away by itself. */
.rp-noshot{ position:absolute; left:0; right:0; bottom:0; z-index:4; display:none;
  align-items:center; justify-content:center; gap:6px; padding:6px 10px;
  font-size:10px; font-weight:800; letter-spacing:.3px; text-transform:uppercase;
  color:#8a6a12; background:rgba(254,243,199,.95); border-top:1px solid rgba(180,140,20,.22); }
.rp-noshot svg{ width:13px; height:13px; stroke:currentColor; fill:none; stroke-width:2; opacity:.8; }
.rp-noshot em{ font-style:normal; }
.rr-thumb--app.wants-shot .rp-noshot{ display:flex; }
.rr-thumb--app.wants-shot .rp-co{ bottom:32px; }
.rr-thumb--app.wants-shot .rp-thumb-scrim{ opacity:0; }

/* ════ Ported from report-review.js injected styles (rr-*) ════ */
.rr-thumb{ position:relative; overflow:hidden; }
.rr-thumb-tex{ position:absolute; inset:0; background:radial-gradient(circle at 6px 6px,rgba(255,255,255,.14) 1.6px,transparent 1.6px) 0 0/18px 18px; opacity:.55; pointer-events:none; }
.rr-thumb-mono{ position:absolute; inset:0; z-index:1; display:flex; align-items:center; justify-content:center; color:#fff; font-weight:800; font-size:38px; letter-spacing:1px; text-shadow:0 2px 6px rgba(0,0,0,.28); }
/* A monogram can be an acronym now — THSM, MPMA — so step the size down by
   length rather than letting four characters at 38px run past the tile. */
.rr-thumb-mono[data-n="3"]{ font-size:31px; letter-spacing:.5px; }
.rr-thumb-mono[data-n="4"]{ font-size:26px; letter-spacing:0; }
/* The old `.rr-thumb--logo` company band, `.rr-thumb-logoimg`, `.rr-thumb-flag`,
   `-badge` and `-stat` are gone: repo cards now carry `.rp-prod` / `.rp-flag` /
   `.rp-co`, and company cards paint their own brand ground. */

/* ════ App thumbnail — the card wears the APP's own face ═══════════════
   Resolved by convention in repos.js resolveThumb: screenshot → app icon →
   monogram. A screenshot fills the band (App-Store style); an icon is a real
   PWA tile, so it's presented as one — rounded square with a soft lift on a
   near-white band tinted with the company accent. The company logo is not a
   candidate: it rides the bottom-left corner as `.rp-co`. */
.rr-thumb--app{ background:linear-gradient(180deg,#fff, color-mix(in srgb,var(--_ac,#649954) 4%,#fff)); }
.rr-thumb--app::before{ content:''; position:absolute; inset:0; pointer-events:none; opacity:.45;
  background:radial-gradient(circle at 7px 7px, color-mix(in srgb,var(--_ac,#649954) 9%,transparent) 1.4px, transparent 1.4px) 0 0/20px 20px; }
.rr-thumb-appimg{ position:relative; z-index:2; width:74px; height:74px; object-fit:cover;
  border-radius:18px; background:#fff; margin-bottom:14px;
  box-shadow:0 3px 12px rgba(15,23,42,.16), 0 0 0 1px rgba(15,23,42,.05);
  transition:transform .22s cubic-bezier(.22,1,.36,1); }
.rp-card:hover .rr-thumb-appimg{ transform:translateY(-2px) scale(1.04); }
/* On a light band the white company pill needs a real edge to sit against. */
.rr-thumb--app:not(.has-shot) .rp-co{ box-shadow:0 1px 5px rgba(15,23,42,.1), 0 0 0 1px rgba(15,23,42,.1); }
.rr-thumb--app.is-fallback .rp-co{ box-shadow:0 2px 12px rgba(0,0,0,.28), 0 0 0 1px rgba(255,255,255,.35); }
/* ⚠️ Those two are (0,3,0) and would strip the demo pill's blue hairline on any
   card without a screenshot — which is most of the demos. Re-stated here, after
   them, so Demo reads as Demo on every band. */
.rr-thumb--app .rp-co.is-demo{ box-shadow:0 2px 10px rgba(15,23,42,.15), 0 0 0 1px rgba(14,165,233,.4); }
.rr-thumb--app.is-fallback .rp-co.is-demo{ box-shadow:0 2px 12px rgba(0,0,0,.26), 0 0 0 1px rgba(125,211,252,.75); }
/* a real screenshot isn't a tile — it owns the whole band */
/* `object-position` is the pre-measure default only — resolveThumb aims it at
   the app's content from the shot's own dimensions once it loads (see aimShot).
   `top center` used to be the final answer, and it framed the nav bar. */
.rr-thumb-appimg.is-shot{ position:absolute; inset:0; width:100%; height:100%;
  object-fit:cover; object-position:50% 22%; border-radius:0; background:none; box-shadow:none; }
.rp-card:hover .rr-thumb-appimg.is-shot{ transform:scale(1.03); }
.rr-thumb--app.has-shot::before{ display:none; }
.rr-thumb--app .rr-thumb-mono{ display:none; }               /* hidden while any image shows */
/* nothing resolved → coloured monogram tile, same as the company thumbs */
.rr-thumb--app.is-fallback{ background:linear-gradient(135deg,var(--_co,#649954), color-mix(in srgb,var(--_co,#649954) 62%,#000)); }
.rr-thumb--app.is-fallback::before{ opacity:.55;
  background:radial-gradient(circle at 6px 6px,rgba(255,255,255,.14) 1.6px,transparent 1.6px) 0 0/18px 18px; }
.rr-thumb--app.is-fallback .rr-thumb-mono{ display:flex; }

.rp-card--rr .rp-card-name{ font-size:14px; line-height:1.32; margin:0 0 2px; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
.rp-card--rr .rp-card-tags{ display:flex; flex-wrap:wrap; gap:5px; align-items:center; margin-top:4px; }
.rr-tag{ display:inline-flex; align-items:center; gap:4px; font-size:11px; font-weight:600; border-radius:6px; padding:3px 8px; line-height:1.2; }
.rr-tag--co{ background:#f1f5f9; color:#334155; border:1px solid #e2e8f0; max-width:170px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.rr-tag--type{ background:color-mix(in srgb,var(--tc,#2563eb) 13%,transparent); color:var(--tc,#2563eb); }
/* a classification nobody has confirmed — dashed, so a guess never reads as a fact */
.rr-tag--type.is-guess{ border:1px dashed color-mix(in srgb,var(--tc,#2563eb) 55%,transparent); opacity:.85; }
.rr-tag--new{ background:#dcfce7; color:#15803d; border:1px solid #bbf7d0; font-weight:800;
  text-transform:uppercase; letter-spacing:.4px; font-size:9.5px; }
.rr-tag--aud{ background:#ecfdf5; color:#047857; }
.rr-tag--aud.is-int{ background:#f1f5f9; color:#475569; }

/* ════ Ported from work.css:7711+ — searchable dropdown + picker bar ════ */
.wt-dropdown{ position:relative; display:inline-block; }
.wt-dropdown-trigger{ display:inline-flex; align-items:center; gap:8px; padding:8px 14px; min-width:180px;
  border-radius:10px; border:1px solid var(--border,#e2e8f0); background:#fff; font:inherit; font-size:13px; font-weight:600; color:#334155;
  cursor:pointer; white-space:nowrap; transition:border-color .2s, box-shadow .2s, transform .15s; }
.wt-dropdown-trigger:hover{ border-color:var(--c-blue,#3A86FF); color:var(--c-blue,#3A86FF); transform:translateY(-1px); box-shadow:0 4px 12px color-mix(in srgb,var(--c-blue) 10%,transparent); }
.wt-dropdown.is-open .wt-dropdown-trigger{ border-color:var(--c-blue,#3A86FF); box-shadow:0 0 0 3px color-mix(in srgb,var(--c-blue) 12%,transparent); }
.wt-dropdown-trigger .wt-dd-chevron{ margin-left:auto; transition:transform .2s; flex-shrink:0; }
.wt-dropdown.is-open .wt-dd-chevron{ transform:rotate(180deg); }
.wt-dropdown-menu{ position:absolute; top:calc(100% + 6px); left:0; min-width:260px; max-height:340px; overflow-y:auto;
  background:#fff; border:1px solid var(--border,#e2e8f0); border-radius:12px;
  box-shadow:0 12px 40px rgba(15,23,42,.14), 0 4px 12px rgba(15,23,42,.06); padding:6px; z-index:1000;
  opacity:0; transform:translateY(-6px) scale(.97); pointer-events:none; transition:opacity .18s, transform .18s; }
.wt-dropdown.is-open .wt-dropdown-menu{ opacity:1; transform:translateY(0) scale(1); pointer-events:auto; }
.wt-dropdown-search{ padding:4px 6px 6px; }
.wt-dropdown-search input{ width:100%; box-sizing:border-box; padding:7px 10px; border-radius:8px; border:1px solid var(--border,#e2e8f0); font:inherit; font-size:12px; color:#334155; }
.wt-dropdown-search input:focus{ outline:none; border-color:var(--c-blue,#3A86FF); }
.wt-dropdown-list{ max-height:250px; overflow-y:auto; }
.wt-dropdown-item{ display:flex; align-items:center; gap:8px; padding:9px 12px; border-radius:8px; font-size:13px; color:#334155; cursor:pointer; transition:background .15s, color .15s; white-space:nowrap; }
.wt-dropdown-item:hover{ background:color-mix(in srgb,var(--c-blue) 8%,transparent); color:var(--c-blue,#3A86FF); }
.wt-dropdown-item.is-active{ background:color-mix(in srgb,var(--c-blue) 12%,transparent); color:var(--c-blue,#3A86FF); font-weight:600; }
.wt-dropdown-item .co-dot{ width:9px; height:9px; border-radius:3px; flex:0 0 auto; }
.wt-dd-label{ flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; }
.wt-dd-sub{ font-size:11px; color:#94a3b8; margin-left:6px; font-weight:500; }
.wk-tab-picker{ display:flex; align-items:center; gap:12px; padding:0; }
.wk-tab-picker-label{ font-size:11px; font-weight:700; color:#64748b; text-transform:uppercase; letter-spacing:.04em; white-space:nowrap; }
.wk-tab-picker-dd{ min-width:240px; max-width:360px; }

/* ══ Coded pickers ════════════════════════════════════════════════════════
   Both of these replaced things a native control cannot do: a company list
   that shows brands, and a sort menu that says what it will DO to the page. */

/* a divider that also names the half of the list below it */
.wt-dd-grouphd{ font-size:10px; font-weight:900; letter-spacing:.7px; text-transform:uppercase;
  color:#94a3b8; padding:9px 12px 5px; }
.wt-dd-grouphd.is-split{ margin-top:4px; border-top:1px solid var(--border-s,#f1f5f9); padding-top:10px; }
.wt-dd-none{ padding:14px 12px; font-size:12.5px; color:#94a3b8; }

/* ── the company mark, one object, three sizes ──────────────────────────
   White ground, real logo if we have one, otherwise the initials TINTED in the
   brand colour. Never the logo on its own colour — that is unreadable. */
.repos-ddlogo,.rp-co-logo,.co-card-logo,.repos-ddmark.is-on{ position:relative; }
.repos-ddmono{ position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
  font-style:normal; font-weight:900; letter-spacing:.2px; color:var(--_ac,#649954);
  font-size:.62em; text-transform:uppercase; }
.repos-ddlogo.has-logo .repos-ddmono,.rp-co-logo.has-logo .repos-ddmono,
.co-card-logo.has-logo .repos-ddmono,.repos-ddmark.has-logo .repos-ddmono{ display:none; }

.repos-ddrow{ padding:8px 10px; gap:10px; }
.repos-ddlogo{ width:26px; height:26px; flex:0 0 auto; border-radius:8px; overflow:hidden; background:#fff;
  display:flex; align-items:center; justify-content:center; font-size:26px;
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--_ac,#649954) 24%,transparent); }
.repos-ddlogo img{ width:100%; height:100%; object-fit:contain; padding:3px; box-sizing:border-box; }
.repos-ddlogo.is-all{ box-shadow:inset 0 0 0 1px #e2e8f0; color:#94a3b8; }
.repos-ddlogo.is-all svg{ width:15px; height:15px; }
.repos-ddrow .wt-dd-label{ font-weight:700; }
.repos-ddrow.is-active{ box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--c-blue) 24%,transparent); }
.repos-ddrow .wt-dd-sub{ font-variant-numeric:tabular-nums; font-weight:700; }
/* the picked company rides the trigger, so the scope is legible while closed */
.repos-ddmark{ display:none; }
.repos-ddmark.is-on{ display:flex; width:20px; height:20px; flex:0 0 auto; border-radius:6px; overflow:hidden;
  background:#fff; align-items:center; justify-content:center; font-size:20px;
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--_ac,#649954) 30%,transparent); }
.repos-ddmark img{ width:100%; height:100%; object-fit:contain; padding:2px; box-sizing:border-box; }

/* Four companies do not need a scrollbar. The shared 250px list cap was
   clipping the last row of a list short enough to show whole. */
.repos-codd .wt-dropdown-menu{ max-height:min(72vh,460px); }
.repos-codd .wt-dropdown-list{ max-height:min(58vh,360px); }

/* ── sort: names the bands you're about to get ── */
.repos-sortdd{ min-width:212px; }
.repos-sortdd .wt-dropdown-trigger{ min-width:212px; }
/* five fixed options — never scroll them */
.repos-sortdd .wt-dropdown-menu{ left:auto; right:0; min-width:308px; max-height:none; overflow:visible; }
.repos-sortdd .wt-dropdown-list{ max-height:none; overflow:visible; }
.repos-sorticon{ flex:0 0 auto; stroke:#94a3b8; }
.repos-sortdd .wt-dropdown-trigger:hover .repos-sorticon{ stroke:currentColor; }
.repos-sortrow{ align-items:flex-start; padding:9px 11px; }
.repos-sortrow .wt-dd-label{ display:flex; flex-direction:column; gap:2px; white-space:normal; }
.repos-sortrow .wt-dd-label b{ font-size:13px; font-weight:800; }
.repos-sortrow .wt-dd-label em{ font-style:normal; font-size:11.5px; font-weight:500; color:#94a3b8; line-height:1.35; }
.repos-sortrow:hover .wt-dd-label em{ color:#7d8b9c; }
.repos-sortcheck{ width:16px; height:16px; flex:0 0 auto; margin-top:2px; color:var(--c-blue); }
.repos-sortcheck svg{ width:16px; height:16px; stroke-width:3; }

/* ── Company cards ────────────────────────────────────────────────────────
   Was: a flat colour band with the logo washed out on top of it and three bare
   numbers underneath. Now: the brand on a white ground with a thin accent
   wash behind it, whether they're ours or a client said in a word, and the mix
   of what we build for them as an actual bar you can read at a glance. */
.co-grid{ display:grid; grid-template-columns:repeat(auto-fill,minmax(268px,1fr)); gap:18px; padding:18px 4px; }
/* same 4% wash as .rp-card — here the colour is the COMPANY's, since that is
   what this card is. Still basically white. */
.co-card{ --rp-card-wash:color-mix(in srgb, var(--rp-card-c,var(--_ac,#649954)) 4%, var(--surf));
  background:var(--rp-card-wash); border:1px solid var(--border); border-radius:18px; overflow:hidden;
  cursor:pointer; display:flex; flex-direction:column; position:relative;
  box-shadow:0 1px 3px rgba(0,0,0,.04), 0 4px 14px rgba(0,0,0,.03);
  transition:border-color .24s, box-shadow .24s, transform .24s cubic-bezier(.22,1,.36,1); }
.co-card::before{ content:''; position:absolute; inset:0 0 auto; height:4px; z-index:2;
  background:linear-gradient(90deg,var(--_ac,#649954), color-mix(in srgb,var(--_ac,#649954) 45%,#fff)); }
.co-card:hover{ transform:translateY(-4px); border-color:color-mix(in srgb,var(--_ac) 42%,var(--border));
  box-shadow:0 14px 40px rgba(15,23,42,.12), 0 2px 8px color-mix(in srgb,var(--_ac) 14%,transparent); }
.co-card-top{ position:relative; height:112px; display:flex; align-items:center; justify-content:center;
  padding:18px; overflow:hidden;
  background:radial-gradient(circle at 50% 120%, color-mix(in srgb,var(--_ac,#649954) 12%,#fff), #fff 72%); }
.co-card-top::after{ content:''; position:absolute; inset:0; pointer-events:none; opacity:.5;
  background:radial-gradient(circle at 7px 7px, color-mix(in srgb,var(--_ac,#649954) 10%,transparent) 1.4px, transparent 1.4px) 0 0/20px 20px; }
.co-card-logo{ position:relative; z-index:2; width:120px; height:66px; display:flex; align-items:center;
  justify-content:center; font-size:66px; }
.co-card-logo img{ max-width:100%; max-height:100%; object-fit:contain;
  filter:drop-shadow(0 2px 5px rgba(15,23,42,.1)); }
.co-card-rel{ position:absolute; top:12px; right:12px; z-index:3; font-size:9.5px; font-weight:900;
  letter-spacing:.6px; text-transform:uppercase; color:var(--_ac,#649954); border-radius:5px; padding:3px 9px;
  background:color-mix(in srgb,var(--_ac,#649954) 12%,#fff);
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--_ac,#649954) 26%,transparent); }
.co-card-body{ padding:15px 17px 4px; display:flex; flex-direction:column; gap:9px; flex:1; }
.co-card-name{ font-size:17px; font-weight:800; color:var(--ink); letter-spacing:-.2px; }
.co-card-sub{ font-size:11.5px; font-weight:600; color:var(--ink3); margin-top:-5px; }
.co-card-bar{ display:flex; height:8px; border-radius:3px; overflow:hidden; background:var(--border-s); gap:2px; }
.co-card-bar i{ display:block; height:100%; }
.co-card-keys{ display:flex; flex-wrap:wrap; gap:5px 12px; }
.co-key{ display:inline-flex; align-items:center; gap:5px; font-size:10.5px; font-weight:700; color:var(--ink3); }
.co-key i{ width:8px; height:8px; border-radius:2.5px; flex:0 0 auto; }
.co-key b{ color:var(--ink2); font-variant-numeric:tabular-nums; }
.co-card-foot{ display:flex; align-items:center; justify-content:space-between; gap:8px;
  margin-top:auto; padding:11px 17px 13px; font-size:11.5px; font-weight:800; color:var(--_ac,#649954); }
.co-card-foot svg{ width:15px; height:15px; transition:transform .22s cubic-bezier(.22,1,.36,1); }
.co-card:hover .co-card-foot svg{ transform:translateX(3px); }

.repos-empty{ grid-column:1/-1; text-align:center; color:var(--ink3); font-size:13px; padding:50px 0; }
/* A failed load used to be a dead end: a parse error and nothing to do about it.
   Now it names the cause and offers the matching way out. */
.repos-empty b{ color:var(--ink); }
.repos-btn{
  display:inline-flex; align-items:center; justify-content:center;
  font:inherit; font-size:13px; font-weight:600; text-decoration:none;
  color:#fff; background:var(--brand, #559e50);
  border:1px solid transparent; border-radius:9px; padding:8px 16px; cursor:pointer;
  transition:filter .13s, box-shadow .13s;
}
.repos-btn:hover{ filter:brightness(1.07); box-shadow:0 3px 10px rgba(85,158,80,.28); }
.repos-btn:focus-visible{ outline:2px solid var(--brand, #559e50); outline-offset:2px; }

/* ── Command Center sections (Agents / Money / APIs) ── */
.ops-note{ font-size:12px; color:var(--ink3); margin:2px 2px 14px; }
.ops-grid{ display:grid; grid-template-columns:repeat(auto-fill,minmax(244px,1fr)); gap:14px; }
.ops-card{ background:var(--surf); border:1px solid var(--border); border-left:3px solid var(--_ac,#649954);
  border-radius:12px; padding:13px 14px; display:flex; flex-direction:column; gap:6px; box-shadow:0 1px 3px rgba(0,0,0,.04); }
.ops-card-h{ display:flex; align-items:center; gap:8px; }
.ops-badge{ font-size:10px; font-weight:800; letter-spacing:.3px; text-transform:uppercase; color:#fff; padding:2px 8px; border-radius:6px; }
.ops-runs{ margin-left:auto; font-size:11px; font-weight:700; color:var(--ink3); font-variant-numeric:tabular-nums; }
.ops-card-name{ font-size:14px; font-weight:700; color:var(--ink); line-height:1.25; }
.ops-card-sub{ font-size:12px; color:var(--ink2); line-height:1.4; }
.ops-card-foot{ font-size:11px; color:var(--ink3); display:flex; align-items:center; gap:6px; margin-top:auto; padding-top:6px; flex-wrap:wrap; }
.ops-card-foot a{ color:var(--c-blue); font-weight:600; }
.ops-2col{ display:grid; grid-template-columns:1fr 1fr; gap:18px; }
@media(max-width:800px){ .ops-2col{ grid-template-columns:1fr; } }
.ops-sec-h{ font-size:12px; font-weight:800; text-transform:uppercase; letter-spacing:.4px; color:var(--ink2); margin:4px 2px 10px; }
.ops-recs{ margin:0; padding-left:18px; font-size:13px; color:var(--ink2); line-height:1.65; }
.ops-cred{ margin-top:12px; font-size:12px; color:#a9781a; background:#fbeecb; border-radius:8px; padding:8px 10px; }
.ops-sec + .ops-sec{ margin-top:22px; }
.ops-note code{ font-family:ui-monospace,Consolas,monospace; font-size:11px; background:var(--border-s); padding:1px 5px; border-radius:4px; }

/* ══ STATIC WEB APPS — the fleet as a ledger, not a card wall ════════════════
   37 apps as .ops-card tiles was 37 boxes to compare five numbers across. This
   is a table: one row per app, the same columns in the same places, so the
   expensive ones and the wasteful ones are found by scanning down a column.
   Teal is money everywhere in this app (see .rm-host) and it holds here. */
.hs-split{ margin:2px 2px 18px; }
.hs-bar{ display:flex; height:10px; border-radius:3px; overflow:hidden; background:var(--border-s); gap:1px; }
.hs-bar span{ height:100%; }
.hs-key{ display:flex; flex-wrap:wrap; gap:14px; margin-top:9px; }
.hs-k{ display:inline-flex; align-items:center; gap:6px; font-size:11.5px; color:var(--ink3); font-weight:600; }
.hs-k i{ width:9px; height:9px; border-radius:2px; }
.hs-k b{ color:var(--ink2); font-weight:800; font-variant-numeric:tabular-nums; }

.hs-table{ border:1px solid var(--border); border-radius:12px; overflow:hidden; background:#fff; }
/* ⚠️ SEVEN CELLS, SEVEN TRACKS. `hs-use` was added between cost and the tier
   flag. A grid short one track does not error — it silently wraps the last cell
   onto an implicit row, and the whole table reads as broken alignment with
   nothing in the console. Count the spans in appRow() before touching this. */
.hs-row{ display:grid; grid-template-columns:minmax(0,2fr) minmax(0,1.75fr) 74px 76px 86px 116px 30px;
  align-items:center; gap:11px; padding:10px 13px; }
.hs-row + .hs-row{ border-top:1px solid var(--border-s); }
.hs-row:hover{ background:#f9fbfa; }
/* A row that opens something says so before it is clicked: the cursor, and the
   name picking up the link colour on hover. Nothing moves — a table of 41 rows
   that lifts under the pointer is a table that never sits still. */
.hs-row.is-open{ cursor:pointer; }
.hs-row.is-open:hover .hs-name b{ color:var(--c-blue); }
.hs-row.is-open:focus-visible{ outline:2px solid var(--c-blue); outline-offset:-2px; }
/* $9 a month for nothing is the finding this view exists to surface, so the row
   carries it rather than leaving it to a chip at the end of the line. */
.hs-row.is-waste{ background:#fffaf2; }
.hs-row.is-waste:hover{ background:#fdf5e9; }
.hs-row.is-none, .hs-row.is-orphan{ background:#fff8f7; }
/* The consolidation worklist reads by colour before it reads by word: red is a
   build, amber is a domain move, and a demo already on the shared app is plain
   white — done rows should recede, not celebrate. */
.hs-row.is-move-build{ background:#fff8f7; }
.hs-row.is-move-build:hover{ background:#fdf1ef; }
.hs-row.is-move-domain{ background:#fffaf2; }
.hs-row.is-move-domain:hover{ background:#fdf5e9; }

/* How many times this demo has actually gone out. Squared, tabular, and the
   never-sent state is a word rather than a zero — "0" beside a $9 bill reads
   like a rounding error; "never" reads like the finding it is. */
.hs-sends{ font-size:12px; font-weight:800; color:var(--ink2); text-align:right;
  font-variant-numeric:tabular-nums; }
.hs-sends i{ font-style:normal; font-size:10px; font-weight:700; color:var(--ink3); margin-left:3px; }
.hs-sends.is-never i{ color:#b4471f; margin-left:0; }
.hs-sends.is-unknown i{ color:var(--ink4); margin-left:0; }
.hs-name{ min-width:0; }
.hs-name b{ display:block; font-size:13px; font-weight:800; color:var(--ink); letter-spacing:-.15px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.hs-name span{ display:block; font-size:11px; color:var(--ink3); margin-top:2px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.hs-repos{ min-width:0; display:flex; flex-wrap:wrap; gap:5px; align-items:center; }
.hs-repos i{ font-style:normal; font-size:11px; color:var(--ink3); }
.hs-repos i.is-none{ color:#b4471f; font-weight:700; }
.hs-repo{ display:inline-flex; align-items:center; cursor:pointer; max-width:100%;
  font:700 11px var(--f,'Inter',system-ui,sans-serif); color:var(--c-blue);
  background:#fff; border:1px solid color-mix(in srgb,var(--c-blue) 28%,#fff);
  border-radius:6px; padding:3px 8px; transition:background .13s;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.hs-repo:hover{ background:color-mix(in srgb,var(--c-blue) 8%,#fff); }
.hs-repo.is-app{ color:#0f766e; border-color:color-mix(in srgb,#0f766e 30%,#fff); font-family:ui-monospace,Consolas,monospace; font-size:10.5px; }
.hs-tier{ font-size:10px; font-weight:800; letter-spacing:.3px; text-transform:uppercase;
  color:var(--_ac,#475569); background:color-mix(in srgb,var(--_ac,#475569) 9%,#fff);
  border:1px solid color-mix(in srgb,var(--_ac,#475569) 26%,#fff);
  border-radius:5px; padding:3px 6px; text-align:center; cursor:help; }
.hs-cost{ font-size:13px; font-weight:800; color:var(--ink); text-align:right; font-variant-numeric:tabular-nums; }
.hs-cost i{ font-style:normal; font-size:10px; font-weight:700; color:var(--ink3); }

/* ══ HOW MANY BUILDS SHIP HERE, AND WHETHER ANYBODY OPENS IT ═════════════════
   The repo COUNT is the answer to "how many repos are connected to this one
   app", so it leads the cell as a plaque and the names follow it. Squared, per
   the corner house rule at the top of this file — a count is never a pill. */
.hs-repon{ display:inline-flex; align-items:center; justify-content:center;
  min-width:20px; height:19px; padding:0 5px; border-radius:5px;
  background:var(--ink); color:#fff; font-size:11px; font-weight:800;
  font-variant-numeric:tabular-nums; flex:0 0 auto; }

/* Usage reads in three states and they must LOOK like three. Idle is the
   finding; "not read" must never wear the finding's colour, or an unmeasured
   app gets deleted for looking dead. */
.hs-use{ font-size:12.5px; font-weight:800; color:var(--ink); text-align:right;
  font-variant-numeric:tabular-nums; line-height:1.15; }
.hs-use i{ display:block; font-style:normal; font-size:9.5px; font-weight:700;
  color:var(--ink3); letter-spacing:.2px; }
.hs-use.is-idle{ color:#9333ea; }
.hs-use.is-idle i{ color:#a855f7; }
/* Deliberately the quietest thing in the row: it is an absence of knowledge,
   not a problem with the app. */
.hs-use.is-unknown{ color:var(--ink3); font-weight:700; }
.hs-flag{ font-size:10px; font-weight:800; letter-spacing:.2px; color:var(--_ac,#64748b); text-align:right; }
.hs-go{ text-align:right; }
.hs-go a{ color:var(--ink3); display:inline-flex; }
.hs-go a:hover{ color:var(--c-blue); }
.hs-go svg{ width:14px; height:14px; }
.hs-refresh{ margin-left:8px; cursor:pointer; font:700 11px var(--f,'Inter',system-ui,sans-serif);
  color:var(--c-blue); background:#fff; border:1px solid color-mix(in srgb,var(--c-blue) 30%,#fff);
  border-radius:6px; padding:2px 8px; }
.hs-refresh:hover{ background:color-mix(in srgb,var(--c-blue) 8%,#fff); }
/* ══ THE FLEET AS CARDS ══════════════════════════════════════════════════════
   Tyler: *"fix the design of each swa card… how much money and value is going
   into each, not just this bland list."*

   ⚠️ THE ONE THING THE TABLE ABOVE WAS RIGHT ABOUT IS PRESERVED ON PURPOSE.
   Forty apps as forty free-form boxes is forty places to hunt for the same
   number, which is why this view was a table in the first place. So every card
   is the SAME six bands in the same order and the three figures sit in a fixed
   three-column grid — you can still read straight down a column of cards and
   compare cost to cost, hits to hits. Break that alignment and this becomes the
   wall the table replaced.

   The accent (--_ac) is the VALUE verdict, never the tier: red means nothing
   opens it, not "on Standard". See VALUE_WORD in repos.js. */
.hs-tools{ display:flex; align-items:center; gap:10px 14px; flex-wrap:wrap; margin:0 2px 12px; }
.hs-filts{ display:flex; flex-wrap:wrap; gap:6px; min-width:0; }
.hs-filt{ display:inline-flex; align-items:center; gap:6px; cursor:pointer;
  font:700 11.5px var(--f,'Inter',system-ui,sans-serif); color:var(--ink2);
  background:#fff; border:1px solid var(--border); border-radius:8px; padding:5px 10px;
  transition:border-color .13s, background .13s, color .13s; }
.hs-filt b{ font-weight:800; font-variant-numeric:tabular-nums; color:var(--_ac,var(--ink3)); }
.hs-filt:hover{ border-color:var(--_ac,var(--c-blue)); }
.hs-filt.is-on{ color:#fff; background:var(--_ac,var(--c-blue)); border-color:var(--_ac,var(--c-blue)); }
.hs-filt.is-on b{ color:#fff; opacity:.75; }
.hs-sorts{ display:flex; align-items:center; gap:2px; margin-left:auto; flex:0 0 auto;
  background:var(--border-s); border-radius:9px; padding:3px; }
.hs-sorts em{ font-style:normal; font-size:10px; font-weight:800; text-transform:uppercase;
  letter-spacing:.4px; color:var(--ink3); padding:0 7px 0 5px; }
.hs-sortb{ cursor:pointer; border:0; background:transparent; border-radius:7px; padding:4px 9px;
  font:700 11.5px var(--f,'Inter',system-ui,sans-serif); color:var(--ink3); }
.hs-sortb:hover{ color:var(--ink); }
.hs-sortb.is-on{ background:#fff; color:var(--ink); box-shadow:0 1px 2px rgba(0,0,0,.07); }

.hs-cards{ display:grid; grid-template-columns:repeat(auto-fill,minmax(288px,1fr)); gap:12px; }
.hs-card{ position:relative; display:flex; flex-direction:column; gap:9px; min-width:0;
  background:var(--surf,#fff); border:1px solid var(--border); border-radius:12px;
  padding:12px 13px 11px; box-shadow:0 1px 2px rgba(16,24,20,.05);
  transition:border-color .14s, box-shadow .14s, transform .14s; }
/* The state, as a hairline down the left edge. A whole tinted card at 41 cards
   is a chequerboard; a 3px rule is legible at a glance and stays quiet. */
.hs-card::before{ content:''; position:absolute; left:0; top:12px; bottom:12px; width:3px;
  border-radius:0 3px 3px 0; background:var(--_ac,#94a3b8); }
.hs-card.is-open{ cursor:pointer; }
.hs-card.is-open:hover{ border-color:color-mix(in srgb,var(--_ac,#94a3b8) 45%,var(--border));
  box-shadow:0 4px 14px rgba(16,24,20,.09); transform:translateY(-1px); }
.hs-card.is-open:focus-visible{ outline:2px solid var(--c-blue); outline-offset:2px; }
/* The finding is the only state that tints, and it tints faintly. */
.hs-card.is-v-dead{ background:#fffaf9; }

.hs-c-hd{ display:flex; align-items:center; gap:7px; }
.hs-c-state{ font-size:10px; font-weight:800; letter-spacing:.35px; text-transform:uppercase;
  color:var(--_ac,#64748b); background:color-mix(in srgb,var(--_ac,#64748b) 12%,transparent);
  border-radius:5px; padding:3px 7px; white-space:nowrap; }
.hs-c-sku{ font-size:9.5px; font-weight:800; letter-spacing:.4px; text-transform:uppercase;
  color:var(--ink3); border:1px solid var(--border); border-radius:5px; padding:2px 6px; cursor:help; }
.hs-c-sku.is-std{ color:var(--ink2); background:var(--border-s); }
.hs-c-out{ margin-left:auto; display:inline-flex; color:var(--ink4); }
.hs-c-out:hover{ color:var(--c-blue); }
.hs-c-out svg{ width:14px; height:14px; }
.hs-c-name b{ display:block; font:800 13px/1.2 ui-monospace,Consolas,monospace; color:var(--ink);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; letter-spacing:-.2px; }
.hs-card.is-open:hover .hs-c-name b{ color:var(--c-blue); }
.hs-c-name span{ display:block; font-size:10.5px; color:var(--ink3); margin-top:3px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

/* ⚠️ THREE TRACKS, FIXED. This is the alignment the card wall lives or dies on:
   money, traffic and repos in the same place on every card. */
.hs-c-figs{ display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:1px;
  background:var(--border-s); border:1px solid var(--border-s); border-radius:8px; overflow:hidden; }
.hs-c-fig{ background:#fff; padding:7px 9px; min-width:0; cursor:help; }
.hs-c-fig b{ display:block; font-size:17px; font-weight:800; color:var(--ink);
  font-variant-numeric:tabular-nums; letter-spacing:-.5px; line-height:1.1; }
.hs-c-fig span{ display:block; font-size:9.5px; font-weight:700; color:var(--ink3);
  margin-top:3px; text-transform:uppercase; letter-spacing:.3px; white-space:nowrap;
  overflow:hidden; text-overflow:ellipsis; }
.hs-c-fig.is-nil b{ color:var(--ink3); }
.hs-c-fig.is-zero b{ color:#b4471f; }
.hs-c-fig.is-unk b{ color:var(--ink4); }

.hs-c-track{ height:5px; border-radius:3px; background:var(--border-s); overflow:hidden; }
.hs-c-track span{ display:block; height:100%; border-radius:3px; background:var(--_ac,#94a3b8); }
/* Unmeasured is hatched, not empty — an empty bar reads as a measured zero, and
   the whole point of this state is that we did not look. */
.hs-c-track.is-unk{ background:repeating-linear-gradient(135deg,#eef1ef 0 4px,#f7f9f8 4px 8px); }
.hs-c-line{ font-size:11.5px; line-height:1.45; color:var(--ink2); min-height:17px; }
.hs-c-line b{ font-weight:800; color:var(--ink); font-variant-numeric:tabular-nums; }
.hs-c-line i.warn{ font-style:normal; font-weight:700; color:#b4471f; }

.hs-c-repos{ display:flex; flex-wrap:wrap; gap:5px; align-items:center; }
.hs-c-repos i{ font-style:normal; font-size:11px; color:var(--ink3); }
.hs-c-repos i.is-none{ color:#b4471f; font-weight:700; }
.hs-repo.is-plain{ cursor:help; color:var(--ink3); border-style:dashed; }

.hs-c-ft{ display:flex; align-items:center; flex-wrap:wrap; gap:5px;
  margin-top:auto; padding-top:9px; border-top:1px solid var(--border-s);
  font-size:10.5px; font-weight:700; color:var(--ink3); }
.hs-c-dot{ color:var(--ink4); }
.hs-c-dep{ cursor:help; display:inline-flex; align-items:center; gap:4px; }
.hs-c-dep::before{ content:''; width:6px; height:6px; border-radius:50%; background:currentColor; }
.hs-c-dep.is-live{ color:#166534; }
.hs-c-dep.is-stale{ color:#b45309; }
.hs-c-dep.is-token{ color:#b4471f; }
.hs-c-warn{ color:#b4471f; }
.hs-c-gh{ margin-left:auto; display:inline-flex; color:var(--ink4); }
.hs-c-gh:hover{ color:var(--ink); }
.hs-c-gh svg{ width:14px; height:14px; }

/* Two meters side by side; the value one leads and takes the room. */
.hs-splits{ display:grid; grid-template-columns:minmax(0,1.4fr) minmax(0,1fr); gap:22px; align-items:start; }
.hs-split-h{ display:flex; align-items:center; gap:6px; font-size:10.5px; font-weight:800;
  text-transform:uppercase; letter-spacing:.4px; color:var(--ink3); margin-bottom:7px; }
.hs-split-h i{ font-style:normal; cursor:help; width:13px; height:13px; border-radius:50%;
  background:var(--border-s); color:var(--ink3); font-size:9px; font-weight:800;
  display:inline-flex; align-items:center; justify-content:center; }
@media (max-width:760px){ .hs-splits{ grid-template-columns:1fr; gap:16px; } }

@media (max-width:860px){
  .hs-sorts{ margin-left:0; }
  /* Cost and tier are the two columns worth keeping aligned on a narrow screen;
     the rest wraps rather than shrinking into ellipses. */
  .hs-row{ grid-template-columns:minmax(0,1fr) 76px 86px; grid-auto-rows:auto; }
  .hs-repos{ grid-column:1 / -1; }
  /* Usage keeps its own line rather than being squeezed to an ellipsis — it is
     one of the two numbers this view exists to show. */
  .hs-use{ grid-column:1 / -1; text-align:left; }
  .hs-use i{ display:inline; margin-left:5px; }
  .hs-flag, .hs-go{ grid-column:1 / -1; text-align:left; }
}

/* ══ ONE APP, OPENED — the popup behind a hosting row ════════════════════════
   Same grammar as .rm-sheet (scrim, boxed dialog, squared corners) but its own
   layer, because it mounts on <html> beside the repo popup rather than inside
   it. ⚠️ z-index sits BELOW .rm-backdrop on purpose: a repo chip in here opens
   the full repo popup ON TOP and this stays behind it — see openSwaApp. No
   backdrop-filter, or it would join the painted layer that .rm-backdrop wins.
   Corners follow the house rule at the top of this file: 12px on the box, 8px
   on the buttons, 4–6px on every plaque. Nothing here is a capsule. */
.hsm{ position:fixed; inset:0; z-index:2147483300; display:flex;
  align-items:center; justify-content:center; padding:26px 16px;
  /* ⚠️ IT MOUNTS ON <html>, SO IT INHERITS NOTHING. Every token this file uses
     is declared on `.repos-page`, and a var() that resolves to nothing makes the
     whole declaration invalid — which is silent: `color:var(--c-blue)` just
     inherits, `border:1px solid var(--border)` just disappears. That is exactly
     how the repo chips in here first rendered as bare bold text. `.rm-backdrop`
     redeclares the set for the same reason (see below); this does too. */
  --f:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
  --ink:#161616; --ink2:#525252; --ink3:#8d8d8d; --ink4:#c6c6c6;
  --surf:#ffffff; --border:#e0e0e0; --border-s:#f4f4f4;
  --c-blue:var(--wt-theme-primary,#649954);
  font-family:var(--f); color:var(--ink); }
.hsm-scrim{ position:absolute; inset:0; background:rgba(9,17,26,.42);
  opacity:0; transition:opacity .2s; }
.hsm.is-open .hsm-scrim{ opacity:1; }
.hsm-box{ position:relative; width:min(620px,100%); max-height:100%;
  display:flex; flex-direction:column; background:#fff; border:1px solid var(--border);
  border-radius:12px; box-shadow:0 18px 60px rgba(9,17,26,.28);
  transform:translateY(10px) scale(.985); opacity:0;
  transition:transform .22s cubic-bezier(.22,1,.36,1), opacity .18s; }
.hsm.is-open .hsm-box{ transform:none; opacity:1; }
/* ⚠️ NO `.hsm-hd` / `.hsm-t` / `.hsm-ft` ANY MORE. The popup grew a hero band
   and a tab strip (see .hsm-hero, and openSwaApp for why), so the old boxed
   header, its two-line title and the button footer are gone from the markup and
   their rules were deleted with them rather than left to mislead. `.hsm-x` stays
   — it is the same close button, restyled onto the picture further down. */
.hsm-x{ flex:0 0 auto; width:26px; height:26px; border-radius:6px; cursor:pointer;
  border:1px solid var(--border); background:#fff; color:var(--ink3); font-size:12px; line-height:1; }
.hsm-x:hover{ color:#b91c1c; border-color:#f0c9c9; }
.hsm-body{ flex:1 1 auto; min-height:0; overflow-y:auto; padding:14px; }
.hsm-body::-webkit-scrollbar{ width:10px; }
.hsm-body::-webkit-scrollbar-thumb{ background:#dfe5e1; border:3px solid #fff; border-radius:99px; }

/* The four numbers, read left to right: what it costs going forward, what it
   has cost so far, what it cost when a month completed, and the verdict. */
.hsm-nums{ display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:8px; }
.hsm-num{ border:1px solid var(--border); border-left:3px solid var(--_ac,#0f766e);
  border-radius:6px; padding:9px 10px; background:#fff; min-width:0; }
.hsm-num b{ display:block; font-size:16px; font-weight:800; color:var(--ink);
  font-variant-numeric:tabular-nums; letter-spacing:-.3px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.hsm-num span{ display:block; font-size:10px; color:var(--ink3); margin-top:3px; line-height:1.3; }
@media (max-width:520px){ .hsm-nums{ grid-template-columns:repeat(2,minmax(0,1fr)); } }

.hsm-dupe{ margin-top:12px; border:1px solid #f0d8ae; background:#fffaf2; border-radius:8px;
  padding:10px 11px; font-size:12px; line-height:1.55; color:#8a4d0a; }
.hsm-dupe b{ color:#7c3f06; }
.hsm-verdict{ margin-top:12px; border:1px solid color-mix(in srgb,var(--_ac,#64748b) 26%,#fff);
  background:color-mix(in srgb,var(--_ac,#64748b) 6%,#fff); border-radius:8px; padding:11px 12px; }
.hsm-verdict b{ display:block; font-size:13px; font-weight:800; color:var(--_ac,#334155); }
.hsm-verdict p{ margin:5px 0 0; font-size:12px; line-height:1.55; color:var(--ink2); }
.hsm-verdict ul{ margin:7px 0 0; padding-left:17px; font-size:12px; line-height:1.6; color:var(--ink2); }
.hsm-verdict code{ font-family:ui-monospace,Consolas,monospace; font-size:11px;
  background:#fff; border:1px solid var(--border); padding:0 4px; border-radius:4px; }

.hsm-sec{ margin-top:16px; }
.hsm-sec h4{ margin:0 0 8px; font-size:11px; font-weight:800; text-transform:uppercase;
  letter-spacing:.4px; color:var(--ink2); }
.hsm-none{ font-size:12px; color:var(--ink3); line-height:1.5;
  border:1px dashed var(--border); border-radius:6px; padding:9px 10px; }
.hsm-note{ margin-top:7px; font-size:11px; color:var(--ink3); }
.hsm-note code, .hsm-none code{ font-family:ui-monospace,Consolas,monospace; font-size:11px;
  background:var(--border-s); padding:1px 4px; border-radius:4px; }

.hsm-addr{ display:flex; align-items:center; justify-content:space-between; gap:10px;
  border:1px solid var(--border); border-radius:6px; padding:7px 10px; background:#fff; }
.hsm-addr + .hsm-addr{ margin-top:5px; }
.hsm-addr.is-default{ background:#f8faf9; }
.hsm-addr.is-unseen, .hsm-addr.is-extra{ border-color:#f0d8ae; background:#fffaf2; }
.hsm-addr a{ font:600 12px ui-monospace,Consolas,monospace; color:var(--c-blue);
  min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.hsm-addr span{ flex:0 0 auto; }
.hsm-addr i{ font-style:normal; font-size:10.5px; font-weight:700; color:var(--ink3); }
.hsm-addr i.ok{ color:#166534; }
.hsm-addr i.warn{ color:#b4471f; }

.hsm-kvs{ display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:1px;
  background:var(--border-s); border:1px solid var(--border); border-radius:6px; overflow:hidden; }
@media (max-width:520px){ .hsm-kvs{ grid-template-columns:minmax(0,1fr); } }
.hsm-kv{ background:#fff; padding:7px 10px; min-width:0; }
/* ⚠️ `> span`, NOT `span`. A kv VALUE may contain a span of its own — the
   deploy-state chip is one — and the unrestricted selector uppercased it, so
   "shipped 28d ago" rendered as SHIPPED 28D AGO in a cell whose neighbour said
   "VisionOne". The label is always the direct child; nothing else is. */
.hsm-kv > span{ display:block; font-size:10px; font-weight:700; text-transform:uppercase;
  letter-spacing:.3px; color:var(--ink3); }
.hsm-kv b{ display:block; font-size:12px; font-weight:700; color:var(--ink); margin-top:2px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.hsm-kv b i{ font-style:normal; font-weight:600; color:var(--ink4); }
.hsm-kv b i.warn{ color:#b4471f; }
.hsm-kv a{ color:var(--c-blue); font-family:ui-monospace,Consolas,monospace; font-size:11.5px; }
.hsm-idle{ margin-top:8px; border:1px solid #f2cfc9; background:#fff6f5; border-radius:6px;
  padding:9px 10px; font-size:12px; line-height:1.55; color:#9c2f18; }
.hsm-chips{ display:flex; flex-wrap:wrap; align-items:center; gap:5px; margin-top:8px; }
.hsm-chips em{ font-style:normal; font-size:11px; color:var(--ink3); margin-right:3px; }
.hsm-src{ margin-top:16px; padding-top:10px; border-top:1px solid var(--border-s);
  font-size:10.5px; color:var(--ink4); line-height:1.5; }

/* ── Admin gate ── */
.repos-gate{ display:flex; flex-direction:column; align-items:center; justify-content:center; gap:14px; padding:90px 24px; text-align:center; }
.repos-gate h2{ font-size:18px; font-weight:800; color:var(--ink); }
.repos-gate p{ font-size:13px; color:var(--ink3); max-width:360px; }
.repos-gate a{ margin-top:6px; background:var(--c-blue); color:#fff; font-weight:700; font-size:13px; padding:9px 18px; border-radius:10px; text-decoration:none; }

/* ── Repo detail modal ── */
.rm-backdrop{ position:fixed; inset:0; z-index:9000; background:rgba(15,23,42,.5); backdrop-filter:blur(3px);
  display:flex; align-items:center; justify-content:center; padding:24px 16px; overflow-y:auto;
  opacity:0; transition:opacity .18s; visibility:visible;
  /* Self-contained design tokens — the modal is appended to <body>, OUTSIDE
     .repos-page, so it must NOT depend on that scope's --surf/--border/etc. */
  --f:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
  --ink:#161616; --ink2:#525252; --ink3:#8d8d8d; --ink4:#c6c6c6;
  --surf:#ffffff; --surf-2:#f8fafc; --border:#e0e0e0; --border-s:#f4f4f4;
  --c-blue:#2f6fb0; }
.rm-backdrop.is-open{ opacity:1; }
/* ⚠️ THE FONT BELONGS ON THE BACKDROP, NOT ON `.rm` — that is why the person
   popup was rendering in a serif. The backdrop DEFINES `--f` (it is appended to
   <body>, outside .repos-page, so it cannot borrow that scope's tokens) but only
   `.rm` ever APPLIED it. `.rm-sheet` is a SIBLING of `.rm` inside the backdrop,
   not a child, so every dialog opened over the popup — "What they were sent",
   the product picker, the connection editor — inherited the host page's body
   font instead. Tyler: *"why is your font just so weird on a lot of these?"*
   Set here, everything inside inherits and no future sheet can miss it. */
.rm-backdrop{ font-family:var(--f); }
.rm{ width:100%; max-width:720px; background:var(--surf); border-radius:18px; overflow:hidden;
  box-shadow:0 24px 70px rgba(15,23,42,.34); transform:translateY(10px) scale(.98); transition:transform .2s;
  font-family:var(--f); color:var(--ink); }
.rm-backdrop.is-open .rm{ transform:none; }
.rm-hero{ position:relative; height:132px; display:flex; align-items:center; gap:16px; padding:0 22px; color:#fff; overflow:hidden; }
.rm-hero .rr-thumb-tex{ opacity:.5; }
.rm-mono{ position:relative; z-index:1; width:62px; height:62px; border-radius:16px; background:rgba(255,255,255,.18);
  border:1px solid rgba(255,255,255,.3); display:grid; place-items:center; font-size:26px; font-weight:800;
  text-shadow:0 2px 6px rgba(0,0,0,.28); flex:0 0 auto; }
.rm-hero-txt{ position:relative; z-index:1; min-width:0; }
.rm-hero-txt h2{ font-size:22px; font-weight:800; letter-spacing:-.3px; text-shadow:0 2px 6px rgba(0,0,0,.25); }
.rm-hero-txt .slug{ font-size:12px; opacity:.92; font-family:ui-monospace,Consolas,monospace; margin-top:2px; }
.rm-close{ position:absolute; top:12px; right:12px; z-index:3; width:32px; height:32px; border-radius:9px;
  background:rgba(255,255,255,.2); border:1px solid rgba(255,255,255,.3); color:#fff; font-size:18px; cursor:pointer;
  display:grid; place-items:center; }
.rm-close:hover{ background:rgba(255,255,255,.32); }
.rm-body{ padding:18px 22px 22px; display:flex; flex-direction:column; gap:18px; }
.rm-actions{ display:flex; gap:10px; flex-wrap:wrap; }
.rm-btn{ display:inline-flex; align-items:center; gap:7px; font-size:13px; font-weight:700; padding:9px 15px; border-radius:10px;
  border:1px solid var(--border); background:#fff; color:var(--ink); cursor:pointer; text-decoration:none; transition:all .14s; }
.rm-btn:hover{ border-color:var(--c-blue); color:var(--c-blue); transform:translateY(-1px); }
.rm-btn.primary{ background:#161616; color:#fff; border-color:#161616; }
.rm-btn.primary:hover{ background:#000; color:#fff; }
.rm-btn.live{ background:var(--c-blue); color:#fff; border-color:var(--c-blue); }
.rm-btn.live:hover{ filter:brightness(1.06); color:#fff; }
.rm-btn svg{ width:15px; height:15px; }
/* ── "What is this?" — the classification toggle that drives the scorecards.
      Deliberately the first thing in the Details pane: it is the one field on
      this screen that changes what the library counts. ── */
.rm-class{ border:1px solid var(--border-s); border-radius:12px; padding:12px 13px 13px; margin-bottom:12px;
  background:linear-gradient(180deg,#fbfdfb,var(--surf)); }
.rm-class-hd b{ display:block; font-size:12.5px; font-weight:800; color:var(--ink); }
.rm-class-hd span{ display:block; font-size:11px; color:var(--ink3); margin-top:2px; line-height:1.45; }
.rm-class-opts{ display:grid; grid-template-columns:repeat(auto-fit,minmax(140px,1fr)); gap:7px; margin-top:10px; }
.rm-class-opt{ text-align:left; border:1px solid var(--border); background:var(--surf); border-radius:10px;
  padding:8px 10px; cursor:pointer; font:inherit; transition:border-color .15s, box-shadow .15s, background .15s; }
.rm-class-opt b{ display:block; font-size:12px; font-weight:800; color:var(--ink2); }
.rm-class-opt span{ display:block; font-size:10.5px; color:var(--ink3); margin-top:2px; line-height:1.35; }
.rm-class-opt:hover{ border-color:color-mix(in srgb,var(--_ac,#649954) 45%,var(--border)); }
.rm-class-opt.is-on{ border-color:var(--_ac,#649954); background:color-mix(in srgb,var(--_ac,#649954) 7%,var(--surf));
  box-shadow:0 0 0 2.5px color-mix(in srgb,var(--_ac,#649954) 14%,transparent); }
.rm-class-opt.is-on b{ color:var(--_ac,#649954); }
.rm-class-msg{ display:none; font-size:11px; font-weight:700; color:#c2472f; margin-top:8px; }
.rm-class-msg.is-on{ display:block; }
.rm-meta{ display:grid; grid-template-columns:repeat(auto-fit,minmax(110px,1fr)); gap:1px; background:var(--border-s);
  border:1px solid var(--border-s); border-radius:12px; overflow:hidden; }
.rm-metacell{ background:var(--surf); padding:11px 13px; }
.rm-metacell b{ display:block; font-size:15px; font-weight:800; color:var(--ink); font-variant-numeric:tabular-nums; }
.rm-metacell span{ font-size:9.5px; font-weight:700; text-transform:uppercase; letter-spacing:.4px; color:var(--ink3); margin-top:4px; display:block; }
.rm-tags{ display:flex; flex-wrap:wrap; gap:6px; }
.rm-sec h3{ font-size:11px; font-weight:800; text-transform:uppercase; letter-spacing:.5px; color:var(--ink2); margin-bottom:9px;
  display:flex; align-items:center; gap:8px; }
.rm-sec h3 .n{ background:var(--border-s); color:var(--ink3); font-size:10px; padding:1px 7px; border-radius:8px; }
.rm-list{ display:flex; flex-direction:column; border:1px solid var(--border-s); border-radius:12px; overflow:hidden; }
.rm-row{ display:flex; align-items:center; gap:11px; padding:10px 13px; border-top:1px solid var(--border-s); text-decoration:none; color:inherit; }
.rm-row:first-child{ border-top:0; }
.rm-row:hover{ background:#f8fafc; }
.rm-row .cdot{ width:9px; height:9px; border-radius:50%; flex:0 0 auto; }
.rm-row .txt{ flex:1; min-width:0; }
.rm-row .txt .t{ font-size:12.5px; font-weight:600; color:var(--ink); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.rm-row .txt .s{ font-size:10.5px; color:var(--ink3); margin-top:2px; }
.rm-row .when{ font-size:10.5px; color:var(--ink3); white-space:nowrap; font-variant-numeric:tabular-nums; }
.rm-row .sha{ font-size:10.5px; color:var(--ink3); font-family:ui-monospace,Consolas,monospace; }
.rm-empty{ font-size:12px; color:var(--ink3); padding:14px 15px; border:1px dashed var(--border); border-radius:10px; }
.rm-note{ font-size:11px; color:var(--ink4); text-align:center; padding-top:4px; }

/* ── tabbed modal (v2) ── */
/* flex column + capped height so the modal always fits & centers; body scrolls */
.rm{ max-width:760px; max-height:calc(100vh - 48px); display:flex; flex-direction:column; }
.rm-hero{ height:120px; flex:0 0 auto; }
.rm-actions, .rm-tabs{ flex:0 0 auto; }
.rm-hero-logo{ position:absolute; right:-8px; top:50%; transform:translateY(-50%); height:150px; width:auto;
  opacity:.14; z-index:0; filter:drop-shadow(0 2px 6px rgba(0,0,0,.2)); pointer-events:none; object-fit:contain; }
.rm-cochip{ display:inline-flex; align-items:center; gap:6px; cursor:pointer; }
/* ⚠️ `.rm-cochip img{width:15px}` LIVED HERE and was the reason "the logo is a
   dot" kept coming back to this file. It is dead — the chip's only image is
   inside `.rm-cochip-plate`, whose own rule is more specific and wins — but it
   read as the live size, so anyone fixing the size fixed the wrong rule. The
   plate (and the mark) is sized in exactly one place; search "THE MARK HAS TO
   BE READABLE". */
.rm-cochip:hover{ background:rgba(255,255,255,.34); }
.rm-metacell.is-filter{ cursor:pointer; }
.rm-metacell.is-filter:hover{ background:#f2f7fd; }
.rm-metacell.is-filter b{ color:var(--c-blue); }
.rm-hero-stats{ position:relative; z-index:1; display:flex; flex-wrap:wrap; gap:6px; margin-top:8px; }
.rm-hero-stats span{ display:inline-flex; align-items:center; gap:5px; font-size:11px; font-weight:700;
  padding:3px 9px; border-radius:6px; background:rgba(255,255,255,.18); border:1px solid rgba(255,255,255,.28);
  text-transform:capitalize; letter-spacing:.2px; }
.rm-hero-stats .ldot{ width:8px; height:8px; border-radius:50%; display:inline-block; box-shadow:0 0 0 1px rgba(255,255,255,.5); }
.rm-actions{ padding:14px 22px 0; }
.rm-tabs{ display:flex; gap:2px; padding:14px 22px 0; margin-top:2px; border-bottom:1px solid var(--border-s); }
.rm-tab{ position:relative; border:0; background:none; cursor:pointer; font-family:var(--f); font-size:13px; font-weight:700;
  color:var(--ink3); padding:9px 13px 12px; display:inline-flex; align-items:center; gap:7px; border-radius:8px 8px 0 0; transition:color .14s; }
.rm-tab:hover{ color:var(--ink); }
.rm-tab.is-on{ color:var(--ink); }
.rm-tab.is-on::after{ content:""; position:absolute; left:8px; right:8px; bottom:-1px; height:2.5px; border-radius:2px; background:var(--c-blue,#2f6fb0); }
.rm-tab .tn{ font-size:10.5px; font-weight:800; background:var(--border-s); color:var(--ink3); padding:1px 7px; border-radius:8px; font-variant-numeric:tabular-nums; }
.rm-tab.is-on .tn{ background:#e8f0fb; color:#2563eb; }
.rm-body{ flex:1 1 auto; min-height:120px; overflow-y:auto; }
.rm-pane{ display:none; flex-direction:column; gap:18px; }
.rm-pane.is-on{ display:flex; }
.rm-desc{ font-size:13px; color:var(--ink2); line-height:1.55; }
.rm-sec{ display:flex; flex-direction:column; }

/* languages */
.rm-langbar{ display:flex; height:9px; border-radius:6px; overflow:hidden; background:var(--border-s); }
.rm-langbar span{ height:100%; }
.rm-langlegend{ display:flex; flex-wrap:wrap; gap:12px; margin-top:9px; }
.rm-langk{ display:inline-flex; align-items:center; gap:6px; font-size:11px; color:var(--ink2); font-weight:600; }
.rm-langk i{ width:9px; height:9px; border-radius:2px; }
.rm-langk b{ color:var(--ink3); font-weight:700; }

/* avatars + rows */
.rm-av{ width:24px; height:24px; border-radius:50%; object-fit:cover; background:var(--border-s); flex:0 0 auto; display:block; }
.rm-av--ph{ display:grid; place-items:center; font-size:11px; font-weight:800; color:#fff; background:#94a3b8; }
.rm-actor{ flex:0 0 auto; display:flex; }
.rm-row--run .rm-rmeta, .rm-rmeta{ display:flex; align-items:center; gap:8px; flex:0 0 auto; }
.rm-rmeta .dur{ font-size:10px; font-weight:700; color:var(--ink3); background:var(--border-s); padding:2px 7px; border-radius:7px; font-variant-numeric:tabular-nums; }
.rm-row--commit .rm-av{ width:22px; height:22px; }

/* contributors */
.rm-contribs{ display:grid; grid-template-columns:repeat(auto-fill,minmax(120px,1fr)); gap:8px; }
.rm-contrib{ display:flex; align-items:center; gap:9px; padding:8px 10px; border:1px solid var(--border-s); border-radius:11px;
  text-decoration:none; color:inherit; transition:border-color .14s,transform .14s; min-width:0; }
.rm-contrib:hover{ border-color:var(--c-blue); transform:translateY(-1px); }
.rm-contrib .rm-av{ width:28px; height:28px; }
.rm-contrib-n{ flex:1; min-width:0; font-size:12px; font-weight:700; color:var(--ink); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.rm-contrib-c{ font-size:11px; font-weight:800; color:var(--ink3); font-variant-numeric:tabular-nums; }

/* branches + pills */
.rm-branch{ display:inline-flex; align-items:center; gap:5px; font-size:11.5px; font-weight:700; color:var(--ink2);
  font-family:ui-monospace,Consolas,monospace; padding:4px 10px; border-radius:7px; background:var(--surf-2,#f8fafc); border:1px solid var(--border-s);
  text-decoration:none; transition:border-color .14s,transform .14s; }
.rm-branch:hover{ border-color:var(--c-blue); transform:translateY(-1px); }
.rm-branch.is-def{ background:#ecfdf5; color:#047857; border-color:#a7f3d0; }
.rm-branch.is-def:hover{ border-color:#16a34a; }
.rm-branch.is-def .dot{ width:7px; height:7px; border-radius:50%; background:#16a34a; }
.rm-branch svg{ opacity:.7; }
.rm-pill{ font-size:9px; font-weight:800; text-transform:uppercase; letter-spacing:.4px; padding:1px 6px; border-radius:6px; background:#fef3c7; color:#92400e; vertical-align:middle; }

/* interactive meta cells + filterable chips */
a.rm-metacell{ text-decoration:none; color:inherit; position:relative; transition:background .14s; }
a.rm-metacell.is-link{ cursor:pointer; }
a.rm-metacell.is-link:hover{ background:#f2f7fd; }
a.rm-metacell.is-link::after{ content:"↗"; position:absolute; top:9px; right:11px; font-size:10px; color:var(--ink4); opacity:0; transition:opacity .14s; }
a.rm-metacell.is-link:hover::after{ opacity:1; }
.rm-clickable{ cursor:pointer; }
.rm-clickable:hover{ filter:brightness(.94); text-decoration:underline; }

@media (max-width:560px){
  .rm-tabs{ padding-left:14px; padding-right:14px; }
  .rm-body{ padding-left:16px; padding-right:16px; max-height:64vh; }
  .rm-actions{ padding-left:16px; padding-right:16px; }
  .rm-hero{ padding-left:16px; padding-right:16px; }
}

/* ── search-driven filter bar (replaced the wall of type bubbles) ── */
.repos-filterbar{ display:flex; gap:7px; flex-wrap:wrap; align-items:center; margin:11px 4px 2px; }
.repos-fpill{ display:inline-flex; align-items:center; gap:6px; border:1px solid var(--border); background:#fff;
  color:var(--ink2); font-family:inherit; font-size:11.5px; font-weight:600; padding:5px 11px; border-radius:8px;
  cursor:pointer; transition:border-color .14s, color .14s, background .14s; }
.repos-fpill b{ font-weight:800; color:var(--ink); }
.repos-fpill i{ font-style:normal; font-size:11px; opacity:.65; }
.repos-fpill:hover{ border-color:var(--c-blue); color:var(--c-blue); }
.repos-fpill:hover b{ color:var(--c-blue); }
.repos-fpill.is-on{ background:var(--c-blue); border-color:var(--c-blue); color:#fff; }
.repos-fpill.is-on b{ color:#fff; }
.repos-fpill.is-ghost{ border-style:dashed; color:var(--ink3); }

/* ── versioning on the card foot ── */
.rp-card-ref, .rp-card-vn{ font-size:9.5px; font-weight:700; padding:1px 6px; border-radius:6px;
  background:var(--border-s,#f4f4f4); color:var(--ink3); white-space:nowrap; }
.rp-card-ref{ font-family:ui-monospace,Consolas,monospace; }
.rp-card-vn{ background:#e8f0fb; color:#2563eb; }

/* Title + sub-line are spans, so they ran together on one line in every list
   pane (Versions, Runs, Commits). Stack them. */
.rm-row .txt .t, .rm-row .txt .s{ display:block; }

/* ── Versions pane rows ── */
.rm-row--ver{ cursor:default; }
.rm-row--ver:hover{ background:transparent; }
.rm-vlinks{ display:flex; gap:10px; flex:0 0 auto; }
.rm-vlinks a{ font-size:11px; font-weight:700; color:var(--c-blue); text-decoration:none; white-space:nowrap; }
.rm-vlinks a:hover{ text-decoration:underline; }
.rm-pill--cur{ background:#dcfce7; color:#166534; }

/* ── WHERE A VERSION ROW CAME FROM ──────────────────────────────────
   Half these rows are now derived (a release, a shipped build, a change nothing
   has deployed yet) and half are still hand-declared. A list that mixes the two
   without saying which is which is worse than the frozen list it replaced, so
   every row wears its provenance — quiet by default, and the ones that mean
   "somebody should look" carry colour. */
.rm-pill--src{ margin-left:6px; background:var(--border-s,#f4f4f4); color:var(--ink3); font-weight:700; }
.rm-pill--src.is-build{ background:#eef6ff; color:#2563eb; }
.rm-pill--src.is-release, .rm-pill--src.is-tag{ background:#f3e8ff; color:#6d28d9; }
.rm-pill--src.is-pending{ background:#fef3c7; color:#92400e; }
.rm-pill--src.is-manual, .rm-pill--src.is-change{ background:#f4f4f4; color:#6b7280; }

/* The state line above the list: live or snapshot, who actually ships this, and
   what is waiting to go out. Its own band, so it reads as the pane's footing
   rather than as the newest version. */
.rm-vstate{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin:0 0 12px;
  padding:9px 12px; border:1px solid var(--border); border-radius:10px; background:#fbfcfe; }
.rm-vstate-w{ display:inline-flex; align-items:center; gap:7px; font-size:11.5px; font-weight:800; color:var(--ink2); white-space:nowrap; }
.rm-vstate-b{ flex:1 1 220px; font-size:11.5px; color:var(--ink3); line-height:1.5; }
.rm-vstate-b b{ color:#92400e; }
.rm-vstate-b a{ color:var(--c-blue); font-weight:700; text-decoration:none; }
.rm-vstate-b a:hover{ text-decoration:underline; }
.rm-vstate-b .sha{ font-family:ui-monospace,Consolas,monospace; font-size:10.5px; }
.rm-vstate .rm-btn{ margin-left:auto; }
.rm-vstate.is-live{ background:#f4fbf6; border-color:#cfe9d8; }
.rm-vstate.is-live .rm-vstate-w{ color:#166534; }
.rm-vstate.is-error{ background:#fff8f6; border-color:#f3d3ca; }
.rm-vstate.is-error .rm-vstate-w{ color:#b3341c; }
/* A live read pulses; a loading one spins. Defined HERE, not borrowed from
   standards.css: two panes sharing a private class is how a spinner disappears
   the day the other file is refactored. */
.rm-vpulse, .rm-vspin{ flex:0 0 auto; }
.rm-vpulse{ width:8px; height:8px; border-radius:50%; background:#16a34a; animation:rmVPulse 2.4s ease-in-out infinite; }
.rm-vspin{ width:11px; height:11px; border:2px solid #cbd5e1; border-top-color:var(--c-blue); border-radius:50%;
  animation:rmVSpin .7s linear infinite; }
@keyframes rmVPulse{ 0%,100%{ box-shadow:0 0 0 0 rgba(22,163,74,.5); } 50%{ box-shadow:0 0 0 4px rgba(22,163,74,0); } }
@keyframes rmVSpin{ to{ transform:rotate(360deg); } }
@media (prefers-reduced-motion:reduce){ .rm-vpulse,.rm-vspin{ animation:none; } }

/* ══ Repo detail = a centred POPUP ══════════════════════════════════
   It was briefly a right-side drawer; a drawer reads as a side panel you
   glance at, and this is the main event. Centred, capped at 88vh, its own
   scroll area, and on phones it becomes a bottom sheet.
   z-index sits above the right-rail FAB stack (10001) but below the Send
   overlay (2147483600). --c-blue is overwritten per-repo in JS with the
   company accent, so every interactive colour in here is branded. */
.rm-backdrop{ z-index:2147483400; align-items:center; justify-content:center;
  padding:clamp(16px,4vh,44px) 18px; overflow-y:auto;
  background:rgba(9,17,26,.52); backdrop-filter:blur(6px); -webkit-backdrop-filter:blur(6px); }
.rm{ width:min(860px,100%); max-width:none; height:auto; max-height:min(88vh,940px); min-height:0;
  border-radius:22px; border:1px solid rgba(255,255,255,.6);
  transform:translateY(18px) scale(.975); opacity:.4;
  transition:transform .3s cubic-bezier(.16,1,.3,1), opacity .22s ease;
  box-shadow:0 40px 90px -20px rgba(9,17,26,.5), 0 12px 30px -12px rgba(9,17,26,.3); }
.rm-backdrop.is-open .rm{ transform:none; opacity:1; }
/* min-height:0 is what lets the scroll area actually shrink — without it the
   flex item refuses to go below its content height and the popup overflows. */
.rm-body{ overscroll-behavior:contain; min-height:0; scrollbar-width:thin; }
.rm-body::-webkit-scrollbar{ width:10px; }
.rm-body::-webkit-scrollbar-thumb{ background:#dfe5e1; border:3px solid #fff; border-radius:99px; }
.rm-body::-webkit-scrollbar-thumb:hover{ background:#c3ccc6; }

/* phones: bottom sheet — thumb-reachable, full width, slides up */
@media (max-width:700px){
  .rm-backdrop{ align-items:flex-end; padding:0; }
  .rm{ width:100%; max-height:93vh; border-radius:22px 22px 0 0; border-bottom:0;
       transform:translateY(30px); }
}

/* ══ Hero — the branded band. White lettering on the company gradient;
   nothing in here is allowed to fall back to near-black body ink. ══ */
.rm-hero{ height:auto; min-height:118px; padding:20px 24px; gap:18px; align-items:center; }
.rm-hero, .rm-hero *{ color:#fff; }
.rm-hero-txt h2{ font-size:24px; line-height:1.15; font-weight:800; letter-spacing:-.4px;
  color:#fff; text-shadow:0 1px 2px rgba(0,0,0,.28), 0 2px 12px rgba(0,0,0,.18); }
.rm-hero-txt .slug{ display:inline-flex; align-items:center; gap:6px; margin-top:4px; padding:2px 8px 2px 9px;
  border-radius:7px; background:rgba(255,255,255,.16); border:1px solid rgba(255,255,255,.22);
  font-size:11.5px; font-weight:600; letter-spacing:.2px; opacity:1; cursor:pointer;
  transition:background .15s, border-color .15s; }
.rm-hero-txt .slug:hover{ background:rgba(255,255,255,.28); border-color:rgba(255,255,255,.42); }
/* the copy affordance is a pseudo-element on purpose: standards.js reads
   .slug textContent to identify the repo, so nothing may be added as a node */
.rm-hero-txt .slug::after{ content:'⧉'; font-size:10px; opacity:.72; }
.rm-hero-txt .slug.is-copied::after{ content:'copied ✓'; opacity:1; font-weight:700; }
.rm-hero::after{ content:''; position:absolute; inset:auto 0 0 0; height:1px; background:rgba(255,255,255,.22); }

/* ── the app icon tile (was a bare "AS" monogram) ──
   Real branded icon when we have one; a crafted gradient monogram when we
   don't — never a flat grey square. */
.rm-icon{ position:relative; z-index:1; width:68px; height:68px; border-radius:18px; flex:0 0 auto;
  display:grid; place-items:center; overflow:hidden;
  background:rgba(255,255,255,.96); border:1px solid rgba(255,255,255,.75);
  box-shadow:0 8px 22px rgba(9,17,26,.24), inset 0 1px 0 rgba(255,255,255,.9); }
.rm-icon img{ width:100%; height:100%; object-fit:contain; padding:9px; display:block; }
.rm-icon.is-mono{ background:linear-gradient(150deg, rgba(255,255,255,.30), rgba(255,255,255,.12));
  border-color:rgba(255,255,255,.42); box-shadow:0 8px 22px rgba(9,17,26,.22), inset 0 1px 0 rgba(255,255,255,.34); }
.rm-icon-mono{ display:none; font-size:25px; font-weight:800; letter-spacing:.5px; color:#fff;
  text-shadow:0 2px 8px rgba(0,0,0,.3); }
.rm-icon-mono[data-n="3"]{ font-size:20px; letter-spacing:0; }
.rm-icon-mono[data-n="4"]{ font-size:16px; letter-spacing:0; }
.rm-icon.is-mono .rm-icon-mono{ display:block; }
.rm-icon.is-mono img{ display:none; }
/* `.rm-icon.is-logo` is gone with the company-logo fallback it styled — this box
   is the app's own icon or the app's initials, never the company mark a second
   time. See mountIcon. */

/* ── giving a build its logo, by clicking its face ──────────────────────────
   The affordance is quiet until you go near it: the icon is a picture first and
   a control second, and a camera badge parked permanently on the header would
   read as part of the mark. `.rm-iconwrap` exists only to position the badge —
   .rm-icon keeps its own overflow:hidden (the icon is clipped to its rounded
   square) so a badge INSIDE it would be clipped away. */
.rm-iconwrap{ position:relative; flex:0 0 auto; display:grid; }
/* ⚠️ THE TWO IMAGE CONTROLS ARE ONE SHAPE, AND IT IS NOT A CIRCLE. A badge on
   the icon (the app's logo) and a badge in the control corner (the screenshot a
   client is sent) are the same kind of thing, so they are the same object: a
   small squared glass tile carrying the one camera. Tyler: *"I don't like how
   you have all the circular, round stuff… our buttons are round, that's what we
   want for SOME buttons, but not for everything."* A round badge was the last
   circle left in this header. */
.rm-imgbtn, .rm-shotbtn{ position:absolute; z-index:4; width:27px; height:27px;
  display:grid; place-items:center; padding:0; cursor:pointer;
  border-radius:7px; border:1px solid rgba(255,255,255,.42);
  background:rgba(9,17,26,.62); color:#fff;
  -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px);
  opacity:0; transform:scale(.86); transition:opacity .16s, transform .16s, background .16s; }
.rm-imgbtn svg, .rm-shotbtn svg{ width:14px; height:14px; }
.rm-imgbtn:hover, .rm-shotbtn:hover{ background:rgba(9,17,26,.9); }
.rm-imgbtn{ right:-7px; bottom:-7px; }
/* Keyboard users never hover, so focus-visible has to reveal it too — otherwise
   the only way to reach this control is with a mouse.
   And the whole band reveals it, not just the icon: nothing tells you an app's
   face is a control, so a hover that only pays off if you already knew where to
   put the pointer is a control most people never find. Both image controls appear
   together, each on the thing it changes. */
.rm-hero:hover .rm-imgbtn,
.rm-iconwrap:hover .rm-imgbtn, .rm-imgbtn:focus-visible{ opacity:1; transform:none; }

/* The picture of the app: in the hero's own control corner, beside Close, so the
   band's two controls sit together and neither is parked on top of the picture
   it is offering to change. The sentence it used to print is its tooltip. */
.rm-shotbtn{ top:17px; right:56px; }
.rm-hero:hover .rm-shotbtn, .rm-shotbtn:focus-visible{ opacity:1; transform:none; }

/* An upload is a round trip to a blob container — say something is happening,
   or a 2 MB PNG on a slow line reads as a dead click. */
.rm-icon.is-busy, .rm-hero-shot.is-busy{ animation:rmImgBusy 1s ease-in-out infinite; }
@keyframes rmImgBusy{ 50%{ opacity:.45; } }

/* The long way in: the logo row in the version editor. `.rm-vicon` is already a
   flex row further down this file — these only share the space out, so the new
   Upload button cannot be squeezed to nothing by the URL field beside it. */
.rm-vicon .rm-vf{ flex:1 1 auto; min-width:0; }
.rm-vicon [data-viconup]{ flex:0 0 auto; white-space:nowrap; }

/* The watermark logo: mrg.jpg has a white matte, which drew a pale rectangle
   across half the hero. multiply makes white disappear into the gradient and
   leaves only the mark; the mask fades whatever is left toward the title. */
.rm-hero-logo{ mix-blend-mode:multiply; opacity:.42; right:-14px; height:170px;
  -webkit-mask-image:linear-gradient(to left,#000 45%,transparent 100%);
          mask-image:linear-gradient(to left,#000 45%,transparent 100%); }

.rm-close{ width:34px; height:34px; top:14px; right:14px; font-size:15px; line-height:1;
  background:rgba(255,255,255,.18); border-color:rgba(255,255,255,.34);
  transition:background .16s, transform .16s, border-color .16s; }
.rm-close:hover{ background:rgba(255,255,255,.34); transform:rotate(90deg); border-color:rgba(255,255,255,.6); }
.rm-close:focus-visible{ outline:2px solid #fff; outline-offset:2px; }

/* hero chips: glass, and the company one is clickable so it says so */
.rm-hero-stats span, .rm-cochip{ background:rgba(255,255,255,.17); border:1px solid rgba(255,255,255,.3);
  backdrop-filter:blur(3px); transition:background .15s, border-color .15s, transform .15s; }
.rm-cochip:hover{ background:rgba(255,255,255,.36); border-color:rgba(255,255,255,.6); transform:translateY(-1px); }

/* Company = mark + name. The logo sits on a white plate at a legible size —
   the old 15px round crop turned every brand into an unreadable dot.
   ⚠️ THE SIZE IS SET ONCE, in the two-row-header block further down (search
   "THE MARK HAS TO BE READABLE"). It used to be set here at 22px AND there, and
   the two disagreed — whichever you found first told you the wrong number. */
.rm-cochip{ display:inline-flex; align-items:center; gap:7px; padding:3px 10px 3px 4px; border-radius:7px;
  font:inherit; font-size:11px; font-weight:700; color:#fff; cursor:pointer; letter-spacing:.2px; }
.rm-cochip-plate{ display:grid; place-items:center; border-radius:7px; overflow:hidden;
  background:#fff; box-shadow:0 1px 3px rgba(9,17,26,.22); flex:0 0 auto; }
.rm-cochip-plate img{ width:100%; height:100%; object-fit:contain; display:block;
  border-radius:0; }                                   /* never a circle */
.rm-cochip-n{ white-space:nowrap; }
.rm-cochip .rm-go{ width:12px; height:12px; }

/* ── Insights stat tiles — the pane leads with numbers now ── */
.rm-stats{ display:grid; grid-template-columns:repeat(auto-fit,minmax(126px,1fr)); gap:9px; }
.rm-stat{ border:1px solid #e8edea; border-left:3px solid var(--sc,#649954); border-radius:11px;
  padding:10px 12px; background:#fff; min-width:0; }
.rm-stat b{ display:block; font-size:19px; font-weight:800; color:var(--sc,#161616); line-height:1.1;
  font-variant-numeric:tabular-nums; letter-spacing:-.4px; }
.rm-stat span{ display:block; margin-top:3px; font-size:9.5px; font-weight:800; letter-spacing:.4px;
  text-transform:uppercase; color:var(--ink3); }
.rm-stat i{ display:block; margin-top:5px; font-style:normal; font-size:10.5px; color:var(--ink3);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

/* one-line "what am I looking at" above a dense list */
.rm-lede{ font-size:12px; line-height:1.55; color:var(--ink3); margin:-4px 0 2px; }

/* GitHub logins run long — 120px clipped every one of them to "TylerBo…" */
.rm-contribs{ grid-template-columns:repeat(auto-fill,minmax(168px,1fr)); }

/* icon override, inside the editor — live preview of whatever you paste */
.rm-vicon{ display:flex; align-items:flex-end; gap:11px; padding:12px 14px; background:#fff;
  border-top:1px solid #eef2f0; }
.rm-vicon-prev{ display:grid; place-items:center; width:46px; height:46px; border-radius:12px; flex:0 0 auto;
  background:#f6f8f7; border:1px solid #e3e9e5; overflow:hidden;
  font-size:9px; font-weight:800; text-transform:uppercase; letter-spacing:.4px; color:var(--ink4); }
.rm-vicon-prev img{ width:100%; height:100%; object-fit:contain; padding:5px; }
.rm-vicon-prev.is-none{ border-style:dashed; }

/* ── action bar: ONE deed, TWO doors ──────────────────────────────────────
   Three buttons: Send (the deed), Open live app and Open in GitHub (places to
   go). Only the deed is filled. The other two used to be filled as well — a
   brand-gradient "Open live app" and a solid-black "Open in GitHub" — which
   put three saturated blocks in a row and left nothing for the eye to land on
   first; add the "Actions ↗" and "Commits ↗" links that used to sit beside
   them and it was six. Outlines here, and the one that matters keeps the
   colour. Hover is where each one declares itself: live tints toward the
   brand, GitHub toward GitHub's own near-black. */
.rm-actions{ padding:16px 24px 2px; gap:8px; }
.rm-btn{ transition:background .15s, border-color .15s, color .15s, transform .15s, box-shadow .15s; }
.rm-btn:hover{ transform:translateY(-1.5px); box-shadow:0 6px 16px -6px color-mix(in srgb,var(--c-blue) 55%,transparent); }
.rm-btn:focus-visible{ outline:2px solid var(--c-blue); outline-offset:2px; }
.rm-btn.primary{ background:#24292f; border-color:#24292f; }        /* GitHub's own black */
.rm-btn.primary:hover{ background:#111418; }
.rm-btn.live{ background:#fff; color:var(--c-blue);
  border-color:color-mix(in srgb, var(--c-blue) 42%, var(--border-s)); box-shadow:none; }
.rm-btn.live:hover{ background:color-mix(in srgb, var(--c-blue) 8%, #fff); color:var(--c-blue);
  border-color:var(--c-blue); }
.rm-btn.gh{ background:#fff; color:#3a4149; border-color:var(--border); box-shadow:none; }
.rm-btn.gh:hover{ background:#f4f6f5; color:#1b2027; border-color:#c9d2cd;
  box-shadow:0 4px 12px -7px rgba(16,24,20,.5); }
.rm-btn.gh svg{ width:15px; height:15px; }
.rm-btn.sm{ font-size:12px; padding:6px 12px; border-radius:9px; }

/* ── tabs: readable at rest, obvious on hover ── */
.rm-tabs{ padding:14px 24px 0; gap:4px; }
.rm-tab{ color:#5f6b64; }
.rm-tab:hover{ color:var(--c-blue); background:color-mix(in srgb,var(--c-blue) 7%,transparent); }
.rm-tab.is-on{ color:var(--c-blue); }
.rm-tab.is-on::after{ background:var(--c-blue); }
.rm-tab.is-on .tn{ background:color-mix(in srgb,var(--c-blue) 14%,transparent); color:var(--c-blue); }
.rm-tab:focus-visible{ outline:2px solid var(--c-blue); outline-offset:-2px; }
.rm-body{ padding:20px 24px 24px; }

/* ── lettering contrast: the old --ink3 (#8d8d8d) failed on white at 10px ── */
.rm-backdrop{ --ink2:#414d46; --ink3:#6b7770; --ink4:#a6b0aa; }
.rm-metacell span{ color:var(--ink3); }
.rm-metacell b{ letter-spacing:-.2px; }
/* 10 cells — a fixed 5 wide fills exactly two rows. auto-fit left a dead
   half-row of empty cells at popup width. */
.rm-meta{ grid-template-columns:repeat(5,minmax(0,1fr)); }
@media (max-width:760px){ .rm-meta{ grid-template-columns:repeat(3,minmax(0,1fr)); } }
@media (max-width:480px){ .rm-meta{ grid-template-columns:repeat(2,minmax(0,1fr)); } }
.rm-sec h3{ color:#3f4b44; }
.rm-desc{ color:#3c4a43; font-size:13.5px; }

/* ── every clickable thing announces itself ── */
a.rm-metacell.is-link:hover, .rm-metacell.is-filter:hover{
  background:color-mix(in srgb,var(--c-blue) 7%,#fff); }
a.rm-metacell.is-link:hover b, .rm-metacell.is-filter:hover b{ color:var(--c-blue); }
.rm-metacell.is-filter{ font:inherit; text-align:left; border:0; width:100%; cursor:pointer; }
a.rm-metacell.is-link::after{ color:var(--c-blue); font-weight:800; }
.rm-metacell.is-filter::after{ content:"→"; position:absolute; top:9px; right:11px; font-size:11px;
  color:var(--c-blue); font-weight:800; opacity:0; transform:translateX(-3px); transition:opacity .14s, transform .14s; }
.rm-metacell.is-filter{ position:relative; }
.rm-metacell.is-filter:hover::after{ opacity:1; transform:none; }
.rm-metacell:focus-visible, .rm-chipgo:focus-visible{ outline:2px solid var(--c-blue); outline-offset:-2px; }
/* ⚠️ NEVER `font:inherit` here. The shorthand resets font-size too, and since
   this rule comes AFTER .rr-tag it beat .rr-tag's 11px — so the type chip
   rendered at the modal's inherited body size while every chip beside it stayed
   small. That is what made one chip in "Tags & versions" twice the size of its
   neighbours. Inherit the family only. */
.rm-chipgo{ border:0; font-family:inherit; font-size:11px; font-weight:600; line-height:1.2;
  cursor:pointer; gap:3px; transition:transform .14s, box-shadow .14s, filter .14s; }
.rm-chipgo:hover{ transform:translateY(-1px); filter:saturate(1.25); box-shadow:0 3px 10px -4px currentColor; }
.rm-go{ width:11px; height:11px; opacity:0; margin-left:-3px; transition:opacity .14s, margin .14s; }
.rm-chipgo:hover .rm-go{ opacity:.85; margin-left:0; }
.rm-tag--warn{ background:#fef2f2; color:#b91c1c; border:1px solid #fecaca; }
.rm-tag--mute{ background:#f6f8f7; color:#5c6a63; border:1px solid #e8edea; }
.rm-tag--topic{ background:#eef6ff; color:#2563eb; border:1px solid #dbeafe; text-decoration:none; }
.rm-tag--topic:hover{ background:#dbeafe; }

/* ══ version-history editor — the one hand-owned thing in here ══ */
.rm-verbar{ display:flex; align-items:center; justify-content:space-between; gap:12px; margin:-2px 0 2px; }
.rm-verbar b{ display:block; font-size:11px; font-weight:800; letter-spacing:.5px; text-transform:uppercase; color:#3f4b44; }
.rm-verbar span{ font-size:11.5px; color:var(--ink3); }
.rm-ved{ border:1px solid color-mix(in srgb,var(--c-blue) 30%,#e6ebe8); border-radius:14px; overflow:hidden;
  background:color-mix(in srgb,var(--c-blue) 3%,#fff); margin-bottom:16px; }
.rm-ved-hd{ display:flex; align-items:center; justify-content:space-between; gap:10px; padding:11px 14px;
  background:color-mix(in srgb,var(--c-blue) 9%,#fff); border-bottom:1px solid color-mix(in srgb,var(--c-blue) 18%,#eef2f0); }
.rm-ved-hd b{ font-size:12.5px; font-weight:800; color:#26332c; }
.rm-ved-hda{ display:flex; gap:7px; }
.rm-vrow{ display:flex; gap:10px; align-items:flex-start; padding:12px 14px; border-bottom:1px solid #eef2f0; background:#fff; }
.rm-vrow:last-child{ border-bottom:0; }
.rm-vgrid{ flex:1; min-width:0; display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:9px; }
.rm-vf{ display:flex; flex-direction:column; gap:3px; min-width:0; }
.rm-vf--wide{ grid-column:span 2; }
.rm-vf--full{ grid-column:1/-1; }
.rm-vf span{ font-size:9.5px; font-weight:800; letter-spacing:.4px; text-transform:uppercase; color:var(--ink3); }
.rm-vf input, .rm-vf select{ width:100%; box-sizing:border-box; border:1px solid #dde4e0; border-radius:8px;
  padding:7px 9px; font:inherit; font-size:12.5px; color:var(--ink); background:#fff; }
.rm-vf input:focus, .rm-vf select:focus{ outline:none; border-color:var(--c-blue);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--c-blue) 13%,transparent); }
.rm-vops{ display:flex; flex-direction:column; gap:4px; flex:0 0 auto; padding-top:14px; }
.rm-iconbtn{ width:26px; height:24px; border:1px solid #dde4e0; background:#fff; border-radius:7px; cursor:pointer;
  font-size:11px; color:var(--ink2); line-height:1; transition:border-color .14s, color .14s, background .14s; }
.rm-iconbtn:hover:not(:disabled){ border-color:var(--c-blue); color:var(--c-blue); }
.rm-iconbtn:disabled{ opacity:.35; cursor:default; }
.rm-iconbtn.is-danger:hover{ border-color:#dc2626; color:#dc2626; background:#fef2f2; }
.rm-ved-ft{ display:flex; align-items:center; justify-content:space-between; gap:12px; padding:11px 14px;
  border-top:1px solid color-mix(in srgb,var(--c-blue) 18%,#eef2f0); background:color-mix(in srgb,var(--c-blue) 5%,#fff); }
.rm-ved-ftb{ display:flex; gap:7px; }
.rm-vmsg{ font-size:11.5px; color:var(--ink3); }
.rm-vmsg.is-ok{ color:#15803d; font-weight:700; }
.rm-vmsg.is-warn{ color:#a16207; font-weight:700; }
@media (max-width:640px){ .rm-vgrid{ grid-template-columns:repeat(2,minmax(0,1fr)); } .rm-vf--wide{ grid-column:span 2; } }

/* save failed → here is the JSON to commit, don't lose the work */
.rm-fallback{ position:fixed; inset:0; z-index:2147483550; display:flex; align-items:center; justify-content:center;
  padding:24px; background:rgba(9,17,26,.55); backdrop-filter:blur(4px); }
.rm-fb-card{ width:min(560px,100%); background:#fff; border-radius:16px; padding:20px 22px;
  box-shadow:0 30px 70px rgba(9,17,26,.45); font-family:'Inter',system-ui,sans-serif; }
.rm-fb-card h3{ font-size:15px; font-weight:800; color:#1a2620; margin-bottom:7px; }
.rm-fb-card p{ font-size:12.5px; line-height:1.6; color:#4a5952; margin-bottom:11px; }
.rm-fb-card code{ background:#f1f5f3; padding:1px 5px; border-radius:5px; font-size:11.5px; }
.rm-fb-card textarea{ width:100%; box-sizing:border-box; height:170px; border:1px solid #dde4e0; border-radius:10px;
  padding:10px 12px; font-family:ui-monospace,Consolas,monospace; font-size:11.5px; color:#33413a; resize:vertical; }
.rm-fb-ft{ display:flex; justify-content:flex-end; gap:8px; margin-top:12px; }

/* ── toast: nothing navigates silently any more ── */
.rm-toast{ position:fixed; left:50%; bottom:26px; transform:translate(-50%,14px); z-index:2147483500;
  display:flex; align-items:center; gap:14px; padding:11px 14px 11px 18px; border-radius:13px;
  background:#12211a; color:#fff; font:600 13px/1.3 'Inter',system-ui,sans-serif;
  box-shadow:0 18px 40px -12px rgba(9,17,26,.6); opacity:0; transition:opacity .2s, transform .2s; }
.rm-toast.is-in{ opacity:1; transform:translate(-50%,0); }
.rm-toast button{ border:1px solid rgba(255,255,255,.28); background:rgba(255,255,255,.12); color:#fff;
  font:800 12px 'Inter',system-ui,sans-serif; padding:5px 12px; border-radius:8px; cursor:pointer; }
.rm-toast button:hover{ background:rgba(255,255,255,.24); }

/* ══════════════════════════════════════════════════════════════════════════
   MOTION — clicking a scorecard should read as the same page changing its
   mind, not as a new page arriving. Every re-paint of the results goes
   through repos.js swapBody(), which sets .is-swapping for one frame: the
   outgoing grid drops out, the incoming cards come in on a short stagger
   driven by --_i (their index, set on each card). Capped at 14 steps so a
   62-card render still finishes in a quarter of a second.
   ══════════════════════════════════════════════════════════════════════════ */
[data-repos-body]{ transition:opacity .16s ease, transform .16s ease; }
[data-repos-body].is-swapping{ opacity:0; transform:translateY(6px); }

@keyframes rpCardIn{ from{ opacity:0; transform:translateY(10px) scale(.985); } to{ opacity:1; transform:none; } }
.rp-card,.co-card{
  animation:rpCardIn .34s cubic-bezier(.22,1,.36,1) both;
  animation-delay:calc(min(var(--_i,0),14) * 22ms);
}
@keyframes rpBandIn{ from{ opacity:0; } to{ opacity:1; } }
.repos-grouphd{ animation:rpBandIn .3s ease both; }

/* Scorecards: the active one lifts and thickens its top rule, so which slice
   you're looking at is legible from across the row. */
.repos-page .ax-card{ transition:transform .26s cubic-bezier(.22,1,.36,1), box-shadow .26s, border-color .2s, opacity .2s; }
.repos-page .ax-card.is-active{ transform:translateY(-3px);
  border-color:color-mix(in srgb,var(--_ac,#64748b) 42%,#e0e0e0);
  box-shadow:0 10px 30px color-mix(in srgb,var(--_ac,#64748b) 20%,transparent), 0 2px 6px rgba(0,0,0,.05); }
.repos-page .ax-card.is-active::before{ height:6px; }
.repos-page .ax-card:active{ transform:translateY(-1px) scale(.985); }
/* a zero is still worth showing (it's an answer) but it shouldn't compete */
.repos-page .ax-card.is-zero:not(.is-active){ opacity:.55; }
.repos-page .ax-card.is-zero:not(.is-active):hover{ opacity:1; }

/* Rail: the active item's colour bar grows in rather than snapping. */
.repos-sidebar .ph-sb-item{ transition:background .18s, color .18s; }
.repos-sidebar .ph-sb-item.is-active::before{ animation:rpRail .26s cubic-bezier(.22,1,.36,1) both; }
@keyframes rpRail{ from{ transform:scaleY(.2); opacity:0; } to{ transform:none; opacity:1; } }

/* The screenshot fades in instead of popping — a 640px image decoding mid-grid
   is otherwise a visible flicker on every card. */
.rr-thumb-appimg{ opacity:0; transition:opacity .3s ease, transform .22s cubic-bezier(.22,1,.36,1); }
.rr-thumb--app.is-ready .rr-thumb-appimg{ opacity:1; }

@media (prefers-reduced-motion:reduce){
  .rp-card,.co-card,.repos-grouphd,.repos-sidebar .ph-sb-item.is-active::before{ animation:none !important; }
  [data-repos-body],[data-repos-body].is-swapping{ transition:none; opacity:1; transform:none; }
  .rr-thumb-appimg{ transition:none; opacity:1; }
  .rp-card:hover,.co-card:hover,.repos-page .ax-card.is-active{ transform:none; }
}
/* ══════════════════════════════════════════════════════════════════════
   v3 — the popup, polished
   ──────────────────────────────────────────────────────────────────────
   Three rules, applied everywhere below:

   1. NO PILLS, NO CIRCLES. Nothing on this screen is a lozenge or a round
      button. Every chip, tag, flag and button is the same squared 7–10px
      family, so a row of them reads as one system instead of a bag of
      shapes. The only round things left are status dots and human faces,
      which are round because of what they ARE.
   2. ONE CHIP SIZE. A chip is 11px/600 with 3px 8px of padding. Full stop.
   3. LABEL ABOVE VALUE. In the facts grid the small grey word says what
      the big dark word is, and reading order is top to bottom.
   ══════════════════════════════════════════════════════════════════════ */

/* ── 1. no pills ── */
.rm-hero-stats span,
.rm-cochip,
.rm-branch,
.repos-fpill,
.repos-crumb button.is-chip,
.repos-fresh,
.rr-thumb-flag,
.rr-thumb-stat,
.rm-sec h3 .n,
.rm-tab .tn,
.rm-rmeta .dur{ border-radius:7px; }
.rm-close{ border-radius:9px; }
/* rotating a square 45° on hover reads as a glitch, not a gesture */
.rm-close:hover{ transform:none; background:rgba(255,255,255,.36); }

/* ── 2. one chip size, one chip shape ── */
.rm-tags .rr-tag,
.rm-tags .rm-chipgo{ font-size:11px; font-weight:600; line-height:1.2; padding:3px 8px;
  border-radius:6px; min-height:22px; box-sizing:border-box; }
.rm-tag--plain{ background:#f6f8f7; color:#5c6a63; border:1px solid #e8edea; }
.rm-tag--topic{ background:#eef6ff; color:#2563eb; border:1px solid #dbeafe; }
.rm-tag--live{ background:#ecfdf5; color:#047857; border:1px solid #a7f3d0; }
/* A demo is the one chip that earns emphasis: it is the reason the Send
   button above it exists. */
.rm-tag--demo{ background:#e0f2fe; color:#0369a1; border:1px solid #bae6fd; font-weight:800; }

/* ── 3. the facts grid ──
   It used to print ten cells whatever the answer was, so a demo read
   "Language —, Size 0 KB, Created —". repos.js now omits what it does not
   know, which means the count varies — so the grid packs instead of
   holding a fixed 5 columns with dead cells at the end. */
.rm-meta{ grid-template-columns:repeat(auto-fit,minmax(132px,1fr)); border-radius:10px; }
@media (max-width:760px){ .rm-meta{ grid-template-columns:repeat(auto-fit,minmax(120px,1fr)); } }
.rm-metacell{ padding:10px 12px 11px; display:flex; flex-direction:column; gap:3px; }
.rm-metacell-l{ font-size:9.5px; font-weight:800; text-transform:uppercase; letter-spacing:.5px;
  color:var(--ink3); }
.rm-metacell b{ font-size:13.5px; font-weight:700; color:#26332c; letter-spacing:-.1px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.rm-metacell.is-filter::after, a.rm-metacell.is-link::after{ top:auto; bottom:10px; }

/* The company: its accent square, then its name in ordinary ink. It used to be
   bold green lettering with no mark at all, which read as a hyperlink that had
   lost its underline. The logo itself lives on the hero chip, where there is
   room for a wordmark to be legible. */
.rm-metaco{ display:inline-flex; align-items:center; gap:7px; min-width:0; }
.rm-comark-dot{ width:9px; height:9px; border-radius:2px; flex:0 0 auto; }

/* ── the hero ──
   The watermark logo is gone from the markup (see openRepo); this keeps any
   cached copy from painting. The band is shorter now that nothing has to
   clear a 170px mark. */
.rm-hero-logo{ display:none !important; }
.rm-hero{ min-height:104px; padding:18px 24px; }
.rm-hero-txt h2{ font-size:22px; }

/* ── the action bar ──
   A demo's Send is the first and brightest thing: white on the company
   accent, with GitHub's black demoted to a neighbour.
   ⚠️ `.rm-btn.send` is written ONCE, further down with the rest of the send row
   (search "SEND, AT THE TOP"). It used to be written here too, in VisionOne's
   fixed green — which meant the button ignored the company accent the whole rest
   of the popup is branded with, and two rules fought over it. */

/* ── "What is this?" — a real segmented control ──
   Four separate rounded cards with a glow around the live one looked like
   four buttons that had drifted apart. One control, four segments, hard
   edges between them: it reads as a switch, which is what it is. */
.rm-class{ border-radius:10px; }
.rm-class-opts{ grid-template-columns:repeat(4,minmax(0,1fr)); gap:0; margin-top:10px;
  border:1px solid var(--border); border-radius:9px; overflow:hidden; background:#fff; }
.rm-class-opt{ border:0; border-left:1px solid var(--border); border-radius:0; padding:9px 11px 10px;
  box-shadow:none; }
.rm-class-opt:first-child{ border-left:0; }
.rm-class-opt:hover{ background:#f7faf8; }
.rm-class-opt.is-on{ box-shadow:none; background:color-mix(in srgb,var(--_ac,#649954) 9%,#fff);
  box-shadow:inset 0 -3px 0 var(--_ac,#649954); }
.rm-class-opt.is-on b{ color:var(--_ac,#649954); }
@media (max-width:640px){ .rm-class-opts{ grid-template-columns:repeat(2,minmax(0,1fr)); }
  .rm-class-opt:nth-child(3){ border-left:0; }
  .rm-class-opt:nth-child(n+3){ border-top:1px solid var(--border); } }

/* ⚠️ Do NOT try to stack the send sheet over this popup with z-index. It
   cannot be done: .rm-backdrop is mounted on <html> and carries a
   backdrop-filter, so Chromium paints it above everything inside <body> —
   .bx-sheet-wrap still lost at z-index 2147483646 (measured). repos.js closes
   the popup when the sheet opens instead; see sendDemo(). */

/* notes that belong under a thing, not centred under the whole pane */
.rm-note--l{ text-align:left; color:var(--ink3); font-size:11.5px; line-height:1.5; padding-top:0; }
.rm-note--l code{ background:#f1f5f3; padding:1px 5px; border-radius:4px; font-size:11px; }
.rm-note--l b{ color:#3f4b44; }

/* History is a button in the crumb line, not a hand-styled one-off */
.repos-crumbbtn{ margin-left:12px; border:1px solid var(--border); background:#fff; color:var(--ink2);
  font:700 12px var(--f,'Inter',system-ui,sans-serif); padding:5px 12px; border-radius:8px; cursor:pointer;
  transition:border-color .14s, color .14s; }
.repos-crumbbtn:hover{ border-color:var(--c-blue); color:var(--c-blue); }

/* ══════════════════════════════════════════════════════════════════════════
   THE PICTURE OF THE APP IS THE HEADER
   ══════════════════════════════════════════════════════════════════════════
   The same screenshot the library card shows and the share email mails, laid
   across the whole band and faded under the company accent — so you can still
   see the app while the lettering stays readable. No shot on disk and the band
   is the accent gradient, exactly as before.
   Two rows now: WHOSE (the company's real mark and its name) and WHAT IT IS,
   then the icon, the title and the facts. Everything below overrides the
   earlier .rm-hero rules on purpose — later wins, and there is one place to
   read the current answer. ══════════════════════════════════════════════ */
.rm-hero{ display:block; min-height:118px; padding:16px 24px 18px; }
.rm-hero.has-shot{ min-height:178px; }
/* ⚠️ THE PICTURE IS THE POINT — DO NOT DYE IT.
   This used to sit at opacity .72 under a veil that laid the company accent at
   82–96% strength across the WHOLE band. Both halves were defensible on their
   own and together they cost the feature its reason to exist: Tyler, looking at
   it — *"there's too much green at the top covering the screenshot."* He was
   right. You could make out that an app was under there and read nothing of it.
   The shot is now at full strength and the accent has stopped being a wash. */
.rm-hero-shot{ position:absolute; inset:0; z-index:0; overflow:hidden; opacity:0; transition:opacity .45s ease; }
.rm-hero-shot.is-in{ opacity:1; }
/* Aimed by aimShot() the moment it loads; this is only what it looks like for
   the frame before that. NEVER put `top` back here — see aimShot's comment. */
.rm-hero-shot img{ width:100%; height:100%; object-fit:cover; object-position:50% 24%; display:block; }
/* The scrim. Its whole job is to be a GROUND FOR LETTERING, not a brand tint —
   so it is heavy exactly where words sit (the bottom-left wedge under the icon,
   the title and the slug; a thin bar along the top where the plaques sit) and
   absent through the middle-right, which is where you actually look at the app.
   The company accent survives as a low tint along the left edge only: enough to
   know whose this is, not enough to repaint a photograph. */
.rm-hero-veil{ position:absolute; inset:0; z-index:0; opacity:0; transition:opacity .45s ease; pointer-events:none; }
.rm-hero.has-shot .rm-hero-veil{ opacity:1;
  background:
    /* A CAPTION SCRIM, and the layout decides where it goes. The header is two
       rows: plaques along the top, then the icon + title + slug along the bottom.
       So it is heavy at the BOTTOM (where the biggest lettering sits), moderate
       along the top (where the plaques sit, and they carry grounds of their own),
       and out of the way through the middle — which is the band of the screenshot
       you actually read the app from. Going from "all wash" to "no scrim" made the
       title fight the app's own toolbar; this is the middle the picture needs. */
    linear-gradient(to top, rgba(4,11,7,.93) 0%,
                            rgba(4,11,7,.86) 17%,
                            rgba(4,11,7,.62) 34%,
                            rgba(4,11,7,.26) 52%,
                            rgba(4,11,7,.10) 68%,
                            rgba(4,11,7,.34) 100%),
    /* a soft wedge in from the bottom-left corner, under the icon and the title */
    radial-gradient(120% 150% at 4% 108%, rgba(4,11,7,.72) 0%,
                                          rgba(4,11,7,.34) 40%,
                                          transparent 72%),
    /* whose it is — a tint at the left edge, not a coat of paint over the app */
    linear-gradient(96deg, color-mix(in srgb, var(--c-blue) 62%, transparent) 0%,
                           color-mix(in srgb, var(--c-blue) 28%, transparent) 20%,
                           color-mix(in srgb, var(--c-blue) 7%, transparent) 40%,
                           transparent 56%); }
/* The texture overlay muddies a photograph. */
.rm-hero.has-shot .rr-thumb-tex{ display:none; }
/* A brighter picture underneath means the lettering has to carry its own weight
   rather than borrow it from the wash that used to be there. */
.rm-hero.has-shot .rm-hero-txt h2{ text-shadow:0 1px 2px rgba(3,10,6,.55), 0 3px 14px rgba(3,10,6,.45); }
.rm-hero.has-shot .rm-hero-txt .slug{ background:rgba(6,16,11,.42); border-color:rgba(255,255,255,.34);
  -webkit-backdrop-filter:blur(3px); backdrop-filter:blur(3px); }
.rm-hero.has-shot .rm-hero-stats span{ background:rgba(6,16,11,.44); border-color:rgba(255,255,255,.32);
  -webkit-backdrop-filter:blur(3px); backdrop-filter:blur(3px); }
/* Clears BOTH controls in the corner — Close, and the camera beside it. At 44px
   (Close only) a long company name ran under the picture button. */
.rm-hero-top{ position:relative; z-index:1; display:flex; align-items:center; gap:8px;
  flex-wrap:wrap; margin-bottom:13px; padding-right:92px; }
.rm-hero-main{ position:relative; z-index:1; display:flex; align-items:center; gap:18px; min-width:0; }

/* ── the app icon: NO BOX ──────────────────────────────────────────────────
   An app icon is already a designed tile — its own artwork, its own rounded
   square — and standing it on a white plate put a white card in the middle of
   the header for nothing. It sits directly on the band with a drop-shadow so it
   still lifts off the picture. The ground comes back only for a mark with a
   TRANSPARENT background, which over a screenshot would otherwise dissolve —
   and it is GLASS, not white. Solid white behind a mark is reserved for the
   company plate, where the mark IS the subject; here the app's picture is. */
.rm-icon{ background:none; border:0; box-shadow:none; border-radius:16px;
  filter:drop-shadow(0 6px 16px rgba(6,14,10,.34)); }
.rm-icon img{ padding:0; border-radius:15px; }
.rm-icon.is-plated{ background:rgba(255,255,255,.16); border:1px solid rgba(255,255,255,.34);
  -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px);
  box-shadow:0 8px 22px rgba(6,14,10,.28), inset 0 1px 0 rgba(255,255,255,.28); filter:none; }
.rm-icon.is-plated img{ padding:8px; border-radius:0; filter:drop-shadow(0 1px 3px rgba(0,0,0,.28)); }
.rm-icon.is-mono{ background:linear-gradient(150deg, rgba(255,255,255,.30), rgba(255,255,255,.12));
  border:1px solid rgba(255,255,255,.42); filter:none; }

/* ── first line: whose it is, and what it is ───────────────────────────────
   ⚠️ NOTHING UP HERE IS A PILL. A rounded-to-death chip reads as a bubble
   floating on the picture; these are small rectangular plaques that sit on it.
   The logo keeps its white ground — a brand mark belongs on paper — and is big
   enough to recognise. */
/* ⚠️ THE MARK HAS TO BE READABLE. It was a 24px plate holding a logo with 2px
   of padding, i.e. a ~20px glyph — which for a wordmark (most of ours are
   wordmarks, not monograms) is a grey smudge you cannot identify. Whose build
   this is happens to be the FIRST thing the header says, so it is sized to be
   read: a 38px plate, and the letters beside it a step up with it. */
.rm-cochip{ padding:5px 12px 5px 6px; border-radius:7px; gap:10px; font-size:13px; font-weight:800; }
.rm-cochip-plate{ width:38px; height:38px; border-radius:8px; }
.rm-cochip-plate img{ padding:3px; }
/* What it is, beside whose it is — and it turns over when the answer below
   changes, so the header never describes a classification you just left. */
/* ⚠️ FAINT, NOT SOLID. It was a block of the kind's colour, which made "who is
   this for" the loudest thing in a header that already shows the company on
   white paper. Now it is the same white plaque, with the kind's colour carried
   in the word — very faint blue for a demo, very faint purple for one of ours.
   The card doesn't carry this at all any more; this is where it lives. */
.rm-kindchip{ display:inline-flex; align-items:center; gap:7px; padding:5px 10px; border-radius:6px;
  font-size:11px; font-weight:800; letter-spacing:.35px; text-transform:uppercase; white-space:nowrap;
  color:color-mix(in srgb, var(--_kc,#7c5cd0) 74%, #000); font-family:inherit;
  background:rgba(255,255,255,.93); border:1px solid color-mix(in srgb, var(--_kc,#7c5cd0) 26%, rgba(255,255,255,.6));
  box-shadow:0 2px 8px rgba(6,14,10,.22);
  transition:opacity .15s ease, transform .15s ease, background .25s ease; }
/* ⚠️ IT SAYS THE WORD NOW. This used to be a bare "?" — see kindChipInner. A
   glyph cannot carry "nobody has confirmed this", and hovering to find out is
   not a design. `unconfirmed` is a small inset tag INSIDE the chip so the chip
   still reads as one thing, and the whole chip is a button to the question. */
/* ⚠️ `.rm-hero, .rm-hero *{color:#fff}` paints every descendant white, and it
   hits the label SPAN directly — so the chip's own colour never reached the
   word and it rendered white-on-white. The label has to claim it back. */
.rm-kindchip .rm-kindchip-l{ color:inherit; }
.rm-kindchip.is-ask{ cursor:pointer; padding-right:5px; }
.rm-kindchip.is-ask:hover{ background:#fff; border-color:color-mix(in srgb, var(--_kc,#7c5cd0) 55%, #fff); }
.rm-kindchip.is-ask:focus-visible{ outline:2px solid var(--_kc,#7c5cd0); outline-offset:2px; }
.rm-kindchip .rm-kindchip-q{ font-style:normal; font-size:9.5px; font-weight:800; letter-spacing:.5px;
  padding:2px 7px; border-radius:5px; color:#8a4d0a; background:#fdf3e3;
  border:1px solid #f0dcbb; text-transform:uppercase; }
.rm-kindchip.is-turning{ opacity:0; transform:translateY(-4px) scale(.96); }
.rm-relchip{ display:inline-flex; align-items:center; padding:5px 9px; border-radius:6px; font-size:10.5px;
  font-weight:800; letter-spacing:.5px; text-transform:uppercase;
  background:rgba(255,255,255,.16); border:1px solid rgba(255,255,255,.3); }
/* A hostname is not a sentence: capitalize made it Crm-Demo.Visiononeperf… */
.rm-hero-stats span{ border-radius:6px; }
.rm-hero-stats span.is-host{ text-transform:none; font-family:ui-monospace,Consolas,monospace; font-size:10.5px; }

/* ══ Sending — the record of who has been shown this, and the way to show
   somebody. Everything here can change under you: answering "Demo" in the pane
   behind repaints this one, so it cross-fades rather than snapping. ══ */
.rm-pane{ transition:opacity .17s ease, transform .17s ease; }
.rm-pane.is-morph{ opacity:0; transform:translateY(6px); }

/* ══ MOVING BETWEEN TABS SHOULD FEEL LIKE MOVING ═══════════════════════════
   Tyler: *"every time I click through these tabs I want a smooth transition —
   smooth effects as things get larger, bigger, smaller. Polish design
   everywhere."*
   ⚠️ A TRANSITION CANNOT DO THIS, WHICH IS WHY THESE ARE ANIMATIONS. Panes switch
   `display:none` → `display:flex`, and display is not animatable — a box that was
   `display:none` one frame ago has no start value to transition FROM, so it just
   appears. An animation on the class that makes it visible replays on every
   switch, which is precisely the event we want to express.
   `is-morph` above still owns the cross-fade for content changing underneath you;
   the two never collide, because an in-place repaint does not re-add `is-on`. */
.rm-pane.is-on{ animation:rmPaneIn .24s cubic-bezier(.2,.8,.3,1) both; }
@keyframes rmPaneIn{ from{ opacity:0; transform:translateY(9px) scale(.994); } }
/* the content arrives a beat after the pane, so the eye lands on the panel and
   then on what is in it. ONE shared delay — a per-row stagger across 200 sends is
   a great deal of animation for no extra meaning. */
.rm-pane.is-on .rm-sec, .rm-pane.is-on .rm-sendstats{
  animation:rmSecIn .28s cubic-bezier(.2,.8,.3,1) .05s both; }
@keyframes rmSecIn{ from{ opacity:0; transform:translateY(6px); } }

/* the tab underline GROWS into place instead of teleporting between tabs */
.rm-tab{ transition:color .16s ease; }
.rm-tab::after{ content:""; position:absolute; left:8px; right:8px; bottom:-1px; height:2.5px;
  border-radius:2px; background:var(--c-blue,#2f6fb0);
  transform:scaleX(0); transform-origin:50% 50%;
  transition:transform .2s cubic-bezier(.2,.8,.3,1); }
.rm-tab.is-on::after{ transform:scaleX(1); }
.rm-tab .tn{ transition:background .16s ease, color .16s ease, transform .16s ease; }
.rm-tab.is-on .tn{ transform:scale(1.06); }

/* "things get bigger" under the pointer — held to 1px and 7% so a column of rows
   does not wobble as the mouse crosses it */
.rm-sendstat{ transition:transform .14s ease, box-shadow .14s ease, background .14s ease; }
.rm-sendstat.is-go:hover{ transform:translateY(-1px); }
.sv-tl-row{ transition:background .13s ease, transform .13s ease; }
.sv-tl-row:hover{ transform:translateX(1px); }
.sv-tl-mark .sv-face{ transition:transform .16s cubic-bezier(.2,.8,.3,1), box-shadow .16s ease; }
.sv-tl-row:hover .sv-tl-mark .sv-face{ transform:scale(1.07); }
/* the receipt unrolls rather than blinking into place */
.sv-detail{ animation:svDetailIn .22s cubic-bezier(.2,.8,.3,1) both; }
@keyframes svDetailIn{ from{ opacity:0; transform:translateY(-4px); } }

/* ⚠️ AND ALL OF IT STANDS DOWN FOR ANYBODY WHO ASKED IT TO. Motion this broad is a
   real problem with vestibular disorders, and "polish everywhere" must not mean
   "unavoidable everywhere". */
@media (prefers-reduced-motion:reduce){
  .rm-pane.is-on, .rm-pane.is-on .rm-sec, .rm-pane.is-on .rm-sendstats, .sv-detail{ animation:none; }
  .rm-tab::after{ transition:none; }
  .sv-tl-row:hover, .rm-sendstat.is-go:hover,
  .sv-tl-row:hover .sv-tl-mark .sv-face{ transform:none; }
}
.rm-sendhd{ display:flex; align-items:center; gap:14px; padding:13px 15px; border-radius:12px;
  border:1px solid var(--border-s); background:linear-gradient(180deg,#fbfdfb,var(--surf)); }
.rm-sendhd.is-demo{ border-color:color-mix(in srgb, var(--c-blue) 28%, var(--border-s));
  background:linear-gradient(180deg, color-mix(in srgb, var(--c-blue) 5%, #fff), var(--surf)); }
.rm-sendhd-t{ min-width:0; flex:1 1 auto; }
.rm-sendhd-t b{ display:block; font-size:13px; font-weight:800; color:var(--ink); }
.rm-sendhd-t span{ display:block; font-size:11.5px; color:var(--ink3); margin-top:3px; line-height:1.5; }
.rm-sendgo{ flex:0 0 auto; }
.rm-sendblock{ flex:0 0 auto; font-size:11.5px; font-weight:700; color:#a2431f; background:#fdf4ee;
  border:1px solid #f5dfd0; border-radius:8px; padding:7px 11px; }
/* Said in the same amber as "nothing to send", because it is the same kind of
   thing: a reason to look before you press the button. Full width under the
   header rather than beside it — it is a sentence, not a chip. */
.rm-sendnote{ font-size:11.5px; line-height:1.55; color:#7c4418; background:#fdf6ec;
  border:1px solid #f2e0c6; border-radius:10px; padding:9px 12px; margin:-4px 0 0; }

/* ══ SEND, AT THE TOP ══════════════════════════════════════════════════════
   The app and its demo, side by side, first in the action row — because being
   put in front of somebody is what this screen is for. The second button is
   quieter than the first (it sends a DIFFERENT build), but it is a real button:
   the alternative was closing this popup and hunting for the demo in the list.

   ⚠️ FLAT, NOT SHINY. Tyler, on the old one: *"the Send This Demo button needs
   to be better. It looks tacky."* It was carrying every trick at once — a
   135° gradient, a wide coloured glow beneath it, 800 weight, and a
   brightness() hover that washed the colour out — while the button beside it
   ("Open live app") wore the SAME gradient in the SAME colour, so the row had
   two competing primaries and no hierarchy at all. A gradient plus a coloured
   drop shadow is what a button looks like when it is trying to be noticed;
   being the only filled thing in the row is what it looks like when it is
   actually the point. So: one flat brand fill, a hairline of its own darker
   edge for definition, a shadow you read as lift rather than as glow, and a
   hover that DEEPENS the colour instead of bleaching it. Everything else in
   this row is an outline — see .rm-btn.live and .rm-btn.gh. */
.rm-sendacts{ display:inline-flex; gap:8px; flex-wrap:wrap; }
.rm-sendacts--pane{ flex:0 0 auto; }
.rm-btn.send{ background:var(--c-blue); color:#fff; font-weight:700;
  border:1px solid color-mix(in srgb, var(--c-blue) 78%, #000);
  box-shadow:0 1px 2px rgba(16,24,20,.14); }
.rm-btn.send:hover{ background:color-mix(in srgb, var(--c-blue) 88%, #000);
  border-color:color-mix(in srgb, var(--c-blue) 66%, #000); color:#fff;
  box-shadow:0 3px 10px -4px color-mix(in srgb, var(--c-blue) 60%, transparent); }
.rm-btn.send:active{ transform:translateY(0); box-shadow:inset 0 1px 3px rgba(0,0,0,.18); }
.rm-btn.send svg{ width:15px; height:15px; opacity:.9; }
/* The demo/app alternative — same shape, less voltage. */
.rm-btn.send.send--alt{ background:none; color:var(--c-blue); font-weight:700; box-shadow:none;
  border:1px solid color-mix(in srgb, var(--c-blue) 40%, var(--border-s)); }
.rm-btn.send.send--alt:hover{ background:color-mix(in srgb, var(--c-blue) 8%, transparent);
  border-color:var(--c-blue); color:var(--c-blue); box-shadow:none; }
/* No live URL is not a disabled button — it is a button that asks first. */
.rm-btn.send.is-nourl{ background:#6c7683; border-color:#59626e; box-shadow:none; }
.rm-btn.send.is-nourl:hover{ background:#5b6470; border-color:#4a525c; box-shadow:none; }
.rm-btn-tag{ font-style:normal; font-size:9.5px; font-weight:800; letter-spacing:.4px; text-transform:uppercase;
  padding:2px 6px; border-radius:5px; background:rgba(255,255,255,.22); border:1px solid rgba(255,255,255,.3); }

/* Where is it deployed? Asked in place, saved on the repo, then the send it was
   asked for happens — see askLiveUrl.
   ⚠️ It is inserted as a SIBLING of `.rm-actions`, which is a flex child of the
   popup shell and carries the shell's own horizontal padding — so this has to
   carry it too or the box runs edge to edge while everything above it is inset. */
.rm-liveask{ flex:0 0 auto; margin:10px 24px 0; padding:13px 15px; border-radius:12px;
  border:1px solid color-mix(in srgb, var(--c-blue) 30%, var(--border-s));
  background:linear-gradient(180deg, color-mix(in srgb, var(--c-blue) 6%, #fff), var(--surf)); }
.rm-liveask-t b{ display:block; font-size:13px; font-weight:800; color:var(--ink); }
.rm-liveask-t span{ display:block; font-size:11.5px; color:var(--ink3); margin-top:3px; line-height:1.5; }
.rm-liveask-r{ display:flex; gap:8px; margin-top:10px; flex-wrap:wrap; }
.rm-liveask-r input{ flex:1 1 260px; min-width:0; padding:9px 11px; border-radius:9px;
  border:1px solid var(--border); background:#fff; font:inherit; font-size:12.5px; color:var(--ink);
  font-family:ui-monospace,Consolas,monospace; }
.rm-liveask-r input:focus{ outline:2px solid var(--c-blue); outline-offset:1px; }
.rm-liveask-m{ font-size:11.5px; color:var(--ink3); margin-top:7px; min-height:0; }
.rm-liveask-m.is-bad{ color:#c2472f; font-weight:700; }

/* The unconfirmed chip points here, so here has to acknowledge being pointed
   at — one pulse of the accent, then back to normal. */
.rm-build.is-flash{ animation:rmFlash 1.35s ease both; }
@keyframes rmFlash{
  0%,100%{ box-shadow:0 0 0 0 transparent; }
  18%,55%{ box-shadow:0 0 0 4px color-mix(in srgb, var(--c-blue) 34%, transparent); }
}
.rm-sendstats{ display:grid; grid-template-columns:repeat(auto-fit,minmax(96px,1fr)); gap:1px;
  background:var(--border-s); border:1px solid var(--border-s); border-radius:12px; overflow:hidden; }
.rm-sendstat{ background:var(--surf); padding:11px 13px; }
.rm-sendstat b{ display:block; font-size:15px; font-weight:800; color:var(--ink); font-variant-numeric:tabular-nums; }
.rm-sendstat span{ display:block; font-size:9.5px; font-weight:700; text-transform:uppercase; letter-spacing:.4px;
  color:var(--ink3); margin-top:4px; }
.sv-tl-t em.rm-more, .rm-row--send .txt .t em.rm-more{ font-style:normal; color:var(--ink3); font-weight:600; }
.rm-tplpill{ display:inline-block; padding:1px 6px; border-radius:5px; background:var(--border-s);
  color:var(--ink2); font-size:10px; font-weight:800; letter-spacing:.2px; }

/* ── what they did with it ──────────────────────────────────────────────────
   Only ever shown for a send SendGrid has reported on, and only the states that
   are true of it — see engChips. Green is "a person did something", grey is "it
   arrived and that is all we know", red is "stop sending to this address". */
.rm-engpill{ display:inline-block; margin-left:6px; padding:1px 7px; border-radius:5px;
  font-size:10px; font-weight:800; letter-spacing:.2px;
  background:var(--border-s); color:var(--ink3); }
.rm-engpill.is-open{ background:#e9f7ef; color:#1a7f4b; }
.rm-engpill.is-click{ background:#e6f1fd; color:#1257a8; }
.rm-engpill.is-bad{ background:#fdecea; color:#b3271a; }
.sv-eng{ flex:0 0 auto; padding:2px 8px; border-radius:6px; font-size:10.5px; font-weight:800;
  letter-spacing:.2px; background:var(--border-s); color:var(--ink3); }
.sv-eng.is-open{ background:#e9f7ef; color:#1a7f4b; }
.sv-eng.is-click{ background:#e6f1fd; color:#1257a8; }
.sv-eng.is-bad{ background:#fdecea; color:#b3271a; }
.sv-sub--eng{ color:var(--ink3); }

@media (prefers-reduced-motion:reduce){
  /* The cross-fade and the chip turning over are meaning, not decoration —
     they arrive instantly instead of not happening. */
  .rm-pane,.rm-kindchip,.rm-hero-shot,.rm-hero-veil{ transition:none; }
  .rm-pane.is-morph{ opacity:1; transform:none; }
  .rm-kindchip.is-turning{ opacity:1; transform:none; }
  /* The flash is a pointer, so it still has to point — it just holds still
     instead of pulsing. */
  .rm-build.is-flash{ animation:none; box-shadow:0 0 0 4px color-mix(in srgb, var(--c-blue) 34%, transparent); }
  /* A filtered row still has to LEAVE — it just leaves at once. The search is
     the point; the sliding is only how it reads. */
  [data-fkey]{ transition:none; }
  [data-fkey].sv-hid{ transform:none; }
  .sv-face-img{ animation:none; }
  /* The logo still arrives; it just does not pop in. */
  .rr-thumb-mark.is-on{ animation:none; }
  .rp-card:hover .rr-thumb-mark{ transform:none; }
}

/* ── the popup header on a phone ───────────────────────────────────────────
   The two-row header stays a two-row header: the company plaque and the
   classification chip wrap onto their own lines. AFTER the desktop padding so
   it actually wins. */
@media (max-width:700px){
  .rm-hero{ padding:14px 16px 16px; }
  .rm-hero.has-shot{ min-height:158px; }
  .rm-hero-top{ margin-bottom:11px; padding-right:40px; gap:6px; }
  .rm-hero-main{ gap:13px; }
  .rm-icon{ width:56px; height:56px; border-radius:14px; }
  .rm-hero-txt h2{ font-size:20px; }
  /* Sending: the button drops under the words rather than squeezing them. */
  .rm-sendhd{ flex-direction:column; align-items:stretch; gap:11px; }
  .rm-sendgo{ justify-content:center; }
}

/* ══════════════════════════════════════════════════════════════════════════
   THE BUILD PANEL — which tool this is, and who this build is for
   ══════════════════════════════════════════════════════════════════════════
   Replaces the "What is this?" box. What was wrong with it, in Tyler's words:
   "I really don't like the design for the 'What is this unconfirmed?' and then
   it says 'Internal tool confirm.' What, no? I don't like how these selection
   things are circles. Just make them their own UI."
   Three faults, three answers:
     • the STATE was jammed into the heading ("What is this?unconfirmed") and
       into the live option's own label ("Internal tool — confirm?") → the title
       bar now states the answer, and Confirm is a button that says Confirm;
     • the options read as four floating bubbles → they are squared-off cells in
       one bordered block, each with a TICK BOX, and the chosen one is filled;
     • the company was a word → it is the company's real mark on white paper.
   ══════════════════════════════════════════════════════════════════════════ */
.rm-build{ border:1px solid var(--border); border-radius:12px; background:var(--surf);
  margin-bottom:14px; overflow:hidden; }
.rm-build.is-guess{ border-color:#e7c9a8; box-shadow:inset 3px 0 0 #d97706; }

/* The title bar: HOW SURE WE ARE, and nothing else.
   ⚠️ The company mark (.rm-build-co / .rm-build-colog) and the classification
   plaque (.rm-build-is) that used to open this bar are GONE — the hero states
   both, an inch above, so this repeated them and a VisionOne demo wore the same
   mark twice. Their rules are deleted rather than left unused; see classPicker. */
.rm-build-hd{ display:flex; align-items:center; gap:10px; flex-wrap:wrap;
  padding:10px 13px; background:linear-gradient(180deg,#fbfdfb,#f4f8f5);
  border-bottom:1px solid var(--border-s); }
.rm-build-warn{ font-size:11px; font-weight:800; color:#8a4d0a; background:#fdf3e3;
  border:1px solid #f0dcbb; border-radius:5px; padding:4px 9px; }
.rm-build-ok{ display:inline-flex; align-items:center; gap:5px; font-size:11px; font-weight:800;
  color:#166534; background:#e9f7ee; border:1px solid #c9e9d5; border-radius:5px; padding:4px 9px; }
.rm-build-ok .rm-tick{ width:11px; height:11px; }
.rm-build-confirm{ margin-left:auto; display:inline-flex; align-items:center; gap:6px;
  font:800 12px var(--f,'Inter',system-ui,sans-serif); color:#fff; cursor:pointer;
  background:#b45309; border:1px solid #96450a; border-radius:7px; padding:6px 12px;
  transition:filter .14s; }
.rm-build-confirm:hover{ filter:brightness(1.09); }
.rm-build-confirm .rm-tick{ width:13px; height:13px; }
.rm-build-src{ font-size:11px; color:var(--ink3); line-height:1.5; padding:9px 13px 0; }

/* one labelled question per block, with a rule between them */
.rm-build-q{ padding:12px 13px 13px; }
.rm-build-q + .rm-build-q{ border-top:1px solid var(--border-s); }
.rm-build-qh b{ display:block; font-size:12.5px; font-weight:800; color:var(--ink); }
.rm-build-qh span{ display:block; font-size:11px; color:var(--ink3); margin-top:2px; line-height:1.45; }

/* ── the four options: cells in one block, each with a tick box ──
   ⚠️ NO CIRCLES. A radio dot in a ring was the exact thing objected to, and a
   rounded card with a glow is the same idea wearing a coat. Square box, square
   tick, hard edges between cells. */
.rm-build .rm-class-opts{ display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:0; margin-top:10px;
  border:1px solid var(--border); border-radius:8px; overflow:hidden; background:#fff; }
.rm-build .rm-class-opt{ display:flex; align-items:flex-start; gap:9px; text-align:left; cursor:pointer;
  border:0; border-radius:0; padding:10px 11px 11px; box-shadow:none; background:#fff; font:inherit;
  border-left:1px solid var(--border); border-top:1px solid var(--border); }
.rm-build .rm-class-opt:nth-child(2n+1){ border-left:0; }
.rm-build .rm-class-opt:nth-child(-n+2){ border-top:0; }
.rm-build .rm-class-opt:hover{ background:#f7faf8; }
/* ⚠️ SPECIFICITY, MEASURED — every box showed a tick until this was scoped.
   `.rm-class-opt span` (0,1,1) is an older rule further up this file, and it beats
   a bare `.rm-opt-tick` (0,1,0): `color:transparent` lost, currentColor came back
   as --ink3, and all four boxes rendered ticked with one of them also filled. Same
   family as the .sd-grade flattening in standards.css — when the element you are
   styling is the same TYPE as a sibling an older rule already claims, scope past
   that rule instead of hoping to out-rank it. */
.rm-build .rm-class-opt > .rm-opt-tick{ flex:0 0 auto; width:17px; height:17px; border-radius:4px;
  margin-top:1px; border:1.5px solid #c9d4cd; background:#fff; display:grid; place-items:center;
  color:transparent; transition:background .13s, border-color .13s, color .13s; }
.rm-build .rm-class-opt > .rm-opt-tick .rm-tick{ width:11px; height:11px; }
.rm-build .rm-class-opt > .rm-opt-txt{ display:block; min-width:0; margin-top:0; }
.rm-build .rm-class-opt .rm-opt-txt > b{ display:block; font-size:12.5px; font-weight:800; color:var(--ink2); }
.rm-build .rm-class-opt .rm-opt-txt > span{ display:block; font-size:10.5px; color:var(--ink3);
  margin-top:2px; line-height:1.4; }
.rm-build .rm-class-opt.is-on{ background:color-mix(in srgb,var(--_ac,#649954) 8%,#fff); box-shadow:none; }
.rm-build .rm-class-opt.is-on > .rm-opt-tick{ background:var(--_ac,#649954); border-color:var(--_ac,#649954); color:#fff; }
.rm-build .rm-class-opt.is-on .rm-opt-txt > b{ color:var(--_ac,#649954); }
@media (max-width:560px){ .rm-build .rm-class-opts{ grid-template-columns:1fr; }
  .rm-build .rm-class-opt{ border-left:0; border-top:1px solid var(--border); }
  .rm-build .rm-class-opt:first-child{ border-top:0; } }

/* ── the product: the tool this is a build of ────────────────────────────── */
.rm-prod-now{ display:flex; align-items:center; gap:11px; flex-wrap:wrap; margin-top:10px;
  padding:10px 11px; border:1px solid var(--border); border-left:3px solid var(--_ac,#7c5cd0);
  border-radius:0 8px 8px 0; background:#fff; }
.rm-prod-mark{ flex:0 0 auto; width:30px; height:30px; border-radius:6px; display:grid; place-items:center;
  font-size:11px; font-weight:800; letter-spacing:.3px; color:#fff; background:var(--_ac,#7c5cd0); }
/* An acronym product — MPMA, THSM — is the whole monogram, so a 30px box has to
   make room for four characters instead of quietly clipping to "MPM". */
.rm-prod-mark[data-n="3"]{ font-size:9.5px; letter-spacing:0; }
.rm-prod-mark[data-n="4"]{ font-size:8px; letter-spacing:-.2px; }
.rm-prod-txt{ min-width:0; flex:1 1 140px; }
.rm-prod-txt b{ display:block; font-size:14px; font-weight:800; color:var(--ink); letter-spacing:-.2px; }
.rm-prod-txt span{ display:block; font-size:11px; color:var(--ink3); margin-top:2px; }
.rm-prod-txt i{ font-style:normal; color:var(--ink3); opacity:.85; }
.rm-prod-edit,.rm-prod-all{ flex:0 0 auto; display:inline-flex; align-items:center; gap:5px;
  font:800 11.5px var(--f,'Inter',system-ui,sans-serif); cursor:pointer; border-radius:6px; padding:6px 10px;
  border:1px solid var(--border); background:#fff; color:var(--ink2); transition:border-color .14s, color .14s; }
.rm-prod-edit:hover,.rm-prod-all:hover{ border-color:var(--_ac,#7c5cd0); color:var(--_ac,#7c5cd0); }
.rm-prod-all .rm-go{ width:12px; height:12px; }

/* every other build of the same tool, as a row you can walk into */
.rm-sibs{ margin-top:8px; border:1px solid var(--border-s); border-radius:8px; overflow:hidden; }
.rm-sib{ width:100%; display:flex; align-items:center; gap:9px; text-align:left; cursor:pointer;
  background:#fff; border:0; border-top:1px solid var(--border-s); padding:8px 10px;
  font:inherit; transition:background .13s; }
.rm-sib:first-child{ border-top:0; }
.rm-sib:hover{ background:#f7faf8; }
.rm-sib-co{ width:22px; height:22px; flex:0 0 auto; border-radius:5px; background:#fff;
  border:1px solid var(--border); display:grid; place-items:center; overflow:hidden; }
.rm-sib-co img{ width:100%; height:100%; object-fit:contain; padding:2px; display:block; }
.rm-sib-co .repos-ddmono{ display:none; font-size:9px; font-weight:800; color:var(--ink3); }
.rm-sib-co.is-fallback .repos-ddmono{ display:block; }
.rm-sib-txt{ min-width:0; flex:1 1 auto; }
.rm-sib-txt b{ display:block; font-size:12.5px; font-weight:700; color:var(--ink2);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.rm-sib-txt span{ display:block; font-size:10.5px; color:var(--ink3); margin-top:1px; }
/* Faint, like the plaque above it: white ground, the kind's colour as the word
   and a hairline. A solid block of blue/purple on every sibling row made the
   popup look like it was ranking them. */
.rm-sib-kind{ flex:0 0 auto; font-size:9.5px; font-weight:800; letter-spacing:.4px; text-transform:uppercase;
  color:var(--_ac,#7c5cd0); background:color-mix(in srgb,var(--_ac,#7c5cd0) 10%,#fff);
  border:1px solid color-mix(in srgb,var(--_ac,#7c5cd0) 30%,#fff);
  border-radius:4px; padding:2px 6px; }
.rm-sib .rm-go{ width:13px; height:13px; flex:0 0 auto; color:var(--ink3); }
.rm-sib-more{ width:100%; border:0; border-top:1px solid var(--border-s); background:#f7faf8; cursor:pointer;
  font:800 11px var(--f,'Inter',system-ui,sans-serif); color:var(--ink3); padding:8px; }

/* ── the product picker (opens under Change) ─────────────────────────────── */
.rm-prodedit{ margin-top:9px; }
.rm-pe{ border:1px solid var(--border); border-radius:9px; background:#fff; overflow:hidden; }
.rm-pe-hd{ font-size:11px; font-weight:700; color:var(--ink3); padding:9px 11px 8px;
  border-bottom:1px solid var(--border-s); background:#fbfdfb; }
.rm-pe-hd b{ font-family:ui-monospace,Consolas,monospace; color:var(--ink2); }
.rm-pe-list{ max-height:210px; overflow-y:auto; }
.rm-pe-row{ width:100%; display:flex; align-items:center; gap:9px; text-align:left; cursor:pointer;
  background:#fff; border:0; border-top:1px solid var(--border-s); padding:7px 11px; font:inherit;
  transition:background .12s; }
.rm-pe-row:first-child{ border-top:0; }
.rm-pe-row:hover{ background:#f7faf8; }
.rm-pe-row.is-on{ background:color-mix(in srgb,var(--_ac,#7c5cd0) 9%,#fff); }
.rm-pe-mark{ width:22px; height:22px; flex:0 0 auto; border-radius:5px; display:grid; place-items:center;
  font-size:9px; font-weight:800; color:#fff; background:var(--_ac,#7c5cd0); }
.rm-pe-mark[data-n="3"]{ font-size:7.5px; }
.rm-pe-mark[data-n="4"]{ font-size:6.5px; letter-spacing:-.2px; }
.rm-pe-n{ flex:1 1 auto; min-width:0; font-size:12.5px; font-weight:700; color:var(--ink2);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.rm-pe-c{ flex:0 0 auto; font-size:10.5px; font-weight:800; color:var(--ink3);
  background:var(--border-s); border-radius:4px; padding:2px 6px; font-variant-numeric:tabular-nums; }
.rm-pe-tick{ flex:0 0 auto; color:var(--_ac,#7c5cd0); display:grid; place-items:center; }
.rm-pe-tick .rm-tick{ width:14px; height:14px; }
.rm-pe-new{ display:flex; gap:7px; padding:9px 11px; border-top:1px solid var(--border-s); background:#fbfdfb; }
.rm-pe-new input{ flex:1 1 auto; min-width:0; font:600 12.5px var(--f,'Inter',system-ui,sans-serif);
  color:var(--ink); background:#fff; border:1px solid var(--border); border-radius:7px; padding:7px 10px; }
.rm-pe-new input:focus{ outline:none; border-color:var(--c-blue); }
.rm-pe-clear{ width:100%; border:0; border-top:1px solid var(--border-s); background:#fff; cursor:pointer;
  font:700 11px var(--f,'Inter',system-ui,sans-serif); color:var(--ink3); padding:8px 8px 8px 11px;
  text-align:left; }
.rm-pe-clear:hover{ color:var(--c-blue); }

/* ── the Static Web App picker ──────────────────────────────────────────────
   The product picker's shape, because it is the same act: pick the thing this
   repo belongs to. Two differences — the rows carry a tier and a price rather
   than a build count, and the sheet opens by telling you when DNS has already
   answered, so a hand-typed record cannot be mistaken for the truth. */
.rm-swape{ --_ac:#0f766e; }
.rm-swape .rm-pe-n{ display:flex; flex-direction:column; gap:2px; white-space:normal; }
.rm-swape .rm-pe-n i{ font-style:normal; font-size:10.5px; font-weight:600; color:var(--ink3); }
.rm-swa-mark{ background:#0f766e; color:#fff; }
.rm-swa-mark svg{ width:13px; height:13px; }
.rm-swape-known{ font-size:11.5px; line-height:1.6; color:#0d5c56; background:#f0faf8;
  border-bottom:1px solid #cfeae6; padding:9px 11px; }
.rm-swape-known b{ color:#0a4a45; font-family:ui-monospace,Consolas,monospace; font-size:11px; }
.rm-swape-known code{ font-family:ui-monospace,Consolas,monospace; font-size:10.5px;
  background:#fff; border:1px solid #d7ece9; padding:1px 5px; border-radius:4px; }
.rm-swape-q{ background:#fff; border-top:0; border-bottom:1px solid var(--border-s); }

/* A finding on the rail: the count says what it costs, this says what is wrong
   with it. Squared, like every other badge in this app. */
.repos-cnt-flag{ display:none; }
.repos-cnt-flag.is-on{ display:inline-grid; place-items:center; flex:0 0 auto; margin-left:6px;
  min-width:17px; height:16px; padding:0 4px; border-radius:4px;
  font-size:10px; font-weight:800; font-variant-numeric:tabular-nums;
  color:#8a4d0a; background:#fdf3e3; border:1px solid #f0d8ae; }
.repos-cnt-flag.is-on + .repos-cnt{ padding-left:6px; }

/* ══ CONNECTIONS — the declared edges between two repos ════════════════════
   Same visual grammar as the sibling rows above it (they are the same kind of
   thing: another repo, one click away) with two differences that carry meaning:
   the row wears the CONNECTION's colour on its left edge rather than the
   company's or the product's, and a row nobody has filed yet is dashed. */
.rm-conns{ margin-top:10px; display:grid; gap:6px; }
.rm-conn-row{ display:flex; align-items:stretch; gap:0; background:#fff;
  border:1px solid var(--border); border-left:3px solid var(--_ac,#7c3aed);
  border-radius:0 8px 8px 0; overflow:hidden; }
/* A GUESS IS NOT AN ANSWER — the dashed edge is the same sentence .rm-build
   .is-guess says with an amber rail, and it is why this row carries "Link it"
   instead of an unlink. */
.rm-conn-row.is-guess{ border-style:dashed; border-left-style:solid;
  background:repeating-linear-gradient(135deg,#fff,#fff 7px,#fcfdfc 7px,#fcfdfc 14px); }
.rm-conn-row.is-gone{ align-items:center; gap:9px; padding:8px 4px 8px 10px; border-left-color:#94a3b8; }
.rm-conn-go{ flex:1 1 auto; min-width:0; display:flex; align-items:center; gap:9px;
  text-align:left; cursor:pointer; background:transparent; border:0; padding:8px 10px;
  font:inherit; transition:background .13s; }
.rm-conn-go:hover{ background:#f7faf8; }
/* What KIND of connection, in words, first — the row is unreadable without it
   ("Its demo" vs "The demo of" is the whole fact). */
.rm-conn-rel{ flex:0 0 auto; font-size:9.5px; font-weight:800; letter-spacing:.4px;
  text-transform:uppercase; color:var(--_ac,#7c3aed);
  background:color-mix(in srgb,var(--_ac,#7c3aed) 10%,#fff);
  border:1px solid color-mix(in srgb,var(--_ac,#7c3aed) 30%,#fff);
  border-radius:4px; padding:3px 7px; white-space:nowrap; }
.rm-conn-txt{ min-width:0; flex:1 1 auto; }
.rm-conn-txt b{ display:block; font-size:12.5px; font-weight:700; color:var(--ink2);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.rm-conn-txt span{ display:block; font-size:10.5px; color:var(--ink3); margin-top:1px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.rm-conn-kind{ flex:0 0 auto; font-size:9.5px; font-weight:800; letter-spacing:.4px;
  text-transform:uppercase; color:var(--_kc,#7c5cd0);
  background:color-mix(in srgb,var(--_kc,#7c5cd0) 10%,#fff);
  border:1px solid color-mix(in srgb,var(--_kc,#7c5cd0) 30%,#fff);
  border-radius:4px; padding:2px 6px; }
.rm-conn-go .rm-go{ width:13px; height:13px; flex:0 0 auto; color:var(--ink3); }
/* Two controls disagreeing is worth a word, not a colour on its own — amber, the
   same one "Guessed, never confirmed" wears, because it is the same class of
   problem: an answer that has not been reconciled. */
.rm-conn-warn{ flex:0 0 auto; font-size:9.5px; font-weight:800; letter-spacing:.3px;
  color:#8a4d0a; background:#fdf3e3; border:1px solid #f0d8ae; border-radius:4px; padding:2px 6px; }
.rm-conn-x,.rm-conn-file{ flex:0 0 auto; cursor:pointer; background:#fbfdfb;
  border:0; border-left:1px solid var(--border-s);
  font:800 11px var(--f,'Inter',system-ui,sans-serif); color:var(--ink3);
  padding:0 11px; transition:color .13s, background .13s; }
.rm-conn-x:hover{ color:#b91c1c; background:#fef4f4; }
.rm-conn-file{ color:var(--_ac,#7c3aed); }
.rm-conn-file:hover{ background:color-mix(in srgb,var(--_ac,#7c3aed) 9%,#fff); }
.rm-conn-none{ margin-top:10px; font-size:11.5px; color:var(--ink3); line-height:1.5;
  background:#fbfdfb; border:1px dashed var(--border); border-radius:8px; padding:10px 11px; }
.rm-conn-add{ margin-top:9px; display:inline-flex; align-items:center; gap:6px; cursor:pointer;
  font:800 11.5px var(--f,'Inter',system-ui,sans-serif); color:var(--ink2);
  background:#fff; border:1px solid var(--border); border-radius:7px; padding:7px 11px;
  transition:border-color .14s, color .14s; }
.rm-conn-add:hover{ border-color:var(--c-blue); color:var(--c-blue); }
.rm-plus{ width:13px; height:13px; flex:0 0 auto; }

/* ══ THE SHEET — a modal over the modal ════════════════════════════════════
   *"I want things like connecting a repo to be pop-ups with smooth transitions
   and everything, just to make it easier and cleaner."* Both editors used to
   expand INSIDE the scrolling pane, pushing everything below them down, so
   opening the list you wanted meant scrolling to find it.

   ⚠️ MOUNTED INSIDE .rm-backdrop, WHICH IS WHY IT CAN STACK AT ALL. That element
   carries a backdrop-filter, and a filtered element paints above everything in
   <body> whatever its z-index — the measured reason the App Store's send sheet
   could never sit over this popup. A child of it is inside that painted layer.
   The same property makes .rm-backdrop the containing block for this
   position:fixed (backdrop-filter establishes one), which is what we want: it is
   already the viewport, minus its own padding. */
.rm-sheet{ position:fixed; inset:0; z-index:40; display:flex;
  align-items:center; justify-content:center; padding:clamp(12px,3vh,32px) 14px; }
.rm-sheet-scrim{ position:absolute; inset:0; background:rgba(9,17,26,.34);
  opacity:0; transition:opacity .22s ease; cursor:pointer; }
.rm-sheet.is-open .rm-sheet-scrim{ opacity:1; }
.rm-sheet-box{ position:relative; width:min(560px,100%); max-height:100%;
  display:flex; flex-direction:column; min-height:0;
  background:var(--surf); border:1px solid var(--border); border-radius:16px; overflow:hidden;
  box-shadow:0 30px 70px -18px rgba(9,17,26,.46), 0 10px 24px -10px rgba(9,17,26,.28);
  /* the same curve and distances the popup itself enters on, so the second
     surface reads as part of the first rather than a different app */
  transform:translateY(14px) scale(.975); opacity:0;
  transition:transform .3s cubic-bezier(.16,1,.3,1), opacity .2s ease; }
.rm-sheet.is-open .rm-sheet-box{ transform:none; opacity:1; }
.rm-sheet-hd{ display:flex; align-items:flex-start; gap:10px; flex:0 0 auto;
  padding:14px 14px 12px; border-bottom:1px solid var(--border-s); background:#fbfdfb; }
.rm-sheet-t{ min-width:0; flex:1 1 auto; }
.rm-sheet-t b{ display:block; font-size:14px; font-weight:800; color:var(--ink); letter-spacing:-.2px; }
.rm-sheet-t span{ display:block; font-size:11px; color:var(--ink3); margin-top:3px; line-height:1.45; }
.rm-sheet-x{ flex:0 0 auto; width:26px; height:26px; border-radius:7px; cursor:pointer;
  border:1px solid var(--border); background:#fff; color:var(--ink3);
  font:700 12px var(--f,'Inter',system-ui,sans-serif); line-height:1;
  transition:color .13s, border-color .13s; }
.rm-sheet-x:hover{ color:#b91c1c; border-color:#f0c9c9; }
.rm-sheet-body{ flex:1 1 auto; min-height:0; overflow-y:auto; padding:12px 14px 14px;
  overscroll-behavior:contain; scrollbar-width:thin; }
.rm-sheet-body::-webkit-scrollbar{ width:10px; }
.rm-sheet-body::-webkit-scrollbar-thumb{ background:#dfe5e1; border:3px solid #fff; border-radius:99px; }
/* phones: a bottom sheet, like the popup behind it */
@media (max-width:700px){
  .rm-sheet{ align-items:flex-end; padding:0; }
  .rm-sheet-box{ width:100%; max-height:88%; border-radius:18px 18px 0 0; border-bottom:0;
    transform:translateY(26px); }
}
@media (prefers-reduced-motion:reduce){
  .rm-sheet-box,.rm-sheet-scrim{ transition:none; }
  .rm-sheet-box{ transform:none; }
}

/* the picker's own body — no header of its own, the sheet states what it is */
.rm-ce{ border:1px solid var(--border); border-radius:9px; background:#fff; overflow:hidden; }

/* ══ THE ANSWER, ABOVE THE FORM ════════════════════════════════════════════
   Tyler: *"the actions just need to be better, easier to find."* This screen is
   opened to say one thing nine times out of ten, and the page already knows what
   that thing is (appOf/demoOf), so it is the first block — one sentence and one
   button — and the six-way picker becomes the "or something else" path below it.
   Tinted, not boxed in its own card: it is part of this panel, not a banner
   stacked on top of one. */
.rm-ce-top{ background:linear-gradient(180deg,#f6f3fd,#fbfaff);
  border-bottom:1px solid var(--border-s); padding:11px 12px 12px; }
.rm-ce-toph > b{ display:block; font-size:13px; font-weight:800; color:var(--ink); }
.rm-ce-toph > span{ display:block; font-size:10.5px; line-height:1.45; color:var(--ink3); margin-top:3px; }
.rm-ce-topact{ display:flex; align-items:center; gap:9px; margin-top:10px;
  background:#fff; border:1px solid #e4ddf7; border-radius:8px; padding:7px 9px; }
.rm-ce-topact .rm-conn-txt{ flex:1 1 auto; min-width:0; }
.rm-ce-topact .rm-btn{ flex:0 0 auto; }
/* The question the six options answer, so they read as a list of answers rather
   than a wall of near-identical labels. */
.rm-ce-q, .rm-ce-lead{ font-size:10.5px; font-weight:800; letter-spacing:.2px;
  color:var(--ink3); padding:9px 12px 7px; }
.rm-ce-lead{ font-weight:700; letter-spacing:0; padding:8px 12px 0; color:var(--ink2); }
/* One click on a row IS the save — there is no Save button to look for, so the
   row carries the verb. Visible on hover only: 30 of them shouting "Link" is a
   list of buttons, not a list of repos. */
.rm-ce-do{ flex:0 0 auto; display:inline-flex; align-items:center; gap:3px;
  font-size:10px; font-weight:800; letter-spacing:.3px; text-transform:uppercase;
  color:var(--c-blue); opacity:0; transition:opacity .12s; }
.rm-ce-do svg{ width:11px; height:11px; }
.rm-ce-row:hover .rm-ce-do, .rm-ce-row:focus-visible .rm-ce-do{ opacity:1; }
/* The KIND first, because it decides which repos are even plausible answers.
   ⚠️ Scoped past .rm-class-opt's own rules the same way .rm-build has to be:
   `.rm-class-opt span` is (0,1,1) and beats a bare .rm-opt-tick (0,1,0), which is
   how all four tick boxes once rendered ticked at the same time. */
.rm-ce-rels{ display:grid; grid-template-columns:repeat(2,minmax(0,1fr));
  border-bottom:1px solid var(--border-s); }
.rm-ce-rel{ display:flex; align-items:flex-start; gap:9px; text-align:left; cursor:pointer;
  background:#fff; border:0; border-top:1px solid var(--border-s); border-left:1px solid var(--border-s);
  padding:9px 10px; font:inherit; transition:background .12s; }
.rm-ce-rel:nth-child(2n+1){ border-left:0; }
.rm-ce-rel:nth-child(-n+2){ border-top:0; }
.rm-ce-rel:hover{ background:#f7faf8; }
.rm-ce-rel > .rm-opt-tick{ flex:0 0 auto; width:16px; height:16px; border-radius:4px;
  border:1.5px solid var(--border); background:#fff; color:transparent;
  display:grid; place-items:center; margin-top:1px; }
.rm-ce-rel > .rm-opt-tick .rm-tick{ width:10px; height:10px; }
.rm-ce-rel > .rm-opt-txt{ display:block; min-width:0; }
.rm-ce-rel .rm-opt-txt > b{ display:block; font-size:12px; font-weight:800; color:var(--ink2); }
.rm-ce-rel .rm-opt-txt > span{ display:block; font-size:10px; color:var(--ink3);
  margin-top:2px; line-height:1.4; }
.rm-ce-rel.is-on{ background:color-mix(in srgb,var(--_ac,#7c3aed) 8%,#fff); }
.rm-ce-rel.is-on > .rm-opt-tick{ background:var(--_ac,#7c3aed); border-color:var(--_ac,#7c3aed); color:#fff; }
.rm-ce-rel.is-on .rm-opt-txt > b{ color:var(--_ac,#7c3aed); }
@media (max-width:560px){ .rm-ce-rels{ grid-template-columns:1fr; }
  .rm-ce-rel{ border-left:0; border-top:1px solid var(--border-s); }
  .rm-ce-rel:first-child{ border-top:0; } }
.rm-ce-search{ display:flex; align-items:center; gap:8px; padding:9px 11px;
  border-bottom:1px solid var(--border-s); background:#fbfdfb; }
.rm-ce-search input{ flex:1 1 auto; min-width:0; font:600 12.5px var(--f,'Inter',system-ui,sans-serif);
  color:var(--ink); background:#fff; border:1px solid var(--border); border-radius:7px; padding:7px 10px; }
.rm-ce-search input:focus{ outline:none; border-color:var(--c-blue); }
.rm-ce-n{ flex:0 0 auto; font-size:10.5px; font-weight:800; color:var(--ink3);
  font-variant-numeric:tabular-nums; }
.rm-ce-list{ max-height:250px; overflow-y:auto; }
.rm-ce-row{ width:100%; display:flex; align-items:center; gap:9px; text-align:left; cursor:pointer;
  background:#fff; border:0; border-top:1px solid var(--border-s); padding:7px 11px; font:inherit;
  transition:background .12s; }
.rm-ce-row:first-child{ border-top:0; }
.rm-ce-row:hover{ background:#f7faf8; }
/* The ranking is the feature — the row that is almost certainly the answer says
   why it is at the top instead of leaving you to trust the order. */
.rm-ce-row.is-likely{ background:#f6fbf7; }
.rm-ce-likely{ flex:0 0 auto; font-size:9.5px; font-weight:800; letter-spacing:.3px;
  text-transform:uppercase; color:#166534; background:#eaf6ec;
  border:1px solid #cbe6d1; border-radius:4px; padding:2px 6px; }
.rm-ce-more{ font-size:10.5px; color:var(--ink3); padding:8px 11px;
  border-top:1px solid var(--border-s); background:#fbfdfb; }

/* ══ THE CONNECTIONS PANE ══════════════════════════════════════════════════
   Three questions about this repo's PLACE, each a card. They used to be crammed
   into the audience card in Overview, under the summary and above the four
   options, which is the clutter this tab exists to undo. */
.rm-connpane{ display:flex; flex-direction:column; gap:14px; }
/* Inside this pane every section is a card in its own right, so the
   border-top-between-siblings rule .rm-build-q carries in the audience card is
   wrong here — it would draw a line between two things that are already boxed. */
.rm-connpane > .rm-build-q{ border:1px solid var(--border); border-radius:12px;
  background:var(--surf); padding:13px; }
.rm-connpane > .rm-build-q + .rm-build-q{ border-top:1px solid var(--border); }
.rm-connpane .rm-prod-now{ margin-top:10px; }

/* ══ HOSTING — the one fact about a repo that costs money ═══════════════════
   Teal, and nothing else in the popup is teal: money is not a classification,
   not a product and not a connection, and colouring it like one of those would
   file it under the wrong question. */
.rm-host{ --_hc:#0f766e; }
.rm-host-now{ display:flex; align-items:center; gap:11px; flex-wrap:wrap; margin-top:10px;
  padding:10px 11px; border:1px solid var(--border); border-left:3px solid var(--_hc);
  border-radius:0 8px 8px 0; background:#fff; }
.rm-host-mark{ flex:0 0 auto; width:30px; height:30px; border-radius:6px; display:grid;
  place-items:center; color:#fff; background:var(--_hc); }
.rm-host-mark svg{ width:17px; height:17px; }
.rm-host-txt{ min-width:0; flex:1 1 150px; }
.rm-host-txt b{ display:block; font-size:13.5px; font-weight:800; color:var(--ink);
  letter-spacing:-.15px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.rm-host-txt span{ display:block; font-size:11px; color:var(--ink3); margin-top:2px; }
/* $9/month for nothing is a finding, not a detail — amber, like every other
   "somebody needs to look at this" in this popup. */
.rm-host-flag{ flex:0 0 auto; font-size:9.5px; font-weight:800; letter-spacing:.3px;
  text-transform:uppercase; color:#8a4d0a; background:#fdf3e3;
  border:1px solid #f0d8ae; border-radius:4px; padding:3px 7px; cursor:help; }
/* The opposite finding, and it is worth saying out loud: Standard on this app is
   buying something real (nearly always custom auth, which is invisible to ARM —
   it lives in staticwebapp.config.json). Without it, "Standard" on an app that
   needs it looks identical to Standard on an app that does not. */
.rm-host-flag.is-ok{ color:#166534; background:#eefbf1; border-color:#bfe3cb; }
/* Recording an app by hand — the way in for the six apps Azure cannot match to a
   repo, and the way to correct one it matched wrongly. */
.rm-host-relink{ flex:0 0 auto; cursor:pointer; font:800 10.5px var(--f,'Inter',system-ui,sans-serif);
  color:var(--ink3); background:#fff; border:1px solid var(--border); border-radius:6px; padding:4px 9px;
  transition:color .13s, border-color .13s; }
.rm-host-relink:hover{ color:var(--_hc,#0f766e); border-color:color-mix(in srgb,var(--_hc,#0f766e) 40%,#fff); }
.rm-host-link{ margin-top:9px; }
/* The record and the world disagree — the fault four demos were hiding behind. */
.rm-host-warn{ margin-top:9px; font-size:11.5px; line-height:1.6; color:#8a3d12;
  background:#fdf3ea; border:1px solid #f0d3b6; border-left:3px solid #d97706;
  border-radius:0 8px 8px 0; padding:9px 11px; }
.rm-host-warn b{ color:#6d2f0c; }
.rm-host-warn code{ font-family:ui-monospace,Consolas,monospace; font-size:10.5px;
  background:rgba(255,255,255,.7); padding:1px 5px; border-radius:4px; }
/* One app for every demo: the standing question, answered on the demo it is
   about. Amber while it is outstanding, green once it is not — never silent,
   because "no message" reads as "nothing to do". */
.rm-host-estate{ margin-top:9px; font-size:11.5px; line-height:1.6; color:#8a4d0a;
  background:#fffaf0; border:1px solid #f0dcbb; border-radius:8px; padding:9px 11px; }
.rm-host-estate.is-on{ color:#14532d; background:#f2fbf5; border-color:#bfe3cb; }
.rm-host-estate b{ color:inherit; }
.rm-host-none{ margin-top:10px; font-size:11.5px; color:var(--ink3); line-height:1.55;
  background:#fbfdfb; border:1px dashed var(--border); border-radius:8px; padding:10px 11px; }
.rm-host-none b{ color:var(--ink2); font-family:ui-monospace,Consolas,monospace; font-weight:700; }
.rm-host-note{ margin-top:8px; font-size:11px; color:var(--ink3); line-height:1.6;
  background:color-mix(in srgb,var(--_hc) 6%,#fff);
  border:1px solid color-mix(in srgb,var(--_hc) 22%,#fff); border-radius:8px; padding:9px 11px; }
.rm-host-note b{ color:var(--ink2); }
.rm-host-peer{ display:inline-flex; align-items:center; cursor:pointer; margin:4px 4px 0 0;
  font:700 10.5px var(--f,'Inter',system-ui,sans-serif); color:var(--_hc);
  background:#fff; border:1px solid color-mix(in srgb,var(--_hc) 30%,#fff);
  border-radius:5px; padding:3px 7px; transition:background .13s; }
.rm-host-peer:hover{ background:color-mix(in srgb,var(--_hc) 10%,#fff); }
.rm-host-peer.is-lead{ font-size:11.5px; padding:4px 9px; }
/* The number somebody actually wants on a demo: what the build it demos costs. */
.rm-host-cross{ display:flex; align-items:center; gap:9px; flex-wrap:wrap; margin-top:8px;
  padding:9px 11px; border:1px dashed var(--border); border-radius:8px; background:#fbfdfb; }
.rm-host-cross-k{ flex:0 0 auto; font-size:9.5px; font-weight:800; letter-spacing:.4px;
  text-transform:uppercase; color:var(--ink3); }
.rm-host-cross-v{ flex:1 1 100%; font-size:11px; color:var(--ink3); }

/* ══ SETUP — the checklist a new repo is measured against ═══════════════════
   The shape is deliberately NOT the popup's record-card shape used by Overview
   and Connections: those answer questions, this one counts work. So it opens
   with a verdict and a bar, and the rows are a ledger — status, what it is,
   what the answer is today, and the control that changes it, in one line each.

   ⚠️ NOTHING HERE IS A CIRCLE. The status mark is a squared tile, the meter has
   a 3px radius, the row buttons are the same 8px as every other small control in
   this popup. See the note on .rm-imgbtn. */
.rm-setup{ display:flex; flex-direction:column; gap:14px; }
.rm-su-hd{ display:flex; align-items:flex-start; gap:16px;
  padding:14px 15px; border:1px solid var(--border); border-radius:12px;
  background:linear-gradient(180deg,#fbfdfb,var(--surf)); }
.rm-setup.is-clear .rm-su-hd{ border-color:#bfe3cb; background:linear-gradient(180deg,#f4fcf6,#fbfefc); }
.rm-su-hdt{ min-width:0; flex:1 1 auto; }
.rm-su-hdt b{ display:block; font-size:14.5px; font-weight:800; color:var(--ink); letter-spacing:-.25px; }
.rm-su-hdt span{ display:block; font-size:11.5px; color:var(--ink3); margin-top:4px; line-height:1.55; }
/* The fraction, big enough to read from the fraction alone. Tabular figures so
   9/11 and 10/11 do not shuffle the row sideways as things get done. */
.rm-su-score{ flex:0 0 auto; text-align:right; font-variant-numeric:tabular-nums; }
.rm-su-score b{ font-size:26px; font-weight:800; color:var(--ink); letter-spacing:-1px; line-height:1; }
.rm-su-score span{ display:block; font-size:10px; font-weight:800; letter-spacing:.4px;
  text-transform:uppercase; color:var(--ink3); margin-top:3px; }
.rm-su-meter{ height:7px; border-radius:3px; background:var(--border-s); overflow:hidden; }
.rm-su-meter span{ display:block; height:100%; border-radius:3px;
  background:linear-gradient(90deg,#3f8f63,#5cb17d); transition:width .35s ease; }
.rm-setup.is-clear .rm-su-meter span{ background:linear-gradient(90deg,#16a34a,#4ade80); }

.rm-su-grp{ border:1px solid var(--border); border-radius:12px; background:var(--surf); overflow:hidden; }
.rm-su-gh{ display:flex; align-items:baseline; gap:10px; flex-wrap:wrap;
  padding:11px 13px; background:#fbfdfb; border-bottom:1px solid var(--border-s); }
.rm-su-gh b{ font-size:12.5px; font-weight:800; color:var(--ink); }
.rm-su-gh span{ flex:1 1 160px; min-width:0; font-size:11px; color:var(--ink3); line-height:1.45; }
.rm-su-gn{ flex:0 0 auto; font-style:normal; font-size:9.5px; font-weight:800; letter-spacing:.4px;
  text-transform:uppercase; color:#8a4d0a; background:#fdf3e3; border:1px solid #f0d8ae;
  border-radius:4px; padding:3px 7px; }
.rm-su-gn.is-ok{ display:inline-flex; align-items:center; gap:4px; color:#166534; background:#eefbf1; border-color:#bfe3cb; }
.rm-su-gn.is-ok .rm-tick{ width:11px; height:11px; }

.rm-su-row{ display:flex; align-items:flex-start; gap:12px; padding:12px 13px; background:#fff; }
.rm-su-row + .rm-su-row{ border-top:1px solid var(--border-s); }
.rm-su-row.is-open{ background:#fffdf8; }
.rm-su-row.is-na{ background:#fbfbfa; }
/* The status mark: a filled tile with a tick when it is done, a hollow one when
   it is owed, a dash when it does not apply. Three states that can be told apart
   at a glance without reading a word — and colour is never the only signal. */
.rm-su-mark{ flex:0 0 auto; width:22px; height:22px; margin-top:1px; border-radius:6px;
  display:grid; place-items:center; border:1.5px solid var(--border); background:#fff; }
.rm-su-mark .rm-tick{ width:13px; height:13px; color:#fff; }
.rm-su-row.is-done .rm-su-mark{ background:#3f8f63; border-color:#3f8f63; }
.rm-su-row.is-open .rm-su-mark{ border-color:#e0b877; border-style:dashed; background:#fffaf0; }
.rm-su-row.is-na .rm-su-mark{ border-color:var(--border-s); background:var(--border-s); }
.rm-su-dash{ width:9px; height:1.5px; background:var(--ink4,#9aa4a0); border-radius:1px; }
.rm-su-txt{ min-width:0; flex:1 1 auto; }
.rm-su-txt > b{ display:block; font-size:13px; font-weight:800; color:var(--ink); letter-spacing:-.15px; }
.rm-su-row.is-na .rm-su-txt > b{ color:var(--ink3); }
/* What the answer is TODAY. The row's own subject line — heavier than the
   explanation under it, because "None found in Azure" is the finding and the
   sentence below is only why it matters. */
.rm-su-said{ display:block; font-size:11.5px; font-weight:700; color:var(--ink2); margin-top:3px;
  line-height:1.5; word-break:break-word; }
.rm-su-row.is-open .rm-su-said{ color:#8a4d0a; }
.rm-su-row.is-na .rm-su-said{ font-weight:600; color:var(--ink3); }
.rm-su-hint{ display:block; font-size:11px; color:var(--ink3); margin-top:4px; line-height:1.5; }
.rm-su-do{ flex:0 0 auto; margin-top:1px; display:inline-flex; align-items:center; gap:5px;
  cursor:pointer; font:800 11.5px var(--f,'Inter',system-ui,sans-serif);
  color:var(--c-blue); background:#fff; border:1px solid color-mix(in srgb,var(--c-blue) 30%,#fff);
  border-radius:8px; padding:6px 10px; transition:background .13s, border-color .13s, transform .13s; }
.rm-su-do:hover{ background:color-mix(in srgb,var(--c-blue) 8%,#fff); border-color:var(--c-blue); transform:translateY(-1px); }
.rm-su-do:focus-visible{ outline:2px solid var(--c-blue); outline-offset:2px; }
.rm-su-do .rm-go{ width:12px; height:12px; }
/* A done row keeps its control — you can still replace a logo — but it stops
   competing with the rows that still want something. */
.rm-su-do.is-quiet{ color:var(--ink3); border-color:var(--border); }
.rm-su-do.is-quiet:hover{ color:var(--c-blue); border-color:color-mix(in srgb,var(--c-blue) 40%,#fff); background:#fff; }
/* What a jump landed on, said once. Same gesture as the classification flash. */
.rm-host.is-flash, .rm-pane.is-flash{ animation:rmFlash 1.35s ease both; }
@media (max-width:560px){
  .rm-su-row{ flex-wrap:wrap; }
  .rm-su-do{ margin-left:34px; }
}

/* ── the connection a library CARD carries ────────────────────────────────
   *"When a repo connects to one, on that repo's card it also shows that it's
   connected, just so that we can say: hey, this demo is for this."* One line, the
   connection's colour, and it is NOT a button — the card itself already opens the
   repo, and a control inside a control is how a card stops being clickable. */
.rp-conn{ display:flex; align-items:center; gap:5px; margin-top:6px;
  font-size:10px; font-weight:800; letter-spacing:.2px; color:var(--_cc,#7c3aed);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.rp-conn svg{ width:11px; height:11px; flex:0 0 auto; opacity:.75; }
.rp-conn i{ font-style:normal; font-weight:600; color:var(--ink3); }

/* ── the company mark in the facts grid ──
   Was a 9px accent square. Now the real mark, letterboxed on white; the square
   is the fallback mountLogos() unhides when no logo file resolves. */
.rm-comark{ width:22px; height:22px; flex:0 0 auto; border-radius:5px; background:#fff;
  border:1px solid var(--border); display:grid; place-items:center; overflow:hidden; }
.rm-comark img{ width:100%; height:100%; object-fit:contain; padding:2px; display:block; }
.rm-comark-dot{ width:9px; height:9px; border-radius:2px; }

/* ══ THE PRODUCTS VIEW — a shelf of TOOLS, not repos ══════════════════════
   "There might be multiple different variations of the same tool, so we need to
   make those be groups. Make sure that groups are a thing, like a CRM, not all
   the different versions of CRMs." This is that shelf: one card per tool, and
   the builds inside it are the content of the card rather than a number on it. */
.pd-grid{ display:grid; grid-template-columns:repeat(auto-fill,minmax(300px,1fr)); gap:18px; padding:18px 4px; }
/* ⚠️ THE PRODUCT'S COLOUR IS THE ORGANISING MARK — *"the products page is where
   we really need to have the icons and styles, because that's where the
   organisation really comes in."* So the card wears its tool's colour as a
   solid left rail plus a tinted head, and every build inside it inherits the
   same one. Nothing on this page is coloured by company or by who a build is
   for; those are words, not colours. */
/* the Products page — the card IS the product, so it gets the product's own
   wash at the same 4%. */
.pd-card{ --rp-card-wash:color-mix(in srgb, var(--rp-card-c,var(--_ac,#7c5cd0)) 4%, var(--surf));
  background:var(--rp-card-wash); border:1px solid var(--border); border-radius:16px; overflow:hidden;
  display:flex; flex-direction:column; cursor:pointer; position:relative;
  transition:border-color .16s, box-shadow .16s, transform .16s; }
.pd-card::before{ content:''; position:absolute; left:0; top:0; bottom:0; width:4px; z-index:2;
  background:var(--_ac,#7c5cd0); }
.pd-card:hover{ border-color:color-mix(in srgb,var(--_ac,#7c5cd0) 55%,var(--border));
  box-shadow:0 10px 26px rgba(20,40,28,.10), 0 2px 10px color-mix(in srgb,var(--_ac,#7c5cd0) 14%,transparent);
  transform:translateY(-2px); }
.pd-card-top{ display:flex; align-items:center; gap:11px; padding:13px 14px 13px 17px;
  border-bottom:1px solid var(--border-s);
  background:linear-gradient(180deg, color-mix(in srgb,var(--_ac,#7c5cd0) 11%,#fff), var(--surf)); }
/* The mark is the app's own icon when one exists (mountProdIcons walks the
   builds), and the monogram on the product's colour when none does — so a tool
   nobody has run `sync:icons` for still reads as itself. */
.pd-card-mark{ position:relative; width:42px; height:42px; flex:0 0 auto; border-radius:11px;
  display:grid; place-items:center; overflow:hidden; background:var(--_ac,#7c5cd0);
  box-shadow:0 3px 10px color-mix(in srgb,var(--_ac,#7c5cd0) 38%,transparent), 0 0 0 1px rgba(15,23,42,.06);
  transition:background .2s; }
/* The icon rides ON TOP of the monogram at opacity 0 — never `display:none`,
   which stops the browser fetching it at all — and fades in when it lands. */
.pd-card-mark img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover;
  opacity:0; transition:opacity .2s; }
.pd-card-mark.has-icon img{ opacity:1; }
.pd-card-mark.has-icon{ background:#fff; }
.pd-card-mark i{ font-style:normal; font-size:14px; font-weight:800; letter-spacing:.3px; color:#fff; }
.pd-card-mark i[data-n="3"]{ font-size:12px; letter-spacing:0; }
.pd-card-mark i[data-n="4"]{ font-size:10px; letter-spacing:-.2px; }
.pd-card-mark.has-icon i{ opacity:0; }
.pd-card-hd{ min-width:0; flex:1 1 auto; }
.pd-card-hd b{ display:block; font-size:15.5px; font-weight:800; color:var(--ink); letter-spacing:-.3px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pd-card-hd span{ display:block; font-size:11px; color:var(--ink3); margin-top:2px; }
.pd-card-n{ flex:0 0 auto; font-size:13px; font-weight:800; color:var(--_ac,#7c5cd0);
  background:#fff; border:1px solid color-mix(in srgb,var(--_ac,#7c5cd0) 30%,#fff);
  border-radius:6px; padding:3px 8px; font-variant-numeric:tabular-nums; }
.pd-card-blurb{ font-size:11.5px; color:var(--ink3); line-height:1.5; padding:10px 14px 0; }
.pd-builds{ padding:8px 10px 10px; flex:1 1 auto; }
.pd-build{ width:100%; display:flex; align-items:center; gap:8px; text-align:left; cursor:pointer;
  background:#fff; border:1px solid var(--border-s); border-radius:7px; padding:7px 9px; margin-top:6px;
  font:inherit; transition:border-color .13s, background .13s; }
.pd-build:first-child{ margin-top:0; }
.pd-build:hover{ border-color:var(--_ac,#7c5cd0); background:#fbfdfb; }
.pd-build-co{ width:22px; height:22px; flex:0 0 auto; border-radius:5px; background:#fff;
  border:1px solid var(--border); display:grid; place-items:center; overflow:hidden; }
.pd-build-co img{ width:100%; height:100%; object-fit:contain; padding:2px; display:block; }
.pd-build-co .repos-ddmono{ display:none; font-size:9px; font-weight:800; color:var(--ink3); }
.pd-build-co.is-fallback .repos-ddmono{ display:block; }
/* a demo build is not a company's — the row says Demo and wears the play mark */
.pd-build-co.is-demo{ background:linear-gradient(180deg,#f4fbff,#e3f3fd); border-color:rgba(14,165,233,.32); }
.pd-build-co.is-demo svg{ width:12px; height:12px; stroke:#0ea5e9; fill:none; stroke-width:2;
  stroke-linecap:round; stroke-linejoin:round; margin-left:1px; }
.pd-build.is-demo b{ color:#0b6fa8; }
.pd-build.is-demo:hover{ border-color:rgba(14,165,233,.5); background:#fbfdff; }
.pd-build-t{ min-width:0; flex:1 1 auto; }
.pd-build-t b{ display:block; font-size:12px; font-weight:700; color:var(--ink2);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pd-build-t span{ display:block; font-size:10px; color:var(--ink3); margin-top:1px;
  font-family:ui-monospace,Consolas,monospace; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
/* `.pd-build-k` (the solid OURS / CLIENT / DEMO chip on every row) is gone: the
   row already names who the build is for, and a coloured badge repeating it
   competed with the one colour that carries meaning here — the product's. */
.pd-build-live{ flex:0 0 auto; width:7px; height:7px; border-radius:50%; background:#16a34a;
  box-shadow:0 0 0 2px #dcfce7; }
.pd-build-more{ display:block; font-size:10.5px; font-weight:700; color:var(--ink3); padding:8px 2px 0; }

/* ══════════════════════════════════════════════════════════════════════════
   THE SEND LEDGER, DRILLED INTO
   ══════════════════════════════════════════════════════════════════════════
   The four numbers were dead text and two of them read as the same fact. Three
   of the four are now the way into a view; the tile that is a fact and not a
   slice ("Last sent") stays a plain cell on purpose — a control that looks
   clickable and isn't is worse than a number. */
.rm-sendstat.is-go{ text-align:left; cursor:pointer; border:0; font:inherit; position:relative;
  transition:background .13s; }
.rm-sendstat.is-go:hover{ background:#f7faf8; }
.rm-sendstat.is-go::after{ content:''; position:absolute; inset:auto 0 0 0; height:3px;
  background:var(--c-blue); opacity:0; transition:opacity .14s; }
.rm-sendstat.is-go.is-on{ background:color-mix(in srgb,var(--c-blue) 7%,#fff); }
.rm-sendstat.is-go.is-on::after{ opacity:1; }
.rm-sendstat.is-go.is-on b{ color:var(--c-blue); }

.rm-sec-hint{ font-style:normal; font-size:10.5px; font-weight:600; color:var(--ink3);
  margin-left:auto; text-transform:none; letter-spacing:0; }
.rm-caret{ flex:0 0 auto; font-size:10px; color:var(--ink3); width:12px; text-align:center; }

/* a send row is a button now — it opens the receipt for that one send */
.rm-row--send.is-go{ width:100%; text-align:left; cursor:pointer; border:0; font:inherit;
  border-top:1px solid var(--border-s); background:#fff; transition:background .13s; }
.rm-list--sends .rm-row--send.is-go:first-child{ border-top:0; }
.rm-row--send.is-go:hover{ background:#f7faf8; }
.rm-row--send.is-go.is-open{ background:color-mix(in srgb,var(--c-blue) 5%,#fff); }

/* ══════════════════════════════════════════════════════════════════════════
   ⚠️⚠️ NOTHING IN THE SENDING SURFACES IS A CAPSULE
   ══════════════════════════════════════════════════════════════════════════
   Tyler, 2026-08-04: *"I don't like how these have the pill effect… even the
   buttons are just not polished. They're too big."*

   CAUSE, and it is not in this file: assets/js/dashboard-meta.js injects at
   RUNTIME

     .wt-ask-ai-fab, button:not(.ax-card):not(.tcd-view-btn):not(.tcd-filter-btn)
       :not(.tcd-ai-btn):not(.tmbp-add-btn){border-radius:var(--wt-theme-btn-radius,12px)!important}

   scoring (0,5,1). Every send row, every tab and every action here is a
   <button>, so all of them inherited the tenant's large button radius and the
   timeline read as a column of lozenges.

   ⚠️ ONE CLASS, TWO CLASSES AND THREE CLASSES ALL LOSE — WITH !important.
   Measured, not reasoned about (see the radius probe in the memory note). Only
   an id beats it, which is why `#svSurface` exists on all three sending
   surfaces and every rule below is written through it.
   🚫 Never "fix" this by lowering --wt-theme-btn-radius: every real button in
   the app wants it. */
#svSurface .sv-tl-row,
#svSurface .sv-detail,
#svSurface .sv-pcard,
#svSurface .sv-ccard,
#svSurface .sv-cwrap,
#svSurface .sv-ps,
#svSurface .sv-ps-hd,
#svSurface .sv-tab,
#svSurface .sv-findbox,
#svSurface .sv-facts,
#svSurface .sv-mail,
#svSurface .rm-btn{ border-radius:10px !important; }
/* The row and its open receipt are ONE object, so the seam between them is
   square on both sides — a rounded join reads as two stacked cards. */
#svSurface .sv-tl-row.is-open{ border-bottom-left-radius:0 !important; border-bottom-right-radius:0 !important; }
#svSurface .sv-tl-row.is-open + .sv-detail{ border-top-left-radius:0 !important; border-top-right-radius:0 !important; }
/* ⚠️ AND THE THINGS THAT REALLY ARE PILLS ARE PUT BACK, or the id fix squares
   off the status chips and the search shortcuts as collateral — they are
   capsules on purpose, everywhere in this product. */
#svSurface .sv-chip,
#svSurface .sv-dot,
#svSurface .rm-engpill,
#svSurface .sv-state,
#svSurface .sv-did,
#svSurface .sv-tab-n,
#svSurface .sv-face,
#svSurface .rm-av{ border-radius:999px !important; }
#svSurface .sv-face, #svSurface .rm-av{ border-radius:50% !important; }

/* ══════════════════════════════════════════════════════════════════════════
   THE OPTIONS MENU — four buttons' worth of actions, one control
   ══════════════════════════════════════════════════════════════════════════
   One quiet trigger on the right of the receipt's subrow. The actions inside
   are rare and one of them is destructive, so none of them earns standing
   space next to a list of people. */
.sv-acts{ position:relative; margin-left:auto; flex:0 0 auto; }
.sv-acts-btn{ display:inline-flex; align-items:center; gap:5px; cursor:pointer;
  background:var(--surf); border:1px solid var(--border); color:var(--ink2);
  font:inherit; font-size:11.5px; font-weight:700; padding:5px 9px; line-height:1.2;
  transition:background .13s, border-color .13s, color .13s; }
.sv-acts-btn:hover{ background:var(--surf-2); border-color:var(--ink4); color:var(--ink); }
.sv-acts-btn i{ font-style:normal; font-size:9px; color:var(--ink3); }
.sv-acts.is-open .sv-acts-btn{ background:var(--surf-2); border-color:var(--ink4); color:var(--ink); }
.sv-acts-menu{ display:none; position:absolute; right:0; top:calc(100% + 5px); z-index:30;
  min-width:210px; padding:4px; background:#fff; border:1px solid var(--border);
  border-radius:10px; box-shadow:0 12px 30px rgba(15,23,42,.16); }
.sv-acts.is-open .sv-acts-menu{ display:block; }
/* An item is a full-width row, not a button-looking thing — inside a menu the
   affordance is the menu. */
.sv-mi{ display:block; width:100%; text-align:left; cursor:pointer; background:transparent;
  border:0; border-radius:7px; font:inherit; font-size:12.5px; font-weight:600;
  color:var(--ink); padding:7px 9px; transition:background .11s, color .11s; }
.sv-mi:hover{ background:var(--surf-2); }
.sv-mi:disabled{ color:var(--ink4); cursor:not-allowed; background:transparent; }
/* ⚠️ THE DESTRUCTIVE ONE IS RED ONLY ON HOVER, and it is last in the list. As a
   standing red button it was the brightest thing on a receipt whose subject is
   who was emailed; here it is a normal row until you reach for it. */
.sv-mi.is-danger{ color:var(--c-red,#dc2626); }
.sv-mi.is-danger:hover{ background:color-mix(in srgb,var(--c-red,#dc2626) 10%,#fff); }
.sv-mi.is-danger:disabled{ color:var(--ink4); background:transparent; }
/* The trigger and its rows keep their own shapes under the id scope. */
#svSurface .sv-acts-btn{ border-radius:8px !important; }
#svSurface .sv-mi{ border-radius:7px !important; }
#svSurface .sv-acts-menu{ border-radius:10px !important; }
.sv-subrow{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; }

/* the expanded receipt: the words that went, then everyone on it */
.sv-detail{ border-top:1px solid var(--border-s); background:#fbfdfb; padding:11px 12px 12px; }
.sv-facts{ display:grid; grid-template-columns:repeat(auto-fit,minmax(140px,1fr)); gap:1px;
  background:var(--border-s); border:1px solid var(--border-s); border-radius:8px; overflow:hidden; }
.sv-fact{ background:#fff; padding:8px 10px 9px; min-width:0; }
.sv-fact span{ display:block; font-size:9px; font-weight:800; text-transform:uppercase;
  letter-spacing:.5px; color:var(--ink3); }
.sv-fact b{ display:block; font-size:12px; font-weight:700; color:#26332c; margin-top:3px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.sv-sub{ font-size:10px; font-weight:800; text-transform:uppercase; letter-spacing:.5px;
  color:var(--ink3); margin:12px 0 7px; }

/* ══════════════════════════════════════════════════════════════════════════
   THE SENDING VIEW — the same list, on the page instead of in a popup
   ══════════════════════════════════════════════════════════════════════════
   Every `sv-` rule in this file is deliberately UNSCOPED, which is what lets
   the ledger render in the page body without a second stylesheet. This block
   is only what the page needs and the popup does not: a card to sit the list
   on (the popup's own panel was doing that job), the three tabs, and the chip
   naming which demo a row is about.
   ⚠️ Tokens resolve here because this is inside `.repos-page`. A dialog
   appended to <body> gets none of them and paints black on black — that trap
   is why the old History modal was written with literal colours. */
.sv-page{ background:var(--surf); border:1px solid var(--border); border-radius:14px;
  padding:14px 16px 16px; display:flex; flex-direction:column; gap:14px; }

/* The three tabs. Deliberately not `.rm-tab`: those are the popup's, sized for
   a dialog header, and one shared class would tie two layouts together. */
.sv-tabs{ display:flex; align-items:center; gap:6px; flex-wrap:wrap;
  border-bottom:1px solid var(--border-s); padding-bottom:11px; }
.sv-tab{ display:inline-flex; align-items:center; gap:7px; border:1px solid transparent;
  background:transparent; border-radius:9px; padding:6px 11px; cursor:pointer;
  font:inherit; font-size:12.5px; font-weight:700; color:var(--ink2);
  transition:background .13s, color .13s, border-color .13s; }
.sv-tab:hover{ background:var(--surf-2); color:var(--ink); }
.sv-tab.is-on{ background:#eef4ff; border-color:color-mix(in srgb,var(--c-blue) 34%,transparent);
  color:var(--c-blue); }
/* The count rides the tab, in the tab's own colour — three numbers that get
   smaller left to right, which is why the note beside them explains itself. */
.sv-tab-n{ font-size:11px; font-weight:800; color:var(--ink3); font-variant-numeric:tabular-nums; }
.sv-tab.is-on .sv-tab-n{ color:var(--c-blue); }
.sv-tabs-note{ margin-left:auto; font-size:11px; color:var(--ink3); font-weight:600; }
@media (max-width:720px){ .sv-tabs-note{ margin-left:0; flex-basis:100%; } }

/* WHAT WENT, on a fleet row. The only genuinely new thing in the list, and it
   reads as the subject of the row, so it leads and it is the row's accent
   rather than the muted grey the client name uses. */
.sv-tl-what{ color:var(--c-blue); font-weight:800; }

/* ══════════════════════════════════════════════════════════════════════════
   SEARCHING THE LEDGER
   ══════════════════════════════════════════════════════════════════════════
   One box over the list, shaped like the library's own search so it reads as
   the same control in a smaller room. The chips beside it are shortcuts INTO
   that box — they type a word into it rather than filtering separately, so
   there is only ever one thing to read and one thing to clear. */
.sv-find{ display:flex; align-items:center; gap:9px; flex-wrap:wrap; margin:-4px 0 -2px; }
.sv-findbox{ display:inline-flex; align-items:center; gap:8px; flex:1 1 240px; min-width:0;
  background:var(--surf); border:1px solid var(--border); border-radius:10px; padding:0 10px; height:36px;
  transition:border-color .14s, box-shadow .14s; }
.sv-findbox:focus-within{ border-color:var(--c-blue);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--c-blue) 14%,transparent); }
.sv-findbox svg{ flex:0 0 auto; stroke:var(--ink3); }
.sv-findbox input{ flex:1 1 auto; min-width:0; border:0; outline:0; background:transparent; font:inherit;
  font-size:12.5px; color:var(--ink); }
/* The browser's own clear cross sits at a different size in every engine and
   ignores the ✕ we drew — one control, ours. */
.sv-findbox input::-webkit-search-cancel-button,
.sv-findbox input::-webkit-search-decoration{ -webkit-appearance:none; appearance:none; }
.sv-findx{ flex:0 0 auto; border:0; background:none; cursor:pointer; font:inherit; font-size:12px;
  color:var(--ink3); padding:2px 3px; border-radius:5px; transition:color .12s, background .12s; }
.sv-findx:hover{ color:var(--ink); background:var(--border-s); }
.sv-chips{ display:inline-flex; gap:6px; flex-wrap:wrap; }
.sv-chip{ border:1px solid var(--border); background:var(--surf); cursor:pointer; font:inherit;
  font-size:11px; font-weight:700; color:var(--ink2); padding:5px 10px; border-radius:8px;
  transition:border-color .13s, background .13s, color .13s; }
.sv-chip:hover{ border-color:var(--c-blue); color:var(--c-blue); }
.sv-chip.is-on{ background:color-mix(in srgb,var(--c-blue) 12%,#fff); border-color:var(--c-blue);
  color:color-mix(in srgb,var(--c-blue) 72%,#0b1a12); }
/* What the filter did, in one line, with the way out on the end of it. */
.sv-findsum{ flex:1 1 100%; display:flex; align-items:center; gap:8px; font-size:11.5px; color:var(--ink3); }
.sv-findsum b{ color:var(--ink); font-weight:800; font-variant-numeric:tabular-nums; }
.sv-sumx{ border:0; background:none; cursor:pointer; font:inherit; font-size:11.5px; font-weight:700;
  color:var(--c-blue); padding:0; text-decoration:underline; text-underline-offset:2px; }
.sv-none i{ font-style:normal; font-weight:700; color:var(--ink2); }
/* A tile whose number is a slice of the ledger rather than all of it. */
.rm-sendstat.is-filtered b{ color:var(--c-blue); }

/* ── the rows moving out of the way ───────────────────────────────────────
   ⚠️ NOTHING IS RE-RENDERED WHILE YOU TYPE (see applySendFilter): a row is told
   to go and CSS takes it out, so the survivors slide up instead of the list
   blinking. `height:auto → 0` only interpolates where `interpolate-size` is
   supported; everywhere else the fade still plays and the collapse simply
   happens at once, which is the right thing to degrade to. */
.sv-body{ interpolate-size:allow-keywords; }
[data-fkey]{ overflow:hidden;
  transition:opacity .17s ease, transform .17s ease, height .22s ease,
             margin .22s ease, padding .22s ease, border-width .22s ease; }
[data-fkey].sv-hid{ opacity:0; transform:translateY(-5px); height:0; pointer-events:none;
  padding-top:0; padding-bottom:0; margin-top:0; margin-bottom:0; border-top-width:0; border-bottom-width:0; }

/* ── people, as cards ─────────────────────────────────────────────────────
   A person is a face, a name, an address and their whole history with this
   build — in one row, so a list of them is scannable rather than four columns
   of text you have to line up by eye.
   ⚠️ MARGIN, NOT `gap`. A collapsed grid item still leaves its gap behind, so a
   filtered-out list would close up into a column of 7px holes. The spacing
   belongs to the row, which means it collapses with the row. */
.sv-people{ display:block; margin-bottom:-7px; }
.sv-people > *{ margin-bottom:7px; }
.sv-pcard{ display:flex; align-items:center; gap:10px; background:#fff;
  border:1px solid var(--border-s); border-radius:9px; padding:9px 11px;
  transition:border-color .15s, box-shadow .15s; }
/* Somebody the search actually NAMED, as opposed to a colleague who was on the
   same email. Both stay on the list; only one of them is what you asked for. */
.sv-pcard.is-hit{ border-color:color-mix(in srgb,var(--c-blue) 45%,var(--border));
  box-shadow:0 0 0 2px color-mix(in srgb,var(--c-blue) 13%,transparent); }
/* ── their actual face ────────────────────────────────────────────────────
   Initials underneath, the CRM's photo laid over them and faded in once it has
   arrived (mountFaces appends it only on load, so there is never a white box
   waiting for a round trip). A 404, a signed-out CRM or somebody who is not in
   it leaves the letters — which is an answer, where a hole is not. */
.sv-face{ position:relative; flex:0 0 auto; width:32px; height:32px; border-radius:8px; overflow:hidden;
  display:grid; place-items:center; background:linear-gradient(150deg,#7c8f83,#55655c); }
.sv-face-mono{ font-style:normal; font-size:11px; font-weight:800; letter-spacing:.3px; color:#fff; }
.sv-face-img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; display:block;
  animation:svFaceIn .22s ease both; }
.sv-face.has-face{ background:#fff; }
@keyframes svFaceIn{ from{ opacity:0 } to{ opacity:1 } }

/* ══ THE SENDING TIMELINE ═══════════════════════════════════════════════════
   Modelled on Quotely's activity-timeline: a vertical rail, one marker per event
   punched through it, the title with a right-aligned tabular time, the detail
   underneath. The one change is that THE MARKER IS THE PERSON — Quotely uses
   colour-coded dots, and a send is something you did to somebody, so their face
   reads faster down a column than a dot does.
   ⚠️ The rail is drawn on the CONTAINER, not per row, so it cannot break into
   dashes when a row is open (the receipt makes rows very unequal heights). */
.sv-tl{ position:relative; padding:6px 0 2px 0; }
.sv-tl::before{ content:''; position:absolute; left:19px; top:14px; bottom:14px; width:2px;
  background:linear-gradient(#e4eae5, #eef2ee); border-radius:2px; }

/* ── the day heading: a NODE ON the rail, not a bar across it ────────────────
   Same-day sends group under one of these, and each new day is a visible stop on
   the line. It sits ON the rail (a ringed dot at the rail's own x) so the line
   appears to pass through the date rather than stopping at it — a full-width
   divider would cut the timeline into unrelated blocks, which is the opposite of
   what a timeline is for.
   ⚠️ The dot is 10px inside a 3px page-coloured ring, at left:15px, so its CENTRE
   lands on the rail at left:19px+1. Change one, change both. */
.sv-tl-day{ position:relative; display:flex; align-items:baseline; gap:9px;
  padding:14px 0 6px 44px; }
.sv-tl-day:first-child{ padding-top:4px; }
.sv-tl-daydot{ position:absolute; left:15px; top:16px; width:10px; height:10px; border-radius:50%;
  background:#c9d5cd; box-shadow:0 0 0 3px #fff; }
.sv-tl-day:first-child .sv-tl-daydot{ top:6px; }
.sv-tl-day b{ font-size:11px; font-weight:800; letter-spacing:.07em; text-transform:uppercase;
  color:#0f172a; }
.sv-tl-day span{ font-size:10.5px; color:#98a89e; }
/* "Still to go" is not a day — it is the group that can still be acted on, so it
   takes the accent and a hollow ring to read as pending rather than past. */
.sv-tl-day.is-sched b{ color:#0b6fb2; }
.sv-tl-day.is-sched .sv-tl-daydot{ background:#fff; border:2.5px solid #0b6fb2;
  width:11px; height:11px; box-shadow:0 0 0 3px #fff; }
.sv-tl-day.sv-hid{ display:none; }
.sv-tl-row{ position:relative; display:flex; align-items:flex-start; gap:12px; width:100%;
  padding:10px 12px 10px 0; border:0; background:transparent; cursor:pointer;
  font:inherit; text-align:left; border-radius:11px; transition:background .13s ease; }
.sv-tl-row:hover{ background:#f6f9f7; }
.sv-tl-row.is-open{ background:#f2f7f4; }
/* the marker: the face, ringed in the page colour so the rail appears to pass
   behind it rather than stopping at it */
.sv-tl-mark{ position:relative; flex:0 0 auto; margin-left:4px; }
.sv-tl-mark .sv-face{ box-shadow:0 0 0 3px #fff, 0 0 0 4.5px #e4eae5; }
.sv-tl-row.is-sched .sv-tl-mark .sv-face{ box-shadow:0 0 0 3px #fff, 0 0 0 4.5px #0b6fb2; }
.sv-tl-row.is-bad  .sv-tl-mark .sv-face{ box-shadow:0 0 0 3px #fff, 0 0 0 4.5px #ef4444; }
.sv-tl-row.is-part .sv-tl-mark .sv-face{ box-shadow:0 0 0 3px #fff, 0 0 0 4.5px #d97706; }
.sv-tl-row.is-pulled .sv-tl-mark{ opacity:.5; }
/* how many others were on it, and the state glyph — both corner badges on the
   face, so the row needs no extra columns */
.sv-tl-n, .sv-tl-g{ position:absolute; font-style:normal; font-weight:800; line-height:1;
  border-radius:999px; background:#0f172a; color:#fff; }
.sv-tl-n{ right:-7px; bottom:-5px; font-size:9.5px; padding:2px 4px; box-shadow:0 0 0 2px #fff; }
.sv-tl-g{ left:-8px; top:-6px; font-size:9px; padding:2px 4px; box-shadow:0 0 0 2px #fff; }
.sv-tl-row.is-sched .sv-tl-g{ background:#0b6fb2; }
.sv-tl-row.is-bad .sv-tl-g, .sv-tl-row.is-part .sv-tl-g{ background:#d97706; }
.sv-tl-row.is-pulled .sv-tl-g{ background:#94a3b8; }

.sv-tl-body{ flex:1 1 auto; min-width:0; display:flex; flex-direction:column; gap:3px; padding-top:2px; }
.sv-tl-head{ display:flex; align-items:baseline; gap:10px; }
.sv-tl-t{ flex:1 1 auto; min-width:0; font-size:13.5px; font-weight:700; color:#0f172a;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.sv-tl-row.is-pulled .sv-tl-t{ text-decoration:line-through; color:#64748b; }
/* tabular, so a column of times lines up — same reason as Quotely's .qtl-when */
.sv-tl-when{ flex:0 0 auto; font-size:11px; color:#8a9a90; white-space:nowrap;
  font-variant-numeric:tabular-nums; }
.sv-tl-row.is-sched .sv-tl-when{ color:#0b6fb2; font-weight:700; }
.sv-tl-sub{ font-size:11.5px; color:#6b7a71; line-height:1.5; }
.sv-tl-sub b{ color:#0f172a; font-weight:700; }
.sv-tag{ display:inline-block; font-size:9.5px; font-weight:800; letter-spacing:.06em;
  text-transform:uppercase; padding:2px 6px; border-radius:999px; }
.sv-tag.is-sched{ background:#e7f2fb; color:#0b6fb2; }
.sv-tag.is-pulled{ background:#f1f5f9; color:#64748b; }
.sv-tl-row .rm-caret{ flex:0 0 auto; align-self:center; color:#c3cdc7; font-size:11px; }
/* the count in the section heading, for the group that can still be acted on */
.sv-pendn{ margin-left:8px; font-size:10.5px; font-weight:800; letter-spacing:.04em;
  text-transform:uppercase; color:#0b6fb2; background:#e7f2fb; padding:3px 8px; border-radius:999px; }
.sv-sub--sched{ color:#0b6fb2; }
.sv-stop{ margin-right:8px; }
/* ⚠️ WE NEVER SEE A REPLY. SendGrid reports delivered/opened/clicked; a reply
   goes to the sender's own inbox and nothing in this product reads it. So the
   honest affordance is a way to go and ask — quiet until you want it. */
.sv-act{ flex:0 0 auto; font-size:10.5px; font-weight:800; letter-spacing:.2px; text-decoration:none;
  color:var(--ink3); border:1px solid transparent; border-radius:7px; padding:4px 9px;
  transition:color .13s, border-color .13s, background .13s; }
.sv-pcard:hover .sv-act, .sv-act:focus-visible{ color:var(--c-blue);
  border-color:color-mix(in srgb,var(--c-blue) 34%,var(--border)); background:color-mix(in srgb,var(--c-blue) 7%,#fff); }
/* the receipt's own action row: what this send was, and doing it again */
.sv-subrow{ display:flex; align-items:center; gap:10px; }
.sv-subrow .sv-sub{ margin-bottom:7px; }
.sv-again{ margin:12px 0 7px auto; font-size:11.5px; padding:6px 11px; }
.sv-pmain{ min-width:0; flex:1 1 auto; }
.sv-pmain b{ display:block; font-size:13px; font-weight:800; color:var(--ink); letter-spacing:-.1px;
  text-transform:capitalize; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.sv-pmail{ display:block; font-size:11px; color:var(--ink3); font-family:ui-monospace,Consolas,monospace;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.sv-pco{ display:inline-flex; align-items:center; gap:5px; margin-top:4px; font-size:10.5px;
  font-weight:700; color:var(--ink2); }
.sv-pco-log{ width:16px; height:16px; border-radius:4px; background:#fff; border:1px solid var(--border);
  display:grid; place-items:center; overflow:hidden; }
.sv-pco-log img{ width:100%; height:100%; object-fit:contain; padding:1px; display:block; }
.sv-pco-log .repos-ddmono{ display:none; font-size:7px; font-weight:800; color:var(--ink3); }
.sv-pco-log.is-fallback .repos-ddmono{ display:block; }
.sv-pmeta{ flex:0 0 auto; text-align:center; }
.sv-pmeta b{ display:block; font-size:14px; font-weight:800; color:var(--ink);
  font-variant-numeric:tabular-nums; }
.sv-pmeta span{ display:block; font-size:9px; font-weight:800; text-transform:uppercase;
  letter-spacing:.4px; color:var(--ink3); }
.sv-pwhen{ flex:0 0 auto; font-size:11px; color:var(--ink3); min-width:58px; text-align:right; }

/* ── companies, as cards you can open ─────────────────────────────────────
   The company number exists BECAUSE a company holds several people, so the
   company card's job is to open onto them. */
/* margin rather than gap, for the same reason .sv-people carries one */
.sv-cos{ display:block; margin-bottom:-8px; }
.sv-cos > *{ margin-bottom:8px; }
.sv-cwrap{ border:1px solid var(--border-s); border-radius:10px; overflow:hidden; background:#fff; }
.sv-ccard{ width:100%; display:flex; align-items:center; gap:11px; text-align:left; cursor:pointer;
  background:#fff; border:0; padding:10px 12px; font:inherit; transition:background .13s; }
.sv-ccard:hover{ background:#f7faf8; }
.sv-ccard.is-open{ background:color-mix(in srgb,var(--c-blue) 5%,#fff); }
/* WHITE GROUND for the mark, monogram when there is no logo to show — never
   somebody else's logo because a name half-matched. */
.sv-clog{ flex:0 0 auto; width:34px; height:34px; border-radius:8px; background:#fff;
  border:1px solid var(--border); display:grid; place-items:center; overflow:hidden; }
.sv-clog img{ width:100%; height:100%; object-fit:contain; padding:3px; display:block; }
.sv-clog .repos-ddmono{ display:none; font-size:11px; font-weight:800; color:var(--ink3); }
.sv-clog.is-fallback .repos-ddmono{ display:block; }
.sv-cmain{ min-width:0; flex:1 1 auto; }
.sv-cmain b{ display:block; font-size:13.5px; font-weight:800; color:var(--ink); letter-spacing:-.2px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.sv-cmain span{ display:block; font-size:11px; color:var(--ink3); margin-top:2px; }
.sv-cwhen{ flex:0 0 auto; font-size:11px; color:var(--ink3); }

@media (max-width:640px){
  .sv-pcard{ flex-wrap:wrap; }
  .sv-pmeta,.sv-pwhen{ text-align:left; min-width:0; }
}

/* ══════════════════════════════════════════════════════════════════════════
   SCHEDULED — one colour, everywhere, and it is AMBER
   ══════════════════════════════════════════════════════════════════════════
   Tyler: *"it should say Scheduled right here in my screenshot, so it's super easy
   to see… I want to fucking see everything."*

   ⚠️ THE "STILL TO GO" GROUP WAS THE SAME BLUE (#0b6fb2) AS THE REST OF THE
   TIMELINE, and blue is this page's colour for "informational" — it appears on
   every ordinary row, every client chip and the page accent itself. So the one
   group that has not happened yet was tinted like all the ones that had. Amber is
   the library's existing word for "waiting on a clock" (it is already the tier
   warning, the "needs a label" card and the partial-failure marker), and it is
   used for every surface of this feature: the day heading, the row's ring and
   glyph, the tag, the section count, the tile, the tab badge and the card flag.
   Deliberately NOT red: nothing is wrong with a scheduled send, and a red badge on
   every demo somebody queued an email for teaches the eye to ignore the colour
   that does mean broken.
   These override the blue above rather than editing it in place, so the diff
   against the timeline redesign stays legible as "the scheduled state changed
   colour" instead of being tangled through 40 lines of unrelated rules. */
.sv-tl-day.is-sched b{ color:#8a5209; }
.sv-tl-day.is-sched span{ color:#b45309; }
.sv-tl-day.is-sched .sv-tl-daydot{ border-color:#d97706; }
.sv-tl-row.is-sched .sv-tl-mark .sv-face{ box-shadow:0 0 0 3px #fff, 0 0 0 4.5px #d97706; }
.sv-tl-row.is-sched .sv-tl-g{ background:#d97706; }
.sv-tl-row.is-sched .sv-tl-when{ color:#8a5209; }
.sv-tag.is-sched{ background:#d97706; color:#fff; }
.sv-pendn{ color:#fff; background:#d97706; }
.sv-sub--sched{ color:#8a5209; }

/* ⚠️ THE WHOLE GROUP IS TINTED, not just its heading. A row that has not gone is a
   different KIND of thing from the ones under it, and a band of colour is what
   makes that readable while scrolling past — which is the entire complaint. The
   dashed left edge is the second half of it: solid is a record of something that
   happened, dashed is a promise. */
.sv-tl-row.is-sched{ background:color-mix(in srgb,#d97706 6%,#fff);
  border-left:3px dashed #d97706; padding-left:9px; margin-left:-12px; }
.sv-tl-row.is-sched:hover{ background:color-mix(in srgb,#d97706 11%,#fff); }
.sv-tl-row.is-sched.is-open{ background:color-mix(in srgb,#d97706 13%,#fff); }
/* The heading flashes when the "Still to go" tile is clicked — scrolling to
   something already on screen otherwise looks like nothing happened. */
.sv-tl-day.is-sched.is-flash{ animation:rmSchedFlash 1.4s ease both; border-radius:10px; }
@keyframes rmSchedFlash{
  0%,100%{ box-shadow:0 0 0 0 transparent; background:transparent; }
  20%,60%{ box-shadow:0 0 0 6px rgba(217,119,6,.26); background:rgba(217,119,6,.1); }
}

/* The sixth tile — amber, and it exists only while the queue does. */
.rm-sendstat--q{ background:color-mix(in srgb,#d97706 8%,#fff) !important; }
.rm-sendstat--q b, .rm-sendstat--q span{ color:#8a5209; }
.rm-sendstat--q::after{ background:#d97706 !important; opacity:1 !important; }
.rm-sendstat-when{ display:block; font-style:normal; font-size:10px; font-weight:700;
  color:#b45309; margin-top:2px; text-transform:none; letter-spacing:0; }

/* The tab's amber count, beside the delivered one and never merged into it —
   the two are different kinds of fact. */
.rm-tab .tq{ font-size:10.5px; font-weight:900; background:#d97706; color:#fff;
  padding:1px 7px; border-radius:8px; margin-left:4px; font-variant-numeric:tabular-nums; }

/* ⚠️ THE CARD FLAG — the only thing in that corner that is not a fault, which is
   why it is amber rather than the reds beside it. It is how a queued send is
   visible from a shelf of forty cards without opening anything. */
.rp-flag.is-sched{ background:#d97706; color:#fff;
  display:inline-flex; align-items:center; gap:4px; }
.rp-flag.is-sched svg{ width:10px; height:10px; }

/* "See the email that went" — the archived copy, beside "send it again" on the
   receipt. A plain outline button: it opens a record and changes nothing, so it
   must not compete with either the affirmative action or the danger one. */
.sv-seeit{ margin-right:8px; }
.sv-seeit[disabled]{ opacity:.55; cursor:progress; }

/* ── WHO SENT IT ──────────────────────────────────────────────────────────
   A face and a name in the middle of the row's second line, and a button
   because it filters. Sits on the baseline of the text around it rather than
   in a box of its own — it is one item in a sentence of facts, not a control
   bolted onto the end of one. */
.sv-by{ display:inline-flex; align-items:center; gap:5px; vertical-align:-4px;
  border:1px solid transparent; border-radius:999px; padding:1px 7px 1px 2px; margin:0 1px;
  background:none; font:inherit; color:var(--ink2); font-weight:700; cursor:pointer;
  transition:background .13s, border-color .13s, color .13s; }
/* ⚠️ THE SHARED FACE TILE IS 32px AND THIS LINE IS 11px TEXT. Scaling the tile
   down here rather than adding a second faceBox size keeps ONE face component:
   the hydrator, the fallback monogram and the decode rule all still apply. */
.sv-by .sv-face{ width:17px; height:17px; border-radius:5px; }
.sv-by .sv-face-mono{ font-size:7.5px; letter-spacing:0; }
.sv-by:hover{ background:color-mix(in srgb,var(--c-blue) 8%,#fff); color:var(--c-blue);
  border-color:color-mix(in srgb,var(--c-blue) 30%,var(--border)); }
.sv-by:focus-visible{ outline:2px solid var(--c-blue); outline-offset:1px; }

/* HOW LONG THEY TOOK, riding on the pill that says they opened it. Lighter and
   un-italicised-looking on purpose: it is a qualifier on the number beside it,
   and at equal weight the two would compete for the same glance. */
.rm-engpill i, .sv-eng i{ font-style:normal; font-weight:600; opacity:.72;
  margin-left:4px; letter-spacing:0; }

/* ── the three actions on a pending receipt ───────────────────────────────
   Send it now · Change the time · Cancel this send. Three buttons of equal
   weight would mean reading all three every time, so the hierarchy IS the
   affordance: send-it-now is the affirmative one and carries the only fill,
   change-the-time stays a plain outline because it destroys nothing, and cancel
   keeps its danger styling as the last resort it is. */
.sv-now{ margin-right:8px; background:var(--c-blue); color:#fff; border-color:var(--c-blue); }
/* ⚠️ THE FILL HAS TO BE RESTATED ON HOVER. .rm-btn:hover recolours the LABEL to
   var(--c-blue) and leaves the background alone — correct for an outline button,
   but on a filled one it paints blue text on a blue fill and the label vanishes. */
.sv-now:hover{ background:var(--c-blue); color:#fff; border-color:var(--c-blue);
  filter:brightness(1.07); transform:translateY(-1px); }
.sv-now:active{ transform:translateY(0); }
/* Change the time, beside Cancel on a pending receipt. Quieter than the danger
   button next to it, because it is the one you will reach for more often and it
   destroys nothing. */
.sv-move{ margin-right:8px; }
.rm-btn.is-danger[disabled]{ opacity:.45; cursor:default; }

/* A grid-view filter that matched nothing, saying what it filtered. */
.repos-empty-why{ display:block; margin-top:7px; font-size:12px; font-weight:500;
  color:var(--ink3); max-width:52ch; }

/* ══════════════════════════════════════════════════════════════════════════
   THE TIMELINE ROW, REBUILT — the people it went to, and whether it went
   ══════════════════════════════════════════════════════════════════════════
   Tyler: *"this timeline UI is super confusing. When I try to click on the people
   to see what it is, it just opened up Tyler Bonahoom. I'm trying to specifically
   see people that I've sent to and see all of them… did the demos actually get
   sent? There needs to be a confirmation."*

   Two things were wrong and one was invisible:
   · The SENDER was a face-plus-name button inside the one-line sub-row, so it
     WRAPPED — every send rendered a stray "Tyler Bonahoom" line above it, and
     clicking that filtered the whole timeline instead of opening the send. It has
     moved into the receipt, where it has room and where it was asked for.
   · The marker was the FIRST recipient only, with a "+2". A send to three people
     looked like a send to one, and the two you could not see were the ones you
     opened the row to find. Now up to three faces overlap on the rail.
   · Nothing said whether an ordinary send had actually GONE. Only `scheduled` and
     `pulled back` spoke; a delivered send said "3 sent" in grey among a line of
     counts. Every row now leads with a state chip. */

/* Three faces, overlapping, tightest on the rail. Reverse row order so the FIRST
   recipient sits on top — the list reads left to right, and the one you named
   first should be the one you can see. */
.sv-tl-faces{ display:flex; flex-direction:row-reverse; align-items:center;
  justify-content:flex-end; }
.sv-tl-faces .sv-face{ margin-left:-11px; }
.sv-tl-faces .sv-face:last-child{ margin-left:0; }         /* = the first recipient */
.sv-tl-mark.is-many .sv-tl-faces .sv-face{ width:27px; height:27px; }
/* Only the top face grows on hover — three of them swelling at once is a wobble,
   not an affordance. */
.sv-tl-row:hover .sv-tl-faces .sv-face{ transform:none; }
.sv-tl-row:hover .sv-tl-faces .sv-face:last-child{ transform:scale(1.07); }

/* ══ THE STATE CHIP — the confirmation, first on the line, always present ═══
   Colour carries the meaning and the word repeats it, because a colour alone is
   not an answer and a word alone is not scannable down thirty rows. */
.sv-tag{ text-transform:uppercase; }
.sv-tag.is-sent{ background:#dcfce7; color:#15803d; }
.sv-tag.is-part{ background:#fef3c7; color:#92400e; }
.sv-tag.is-none{ background:#fee2e2; color:#b91c1c; }
/* SCHEDULED stays the loudest: it is the one state where nothing has happened yet
   and something still can be done about it. */
.sv-tag.is-sched{ background:#d97706; color:#fff; }
.sv-tag.is-pulled{ background:#e9eef2; color:#64748b; text-decoration:line-through; }

/* ══ WHAT WAS SENT — the receipt's headline, not a grid cell ════════════════
   An email-shaped block: who it was from, when it went, the subject as a subject
   and the words as words. It is the copy taken at send time, never a re-render —
   see the note in viewSends. */
.sv-mail{ border:1px solid var(--border-s); border-left:3px solid var(--c-blue);
  border-radius:11px; background:var(--surf); overflow:hidden; margin-bottom:11px; }
.sv-mail-hd{ display:flex; align-items:center; gap:10px; flex-wrap:wrap;
  padding:9px 13px; background:#f8faf9; border-bottom:1px solid var(--border-s); }
.sv-mail-when{ margin-left:auto; font-size:10.5px; color:var(--ink3); white-space:nowrap; }
.sv-mail-when i{ font-style:normal; opacity:.75; }
.sv-mail-subj{ padding:12px 15px 0; font-size:14.5px; font-weight:800; color:var(--ink);
  line-height:1.35; }
.sv-mail-body{ padding:8px 15px 14px; font-size:13px; line-height:1.62; color:var(--ink2); }
.sv-mail-body p{ margin:0 0 9px; }
.sv-mail-body p:last-child{ margin-bottom:0; }
.sv-mail-body.is-none{ color:var(--ink3); font-style:italic; font-size:12px; }

/* The sender, where it belongs. A real control with room for a face and a name —
   the same click-to-filter it always had, minus the wrapping. */
.sv-by{ display:inline-flex; align-items:center; gap:7px; border:1px solid var(--border-s);
  background:var(--surf); border-radius:9px; padding:3px 10px 3px 4px; cursor:pointer;
  font:inherit; font-size:12px; font-weight:750; color:var(--ink);
  transition:border-color .12s, background .12s; }
.sv-by:hover{ border-color:var(--c-blue); background:color-mix(in srgb,var(--c-blue) 6%,#fff); }
.sv-by .sv-face{ width:24px; height:24px; border-radius:7px; }
.sv-by.is-none{ color:var(--ink3); font-weight:600; font-style:italic; cursor:default; }
.sv-by.is-none:hover{ border-color:var(--border-s); background:var(--surf); }

@media (max-width:620px){
  .sv-mail-when{ margin-left:0; width:100%; }
}

/* ══════════════════════════════════════════════════════════════════════════
   THE PERSON POPUP — what one person was actually sent
   ══════════════════════════════════════════════════════════════════════════
   Tyler: *"I should be able to click on each person's card, and it'll pull up the
   popup of what they actually sent. That's why I don't need the 'Tyler Bonahoom
   shared the demo with you' and showing the when it's sent and the scheduled and
   all that, because in that card popup, it'll show me that data. The only thing I
   care about is that on this day, it was sent to these people."*

   So the timeline row lost the email block, the facts grid and the engagement pills,
   and all three arrived here — about ONE person, ONE send, where they can be precise
   instead of averaged. It rides the existing `.rm-sheet` skin (one dialog, one scrim,
   one ✕, one Esc) and mounts inside `.rm-backdrop`, which is not a style choice: a
   dialog in <body> paints UNDERNEATH the popup because of the backdrop-filter. */

/* The card advertises itself as a door. */
.sv-pcard.is-go{ cursor:pointer; transition:border-color .13s ease, background .13s ease, transform .13s ease; }
.sv-pcard.is-go:hover{ border-color:var(--c-blue); background:color-mix(in srgb,var(--c-blue) 4%,#fff); }
.sv-pcard.is-go:focus-visible{ outline:2px solid var(--c-blue); outline-offset:2px; }
/* A caret would be a fifth thing on an already busy row; the whole card lifting a
   hair is the affordance, and it costs no space. */
@media (prefers-reduced-motion:no-preference){
  .sv-pcard.is-go:hover{ transform:translateY(-1px); }
}
.sv-sub-hint{ display:block; font-style:normal; font-size:10.5px; color:var(--ink3);
  font-weight:500; margin-top:2px; }

/* Who this is about, at the top of the dialog. */
.sv-phd{ display:flex; align-items:center; gap:11px; padding-bottom:12px;
  border-bottom:1px solid var(--border-s); margin-bottom:12px; }
.sv-phd .sv-face{ width:40px; height:40px; border-radius:11px; }
.sv-phd-id{ flex:1 1 auto; min-width:0; display:flex; flex-direction:column; gap:1px; }
.sv-phd-id b{ font-size:15px; font-weight:800; color:var(--ink); }
.sv-phd-id > span{ font-size:11.5px; color:var(--ink3); overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap; }
.sv-phd-co{ display:inline-flex; align-items:center; gap:5px; font-size:11px;
  color:var(--ink2); font-weight:650; margin-top:3px; }
.sv-psub{ font-size:10.5px; font-weight:800; letter-spacing:.5px; text-transform:uppercase;
  color:var(--ink3); margin-bottom:8px; }

/* One send they are on. Collapsed it is a state, a date and what they did — which is
   usually the whole answer. Expanded it is the email. */
.sv-pslist{ display:flex; flex-direction:column; gap:9px; }
.sv-ps{ border:1px solid var(--border-s); border-radius:11px; overflow:hidden;
  background:var(--surf); }
.sv-ps.is-open{ border-color:color-mix(in srgb,var(--c-blue) 40%,var(--border-s)); }
.sv-ps-hd{ display:flex; align-items:center; gap:9px; width:100%; padding:9px 12px;
  border:0; background:#f8faf9; cursor:pointer; font:inherit; text-align:left; }
.sv-ps-hd:hover{ background:#f2f7f4; }
.sv-ps-when{ flex:1 1 auto; font-size:11.5px; color:var(--ink2); font-weight:650; }
.sv-ps-did{ padding:9px 12px; display:flex; flex-wrap:wrap; gap:7px; align-items:center;
  border-top:1px solid var(--border-s); }
.sv-ps-body{ padding:11px 12px 12px; border-top:1px solid var(--border-s);
  animation:svDetailIn .2s cubic-bezier(.2,.8,.3,1) both; }
.sv-ps-body .sv-mail{ margin-bottom:10px; }

/* ⚠️ WHAT THEY DID, IN WORDS, NOT IN COUNTS. "3 opened" on a row is a number about
   three different people; this is a sentence about one, and the difference is the
   whole reason the popup exists. */
.sv-did{ font-size:12px; font-weight:700; border-radius:7px; padding:3px 9px; }
.sv-did i{ font-style:normal; font-weight:600; opacity:.85; }
.sv-did.is-ok{ background:var(--border-s); color:var(--ink2); }
.sv-did.is-open{ background:#dcfce7; color:#15803d; }
.sv-did.is-click{ background:#dbeafe; color:#1d4ed8; }
.sv-did.is-bad{ background:#fee2e2; color:#b91c1c; }
.sv-did.is-wait{ background:#fef3c7; color:#92400e; }
.sv-did.is-none{ background:transparent; color:var(--ink3); font-weight:500; padding-left:0; }

/* One aggregate word on the row, where five pills used to be. */
.sv-dot{ font-weight:750; color:var(--ink2); }
.sv-dot.is-open{ color:#15803d; }
.sv-dot.is-bad{ color:#b91c1c; }

@media (max-width:620px){
  .sv-ps-hd{ flex-wrap:wrap; }
  .sv-ps-when{ width:100%; order:3; }
}

/* ══════════════════════════════════════════════════════════════════════════
   THE PERSON POPUP IS TWO PANES — info left, the whole email right
   ══════════════════════════════════════════════════════════════════════════
   Tyler: *"this needs to be better coded UI in the pop-up as well. I should be able
   to see the entire thing. I should be able to click and expand and see the entire
   graphic on the right side. This pop-up can be big. The left side can be Info. The
   right side is the entire thing to review what got sent, everything — and just to
   that person."*

   The email is 600px of design. Reviewing it inside a 560px dialog beside its own
   facts meant reviewing neither, so the person sheet is the one that goes wide. */
.rm-sheet.is-wide .rm-sheet-box{ width:min(1120px,100%); }
.rm-sheet.is-wide .rm-sheet-body{ padding:0; overflow:hidden; display:flex; min-height:0; }

.sv-two{ display:flex; flex:1 1 auto; min-height:0; width:100%; }
/* ⚠️ EACH PANE SCROLLS ITSELF. One scroller for both would drag the email out of
   view while you read the facts, which is the exact thing two panes are for. */
.sv-two-l{ flex:0 0 clamp(300px,34%,400px); min-width:0; overflow:auto;
  padding:14px 15px 16px; border-right:1px solid var(--border-s); }
.sv-two-r{ flex:1 1 auto; min-width:0; display:flex; flex-direction:column;
  background:#f4f7f5; }

.sv-mailpane-hd{ display:flex; align-items:center; gap:10px; flex:0 0 auto;
  padding:10px 14px; border-bottom:1px solid var(--border-s); background:#fbfdfb; }
.sv-mailpane-t{ flex:1 1 auto; min-width:0; font-size:11px; font-weight:800;
  letter-spacing:.06em; text-transform:uppercase; color:var(--ink3);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.sv-mailpane-x{ flex:0 0 auto; border:1px solid var(--border); background:var(--surf);
  color:var(--ink2); font:inherit; font-size:11px; font-weight:800; padding:5px 11px;
  border-radius:8px; cursor:pointer; transition:border-color .12s, color .12s; }
.sv-mailpane-x:hover{ border-color:var(--c-blue); color:var(--c-blue); }

/* The frame is the email at its own width, centred, scrolling inside the pane. */
.sv-mailpane-wrap{ position:relative; flex:1 1 auto; min-height:0; overflow:auto;
  padding:14px; display:flex; justify-content:center; align-items:flex-start; }
.sv-mailpane-fr{ width:100%; max-width:620px; min-height:100%; border:0;
  background:#fff; border-radius:12px;
  box-shadow:0 8px 24px -12px rgba(9,17,26,.3), 0 0 0 1px rgba(9,17,26,.07); }
.sv-mailpane-load{ position:absolute; inset:0; display:grid; place-items:center;
  font-size:12px; color:var(--ink3); pointer-events:none; padding:20px; text-align:center; }
/* ⚠️ NOT AN ERROR STATE. A send from before copies were kept is a normal old record;
   it shows the subject, because that IS what the person saw in their inbox. */
.sv-mailpane-none{ flex:1 1 auto; display:flex; flex-direction:column; gap:9px;
  justify-content:center; align-items:center; text-align:center; padding:28px 26px;
  color:var(--ink3); }
.sv-mailpane-none b{ font-size:15px; font-weight:800; color:var(--ink2); max-width:34ch;
  line-height:1.35; }
.sv-mailpane-none span{ font-size:12px; line-height:1.6; max-width:44ch; }

/* One column below the width where two would squeeze both. Email FIRST, because on a
   phone the email is the thing you opened the card to see. */
@media (max-width:900px){
  .rm-sheet.is-wide .rm-sheet-body{ overflow:auto; }
  .sv-two{ flex-direction:column-reverse; }
  .sv-two-l{ flex:0 0 auto; border-right:0; border-top:1px solid var(--border-s); }
  .sv-two-r{ flex:0 0 auto; }
  .sv-mailpane-wrap{ max-height:60vh; }
  .sv-mailpane-fr{ min-height:420px; }
}

/* The badge that says WHICH email you are looking at — the archived copy they
   received, or today's template rebuilt around the recorded words. The distinction is
   the entire reason a copy is archived at all, so it is never left to be inferred. */
.sv-mailpane-badge{ flex:0 0 auto; font-size:9.5px; font-weight:900; letter-spacing:.07em;
  text-transform:uppercase; padding:3px 8px; border-radius:999px; cursor:help; }
.sv-mailpane-badge[hidden]{ display:none; }
.sv-mailpane-badge.is-arch{ background:#dcfce7; color:#15803d; }
.sv-mailpane-badge.is-rebuilt{ background:#fef3c7; color:#92400e; }

/* ⚠️ A DOLLAR NOBODY READ IS NOT $0. Cost Management answers 429 under repeated
   reads, and the fleet then prints a $0 wall under the words "Actual billed
   cost" — the same failure shape as the empty app list this view shipped with.
   The banner is loud on purpose: the traffic beside it is still true. */
.hs-warn{ margin:0 2px 12px; border:1px solid #f0d8ae; background:#fffaf2; border-radius:8px;
  padding:9px 12px; font-size:12px; line-height:1.5; color:#7c3f06; }
.hs-warn b{ color:#7c3f06; }
/* Linked, but the deploy DATE was never read — a fact plus an unknown, so it is
   the quiet colour. Only `token` (nothing auto-deploys) and `stale` (a date, and
   it is old) are findings. */
.hs-c-dep.is-linked{ color:var(--ink3); }

/* ── the face ────────────────────────────────────────────────────────────────
   49 cards of identical geometry, all named vo-app-something in the same mono
   face, is a wall you read rather than recognise. The monogram is painted from
   the app's own name (hue = a hash of it) so a card is distinct BEFORE any
   network call, and a real logo drops in on top when markChain finds one. */
.hs-c-id{ display:flex; align-items:center; gap:9px; min-width:0; }
.hs-c-id .hs-c-name{ min-width:0; flex:1 1 auto; }
.hs-c-mark{ position:relative; flex:0 0 auto; width:34px; height:34px; border-radius:9px;
  display:inline-flex; align-items:center; justify-content:center; overflow:hidden;
  background:hsl(var(--_h,210) 62% 94%); box-shadow:inset 0 0 0 1px hsl(var(--_h,210) 45% 84%); }
.hs-c-mark i{ font-style:normal; font-size:12.5px; font-weight:800; letter-spacing:-.3px;
  color:hsl(var(--_h,210) 55% 32%); }
.hs-c-mark img{ position:absolute; inset:0; width:100%; height:100%; object-fit:contain;
  background:#fff; padding:3px; }
.hs-c-mark.is-on{ background:#fff; box-shadow:inset 0 0 0 1px var(--border); }
.hs-c-mark.is-on i{ display:none; }
/* The key to the three figures — said once, above the wall, instead of assumed. */
.hs-legend{ margin:0 2px 12px; font-size:11.5px; line-height:1.5; color:var(--ink3); }
.hs-legend b{ font-weight:700; color:var(--ink2); }

/* ── is it used enough to keep ───────────────────────────────────────────────
   Tyler: *"a lot of the time we see it but won't know if people are using it
   enough to make it worth keeping."* A 30-day total cannot answer that, so this
   row carries the two things that can: the PACE (requests a day, the number a
   person can judge) and the SHAPE (30 daily buckets the metrics call already
   returned, drawn small). The sparkline is not a chart — it is the difference
   between "healthy" and "had one busy week in April". */
.hs-c-act{ display:flex; align-items:center; gap:7px; min-width:0;
  padding:7px 9px; border-radius:8px; background:var(--border-s); cursor:help; }
.hs-c-act b{ font-size:12.5px; font-weight:800; color:var(--ink); font-variant-numeric:tabular-nums;
  white-space:nowrap; }
.hs-c-act > span{ font-size:11px; font-weight:600; color:var(--ink3); white-space:nowrap;
  overflow:hidden; text-overflow:ellipsis; }
.hs-c-spark{ margin-left:auto; flex:0 0 auto; color:var(--_ac,#94a3b8); opacity:.85; }
.hs-c-act i{ font-style:normal; flex:0 0 auto; font-size:10px; font-weight:800; color:var(--ink3); white-space:nowrap; }
.hs-c-act i.is-up{ color:#166534; }
.hs-c-act i.is-down{ color:#b4471f; }
.hs-c-act.is-none b, .hs-c-act.is-none > span{ color:#b4471f; }
.hs-c-act.is-unk b, .hs-c-act.is-unk > span{ color:var(--ink4); }
/* A trend and a sparkline together need the room; on a narrow card the words go
   first and the picture keeps its 46px. */
@media (max-width:400px){ .hs-c-act i{ display:none; } }

/* ── the fold ────────────────────────────────────────────────────────────────
   Everything under the wall is a DIFFERENT subject (demo consolidation, sends,
   unaccounted URLs). Closed by default so the page opens on the fleet. */
.hs-fold{ border:1px solid var(--border); border-radius:12px; background:#fff; padding:0 14px; }
.hs-fold > summary{ cursor:pointer; list-style:none; margin:0 !important; padding:13px 0;
  display:flex; align-items:center; gap:8px; }
.hs-fold > summary::-webkit-details-marker{ display:none; }
.hs-fold > summary::before{ content:'▸'; color:var(--ink4); font-size:11px; transition:transform .15s; }
.hs-fold[open] > summary::before{ transform:rotate(90deg); }
.hs-fold > summary b{ color:var(--c-blue); }
.hs-fold[open]{ padding-bottom:14px; }
.hs-fold .ops-note{ margin-left:0; margin-right:0; }

/* The freshness line, with the live dot the auto-refresh earns. */
.hs-src{ display:flex; align-items:center; gap:7px; flex-wrap:wrap; }
.hs-src i{ font-style:normal; color:var(--ink4); }
.hs-livedot{ width:7px; height:7px; border-radius:50%; background:#16a34a; flex:0 0 auto;
  box-shadow:0 0 0 3px color-mix(in srgb,#16a34a 18%,transparent); }

/* ── search, and one client at a time ────────────────────────────────────────
   Tyler: *"we need a search bar on all of these left side tabs"* and *"if we are
   going to track what we have set up for other companies there needs to be
   select company dropdowns, not just a full list."* Same bar on every Command
   Center view, so the four of them read as one product. */
.hs-find{ display:flex; align-items:center; gap:8px; margin:0 2px 12px; flex-wrap:wrap; }
.hs-findbox{ display:inline-flex; align-items:center; gap:8px; flex:1 1 260px; min-width:0;
  border:1px solid var(--border); border-radius:10px; padding:8px 13px; background:#fff;
  transition:border-color .15s, box-shadow .15s; }
.hs-findbox:focus-within{ border-color:var(--c-blue); box-shadow:0 0 0 3px color-mix(in srgb,var(--c-blue) 14%,transparent); }
.hs-findbox svg{ flex:0 0 auto; stroke:var(--ink3); }
.hs-findbox input{ border:0; outline:0; background:transparent; font:inherit; font-size:13px; width:100%; color:var(--ink); }
.hs-findbox input::-webkit-search-cancel-button{ cursor:pointer; }
.hs-cosel{ flex:0 0 auto; background:#fff; border:1px solid var(--border); border-radius:10px;
  padding:8px 12px; font:inherit; font-size:13px; font-weight:600; color:var(--ink2); cursor:pointer; max-width:100%; }
.hs-cosel:focus{ outline:2px solid color-mix(in srgb,var(--c-blue) 45%,transparent); outline-offset:1px; }
.ops-find-cnt{ font-size:11.5px; font-weight:700; color:var(--ink3); flex:0 0 auto; }

/* ── whose app is it ─────────────────────────────────────────────────────────
   The mark carries the CLIENT's brand accent, not a hash of the app name, so a
   wall of 49 groups by eye into the companies they belong to. The logo, when we
   have one that genuinely belongs to this app, still wins the plate. */
.hs-c-mark.has-co{ background:color-mix(in srgb,var(--_co,#64748b) 13%,#fff);
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--_co,#64748b) 32%,#fff); }
.hs-c-mark.has-co i{ color:color-mix(in srgb,var(--_co,#64748b) 78%,#000); }
.hs-c-co{ font-size:9.5px; font-weight:800; letter-spacing:.3px; text-transform:uppercase;
  display:inline-flex; align-items:center; gap:4px; cursor:help; white-space:nowrap;
  color:color-mix(in srgb,var(--_co,#64748b) 75%,#000); }
.hs-c-co::before{ content:''; width:6px; height:6px; border-radius:2px; background:var(--_co,#64748b); }
.hs-c-co.is-none{ color:var(--ink4); }
.hs-c-co.is-none::before{ background:var(--ink4); }

/* ══════════════════════════════════════════════════════════════════════════
   STATIC WEB APPS — the wall, the money panel, the waiting state
   ══════════════════════════════════════════════════════════════════════════ */

/* ⚠️ FOUR ACROSS AT MOST, THREE IS THE COMFORTABLE ONE. Tyler: *"I want them
   to be cards, designed in rows of like four or three."* `auto-fill` with a
   288px floor gave SIX columns on a 27" monitor, and a 53-card wall six wide is
   the same undifferentiated grid the table was replaced for. The cap is on the
   TRACK COUNT, not on a media query, so it holds at every width in between. */
.hs-cards{ grid-template-columns:repeat(auto-fill,minmax(clamp(288px,30%,420px),1fr)); }
@media (min-width:1180px){ .hs-cards{ grid-template-columns:repeat(3,minmax(0,1fr)); } }
@media (min-width:1560px){ .hs-cards{ grid-template-columns:repeat(4,minmax(0,1fr)); } }

/* ── personality ──────────────────────────────────────────────────────────
   Tyler: *"put personality to it if you can… what company it's for, more of a
   static web app profile."* The card already knew the client; it wore it as a
   6px dot. The accent now runs across the whole head of the card, so a wall of
   53 reads as CLIENTS first and apps second — which is how anybody actually
   looks for one. ⚠️ The value verdict keeps the left-edge rule: the two facts
   are on different axes and must not share a colour channel. */
.hs-card{ padding-top:14px; }
.hs-card::after{ content:''; position:absolute; left:0; right:0; top:0; height:3px;
  border-radius:12px 12px 0 0; background:var(--_co,transparent); opacity:.9; }
.hs-card:hover{ border-color:var(--_co,var(--ink4)); box-shadow:0 6px 18px rgba(16,24,20,.10); transform:translateY(-1px); }
.hs-c-mark{ width:34px; height:34px; }
.hs-c-mark.has-co{ box-shadow:0 0 0 2px color-mix(in srgb, var(--_co) 26%, transparent); }
.hs-c-name b{ font-size:13.5px; letter-spacing:-.01em; }

/* ── the waiting state ────────────────────────────────────────────────────
   ⚠️ NO PROGRESS SEMANTICS ANYWHERE IN HERE. A bar that grows, a spinner that
   spins to a stop, a track that fills — all of them promise a finish time this
   page does not know. A soft breathing block promises only that something is
   coming, which is the truth. */
.hs-skel-hd{ height:64px; border-radius:10px; margin:0 2px 16px; background:var(--border-s); }
.hs-skel .hs-skcard{ border:1px solid var(--border); border-radius:12px; padding:14px 13px 12px;
  display:flex; flex-direction:column; gap:10px; }
.hs-skl{ display:block; height:10px; border-radius:4px; background:var(--border-s); }
.hs-skl.w40{ width:40%; } .hs-skl.w70{ width:70%; } .hs-skl.w90{ width:90%; }
.hs-skfigs{ display:grid; grid-template-columns:repeat(3,1fr); gap:8px; }
.hs-skfigs i{ height:30px; border-radius:6px; background:var(--border-s); }
.hs-skel-hd,.hs-skl,.hs-skfigs i{ animation:hsBreathe 1.5s ease-in-out infinite; }
.hs-skcard{ animation-delay:calc(var(--_i,0) * 60ms); }
@keyframes hsBreathe{ 50%{ opacity:.45; } }
@media (prefers-reduced-motion:reduce){
  .hs-skel-hd,.hs-skl,.hs-skfigs i{ animation:none; opacity:.7; } }

/* ── nothing came back, and why ───────────────────────────────────────────
   The old version of this screen was one grey sentence containing the words
   "no answer". This is a diagnosis: which half failed, what Azure said, and the
   command that repairs it — selectable, because a fix nobody can copy is not
   a fix. */
.hs-blocked{ border:1px solid var(--border); border-radius:12px; background:var(--surf);
  padding:20px 20px 16px; max-width:760px; }
.hs-blocked-h{ font-size:15px; font-weight:800; letter-spacing:-.01em; margin-bottom:6px; }
.hs-blocked-lead{ margin:0 0 14px; font-size:12.5px; line-height:1.6; color:var(--ink2); }
.hs-blocked-halves{ display:grid; grid-template-columns:repeat(auto-fit,minmax(220px,1fr)); gap:10px; margin-bottom:14px; }
.hs-half{ border:1px solid var(--border); border-left:3px solid var(--ink4); border-radius:8px; padding:9px 11px; }
.hs-half b{ display:block; font-size:11px; font-weight:800; text-transform:uppercase;
  letter-spacing:.05em; color:var(--ink3); margin-bottom:3px; }
.hs-half span{ font-size:12px; line-height:1.5; color:var(--ink2); }
.hs-half.is-bad{ border-left-color:#dc2626; }
.hs-half.is-ok{ border-left-color:#166534; }
.hs-fix{ border:1px solid var(--border); border-radius:8px; padding:10px 11px; margin-bottom:14px;
  background:var(--border-s); }
.hs-fix b{ display:block; font-size:11px; font-weight:800; text-transform:uppercase;
  letter-spacing:.05em; color:var(--ink3); margin-bottom:5px; }
.hs-fix code{ display:block; font-size:11.5px; line-height:1.6; word-break:break-all;
  user-select:all; color:var(--ink); }
.hs-blocked-ft{ display:flex; align-items:center; gap:10px; }
.hs-blocked-ft i{ font-style:normal; font-size:11px; color:var(--ink4); }

/* ══════════════════════════════════════════════════════════════════════════
   STATIC WEB APPS — THE SIMPLE CARD, AND THE PROFILE BEHIND IT
   Tyler: *"the swa area needs to be a simpler card per swa, not so much info —
   just the name, logo, i guess activity. Things like repos connected can all
   show inside; the inside popups needs tabs and everything just like the repos
   popup, all polished, links to get to it in azure, everything, big billing."*
   ══════════════════════════════════════════════════════════════════════════ */

/* ── the card, stripped to three rows ───────────────────────────────────────
   Was: header chips, a three-figure grid, a bar, a sentence, up to six repo
   chips and a five-part footer. Now: who/what, is-anybody-there, one quiet
   line. Everything removed has a named home in the popup — see appCard.
   ⚠️ THE FIGURE GRID AND THE FOOTER ARE GONE FROM THE MARKUP, so their rules
   below are dead for this card and are left only because `.hs-row` (the mobile
   list) still uses several of them. Do not "tidy" them away without checking. */
.hs-card.is-slim{ gap:10px; padding:13px 14px 12px; }
/* No footer to push down any more, so nothing needs margin-top:auto — but the
   cards in a row must still line up, which they do because all three rows are
   fixed height. */
/* ⚠️ THE ROUND-1 FLEX RULES FOR THIS ROW ARE GONE, NOT OVERRIDDEN — see the
   three-slot grid in the round-2 block at the foot of this file. They set
   `flex:0 1 auto` on children that are now grid items, which is inert but reads
   as though the row were still a flex line. */

/* The one line under the activity row. Four facts, dot-separated, all quiet —
   nothing here competes with the name or the pace, because nothing here is
   what you scan a wall of 53 for. */
/* One line, always — client, repos, money. It wraps rather than clipping if a
   client name is very long, but with the verdict word gone (see appCard) three
   short facts fit a 258px card, so in practice it never does. */
.hs-c-meta{ display:flex; align-items:center; flex-wrap:wrap; gap:5px;
  font-size:10.5px; font-weight:700; color:var(--ink3); min-width:0; }
.hs-c-meta .hs-c-co{ font-size:9.5px; min-width:0; overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap; }
.hs-c-m{ cursor:help; white-space:nowrap; }
.hs-c-m.is-warn{ color:#b4471f; }
.hs-c-m.is-unk{ color:var(--ink4); }
.hs-c-m.is-free{ color:#166534; }
/* ⚠️ THE TRACK CAP FROM THE ORIGINAL WALL IS RESTATED HERE, NOT REPLACED. The
   cap ("four across at most, three is the comfortable one") is a rule Tyler set,
   and this block sits after it in the file — so overriding only the auto-fill
   floor would have silently killed both media queries. The floor comes down
   because the card is now HALF AS TALL, and the 4-across breakpoint comes down
   with it: three 520px cards of three short rows is a lot of empty card. */
.hs-cards{ grid-template-columns:repeat(auto-fill,minmax(clamp(258px,28%,400px),1fr)); }
@media (min-width:1180px){ .hs-cards{ grid-template-columns:repeat(3,minmax(0,1fr)); } }
@media (min-width:1400px){ .hs-cards{ grid-template-columns:repeat(4,minmax(0,1fr)); } }

/* ══ THE PROFILE ═══════════════════════════════════════════════════════════
   Same grammar as the repo popup — accented hero, real actions, tabs, one pane
   each — because these are the only two "profile" popups in the product and
   they should not be two designs. It stays a `.hsm` and not a `.rm-backdrop`
   for the stacking and Escape reasons written above openSwaApp. */
.hsm-box{ width:min(880px,100%); overflow:hidden; }

/* ── the hero ─────────────────────────────────────────────────────────────
   The client's accent, not the verdict's: the verdict is a WORD in here (the
   pill, and a whole block on Overview) and does not need a colour channel too.
   ⚠️ `.hsm-hd` / `.hsm-t` / `.hsm-ft` are no longer emitted — this replaces
   all three. */
.hsm-hero{ position:relative; flex:0 0 auto; padding:16px 18px 14px; color:#fff; overflow:hidden; }
.hsm-hero .rr-thumb-tex{ opacity:.4; }
.hsm-hero > *{ position:relative; z-index:1; }
.hsm-hero-top{ display:flex; align-items:center; flex-wrap:wrap; gap:6px; padding-right:34px; }
.hsm-pill{ font-size:9.5px; font-weight:800; letter-spacing:.4px; text-transform:uppercase;
  background:rgba(255,255,255,.22); border:1px solid rgba(255,255,255,.28); color:#fff;
  border-radius:5px; padding:3px 7px; cursor:help; white-space:nowrap; }
.hsm-pill.is-quiet{ background:rgba(255,255,255,.1); border-color:rgba(255,255,255,.2); }
/* Close sits on the picture, so it is a glass square rather than the white
   bordered button it was in the old header. */
.hsm-hero .hsm-x{ position:absolute; top:12px; right:12px; z-index:3; width:28px; height:28px;
  border-radius:8px; border:1px solid rgba(255,255,255,.28); background:rgba(255,255,255,.14);
  color:#fff; font-size:12px; line-height:1; }
.hsm-hero .hsm-x:hover{ background:rgba(255,255,255,.26); border-color:rgba(255,255,255,.45); color:#fff; }

.hsm-hero-id{ display:flex; align-items:center; gap:13px; margin-top:11px; min-width:0; }
.hsm-mark{ position:relative; flex:0 0 auto; width:48px; height:48px; border-radius:12px;
  overflow:hidden; display:inline-flex; align-items:center; justify-content:center;
  background:rgba(255,255,255,.18); border:1px solid rgba(255,255,255,.3); }
.hsm-mark i{ font-style:normal; font-size:17px; font-weight:800; letter-spacing:-.4px;
  color:#fff; text-shadow:0 2px 5px rgba(0,0,0,.3); }
.hsm-mark img{ position:absolute; inset:0; width:100%; height:100%; object-fit:contain;
  background:#fff; padding:4px; }
.hsm-mark.is-on{ background:#fff; border-color:rgba(255,255,255,.55); }
.hsm-mark.is-on i{ display:none; }
.hsm-hero-txt{ min-width:0; flex:1 1 auto; }
.hsm-hero-txt h3{ margin:0; font:800 19px/1.15 ui-monospace,Consolas,monospace; letter-spacing:-.4px;
  text-shadow:0 2px 6px rgba(0,0,0,.22); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.hsm-hero-sub{ display:flex; align-items:center; flex-wrap:wrap; gap:4px 9px; margin-top:5px; min-width:0; }
.hsm-hero-sub a, .hsm-hero-sub > span{ font:600 12px ui-monospace,Consolas,monospace; color:#fff;
  opacity:.95; text-decoration:none; border-bottom:1px solid rgba(255,255,255,.4); }
.hsm-hero-sub a:hover{ border-bottom-color:#fff; }
.hsm-hero-sub i{ font-style:normal; font-size:11px; opacity:.72; }

/* The four figures the card wall sorts on, restated so opening a card can
   never contradict the card. */
.hsm-hero-figs{ display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:1px;
  margin-top:13px; border-radius:8px; overflow:hidden; background:rgba(255,255,255,.2); }
.hsm-hero-figs > div{ background:rgba(255,255,255,.13); padding:7px 10px; min-width:0; cursor:help; }
.hsm-hero-figs b{ display:block; font-size:16px; font-weight:800; letter-spacing:-.4px;
  font-variant-numeric:tabular-nums; line-height:1.15; }
.hsm-hero-figs span{ display:block; font-size:9.5px; font-weight:700; text-transform:uppercase;
  letter-spacing:.3px; opacity:.78; margin-top:2px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }

/* ── the action row and the tabs ────────────────────────────────────────── */
.hsm-acts{ flex:0 0 auto; display:flex; flex-wrap:wrap; gap:7px; padding:11px 18px 0; }
.hsm-tabs{ flex:0 0 auto; display:flex; gap:4px; padding:12px 18px 0; overflow-x:auto;
  border-bottom:1px solid var(--border-s); }
.hsm-tabs::-webkit-scrollbar{ height:0; }
.hsm-tab{ position:relative; flex:0 0 auto; border:0; background:none; cursor:pointer;
  font-family:var(--f); font-size:12.5px; font-weight:700; color:#5f6b64;
  padding:8px 11px 10px; border-radius:8px 8px 0 0; display:inline-flex; align-items:center; gap:6px;
  transition:color .16s, background .16s; }
.hsm-tab:hover{ color:var(--c-blue); background:color-mix(in srgb,var(--c-blue) 7%,transparent); }
.hsm-tab.is-on{ color:var(--c-blue); }
.hsm-tab.is-on::after{ content:''; position:absolute; left:8px; right:8px; bottom:-1px; height:2.5px;
  border-radius:2px; background:var(--c-blue); }
.hsm-tab:focus-visible{ outline:2px solid var(--c-blue); outline-offset:-2px; }
.hsm-tab .tn{ font-size:10px; font-weight:800; background:var(--border-s); color:var(--ink3);
  padding:1px 6px; border-radius:7px; font-variant-numeric:tabular-nums; }
.hsm-tab.is-on .tn{ background:color-mix(in srgb,var(--c-blue) 14%,transparent); color:var(--c-blue); }
.hsm-body{ padding:16px 18px 18px; }
.hsm-pane{ display:none; }
.hsm-pane.is-on{ display:block; }
/* Every pane opens with a block that needs no top gap of its own. */
.hsm-pane > .hsm-sec:first-child, .hsm-pane > .hsm-nums:first-child{ margin-top:0; }

/* ── the state block: the verdict as a sentence, not a chip ─────────────── */
.hsm-state{ margin-top:12px; border:1px solid color-mix(in srgb,var(--_ac,#64748b) 24%,#fff);
  background:color-mix(in srgb,var(--_ac,#64748b) 5%,#fff); border-radius:8px; padding:11px 12px; }
.hsm-state-l{ display:inline-block; font-size:10px; font-weight:800; letter-spacing:.4px;
  text-transform:uppercase; color:#fff; background:var(--_ac,#64748b);
  border-radius:5px; padding:3px 8px; }
.hsm-state p{ margin:8px 0 0; font-size:12px; line-height:1.55; color:var(--ink2); }
.hsm-state-line{ margin-top:7px; padding-top:7px; border-top:1px solid color-mix(in srgb,var(--_ac,#64748b) 18%,#fff);
  font-size:12px; line-height:1.5; color:var(--ink2); }
.hsm-state-line b{ font-weight:800; color:var(--ink); font-variant-numeric:tabular-nums; }
.hsm-state-line i.warn{ font-style:normal; font-weight:700; color:#b4471f; }

/* ── thirty days, one bar a day ──────────────────────────────────────────
   ⚠️ NOT A CHART WITH AN AXIS. The question is "what happened", and a labelled
   y-axis on 30 buckets of file requests invites arithmetic nobody wants to do.
   The tallest bar is named underneath, so every other bar is read against it,
   and each bar carries its own date and count on hover. A measured zero draws a
   1px floor — an absent bar and a zero bar must not look the same. */
.hsm-bars{ display:flex; align-items:flex-end; gap:2px; height:64px; margin-top:2px;
  padding:0 1px; border-bottom:1px solid var(--border); }
.hsm-bar{ flex:1 1 0; min-width:0; height:var(--_p,0%); border-radius:2px 2px 0 0;
  background:linear-gradient(180deg,var(--c-blue),color-mix(in srgb,var(--c-blue) 55%,#fff));
  cursor:help; transition:filter .12s; }
.hsm-bar:hover{ filter:brightness(1.12) saturate(1.2); }
.hsm-bar.is-zero{ height:1px; background:var(--ink4); border-radius:0; }
.hsm-barsx{ display:flex; align-items:center; justify-content:space-between; gap:10px;
  margin-top:6px; font-size:10.5px; color:var(--ink3); font-variant-numeric:tabular-nums; }
.hsm-barsx b{ font-weight:700; color:var(--ink2); cursor:help; }
/* Overview carries the same chart as Traffic and must not compete with it —
   short enough to read as a summary, tall enough to still show the spike. */
.hsm-bars.is-mini{ height:40px; }
.hsm-spark{ margin-top:11px; }

/* ── the doors into Azure ────────────────────────────────────────────────
   Tyler: *"links to get to it in azure, everything."* Each one says what it
   answers, because "Metrics" and "Activity log" are not self-explanatory to
   anybody who does not already live in the portal. */
.hsm-azrow{ display:flex; flex-wrap:wrap; gap:7px; }
.hsm-azgrid{ display:grid; grid-template-columns:repeat(auto-fill,minmax(232px,1fr)); gap:7px; }
.hsm-az{ position:relative; display:block; border:1px solid var(--border); border-radius:8px;
  background:#fff; padding:9px 30px 9px 11px; text-decoration:none; min-width:0;
  transition:border-color .14s, box-shadow .14s, transform .14s; }
.hsm-az:hover{ border-color:var(--c-blue); box-shadow:0 4px 12px rgba(16,24,20,.08); transform:translateY(-1px); }
.hsm-az b{ display:block; font-size:12.5px; font-weight:800; color:var(--ink); }
.hsm-az:hover b{ color:var(--c-blue); }
.hsm-az span{ display:-webkit-box; margin-top:3px; font-size:11px; line-height:1.45;
  color:var(--ink3); -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
.hsm-az svg{ position:absolute; top:10px; right:10px; width:13px; height:13px; color:var(--ink4); }
.hsm-az:hover svg{ color:var(--c-blue); }

/* The full ARM path, copyable — it is what Cost Management groups by and what
   every link above is built from, so it is a fact worth handing over. */
.hsm-idpath{ display:flex; align-items:center; gap:8px; margin-top:8px; min-width:0;
  border:1px solid var(--border-s); background:#fafbfa; border-radius:6px; padding:7px 8px 7px 10px; }
.hsm-idpath code{ flex:1 1 auto; min-width:0; font-family:ui-monospace,Consolas,monospace;
  font-size:10.5px; color:var(--ink2); overflow-x:auto; white-space:nowrap; }
.hsm-idpath code::-webkit-scrollbar{ height:0; }
.rm-btn.xs{ font-size:11px; padding:4px 9px; border-radius:7px; flex:0 0 auto; }

@media (max-width:720px){
  .hsm{ padding:0; align-items:stretch; }
  .hsm-box{ width:100%; max-height:100%; border-radius:0; border:0; }
  .hsm-hero-figs{ grid-template-columns:repeat(2,minmax(0,1fr)); }
  .hsm-nums{ grid-template-columns:repeat(2,minmax(0,1fr)); }
  .hsm-hero, .hsm-acts, .hsm-tabs, .hsm-body{ padding-left:14px; padding-right:14px; }
  .hsm-azgrid{ grid-template-columns:minmax(0,1fr); }
}

/* == WHICH KIND OF THING IS THIS - the Azure mark, said blatantly =========
   Tyler: *"we need an azure icon or something to really separate when you're
   looking at a static web app vs a repo - they both look so similar and it
   needs to be blatant."* A repository and the Azure app it deploys to wear the
   SAME logo, the SAME client accent and the SAME tabbed popup, so the kind is
   stated three times over now: a strip across the top of every hero, a badge
   welded to the corner of every mark, and the mark on the head above the wall.
   AZURE BLUE = a hosting resource. GRAPHITE = source code. The glyphs are
   AZ_ICON / REPO_ICON in repos.js - one definition, every surface.

   WARNING: THE BAND IS ABSOLUTE, AND THE HERO PAYS FOR IT IN PADDING-TOP.
   A full-bleed strip drawn with negative margins is clipped correctly by the
   hero's overflow:hidden but its RECT is still wider than the popup, and the
   popup harness measures rects - it read as content spilling out of the box.
   Positioned instead: the band is exactly the hero's width, the hero reserves
   its height at the top, and the band re-states the hero's own side padding so
   its first letter lands on the hero's content edge. Change one, change both. */
.hsm-hero{ padding-top:60px; }
.rm-hero{ padding-top:62px; }
.kind-band{ --_kb-r:60px; position:absolute; z-index:2; left:0; right:0; top:0; height:48px;
  display:flex; align-items:center; gap:9px; padding:0 var(--_kb-r) 0 18px;
  box-shadow:inset 0 -1px 0 rgba(255,255,255,.14); }
/* The hero's own controls sit ON this strip - Close on both, and the repo
   hero's camera beside it - so the words have to stop short of them. */
.rm-hero .kind-band{ --_kb-r:104px; padding-left:24px; }
.kind-band > svg{ flex:0 0 auto; width:19px; height:19px; }
.kind-band b{ flex:0 0 auto; font-family:var(--f); font-size:11.5px; font-weight:800;
  letter-spacing:.9px; text-transform:uppercase; color:#fff; white-space:nowrap; }
.kind-band i{ min-width:0; font-style:normal; font-size:11px; color:rgba(255,255,255,.62);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.kind-band i::before{ content:''; display:inline-block; width:1px; height:11px;
  margin-right:9px; vertical-align:-1px; background:rgba(255,255,255,.28); }
.kind-band.is-az{ background:linear-gradient(90deg,#062038,#0d3f6c 46%,#12558f); }
.kind-band.is-repo{ background:linear-gradient(90deg,#12171d,#232f3b 46%,#2f3f4f); }
.kind-band.is-repo > svg{ color:#8ed0ff; }

/* THE AZURE MARK IS NOT ON THE LOGO. It was a badge on the corner of the mark
   plate, which put it on top of the artwork it was there to label. It is a chip
   at the far end of the card's identity row now - opposite the face, beside the
   open-in-a-new-tab arrow, on the same baseline as both. The popup has none at
   all: the band across its hero already says the words.
   Tinted rather than white, so it reads as Azure at 20px without a border. */
.hs-c-kind{ flex:0 0 auto; display:inline-flex; align-items:center; justify-content:center;
  width:22px; height:22px; border-radius:7px; cursor:help;
  background:color-mix(in srgb,#0078d4 11%,#fff); box-shadow:inset 0 0 0 1px color-mix(in srgb,#0078d4 22%,transparent); }
.hs-c-kind svg{ width:13px; height:13px; }
.hs-card.is-open:hover .hs-c-kind{ background:color-mix(in srgb,#0078d4 17%,#fff); }

/* How many faces are still missing, said once above the wall. A count is a job;
   a wall of initials is a shrug. */
.hs-nologo{ margin-left:auto; flex:0 0 auto; font-weight:700; font-size:11px; letter-spacing:0;
  text-transform:none; color:#a16207; background:#fef6e7; border-radius:6px; padding:2px 8px; cursor:help; }
.hs-nologo:empty{ display:none; }
.hs-nologo.is-ok{ color:var(--ink3); background:var(--border-s); }

/* The head above the wall. `.ops-sec-h` is uppercase and tight, so the sentence
   that follows it is the quiet half - it is there for the person who arrived on
   this page from the library and has not noticed the page changed under them. */
.ops-sec-h.is-az{ display:flex; align-items:center; gap:8px; }
.ops-sec-h.is-az svg{ flex:0 0 auto; width:16px; height:16px; }
.ops-sec-h.is-az em{ min-width:0; font-style:normal; font-weight:600; text-transform:none;
  letter-spacing:0; font-size:11.5px; color:var(--ink3);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.ops-sec-h.is-az em::before{ content:'\00b7'; margin:0 7px 0 0; color:var(--ink4); }

/* A repo card, and the chip on it that names the app it ships to: the two
   glyphs side by side on one card is the clearest statement of the difference
   anywhere in this file - THIS is the code, THAT is where it is hosted. */
.rp-card-slug{ display:flex; align-items:center; gap:5px; }
.rp-card-slug > span{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.rp-card-slug > svg{ flex:0 0 auto; width:12px; height:12px; color:var(--ink4); }
.rr-tag--swa > svg{ flex:0 0 auto; width:12px; height:12px; margin-right:1px; }

/* Every repository named inside an APP popup wears the repo mark, so a list of
   chips under an Azure hero cannot be read as more apps. Drawn in CSS because
   these chips are built in three places; the path is REPO_ICON's, kept in step
   by hand - if you change one, change both. */
.hs-repo{ background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='7' cy='6' r='2.3'/%3E%3Ccircle cx='7' cy='18' r='2.3'/%3E%3Ccircle cx='17' cy='8.4' r='2.3'/%3E%3Cpath d='M7 8.3v7.4M16.9 10.7c-.2 3-2.6 4.3-5.4 4.8'/%3E%3C/svg%3E");
  background-repeat:no-repeat; background-position:8px 50%; background-size:12px 12px;
  padding-left:25px; }

@media (max-width:720px){
  /* At this width the hero's own padding drops to 14px and the explanatory half
     of the band is the first thing that has to go - the mark and the noun are
     the part that answers the question. */
  .hsm-hero{ padding-top:54px; }
  .kind-band{ height:44px; gap:8px; padding-left:14px; }
  .kind-band i{ display:none; }
}


/* ══════════════════════════════════════════════════════════════════════════
   STATIC WEB APPS — ROUND 2: THE POLISH
   Tyler: *"I like the simpleness but still needs a better design, more
   polished, better code"* · *"add the companies dropdown, smooth transitions,
   polished design, logos, anything"* · *"search bar."*
   ══════════════════════════════════════════════════════════════════════════ */

/* ── one shared curve and one shared timing ─────────────────────────────────
   Every transition on this screen uses these two, so the wall moves as one
   surface rather than as fifty-four independently-eased boxes. Tokens on the
   page root, not on the card, because the find bar and the picker share them. */
.repos-page{ --hs-ease:cubic-bezier(.22,1,.36,1); --hs-fast:.14s; --hs-slow:.24s; }

/* ── the card: uniform geometry above everything ────────────────────────────
   ⚠️ EVERY CARD IS THE SAME HEIGHT AND EVERY ROW LINES UP. That is the whole
   difference between a wall you scan and a wall you read, and it is why the
   name block and the activity row are both FIXED rather than content-sized. */
.hs-card.is-slim{ gap:11px; padding:14px 14px 12px; }

/* The top rule is the CLIENT — and it is drawn on every card, quietly, when
   there is no client. A rule that only some cards have makes the wall look
   half-broken; the old `transparent` did exactly that on 15 of 21 cards. */
.hs-card.is-slim::after{ background:var(--_co, color-mix(in srgb,var(--ink4) 55%,transparent)); }

/* ── identity: two reserved lines for the name, one for the host ───────────
   ⚠️ RESERVED, NOT GROWN. `vo-app-ems-transition-hub-demo` needs two lines and
   `vo-links` needs one; clamping to 2 with a min-height of 2 means the long one
   fits and the short one does not change the card's height. Truncating the
   PRIMARY KEY of the screen — which is what "vo-app-ems-transiti…" was — is not
   a trade worth 16px. */
/* 11px. This was 13 while a kind badge hung 5px off the mark's corner and the
   gap had to clear the BADGE rather than the plate; the badge is a chip at the
   far end of the row now (.hs-c-kind), so the gap is back to clearing the mark. */
.hs-card.is-slim .hs-c-id{ align-items:flex-start; gap:11px; }
.hs-card.is-slim .hs-c-mark{ width:38px; height:38px; border-radius:10px; margin-top:1px; }
.hs-card.is-slim .hs-c-name{ padding-top:1px; }
/* The chip and the arrow sit on the name's first line, not centred on a
   two-line block — .hs-c-id aligns to flex-start here. */
.hs-card.is-slim .hs-c-kind, .hs-card.is-slim .hs-c-out{ margin-top:1px; }
/* ⚠️ `> b`, NOT `b`. The hostname's bright half is a <b> INSIDE .hs-c-name, so
   an unrestricted descendant selector handed it the name's two-line clamp and
   its min-height — the host line measured 47px instead of 14 and every card came
   out 185px instead of 146. Same mistake as `.hsm-kv span` uppercasing a nested
   chip. On this screen, scope to the child. */
.hs-card.is-slim .hs-c-name > b{
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;
  white-space:normal; word-break:break-all;
  font:800 13.5px/1.25 ui-monospace,Consolas,monospace; letter-spacing:-.3px;
  min-height:calc(2 * 1.25em); color:var(--ink); transition:color var(--hs-fast) ease; }
.hs-c-host{ display:block; margin-top:2px; font-size:10.5px; line-height:1.3;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
/* Bright where the fact is, dim where it repeats. Half this wall ends in the
   same 25 characters, and "coaching-demo.visiononeperfor…" cut the wrong half. */
/* Stated in LONGHANDS, in full, for two reasons. One: the unscoped
   `.hs-c-name b` rule higher up this file still matches the hostname's bright
   half, and every property it sets has to be answered here or it leaks in — it
   is what made the host line 13.5px mono, the same face as the name directly
   above it. Two: ⚠️ `font: 700 10.5px/1.3 inherit` IS AN INVALID SHORTHAND —
   the family slot does not accept `inherit`, so the whole declaration is thrown
   away silently and the fallback wins. That is what shipped in the first cut. */
.hs-c-host b{ display:inline; min-height:0; letter-spacing:0;
  font-family:ui-monospace,Consolas,monospace; font-size:10.5px; font-weight:700;
  line-height:1.3; white-space:nowrap; color:var(--ink2); }
.hs-c-host i{ display:inline; font-style:normal; font-size:10.5px; font-weight:500;
  font-family:ui-monospace,Consolas,monospace; color:var(--ink4); }
/* The open-the-site arrow gets a real hit target and a plate on hover — it was
   a 14px glyph with no affordance at all. */
.hs-card.is-slim .hs-c-out{ flex:0 0 auto; width:24px; height:24px; border-radius:7px;
  display:inline-flex; align-items:center; justify-content:center; margin-left:2px;
  color:var(--ink4); transition:color var(--hs-fast) ease, background var(--hs-fast) ease; }
.hs-card.is-slim .hs-c-out:hover{ color:var(--c-blue); background:color-mix(in srgb,var(--c-blue) 10%,transparent); }

/* ── the activity row: three fixed slots ───────────────────────────────────
   ⚠️ A GRID, NEVER A FLEX LINE. As flex, the sparkline landed wherever the words
   before it happened to end — 54 shapes at 54 offsets, which is what made the
   wall look untidy in Tyler's screenshot. Fixed outer columns mean the pace, the
   band and the shape each read straight down the column.
   ⚠️ AND THE SHAPE SLOT IS FIXED WHETHER OR NOT THERE IS A TREND ARROW. An
   `is-flat` placeholder keeps the width, so a card with no trend does not pull
   its sparkline 12px right of its neighbour's. */
.hs-card.is-slim .hs-c-act{
  display:grid; grid-template-columns:64px minmax(0,1fr) 60px; align-items:center;
  gap:8px; padding:8px 10px; border-radius:9px; background:var(--border-s);
  transition:background var(--hs-fast) ease; }
.hs-c-pace{ display:flex; align-items:baseline; gap:3px; min-width:0; }
.hs-c-pace b{ font-size:15px; font-weight:800; color:var(--ink); letter-spacing:-.5px;
  font-variant-numeric:tabular-nums; line-height:1.1; }
.hs-c-pace b.is-unk{ color:var(--ink4); }
.hs-c-pace i{ font-style:normal; font-size:9px; font-weight:700; text-transform:uppercase;
  letter-spacing:.3px; color:var(--ink4); white-space:nowrap; }
.hs-c-band{ font-size:11px; font-weight:600; color:var(--ink3); min-width:0;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.hs-c-shape{ display:flex; align-items:center; justify-content:flex-end; gap:4px; }
.hs-c-shape .hs-c-spark{ margin-left:0; }
.hs-c-shape i{ font-style:normal; flex:0 0 auto; width:11px; text-align:right;
  font-size:10px; font-weight:800; line-height:1; }
.hs-c-shape i.is-up{ color:#166534; }
.hs-c-shape i.is-down{ color:#b4471f; }
.hs-c-shape i.is-flat{ color:transparent; }
/* The two ends of the scale get their own colour, and nothing in between does —
   a five-colour band scale would be a legend nobody asked for. */
.hs-c-act.is-none .hs-c-pace b, .hs-c-act.is-none .hs-c-band{ color:#b4471f; }
.hs-c-act.is-heavy .hs-c-pace b{ color:#14532d; }
.hs-c-act.is-unk .hs-c-band{ color:var(--ink4); }

/* ── the meta line ────────────────────────────────────────────────────────
   Only what we know. `is-orphan` is the collapsed form of what used to be two
   greyed-out negatives side by side ("UNASSIGNED · no repo") — one phrase, and
   it is the actionable one. */
.hs-c-m.is-quiet{ color:var(--ink4); font-weight:600; }
.hs-c-m.is-orphan{ color:var(--ink3); font-weight:600; font-style:normal;
  border-bottom:1px dashed var(--ink4); cursor:help; }
.hs-c-m.is-free{ color:#166534; }

/* ── movement ─────────────────────────────────────────────────────────────
   ⚠️ NO ENTRANCE ANIMATION, NO STAGGER, NO SHIMMER. 54 cards fading in one
   after another is a progress bar wearing a costume — it promises a finish this
   page does not know about, which is the rule the waiting state already follows.
   What moves is what the reader is pointing at. */
.hs-card.is-slim{
  transition:border-color var(--hs-fast) ease, box-shadow var(--hs-slow) var(--hs-ease),
    transform var(--hs-slow) var(--hs-ease); }
.hs-card.is-slim:hover{ transform:translateY(-2px);
  border-color:color-mix(in srgb,var(--_co,var(--ink4)) 60%,var(--border));
  box-shadow:0 10px 24px -10px rgba(16,24,20,.28); }
.hs-card.is-slim:hover .hs-c-name > b{ color:var(--c-blue); }
.hs-card.is-slim:hover .hs-c-act{ background:color-mix(in srgb,var(--_ac,#94a3b8) 8%,var(--border-s)); }
.hs-card.is-slim:active{ transform:translateY(0); box-shadow:0 2px 6px rgba(16,24,20,.14); }
.hs-card.is-slim .hs-c-spark{ transition:opacity var(--hs-fast) ease; }
.hs-card.is-slim:hover .hs-c-spark{ opacity:1; }
/* The filter and sort chips move on the same curve as everything else. */
.hs-filt, .hs-sortb{ transition:background var(--hs-fast) ease, color var(--hs-fast) ease,
  border-color var(--hs-fast) ease, box-shadow var(--hs-fast) ease; }
/* ⚠️ AND SOMEBODY WHO ASKED FOR NO MOTION GETS NONE. */
@media (prefers-reduced-motion: reduce){
  .repos-page{ --hs-fast:0s; --hs-slow:0s; }
  .hs-card.is-slim:hover{ transform:none; }
  .hs-codd .wt-dropdown-menu{ transition:none; }
}

/* ── the search bar ───────────────────────────────────────────────────────
   Tyler: *"search bar."* It was a grey box with a magnifier. It now has a
   visible focus state on the whole box, a clear button, and the count of what
   is left — the three things that make a search feel answered. */
.hs-find{ align-items:stretch; gap:10px; margin-bottom:14px; }
.hs-findbox{ position:relative; padding:9px 14px; border-radius:11px;
  transition:border-color var(--hs-fast) ease, box-shadow var(--hs-fast) ease, background var(--hs-fast) ease; }
.hs-findbox svg{ transition:stroke var(--hs-fast) ease; }
.hs-findbox:focus-within{ box-shadow:0 0 0 3px color-mix(in srgb,var(--c-blue) 16%,transparent); }
.hs-findbox:focus-within svg, .hs-findbox.has-q svg{ stroke:var(--c-blue); }
.hs-findbox.has-q{ border-color:color-mix(in srgb,var(--c-blue) 40%,var(--border)); }
.hs-findx{ flex:0 0 auto; width:22px; height:22px; border-radius:6px; border:0; cursor:pointer;
  background:var(--border-s); color:var(--ink3); font-size:10px; line-height:1;
  display:inline-flex; align-items:center; justify-content:center;
  transition:background var(--hs-fast) ease, color var(--hs-fast) ease; }
.hs-findx:hover{ background:#f2dcd8; color:#b4471f; }
.hs-findcnt{ flex:0 0 auto; align-self:center; font-size:11.5px; font-weight:700;
  color:var(--ink3); font-variant-numeric:tabular-nums; }

/* ── the company picker ───────────────────────────────────────────────────
   The Library's dropdown, reused — same trigger, same menu, same logo plates
   (.repos-ddlogo / .repos-ddmark are defined with it), so the two pickers on
   this product are one control rather than two designs. What is added here is
   the count on the trigger and the open/close transition. */
.hs-codd{ flex:0 0 auto; align-self:stretch; }
.hs-codd .wt-dropdown-trigger{ height:100%; border-radius:11px; gap:8px;
  transition:border-color var(--hs-fast) ease, box-shadow var(--hs-fast) ease; }
.hs-codd .wt-dropdown-trigger:hover{ border-color:color-mix(in srgb,var(--c-blue) 45%,var(--border)); }
.hs-codd.is-open .wt-dropdown-trigger{ border-color:var(--c-blue);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--c-blue) 14%,transparent); }
.hs-codd-n{ flex:0 0 auto; font-size:10.5px; font-weight:800; color:var(--ink3);
  background:var(--border-s); border-radius:7px; padding:2px 7px; font-variant-numeric:tabular-nums; }
.hs-codd .wt-dd-caret{ flex:0 0 auto; color:var(--ink4);
  transition:transform var(--hs-slow) var(--hs-ease); }
.hs-codd.is-open .wt-dd-caret{ transform:rotate(180deg); }
/* ⚠️ THE MENU TRANSITIONS ON OPACITY AND TRANSFORM ONLY, AND KEEPS
   `visibility` FOR THE CLOSED STATE. Animating height or display cannot be
   transitioned and animating `display:none` cancels it outright; visibility can
   be stepped at the end so a closed menu is not focusable. */
/* ⚠️ ANCHORED RIGHT. The picker is the last control in the find bar, so a
   left-anchored menu (which is what the Library's shared rule gives it, and the
   Library's picker sits on the left) hung 18px past the right edge of the page
   and gave the whole document a horizontal scrollbar. */
.hs-codd .wt-dropdown-menu{ left:auto; right:0; opacity:0; visibility:hidden;
  transform:translateY(-6px) scale(.985); transform-origin:top right;
  transition:opacity var(--hs-fast) ease, transform var(--hs-slow) var(--hs-ease),
    visibility 0s linear var(--hs-slow); }
.hs-codd.is-open .wt-dropdown-menu{ opacity:1; visibility:visible;
  transform:none; transition-delay:0s, 0s, 0s; }
.hs-codd .repos-ddrow{ transition:background var(--hs-fast) ease; }

/* ── the panes inside the popup fade rather than cut ──────────────────────
   One short cross-fade so switching tabs reads as one surface turning over.
   ⚠️ `display` still does the showing — a pane left in the layout at opacity 0
   would keep its height and the box would size to the tallest tab. */
.hsm-pane.is-on{ animation:hsmFade var(--hs-slow,.24s) var(--hs-ease,ease) both; }
@keyframes hsmFade{ from{ opacity:0; transform:translateY(4px); } to{ opacity:1; transform:none; } }
@media (prefers-reduced-motion: reduce){ .hsm-pane.is-on{ animation:none; } }
.hsm-tab{ transition:color var(--hs-fast,.14s) ease, background var(--hs-fast,.14s) ease; }
.hsm-az{ transition:border-color var(--hs-fast,.14s) ease, box-shadow var(--hs-slow,.24s) ease,
  transform var(--hs-slow,.24s) cubic-bezier(.22,1,.36,1); }
.hsm-bar{ transition:filter var(--hs-fast,.14s) ease; }

@media (max-width:520px){
  /* The picker takes its own line rather than squeezing the search box to a
     stub — the search box is the one somebody came here to use. */
  .hs-find{ flex-wrap:wrap; }
  .hs-codd{ flex:1 1 100%; }
  .hs-codd .wt-dropdown-menu{ left:0; right:0; transform-origin:top left; }
}

/* ══ THE HOSTING-PLAN SWITCH ═══════════════════════════════════════════════════
   The control that turns an app's bill off — apps/repos/repos.js
   swaPlanControl(), first section of the Billing pane.

   ⚠️ .rm-btn.warn AND :disabled ARE SCOPED TO .hsm-plan HERE ON PURPOSE.
   Neither exists globally (.rm-btn has .live and .gh and nothing else), and
   introducing a global button variant from a feature stylesheet is how one
   screen restyles four others. If a second surface needs "warn", promote it
   then — not now.
   ⚠️ A DISABLED BUTTON MUST STILL READ AS A BUTTON, not as missing furniture.
   The reason it is disabled is printed underneath it in .hsm-plan-no, because
   a greyed control whose explanation lives in a title attribute is a dead
   button to everybody who does not hover. */
.hsm-plan-sw{ margin-top:9px; display:flex; align-items:center; justify-content:space-between;
  gap:12px; flex-wrap:wrap; padding:11px 13px; border-radius:10px;
  border:1px solid var(--_pc,#cbd5e1); background:var(--_pb,#f8fafc); }
.hsm-plan-sw.is-on{ --_pc:#e5d3ae; --_pb:#fffdf7; }
.hsm-plan-sw.is-off{ --_pc:#bcd8c6; --_pb:#f6fbf7; }
.hsm-plan-now{ display:flex; align-items:baseline; gap:9px; min-width:0; }
.hsm-plan-now b{ font-size:15px; font-weight:800; letter-spacing:-.01em; color:#334155; }
.hsm-plan-sw.is-on .hsm-plan-now b{ color:#92400e; }
.hsm-plan-sw.is-off .hsm-plan-now b{ color:#166534; }
.hsm-plan-now span{ font-size:12px; color:var(--ink2); }
.hsm-plan-btns{ display:flex; gap:7px; flex-shrink:0; }
.hsm-plan .rm-btn.warn{ background:#b45309; border-color:#b45309; color:#fff; }
.hsm-plan .rm-btn.warn:hover{ filter:brightness(1.07); color:#fff; }
.hsm-plan .rm-btn[disabled]{ opacity:.55; cursor:not-allowed; filter:grayscale(.4); }
.hsm-plan .rm-btn[disabled]:hover{ filter:grayscale(.4); }

.hsm-plan-what{ margin:8px 0 0; font-size:12px; line-height:1.6; color:var(--ink2); }
.hsm-plan-what b{ color:var(--ink); font-weight:700; }

/* The refusal. Reuses .hsm-idle's shape (the pale-red note) and adds the
   monospace block for Azure's own words and the az commands. */
.hsm-plan-no{ line-height:1.55; }
.hsm-plan-no pre{ margin:7px 0 0; padding:8px 9px; border-radius:6px; background:#fff;
  border:1px solid #f0cfc9; font-family:ui-monospace,Consolas,monospace; font-size:11px;
  line-height:1.5; white-space:pre-wrap; word-break:break-word; color:#7f1d1d; }
.hsm-plan-warn{ color:#92400e; }
.hsm-plan-done{ color:#166534; }

/* The confirm step. Two clicks, always — see the click handler in repos.js. */
.hsm-plan-ask{ margin-top:9px; padding:11px 13px; border-radius:10px;
  border:1px solid #cbd5e1; background:#fff;
  box-shadow:0 2px 10px rgba(15,23,42,.06); }
.hsm-plan-ask > b{ display:block; font-size:13px; font-weight:800; color:var(--ink); }
.hsm-plan-ask p{ margin:6px 0 0; font-size:12px; line-height:1.55; color:var(--ink2); }
.hsm-plan-ask ul{ margin:6px 0 0; padding-left:17px; font-size:12px; line-height:1.6; color:var(--ink2); }
.hsm-plan-ask .hsm-azrow{ margin-top:10px; }

@media (max-width:560px){
  /* ⚠️ THE BUTTON GOES FULL WIDTH RATHER THAN WRAPPING UNDER A LABEL AT 40px.
     .hsm-plan-sw already wraps; without this the button lands hard against the
     left edge at a width that reads as a broken row. */
  .hsm-plan-btns{ width:100%; }
  .hsm-plan-btns .rm-btn{ flex:1 1 auto; justify-content:center; }
}

/* == RETIRING IS THE PRIMARY ACTION, THE TIER FLIP IS A FOOTNOTE ==============
   See swaPlanControl in repos.js. "Off" means the resource is DELETED; moving an
   app to the Free plan is demoted into .hsm-plan-alt because a Free app still
   exists, still answers, still holds its API keys, and spends one of only ten
   Free slots in the subscription.
   WARNING: .hsm-plan-alt IS DELIBERATELY QUIETER THAN THE BLOCK ABOVE IT - same
   panel, lower contrast, dashed rule, no accent. It is an alternative, not a
   second headline. */
.hsm-plan-alt{ margin-top:11px; padding:10px 12px; border-radius:9px;
  border:1px dashed var(--line,#dbe3dd); background:#fbfcfb; }
.hsm-plan-alt-h{ font-size:11px; font-weight:800; letter-spacing:.04em; text-transform:uppercase;
  color:var(--ink3,#7b8a80); }
.hsm-plan-alt p{ margin:5px 0 0; font-size:12px; line-height:1.55; color:var(--ink2); }
.hsm-plan-alt p b{ color:var(--ink); font-weight:700; }
.hsm-plan-alt .hsm-azrow{ margin-top:9px; }

/* The command, which is the actual deliverable of this panel. Selectable, and it
   must WRAP rather than scroll - a half-visible command gets half-copied. */
.hsm-plan-cmd{ margin:6px 0 0; padding:8px 10px; border-radius:6px;
  background:#0f1a14; color:#d7eade;
  font-family:ui-monospace,Consolas,monospace; font-size:11.5px; line-height:1.5;
  white-space:pre-wrap; word-break:break-all; user-select:all; }

.hsm-plan-sw .hsm-plan-now b{ font-variant-numeric:tabular-nums; }
