/* Minty Media Registry — custom UI skin for Verdaccio's built-in UI.
 * Loaded via web.metaScripts (config.yaml) as a <link rel="stylesheet">.
 *
 * Verdaccio's UI is a MUI/emotion app: class names are hashed per-build and
 * MUST NOT be relied on. Selectors below target stable attribute fragments
 * (e.g. [class*="MuiCard"]), tag names, and structural roles instead, so a
 * Verdaccio bundle rebuild does not silently break the skin.
 *
 * darkMode is the configured default (web.darkMode: true) so the palette is
 * dark-first; the light theme toggle is left alone rather than fought.
 */

@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');

:root {
  /* Fix round 6: monochrome "light black" scheme — round 5's mint accent
   * pair is gone entirely. Two neutral grays now carry
   * every interactive/brand cue: --mm-primary is the "primary tone" (matches
   * config.yaml's web.primaryColor, used for solid-fill/selected chrome —
   * contained buttons, selected tabs, checked icons), and --mm-highlight is
   * the lighter "interactive accent" (hover borders, focus rings, hover
   * link color) — kept as a separate token from --mm-primary purely because
   * a lighter tone reads better than the darker primary tone against the
   * dark page background. No other colored accents remain in this file
   * except the GitHub alert palette and the vendored markdown link blue,
   * both left untouched below.
   */
  --mm-primary: #484f58;
  --mm-highlight: #6e7681;

  --mm-radius: 12px;
  --mm-border: #343b45;
  --mm-shadow: 0 4px 20px rgba(0, 0, 0, 0.35), 0 1px 2px rgba(0, 0, 0, 0.2);

  /* Fix round 6: page background is now LIGHTER and DISTINCT from the
   * README/markdown panel (which keeps its own darker GitHub-dark
   * background — see the `.markdown-body` panel rule near the bottom of
   * this file). --mm-bg-1 is the card/surface tone (package cards,
   * .mm-grid cards, popper paper); --mm-bg-2 is one step lighter again,
   * for code blocks and card hover states — keeping a consistent
   * light-on-dark elevation order (page < surface < hover/elevated). */
  --mm-bg-0: #171c23;
  --mm-bg-1: #1f262e;
  --mm-bg-2: #262e38;
  --mm-text: #e9e9f0;
  --mm-text-dim: #9a9ab0;
}

/* Light-theme override: keep the accent colors, but don't fight MUI's light
 * background/text — just soften borders/shadows to match. Keyed off MUI's
 * own color-scheme attribute (not a class-name substring match, which could
 * false-positive on unrelated classes like "highlight"), with a
 * prefers-color-scheme fallback for the case where that attribute isn't
 * set. darkMode is the configured default, so this is a light-mode-only
 * refinement, never the primary target. */
[data-mui-color-scheme="light"] {
  --mm-border: rgba(0, 0, 0, 0.08);
  --mm-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
}

@media (prefers-color-scheme: light) {
  :root:not([data-mui-color-scheme]) {
    --mm-border: rgba(0, 0, 0, 0.08);
    --mm-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
  }
}

html, body {
  font-family: 'Inter', system-ui, -apple-system, "Segoe UI", Roboto, sans-serif !important;
  background-color: var(--mm-bg-0) !important;
  color: var(--mm-text);
}

/* Full-page layout wrappers between <body> and actual content: transparent
 * so the single background-color set on html/body above is the only thing
 * ever painted behind the page. Cards/panels ([class*="MuiCard"],
 * [class*="MuiPaper"]) are NOT included here — they keep their own surface
 * color (see "Cards / panels" below). */
#root,
#root > div,
main {
  background: transparent !important;
}

/* Belt-and-braces: hide the native header buttons removed via
 * web.showInfo / web.showSettings / web.showThemeSwitch (config.yaml) in
 * case a future ui-theme build renders them before those config toggles
 * take effect, or the toggles otherwise lag. */
#header--button-settings,
#header--button-registryInfo,
[data-testid="header--button--dark"],
[data-testid="header--button--light"] {
  display: none !important;
}

* {
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.18) transparent;
}
*::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}
*::-webkit-scrollbar-track {
  background: transparent;
}
*::-webkit-scrollbar-thumb {
  background-color: rgba(255, 255, 255, 0.18);
  border-radius: 8px;
  border: 2px solid transparent;
  background-clip: content-box;
}
*::-webkit-scrollbar-thumb:hover {
  background-color: rgba(255, 255, 255, 0.32);
}

/* ---------- Header / nav ---------- */
header,
[class*="MuiAppBar"],
nav[class*="Header"],
[data-testid="header"] {
  background: linear-gradient(180deg, var(--mm-bg-1), var(--mm-bg-0)) !important;
  border-bottom: 1px solid var(--mm-border) !important;
  box-shadow: none !important;
  backdrop-filter: blur(6px);
}

header a, header button, nav a, nav button {
  transition: color 150ms ease, background-color 150ms ease, opacity 150ms ease;
}

/* Logo image in the header — a bit of breathing room, crisp edges. */
header img,
[class*="MuiToolbar"] img {
  image-rendering: -webkit-optimize-contrast;
}

/* ---------- Search box ---------- */
/* Fix round 4: scoped strictly to [data-testid="search-container"] (the
 * real stable hook around the MUI Autocomplete search input) instead of
 * every MuiInputBase-root in the app. Previous rounds painted a border
 * directly on the input root *and* let MUI's own notched `fieldset`
 * (the element that actually draws the outline) paint its own border
 * underneath, then added a focus box-shadow ring on top of both — three
 * overlapping outline effects. Now the input root only sets background/
 * text color; the single border lives on `fieldset` alone, and there is no
 * box-shadow at all. */
[data-testid="search-container"] [class*="MuiInputBase-root"] {
  background-color: var(--mm-bg-1) !important;
  border-radius: 8px !important;
  color: #e6edf3 !important;
  box-shadow: none !important;
}

[data-testid="search-container"] fieldset {
  border: 1px solid #343b45 !important;
  border-radius: 8px !important;
  box-shadow: none !important;
}

[data-testid="search-container"] [class*="MuiInputBase-root"]:hover fieldset {
  border-color: var(--mm-highlight) !important;
}

[data-testid="search-container"] [class*="MuiInputBase-root"].Mui-focused fieldset,
[data-testid="search-container"]:focus-within fieldset {
  border-color: var(--mm-highlight) !important;
  box-shadow: none !important;
}

[data-testid="search-container"] input {
  color: #e6edf3 !important;
}

[data-testid="search-container"] input::placeholder {
  color: #7d8590 !important;
  opacity: 1 !important;
}

/* Fix round 5: the Autocomplete search dropdown renders in a MUI popper
 * portalled to the end of <body>, outside [data-testid="search-container"]
 * entirely, so none of the scoped rules above reach it. Verified in the
 * field: it was being clipped/overlapped by our own styled containers
 * (cards/panels above default to a modest stacking context, and the popper
 * wasn't beating them). Force it to the top of the stack and give its paper
 * the same dark surface/border as the rest of the skin so the suggestion
 * list is fully visible and legible. */
[class*="MuiAutocomplete-popper"],
[class*="MuiPopper-root"] {
  z-index: 3000 !important;
}

[class*="MuiAutocomplete-popper"] [class*="MuiPaper"],
[class*="MuiPopper-root"] [class*="MuiPaper"] {
  background-color: var(--mm-bg-1) !important;
  border: 1px solid #343b45 !important;
}

/* Round-11 tweak: field-verified the rule above still isn't matching the
 * real element — the owner sees the page content underneath show through
 * the suggestion list (the found package text overlapping the
 * "Dependencies" tab text behind it), so the popper's actual paper/listbox
 * is transparent in the live DOM. Belt-and-braces: widen the selector list
 * (the real bundle's class name for this apparently isn't `MuiPaper` or
 * isn't nested where expected) and cover the listbox `<ul>` itself too, in
 * case the paper wrapper is the transparent layer and the list content
 * paints straight through it. Border/shadow are scoped to just the two
 * paper-level selectors (the outermost popper child) so the `ul`/listbox
 * matches below don't double up a border on the same visual edge. */
[class*="MuiAutocomplete-popper"] [class*="MuiPaper"],
[class*="MuiAutocomplete-popper"] [class*="MuiAutocomplete-paper"],
[class*="MuiAutocomplete-popper"] ul,
[class*="MuiAutocomplete-listbox"] {
  background-color: #1f262e !important;
}

[class*="MuiAutocomplete-popper"] [class*="MuiPaper"],
[class*="MuiAutocomplete-popper"] [class*="MuiAutocomplete-paper"] {
  border: 1px solid #343b45;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
}

/* Round-12: root cause of the bleed-through, field-verified against the
 * owner's live DOM — the popper is NOT portaled to <body> the way round 5
 * assumed. Its direct parent wrapper (a hashed `css-1e0utw4` div) computes
 * `z-index: 1; position: relative`, which creates its OWN stacking context
 * capped at 1 — the popper's `z-index: 3000` above only ever competes
 * within that capped context, so it never actually escapes above the
 * sticky sidebar / tabs painting on top of it at the page level. Lifting
 * the wrapper itself (not just the popper) is what actually raises the
 * whole stack. `:has(>` targets exactly that parent — the element whose
 * DIRECT child is the popper — without depending on the hashed class name,
 * which is expected to change on any bundle rebuild. */
div:has(> [class*="MuiAutocomplete-popper"]) {
  z-index: 1300 !important;
}

/* Belt-and-braces: keep the whole header above page content too, in case
 * some other ancestor between the header and the popper wrapper also caps
 * a stacking context lower than 1300. */
header[class*="MuiPaper-root"] {
  position: relative;
  z-index: 1200;
}

/* ---------- Cards / panels ---------- */
[class*="MuiCard"],
[class*="MuiPaper"],
[class*="Sidebar"],
[class*="MuiAccordion"] {
  background-color: var(--mm-bg-1) !important;
  background-image: none !important;
  border: 1px solid var(--mm-border) !important;
  border-radius: var(--mm-radius) !important;
  box-shadow: var(--mm-shadow) !important;
}

[class*="MuiCard"]:hover,
[class*="MuiAccordion"]:hover {
  border-color: var(--mm-highlight) !important;
  transition: border-color 200ms ease, transform 150ms ease;
}

/* Package list rows */
[class*="MuiListItem"],
[class*="MuiTableRow"] {
  border-radius: calc(var(--mm-radius) - 4px);
  transition: background-color 150ms ease;
}
[class*="MuiListItem"]:hover,
[class*="MuiTableRow"]:hover {
  background-color: rgba(255, 255, 255, 0.04) !important;
}

/* ---------- Package cards (fix round 4: flat hover) ---------- */
/* Owner feedback: "a lot of back colors" on hover. Root cause was MUI's own
 * layered hover treatment on the card — a ripple overlay div plus a
 * focus-highlight overlay div, each painting their own semi-transparent
 * color on top of the card and on top of each other/the [class*="MuiCard"]
 * rules above. Fix: one flat card surface, one flat hover surface, no
 * gradients, and the MUI overlay elements themselves are hidden outright so
 * they can never layer a second/third color on top. */
.package,
[data-testid="package-item-list"] {
  background-color: var(--mm-bg-1) !important;
  background-image: none !important;
  border: 1px solid #343b45 !important;
  border-radius: 12px !important;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2) !important;
  transition: border-color 150ms ease, background-color 150ms ease;
}

.package:hover,
[data-testid="package-item-list"]:hover {
  border-color: var(--mm-highlight) !important;
  background-color: var(--mm-bg-2) !important;
}

.package *,
[data-testid="package-item-list"] * {
  background-image: none !important;
}

.package [class*="TouchRipple"],
.package [class*="focusHighlight"],
[data-testid="package-item-list"] [class*="TouchRipple"],
[data-testid="package-item-list"] [class*="focusHighlight"] {
  display: none !important;
}

/* Fix round 5: the round-4 `mm-pkg-grid`/`mm-pkg-cell` tagging approach
 * (custom.js finding the nearest common ancestor of `.package` wrappers and
 * grid-laying it out) is REMOVED — it targeted Verdaccio's native package
 * list, which turned out to be react-virtualized (rows are absolutely
 * positioned and only the visible rows exist in the DOM at any time), so a
 * CSS grid on that container could never work. See the `.mm-grid` /
 * `.mm-hidden` rules below: custom.js now fetches the full package list
 * itself and renders an independent grid, hiding the native virtualized
 * list instead of trying to reflow it. */
.mm-hidden {
  display: none !important;
}

/* Fix round 6: pre-hide the native virtualized package list on the home
 * page BEFORE custom.js has a chance to run at all. Previously the native
 * list painted for a frame (or more, on a slow connection) before
 * buildHomeGrid() fetched the package list and hid it — a visible "flash"
 * of the old UI. This rule hides it instantly via plain CSS the moment the
 * home page mounts; custom.js's `.mm-hidden` class (added once the custom
 * grid is actually built) is now redundant belt-and-braces rather than
 * load-bearing. Scoped strictly under [data-testid="home-page-container"]
 * so no other virtualized list anywhere else in the app is touched.
 *
 * If the packages fetch fails, is unauthorized, or returns zero packages,
 * custom.js adds `.mm-native-visible` to the home container instead of
 * building an (otherwise empty) grid — the rule below restores the native
 * list as a working fallback in that case. */
[data-testid="home-page-container"] [class*="ReactVirtualized"] {
  visibility: hidden;
  height: 0 !important;
  overflow: hidden !important;
}

.mm-native-visible [class*="ReactVirtualized"] {
  visibility: visible !important;
  height: auto !important;
  display: block !important;
}

/* Fix round 14: expired-session hint bar (custom.js markHomeGridDegraded/
 * buildSessionHintBar) — shown above the native-list fallback when a token
 * was sent but the packages fetch came back empty or unauthorized (most
 * likely an expired registry-UI JWT), instead of leaving the homepage
 * silently blank. Compact, same dark chip surface as the search-popper fix
 * above (#1f262e / #343b45), muted body text; the dismiss button only
 * hides the bar itself (round 13/14's rebuild-on-auth-change logic is what
 * actually clears it once the user logs back in). */
.mm-session-hint {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 0 0 12px;
  padding: 10px 14px;
  background-color: #1f262e;
  border: 1px solid #343b45;
  border-radius: 8px;
  color: #8b949e;
  font-size: 0.875rem;
  line-height: 1.4;
}

.mm-session-hint-dismiss {
  flex-shrink: 0;
  background: transparent;
  border: none;
  color: #8b949e;
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  padding: 2px 4px;
}

.mm-session-hint-dismiss:hover,
.mm-session-hint-dismiss:focus-visible {
  color: #e6edf3;
}

.mm-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
  gap: 16px;
  align-items: stretch;
  margin-top: 8px;
}

.mm-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  background-color: var(--mm-bg-1);
  background-image: none !important;
  border: 1px solid #343b45;
  border-radius: 12px;
  padding: 16px;
  cursor: pointer;
  transition: border-color 150ms ease, background-color 150ms ease;
}

.mm-card:hover,
.mm-card:focus-visible {
  border-color: var(--mm-highlight);
  background-color: var(--mm-bg-2);
  outline: none;
}

.mm-card-title {
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
  color: #e6edf3;
  overflow-wrap: anywhere;
}

.mm-card-desc {
  margin: 0;
  font-size: 0.875rem;
  color: #9a9ab0;
  flex-grow: 1;
}

.mm-card-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

/* Fix round 7: version chip reverts to the original brand mint (owner
 * request) — the only spot in this file that still uses the mint token; the
 * rest of the UI stays on the round-6 monochrome scheme.
 * Fix round 9: the border alpha dimmed too far in round 7/8 — brightened
 * back up below. Text color and background fill are unchanged. */
.mm-card-chip {
  display: inline-block;
  padding: 2px 10px;
  border-radius: 999px;
  background-color: rgba(2, 248, 178, 0.08);
  color: #02f8b2;
  border: 1px solid rgba(2, 248, 178, 0.6);
  font-size: 0.75rem;
  font-weight: 600;
}

.mm-card-date {
  font-size: 0.75rem;
  color: #7d8590;
}

/* Fix round 8: the version chip lives inside this row (appended last in
 * custom.js's buildPackageCard, after the avatar + name) instead of its own
 * meta row — same line as the author.
 * Fix round 9: the chip no longer sits directly in this row — it's now
 * inside `.mm-card-author-right` below, stacked above the "published X days
 * ago" date, both pushed to the far right of this row as one column. */
.mm-card-author {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: auto;
}

/* Fix round 9: right-aligned column holding the version chip on top and the
 * publish date directly under it — replaces round 8's chip-only
 * margin-left: auto rule (chip alone pushed right, no room for a date
 * beneath it). */
.mm-card-author-right {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
  margin-left: auto;
}

.mm-card-author img {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  object-fit: cover;
}

.mm-card-author span {
  font-size: 0.8125rem;
  color: #9a9ab0;
}

/* ---------- Buttons / tabs (incl. the install-snippet package-manager tabs) ---------- */
[class*="MuiButton-root"],
[class*="MuiTab-root"],
[class*="MuiChip-root"] {
  border-radius: calc(var(--mm-radius) - 4px) !important;
  text-transform: none !important;
  transition: background-color 150ms ease, color 150ms ease, border-color 150ms ease, opacity 150ms ease;
}

[class*="MuiButton-contained"],
[class*="MuiTab-root"][aria-selected="true"],
[class*="Mui-selected"] {
  background-color: var(--mm-primary) !important;
  color: #fff !important;
}

[class*="MuiButton-root"]:hover {
  opacity: 0.92;
}

/* Links, active nav, and any element MUI marks "primary" pick up the brand. */
a,
[class*="MuiLink"] {
  color: var(--mm-highlight);
}
a:hover {
  color: var(--mm-highlight);
  text-decoration-color: var(--mm-highlight);
}

[class*="MuiSvgIcon"][class*="colorPrimary"],
[class*="Mui-checked"] {
  color: var(--mm-primary) !important;
}

/* ---------- Code / install snippet block ---------- */
/* Excludes the README container ([data-testid="readme"] / .markdown-body):
 * that content is fully styled by the vendored github-markdown-css below,
 * and these rules (font-family + !important background) would otherwise
 * fight it. */
pre:not([data-testid="readme"] pre):not(.markdown-body pre),
code:not([data-testid="readme"] code):not(.markdown-body code),
kbd:not([data-testid="readme"] kbd):not(.markdown-body kbd),
[class*="CodeBlock"]:not([data-testid="readme"] [class*="CodeBlock"]):not(.markdown-body [class*="CodeBlock"]),
[class*="MuiCard"] pre:not([data-testid="readme"] pre):not(.markdown-body pre) {
  font-family: "JetBrains Mono", "Fira Code", ui-monospace, SFMono-Regular, Menlo, monospace;
  background-color: var(--mm-bg-2) !important;
  border: 1px solid var(--mm-border);
  border-radius: calc(var(--mm-radius) - 4px);
}

/* Avatars (see custom.js — gravatar images get swapped to a single GitHub
 * avatar; scoped to img[src*="gravatar"] only, so this styling rule matches
 * the same narrow selector rather than any alt/class heuristic that could
 * catch unrelated README images). */
img[src*="gravatar"] {
  border-radius: 50%;
  border: 1px solid var(--mm-border);
}

/* Fix round 7 (re-anchored — see follow-up note below): kill the tab-click
 * animation on the detail tabs (Readme/Dependencies/Versions/Uplinks) — the
 * MUI ripple, the sliding tab indicator, and any tab-button transition all
 * made switching tabs feel laggy.
 *
 * Follow-up: this session's own grep of the shipped @verdaccio/ui-theme
 * bundle showed `data-testid="tabs"` actually belongs to a different,
 * generic Tabs instance (the info-dialog's `aria-label="infoTabs"` Tabs) —
 * not this detail tab bar, whose individual tabs carry their own
 * `<name>-tab` testids without a `data-testid="tabs"` wrapper. Re-anchored
 * via `:has([data-testid="readme-tab"])` instead, which identifies the
 * detail tab bar's own MuiTabs-root directly and can't accidentally match
 * the unrelated info-dialog tabs. */
[class*="MuiTabs-root"]:has([data-testid="readme-tab"]) [class*="TouchRipple"] {
  display: none !important;
}

[class*="MuiTabs-root"]:has([data-testid="readme-tab"]) [class*="MuiTabs-indicator"] {
  transition: none !important;
}

[data-testid$="-tab"] {
  transition: none !important;
}

/* Tab content fade/grow (MUI's default panel-switch transition), scoped
 * under the same re-anchored tabs container so it never touches transitions
 * elsewhere. */
[class*="MuiTabs-root"]:has([data-testid="readme-tab"]) [class*="MuiFade-root"],
[class*="MuiTabs-root"]:has([data-testid="readme-tab"]) [class*="MuiGrow-root"],
[class*="MuiTabs-root"]:has([data-testid="readme-tab"]) [class*="MuiCollapse-root"] {
  transition: none !important;
}

/* ---------- Detail page tabs (fix round 5) ---------- */
/* Uplinks tab: config.yaml's web.showUplinks: false already removes it at
 * the source (native Verdaccio toggle); this is belt-and-braces in case a
 * future ui-theme build renders it before that config takes effect. */
[data-testid="uplinks-tab"] {
  display: none !important;
}

/* Dependencies tab: each dependency-type block inside dependencies-box
 * carries its own key as data-testid (e.g. data-testid="devDependencies"),
 * verified directly against the shipped Dependencies bundle — hide the
 * devDependencies block only; dependencies/peerDependencies/
 * bundleDependencies/optionalDependencies stay visible. Belt-and-braces
 * alongside custom.js's hideDevDependenciesBlock(), which also covers a
 * future bundle that renamed/dropped that testid but kept the title text. */
[data-testid="dependencies-box"] [data-testid="devDependencies"] {
  display: none !important;
}

/* Raw manifest button: config.yaml's web.showRaw: false already removes it
 * at the source (native Verdaccio toggle); belt-and-braces in case a future
 * ui-theme build renders it before that config takes effect. */
[data-testid="raw-btn"] {
  display: none !important;
}

/* Module-type badges (the little CJS/ESM icons next to the package name on
 * the detail page). Alt text verified directly against the shipped bundle
 * (node_modules/@verdaccio/ui-theme/static/build.*.js): `kr=({module:e})=>
 * e==='commonjs'?...:e==='module'?...:null`, rendering `<img alt="commonjs">`
 * or `<img alt="es6 modules">`. Their wrapper is a plain styled `<div>` with
 * a hashed emotion class name (not a stable hook), so instead of guessing
 * that class we hide the badge's own direct parent generically via :has() —
 * this also removes the wrapper's marginLeft spacing, leaving no gap. */
img[alt="commonjs"],
img[alt="es6 modules"] {
  display: none !important;
}

*:has(> img[alt="commonjs"]),
*:has(> img[alt="es6 modules"]) {
  display: none !important;
}

/* ---------- Un-box the README (fix round 8) ---------- */
/* On the detail page the readme was triple-boxed: an outer tab-content card
 * around an inner panel around [data-testid="readme"] itself, each with its
 * own MuiCard/MuiPaper background+border+shadow (from the generic
 * "Cards / panels" rule near the top of this file) stacked on top of the
 * markdown panel's own chrome (the `.markdown-body` rule near the bottom).
 * Strip every ANCESTOR card's visuals down to nothing — :has() matches each
 * of them regardless of depth, so both the outer tab-content card and the
 * inner panel are caught in one rule without needing to know the exact
 * nesting — leaving [data-testid="readme"]'s own `.markdown-body` panel
 * (background #0d1117, border #30363d, radius) as the ONLY visible box.
 * Higher specificity than the plain `[class*="MuiCard"]`/`[class*="MuiPaper"]`
 * rule (an extra :has() argument), so this wins regardless of source order. */
[class*="MuiCard"]:has([data-testid="readme"]),
[class*="MuiPaper"]:has([data-testid="readme"]),
[role="tabpanel"]:has([data-testid="readme"]) {
  background: transparent !important;
  border: none !important;
  box-shadow: none !important;
  padding: 0 !important;
}

/* Catch-all companion to the rule above, applied by custom.js's
 * unboxReadmeAncestors(): a ui-theme build can wrap the readme in a plain
 * styled <div> whose emotion class matches none of the three selectors
 * above, which reappears as a second box around the markdown panel. The JS
 * decides from computed style which ancestors actually paint a surface, so
 * this class only ever lands on a real box. Padding is deliberately NOT
 * reset here — the class can land on a layout container whose padding is
 * the page gutter. */
.mm-unboxed {
  background: transparent !important;
  border: none !important;
  box-shadow: none !important;
}

/* ---------- Detail-page sidebar info box (fix round 8) ---------- */
/* Same dark surface as the markdown panel (#0d1117 / border #30363d)
 * instead of the app-wide --mm-bg-1 surface tone — visually pairs the
 * sidebar with the (also just un-boxed, above) readme panel. Higher
 * specificity than the generic "Cards / panels" rule above (data-testid
 * attribute selector vs. a bare class-fragment one), so no !important
 * tug-of-war is needed on source order for the background/border, though
 * !important is still used since the generic rule also uses it. */
[data-testid="sidebar"] {
  background-color: #0d1117 !important;
  border: 1px solid #30363d !important;
  /* Round-12: the sidebar is position:sticky, which (like the popper
   * wrapper above) opens its own stacking context — pin it explicitly low
   * so its sticky positioning can never end up competing with (and
   * painting over) the search popper's now-lifted stack. */
  z-index: 0;
}

/* Package description text (and, by extension, the "Latest vX.Y.Z -
 * Published ..." line below it — see .mm-latest-ver, which overrides just
 * the version token back to white/bold) — muted gray, matching the
 * markdown panel's own secondary-text tone.
 *
 * Fix round 10: round 8's `[data-testid="sidebar"] p {color: #8b949e;}`
 * never actually took — field-verified the description text isn't a bare
 * `<p>` at all, it's a MUI Typography component (`[class*="MuiTypography-
 * body"]`), which the plain `p` selector never matched. Broadened to catch
 * both, and given `!important` since MUI's own generated classes carry
 * inline-level specificity/order that a plain descendant selector can lose
 * to. The two exceptions below (.mm-latest-ver, the title) are restated
 * AFTER this rule, also with `!important`, specifically so they win the
 * tie against it regardless of source order or nesting. */
[data-testid="sidebar"] p,
[data-testid="sidebar"] [class*="MuiTypography-body"] {
  color: #8b949e !important;
}

/* Fix round 11: rounds 8 and 10 both tried to gray the description via a
 * guessed CSS selector (the plain `p` / `MuiTypography-body` rule directly
 * above) — field-verified BOTH missed the real element; the description
 * stayed white. custom.js's tagDescriptionText() replaces the guess with a
 * deterministic DOM-structural pass and tags the actual description
 * elements with `.mm-desc`; the `* ` half is included since a tagged
 * element can itself carry nested inline markup (links, code spans) that
 * would otherwise fall back to inherited (white) text color. */
.mm-desc,
.mm-desc * {
  color: #8b949e !important;
}

/* custom.js's wrapLatestVersion() wraps the vX.Y.Z token of the "Latest
 * vX.Y.Z - Published ..." sidebar line in this span; the rest of that line
 * stays the muted gray set above. Restated after the gray rule (fix round
 * 10) so it can't be caught by it. */
.mm-latest-ver {
  color: #fff !important;
  font-weight: 600;
}

/* Fix round 10: the package title itself must stay white — it's a heading
 * element (or the MUI Typography-h* variant of one), never the muted
 * description text, so it gets its own explicit exception, restated after
 * the gray rule for the same reason as .mm-latest-ver above. */
[data-testid="sidebar"] h1,
[data-testid="sidebar"] h2,
[data-testid="sidebar"] h3,
[data-testid="sidebar"] h4,
[data-testid="sidebar"] h5,
[data-testid="sidebar"] b,
[data-testid="sidebar"] strong,
[data-testid="sidebar"] [class*="MuiTypography-h"] {
  color: #fff !important;
}

/* ---------- Install command code box (fix round 10) ---------- */
/* The npm-manager install item ([data-testid="installListItem-npm"]) — bun
 * icon + command text — now reads as a code block instead of a plain row:
 * monospace font, dark surface matching the vendored markdown `pre`/`code`
 * tone (#161b22 sits between the readme panel #0d1117 and its inline-code
 * chip #656c7633), a hairline border, and rounded corners. `user-select:
 * all` on the item means a single click selects the whole command in one
 * go — this doubles as the copy affordance now that the copy button itself
 * is hidden (see the buttons rule below). */
[data-testid="sidebar"] [data-testid="installListItem-npm"] {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
    "Liberation Mono", monospace;
  background: #161b22;
  border: 1px solid #30363d;
  border-radius: 6px;
  padding: 6px 10px;
  user-select: all;
}

[data-testid="sidebar"] [data-testid="installListItem-npm"] img {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
}

/* ---------- Remove Installation buttons (fix round 10) ---------- */
/* The per-item copy button inside the install list is redundant now that
 * the whole command is a click-to-select code box (above); the
 * Installation header's gear/settings icon button has no stable
 * data-testid, so `.installation-header button` is a best-effort hook
 * (harmless no-op if that class doesn't exist in a given build) — the
 * reliable mechanism for it is custom.js's hideInstallationHeaderButtons(),
 * which hides any <button> found in the Installation heading's own row by
 * text match, independent of any class name. Scoped strictly within the
 * sidebar so this can never reach a button anywhere else in the app. */
[data-testid="sidebar"] [data-testid="installList"] button,
[data-testid="sidebar"] .installation-header button {
  display: none !important;
}

/* ---------- README anchor scroll offset (fix round 10) ---------- */
/* custom.js's assignReadmeHeadingIds() gives every README heading a
 * GitHub-style slug id so in-page ToC links (#installation etc.) resolve;
 * this keeps an anchored heading from landing flush under the sticky
 * header. */
.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
  scroll-margin-top: 80px;
}

/* ---------- GFM task lists (fix round 7) ---------- */
/* The renderer emits plain `<li><input type="checkbox">...</li>` markup
 * without GitHub's own task-list classes, so a bullet shows next to the
 * checkbox. custom.js adds `.task-list-item` / `.contains-task-list` so the
 * vendored github-markdown-css's own `.task-list-item{list-style-type:none}`
 * rule (see the vendored block below) applies; this `:has()` rule is a
 * class-independent safety net for the bullet, and the spacing rule matches
 * the vendored sheet's `.task-list-item-checkbox` margin/alignment, which
 * only targets that specific class — not a bare checkbox input. */
.markdown-body li:has(> input[type="checkbox"]) {
  list-style-type: none;
}

.markdown-body .task-list-item input {
  margin: 0 0.2em 0.25em -1.4em;
  vertical-align: middle;
}

/* ---------- Footer ---------- */
/* The "Powered by Verdaccio / Made with ♥" bar — not part of our branding. */
[data-testid="footer"] {
  display: none !important;
}

/* ---------- README alert boxes (GitHub-exact) ---------- */
/* Structure injected by custom.js: a <blockquote> that started with
 * "[!NOTE]" etc. is replaced with GitHub's real markup —
 * <div class="markdown-alert markdown-alert-<type>"> containing a
 * <p class="markdown-alert-title"> (octicon + capitalized label) followed
 * by the original content.
 *
 * NOTE: the vendored github-markdown-css block below ships its own, more
 * specific `.markdown-body .markdown-alert.markdown-alert-<type>` rules
 * (higher specificity — two classes + a descendant combinator vs. our one
 * class here). Its title colors happen to already match the palette below,
 * but its border-left-colors are GitHub's real two-tone values, not the
 * flat "border = title color" palette specified for this skin — so the
 * per-type border-left-color below carries !important to guarantee it
 * wins regardless of source order. */
.markdown-alert {
  padding: 0.5rem 1rem;
  margin-bottom: 1rem;
  border-left: 0.25em solid;
  color: inherit;
}

.markdown-alert-title {
  display: flex;
  align-items: center;
  gap: 0.5em;
  font-weight: 500;
  margin-top: 0;
}

.markdown-alert-note {
  border-left-color: #4493f8 !important;
}
.markdown-alert-note .markdown-alert-title {
  color: #4493f8;
}

.markdown-alert-tip {
  border-left-color: #3fb950 !important;
}
.markdown-alert-tip .markdown-alert-title {
  color: #3fb950;
}

.markdown-alert-important {
  border-left-color: #ab7df8 !important;
}
.markdown-alert-important .markdown-alert-title {
  color: #ab7df8;
}

.markdown-alert-warning {
  border-left-color: #d29922 !important;
}
.markdown-alert-warning .markdown-alert-title {
  color: #d29922;
}

.markdown-alert-caution {
  border-left-color: #f85149 !important;
}
.markdown-alert-caution .markdown-alert-title {
  color: #f85149;
}

/* =====================================================================
 * Vendored: github-markdown-css v5.8.1 (dark theme), MIT License.
 * https://github.com/sindresorhus/github-markdown-css
 * Downloaded verbatim (minified) from
 * https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.8.1/github-markdown-dark.min.css
 * so `.markdown-body` (the README container — see custom.js, which adds
 * this class to [data-testid="readme"] if missing) gets genuine GitHub
 * markdown styling. Do not hand-edit the minified block below; if it ever
 * needs to change, re-download and replace it wholesale.
 * ===================================================================== */
.markdown-body{color-scheme:dark;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;margin:0;color:#f0f6fc;background-color:#0d1117;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";font-size:16px;line-height:1.5;word-wrap:break-word}.markdown-body .octicon{display:inline-block;fill:currentColor;vertical-align:text-bottom}.markdown-body h1:hover .anchor .octicon-link:before,.markdown-body h2:hover .anchor .octicon-link:before,.markdown-body h3:hover .anchor .octicon-link:before,.markdown-body h4:hover .anchor .octicon-link:before,.markdown-body h5:hover .anchor .octicon-link:before,.markdown-body h6:hover .anchor .octicon-link:before{width:16px;height:16px;content:' ';display:inline-block;background-color:currentColor;-webkit-mask-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' version='1.1' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg>");mask-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' version='1.1' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg>")}.markdown-body details,.markdown-body figcaption,.markdown-body figure{display:block}.markdown-body summary{display:list-item}.markdown-body [hidden]{display:none!important}.markdown-body a{background-color:transparent;color:#4493f8;text-decoration:none}.markdown-body abbr[title]{border-bottom:none;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}.markdown-body b,.markdown-body strong{font-weight:600}.markdown-body dfn{font-style:italic}.markdown-body h1{margin:.67em 0;font-weight:600;padding-bottom:.3em;font-size:2em;border-bottom:1px solid #3d444db3}.markdown-body mark{background-color:#bb800926;color:#f0f6fc}.markdown-body small{font-size:90%}.markdown-body sub,.markdown-body sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}.markdown-body sub{bottom:-.25em}.markdown-body sup{top:-.5em}.markdown-body img{border-style:none;max-width:100%;box-sizing:content-box}.markdown-body code,.markdown-body kbd,.markdown-body pre,.markdown-body samp{font-family:monospace;font-size:1em}.markdown-body figure{margin:1em 2.5rem}.markdown-body hr{box-sizing:content-box;overflow:hidden;background:0 0;border-bottom:1px solid #3d444db3;height:.25em;padding:0;margin:1.5rem 0;background-color:#3d444d;border:0}.markdown-body input{font:inherit;margin:0;overflow:visible;font-family:inherit;font-size:inherit;line-height:inherit}.markdown-body [type=button],.markdown-body [type=reset],.markdown-body [type=submit]{-webkit-appearance:button;appearance:button}.markdown-body [type=checkbox],.markdown-body [type=radio]{box-sizing:border-box;padding:0}.markdown-body [type=number]::-webkit-inner-spin-button,.markdown-body [type=number]::-webkit-outer-spin-button{height:auto}.markdown-body [type=search]::-webkit-search-cancel-button,.markdown-body [type=search]::-webkit-search-decoration{-webkit-appearance:none;appearance:none}.markdown-body ::-webkit-input-placeholder{color:inherit;opacity:.54}.markdown-body ::-webkit-file-upload-button{-webkit-appearance:button;appearance:button;font:inherit}.markdown-body a:hover{text-decoration:underline}.markdown-body ::placeholder{color:#9198a1;opacity:1}.markdown-body hr::before{display:table;content:""}.markdown-body hr::after{display:table;clear:both;content:""}.markdown-body table{border-spacing:0;border-collapse:collapse;display:block;width:max-content;max-width:100%;overflow:auto;font-variant:tabular-nums}.markdown-body td,.markdown-body th{padding:0}.markdown-body details summary{cursor:pointer}.markdown-body [role=button]:focus,.markdown-body a:focus,.markdown-body input[type=checkbox]:focus,.markdown-body input[type=radio]:focus{outline:2px solid #1f6feb;outline-offset:-2px;box-shadow:none}.markdown-body [role=button]:focus:not(:focus-visible),.markdown-body a:focus:not(:focus-visible),.markdown-body input[type=checkbox]:focus:not(:focus-visible),.markdown-body input[type=radio]:focus:not(:focus-visible){outline:solid 1px transparent}.markdown-body [role=button]:focus-visible,.markdown-body a:focus-visible,.markdown-body input[type=checkbox]:focus-visible,.markdown-body input[type=radio]:focus-visible{outline:2px solid #1f6feb;outline-offset:-2px;box-shadow:none}.markdown-body a:not([class]):focus,.markdown-body a:not([class]):focus-visible,.markdown-body input[type=checkbox]:focus,.markdown-body input[type=checkbox]:focus-visible,.markdown-body input[type=radio]:focus,.markdown-body input[type=radio]:focus-visible{outline-offset:0}.markdown-body kbd{display:inline-block;padding:.25rem;font:11px ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;line-height:10px;color:#f0f6fc;vertical-align:middle;background-color:#151b23;border:solid 1px #3d444db3;border-bottom-color:#3d444db3;border-radius:6px;box-shadow:inset 0 -1px 0 #3d444db3}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{margin-top:1.5rem;margin-bottom:1rem;font-weight:600;line-height:1.25}.markdown-body h2{font-weight:600;padding-bottom:.3em;font-size:1.5em;border-bottom:1px solid #3d444db3}.markdown-body h3{font-weight:600;font-size:1.25em}.markdown-body h4{font-weight:600;font-size:1em}.markdown-body h5{font-weight:600;font-size:.875em}.markdown-body h6{font-weight:600;font-size:.85em;color:#9198a1}.markdown-body p{margin-top:0;margin-bottom:10px}.markdown-body blockquote{margin:0;padding:0 1em;color:#9198a1;border-left:.25em solid #3d444d}.markdown-body ol,.markdown-body ul{margin-top:0;margin-bottom:0;padding-left:2em}.markdown-body ol ol,.markdown-body ul ol{list-style-type:lower-roman}.markdown-body ol ol ol,.markdown-body ol ul ol,.markdown-body ul ol ol,.markdown-body ul ul ol{list-style-type:lower-alpha}.markdown-body dd{margin-left:0}.markdown-body code,.markdown-body samp,.markdown-body tt{font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;font-size:12px}.markdown-body pre{margin-top:0;margin-bottom:0;font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;font-size:12px;word-wrap:normal}.markdown-body .octicon{display:inline-block;overflow:visible!important;vertical-align:text-bottom;fill:currentColor}.markdown-body input::-webkit-inner-spin-button,.markdown-body input::-webkit-outer-spin-button{margin:0;appearance:none}.markdown-body .mr-2{margin-right:.5rem!important}.markdown-body::before{display:table;content:""}.markdown-body::after{display:table;clear:both;content:""}.markdown-body>:first-child{margin-top:0!important}.markdown-body>:last-child{margin-bottom:0!important}.markdown-body a:not([href]){color:inherit;text-decoration:none}.markdown-body .absent{color:#f85149}.markdown-body .anchor{float:left;padding-right:.25rem;margin-left:-20px;line-height:1}.markdown-body .anchor:focus{outline:0}.markdown-body blockquote,.markdown-body details,.markdown-body dl,.markdown-body ol,.markdown-body p,.markdown-body pre,.markdown-body table,.markdown-body ul{margin-top:0;margin-bottom:1rem}.markdown-body blockquote>:first-child{margin-top:0}.markdown-body blockquote>:last-child{margin-bottom:0}.markdown-body h1 .octicon-link,.markdown-body h2 .octicon-link,.markdown-body h3 .octicon-link,.markdown-body h4 .octicon-link,.markdown-body h5 .octicon-link,.markdown-body h6 .octicon-link{color:#f0f6fc;vertical-align:middle;visibility:hidden}.markdown-body h1:hover .anchor,.markdown-body h2:hover .anchor,.markdown-body h3:hover .anchor,.markdown-body h4:hover .anchor,.markdown-body h5:hover .anchor,.markdown-body h6:hover .anchor{text-decoration:none}.markdown-body h1:hover .anchor .octicon-link,.markdown-body h2:hover .anchor .octicon-link,.markdown-body h3:hover .anchor .octicon-link,.markdown-body h4:hover .anchor .octicon-link,.markdown-body h5:hover .anchor .octicon-link,.markdown-body h6:hover .anchor .octicon-link{visibility:visible}.markdown-body h1 code,.markdown-body h1 tt,.markdown-body h2 code,.markdown-body h2 tt,.markdown-body h3 code,.markdown-body h3 tt,.markdown-body h4 code,.markdown-body h4 tt,.markdown-body h5 code,.markdown-body h5 tt,.markdown-body h6 code,.markdown-body h6 tt{padding:0 .2em;font-size:inherit}.markdown-body summary h1,.markdown-body summary h2,.markdown-body summary h3,.markdown-body summary h4,.markdown-body summary h5,.markdown-body summary h6{display:inline-block}.markdown-body summary h1 .anchor,.markdown-body summary h2 .anchor,.markdown-body summary h3 .anchor,.markdown-body summary h4 .anchor,.markdown-body summary h5 .anchor,.markdown-body summary h6 .anchor{margin-left:-40px}.markdown-body summary h1,.markdown-body summary h2{padding-bottom:0;border-bottom:0}.markdown-body ol.no-list,.markdown-body ul.no-list{padding:0;list-style-type:none}.markdown-body ol[type="a s"]{list-style-type:lower-alpha}.markdown-body ol[type="A s"]{list-style-type:upper-alpha}.markdown-body ol[type="i s"]{list-style-type:lower-roman}.markdown-body ol[type="I s"]{list-style-type:upper-roman}.markdown-body ol[type="1"]{list-style-type:decimal}.markdown-body div>ol:not([type]){list-style-type:decimal}.markdown-body ol ol,.markdown-body ol ul,.markdown-body ul ol,.markdown-body ul ul{margin-top:0;margin-bottom:0}.markdown-body li>p{margin-top:1rem}.markdown-body li+li{margin-top:.25em}.markdown-body dl{padding:0}.markdown-body dl dt{padding:0;margin-top:1rem;font-size:1em;font-style:italic;font-weight:600}.markdown-body dl dd{padding:0 1rem;margin-bottom:1rem}.markdown-body table th{font-weight:600}.markdown-body table td,.markdown-body table th{padding:6px 13px;border:1px solid #3d444d}.markdown-body table td>:last-child{margin-bottom:0}.markdown-body table tr{background-color:#0d1117;border-top:1px solid #3d444db3}.markdown-body table tr:nth-child(2n){background-color:#151b23}.markdown-body table img{background-color:transparent}.markdown-body img[align=right]{padding-left:20px}.markdown-body img[align=left]{padding-right:20px}.markdown-body .emoji{max-width:none;vertical-align:text-top;background-color:transparent}.markdown-body span.frame{display:block;overflow:hidden}.markdown-body span.frame>span{display:block;float:left;width:auto;padding:7px;margin:13px 0 0;overflow:hidden;border:1px solid #3d444d}.markdown-body span.frame span img{display:block;float:left}.markdown-body span.frame span span{display:block;padding:5px 0 0;clear:both;color:#f0f6fc}.markdown-body span.align-center{display:block;overflow:hidden;clear:both}.markdown-body span.align-center>span{display:block;margin:13px auto 0;overflow:hidden;text-align:center}.markdown-body span.align-center span img{margin:0 auto;text-align:center}.markdown-body span.align-right{display:block;overflow:hidden;clear:both}.markdown-body span.align-right>span{display:block;margin:13px 0 0;overflow:hidden;text-align:right}.markdown-body span.align-right span img{margin:0;text-align:right}.markdown-body span.float-left{display:block;float:left;margin-right:13px;overflow:hidden}.markdown-body span.float-left span{margin:13px 0 0}.markdown-body span.float-right{display:block;float:right;margin-left:13px;overflow:hidden}.markdown-body span.float-right>span{display:block;margin:13px auto 0;overflow:hidden;text-align:right}.markdown-body code,.markdown-body tt{padding:.2em .4em;margin:0;font-size:85%;white-space:break-spaces;background-color:#656c7633;border-radius:6px}.markdown-body code br,.markdown-body tt br{display:none}.markdown-body del code{text-decoration:inherit}.markdown-body samp{font-size:85%}.markdown-body pre code{font-size:100%}.markdown-body pre>code{padding:0;margin:0;word-break:normal;white-space:pre;background:0 0;border:0}.markdown-body .highlight{margin-bottom:1rem}.markdown-body .highlight pre{margin-bottom:0;word-break:normal}.markdown-body .highlight pre,.markdown-body pre{padding:1rem;overflow:auto;font-size:85%;line-height:1.45;color:#f0f6fc;background-color:#151b23;border-radius:6px}.markdown-body pre code,.markdown-body pre tt{display:inline;max-width:auto;padding:0;margin:0;overflow:visible;line-height:inherit;word-wrap:normal;background-color:transparent;border:0}.markdown-body .csv-data td,.markdown-body .csv-data th{padding:5px;overflow:hidden;font-size:12px;line-height:1;text-align:left;white-space:nowrap}.markdown-body .csv-data .blob-num{padding:10px .5rem 9px;text-align:right;background:#0d1117;border:0}.markdown-body .csv-data tr{border-top:0}.markdown-body .csv-data th{font-weight:600;background:#151b23;border-top:0}.markdown-body [data-footnote-ref]::before{content:"["}.markdown-body [data-footnote-ref]::after{content:"]"}.markdown-body .footnotes{font-size:12px;color:#9198a1;border-top:1px solid #3d444d}.markdown-body .footnotes ol{padding-left:1rem}.markdown-body .footnotes ol ul{display:inline-block;padding-left:1rem;margin-top:1rem}.markdown-body .footnotes li{position:relative}.markdown-body .footnotes li:target::before{position:absolute;top:calc(.5rem*-1);right:calc(.5rem*-1);bottom:calc(.5rem*-1);left:calc(1.5rem*-1);pointer-events:none;content:"";border:2px solid #1f6feb;border-radius:6px}.markdown-body .footnotes li:target{color:#f0f6fc}.markdown-body .footnotes .data-footnote-backref g-emoji{font-family:monospace}.markdown-body body:has(:modal){padding-right:var(--dialog-scrollgutter)!important}.markdown-body .pl-c{color:#9198a1}.markdown-body .pl-c1,.markdown-body .pl-s .pl-v{color:#79c0ff}.markdown-body .pl-e,.markdown-body .pl-en{color:#d2a8ff}.markdown-body .pl-s .pl-s1,.markdown-body .pl-smi{color:#f0f6fc}.markdown-body .pl-ent{color:#7ee787}.markdown-body .pl-k{color:#ff7b72}.markdown-body .pl-pds,.markdown-body .pl-s,.markdown-body .pl-s .pl-pse .pl-s1,.markdown-body .pl-sr,.markdown-body .pl-sr .pl-cce,.markdown-body .pl-sr .pl-sra,.markdown-body .pl-sr .pl-sre{color:#a5d6ff}.markdown-body .pl-smw,.markdown-body .pl-v{color:#ffa657}.markdown-body .pl-bu{color:#f85149}.markdown-body .pl-ii{color:#f0f6fc;background-color:#8e1519}.markdown-body .pl-c2{color:#f0f6fc;background-color:#b62324}.markdown-body .pl-sr .pl-cce{font-weight:700;color:#7ee787}.markdown-body .pl-ml{color:#f2cc60}.markdown-body .pl-mh,.markdown-body .pl-mh .pl-en,.markdown-body .pl-ms{font-weight:700;color:#1f6feb}.markdown-body .pl-mi{font-style:italic;color:#f0f6fc}.markdown-body .pl-mb{font-weight:700;color:#f0f6fc}.markdown-body .pl-md{color:#ffdcd7;background-color:#67060c}.markdown-body .pl-mi1{color:#aff5b4;background-color:#033a16}.markdown-body .pl-mc{color:#ffdfb6;background-color:#5a1e02}.markdown-body .pl-mi2{color:#f0f6fc;background-color:#1158c7}.markdown-body .pl-mdr{font-weight:700;color:#d2a8ff}.markdown-body .pl-ba{color:#9198a1}.markdown-body .pl-sg{color:#3d444d}.markdown-body .pl-corl{text-decoration:underline;color:#a5d6ff}.markdown-body [role=button]:focus:not(:focus-visible),.markdown-body [role=tabpanel][tabindex="0"]:focus:not(:focus-visible),.markdown-body a:focus:not(:focus-visible),.markdown-body button:focus:not(:focus-visible),.markdown-body summary:focus:not(:focus-visible){outline:0;box-shadow:none}.markdown-body [tabindex="0"]:focus:not(:focus-visible),.markdown-body details-dialog:focus:not(:focus-visible){outline:0}.markdown-body g-emoji{display:inline-block;min-width:1ch;font-family:"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1em;font-style:normal!important;font-weight:400;line-height:1;vertical-align:-.075em}.markdown-body g-emoji img{width:1em;height:1em}.markdown-body .task-list-item{list-style-type:none}.markdown-body .task-list-item label{font-weight:400}.markdown-body .task-list-item.enabled label{cursor:pointer}.markdown-body .task-list-item+.task-list-item{margin-top:.25rem}.markdown-body .task-list-item .handle{display:none}.markdown-body .task-list-item-checkbox{margin:0 .2em .25em -1.4em;vertical-align:middle}.markdown-body ul:dir(rtl) .task-list-item-checkbox{margin:0 -1.6em .25em .2em}.markdown-body ol:dir(rtl) .task-list-item-checkbox{margin:0 -1.6em .25em .2em}.markdown-body .contains-task-list:focus-within .task-list-item-convert-container,.markdown-body .contains-task-list:hover .task-list-item-convert-container{display:block;width:auto;height:24px;overflow:visible;clip:auto}.markdown-body ::-webkit-calendar-picker-indicator{filter:invert(50%)}.markdown-body .markdown-alert{padding:.5rem 1rem;margin-bottom:1rem;color:inherit;border-left:.25em solid #3d444d}.markdown-body .markdown-alert>:first-child{margin-top:0}.markdown-body .markdown-alert>:last-child{margin-bottom:0}.markdown-body .markdown-alert .markdown-alert-title{display:flex;font-weight:500;align-items:center;line-height:1}.markdown-body .markdown-alert.markdown-alert-note{border-left-color:#1f6feb}.markdown-body .markdown-alert.markdown-alert-note .markdown-alert-title{color:#4493f8}.markdown-body .markdown-alert.markdown-alert-important{border-left-color:#8957e5}.markdown-body .markdown-alert.markdown-alert-important .markdown-alert-title{color:#ab7df8}.markdown-body .markdown-alert.markdown-alert-warning{border-left-color:#9e6a03}.markdown-body .markdown-alert.markdown-alert-warning .markdown-alert-title{color:#d29922}.markdown-body .markdown-alert.markdown-alert-tip{border-left-color:#238636}.markdown-body .markdown-alert.markdown-alert-tip .markdown-alert-title{color:#3fb950}.markdown-body .markdown-alert.markdown-alert-caution{border-left-color:#da3633}.markdown-body .markdown-alert.markdown-alert-caution .markdown-alert-title{color:#f85149}.markdown-body>:first-child>.heading-element:first-child{margin-top:0!important}.markdown-body .highlight pre:has(+.zeroclipboard-container){min-height:52px}

/* ---------------------------------------------------------------------
 * Fix round 6: the README now gets its OWN distinct, darker panel instead
 * of blending transparently into the page background (round 3's
 * `background-color: transparent` override below is replaced). The page
 * background is now a lighter neutral (#171c23 — see --mm-bg-0 above); the
 * markdown panel stays GitHub's own dark (#0d1117, the vendored
 * stylesheet's own default, restated here for clarity) with real panel
 * chrome (padding/radius/border) so it visibly reads as a card sitting on
 * top of the page, not a seamless continuation of it. The border color
 * (#30363d) is intentionally GitHub's own, not the app-wide neutral border
 * (#343b45) used elsewhere in this file — it's part of the vendored
 * markdown identity, same as the untouched link blue (#4493f8) above.
 * --------------------------------------------------------------------- */
[data-testid="readme"].markdown-body,
.markdown-body {
  background-color: #0d1117 !important;
  padding: 16px;
  border-radius: 8px;
  border: 1px solid #30363d;
}

/* Only the OUTERMOST markdown panel gets the box. The ui-theme can render
 * its own `.markdown-body` inside [data-testid="readme"] (which custom.js
 * also tags with that class), and the rule above would then paint a panel
 * around a panel — the "double boxed" readme. Nested ones keep the GitHub
 * markdown typography and lose only the surface. */
.markdown-body .markdown-body {
  background-color: transparent !important;
  padding: 0 !important;
  border: none !important;
  border-radius: 0 !important;
}

/* ---------------------------------------------------------------------
 * Documentation tab (fourth tab on package detail pages, fix round 15) —
 * see ui/custom.js's f4f) section for the injection/toggle logic.
 * Monochrome, per spec: no new colors beyond the existing --mm-border /
 * --mm-highlight tokens (which already equal the two swatches named in the
 * spec, #343b45 and #6e7681) plus the same dark surface tones the README
 * panel above already uses (#1f262e select background, #0d1117 iframe
 * background).
 * --------------------------------------------------------------------- */
.mm-doc-tab {
  cursor: pointer;
  user-select: none;
}

.mm-doc-tab:hover {
  opacity: 0.85;
}

.mm-docs-panel {
  padding: 16px 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.mm-docs-controls {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

.mm-docs-select {
  background-color: #1f262e;
  border: 1px solid #343b45;
  color: var(--mm-text);
  border-radius: calc(var(--mm-radius) - 4px);
  padding: 6px 10px;
  font-family: 'Inter', system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

.mm-docs-select:hover,
.mm-docs-select:focus {
  border-color: var(--mm-highlight);
  outline: none;
}

.mm-docs-open-link {
  color: var(--mm-highlight);
  text-decoration: none;
  font-size: 0.875rem;
  white-space: nowrap;
}

.mm-docs-open-link:hover {
  text-decoration: underline;
}

.mm-docs-iframe {
  width: 100%;
  height: calc(100vh - 180px);
  min-height: 520px;
  border: 1px solid #343b45;
  border-radius: 8px;
  background-color: #0d1117;
}

/* ---------------------------------------------------------------------
 * Remove the package-info sidebar (fix round 17).
 *
 * The detail page ships as a two-column row: tab content beside a sticky
 * package-info panel. That panel squeezed every tab — the docs iframe
 * worst of all — into two thirds of the page. Two earlier attempts (hiding
 * it only on the docs tab, then restacking it as a header block above the
 * tabs) were both rejected, so it is now gone outright and the tab content
 * takes the whole row.
 *
 * Anchored on the ui-theme's own stable hooks rather than MUI grid class
 * names: the row is [data-testid="version-layout"] and its two children are
 * the content and sidebar columns, distinguished by which one contains
 * [data-testid="sidebar"]. Verified against the shipped bundle. No JS is
 * involved — nothing to keep in sync with a re-render.
 *
 * NOTE: the package name, description and "Latest vX - Published ..." line
 * live INSIDE that sidebar, so the detail page no longer names its own
 * package. That is the deliberate trade for the full width.
 * ------------------------------------------------------------------- */
[data-testid="version-layout"] > *:has([data-testid="sidebar"]) {
  display: none !important;
}

[data-testid="version-layout"] > *:not(:has([data-testid="sidebar"])) {
  flex-basis: 100% !important;
  max-width: 100% !important;
  width: 100% !important;
}

.mm-docs-message {
  color: var(--mm-text-dim);
  padding: 24px 0;
}

/* Native tab content hidden while our panel is shown: every direct child of
 * the tabs' shared parent EXCEPT the tabs root itself (tagged
 * `.mm-docs-tabs-root` by custom.js the first time it's found — a class,
 * not a selector guess, so this works whether or not that ancestor also
 * carries the real `[class*="MuiTabs-root"]` MUI class) and our own panel
 * is hidden outright; restored the moment any native tab is clicked (see
 * custom.js's hideDocsPanel()). */
.mm-docs-native-hidden > *:not(.mm-docs-tabs-root):not(.mm-docs-panel) {
  display: none !important;
}
