/*!
 * مِهَار | Mihhar — Design System  ·  Dark + White + Blue
 * ------------------------------------------------------------------
 * Principles
 *   1. Dark ground, white content, blue emphasis. Depth comes from the
 *      surface ramp and hairline borders — never from shadows or glass.
 *   2. One theme. There is no light mode and no theme switcher; the
 *      product looks the same on every install.
 *   3. Blue is a signal, not decoration. It is spent only on primary
 *      actions, active navigation, selection, links, focus, progress
 *      and key metrics. Everything else is neutral.
 *   4. No transforms, no lift, no glow, no gradients as structure. The
 *      only motion is the ~110ms a control needs to feel responsive.
 *   5. One scale for type, one for space, one for radius. Every screen
 *      of the product is assembled from the same parts.
 *   6. RTL-first, and defensively overflow-proof.
 *   7. Three weights: 400 body, 500 emphasis, 700 heading. Tajawal has
 *      no 600 cut, so a rule asking for one does not fail — it resolves
 *      to 700, and the design ends up with two weights pretending to be
 *      three. Every 600 in this product was rewritten to 500 for that
 *      reason, not as a restyling.
 */

:root {
  /* ── Brand (accent is injected at runtime from settings) ───────── */
  --mh-accent: #2563eb;
  --mh-accent-rgb: 37, 99, 235;
  --mh-accent-hover: #3b76f0;   /* on dark, hover brightens */
  --mh-accent-strong: #1d4ed8;  /* pressed / heavy fills    */
  --mh-accent-soft: #11203a;    /* tinted dark fill         */
  --mh-accent-line: #1e4488;    /* tinted dark border       */

  /* The accent, as *text*.
     #2563eb is the brand blue and it is the right fill — white on it
     reads at 8:1. As text on the dark ground it reaches only 3.2:1,
     which fails the body-text floor, so links, active tabs and accent
     badges take a lifted tint of the same hue instead (6.6:1). Fills
     keep the brand colour; only type moves. */
  --mh-accent-text: #80a5f3;

  /* ── The dark ramp ─────────────────────────────────────────────── */
  --mh-d-900: #080b12;  /* page ground              */
  --mh-d-800: #0f131c;  /* surface                  */
  --mh-d-700: #151b26;  /* elevated surface         */
  --mh-d-600: #1b2231;  /* inset / hover            */
  --mh-d-500: #232b3c;  /* strong inset             */

  /* The text ramp.
     On a dark ground you cannot have four widely-spaced greys that all
     clear 4.5:1 — the range simply is not there. So the ramp is tuned to
     the job each rung does rather than to even visual spacing:
     `text-2` and `text-3` both carry real copy and both clear 4.5:1,
     and `text-4` is the quietest step — now also above the line, for
     the reason set out beside it.
     Measured against --mh-d-800 (#0f131c), the surface most text sits on. */
  --mh-white: #ffffff;
  --mh-slate-200: #e2e8f0;   /* 12.6:1 */
  --mh-slate-300: #cbd5e1;   /* 10.4:1 */
  --mh-slate-400: #a9b4c7;   /*  7.8:1 — secondary body copy */
  --mh-slate-500: #8b97ac;   /*  5.5:1 — captions, labels, table heads */

  /* Was #64748b at 3.4:1, labelled "decorative only, never body" — and
     reached for as body all over the product regardless: a delivery
     promise, a rating count, the date on a review, the note under a
     price, a job's city, a date range on a timeline. A rule that has to
     be remembered on every new line of CSS is a rule that gets broken,
     so the colour now clears AA instead of the comment asking people
     not to use it.

     4.5:1 on --mh-d-600, the lightest surface it lands on, and 5.6:1 on
     the page ground. Still visibly the quietest rung in the ramp. */
  --mh-slate-600: #7b8aa0;   /*  4.5:1 — quiet, and still readable */

  /* ── Semantic surfaces ─────────────────────────────────────────── */
  --mh-bg: var(--mh-d-900);
  --mh-surface: var(--mh-d-800);
  --mh-surface-sub: var(--mh-d-700);
  --mh-surface-mute: var(--mh-d-600);
  --mh-surface-hard: var(--mh-d-500);
  --mh-border: rgba(255, 255, 255, 0.08);
  --mh-border-strong: rgba(255, 255, 255, 0.14);
  --mh-border-hard: rgba(255, 255, 255, 0.22);
  --mh-text: var(--mh-white);
  --mh-text-2: var(--mh-slate-400);
  --mh-text-3: var(--mh-slate-500);
  --mh-text-4: var(--mh-slate-600);
  --mh-text-inv: var(--mh-white);   /* text sitting on the accent fill */

  /* Legacy aliases — kept so nothing that referenced the old brand
     tokens breaks. Both now resolve to dark-safe neutrals. */
  --mh-deep: var(--mh-accent-strong);
  --mh-ink: var(--mh-d-500);

  /* ── Status — readable on the dark ramp, never neon ────────────── */
  --mh-success: #4ade80;
  --mh-success-bg: #0d2018;
  --mh-success-line: rgba(74, 222, 128, 0.24);
  --mh-warn: #fbbf24;
  --mh-warn-bg: #241b08;
  --mh-warn-line: rgba(251, 191, 36, 0.24);
  --mh-danger: #f87171;
  --mh-danger-bg: #26100f;
  --mh-danger-line: rgba(248, 113, 113, 0.26);
  --mh-info: #60a5fa;
  --mh-info-bg: var(--mh-accent-soft);
  --mh-info-line: var(--mh-accent-line);

  /* The old gold is retired: blue is the only brand accent. These
     aliases now carry the amber *warning* semantic so every existing
     `--gold` class keeps working and reads as attention, not brand. */
  --mh-gold: var(--mh-warn);
  --mh-gold-fg: var(--mh-warn);
  --mh-gold-bg: var(--mh-warn-bg);
  --mh-gold-line: var(--mh-warn-line);

  /* ── Radius — one tight scale ──────────────────────────────────── */
  --mh-r-xs: 4px;
  --mh-r-sm: 6px;
  --mh-r: 8px;
  --mh-r-lg: 12px;
  --mh-r-pill: 999px;

  /* ── Space — 4px base ──────────────────────────────────────────── */
  --mh-1: 4px;
  --mh-2: 8px;
  --mh-3: 12px;
  --mh-4: 16px;
  --mh-5: 20px;
  --mh-6: 24px;
  --mh-7: 28px;
  --mh-8: 32px;
  --mh-10: 40px;
  --mh-12: 48px;
  --mh-16: 64px;

  /* ── Type ──────────────────────────────────────────────────────────
     Tajawal — the platform's own face, so a screen this plugin draws
     and a screen the site draws are set in the same type. IBM Plex Sans
     Arabic stands behind it (it carries a matching Latin, which is why
     this design was built against it), then the system stack. */
  --mh-font: "Tajawal", "IBM Plex Sans Arabic", "Noto Sans Arabic",
             -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  --mh-font-mono: ui-monospace, "SFMono-Regular", "JetBrains Mono", Consolas, monospace;

  /* Weights — named, so no screen invents its own, and declared in
     weights Tajawal actually draws. The family has no 600: asking for
     one does not fail, it silently resolves to 700, which collapses
     "semibold" and "bold" into the same stroke and flattens every
     heading hierarchy built on the pair. So the ramp steps
     400 → 500 → 700 → 800, all of which are real cuts. */
  --mh-w-regular: 400;
  --mh-w-medium: 500;
  --mh-w-semi: 700;
  --mh-w-bold: 800;

  --mh-t-display: clamp(1.5rem, 1.24rem + 1.15vw, 2.125rem); /* 24 → 34 */
  --mh-t-title: clamp(1.1875rem, 1.11rem + 0.34vw, 1.375rem); /* 19 → 22 */
  --mh-t-h2: 1.0625rem;   /* 17 — section heading   */
  --mh-t-h3: 0.9375rem;   /* 15 — card heading      */
  --mh-t-body: 0.9375rem; /* 15 — body              */
  --mh-t-sm: 0.875rem;    /* 14 — secondary         */
  --mh-t-xs: 0.8125rem;   /* 13 — caption / label   */
  --mh-t-2xs: 0.75rem;    /* 12 — metadata / badge  */
  --mh-t-value: clamp(1.375rem, 1.2rem + 0.8vw, 1.75rem); /* 22 → 28, metrics */

  --mh-lh-tight: 1.35;
  --mh-lh-snug: 1.55;
  --mh-lh: 1.75;

  /* Arabic sits lower and denser than Latin at the same size; a touch
     more leading on long-form text keeps diacritics from colliding. */
  --mh-lh-ar: 1.85;
  --mh-track-label: 0.06em;

  /* ── Motion — the minimum a control needs to feel responsive ───── */
  --mh-t-fast: 110ms linear;

  /* ── Layout ────────────────────────────────────────────────────── */
  --mh-max: 1240px;
  --mh-side: 248px;
  --mh-gutter: clamp(16px, 3vw, 32px);

  /* The page ground *behind* the plugin surface. One step below the
     surface so the shell's top corners read as a lift rather than as a
     line, without adding a shadow to say the same thing. */
  --mh-canvas: #05070c;
  --mh-shell-r: 20px;

  --mh-control-h: 40px;
  --mh-control-h-sm: 32px;
  --mh-control-h-lg: 46px;
  --mh-topbar-h: 56px;
  --mh-z-side: 40;
  --mh-z-topbar: 45;
  --mh-z-modal: 60;
  --mh-z-toast: 70;
}

/* ═══════════════════════════ RESET / BASE ═══════════════════════════ */

/* The plugin owns the whole page on its own routes. Without this the
   surrounding theme's white ground frames a dark product, which reads
   as a broken embed rather than an app. `mihhar-dark` is added to
   <body> only on pages that render a Mihhar shortcode. */
body.mihhar-dark {
  background: var(--mh-bg);
  color: var(--mh-text);
  color-scheme: dark;
}
body.mihhar-dark :where(#page, #content, .site, .site-content, main, .entry-content, .wp-site-blocks) {
  background: transparent;
}

/* Pages that render the app shell paint the deeper canvas, so the strip
   above and beside the plugin surface is the ground the surface sits on
   rather than the surface repeated. */
body.mihhar-page.mihhar-platform { background: var(--mh-canvas); }

/* ═══════════════════ THE PLATFORM LAYOUT (3.3) ═══════════════════

   The plugin's own page layout, owned by the plugin.

   ── Where the width was actually being decided ───────────────────

   A shortcode renders inside whatever the active theme wrapped the page
   content in, and that wrapper decides six things:

     max-width   a centred column, `--wp--style--global--content-size`,
                 Elementor's `--content-width`, `.container`
     width       `.col-md-9`, a percentage main beside a sidebar
     padding     the wrapper's own inline padding
     margin      `margin-inline: auto`, which centres what it caps
     overflow    `overflow: hidden`, for sticky headers and animations
     display     `.e-con { display: flex; flex-direction: column }`,
                 where the inline size is the *cross* axis and
                 `align-items` shrinks children to their own content

   Answering those from outside means identifying the wrapper — and a
   page builder gives the site header the same class names it gives the
   content, so every answer is a guess. Two releases of guesses said
   plainly enough that the mechanism was wrong, not the arithmetic.

   ── The layout that replaces them ────────────────────────────────

   `Routing\Template` serves the platform's screens from
   `templates/platform.php`: the theme's header, this root, the theme's
   footer, and none of the theme's page layout in between. There is no
   wrapper left to widen, so nothing here widens one.

     #mihhar-page-root              the root — width, gutter, ground
       └── #mihhar-page-surface      the surface and its radius
             └── .mh-app             the screen

   The two ids are not styling hooks — the classes do that. They exist so
   the rules further down can reach the *ancestors* of the root through
   `:has(#mihhar-page-root)` at a specificity that answers a theme's
   `#content { max-width: … }` without one `!important`.

   No `!important`. No viewport units. No negative margins. Nothing that
   reaches outside this subtree, and nothing that touches a header, a
   footer or any other page on the site. */

.mihhar-page-root {
  /* The gutter scales with the space available rather than with the
     viewport, so it is correct inside any box the layout is given — a
     full-width page, a narrower embedded one, a tablet, a phone. */
  --mihhar-page-gutter: clamp(var(--mh-4), 2.5%, var(--mh-10, 40px));

  display: block;
  box-sizing: border-box;
  width: 100%;
  max-width: none;
  margin: 0;
  padding: var(--mh-6) 0 0;
  background: var(--mh-canvas);

  /* A grid or flex item by accident, in a layout the plugin does not
     control: fill the line rather than shrink to content. These are
     inert where the parent is neither, and they are declarations about
     this element — not overrides of somebody else's. */
  min-width: 0;
  flex: 1 1 100%;
  align-self: stretch;
  justify-self: stretch;
  grid-column: 1 / -1;
}

/* The same root, addressed by id.

   Not a duplicate for its own sake. The block above is the definition;
   this is the one that has to *win*. Themes constrain children
   positionally — `#content > *`, `.is-layout-constrained > *`,
   `.entry-content > *` — and a positional rule with an id in it outranks
   any class selector, however carefully written. So the declarations
   that decide "fill the box you are in, whatever kind of box it is" are
   restated at id specificity.

   Two selectors, and the second is not decoration:

     #mihhar-page-root.mihhar-page-root            (1,1,0)  beats `#content > *`
     body :has(> #mihhar-page-root) > #…           (2,0,2)  beats `#page #content > *`

   A tie is not good enough here. `#mihhar-page-root` alone is (1,0,0) —
   the same as `#content > *` — and a tie is broken by which stylesheet
   the browser happened to load last, which is not something a plugin
   gets to decide. Adding the element's own class costs nothing and ends
   the question. The second selector reaches the root through its parent
   so that a two-id positional rule loses too, and it names no wrapper:
   "the thing that contains our root", whatever that is. */

#mihhar-page-root.mihhar-page-root,
body :has(> #mihhar-page-root) > #mihhar-page-root {
  width: 100%;
  max-width: none;
  min-width: 0;
  margin-inline: 0;
  float: none;
  flex: 1 1 100%;
  align-self: stretch;
  justify-self: stretch;
  grid-column: 1 / -1;
}

/* The painted surface. The 20px radius belongs to this one element:
   cards inside keep the design system's smaller radius, so this reads as
   the app's frame rather than one more rounded box. */
.mihhar-page-root__surface {
  box-sizing: border-box;
  width: 100%;
  min-width: 0;
  background: var(--mh-bg);
  border-top: 1px solid var(--mh-border);
  border-radius: var(--mh-shell-r) var(--mh-shell-r) 0 0;
  /* Deliberately no `overflow`. Any value other than `visible` would
     make this the scrollport for the sticky sidebar and the sticky
     mobile navigation inside it, and both would silently stop
     sticking. */
}

/* The screen fills the surface and takes the gutter from the root, so
   "full width with sensible side spacing" is one decision in one place.
   A descendant selector rather than a child one: nothing may break by
   gaining a wrapper — and on a page built with a builder it gains
   several.

   The id form is there for the same reason as above: a builder writes
   `.elementor-widget-container > *` and similar, and the screen must
   not be at the mercy of stylesheet order. */
.mihhar-page-root .mh-app,
#mihhar-page-root .mh-app {
  width: 100%;
  max-width: none;
  margin-inline: 0;
  padding-inline: var(--mihhar-page-gutter);
}

/* A variant with no surface — the auth screens own the viewport. */
.mihhar-page-root--bare {
  padding: 0;
  background: transparent;
}

/* ── Responsive, by available space ──────────────────────────────

   The gutter above already scales continuously, so these two rules are
   about *shape* rather than size: on a small screen the surface stops
   pretending to be a card floating on a ground, and becomes the page. */

@media (max-width: 782px) {
  .mihhar-page-root { padding-top: 0; }

  .mihhar-page-root__surface {
    border-radius: 0;
    border-top: 0;
  }
}

/* ── The two rendering paths ─────────────────────────────────────

   `mihhar-owned`    the plugin's template is serving this page, and the
                     root above *is* the page layout.

   `mihhar-embedded` the platform is a guest inside a layout somebody
                     else composed — an Elementor page, a custom
                     template. It fills the box it is given, responsively
                     and without overflow, and does not try to escape it.
                     A guest that rearranged the room would be the bug,
                     not the fix. */

body.mihhar-embedded .mihhar-page-root {
  padding-top: 0;
  background: transparent;
}

body.mihhar-embedded .mihhar-page-root__surface {
  border-radius: var(--mh-shell-r);
  border: 1px solid var(--mh-border);
}

/* ── The wrappers the template cannot avoid ──────────────────────

   Two of them, above and below, and both used to be answered by naming
   class names. That is what kept failing: a name list is a guess about
   somebody else's markup, and it was wrong for Astra's `.ast-container`,
   OceanWP's `#content-wrap`, GeneratePress's `.grid-container`, Kadence's
   `.content-container`, and for every wrapper Elementor puts *inside* the
   content — which is the set that was actually holding the page at 46%.

   Neither rule below names anything but our own two elements. They are
   structural: "whatever contains the platform's root" and "whatever sits
   between the platform's surface and the platform's screen". A theme
   published tomorrow is covered for the same reason today's is.

   The id on our root is what makes this work without `!important`. An id
   outranks any number of classes, so a theme's `#content { max-width }`
   can only be answered by a selector that carries an id of its own —
   and `:has(#mihhar-page-root)` carries ours. The doubled `:has()` in the
   second selector of each pair is not a typo: it is the same rule at two
   ids, for a theme that writes `#page #content`. One block, two
   specificities, because a selector list is resolved per selector.


   ①  ABOVE — everything from <body> down to the root.

   Scoped to `body.mihhar-owned`, a class the plugin adds only to pages
   its own template is serving. Properties rather than `display: contents`
   here, deliberately: these wrappers also hold the site's header and
   footer, and dissolving their boxes would change how those lay out.
   Their width, padding and float go; their box stays. */

/* Before any of that: stop the width changing between tabs.

   A dashboard is a set of tabs of wildly different heights. The
   overview scrolls; the settings tab does not. Moving between them
   adds and removes the viewport's vertical scrollbar, and each time it
   appears or disappears the layout is re-resolved fifteen pixels
   narrower or wider — so the page jumps sideways on a tab change,
   which in a right-to-left document reads as the content sliding out
   past the right edge.

   Nothing is overflowing when that happens. The page is being laid out
   at two different widths a moment apart, and `overflow-x: hidden`
   would hide the evidence while leaving the jump exactly where it was.
   Keeping the scrollbar removes the cause: the width stops changing.

   Kept, rather than `scrollbar-gutter: stable`, which reserves fifteen
   pixels even on the systems whose scrollbars float above the content
   and cost nothing — macOS, and every trackpad-only machine. That
   would take width away from readers who never had a jump to fix.
   Always showing the scrollbar costs those readers nothing, and costs
   everyone else precisely what their longest tab already costs them.

   `overflow-y`, and only `overflow-y`: nothing here touches horizontal
   overflow, which would conceal a layout fault instead of removing one.

   Scoped to the pages the plugin serves and to the community's own
   document; the site's own pages keep the browser's default. */

html:has(> body.mihhar-owned) {
  overflow-y: scroll;
}

body.mihhar-owned :has(#mihhar-page-root),
body.mihhar-owned :has(#mihhar-page-root):has(#mihhar-page-root) {
  max-width: none;
  width: auto;
  min-width: 0;
  padding-inline: 0;
  margin-inline: 0;
  float: none;

  /* Inert unless the parent is flex or grid, and correct when it is:
     the cross axis of a flex column, the track of a rail grid. */
  align-self: stretch;
  justify-self: stretch;
  grid-column: 1 / -1;
}

/* Firefox before 121 and Safari before 15.4 have no `:has()`. There the
   rule above never matches, so the conventional WordPress wrapper names
   stand in — the old behaviour, kept only where the real rule cannot
   run, rather than carried alongside it. */
@supports not selector(:has(*)) {
  body.mihhar-owned :is(
    #page, #content, #primary, #main,
    .site, .site-content, .site-main, .content-area
  ) {
    max-width: none;
    width: auto;
    min-width: 0;
    padding-inline: 0;
    margin-inline: 0;
    float: none;
    align-self: stretch;
    justify-self: stretch;
  }

  body.mihhar-owned #page :is(
    #content, #primary, #main,
    .site-content, .site-main, .content-area
  ) {
    max-width: none;
    width: auto;
    min-width: 0;
    padding-inline: 0;
    margin-inline: 0;
  }
}

/* ②  BELOW — everything between the surface and the screen.

   On a page built with a page builder, `the_content()` renders the
   builder's tree inside our root: `.elementor` → `.e-con` (capped at
   `--container-max-width`, 1140px by default) → the column → the widget
   → the shortcode → `.mh-app`. The root is full width and the screen
   inside it is not, which looks identical to the bug we just fixed and
   has a different cause.

   `display: contents` rather than a property list, because here it is
   exactly true: these elements are not part of this page's layout. One
   declaration removes the box entirely — max-width, padding, flex item,
   grid item, `--container-max-width` and whatever the next release of a
   builder invents — where a property list removes only what it lists.

   Only *ancestors* of the screen dissolve. A hero section the site owner
   put above the shortcode is a sibling, keeps its box, and renders
   exactly as they composed it. */

#mihhar-page-root :not(.mihhar-page-root__surface):has(.mh-app),
#mihhar-page-root :not(.mihhar-page-root__surface):has(.mh-app):has(.mh-app) {
  display: contents;
}

/* The ground, on pages the plugin owns. */
body.mihhar-page.mihhar-platform { background: var(--mh-canvas); }

/* Native widgets — scrollbars, form controls, the caret — follow. */
body.mihhar-dark ::-webkit-scrollbar { width: 10px; height: 10px; }
body.mihhar-dark ::-webkit-scrollbar-track { background: var(--mh-d-900); }
body.mihhar-dark ::-webkit-scrollbar-thumb {
  background: var(--mh-d-600);
  border: 2px solid var(--mh-d-900);
  border-radius: 999px;
}
body.mihhar-dark ::-webkit-scrollbar-thumb:hover { background: var(--mh-d-500); }

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

.mh ::selection { background: var(--mh-accent); color: var(--mh-white); }

.mh {
  font-family: var(--mh-font);
  font-size: var(--mh-t-body);
  font-weight: var(--mh-w-regular);
  line-height: var(--mh-lh);
  color: var(--mh-text);
  background: var(--mh-bg);
  color-scheme: dark;
  direction: rtl;
  text-align: right;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-feature-settings: "kern" 1;
  /* Nothing inside the product may push the page sideways. */
  overflow-x: clip;
  max-width: 100%;
}

/* Digits line up in every table, metric and countdown. */
.mh :where(table, .mh-stat__value, .mh-fact__value, .mh-pager, .mh-meta, time, .mh-mono) {
  font-variant-numeric: tabular-nums;
}

/* Every layout child may shrink — the single most common overflow cause. */
.mh :where(div, section, article, aside, main, header, footer, form, nav, span, p, li) {
  min-width: 0;
}

.mh :where(img, svg, video, canvas) {
  max-width: 100%;
  height: auto;
}

.mh :where(h1, h2, h3, h4) {
  margin: 0;
  color: var(--mh-text);
  line-height: var(--mh-lh-tight);
  letter-spacing: -0.011em;
  font-weight: 500;
  overflow-wrap: break-word;
}

.mh p {
  margin: 0 0 var(--mh-3);
  overflow-wrap: break-word;
}
.mh p:last-child { margin-bottom: 0; }

/* Zero-specificity so component classes (buttons, nav items, chips) always win. */
.mh :where(a) {
  color: var(--mh-accent-text);
  text-decoration: none;
  transition: color var(--mh-t-fast);
}
.mh :where(a:hover) { color: var(--mh-white); }

/* Focus is the loudest state in the system — and it is an outline, not a shadow. */
.mh :focus-visible {
  outline: 2px solid var(--mh-accent-text);
  outline-offset: 2px;
  border-radius: var(--mh-r-xs);
}
.mh :focus:not(:focus-visible) { outline: none; }

.mh-icon { flex-shrink: 0; display: block; }

.mh-sr {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ═══════════════════════════ TYPOGRAPHY ═══════════════════════════ */

.mh-display {
  font-size: var(--mh-t-display);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.25;
}

.mh-eyebrow {
  font-size: var(--mh-t-2xs);
  font-weight: 500;
  letter-spacing: 0.06em;
  color: var(--mh-text-3);
  text-transform: uppercase;
}

.mh-muted { color: var(--mh-text-3); }
.mh-meta {
  font-size: var(--mh-t-2xs);
  color: var(--mh-text-3);
  font-weight: 500;
  line-height: var(--mh-lh-snug);
}

.mh-mono {
  font-family: var(--mh-font-mono);
  direction: ltr;
  unicode-bidi: isolate;
  font-size: var(--mh-t-2xs);
  letter-spacing: 0;
}

/* ═══════════════════════════ BUTTONS ═══════════════════════════ */

.mh-btn {
  --btn-bg: var(--mh-surface);
  --btn-fg: var(--mh-text);
  --btn-bd: var(--mh-border-strong);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--mh-2);
  min-height: var(--mh-control-h);
  padding: 0 var(--mh-4);
  border: 1px solid var(--btn-bd);
  border-radius: var(--mh-r);
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-family: inherit;
  font-size: var(--mh-t-sm);
  font-weight: 500;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--mh-t-fast), border-color var(--mh-t-fast), color var(--mh-t-fast);
  -webkit-tap-highlight-color: transparent;
}

.mh-btn:hover { background: var(--mh-surface-sub); color: var(--btn-fg); }

.mh-btn:disabled,
.mh-btn[aria-disabled="true"] {
  color: var(--mh-text-3);
  border-color: var(--mh-border);
  background: var(--mh-surface-sub);
  cursor: not-allowed;
}

.mh-btn--primary {
  --btn-bg: var(--mh-accent);
  --btn-fg: var(--mh-text-inv);
  --btn-bd: var(--mh-accent);
}
.mh-btn--primary:hover { --btn-bg: var(--mh-accent-hover); --btn-bd: var(--mh-accent-hover); color: var(--mh-text-inv); }

.mh-btn--deep {
  --btn-bg: var(--mh-ink);
  --btn-fg: var(--mh-text-inv);
  --btn-bd: var(--mh-ink);
}
.mh-btn--deep:hover { --btn-bg: var(--mh-deep); color: var(--mh-text-inv); }

/* Gold is a *quiet* secondary emphasis: outline, not fill. */
.mh-btn--gold {
  --btn-bg: var(--mh-surface);
  --btn-fg: var(--mh-gold-fg);
  --btn-bd: var(--mh-gold-line);
}
.mh-btn--gold:hover { --btn-bg: var(--mh-gold-bg); color: var(--mh-gold-fg); }

.mh-btn--ghost {
  --btn-bg: transparent;
  --btn-fg: var(--mh-text-2);
  --btn-bd: transparent;
}
.mh-btn--ghost:hover { --btn-bg: var(--mh-surface-mute); --btn-fg: var(--mh-text); }

.mh-btn--soft {
  --btn-bg: var(--mh-accent-soft);
  --btn-fg: var(--mh-accent-text);
  --btn-bd: transparent;
}
.mh-btn--soft:hover { --btn-bg: var(--mh-accent-soft); --btn-bd: var(--mh-accent-line); color: var(--mh-accent-text); }

.mh-btn--danger {
  --btn-bg: var(--mh-surface);
  --btn-fg: var(--mh-danger);
  --btn-bd: var(--mh-danger-line);
}
.mh-btn--danger:hover { --btn-bg: var(--mh-danger-bg); color: var(--mh-danger); }

.mh-btn--sm { min-height: var(--mh-control-h-sm); padding: 0 var(--mh-3); font-size: var(--mh-t-xs); border-radius: var(--mh-r-sm); }
.mh-btn--lg { min-height: var(--mh-control-h-lg); padding: 0 var(--mh-6); font-size: var(--mh-t-body); }
.mh-btn--block { display: flex; width: 100%; }
.mh-btn--icon { width: var(--mh-control-h); padding: 0; }
.mh-btn--icon.mh-btn--sm { width: var(--mh-control-h-sm); }
.mh-btn.is-loading { pointer-events: none; color: var(--mh-text-3); }
.mh-btn.is-loading .mh-icon { animation: mh-spin 0.9s linear infinite; }

/* ═══════════════════════════ FORMS ═══════════════════════════ */

.mh-field { display: flex; flex-direction: column; gap: var(--mh-2); min-width: 0; }

.mh-label {
  display: flex;
  align-items: center;
  gap: var(--mh-1);
  font-size: var(--mh-t-xs);
  font-weight: 500;
  color: var(--mh-text-2);
  line-height: var(--mh-lh-snug);
}
.mh-label .mh-icon { color: var(--mh-text-3); }
.mh-req { color: var(--mh-danger); }
.mh-opt { color: var(--mh-text-3); font-weight: 500; }

.mh-input,
.mh-select,
.mh-textarea {
  width: 100%;
  max-width: 100%;
  min-height: var(--mh-control-h);
  padding: var(--mh-2) var(--mh-3);
  font-family: inherit;
  font-size: var(--mh-t-sm);
  font-weight: 500;
  line-height: var(--mh-lh-snug);
  color: var(--mh-text);
  background: var(--mh-surface);
  border: 1px solid var(--mh-border-strong);
  border-radius: var(--mh-r);
  appearance: none;
  transition: border-color var(--mh-t-fast), background-color var(--mh-t-fast);
}

.mh-textarea { min-height: 108px; padding: var(--mh-3); resize: vertical; line-height: var(--mh-lh); }

.mh-input::placeholder,
.mh-textarea::placeholder { color: var(--mh-n-400); font-weight: 400; }

.mh-input:hover,
.mh-select:hover,
.mh-textarea:hover { border-color: var(--mh-n-400); }

.mh-input:focus,
.mh-select:focus,
.mh-textarea:focus {
  outline: 2px solid var(--mh-accent);
  outline-offset: -1px;
  border-color: var(--mh-accent);
}

.mh-input[readonly],
.mh-input:disabled,
.mh-select:disabled,
.mh-textarea:disabled {
  background: var(--mh-surface-sub);
  color: var(--mh-text-3);
  border-color: var(--mh-border);
  cursor: not-allowed;
}

/* Invalid state is driven by the accessible attribute, so the visual and the
   screen-reader announcement can never drift apart. */
.mh-input.is-invalid,
.mh-textarea.is-invalid,
.mh :where(.mh-input, .mh-select, .mh-textarea)[aria-invalid="true"] { border-color: var(--mh-danger); }
.mh :where(.mh-input, .mh-select, .mh-textarea)[aria-invalid="true"]:focus { outline-color: var(--mh-danger); }

.mh-select {
  padding-inline-end: var(--mh-3);
  padding-inline-start: var(--mh-8);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23878c9c' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: left var(--mh-3) center;
  background-size: 14px;
  cursor: pointer;
}
.mh-select--sm { min-height: var(--mh-control-h-sm); font-size: var(--mh-t-xs); background-size: 12px; }

.mh-help { font-size: var(--mh-t-2xs); color: var(--mh-text-3); line-height: var(--mh-lh-snug); }
.mh-error {
  display: flex;
  align-items: flex-start;
  gap: var(--mh-1);
  font-size: var(--mh-t-2xs);
  color: var(--mh-danger);
  font-weight: 500;
  line-height: var(--mh-lh-snug);
  overflow-wrap: anywhere;
}
.mh-error[hidden] { display: none; }
.mh-error .mh-icon { flex-shrink: 0; margin-top: 1px; }

/* ── Step indicator ──────────────────────────────────────
   Numbers, labels and one hairline. Used by signup today; any other
   multi-step flow can reuse it as-is. */

.mh-steps {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--mh-3);
  margin: 0 0 var(--mh-6);
  padding: 0;
  list-style: none;
  counter-reset: none;
  min-width: 0;
}
.mh-steps__item {
  display: flex;
  align-items: baseline;
  gap: var(--mh-2);
  padding-top: var(--mh-2);
  border-top: 2px solid var(--mh-border);
  color: var(--mh-text-3);
  min-width: 0;
  transition: border-color var(--mh-t-fast), color var(--mh-t-fast);
}
.mh-steps__num {
  font-size: var(--mh-t-2xs);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
  flex-shrink: 0;
}
.mh-steps__label {
  font-size: var(--mh-t-2xs);
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mh-steps__item.is-done { border-top-color: var(--mh-accent-line); color: var(--mh-text-2); }
.mh-steps__item.is-current {
  border-top-color: var(--mh-accent);
  color: var(--mh-accent-text);
}
.mh-steps__item.is-current .mh-steps__label { font-weight: 500; }

/* The whole product is dark now, so the old on-dark inversion is just
   the default. The modifier is kept as a no-op alias so existing markup
   keeps rendering identically. */
.mh-steps--on-dark .mh-steps__item { border-top-color: var(--mh-border); color: var(--mh-text-3); }
.mh-steps--on-dark .mh-steps__item.is-done { border-top-color: var(--mh-accent-line); color: var(--mh-text-2); }
.mh-steps--on-dark .mh-steps__item.is-current { border-top-color: var(--mh-accent); color: var(--mh-accent-text); }

.mh-pass { position: relative; display: block; }
.mh-pass .mh-input { padding-inline-start: var(--mh-10); }
.mh-pass__eye {
  position: absolute;
  inset-inline-start: var(--mh-2);
  top: 50%;
  transform: translateY(-50%);
  width: 28px; height: 28px;
  display: grid; place-items: center;
  padding: 0;
  border: 0;
  background: none;
  color: var(--mh-text-3);
  cursor: pointer;
  border-radius: var(--mh-r-xs);
  transition: color var(--mh-t-fast);
}
.mh-pass__eye:hover { color: var(--mh-text); }

.mh-meter { height: 3px; border-radius: var(--mh-r-pill); background: var(--mh-border); overflow: hidden; }
.mh-meter__bar { display: block; height: 100%; width: 0; border-radius: inherit; transition: width var(--mh-t-fast), background-color var(--mh-t-fast); }
.mh-meter__bar[data-level="1"] { width: 25%; background: var(--mh-danger); }
.mh-meter__bar[data-level="2"] { width: 50%; background: var(--mh-warn); }
.mh-meter__bar[data-level="3"] { width: 75%; background: var(--mh-gold); }
.mh-meter__bar[data-level="4"] { width: 100%; background: var(--mh-success); }

.mh-check {
  display: flex;
  align-items: flex-start;
  gap: var(--mh-2);
  font-size: var(--mh-t-sm);
  font-weight: 500;
  color: var(--mh-text-2);
  cursor: pointer;
  line-height: var(--mh-lh-snug);
}
.mh-check input {
  width: 16px; height: 16px;
  margin-top: 3px;
  accent-color: var(--mh-accent);
  flex-shrink: 0;
}

.mh-radio-list { display: flex; flex-direction: column; gap: var(--mh-1); }
.mh-radio {
  display: flex;
  align-items: center;
  gap: var(--mh-2);
  padding: var(--mh-2) var(--mh-2);
  border-radius: var(--mh-r-sm);
  font-size: var(--mh-t-sm);
  font-weight: 500;
  color: var(--mh-text-2);
  cursor: pointer;
  transition: background-color var(--mh-t-fast), color var(--mh-t-fast);
}
.mh-radio:hover { background: var(--mh-surface-sub); color: var(--mh-text); }
.mh-radio input { width: 15px; height: 15px; accent-color: var(--mh-accent); flex-shrink: 0; }
.mh-radio:has(input:checked) { color: var(--mh-accent-text); font-weight: 500; }

.mh-form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr));
  gap: var(--mh-4);
}
.mh-form-grid--full { grid-template-columns: minmax(0, 1fr); }

.mh-form-actions {
  display: flex;
  align-items: center;
  gap: var(--mh-3);
  flex-wrap: wrap;
  margin-top: var(--mh-6);
  padding-top: var(--mh-5);
  border-top: 1px solid var(--mh-border);
}

.mh-section-label {
  display: flex;
  align-items: center;
  gap: var(--mh-2);
  margin: var(--mh-7) 0 var(--mh-4);
  font-size: var(--mh-t-2xs);
  font-weight: 500;
  letter-spacing: 0.05em;
  color: var(--mh-text-3);
  text-transform: uppercase;
}
.mh-section-label::after { content: ""; flex: 1; height: 1px; background: var(--mh-border); }
.mh-section-label:first-child { margin-top: 0; }

/* ═══════════════════════════ SURFACES ═══════════════════════════ */

.mh-card {
  background: var(--mh-surface);
  border: 1px solid var(--mh-border);
  border-radius: var(--mh-r-lg);
  overflow: hidden;
}

/* Card padding, widened in 4.2.0.
   A hairline border 16px from its contents looks like a box the content
   outgrew. The same border at 20/24px looks like a panel the content
   was placed in. Nothing else about the card changed. */
.mh-card__head {
  display: flex;
  align-items: center;
  gap: var(--mh-3);
  padding: var(--mh-5) var(--mh-6);
  border-bottom: 1px solid var(--mh-border);
}
.mh-card__head h2,
.mh-card__head h3 { font-size: var(--mh-t-h2); font-weight: 500; }
.mh-card__head h3 { font-size: var(--mh-t-h3); }
.mh-card__head p { margin: 2px 0 0; font-size: var(--mh-t-2xs); color: var(--mh-text-3); }
.mh-card__head > .mh-icon { color: var(--mh-text-3); }
.mh-card__head-actions { margin-inline-start: auto; display: flex; gap: var(--mh-2); flex-wrap: wrap; }

.mh-card__body { padding: var(--mh-6); }

.mh-card__foot {
  display: flex;
  align-items: center;
  gap: var(--mh-3);
  flex-wrap: wrap;
  padding: var(--mh-5) var(--mh-6);
  border-top: 1px solid var(--mh-border);
  background: var(--mh-surface-sub);
}

.mh-divider { height: 1px; margin: var(--mh-5) 0; background: var(--mh-border); border: 0; }

/* ═══════════════════════════ BADGES ═══════════════════════════ */

.mh-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--mh-1);
  max-width: 100%;
  padding: 2px var(--mh-2);
  border: 1px solid transparent;
  border-radius: var(--mh-r-sm);
  font-size: var(--mh-t-2xs);
  font-weight: 500;
  line-height: 1.7;
  white-space: nowrap;
}
.mh-badge > span { overflow: hidden; text-overflow: ellipsis; }

.mh-badge--brand,
.mh-badge--info    { background: var(--mh-accent-soft); color: var(--mh-accent-text); border-color: var(--mh-accent-line); }
.mh-badge--success { background: var(--mh-success-bg);  color: var(--mh-success);    border-color: var(--mh-success-line); }
.mh-badge--warn    { background: var(--mh-warn-bg);     color: var(--mh-warn);       border-color: var(--mh-warn-line); }
.mh-badge--danger  { background: var(--mh-danger-bg);   color: var(--mh-danger);     border-color: var(--mh-danger-line); }
.mh-badge--gold    { background: var(--mh-gold-bg);     color: var(--mh-gold-fg);    border-color: var(--mh-gold-line); }
.mh-badge--muted   { background: var(--mh-surface-sub); color: var(--mh-text-3);     border-color: var(--mh-border); }
.mh-badge--soft    { background: transparent; }

.mh-badge__icon { margin-block: -1px; }
.mh-dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex-shrink: 0; }

.mh-tagchip {
  display: inline-flex;
  align-items: center;
  padding: 2px var(--mh-2);
  border: 1px solid var(--mh-border);
  border-radius: var(--mh-r-sm);
  background: var(--mh-surface-sub);
  color: var(--mh-text-2);
  font-size: var(--mh-t-2xs);
  font-weight: 500;
}
.mh-tagchip--lg { padding: var(--mh-1) var(--mh-3); font-size: var(--mh-t-xs); }

/* ── Filter chips / segmented navigation ─────────────────────────── */

.mh-filters {
  display: flex;
  gap: var(--mh-1);
  flex-wrap: wrap;
  min-width: 0;
}

.mh-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--mh-2);
  min-height: var(--mh-control-h-sm);
  padding: 0 var(--mh-3);
  border: 1px solid transparent;
  border-radius: var(--mh-r-sm);
  background: transparent;
  color: var(--mh-text-2);
  font-size: var(--mh-t-xs);
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--mh-t-fast), color var(--mh-t-fast), border-color var(--mh-t-fast);
}
.mh-chip:hover { background: var(--mh-surface-mute); color: var(--mh-text); }
.mh-chip.is-active {
  background: var(--mh-accent-soft);
  border-color: var(--mh-accent-line);
  color: var(--mh-accent-text);
  font-weight: 500;
}
.mh-chip__count { color: var(--mh-text-3); font-variant-numeric: tabular-nums; font-size: var(--mh-t-2xs); }
.mh-chip.is-active .mh-chip__count { color: var(--mh-accent-text); }

/* ═══════════════════════════ ALERTS ═══════════════════════════ */

.mh-alert {
  display: flex;
  align-items: flex-start;
  gap: var(--mh-3);
  padding: var(--mh-3) var(--mh-4);
  border: 1px solid var(--mh-border);
  border-radius: var(--mh-r);
  background: var(--mh-surface-sub);
  color: var(--mh-text-2);
  font-size: var(--mh-t-sm);
  font-weight: 500;
  line-height: var(--mh-lh-snug);
}
.mh-alert .mh-icon { margin-top: 2px; }
.mh-alert[hidden] { display: none; }
.mh-alert--ok   { background: var(--mh-success-bg); border-color: var(--mh-success-line); color: var(--mh-success); }
.mh-alert--err  { background: var(--mh-danger-bg);  border-color: var(--mh-danger-line);  color: var(--mh-danger); }
.mh-alert--warn { background: var(--mh-warn-bg);    border-color: var(--mh-warn-line);    color: var(--mh-warn); }
.mh-alert--info { background: var(--mh-accent-soft);border-color: var(--mh-accent-line);  color: var(--mh-accent-text); }
.mh-alert strong { font-weight: 500; }

/* ═══════════════════════════ AVATAR ═══════════════════════════ */

.mh-avatar {
  width: 36px; height: 36px;
  flex-shrink: 0;
  display: grid;
  place-items: center;
  overflow: hidden;
  border: 1px solid var(--mh-border);
  border-radius: var(--mh-r);
  background: var(--mh-surface-sub);
  color: var(--mh-text-2);
  font-size: var(--mh-t-sm);
  font-weight: 500;
  user-select: none;
}
.mh-avatar img { width: 100%; height: 100%; object-fit: cover; }
.mh-avatar--sm { width: 28px; height: 28px; font-size: var(--mh-t-2xs); border-radius: var(--mh-r-sm); }
.mh-avatar--lg { width: 48px; height: 48px; font-size: var(--mh-t-h2); }
.mh-avatar--staff { background: var(--mh-accent-soft); border-color: var(--mh-accent-line); color: var(--mh-accent-text); }

/* ═══════════════════════════ EMPTY / LOADING ═══════════════════════════ */

.mh-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--mh-3);
  padding: var(--mh-12) var(--mh-5);
  text-align: center;
}
.mh-empty__icon {
  display: grid;
  place-items: center;
  width: 44px; height: 44px;
  border: 1px solid var(--mh-border);
  border-radius: var(--mh-r);
  background: var(--mh-surface-sub);
  color: var(--mh-text-3);
}
.mh-empty h3 { font-size: var(--mh-t-h2); font-weight: 500; }
.mh-empty p { max-width: 44ch; margin: 0; font-size: var(--mh-t-sm); color: var(--mh-text-3); }
.mh-empty .mh-btn { margin-top: var(--mh-2); }

.mh-skel {
  border-radius: var(--mh-r-sm);
  background: var(--mh-surface-mute);
  animation: mh-fade-pulse 1.4s ease-in-out infinite;
}
.mh-skel--text { height: 10px; margin-bottom: var(--mh-2); }
.mh-skel--title { height: 16px; width: 45%; margin-bottom: var(--mh-3); }
.mh-skel--card { height: 88px; border-radius: var(--mh-r-lg); }
.mh-skel--circle { width: 36px; height: 36px; border-radius: 50%; }

.mh-progress { height: 4px; border-radius: var(--mh-r-pill); background: var(--mh-border); overflow: hidden; }
.mh-progress__bar { display: block; height: 100%; border-radius: inherit; background: var(--mh-accent); transition: width var(--mh-t-fast); }
.mh-progress--gold .mh-progress__bar { background: var(--mh-gold); }

/* ═══════════════════════════ TOASTS ═══════════════════════════ */

.mh-toasts {
  position: fixed;
  inset-block-end: var(--mh-5);
  inset-inline-start: var(--mh-5);
  z-index: 99999;
  display: flex;
  flex-direction: column;
  gap: var(--mh-2);
  max-width: min(360px, calc(100vw - var(--mh-8)));
  pointer-events: none;
  direction: rtl;
}
.mh-toast {
  display: flex;
  align-items: flex-start;
  gap: var(--mh-2);
  padding: var(--mh-3) var(--mh-4);
  border: 1px solid var(--mh-border-strong);
  border-radius: var(--mh-r);
  background: var(--mh-surface);
  color: var(--mh-text);
  font-family: var(--mh-font);
  font-size: var(--mh-t-sm);
  font-weight: 500;
  line-height: var(--mh-lh-snug);
  pointer-events: auto;
}
.mh-toast.is-out { opacity: 0; transition: opacity var(--mh-t-fast); }
.mh-toast--ok  { border-color: var(--mh-success-line); }
.mh-toast--err { border-color: var(--mh-danger-line); }
.mh-toast__icon--ok   { color: var(--mh-success); }
.mh-toast__icon--err  { color: var(--mh-danger); }
.mh-toast__icon--info { color: var(--mh-accent-text); }

/* ═══════════════════════════ MODAL ═══════════════════════════ */

.mh-modal {
  position: fixed;
  inset: 0;
  z-index: 99998;
  display: grid;
  place-items: center;
  padding: var(--mh-5);
  background: rgba(4, 6, 11, 0.72);
}
.mh-modal[hidden] { display: none; }
.mh-modal__box {
  width: 100%;
  max-width: min(440px, 100%);
  background: var(--mh-surface);
  border: 1px solid var(--mh-border-strong);
  border-radius: var(--mh-r-lg);
  overflow: hidden;
  direction: rtl;
}
.mh-modal__head { padding: var(--mh-4) var(--mh-5); border-bottom: 1px solid var(--mh-border); }
.mh-modal__head h3 { font-size: var(--mh-t-h2); font-weight: 500; }
.mh-modal__body { padding: var(--mh-5); font-size: var(--mh-t-sm); color: var(--mh-text-2); }
.mh-modal__foot {
  display: flex;
  gap: var(--mh-2);
  padding: var(--mh-4) var(--mh-5);
  border-top: 1px solid var(--mh-border);
  background: var(--mh-surface-sub);
}

/* ═══════════════════════════ PAGINATION ═══════════════════════════ */

.mh-pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--mh-3);
  flex-wrap: wrap;
}
.mh-pager__info { font-size: var(--mh-t-2xs); color: var(--mh-text-3); font-variant-numeric: tabular-nums; }
.mh-pager__links { display: flex; gap: var(--mh-1); flex-wrap: wrap; }
.mh-pager__links a,
.mh-pager__links span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--mh-control-h-sm);
  height: var(--mh-control-h-sm);
  padding: 0 var(--mh-2);
  border: 1px solid var(--mh-border);
  border-radius: var(--mh-r-sm);
  background: var(--mh-surface);
  color: var(--mh-text-2);
  font-size: var(--mh-t-xs);
  font-weight: 500;
  text-decoration: none;
  font-variant-numeric: tabular-nums;
  transition: border-color var(--mh-t-fast), color var(--mh-t-fast);
}
.mh-pager__links a:hover { border-color: var(--mh-border-strong); color: var(--mh-text); }
.mh-pager__links .current {
  background: var(--mh-accent-soft);
  border-color: var(--mh-accent-line);
  color: var(--mh-accent-text);
  font-weight: 500;
}

/* ═══════════════════════════ ANIMATION ═══════════════════════════ */

@keyframes mh-spin { to { transform: rotate(360deg); } }
@keyframes mh-fade-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } }

/* `mh-rise` is kept as a hook but is intentionally inert — no motion. */
.mh-rise { animation: none; }

@media (prefers-reduced-motion: reduce) {
  .mh *,
  .mh *::before,
  .mh *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* ═══════════════════════════ UTILITIES ═══════════════════════════ */

/* The only transition allowed between steps: opacity. No movement. */
@keyframes mh-fade { from { opacity: 0; } to { opacity: 1; } }
.mh-fade { animation: mh-fade 180ms linear; }

.mh-row { display: flex; align-items: center; gap: var(--mh-3); min-width: 0; }
.mh-row--between { justify-content: space-between; }
.mh-row--wrap { flex-wrap: wrap; }
.mh-col { display: flex; flex-direction: column; gap: var(--mh-3); min-width: 0; }
.mh-grow { flex: 1; min-width: 0; }
.mh-truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.mh-wrap-any { overflow-wrap: anywhere; word-break: break-word; }

.mh-grid { display: grid; gap: var(--mh-4); }
.mh-grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr)); }
.mh-grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 180px), 1fr)); }
.mh-grid--4 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 150px), 1fr)); }

/* ═══════════════════════════ TABLES ═══════════════════════════
   One table for the whole product — portal and admin alike. The
   wrapper owns the horizontal scroll so a wide table can never push
   the page sideways, and the header stays put while rows scroll. */

.mh-tablewrap {
  border: 1px solid var(--mh-border);
  border-radius: var(--mh-r-lg);
  background: var(--mh-surface);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
}
.mh-card > .mh-tablewrap,
.mh-card__body--flush > .mh-tablewrap { border: 0; border-radius: 0; background: none; }

.mh-table {
  width: 100%;
  min-width: 640px;
  border-collapse: collapse;
  font-size: var(--mh-t-sm);
}
.mh-table--wide { min-width: 860px; }
.mh-table--auto { min-width: 0; }

.mh-table th,
.mh-table td {
  padding: var(--mh-3) var(--mh-4);
  text-align: start;
  vertical-align: middle;
  border-bottom: 1px solid var(--mh-border);
}
.mh-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--mh-surface-sub);
  border-bottom: 1px solid var(--mh-border-strong);
  color: var(--mh-text-3);
  font-size: var(--mh-t-2xs);
  font-weight: 500;
  letter-spacing: var(--mh-track-label);
  white-space: nowrap;
}
.mh-table tbody tr:last-child td { border-bottom: 0; }
.mh-table tbody tr:hover td { background: var(--mh-surface-sub); }
.mh-table tbody tr.is-selected td { background: var(--mh-accent-soft); }
.mh-table td strong { font-weight: 500; color: var(--mh-text); }
.mh-table .mh-table__sub { display: block; font-size: var(--mh-t-2xs); color: var(--mh-text-3); }
.mh-table__num { font-variant-numeric: tabular-nums; white-space: nowrap; }
.mh-table__actions { display: flex; gap: var(--mh-1); justify-content: flex-end; white-space: nowrap; }
.mh-table__check { width: 40px; }
.mh-table--compact th,
.mh-table--compact td { padding: var(--mh-2) var(--mh-3); }

/* A sortable header is a button, not a decorated cell. */
.mh-table__sort {
  display: inline-flex;
  align-items: center;
  gap: var(--mh-1);
  border: 0;
  padding: 0;
  background: none;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  cursor: pointer;
}
.mh-table__sort:hover { color: var(--mh-text); }
.mh-table__sort[aria-sort="ascending"],
.mh-table__sort[aria-sort="descending"] { color: var(--mh-accent-text); }

/* ═══════════════════════════ TABS ═══════════════════════════ */

.mh-tabs {
  display: flex;
  gap: var(--mh-1);
  min-width: 0;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  border-bottom: 1px solid var(--mh-border);
}
.mh-tabs::-webkit-scrollbar { display: none; }

.mh-tab {
  display: inline-flex;
  align-items: center;
  gap: var(--mh-2);
  flex-shrink: 0;
  padding: var(--mh-3) var(--mh-4);
  margin-bottom: -1px;
  border: 0;
  border-bottom: 2px solid transparent;
  background: none;
  color: var(--mh-text-3);
  font-family: inherit;
  font-size: var(--mh-t-sm);
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: color var(--mh-t-fast), border-color var(--mh-t-fast);
}
.mh-tab:hover { color: var(--mh-text); }
.mh-tab[aria-selected="true"],
.mh-tab.is-active {
  color: var(--mh-accent-text);
  border-bottom-color: var(--mh-accent-text);
  font-weight: 500;
}
.mh-tab__count {
  padding: 0 var(--mh-2);
  border-radius: var(--mh-r-pill);
  background: var(--mh-surface-mute);
  color: var(--mh-text-3);
  font-size: var(--mh-t-2xs);
  font-variant-numeric: tabular-nums;
}
.mh-tab[aria-selected="true"] .mh-tab__count,
.mh-tab.is-active .mh-tab__count { background: var(--mh-accent-soft); color: var(--mh-accent-text); }

/* ═══════════════════════════ DROPDOWN ═══════════════════════════ */

.mh-menu { position: relative; display: inline-flex; }
.mh-menu__panel {
  position: absolute;
  top: calc(100% + var(--mh-1));
  inset-inline-end: 0;
  z-index: var(--mh-z-side);
  min-width: 200px;
  max-width: min(280px, 90vw);
  padding: var(--mh-1);
  border: 1px solid var(--mh-border-strong);
  border-radius: var(--mh-r);
  background: var(--mh-surface-sub);
}
.mh-menu__panel[hidden] { display: none; }
.mh-menu__item {
  display: flex;
  align-items: center;
  gap: var(--mh-2);
  width: 100%;
  padding: var(--mh-2) var(--mh-3);
  border: 0;
  border-radius: var(--mh-r-sm);
  background: none;
  color: var(--mh-text-2);
  font: inherit;
  font-size: var(--mh-t-sm);
  text-align: start;
  text-decoration: none;
  cursor: pointer;
}
.mh-menu__item:hover { background: var(--mh-surface-mute); color: var(--mh-text); }
.mh-menu__item--danger { color: var(--mh-danger); }
.mh-menu__item--danger:hover { background: var(--mh-danger-bg); color: var(--mh-danger); }
.mh-menu__sep { height: 1px; margin: var(--mh-1) 0; background: var(--mh-border); }
.mh-menu__label {
  padding: var(--mh-2) var(--mh-3) var(--mh-1);
  font-size: var(--mh-t-2xs);
  font-weight: 500;
  letter-spacing: var(--mh-track-label);
  color: var(--mh-text-4);
}

/* ═══════════════════════════ BREADCRUMBS ═══════════════════════════ */

.mh-crumbs {
  display: flex;
  align-items: center;
  gap: var(--mh-2);
  flex-wrap: wrap;
  min-width: 0;
  font-size: var(--mh-t-xs);
  color: var(--mh-text-3);
}
.mh-crumbs a { color: var(--mh-text-3); }
.mh-crumbs a:hover { color: var(--mh-text); }
.mh-crumbs__sep { color: var(--mh-text-4); }
.mh-crumbs [aria-current="page"] { color: var(--mh-text-2); font-weight: 500; }

/* ═══════════════════════════ TOGGLE ═══════════════════════════
   Used by feature flags and notification preferences. */

.mh-switch {
  display: inline-flex;
  align-items: center;
  gap: var(--mh-3);
  cursor: pointer;
  min-width: 0;
}
.mh-switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.mh-switch__track {
  position: relative;
  width: 38px;
  height: 22px;
  flex-shrink: 0;
  border: 1px solid var(--mh-border-strong);
  border-radius: var(--mh-r-pill);
  background: var(--mh-surface-mute);
  transition: background-color var(--mh-t-fast), border-color var(--mh-t-fast);
}
.mh-switch__track::after {
  content: "";
  position: absolute;
  top: 2px;
  inset-inline-start: 2px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--mh-text-3);
  transition: inset-inline-start var(--mh-t-fast), background-color var(--mh-t-fast);
}
.mh-switch input:checked + .mh-switch__track {
  background: var(--mh-accent);
  border-color: var(--mh-accent);
}
.mh-switch input:checked + .mh-switch__track::after {
  inset-inline-start: 18px;
  background: var(--mh-white);
}
.mh-switch input:focus-visible + .mh-switch__track { outline: 2px solid var(--mh-accent-text); outline-offset: 2px; }
.mh-switch input:disabled + .mh-switch__track { opacity: 0.5; cursor: not-allowed; }
.mh-switch__text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.mh-switch__text b { font-size: var(--mh-t-sm); font-weight: 500; }
.mh-switch__text span { font-size: var(--mh-t-2xs); color: var(--mh-text-3); }

/* ═══════════════════════════ LOADING ═══════════════════════════ */

.mh-spinner {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  border: 2px solid var(--mh-border-strong);
  border-top-color: var(--mh-accent);
  border-radius: 50%;
  animation: mh-spin 0.8s linear infinite;
}
.mh-spinner--lg { width: 26px; height: 26px; border-width: 3px; }

.mh-loading {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--mh-3);
  padding: var(--mh-12) var(--mh-5);
  color: var(--mh-text-3);
  font-size: var(--mh-t-sm);
}

/* A region waiting on a request: dimmed, not replaced, so the layout
   does not jump when the data lands. */
.mh-busy { position: relative; }
.mh-busy[aria-busy="true"] > * { opacity: 0.4; pointer-events: none; }
.mh-busy[aria-busy="true"]::after {
  content: "";
  position: absolute;
  top: 50%;
  inset-inline-start: 50%;
  width: 24px;
  height: 24px;
  margin: -12px 0 0 -12px;
  border: 3px solid var(--mh-border-strong);
  border-top-color: var(--mh-accent);
  border-radius: 50%;
  animation: mh-spin 0.8s linear infinite;
}

/* ═══════════════════════════ KEY / VALUE ═══════════════════════════ */

.mh-kv { display: grid; gap: 0; margin: 0; }
.mh-kv > div {
  display: grid;
  grid-template-columns: minmax(120px, 34%) minmax(0, 1fr);
  gap: var(--mh-3);
  padding: var(--mh-3) 0;
  border-bottom: 1px solid var(--mh-border);
}
.mh-kv > div:last-child { border-bottom: 0; }
.mh-kv dt { font-size: var(--mh-t-xs); color: var(--mh-text-3); }
.mh-kv dd { margin: 0; font-size: var(--mh-t-sm); color: var(--mh-text); overflow-wrap: anywhere; }
@media (max-width: 520px) {
  .mh-kv > div { grid-template-columns: 1fr; gap: var(--mh-1); }
}

/* ═══════════════════ CHOICE CONTROLS (radio / checkbox) ═══════════════════
   Native inputs, styled only where the default is illegible on a dark
   ground. `accent-color` does that in one line and keeps the control's
   own keyboard behaviour, focus ring and screen-reader semantics — all
   of which a hand-built replacement would have to reimplement. */

.mh-choices {
  display: flex;
  flex-wrap: wrap;
  gap: var(--mh-2);
}

.mh-choice {
  display: inline-flex;
  align-items: center;
  gap: var(--mh-2);
  padding: 8px 12px;
  border: 1px solid var(--mh-border);
  border-radius: var(--mh-r-sm);
  background: var(--mh-surface-sub);
  font-size: var(--mh-t-sm);
  color: var(--mh-text-2);
  cursor: pointer;
  min-width: 0;
}
.mh-choice:hover { border-color: var(--mh-border-strong); color: var(--mh-text); }
.mh-choice span { overflow-wrap: anywhere; }
.mh-choice input { accent-color: var(--mh-accent); flex: none; }
.mh-choice:has(input:checked) {
  border-color: var(--mh-accent-line);
  background: var(--mh-accent-soft);
  color: var(--mh-text);
}
.mh-choice:focus-within { outline: 2px solid var(--mh-accent-text); outline-offset: 2px; }

/* Per-field help text, under the control it explains. */
.mh-hint {
  display: block;
  margin-top: 4px;
  font-size: var(--mh-t-2xs);
  color: var(--mh-text-3);
  line-height: var(--mh-lh-snug);
}

/* ═══════════════════ USERNAME (4.3) ═══════════════════
   The public address, chosen at signup and editable later. One
   component for both places: the signup form and the profile editor.
   The `@` sits where the eye button sits on a password field, the
   preview under the field shows the address as it will be, and the
   state beside the field mirrors the server's answer. */
.mh-uname__wrap { position: relative; display: block; direction: ltr; }
.mh-uname__wrap .mh-input { padding-inline-start: var(--mh-10); padding-inline-end: 112px; }
.mh-uname__input { text-align: start; letter-spacing: 0.01em; }
.mh-uname__at {
  position: absolute;
  inset-inline-start: var(--mh-3);
  top: 50%;
  transform: translateY(-50%);
  font-weight: 600;
  color: var(--mh-text-3);
  pointer-events: none;
  font-family: var(--mh-font-mono, ui-monospace, monospace);
}
.mh-uname__state {
  position: absolute;
  inset-inline-end: var(--mh-3);
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  gap: var(--mh-1);
  max-width: 45%;
  font-size: var(--mh-t-2xs);
  font-weight: 500;
  color: var(--mh-text-3);
  white-space: nowrap;
  pointer-events: none;
}
.mh-uname__state .mh-icon { width: 13px; height: 13px; flex: none; }
.mh-uname.is-checking .mh-uname__state { color: var(--mh-text-3); }
.mh-uname.is-free .mh-uname__state { color: var(--mh-success); }
.mh-uname.is-free .mh-input { border-color: var(--mh-success-line); }
.mh-uname.is-taken .mh-uname__state { color: var(--mh-danger); }
.mh-uname__suggest {
  pointer-events: auto;
  border: 1px solid var(--mh-border);
  background: var(--mh-surface-sub);
  color: var(--mh-text);
  border-radius: var(--mh-r-pill);
  padding: 1px 8px;
  font: inherit;
  font-size: var(--mh-t-2xs);
  cursor: pointer;
  direction: ltr;
}
.mh-uname__suggest:hover { border-color: var(--mh-border-strong); }
.mh-uname__hint {
  display: block;
  margin-top: var(--mh-1);
  font-size: var(--mh-t-2xs);
  color: var(--mh-text-3);
  overflow-wrap: anywhere;
  text-align: start;
}
.mh-uname__base { opacity: 0.7; }
.mh-uname__preview { color: var(--mh-text); font-weight: 500; }
