/* ==========================================================
   hostyt-hub.css - Clean app-console skin

   Loads AFTER modern-hostyt.css (structural base) and owns
   every visual token and component surface. The base file is
   a byte-for-byte copy of the one in themes/modern-hostyt, so
   upstream fixes port with a single cp; nothing here may
   depend on editing it.

   Identity: white surfaces on a cool canvas, one hairline
   weight, tinted active states instead of fills and bars,
   flat tables with full-width rules, borderless tinted
   badges, shadows reserved for things that actually float.

   Section numbers mirror modern-hostyt.css so the two files
   can be read side by side.
   ========================================================== */

/* ----------------------------------------------------------
   1. DESIGN TOKENS
   ---------------------------------------------------------- */
:root,
[data-theme="light"] {
  /* --- Brand ---
     One hex drives the family. --mh-accent is the only value a brand has
     to set (see partial_theme_head.html.twig); hover, tint and ring are
     mixed from it, so they follow automatically. Measured: #2051F1 is
     5.99:1 on white both ways. */
  --hub-brand:        #2051F1;
  --mh-accent:        var(--hub-brand);
  --mh-accent-hover:  color-mix(in srgb, var(--mh-accent) 86%, #000);
  --mh-accent-subtle: color-mix(in srgb, var(--mh-accent) 9%, #fff);
  /* Kept for the base stylesheet, which builds a few rgba() values from it.
     It cannot follow a brand override - anything in this skin that has to
     track the brand uses color-mix instead. */
  --mh-accent-rgb:    32,81,241;

  /* --- Surfaces ---
     White ground throughout; a hairline does the separating, not a shade.
     --hub-bg-subtle exists only where a run of cards needs something to
     sit on. */
  --mh-bg:            #FFFFFF;
  --mh-bg-card:       #FFFFFF;
  --mh-bg-card-rgb:   255,255,255;
  --mh-bg-sidebar:    #FFFFFF;
  --mh-bg-topbar:     #FFFFFF;
  --mh-bg-input:      #FFFFFF;
  --mh-bg-hover:      #EDF2F7;
  --mh-bg-code:       #EDF2F7;
  --mh-bg-modal:      rgba(26,32,44,.44);
  --hub-bg-subtle:    #F7F8FA;
  --hub-nav-active:   #F5F6F7;

  /* Glass is off: solid white, and blur 0 keeps the base's
     backdrop-filter declarations inert instead of fighting them. */
  --mh-glass-bg:      #FFFFFF;
  --mh-glass-border:  #EEEFF1;
  --mh-glass-blur:    0px;

  /* --- Text ---
     Muted is NOT the reference's gray.500 (#718096). Measured at 4.02:1 on
     white and 3.56:1 on the subtle fill, it fails AA for body text, so it
     is raised to #616E81 (5.18 / 4.60). */
  --mh-text:          #1A202C;
  --mh-text-secondary:#4A5568;
  --mh-text-muted:    #616E81;
  --mh-text-inverse:  #FFFFFF;

  /* Hairlines - one weight for the whole UI */
  --mh-border:        #EEEFF1;
  --mh-border-subtle: #F2F3F5;
  --mh-border-focus:  var(--mh-accent);
  --mh-ring:          0 0 0 3px color-mix(in srgb, var(--mh-accent) 22%, transparent);

  /* Shadows - near zero. Only overlays get real lift. The button carries a
     1px seat rather than a blur, which is what the reference does. */
  --mh-shadow-sm:     0 1px 2px rgba(26,32,44,.04);
  --mh-shadow:        0 1px 2px rgba(26,32,44,.04);
  --mh-shadow-md:     0 2px 6px rgba(26,32,44,.06);
  --mh-shadow-lg:     0 8px 24px rgba(26,32,44,.08);
  --mh-shadow-xl:     0 16px 40px rgba(26,32,44,.12);
  --hub-btn-shadow:   0 2px 0 0 color-mix(in srgb, var(--mh-accent) 14%, transparent);

  /* --- Status ---
     Chakra 100/700-800 pairs, each measured against its own fill, which is
     the tighter reading. Warning is the exception: orange.700 on
     orange.100 came in at 3.90:1, so it is raised to #AE4E1E (4.59:1). */
  --mh-success:       #22543D;
  --mh-success-bg:    #C6F6D5;
  --mh-danger:        #822727;
  --mh-danger-bg:     #FED7D7;
  --mh-warning:       #AE4E1E;
  --mh-warning-bg:    #FEEBC8;
  --mh-info:          #2B6CB0;
  --mh-info-bg:       #EBF8FF;
  --hub-purple:       #553C9A;
  --hub-purple-bg:    #E9D8FD;

  /* The 800-weights above are badge TEXT, sitting on a 100-weight tint. The
     base stylesheet also uses --mh-success / --mh-danger as solid button
     fills, where an 800 reads as mud. These are the fill weights, chosen so
     a white label still clears AA: 6.65:1 on green, 5.52:1 on red. Graphics
     (meter, ring, switch) use them too, so a filled shape never goes near
     black. */
  --hub-success-solid: #276749;
  --hub-danger-solid:  #C53030;
  --hub-warning-solid: #C05621;
  --hub-info-solid:    #2B6CB0;

  /* Geometry */
  --mh-radius-sm:     6px;
  --mh-radius:        8px;
  --mh-radius-lg:     12px;
  --mh-radius-xl:     16px;
  --mh-radius-full:   9999px;

  --mh-sidebar-w:     248px;
  --mh-sidebar-w-rail: 72px;
  --mh-topbar-h:      52px;
  --mh-bottom-nav-h:  58px;

  /* Motion - short and flat, no spring */
  --mh-transition:    .16s cubic-bezier(.4,0,.2,1);
  --mh-transition-slow: .24s cubic-bezier(.4,0,.2,1);

  /* --- Hub-only tokens (prefixed so they never collide) --- */
  --hub-neutral:      #4A5568;
  --hub-neutral-bg:   #EDF2F7;
  --hub-row-h:        52px;
  --hub-nav-radius:   8px;
  --hub-tile:         40px;
  --hub-title:        1.125rem;   /* page title in the topbar */
  --hub-display:      1.75rem;    /* entity headline */
}

[data-theme="dark"] {
  /* The reference ships light only, so dark is ours. #2051F1 is unreadable
     on a dark ground (it is a deep blue), so the accent lifts to #8AB4FF:
     8.45:1 on a card, and 9.06:1 for ink sitting on the filled version. */
  --mh-accent:        color-mix(in srgb, var(--hub-brand) 58%, #fff);
  --mh-accent-hover:  color-mix(in srgb, var(--mh-accent) 82%, #fff);
  --mh-accent-subtle: color-mix(in srgb, var(--mh-accent) 14%, transparent);
  --mh-accent-rgb:    138,180,255;

  --mh-bg:            #0F1113;
  --mh-bg-card:       #16191C;
  --mh-bg-card-rgb:   22,25,28;
  --mh-bg-sidebar:    #131619;
  --mh-bg-topbar:     #131619;
  --mh-bg-input:      #1A1E22;
  --mh-bg-hover:      #1D2126;
  --mh-bg-code:       #1A1E22;
  --mh-bg-modal:      rgba(4,6,8,.66);
  --hub-bg-subtle:    #131619;
  --hub-nav-active:   #1D2126;

  --mh-glass-bg:      #16191C;
  --mh-glass-border:  #242A2E;
  --mh-glass-blur:    0px;

  --mh-text:          #F2F4F5;
  --mh-text-secondary:#A5ADB5;
  --mh-text-muted:    #8B939B;
  --mh-text-inverse:  #0F1113;

  --mh-border:        #242A2E;
  --mh-border-subtle: #1E2327;

  --mh-shadow-sm:     0 1px 2px rgba(0,0,0,.3);
  --mh-shadow:        0 1px 2px rgba(0,0,0,.3);
  --mh-shadow-md:     0 2px 6px rgba(0,0,0,.36);
  --mh-shadow-lg:     0 8px 24px rgba(0,0,0,.46);
  --mh-shadow-xl:     0 16px 40px rgba(0,0,0,.56);
  --hub-btn-shadow:   none;

  /* Tints go translucent so they sit on any dark surface; the text colours
     are the light-mode fills, which read as the bright half in reverse. */
  --mh-success:       #9AE6B4;
  --mh-success-bg:    rgba(154,230,180,.14);
  --mh-danger:        #FEB2B2;
  --mh-danger-bg:     rgba(254,178,178,.14);
  --mh-warning:       #FBD38D;
  --mh-warning-bg:    rgba(251,211,141,.14);
  --mh-info:          #90CDF4;
  --mh-info-bg:       rgba(144,205,244,.14);
  --hub-purple:       #D6BCFA;
  --hub-purple-bg:    rgba(214,188,250,.14);

  /* In dark the bright tint IS the fill, and the label on it turns to ink -
     see the button rule further down. */
  --hub-success-solid: #9AE6B4;
  --hub-danger-solid:  #FEB2B2;
  --hub-warning-solid: #FBD38D;
  --hub-info-solid:    #90CDF4;

  --hub-neutral:      #B4BCC4;
  --hub-neutral-bg:   rgba(180,188,196,.12);
}

/* --- Brand safety clamp ---
   A brand may set --hub-brand to any hex, including one too light to carry
   white text. Measured: a cyan brand lands at 3.68:1 on white, below AA, and
   the plain-mix fallback cannot fix that because CSS cannot branch on
   contrast. Clamping lightness in OKLCH can: capping L at 0.52 for light and
   flooring it at 0.80 for dark held 4.87:1 or better across every brand hue
   tested - blue, green, orange, violet, cyan, crimson, yellow, lime.

   The shipped brand (#2051F1, L=0.52) is unchanged by the clamp, so this
   only ever engages for a brand that would otherwise be unreadable. Guarded
   by @supports; engines without relative colour syntax keep the values
   above, which are correct for the shipped palette. */
@supports (color: oklch(from red l c h)) {
  :root,
  [data-theme="light"] { --mh-accent: oklch(from var(--hub-brand) min(l, 0.52) c h); }
  [data-theme="dark"]  { --mh-accent: oklch(from var(--hub-brand) max(l, 0.80) c h); }
}

/* ----------------------------------------------------------
   2. BASE
   ---------------------------------------------------------- */
/* The reference sets a 16px body and drops to 13-14px for dense controls,
   rather than shrinking everything. Components below opt down explicitly. */
body {
  font-size: 16px;
  letter-spacing: -.003em;
}

h1, h2, h3, h4, h5, h6 { font-weight: 600; letter-spacing: -.018em; }
h1 { font-size: 1.5rem; }
h2 { font-size: 1.25rem; }
h3 { font-size: 1.0625rem; }

/* Numbers line up in every column that holds them */
.mh-table td,
.mh-stat__value,
.hub-meter__value,
.hub-tile__value {
  font-variant-numeric: tabular-nums;
}

/* ----------------------------------------------------------
   3. LAYOUT - SIDEBAR + TOPBAR
   ---------------------------------------------------------- */

/* --- Sidebar ---
   No border: the reference separates the column with contrast alone. A
   hairline-weight shadow keeps the edge readable now that the content
   ground is also white, without reading as a rule. */
.mh-sidebar {
  border-right: 0;
  box-shadow: 1px 0 0 0 rgba(26,32,44,.06);
}

/* One continuous white column: no rule under the wordmark. */
.mh-sidebar__brand {
  border-bottom: none;
  padding: 0 var(--mh-space-4);
  gap: var(--mh-space-3);
}
.mh-sidebar__brand img {
  height: 28px;
  border-radius: var(--mh-radius-sm);
}
.mh-sidebar__brand span {
  font-size: 1.0625rem;
  letter-spacing: -.02em;
}

.hub-sidebar-head {
  display: flex;
  align-items: center;
  gap: var(--mh-space-1);
  padding-right: var(--mh-space-2);
}
.hub-sidebar-head .mh-sidebar__brand { flex: 1; min-width: 0; }

.hub-sidebar-collapse {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  flex-shrink: 0;
  padding: 0;
  border: none;
  border-radius: var(--mh-radius-sm);
  background: transparent;
  color: var(--mh-text-muted);
  cursor: pointer;
  transition: background var(--mh-transition), color var(--mh-transition);
}
.hub-sidebar-collapse:hover { background: var(--mh-bg-hover); color: var(--mh-text); }
/* Revealed by script, so a client without JS never sees a control that
   would do nothing. */
.hub-sidebar-collapse[hidden] { display: none; }

.sidebar-nav {
  padding: var(--mh-space-2) var(--mh-space-2) var(--mh-space-4);
}

/* --- Collapsed sidebar: a rail of icons (desktop) ---
   Collapsing to icons rather than hiding the column keeps navigation one
   click away and the logo mark on screen. Width is driven by re-pointing
   --mh-sidebar-w on .mh-app, so the fixed column and the main column's
   margin both follow from one declaration. */
@media (min-width: 1025px) {
  .mh-app.is-sidebar-rail { --mh-sidebar-w: var(--mh-sidebar-w-rail); }

  /* Nav labels are bare text nodes beside the icons and cannot be targeted
     on their own - zeroing the type on the row and restoring it on the icon
     is what actually collapses them. */
  .is-sidebar-rail .sidebar-nav__link {
    justify-content: center;
    gap: 0;
    font-size: 0;
    overflow: hidden;
    white-space: nowrap;
  }
  .is-sidebar-rail .sidebar-nav__link svg { width: 20px; height: 20px; }
  .is-sidebar-rail .sidebar-nav { padding-left: var(--mh-space-2); padding-right: var(--mh-space-2); }

  /* The logo mark stays; only the wordmark and the account text go. */
  .is-sidebar-rail .mh-sidebar__brand span,
  .is-sidebar-rail .mh-user__name,
  .is-sidebar-rail .mh-user__email { display: none; }
  .is-sidebar-rail .mh-sidebar__brand {
    justify-content: center;
    padding: 0;
    min-height: var(--mh-topbar-h);
  }
  .is-sidebar-rail .mh-sidebar__brand img { height: 26px; }
  .is-sidebar-rail .hub-sidebar-head { padding-right: 0; flex-direction: column; gap: 0; }
  .is-sidebar-rail .hub-sidebar-collapse { margin-bottom: var(--mh-space-2); }

  /* Group headings become a rule: the grouping survives, the words go. */
  .is-sidebar-rail .sidebar-nav__label {
    font-size: 0;
    padding: var(--mh-space-3) var(--mh-space-2) 0;
    border-top: 1px solid var(--mh-border-subtle);
    margin-top: var(--mh-space-3);
  }
  .is-sidebar-rail .sidebar-nav > .sidebar-nav__label:first-child {
    border-top: none;
    margin-top: 0;
    padding-top: 0;
  }

  /* A count is unreadable at this width; a dot still says "something here". */
  .is-sidebar-rail .sidebar-nav__item { position: relative; }
  .is-sidebar-rail .sidebar-nav__badge {
    position: absolute;
    top: 6px;
    right: 12px;
    margin: 0;
    width: 7px;
    height: 7px;
    padding: 0;
    font-size: 0;
    border-radius: var(--mh-radius-full);
    background: var(--hub-danger-solid);
  }

  /* The footer can hold whatever a brand puts there, so it is clipped
     rather than trusted to fit the rail. */
  .is-sidebar-rail .mh-sidebar__footer {
    justify-content: center;
    padding: var(--mh-space-3) 0;
    overflow: hidden;
  }
  .is-sidebar-rail .mh-sidebar__footer .mh-user { flex: 0 0 auto; min-width: 0; }
}

/* Group labels read as quiet section names, not as shouted
   micro-caps. Sentence case, muted, air above. */
.sidebar-nav__label {
  padding: var(--mh-space-5) var(--mh-space-3) var(--mh-space-1);
  font-size: .8125rem;
  font-weight: 500;
  text-transform: none;
  letter-spacing: 0;
  color: var(--mh-text-muted);
}
/* The label is itself an <li>, so the first group needs no
   extra air above it. */
.sidebar-nav > .sidebar-nav__label:first-child { padding-top: var(--mh-space-2); }

.sidebar-nav__link {
  padding: 9px var(--mh-space-3);
  border-radius: var(--hub-nav-radius);
  font-size: .9375rem;
  font-weight: 500;
  color: var(--mh-text);
  transition: background var(--mh-transition), color var(--mh-transition);
}
.sidebar-nav__link svg {
  opacity: 1;
  color: var(--mh-text-muted);
  stroke-width: 1.6;
  transition: color var(--mh-transition);
}
.sidebar-nav__link:hover {
  background: var(--mh-bg-hover);
}
.sidebar-nav__link:hover svg { color: var(--mh-text-secondary); }

/* Active state: the neutral fill measured off the app, with the accent on
   the label and icon as the screenshots show. #2051F1 on #F5F6F7 is
   5.53:1, so the pair holds. No left bar; weight is never the only signal. */
.sidebar-nav__item.is-active .sidebar-nav__link {
  background: var(--hub-nav-active);
  color: var(--mh-accent);
  font-weight: 600;
}
.sidebar-nav__item.is-active .sidebar-nav__link svg { color: var(--mh-accent); }

.sidebar-nav__badge {
  background: var(--mh-danger-bg);
  color: var(--mh-danger);
  font-weight: 600;
  font-size: .75rem;
  padding: 1px 8px;
}

.mh-sidebar__footer {
  padding: var(--mh-space-3) var(--mh-space-4);
  border-top: 1px solid var(--mh-border);
  font-size: .875rem;
}

/* --- Topbar --- */
.mh-topbar {
  gap: var(--mh-space-3);
  padding: 0 var(--mh-space-5);
  background: var(--mh-bg-topbar);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

/* Page identity sits where the reference puts it: icon plus
   name, first thing in the bar. The breadcrumb stays in the
   markup (modules override that block) but steps back. */
.hub-page-head {
  display: flex;
  align-items: center;
  gap: var(--mh-space-3);
  min-width: 0;
  flex: 1;
}
.hub-page-head__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  color: var(--mh-text-secondary);
}
.hub-page-head__icon svg { width: 22px; height: 22px; stroke-width: 1.7; }
.hub-page-head__title {
  font-size: var(--hub-title);
  font-weight: 600;
  letter-spacing: -.02em;
  color: var(--mh-text);
  margin: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* When the page head is present the breadcrumb becomes a thin
   trail under it rather than the headline of the bar. */
.mh-topbar:has(.hub-page-head) .mh-topbar__breadcrumb {
  flex: 0 1 auto;
  font-size: .78rem;
  opacity: .85;
}
.mh-topbar__breadcrumb > :last-child:not(.sep):not(a) {
  font-weight: 500;
}

.mh-topbar__actions { gap: var(--mh-space-2); }

/* --- Page shell --- */
.mh-page-header { padding: var(--mh-space-5) var(--mh-space-6) 0; }
.mh-page-header h1 {
  font-size: var(--hub-display);
  font-weight: 700;
  letter-spacing: -.025em;
}
.mh-page-body { padding: var(--mh-space-5) var(--mh-space-6) var(--mh-space-8); }

.mh-footer {
  border-top: 1px solid var(--mh-border);
  font-size: .8125rem;
}

/* Flat list pages: white ground, so a table can run edge to
   edge the way the reference does. Applied per page in Twig. */
.hub-page--flat .mh-page-body {
  background: var(--mh-bg-card);
  padding-left: 0;
  padding-right: 0;
  padding-top: 0;
}
.hub-page--flat .mh-page-header {
  background: var(--mh-bg-card);
  padding-bottom: var(--mh-space-2);
}
/* The page gutter is gone so the rules can reach the edges; anything
   that is not a table has to carry the gutter itself. */
.hub-page--flat .mh-page-body > :not(.mh-table-wrap) {
  padding-left: var(--mh-space-6);
  padding-right: var(--mh-space-6);
}

/* ----------------------------------------------------------
   5. CARDS
   ---------------------------------------------------------- */
.mh-card {
  border: 1px solid var(--mh-border);
  border-radius: var(--mh-radius-lg);
  box-shadow: none;
}
/* Kill the glossy top sheen and the inset white ring - both
   read as decoration the moment the surface goes clean. */
.mh-card::before { content: none; }
.mh-card:hover { box-shadow: none; }

.mh-card--elevated { box-shadow: var(--mh-shadow-lg); }

.mh-card--glass {
  background: var(--mh-bg-card);
  border-color: var(--mh-border);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

/* Clickable cards answer with the accent hairline, not a hop. */
.mh-card--clickable { transition: border-color var(--mh-transition), background var(--mh-transition); }
.mh-card--clickable:hover {
  transform: none;
  box-shadow: none;
  border-color: rgba(var(--mh-accent-rgb), .45);
}

.mh-card__header {
  padding: var(--mh-space-4) var(--mh-space-5);
  border-bottom: 1px solid var(--mh-border);
  gap: var(--mh-space-3);
}
.mh-card__header h3 {
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: -.015em;
  display: flex;
  align-items: center;
  gap: var(--mh-space-2);
}
.mh-card__header h3 svg {
  width: 18px; height: 18px;
  color: var(--mh-text-muted);
  flex-shrink: 0;
}
.mh-card__footer { background: transparent; }

/* A card whose whole body is a table drops its own padding so
   the rules can span the full width. */
.mh-card:has(> .mh-table-wrap) { overflow: hidden; }
.mh-card:has(> .mh-table-wrap) > .mh-table-wrap > .mh-table > thead th:first-child,
.mh-card:has(> .mh-table-wrap) > .mh-table-wrap > .mh-table > tbody td:first-child { padding-left: var(--mh-space-5); }
.mh-card:has(> .mh-table-wrap) > .mh-table-wrap > .mh-table > thead th:last-child,
.mh-card:has(> .mh-table-wrap) > .mh-table-wrap > .mh-table > tbody td:last-child { padding-right: var(--mh-space-5); }

/* Stat tile */
.mh-stat { padding: var(--mh-space-4) var(--mh-space-5); }
.mh-stat__icon {
  width: var(--hub-tile);
  height: var(--hub-tile);
  border-radius: var(--mh-radius);
}
.mh-stat__icon svg { width: 20px; height: 20px; stroke-width: 1.7; }
.mh-stat__value {
  font-size: 1.5rem;
  font-weight: 650;
  letter-spacing: -.025em;
}
.mh-stat__label { font-size: .8125rem; color: var(--mh-text-muted); }

/* ----------------------------------------------------------
   6. BUTTONS
   ---------------------------------------------------------- */
/* 13px label on a 8px radius, and a 1px seat instead of a blur - the
   reference's button, measured. */
.mh-btn {
  padding: 7px 15px;
  font-size: .8125rem;
  font-weight: 500;
  border-radius: var(--mh-radius);
  letter-spacing: -.005em;
}
.mh-btn svg { width: 16px; height: 16px; stroke-width: 1.8; }
.mh-btn--primary { box-shadow: var(--hub-btn-shadow); }
.mh-btn--primary:hover { box-shadow: var(--hub-btn-shadow); }
.mh-btn--secondary { border-color: var(--mh-border); }
.mh-btn--secondary:hover { border-color: var(--mh-border); background: var(--mh-bg-hover); }
.mh-btn--sm { padding: 4px var(--mh-space-3); font-size: .75rem; }
.mh-btn--lg { padding: 10px var(--mh-space-5); font-size: .875rem; }
.mh-btn--icon { width: 34px; height: 34px; }

/* Solid buttons take the fill weights, not the badge-text weights the base
   would otherwise reach for. */
.mh-btn--danger,
.mh-btn--danger:hover {
  background: var(--hub-danger-solid);
  border-color: var(--hub-danger-solid);
}
.mh-btn--danger:hover { filter: brightness(.92); }
.mh-btn--success {
  background: var(--hub-success-solid);
  border-color: var(--hub-success-solid);
}

/* Dark mode brightens every solid fill, and white-on-bright is where
   contrast collapses. Ink labels instead - the same fills then read at
   7:1 or better. */
[data-theme="dark"] .mh-btn--primary,
[data-theme="dark"] .mh-btn--primary:hover,
[data-theme="dark"] .mh-btn--success,
[data-theme="dark"] .mh-btn--danger,
[data-theme="dark"] .mh-btn--danger:hover {
  color: var(--mh-text-inverse);
}

/* Soft button: tinted, borderless - for secondary actions that
   should still carry their meaning's colour. */
.mh-btn--soft {
  background: var(--mh-accent-subtle);
  color: var(--mh-accent);
  border-color: transparent;
}
.mh-btn--soft:hover { background: rgba(var(--mh-accent-rgb), .16); color: var(--mh-accent); }

/* ----------------------------------------------------------
   7. FORMS
   ---------------------------------------------------------- */
.mh-form-control {
  padding: 9px var(--mh-space-3);
  border-radius: var(--mh-radius);
  font-size: .875rem;
}
.mh-form-control:focus { border-color: var(--mh-accent); }
.mh-form-label {
  font-size: .8125rem;
  font-weight: 600;
  color: var(--mh-text-secondary);
}

/* Toolbar row: search grows, filters sit beside it, the primary
   action is pinned right. Straight from the reference. */
.hub-toolbar {
  display: flex;
  align-items: center;
  gap: var(--mh-space-2);
  flex-wrap: wrap;
  padding: var(--mh-space-4) 0;
}
.hub-toolbar__search {
  position: relative;
  flex: 1 1 260px;
  min-width: 200px;
  max-width: 420px;
}
.hub-toolbar__search .mh-form-control { padding-left: 38px; }
.hub-toolbar__search svg {
  position: absolute;
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
  width: 17px; height: 17px;
  color: var(--mh-text-muted);
  pointer-events: none;
}
.hub-toolbar__spacer { flex: 1 1 auto; }
/* A filter chip states its own result count, so the number
   never has to be hunted for elsewhere on the page. */
.hub-toolbar__count {
  color: var(--mh-text-secondary);
  font-weight: 500;
}

/* ----------------------------------------------------------
   8. TABLES
   ---------------------------------------------------------- */
.mh-table { font-size: .8125rem; }

/* Column names are readable words with a small leading icon, not
   letter-spaced micro-caps on a tinted strip. The base ships a
   "premium table headers" block that wins on specificity AND uses
   !important, so this has to match it on both counts. */
.mh-table th,
.mh-table thead th,
.table th {
  padding: var(--mh-space-2) var(--mh-space-4);
  background: transparent !important;
  font-size: .75rem !important;
  font-weight: 500 !important;
  text-transform: none !important;
  letter-spacing: 0 !important;
  color: var(--mh-text-secondary) !important;
  border-bottom: 1px solid var(--mh-border);
  border-radius: 0;
}
.mh-table th svg {
  width: 15px; height: 15px;
  vertical-align: -3px;
  margin-right: 6px;
  color: var(--mh-text-muted);
  stroke-width: 1.7;
}
.mh-table td {
  padding: var(--mh-space-3) var(--mh-space-4);
  height: var(--hub-row-h);
  border-bottom: 1px solid var(--mh-border-subtle);
}
/* The rule under the final row stays: it closes the list
   instead of leaving it frayed. */
.mh-table tr:last-child td { border-bottom: 1px solid var(--mh-border-subtle); }
/* Hover is a neutral wash, not an accent tint - the base tints with
   the brand colour via !important, which reads as a selection. */
.mh-table tbody tr:hover td { background: var(--mh-bg-hover) !important; }
.mh-table tbody tr:hover td:has(.mh-empty-state),
.mh-table tbody tr:has(.mh-empty-state):hover td { background: transparent !important; }

/* Full-bleed variant for flat list pages */
.hub-page--flat .mh-table-wrap > .mh-table > thead th:first-child,
.hub-page--flat .mh-table-wrap > .mh-table > tbody td:first-child { padding-left: var(--mh-space-6); }
.hub-page--flat .mh-table-wrap > .mh-table > thead th:last-child,
.hub-page--flat .mh-table-wrap > .mh-table > tbody td:last-child { padding-right: var(--mh-space-6); }

.mh-table--empty { color: var(--mh-text-muted); }

/* ----------------------------------------------------------
   9. BADGES & STATUS
   ---------------------------------------------------------- */
.mh-badge {
  padding: 4px 8px;
  font-size: .75rem;
  font-weight: 500;
  line-height: 1.2;
  border-radius: var(--mh-radius-sm);
  letter-spacing: -.003em;
  border: none;
}
.mh-badge--neutral { background: var(--hub-neutral-bg); color: var(--hub-neutral); }
.mh-badge--purple  { background: var(--hub-purple-bg);  color: var(--hub-purple); }
.mh-badge__dot { width: 5px; height: 5px; }

/* ----------------------------------------------------------
   10-13. TABS, ALERTS, TOASTS, MODALS
   ---------------------------------------------------------- */
.mh-alert {
  border-radius: var(--mh-radius);
  box-shadow: none;
}
.mh-toast { border-radius: var(--mh-radius); box-shadow: var(--mh-shadow-lg); }

/* The scrim is a flat wash. Blurring the page behind a dialog is
   the kind of effect this skin trades away for clarity. */
.mh-modal-overlay {
  background: var(--mh-bg-modal);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
.mh-modal {
  border: 1px solid var(--mh-border);
  border-radius: var(--mh-radius-lg);
  box-shadow: var(--mh-shadow-xl);
}
[data-theme="dark"] .mh-modal {
  background: var(--mh-bg-card);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border-color: var(--mh-border);
}
.mh-modal__header { padding: var(--mh-space-4) var(--mh-space-5); }

.mh-dropdown-menu {
  border-radius: var(--mh-radius);
  box-shadow: var(--mh-shadow-lg);
  border: 1px solid var(--mh-border);
}

/* ----------------------------------------------------------
   15. AVATAR
   ---------------------------------------------------------- */
/* Rounded square, not a circle - the reference's most visible
   small decision, and it changes how dense lists read. Sizing is
   left alone so the base's --sm / --lg variants keep working. */
.mh-avatar {
  border-radius: var(--mh-radius-sm);
  border: none;
}

.hub-avatar {
  width: 32px;
  height: 32px;
  border-radius: var(--mh-radius-sm);
  object-fit: cover;
  flex-shrink: 0;
}
.hub-avatar--lg { width: 44px; height: 44px; border-radius: var(--mh-radius); }

/* ----------------------------------------------------------
   19. EMPTY STATE
   ---------------------------------------------------------- */
.mh-empty-state { padding: var(--mh-space-12) var(--mh-space-6); }
/* Same rounded-square tile as everywhere else, so an empty list
   still looks like part of the system. */
.mh-empty-state__icon {
  width: 48px;
  height: 48px;
  border-radius: var(--mh-radius);
}
.mh-empty-state__icon svg { width: 22px; height: 22px; stroke-width: 1.7; }
.mh-empty-state__title { font-size: 1rem; font-weight: 600; }

/* ----------------------------------------------------------
   22. AUTH PAGES
   ---------------------------------------------------------- */
/* First contact with the brand, so it follows the same rules as
   the panel: a solid card, one hairline, no frosted glass. */
.mh-auth__card {
  background: var(--mh-bg-card);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border: 1px solid var(--mh-border);
  border-radius: var(--mh-radius-lg);
  box-shadow: var(--mh-shadow-md);
  padding: var(--mh-space-8);
}
[data-theme="dark"] .mh-auth__card {
  background: var(--mh-bg-card);
  border-color: var(--mh-border);
  box-shadow: var(--mh-shadow-md);
}
.mh-auth__title {
  font-size: 1.5rem;
  font-weight: 700;
  letter-spacing: -.025em;
}
.mh-auth__logo { margin-bottom: var(--mh-space-6); }

/* ----------------------------------------------------------
   26. HUB COMPONENTS
   ---------------------------------------------------------- */

/* --- Entity header: title, status pills, actions, sub-tabs --- */
.hub-entity-head { padding-bottom: var(--mh-space-2); }
.hub-entity-head__top {
  display: flex;
  align-items: flex-start;
  gap: var(--mh-space-4);
  flex-wrap: wrap;
}
.hub-entity-head__title {
  font-size: var(--hub-display);
  font-weight: 700;
  letter-spacing: -.028em;
  margin: 0;
  line-height: 1.2;
}
.hub-entity-head__meta {
  display: flex;
  align-items: center;
  gap: var(--mh-space-2);
  flex-wrap: wrap;
  margin-top: var(--mh-space-2);
  color: var(--mh-text-muted);
  font-size: .875rem;
}
.hub-entity-head__actions {
  display: flex;
  align-items: center;
  gap: var(--mh-space-2);
  margin-left: auto;
}

/* --- Info list: tinted icon tile, title, subtitle ---
   The reference's "About" pattern. Reads well for anything
   that is a label plus one fact: plan, renewal, IP, region. */
.hub-info-list {
  display: flex;
  flex-direction: column;
  gap: var(--mh-space-4);
}
.hub-info {
  display: flex;
  align-items: flex-start;
  gap: var(--mh-space-3);
}
.hub-info__icon {
  width: var(--hub-tile);
  height: var(--hub-tile);
  border-radius: var(--mh-radius);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  background: var(--mh-accent-subtle);
  color: var(--mh-accent);
}
.hub-info__icon svg { width: 19px; height: 19px; stroke-width: 1.7; }
.hub-info__icon--info    { background: var(--mh-info-bg);    color: var(--mh-info); }
.hub-info__icon--success { background: var(--mh-success-bg); color: var(--mh-success); }
.hub-info__icon--warning { background: var(--mh-warning-bg); color: var(--mh-warning); }
.hub-info__icon--danger  { background: var(--mh-danger-bg);  color: var(--mh-danger); }
.hub-info__icon--neutral { background: var(--hub-neutral-bg); color: var(--hub-neutral); }
.hub-info__body { min-width: 0; }
.hub-info__title {
  font-weight: 600;
  font-size: .9375rem;
  color: var(--mh-text);
  line-height: 1.35;
  word-break: break-word;
}
.hub-info__sub {
  font-size: .8125rem;
  color: var(--mh-text-muted);
  line-height: 1.45;
}

/* --- Tile row: icon tiles with a label and a number ---
   The reference's milestone strip. Here it carries usage
   tiers and quota thresholds. */
.hub-tile-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(84px, 1fr));
  gap: var(--mh-space-3);
}
.hub-tile { text-align: center; }
.hub-tile__icon {
  width: var(--hub-tile);
  height: var(--hub-tile);
  margin: 0 auto var(--mh-space-2);
  border-radius: var(--mh-radius);
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--mh-accent-subtle);
  color: var(--mh-accent);
}
.hub-tile__icon svg { width: 19px; height: 19px; stroke-width: 1.7; }
.hub-tile__label {
  font-size: .8125rem;
  font-weight: 500;
  color: var(--mh-text);
}
.hub-tile__value { font-size: .8125rem; color: var(--mh-text-muted); }
/* Not yet reached: present but visibly out of play. */
.hub-tile--muted .hub-tile__icon {
  background: var(--hub-neutral-bg);
  color: var(--mh-text-muted);
  opacity: .6;
}
.hub-tile--muted .hub-tile__label,
.hub-tile--muted .hub-tile__value { color: var(--mh-text-muted); }

/* --- Meter: a thin usage bar, information not decoration --- */
.hub-meter { display: block; }
/* Stacked meters space themselves, so a template never has to
   remember a margin utility for the common case. */
.hub-meter + .hub-meter { margin-top: var(--mh-space-5); }
.hub-meter__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--mh-space-3);
  margin-bottom: 6px;
  font-size: .8125rem;
}
.hub-meter__label { color: var(--mh-text-secondary); font-weight: 500; }
.hub-meter__value { color: var(--mh-text-muted); }
.hub-meter__track {
  height: 6px;
  border-radius: var(--mh-radius-full);
  background: var(--hub-neutral-bg);
  overflow: hidden;
}
.hub-meter__fill {
  display: block;
  height: 100%;
  width: 0;
  border-radius: inherit;
  background: var(--mh-accent);
  transition: width .5s cubic-bezier(.4,0,.2,1);
}
.hub-meter--warning .hub-meter__fill { background: var(--hub-warning-solid); }
.hub-meter--danger  .hub-meter__fill { background: var(--hub-danger-solid); }

/* --- Section heading between cards ---
   Small, uppercase, muted - the reference's group heading, used both
   between cards and above toggle rows. */
.hub-section-title {
  font-size: .6875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--mh-text-muted);
  margin: var(--mh-space-6) 0 var(--mh-space-3);
}

/* ----------------------------------------------------------
   27. HUB PATTERNS FROM THE MEASURED BRIEF
   ---------------------------------------------------------- */

/* --- Sub-tabs: a second, quieter row under the main tabs ---
   The reference nests navigation two deep inside a record. Main tabs keep
   the base .mh-tabs look; this is the row beneath them. */
.hub-subtabs {
  display: flex;
  gap: var(--mh-space-1);
  flex-wrap: wrap;
  padding: var(--mh-space-2) 0;
  margin-bottom: var(--mh-space-4);
  border-bottom: 1px solid var(--mh-border);
}
.hub-subtab {
  padding: 5px 10px;
  border-radius: var(--mh-radius-sm);
  font-size: .8125rem;
  font-weight: 500;
  color: var(--mh-text-secondary);
  background: transparent;
  border: none;
  cursor: pointer;
  text-decoration: none;
  transition: background var(--mh-transition), color var(--mh-transition);
}
.hub-subtab:hover { background: var(--mh-bg-hover); color: var(--mh-text); }
.hub-subtab.is-active {
  background: var(--hub-nav-active);
  color: var(--mh-accent);
  font-weight: 600;
}

/* --- Service tab bar ---
   The reference puts a record's sections in one horizontal strip directly
   under the page title, not nested inside a card, and hangs that record's
   main action off the right end of the same row. One component does both:
   tabs scroll on the left, actions stay pinned right.

   The tab buttons keep .mh-tabs around them because the base theme's tab
   script binds there and looks panels up by id, which is what lets the
   strip live outside the card its panels are in. */
.hub-tabbar {
  display: flex;
  align-items: center;
  gap: var(--mh-space-4);
  margin: 0 0 var(--mh-space-5);
  border-bottom: 1px solid var(--mh-border);
}
.hub-tabbar .mh-tabs,
.hub-tabbar .mh-tabs-wrap {
  flex: 1;
  min-width: 0;
  border-bottom: none;
  margin: 0;
}
/* The strip scrolls rather than pushing the page wide; arrows are built by
   the skin once the merge has settled its real width. */
.hub-tabbar .mh-tabs {
  padding: 0;
  overflow-x: auto;
  scroll-behavior: smooth;
}
.hub-tabbar .mh-tabs-arrow { bottom: var(--mh-space-2); }

.hub-tabbar__actions {
  display: flex;
  align-items: center;
  gap: var(--mh-space-2);
  flex-shrink: 0;
  flex-wrap: wrap;
  padding-bottom: var(--mh-space-2);
}

/* Tabs inside the bar: a resting row of quiet labels, the current one
   lifted onto a white pill with a hairline. */
.hub-tabbar .mh-tab {
  padding: 6px 12px;
  margin: 0 2px var(--mh-space-2) 0;
  border: 1px solid transparent;
  border-radius: var(--mh-radius);
  background: transparent;
  font-size: .8125rem;
  font-weight: 500;
  color: var(--mh-text-secondary);
  white-space: nowrap;
  transition: background var(--mh-transition), color var(--mh-transition);
}
.hub-tabbar .mh-tab svg {
  width: 15px;
  height: 15px;
  vertical-align: -3px;
  margin-right: 6px;
  stroke-width: 1.7;
}
.hub-tabbar .mh-tab:hover { background: var(--mh-bg-hover); color: var(--mh-text); }
.hub-tabbar .mh-tab.is-active {
  background: var(--mh-bg-card);
  border-color: var(--mh-border);
  color: var(--mh-accent);
  font-weight: 600;
  box-shadow: var(--mh-shadow-sm);
}

/* A card that only exists to hold tab panels loses its own top edge, so the
   bar above it reads as the lid. */
.hub-tabbar + .mh-card { margin-top: 0; }

/* On a phone the strip stacks: sections scroll on their own line, actions
   wrap onto the next one. Neither may push the page sideways - a panel that
   scrolls horizontally is the thing this whole layout exists to avoid. */
@media (max-width: 768px) {
  .hub-tabbar {
    flex-wrap: wrap;
    gap: 0;
    align-items: stretch;
  }
  .hub-tabbar .mh-tabs,
  .hub-tabbar .mh-tabs-wrap { flex: 1 1 100%; width: 100%; }
  .hub-tabbar__actions {
    width: 100%;
    padding: var(--mh-space-2) 0 var(--mh-space-3);
    gap: var(--mh-space-2);
  }
  /* Buttons share the row and wrap; none of them may run off the edge. */
  .hub-tabbar__actions .mh-btn {
    flex: 0 1 auto;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
  }
}

/* --- Stepper: numbered circles joined by a rule ---
   Active is the filled circle carrying its number; a finished step trades
   the number for a check, so "where am I" and "what is done" are two
   different marks rather than two shades of one. */
.hub-stepper {
  display: flex;
  align-items: flex-start;
  gap: 0;
  margin-bottom: var(--mh-space-6);
  list-style: none;
  padding: 0;
}
.hub-step {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  position: relative;
  min-width: 0;
  text-align: center;
}
/* The connector is drawn from the step, not between them, so it survives
   wrapping and a changing number of steps. */
.hub-step:not(:first-child)::before {
  content: '';
  position: absolute;
  top: 13px;
  right: 50%;
  left: -50%;
  height: 1px;
  background: var(--mh-border);
}
.hub-step.is-done::before,
.hub-step.is-active::before { background: var(--mh-accent); }
.hub-step__marker {
  position: relative;
  z-index: 1;
  width: 26px;
  height: 26px;
  border-radius: var(--mh-radius-full);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: .75rem;
  font-weight: 600;
  background: var(--mh-bg-card);
  color: var(--mh-text-muted);
  border: 1px solid var(--mh-border);
}
.hub-step__marker svg { width: 14px; height: 14px; stroke-width: 2.4; }
.hub-step.is-active .hub-step__marker {
  background: var(--mh-accent);
  border-color: var(--mh-accent);
  color: var(--mh-text-inverse);
}
.hub-step.is-done .hub-step__marker {
  background: var(--hub-neutral-bg);
  border-color: transparent;
  color: var(--mh-text-secondary);
}
.hub-step__label {
  font-size: .75rem;
  color: var(--mh-text-muted);
  max-width: 12ch;
  overflow-wrap: anywhere;
}
.hub-step.is-active .hub-step__label { color: var(--mh-text); font-weight: 600; }

/* --- Toggle switch --- */
.hub-switch { display: inline-flex; align-items: center; flex-shrink: 0; }
.hub-switch input {
  position: absolute;
  opacity: 0;
  width: 40px;
  height: 22px;
  margin: 0;
  cursor: pointer;
}
.hub-switch__track {
  width: 40px;
  height: 22px;
  border-radius: var(--mh-radius-full);
  background: var(--hub-neutral-bg);
  position: relative;
  transition: background var(--mh-transition);
  pointer-events: none;
}
.hub-switch__track::after {
  content: '';
  position: absolute;
  top: 3px;
  left: 3px;
  width: 16px;
  height: 16px;
  border-radius: var(--mh-radius-full);
  background: #fff;
  box-shadow: 0 1px 2px rgba(26,32,44,.2);
  transition: transform var(--mh-transition);
}
.hub-switch input:checked + .hub-switch__track { background: var(--hub-success-solid); }
.hub-switch input:checked + .hub-switch__track::after { transform: translateX(18px); }
.hub-switch input:focus-visible + .hub-switch__track { box-shadow: var(--mh-ring); }

/* Row that pairs a switch with an icon, a title and an explanation. */
.hub-switch-row {
  display: flex;
  align-items: center;
  gap: var(--mh-space-3);
  padding: var(--mh-space-3) 0;
  border-bottom: 1px solid var(--mh-border-subtle);
}
.hub-switch-row:last-child { border-bottom: none; }
.hub-switch-row__body { flex: 1; min-width: 0; }
.hub-switch-row__title { font-size: .875rem; font-weight: 500; }
.hub-switch-row__desc { font-size: .8125rem; color: var(--mh-text-muted); }

/* --- Segmented control --- */
.hub-segment {
  display: inline-flex;
  padding: 2px;
  gap: 2px;
  background: var(--hub-neutral-bg);
  border-radius: var(--mh-radius);
}
.hub-segment__item {
  padding: 5px 12px;
  border: none;
  background: transparent;
  border-radius: 6px;
  font-size: .8125rem;
  font-weight: 500;
  color: var(--mh-text-secondary);
  cursor: pointer;
  text-decoration: none;
  transition: background var(--mh-transition), color var(--mh-transition);
}
.hub-segment__item.is-active {
  background: var(--mh-bg-card);
  color: var(--mh-text);
  box-shadow: var(--mh-shadow-sm);
}

/* --- Filter popover --- */
.hub-popover { position: relative; display: inline-block; }
.hub-popover__panel {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 1035;
  min-width: 260px;
  padding: var(--mh-space-4);
  background: var(--mh-bg-card);
  border: 1px solid var(--mh-border);
  border-radius: var(--mh-radius-lg);
  box-shadow: var(--mh-shadow-lg);
}
.hub-popover__panel[hidden] { display: none; }
.hub-popover__row { margin-bottom: var(--mh-space-3); }
.hub-popover__row:last-child { margin-bottom: 0; }
.hub-popover__clear {
  background: none;
  border: none;
  padding: 0;
  font-size: .8125rem;
  color: var(--mh-accent);
  cursor: pointer;
}

/* --- Danger zone ---
   Reversible actions get a neutral button, irreversible ones a filled red.
   The difference in weight is the warning; the copy alone is not. */
.hub-danger { border-color: color-mix(in srgb, var(--mh-danger) 30%, var(--mh-border)); }
.hub-danger__row {
  display: flex;
  align-items: center;
  gap: var(--mh-space-3);
  padding: var(--mh-space-4) 0;
  border-bottom: 1px solid var(--mh-border-subtle);
}
.hub-danger__row:last-child { border-bottom: none; }
.hub-danger__body { flex: 1; min-width: 0; }
.hub-danger__title { font-weight: 600; font-size: .875rem; }
.hub-danger__desc { font-size: .8125rem; color: var(--mh-text-muted); }

/* --- Progress ring --- */
.hub-ring { display: inline-flex; align-items: center; justify-content: center; position: relative; }
.hub-ring svg { transform: rotate(-90deg); display: block; }
.hub-ring__track { stroke: var(--hub-neutral-bg); fill: none; }
.hub-ring__fill { stroke: var(--mh-accent); fill: none; stroke-linecap: round; }
.hub-ring--warning .hub-ring__fill { stroke: var(--hub-warning-solid); }
.hub-ring--danger  .hub-ring__fill { stroke: var(--hub-danger-solid); }
.hub-ring__value {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: .8125rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* --- Avatar with an initial, for clients with no picture --- */
.hub-initial {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: var(--mh-radius-full);
  background: var(--mh-accent-subtle);
  color: var(--mh-accent);
  font-size: .8125rem;
  font-weight: 600;
  flex-shrink: 0;
  text-transform: uppercase;
}

/* --- Chat bubbles ---
   The client's own messages sit right in a tinted bubble, staff replies left
   on a neutral one. Side plus fill both carry the distinction, so it still
   reads when the tint is lost to a colour-vision difference. */
.mh-chat .mh-message {
  max-width: 78%;
  padding: var(--mh-space-3) var(--mh-space-4);
  border-radius: var(--mh-radius-lg);
  border: none;
}
.mh-chat .mh-message--client {
  margin-left: auto;
  background: var(--mh-accent-subtle);
  border-bottom-right-radius: var(--mh-radius-sm);
}
.mh-chat .mh-message--staff {
  margin-right: auto;
  background: var(--hub-neutral-bg);
  border-bottom-left-radius: var(--mh-radius-sm);
}
.mh-chat .mh-message__author { font-size: .8125rem; font-weight: 600; }
.mh-chat .mh-message__time { font-size: .6875rem; color: var(--mh-text-muted); }
.mh-chat .mh-message__body { font-size: .875rem; }

@media (max-width: 640px) {
  .mh-chat .mh-message { max-width: 92%; }
}

/* --- Empty state illustration in a dotted frame --- */
.mh-empty-state__icon {
  background: var(--mh-bg-card);
  border: 1px dashed var(--mh-border);
  color: var(--mh-text-muted);
}

/* --- User dropdown header: avatar, name, address --- */
.hub-menu-head {
  display: flex;
  align-items: center;
  gap: var(--mh-space-3);
  padding: var(--mh-space-3) var(--mh-space-4);
  border-bottom: 1px solid var(--mh-border);
}
.hub-menu-head__name { font-weight: 600; font-size: .875rem; line-height: 1.3; }
.hub-menu-head__mail {
  font-size: .75rem;
  color: var(--mh-text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ----------------------------------------------------------
   25. RESPONSIVE
   ---------------------------------------------------------- */
@media (max-width: 768px) {
  .mh-topbar { padding: 0 var(--mh-space-4); }
  .hub-page-head__title { font-size: 1.125rem; }
  .mh-page-body { padding: var(--mh-space-4) var(--mh-space-4) var(--mh-space-8); }
  .mh-page-header { padding: var(--mh-space-4) var(--mh-space-4) 0; }
  .mh-page-header h1,
  .hub-entity-head__title { font-size: 1.5rem; }
  .hub-page--flat .mh-page-body { padding-left: 0; padding-right: 0; }
  .hub-page--flat .mh-page-body > :not(.mh-table-wrap) {
    padding-left: var(--mh-space-4);
    padding-right: var(--mh-space-4);
  }
  .hub-page--flat .mh-table-wrap > .mh-table > thead th:first-child,
  .hub-page--flat .mh-table-wrap > .mh-table > tbody td:first-child { padding-left: var(--mh-space-4); }
  .hub-page--flat .mh-table-wrap > .mh-table > thead th:last-child,
  .hub-page--flat .mh-table-wrap > .mh-table > tbody td:last-child { padding-right: var(--mh-space-4); }
  .hub-toolbar__search { max-width: none; }
}

/* Modals become bottom sheets on phones - the one place the
   panel should feel like an app rather than a page. */
@media (max-width: 640px) {
  .hub-sheet {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    top: auto;
    max-height: 88vh;
    border-radius: var(--mh-radius-xl) var(--mh-radius-xl) 0 0;
    animation: hub-sheet-in .24s cubic-bezier(.4,0,.2,1);
  }
  .hub-sheet::before {
    content: '';
    display: block;
    width: 36px;
    height: 4px;
    margin: 10px auto 2px;
    border-radius: var(--mh-radius-full);
    background: var(--mh-border);
  }
}
@keyframes hub-sheet-in {
  from { transform: translateY(100%); }
  to   { transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .hub-sheet { animation: none; }
  .hub-meter__fill { transition: none; }
}
