/* =============================================================================
   Miira theme elements  —  /manage/theme.css
   -----------------------------------------------------------------------------
   The canonical, variable-driven component system that the Theme builder
   (/manage/theme-builder.html) previews and tunes. These classes are the
   migration TARGET: the manage portal, playbooks, and dashboard should move
   onto them so button/panel/input styling has one source of truth.

   Layering:
     - The --mui-* tokens in :root below are the OVERRIDE KNOBS. Tweak them
       (live, in the Theme builder, or per-page) to reskin every component.
     - Every component rule ALSO carries an inline fallback, so a component
       still renders correctly if a token is missing, and so colour intents
       cascade straight from --accent / --portal-* (and thus follow the active
       theme: dark / warm-light / cool-light / monochrome) automatically.

   Loads after /manage/styles.css (for --accent* / --portal-* tokens).
   ========================================================================== */

:root {
    /* ---- Typography ----------------------------------------------------- */
    /* Body / UI role — font is --portal-font (styles.css); weight + transform here. */
    --mui-body-weight:       400;
    --mui-body-transform:    none;
    --mui-heading-font:      var(--portal-font, 'SF Pro Display', -apple-system, sans-serif);
    --mui-heading-weight:    600;
    --mui-heading-transform: none;
    --mui-heading-size:            16px;
    --mui-heading-letter-spacing:  0em;
    --mui-heading-line-height:     1.25;

    /* Body / UI + Monospace sizing. The families live in styles.css; these
       sizing/spacing tokens live here so the theme builder owns them in one place.
       Consumed by the base element rules (body / code) in styles.css. */
    --portal-font-size:              14px;
    --portal-letter-spacing:         0em;
    --portal-line-height:            1.5;
    --portal-font-mono-size:              13px;
    --portal-font-mono-letter-spacing:    0em;
    --portal-font-mono-line-height:       1.5;

    /* Global type scale — multiplies the rendered size of the whole manage /
       playbook app (via `zoom` on the app root) so even hard-coded px text scales
       proportionally. 1 = 100%. */
    --portal-font-scale:     1;

    /* ---- Text type-scale (general size ladder) --------------------------
       The canonical size steps that legacy px sizes across the portal +
       playbooks map onto, so the Theme-builder Body/Heading sliders drive the
       whole app (not just the .miira-* components). Sub-body steps track the
       Body/UI Size slider (--portal-font-size); title steps track the Headings
       Size slider (--mui-heading-size), so each slider owns half the ladder.
       The px in each calc() default reproduces today's rendered size, so
       nothing shifts while the sliders sit at their defaults. Use via the
       nearest step with a px fallback, e.g. `font-size: var(--fs-sm, 11px)`. */
    --fs-3xs:     calc(var(--portal-font-size, 14px) - 6px);    /*  8  */
    --fs-2xs:     calc(var(--portal-font-size, 14px) - 5px);    /*  9  */
    --fs-xs:      calc(var(--portal-font-size, 14px) - 4px);    /* 10  */
    --fs-sm:      calc(var(--portal-font-size, 14px) - 3px);    /* 11  */
    --fs-md:      calc(var(--portal-font-size, 14px) - 2px);    /* 12  (== --mui-pill / --mui-filter / --mui-card-desc) */
    --fs-nm:      calc(var(--portal-font-size, 14px) - 1px);    /* 13  (== --mui-table) */
    --fs-base:    var(--portal-font-size, 14px);                /* 14  */
    --fs-title:   calc(var(--mui-heading-size, 16px) - 1px);    /* 15  (== --mui-card-title) */
    --fs-lg:      var(--mui-heading-size, 16px);                /* 16  */
    --fs-xl:      calc(var(--mui-heading-size, 16px) + 2px);    /* 18  */
    --fs-2xl:     calc(var(--mui-heading-size, 16px) + 4px);    /* 20  */
    --fs-3xl:     calc(var(--mui-heading-size, 16px) + 6px);    /* 22  */
    --fs-4xl:     calc(var(--mui-heading-size, 16px) + 8px);    /* 24  */
    --fs-5xl:     calc(var(--mui-heading-size, 16px) + 12px);   /* 28  */
    --fs-display: calc(var(--mui-heading-size, 16px) + 15px);   /* 31  */

    /* ---- Button geometry (shared by every intent + style) ---------------- */
    --mui-btn-font:          var(--portal-font, 'SF Pro Display', -apple-system, sans-serif);
    --mui-btn-font-size:     12px;
    --mui-btn-letter-spacing: 0em;
    --mui-btn-line-height:   1.1;
    --mui-btn-font-weight:   600;
    --mui-btn-transform:     none;
    --mui-btn-radius:        1px;
    --mui-btn-pad-y:         10px;
    --mui-btn-pad-x:         20px;
    --mui-btn-gap:           8px;     /* icon / label gap */
    --mui-btn-border-width:  1px;
    --mui-btn-glyph:         18px;    /* svg icon size */
    --mui-btn-icon-size:     36px;    /* square footprint for the icon-only style */
    --mui-btn-transition:    150ms ease;
    /* Side modal / drawer motion — shared by every slide-in panel (Files, Messenger
       drawer, Messenger modal, contact detail slide-over, residence right-rail). Two
       independently-tunable effects, each with its own duration + easing: the slide
       (transform/width/box-shadow) and the fade (backdrop scrim + the panel's own
       opacity). Defaults match the historical drawer family. Tuned via the theme
       builder's "Side modals" controls. */
    --mui-drawer-slide-duration: 340ms;
    --mui-drawer-slide-ease:     cubic-bezier(.22,.61,.36,1);
    --mui-drawer-fade-duration:  300ms;
    --mui-drawer-fade-ease:      ease;
    /* Raised look: a glass edge (crisp top highlight, soft lower shade, hairline outer
       sheen) — the same finish the Luxe-sheen power style uses. --mui-btn-raised is a
       0–100 intensity that scales every layer's alpha, so 0 = flat and 100 = full. The
       theme builder's "Raised depth" slider drives it. The shadow re-evaluates per
       element, so the sheen style can force its own full-strength edge locally. */
    --mui-btn-raised:        0;
    --mui-btn-raised-shadow:
        inset 0 1px 0 rgba(255, 255, 255, calc(0.5 * var(--mui-btn-raised, 0) / 100)),
        inset 0 -2px 2px rgba(0, 0, 0, calc(0.32 * var(--mui-btn-raised, 0) / 100)),
        0 0 0 1px rgba(255, 255, 255, calc(0.08 * var(--mui-btn-raised, 0) / 100)),
        0 2px 5px rgba(0, 0, 0, calc(0.35 * var(--mui-btn-raised, 0) / 100));

    /* ---- Pill button geometry (the compact --pill button style) --------- */
    --mui-pill-radius:     999px;
    --mui-pill-pad-y:      6px;
    --mui-pill-pad-x:      12px;
    --mui-pill-font-size:  calc(var(--portal-font-size, 14px) - 2px);

    /* ---- Filter chip (standalone .miira-filter component) ---------------
       Filters are their OWN component, not a button — these tokens fully describe
       them. Defaults reproduce the previous widget look: a secondary-grey pill that
       tints with the accent when selected (.is-active). */
    --mui-filter-radius:        999px;
    --mui-filter-pad-y:         6px;
    --mui-filter-pad-x:         12px;
    --mui-filter-font-size:     calc(var(--portal-font-size, 14px) - 2px);
    --mui-filter-gap:           6px;
    --mui-filter-glyph:         14px;   /* svg icon size */
    --mui-filter-border-width:  1px;
    --mui-filter-font:          var(--portal-font, 'SF Pro Display', -apple-system, sans-serif);
    --mui-filter-font-weight:   500;
    --mui-filter-bg:            var(--portal-input-bg, rgba(255, 255, 255, 0.025));
    --mui-filter-text:          var(--portal-text, #ffffff);
    --mui-filter-border:        var(--portal-border, #1e2a36);
    --mui-filter-bg-hover:      var(--portal-bg-card-hover, #161a24);
    --mui-filter-border-hover:  var(--portal-text-dim, #5a6a7a);
    --mui-filter-active-bg:     rgba(var(--accent-rgb, 99, 102, 241), 0.12);
    --mui-filter-active-text:   var(--accent-text, #a5b4fc);
    --mui-filter-active-border: rgba(var(--accent-rgb, 99, 102, 241), 0.35);

    /* ---- Switch / toggle ------------------------------------------------ */
    --mui-switch-w:     34px;
    --mui-switch-h:     20px;
    --mui-switch-knob:  16px;
    --mui-switch-on:    var(--accent, #6366f1);
    --mui-switch-off:   var(--portal-border, #1e2a36);
    /* Depth: a 0–100 intensity that presses the track in (inset) and lifts the knob
       out (drop shadow). 0 = flat. The theme builder's "Switch depth" slider drives it. */
    --mui-switch-raised: 0;
    --mui-switch-indent-shadow:
        inset 0 1px 2px rgba(0, 0, 0, calc(0.5 * var(--mui-switch-raised, 0) / 100)),
        inset 0 -1px 0 rgba(255, 255, 255, calc(0.06 * var(--mui-switch-raised, 0) / 100));
    --mui-switch-knob-shadow:
        0 1px 2px rgba(0, 0, 0, calc(0.45 * var(--mui-switch-raised, 0) / 100)),
        0 0 0 1px rgba(0, 0, 0, calc(0.06 * var(--mui-switch-raised, 0) / 100));

    /* ---- Colour intents ------------------------------------------------- */
    /* Primary / Power — the accent fill (standard call-to-action). */
    --mui-primary-bg:        var(--accent, #6366f1);
    --mui-primary-text:      var(--accent-contrast, #ffffff);
    --mui-primary-border:    var(--accent, #6366f1);
    --mui-primary-bg-hover:  var(--accent-hover, #5558e6);

    /* Power — Primary + an animated glow (premium CTA). Three styles ship; a theme
       picks one by gating these (the other layers stay inert):
         · Orbit    — discrete light sliver(s) travelling the edge (--…-orbit-opacity)
         · Flow     — the accent gradient flowing around the ring  (--…-flow-opacity)
         · Gradient — the accent fill itself rotating on the button face
                      (--…-fill-play running spins the gradient's angle) */
    --mui-power-orbit-duration:  9s;        /* time for one full revolution / rotation */
    --mui-power-orbit-count:     1;         /* number of glow slivers (evenly spaced) */
    --mui-power-glow:            50;         /* glow intensity, 0–100 (highlight alpha) */
    --mui-power-orbit-opacity:   1;          /* Orbit style visibility */
    --mui-power-flow-opacity:    0;          /* Flow style visibility */
    --mui-power-fill-play:       paused;     /* Scrolling-fractal style: running scrolls the grain */
    /* Scrolling-fractal style: the accent-2 grain mask tiles at this scale. Glow
       (0–100) drives it — higher glow = coarser grain (40px → 180px). */
    --mui-power-noise-scale:     calc(40px + var(--mui-power-glow, 50) * 1.4px);
    --mui-power-dots-play:       paused;     /* Scrolling dot-matrix style: running scrolls the dot grid */
    /* Scrolling dot-matrix style: the accent-2 dot grid tiles (one dot per tile) at
       this pitch. Glow (0–100) drives it — higher glow = coarser grid (4px → 11px). */
    --mui-power-dot-scale:       calc(4px + var(--mui-power-glow, 50) * 0.07px);
    --mui-power-sheen-play:      paused;     /* Luxe-sheen style: running sweeps the glint */

    /* Secondary — our standard grey (subtle fill, neutral border). */
    --mui-secondary-bg:            var(--portal-input-bg, rgba(255, 255, 255, 0.025));
    --mui-secondary-text:          var(--portal-text, #ffffff);
    --mui-secondary-border:        var(--portal-border, #1e2a36);
    --mui-secondary-bg-hover:      var(--portal-bg-card-hover, #161a24);
    --mui-secondary-border-hover:  var(--portal-text-dim, #5a6a7a);

    /* Subtle — low-emphasis outline that fills with the accent on hover
       (dashboard connector "Connect"/add button). */
    --mui-subtle-bg:          transparent;
    --mui-subtle-text:        var(--accent-text, #a5b4fc);
    --mui-subtle-border:      var(--portal-border, #1e2a36);
    --mui-subtle-bg-hover:    var(--accent, #6366f1);
    --mui-subtle-text-hover:  var(--accent-contrast, #ffffff);

    /* Danger — destructive actions (delete, cleanup). Soft red by default. */
    --mui-danger-bg:            rgba(239, 68, 68, 0.12);
    --mui-danger-text:          var(--portal-accent-red, #ef4444);
    --mui-danger-border:        rgba(239, 68, 68, 0.45);
    --mui-danger-bg-hover:      rgba(239, 68, 68, 0.20);
    --mui-danger-border-hover:  rgba(239, 68, 68, 0.75);

    /* Ghost / link — text-only inline actions ("Manage", "View"). */
    --mui-ghost-text:        var(--accent-text, #a5b4fc);
    --mui-ghost-text-hover:  var(--accent, #6366f1);

    /* ---- Panel / card --------------------------------------------------- */
    --mui-panel-bg:      var(--portal-bg-card, #11141d);
    --mui-panel-border:  var(--portal-border, #1e2a36);
    --mui-panel-radius:  5px;
    --mui-panel-pad:     24px;

    /* ---- Input / form control ------------------------------------------ */
    --mui-input-bg:      var(--portal-bg-surface, #11141d);
    --mui-input-border:  var(--portal-border, #1e2a36);
    --mui-input-text:    var(--portal-text, #ffffff);
    --mui-input-radius:  1px;
    --mui-input-pad-y:   8px;
    --mui-input-pad-x:   10px;
    /* Tracks the Body/UI Size slider (--portal-font-size, default 14px) so form
       inputs scale with the body role. Offset preserves the original px default. */
    --mui-input-font-size: var(--portal-font-size, 14px);

    /* ---- Divider hairlines ---------------------------------------------- */
    /* The horizontal lines between table rows (--mui-table-divider) and on
       panel/card-header/switch-row/heading separators (--mui-divider). Default
       to transparent (hidden); set either to var(--portal-border) to show them.
       The Theme builder's "Dividers / lines" toggles flip these. */
    --mui-table-divider:  transparent;
    --mui-divider:        transparent;

    /* ---- Table ---------------------------------------------------------- */
    --mui-table-font-size:    calc(var(--portal-font-size, 14px) - 1px);
    --mui-table-cell-pad-y:   9px;
    --mui-table-cell-pad-x:   12px;
    /* Header cells take their own vertical padding (a denser/airier header band),
       and the first/last columns get an outer X gutter so content doesn't hug the
       rounded table edge. Both default to the matching cell padding token. */
    --mui-table-header-pad-y: var(--mui-table-cell-pad-y);
    --mui-table-edge-pad-x:   var(--mui-table-cell-pad-x);
    --mui-table-radius:       5px;    /* follows --mui-panel-radius — a table is a panel-like container */
    --mui-table-row-hover:    var(--portal-bg-card-hover, #161a24);
    /* Header-band fill for every table header (and the stocklist level-separator
       rows). Editable in the Theme builder (Tables → Header). Defaults to the lifted
       "chip" surface each theme already defines (--portal-project-selector-bg — what
       the stocklist level rows used), so it reads as a distinct band on every palette
       and resolves to a real colour (no color-mix, which some engines leave unevaluated
       and render black). */
    --mui-table-header-bg:    var(--portal-project-selector-bg, var(--portal-nav-bg, #141a21));
    /* Body-cell fill + text (Theme builder → Tables → Body fill / Body text).
       Fill defaults to the table chrome surface (same as .stock-table-wrap), so the
       picker shows a real colour and the stocklist body is unchanged; text follows
       --portal-text. */
    --mui-table-body-bg:      var(--portal-nav-bg, var(--portal-bg-card, #11141d));
    --mui-table-body-text:    var(--portal-text, #ffffff);

    /* ---- Card (independent family; tunes separately from panels) -------- */
    --mui-card-radius:        12px;
    --mui-card-pad:           24px;   /* body zone */
    --mui-card-border:        var(--portal-border, #1e2a36);
    --mui-card-border-width:  1px;
    --mui-card-header-pad-y:  18px;
    --mui-card-header-pad-x:  22px;
    --mui-card-header-border: var(--mui-card-border, var(--portal-border, #1e2a36));
    --mui-card-gap:           16px;
    /* Card title tracks the Headings Size slider; description tracks Body Size.
       Offsets keep the original 15px / 12px defaults. */
    --mui-card-title-size:    calc(var(--mui-heading-size, 16px) - 1px);
    --mui-card-desc-size:     calc(var(--portal-font-size, 14px) - 2px);
    /* Hover: lift + shadow geometry are theme-invariant (global, here);
       --mui-card-hover-border / -shadow are re-set per [data-theme] in styles.css
       (so they are NOT reachable by the builder's :root colour pickers). */
    --mui-card-hover-lift:    -2px;
    --mui-card-hover-shadow:  0 8px 22px rgba(0, 0, 0, 0.3);
    --mui-card-hover-border:  var(--portal-border-active, #344052);  /* dark default */
}

/* =============================================================================
   Buttons  —  .miira-btn  +  colour intent  +  style modifier
   e.g.  <button class="miira-btn miira-btn--primary">Save</button>
         <button class="miira-btn miira-btn--subtle miira-btn--icon">…</button>
         <button class="miira-btn miira-btn--secondary miira-btn--pill">Select all</button>
   ========================================================================== */

.miira-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* Neutralise the global `button {width:100%;max-width:308px;height:36px}`
       rule in styles.css — .miira-btn sizes to its content. */
    width: auto;
    max-width: none;
    height: auto;
    box-sizing: border-box;
    /* Consistent height whether or not the button has an icon: the icon (taller
       than the text line) would otherwise make icon buttons taller. */
    min-height: calc(var(--mui-btn-glyph, 18px) + 2 * var(--mui-btn-pad-y, 8px) + 2 * var(--mui-btn-border-width, 1px));
    gap: var(--mui-btn-gap, 8px);
    padding: var(--mui-btn-pad-y, 8px) var(--mui-btn-pad-x, 16px);
    border: var(--mui-btn-border-width, 1px) solid transparent;
    box-shadow: var(--mui-btn-raised-shadow);
    /* Two-tier override composition. Colour intents (--primary…--power) and style
       classes (--icon/--widget/--block) each want to override radius / font / colour
       independently — but a button can carry BOTH at once. So neither axis sets these
       properties directly (that would make specificity / source order decide who wins,
       clobbering the other when its override is unset). Instead:
         · intent rules set the --btn-i-* tier,
         · style rules set the --btn-s-* tier,
         · only this base rule applies them, style-tier over intent-tier over global.
       Each tier's token is declared with NO fallback, so when unset it resolves to the
       guaranteed-invalid value and the next tier's fallback is used — an unset override
       is therefore completely inert. */
    border-radius:  var(--btn-s-radius, var(--btn-i-radius, var(--mui-btn-radius, 8px)));
    border-color:   var(--btn-s-bd,     var(--btn-i-bd,     var(--mui-btn-border, transparent)));
    background:     var(--btn-s-bg,     var(--btn-i-bg,     var(--mui-btn-bg, transparent)));
    color:          var(--btn-s-fg,     var(--btn-i-fg,     var(--mui-btn-text, var(--portal-text, #ffffff))));
    font-family:    var(--btn-s-ff,     var(--btn-i-ff,     var(--mui-btn-font, var(--portal-font, 'Inter', sans-serif))));
    font-size:      var(--btn-s-fs,     var(--btn-i-fs,     var(--mui-btn-font-size, 13px)));
    font-weight:    var(--btn-s-fw,     var(--btn-i-fw,     var(--mui-btn-font-weight, 600)));
    text-transform: var(--btn-s-tt,     var(--btn-i-tt,     var(--mui-btn-transform, none)));
    letter-spacing: var(--mui-btn-letter-spacing, normal);
    line-height: var(--mui-btn-line-height, 1.1);
    white-space: nowrap;
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
    transition:
        background var(--mui-btn-transition, 150ms ease),
        border-color var(--mui-btn-transition, 150ms ease),
        color var(--mui-btn-transition, 150ms ease),
        box-shadow var(--mui-btn-transition, 150ms ease),
        filter var(--mui-btn-transition, 150ms ease);
}

.miira-btn svg {
    width: var(--mui-btn-glyph, 18px);
    height: var(--mui-btn-glyph, 18px);
    flex: 0 0 auto;
}

/* Label text must follow the button's own colour AND font. The global
   `h1…span { color: var(--portal-text); font-family: 'SF Pro Display'… }` rule
   in styles.css targets bare <span> labels directly (so they don't inherit) —
   re-assert inheritance here so intents like --primary/--power keep their
   accent-contrast text, and so the label uses the themed button font/weight
   rather than the reset's hard-coded family. */
.miira-btn span {
    color: inherit;
    font: inherit;
    letter-spacing: inherit;
}

.miira-btn:disabled,
.miira-btn[aria-disabled="true"] {
    /* Dimmed but still hoverable — disabled buttons keep their title tooltip and
       any "coming soon" hover pill (pointer-events stays enabled). Native
       <button disabled> is already unclickable; aria-disabled relies on JS guards. */
    opacity: 0.5;
}

.miira-btn:focus-visible {
    outline: 2px solid var(--accent, #6366f1);
    outline-offset: 2px;
}

/* ---- Colour intents ---- */

/* Colour intents set the --btn-i-* tier only (see the base rule). Colours always
   resolve; geometry/type override tokens use no fallback so an unset one is inert. */
.miira-btn--primary {
    --btn-i-bg: var(--mui-btn-primary-bg, var(--mui-primary-bg, var(--accent, #6366f1)));
    --btn-i-bd: var(--mui-btn-primary-border, var(--mui-primary-border, var(--accent, #6366f1)));
    --btn-i-fg: var(--mui-btn-primary-text, var(--mui-primary-text, var(--accent-contrast, #ffffff)));
    --btn-i-radius: var(--mui-btn-primary-radius);
    --btn-i-ff: var(--mui-btn-primary-font);
    --btn-i-fs: var(--mui-btn-primary-font-size);
    --btn-i-fw: var(--mui-btn-primary-font-weight);
    --btn-i-tt: var(--mui-btn-primary-transform);
}
.miira-btn--primary:hover:not(:disabled) {
    background: var(--mui-primary-bg-hover, var(--accent-hover, #5558e6));
    border-color: var(--mui-primary-bg-hover, var(--accent-hover, #5558e6));
}

.miira-btn--secondary {
    --btn-i-bg: var(--mui-btn-secondary-bg, var(--mui-secondary-bg, var(--portal-input-bg, rgba(255, 255, 255, 0.025))));
    --btn-i-bd: var(--mui-btn-secondary-border, var(--mui-secondary-border, var(--portal-border, #1e2a36)));
    --btn-i-fg: var(--mui-btn-secondary-text, var(--mui-secondary-text, var(--portal-text, #ffffff)));
    --btn-i-radius: var(--mui-btn-secondary-radius);
    --btn-i-ff: var(--mui-btn-secondary-font);
    --btn-i-fs: var(--mui-btn-secondary-font-size);
    --btn-i-fw: var(--mui-btn-secondary-font-weight);
    --btn-i-tt: var(--mui-btn-secondary-transform);
}
.miira-btn--secondary:hover:not(:disabled) {
    background: var(--mui-secondary-bg-hover, var(--portal-bg-card-hover, #161a24));
    border-color: var(--mui-secondary-border-hover, var(--portal-text-dim, #5a6a7a));
}

.miira-btn--subtle {
    --btn-i-bg: var(--mui-btn-subtle-bg, var(--mui-subtle-bg, transparent));
    --btn-i-bd: var(--mui-btn-subtle-border, var(--mui-subtle-border, var(--portal-border, #1e2a36)));
    --btn-i-fg: var(--mui-btn-subtle-text, var(--mui-subtle-text, var(--accent-text, #a5b4fc)));
    --btn-i-radius: var(--mui-btn-subtle-radius);
    --btn-i-ff: var(--mui-btn-subtle-font);
    --btn-i-fs: var(--mui-btn-subtle-font-size);
    --btn-i-fw: var(--mui-btn-subtle-font-weight);
    --btn-i-tt: var(--mui-btn-subtle-transform);
}
.miira-btn--subtle:hover:not(:disabled) {
    background: var(--mui-subtle-bg-hover, var(--accent, #6366f1));
    border-color: var(--mui-subtle-bg-hover, var(--accent, #6366f1));
    color: var(--mui-subtle-text-hover, var(--accent-contrast, #ffffff));
}

.miira-btn--danger {
    --btn-i-bg: var(--mui-btn-danger-bg, var(--mui-danger-bg, rgba(239, 68, 68, 0.12)));
    --btn-i-bd: var(--mui-btn-danger-border, var(--mui-danger-border, rgba(239, 68, 68, 0.45)));
    --btn-i-fg: var(--mui-btn-danger-text, var(--mui-danger-text, var(--portal-accent-red, #ef4444)));
    --btn-i-radius: var(--mui-btn-danger-radius);
    --btn-i-ff: var(--mui-btn-danger-font);
    --btn-i-fs: var(--mui-btn-danger-font-size);
    --btn-i-fw: var(--mui-btn-danger-font-weight);
    --btn-i-tt: var(--mui-btn-danger-transform);
}
.miira-btn--danger:hover:not(:disabled) {
    background: var(--mui-danger-bg-hover, rgba(239, 68, 68, 0.20));
    border-color: var(--mui-danger-border-hover, rgba(239, 68, 68, 0.75));
}

.miira-btn--ghost {
    --btn-i-bg: var(--mui-btn-ghost-bg, transparent);
    --btn-i-bd: var(--mui-btn-ghost-border, transparent);
    --btn-i-fg: var(--mui-btn-ghost-text, var(--mui-ghost-text, var(--accent-text, #a5b4fc)));
    --btn-i-radius: var(--mui-btn-ghost-radius);
    --btn-i-ff: var(--mui-btn-ghost-font);
    --btn-i-fs: var(--mui-btn-ghost-font-size);
    --btn-i-fw: var(--mui-btn-ghost-font-weight);
    --btn-i-tt: var(--mui-btn-ghost-transform);
    padding-left: 6px;
    padding-right: 6px;
    /* A ghost/link button reads as text, not a raised surface — never give it the
       raised glass edge, even when the global toggle is on. */
    box-shadow: none;
}
.miira-btn--ghost:hover:not(:disabled) {
    color: var(--mui-ghost-text-hover, var(--accent, #6366f1));
    text-decoration: underline;
}

/* ---- Power: Primary fill + orbiting light ---- */
@property --mui-power-angle {
    syntax: '<angle>';
    inherits: false;
    initial-value: 0deg;
}
@keyframes miiraPowerOrbit {
    to { --mui-power-angle: 360deg; }
}
/* Flow style: a slow living sheen — the gradient subtly brightens and saturates
   as it turns, so the edge reads like polished metal catching the light. */
@keyframes miiraPowerSheen {
    0%, 100% { filter: brightness(1)    saturate(1.05); }
    50%      { filter: brightness(1.22) saturate(1.4);  }
}
/* Gradient style: the accent fill stays STATIC and the liquid motion comes from the
   accent-2 grain scrolling over it. Scrolling the gradient itself read as a repeating
   tile marching across; scrolling an organic noise texture instead has no recognisable
   landmark, so it reads as flowing liquid. We shift the mask by exactly one tile
   (--mui-power-noise-scale) on each axis, so the tiled noise wraps seamlessly. */
@keyframes miiraPowerNoise {
    from {
        -webkit-mask-position: 0 0;
        mask-position: 0 0;
    }
    to {
        -webkit-mask-position: var(--mui-power-noise-scale) var(--mui-power-noise-scale);
        mask-position: var(--mui-power-noise-scale) var(--mui-power-noise-scale);
    }
}
/* Dot-matrix style: identical mechanics to the fractal above — a static accent-2 sheet
   revealed through a scrolling mask — but the mask is a regular grid of dots instead of
   organic noise. Shifting by a whole number of tiles on each axis wraps the grid
   seamlessly; using an uneven step (1 tile across, 2 down) gives a shallower, more
   artful tilt (~26.5°) than a plain 45° diagonal, with no visible jump. */
@keyframes miiraPowerDots {
    from {
        -webkit-mask-position: 0 0;
        mask-position: 0 0;
    }
    to {
        -webkit-mask-position: var(--mui-power-dot-scale) calc(var(--mui-power-dot-scale) * 2);
        mask-position: var(--mui-power-dot-scale) calc(var(--mui-power-dot-scale) * 2);
    }
}

.miira-btn--power {
    position: relative;
    /* Own stacking context so the Gradient style's grain (::after, z-index -1) can sit
       above the fill but below the label text. */
    isolation: isolate;
    /* Plain, STATIC 135° accent fill — identical for every power style. The Gradient
       style's motion comes from the accent-2 grain scrolling on top (see the style
       query below), not from moving this gradient, so there is no tile-like scroll.
       With no --accent-2 both stops collapse to --accent (solid). Routed through the
       --btn-i-* tier (see the base rule) so style-class overrides can still win. */
    --btn-i-bg: var(--mui-btn-power-bg, linear-gradient(
        135deg,
        var(--accent, #6366f1),
        var(--accent-2, var(--accent, #6366f1))
    ));
    --btn-i-bd: var(--mui-btn-power-border, var(--mui-primary-border, var(--accent, #6366f1)));
    --btn-i-fg: var(--mui-btn-power-text, var(--mui-primary-text, var(--accent-contrast, #ffffff)));
    --btn-i-radius: var(--mui-btn-power-radius);
    --btn-i-ff: var(--mui-btn-power-font);
    --btn-i-fs: var(--mui-btn-power-font-size);
    --btn-i-fw: var(--mui-btn-power-font-weight);
    --btn-i-tt: var(--mui-btn-power-transform);
}
/* Keep the rotating gradient (and its animation) intact on hover; brighten slightly
   for feedback rather than swapping the background, which would reset the spin. */
.miira-btn--power:hover:not(:disabled) {
    border-color: var(--mui-primary-bg-hover, var(--accent-hover, #5558e6));
    filter: brightness(1.06);
}
/* A faint light arc in a conic gradient, masked to the border ring so only a
   travelling sliver glides along the edge. */
.miira-btn--power::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    padding: 1px;
    /* One sliver per --mui-power-orbit-count, evenly spaced around the ring: the
       gradient repeats every (360deg / count), with the highlight near the end of
       each segment. --mui-power-glow (0–100) drives the highlight's alpha. */
    background: repeating-conic-gradient(
        from var(--mui-power-angle, 0deg),
        rgba(255, 255, 255, 0) 0deg,
        rgba(255, 255, 255, 0)
            calc(360deg / var(--mui-power-orbit-count, 1) * 0.74),
        rgb(255 255 255 / calc(var(--mui-power-glow, 50) * 1%))
            calc(360deg / var(--mui-power-orbit-count, 1) * 0.92),
        rgba(255, 255, 255, 0)
            calc(360deg / var(--mui-power-orbit-count, 1))
    );
    -webkit-mask:
        linear-gradient(#000 0 0) content-box,
        linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
    mask:
        linear-gradient(#000 0 0) content-box,
        linear-gradient(#000 0 0);
    mask-composite: exclude;
    animation: miiraPowerOrbit var(--mui-power-orbit-duration, 9s) linear infinite;
    opacity: var(--mui-power-orbit-opacity, 1);
    pointer-events: none;
}
/* Flow style: the accent gradient itself wrapped around the border ring and slowly
   turning, with a luminous band sweeping through it — a sleek, liquid sheen. Masked
   to the ring exactly like Orbit; gated off by default via --mui-power-flow-opacity. */
.miira-btn--power::before {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    padding: 1.5px;
    background: conic-gradient(
        from var(--mui-power-angle, 0deg),
        var(--accent, #6366f1),
        var(--accent-2, var(--accent, #6366f1)),
        rgb(255 255 255 / calc(var(--mui-power-glow, 50) * 1%)),
        var(--accent-2, var(--accent, #6366f1)),
        var(--accent, #6366f1)
    );
    -webkit-mask:
        linear-gradient(#000 0 0) content-box,
        linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
    mask:
        linear-gradient(#000 0 0) content-box,
        linear-gradient(#000 0 0);
    mask-composite: exclude;
    animation:
        miiraPowerOrbit var(--mui-power-orbit-duration, 9s) linear infinite,
        miiraPowerSheen 6s ease-in-out infinite;
    opacity: var(--mui-power-flow-opacity, 0);
    pointer-events: none;
}
/* Gradient style adds an accent-2 grain over the gliding fill. The three power
   styles are mutually exclusive, so when Gradient is active (--mui-power-fill-play:
   running) Orbit is off and its ::after box is free to repurpose. We can't mask the
   button itself (that would eat the label text), so the grain lives on ::after: a
   full-face accent-2 sheet revealed through a tileable feTurbulence mask. The mask
   tiles at --mui-power-noise-scale, which Glow drives. */
@container style(--mui-power-fill-play: running) {
    .miira-btn--power::after {
        padding: 0;
        /* Below the label text (see isolation on .miira-btn--power), above the fill. */
        z-index: -1;
        background: var(--accent-2, var(--accent, #6366f1));
        /* feTurbulence noise piped into the alpha channel (RGB forced white, alpha =
           luminance) so it works as an alpha mask everywhere. The filter region is
           pinned to 0 0 100% 100% — without it the default -10%..110% region clips
           the noise and stitchTiles can't stitch, which shows up as tile seams. */
        -webkit-mask:
            url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='mn' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.06' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 1.4 0 0 0 -0.2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23mn)'/%3E%3C/svg%3E")
            0 0 / var(--mui-power-noise-scale) repeat;
        mask:
            url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='mn' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.06' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 1.4 0 0 0 -0.2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23mn)'/%3E%3C/svg%3E")
            0 0 / var(--mui-power-noise-scale) repeat;
        -webkit-mask-composite: source-over;
        mask-composite: add;
        /* Soften the grain so the fractal blobs read as a hazy sheen, not crisp specks. */
        filter: blur(0.6px);
        animation: miiraPowerNoise var(--mui-power-orbit-duration, 9s) linear infinite;
        opacity: 0.7;
    }
}
/* Dot-matrix style: same repurposed ::after as Gradient (mutually exclusive with the
   ring styles), but the accent-2 sheet is revealed through a tiled dot grid rather than
   feTurbulence noise. Each tile holds one soft dot (opaque centre, transparent surround),
   so the grid reads as a scrolling dot matrix as the mask drifts. */
@container style(--mui-power-dots-play: running) {
    /* Clip the rotated, oversized dot sheet back to the rounded button face. */
    .miira-btn--power { overflow: hidden; }
    .miira-btn--power::after {
        padding: 0;
        /* Rotate the whole lattice off-axis so it doesn't read as a plain grid, and
           oversize the sheet (inset negative) so the tilted square still covers every
           corner of the face after rotation. */
        inset: -55%;
        transform: rotate(17deg);
        /* Below the label text (see isolation on .miira-btn--power), above the fill. */
        z-index: -1;
        background: var(--accent-2, var(--accent, #6366f1));
        /* One dot per tile: a pinpoint opaque core out to ~9% of the pitch, transparent
           beyond. mask alpha (default match-source) gates visibility, so the dots show
           and the gaps stay clear. Tiled at --mui-power-dot-scale on both axes. */
        -webkit-mask:
            radial-gradient(circle at 50% 50%,
                #000 0, #000 9%, transparent 16%)
            0 0 / var(--mui-power-dot-scale) var(--mui-power-dot-scale) repeat;
        mask:
            radial-gradient(circle at 50% 50%,
                #000 0, #000 9%, transparent 16%)
            0 0 / var(--mui-power-dot-scale) var(--mui-power-dot-scale) repeat;
        /* Barely soften the edges — just enough to anti-alias the fine dots without
           blurring away the crisp, high-tech read. */
        filter: blur(0.25px);
        animation: miiraPowerDots var(--mui-power-orbit-duration, 9s) linear infinite;
        opacity: 0.6;
    }
}
/* Luxe-sheen style: a specular light streak glints across the face, then rests — the
   quick sweep-and-pause reads like light catching polished glass or brushed metal, an
   understated way to draw the eye. A faint glass edge (top highlight + bottom shade)
   gives it a premium, high-tech sheen even between glints. Uses ::before, which is free
   whenever this style is active (Flow — the other ::before user — is mutually exclusive
   with it). */
@keyframes miiraPowerGlint {
    /* Streak starts off the right edge, sweeps across once (fast), then waits off the
       left edge for the rest of the cycle before repeating. The sweep spans 32% of the
       5s cycle (~1.6s) — the movement rate that reads best — leaving a ~3.4s rest. */
    0%        { background-position: 180% 0; }
    32%, 100% { background-position: -80% 0; }
}
@container style(--mui-power-sheen-play: running) {
    .miira-btn--power {
        /* Glassy edge, always at full strength for this style regardless of the global
           "Raised depth" slider (the shadow re-evaluates using this local intensity). */
        --mui-btn-raised: 100;
        box-shadow: var(--mui-btn-raised-shadow);
    }
    .miira-btn--power::before {
        padding: 0;
        -webkit-mask: none;
        mask: none;
        /* A narrow, feathered white band tilted off-vertical — the moving glint. */
        background: linear-gradient(
            105deg,
            transparent 38%,
            rgba(255, 255, 255, 0.25) 47%,
            rgba(255, 255, 255, 0.65) 50%,
            rgba(255, 255, 255, 0.25) 53%,
            transparent 62%
        );
        background-size: 250% 100%;
        background-position: 180% 0;
        background-repeat: no-repeat;
        mix-blend-mode: screen;
        /* Glow (0–100) drives the glint's opacity, so it can be toned right down. */
        opacity: calc(var(--mui-power-glow, 50) / 100);
        /* Fixed 5s cycle (one glint every ~5s) — independent of the shared Orbit speed
           slider, which is tuned for the ring styles. */
        animation: miiraPowerGlint 5s ease-in-out infinite;
    }
}
@media (prefers-reduced-motion: reduce) {
    .miira-btn--power,
    .miira-btn--power::after,
    .miira-btn--power::before { animation: none; }
}

/* ---- Style modifiers (compose with any colour intent) ----
   These set the --btn-s-* tier (see the base rule), which sits ABOVE the colour
   intents' --btn-i-* tier — so a style-class override wins over an intent override
   on the same button, and an unset style override cleanly falls through to the
   intent (its token is declared with no fallback = inert when unset). */

/* Icon-only: square footprint, no label. */
.miira-btn--icon {
    width: var(--mui-btn-icon-size, 36px);
    height: var(--mui-btn-icon-size, 36px);
    min-height: var(--mui-btn-icon-size, 36px);
    padding: 0;
    gap: 0;
    --btn-s-radius: var(--mui-btn-icon-radius);
    --btn-s-bg: var(--mui-btn-icon-bg);
    --btn-s-fg: var(--mui-btn-icon-text);
    --btn-s-bd: var(--mui-btn-icon-border);
    --btn-s-ff: var(--mui-btn-icon-font);
    --btn-s-fs: var(--mui-btn-icon-font-size);
    --btn-s-fw: var(--mui-btn-icon-font-weight);
    --btn-s-tt: var(--mui-btn-icon-transform);
}

/* Pill: compact rounded button, lighter weight — a small button shape (Connect,
   Add, Select all, Back). Radius / font-size / weight route through the style tier
   so the pill geometry composes with any colour intent. (Filter chips are NOT this
   — they are the standalone .miira-filter component below.) */
.miira-btn--pill {
    padding: var(--mui-pill-pad-y, 6px) var(--mui-pill-pad-x, 12px);
    gap: 6px;
    /* Pills stay compact (smaller 14px glyph), not the full button height. */
    min-height: calc(14px + 2 * var(--mui-pill-pad-y, 6px) + 2 * var(--mui-btn-border-width, 1px));
    /* Style-tier overrides (theme builder → "Pill" class). Radius / font-size / weight
       keep the pill defaults; colour / font / transform are opt-in (unset = inherit the
       intent). --mui-btn-pill-* is per-class; --mui-pill-* is the shared pill geometry. */
    --btn-s-radius: var(--mui-btn-pill-radius, var(--mui-pill-radius, 999px));
    --btn-s-fs: var(--mui-btn-pill-font-size, var(--mui-pill-font-size, 12px));
    --btn-s-fw: var(--mui-btn-pill-font-weight, 500);
    --btn-s-bg: var(--mui-btn-pill-bg);
    --btn-s-fg: var(--mui-btn-pill-text);
    --btn-s-bd: var(--mui-btn-pill-border);
    --btn-s-ff: var(--mui-btn-pill-font);
    --btn-s-tt: var(--mui-btn-pill-transform);
}
.miira-btn--pill svg {
    width: 14px;
    height: 14px;
}

/* Full-width helper (forms, mobile rows). */
.miira-btn--block {
    width: 100%;
    --btn-s-radius: var(--mui-btn-block-radius);
    --btn-s-bg: var(--mui-btn-block-bg);
    --btn-s-fg: var(--mui-btn-block-text);
    --btn-s-bd: var(--mui-btn-block-border);
    --btn-s-ff: var(--mui-btn-block-font);
    --btn-s-fs: var(--mui-btn-block-font-size);
    --btn-s-fw: var(--mui-btn-block-font-weight);
    --btn-s-tt: var(--mui-btn-block-transform);
}

/* =============================================================================
   Filter chip — standalone component (NOT a button)
   Used for filter/category toolbars (e.g. the collateral filter row). A compact
   pill that reads its own --mui-filter-* tokens; add .is-active for the selected
   chip. Kept deliberately independent of .miira-btn so filters can be themed on
   their own terms.
   ========================================================================== */
.miira-filter {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    /* Neutralise the global `button {width:100%;max-width:308px;height:36px}`
       rule (styles.css) so a <button class="miira-filter"> is content-sized. */
    width: auto;
    max-width: none;
    height: auto;
    gap: var(--mui-filter-gap, 6px);
    padding: var(--mui-filter-pad-y, 6px) var(--mui-filter-pad-x, 12px);
    min-height: calc(var(--mui-filter-glyph, 14px) + 2 * var(--mui-filter-pad-y, 6px) + 2 * var(--mui-filter-border-width, 1px));
    border: var(--mui-filter-border-width, 1px) solid var(--mui-filter-border, var(--portal-border, #1e2a36));
    border-radius: var(--mui-filter-radius, 999px);
    background: var(--mui-filter-bg, var(--portal-input-bg, rgba(255, 255, 255, 0.025)));
    color: var(--mui-filter-text, var(--portal-text, #ffffff));
    font-family: var(--mui-filter-font, var(--portal-font, 'Inter', sans-serif));
    font-size: var(--mui-filter-font-size, 12px);
    font-weight: var(--mui-filter-font-weight, 500);
    line-height: 1.1;
    white-space: nowrap;
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
    transition:
        background 150ms ease,
        border-color 150ms ease,
        color 150ms ease;
}
.miira-filter svg {
    width: var(--mui-filter-glyph, 14px);
    height: var(--mui-filter-glyph, 14px);
    flex: 0 0 auto;
}
/* Bare <span> labels/counts inside must follow the chip's colour (the global
   `…span { color: var(--portal-text) }` rule in styles.css targets them directly). */
.miira-filter span {
    color: inherit;
}
.miira-filter:hover:not(:disabled):not([aria-disabled="true"]) {
    background: var(--mui-filter-bg-hover, var(--portal-bg-card-hover, #161a24));
    border-color: var(--mui-filter-border-hover, var(--portal-text-dim, #5a6a7a));
}
.miira-filter:disabled,
.miira-filter[aria-disabled="true"] {
    opacity: 0.5;
    cursor: default;
}
.miira-filter:focus-visible {
    outline: 2px solid var(--accent, #6366f1);
    outline-offset: 2px;
}
.miira-filter.is-active {
    background: var(--mui-filter-active-bg, rgba(var(--accent-rgb, 99, 102, 241), 0.12));
    border-color: var(--mui-filter-active-border, rgba(var(--accent-rgb, 99, 102, 241), 0.35));
    color: var(--mui-filter-active-text, var(--accent-text, #a5b4fc));
}

/* =============================================================================
   Panel / card
   ========================================================================== */
.miira-panel {
    background: var(--mui-panel-bg, var(--portal-bg-card, #11141d));
    border: 1px solid var(--mui-panel-border, var(--portal-border, #1e2a36));
    border-radius: var(--mui-panel-radius, 12px);
    padding: var(--mui-panel-pad, 24px);
    box-sizing: border-box;
}
.miira-panel__title {
    margin: 0 0 4px;
    font-family: var(--mui-heading-font, var(--portal-font, sans-serif));
    font-size: var(--mui-heading-size, 16px);
    font-weight: var(--mui-heading-weight, 600);
    text-transform: var(--mui-heading-transform, none);
    letter-spacing: var(--mui-heading-letter-spacing, normal);
    line-height: var(--mui-heading-line-height, 1.25);
    color: var(--portal-text, #ffffff);
}
.miira-panel__desc {
    margin: 0;
    font-size: 13px;
    line-height: 1.5;
    color: var(--portal-text-muted, #7a8a9a);
}

/* =============================================================================
   Form controls
   ========================================================================== */
.miira-field {
    display: block;
    margin-bottom: 14px;
}
.miira-field__label {
    display: block;
    margin-bottom: 6px;
    font-size: 13px;
    color: var(--portal-text-muted, #7a8a9a);
}
.miira-input,
.miira-select,
.miira-textarea {
    width: 100%;
    padding: var(--mui-input-pad-y, 8px) var(--mui-input-pad-x, 10px);
    background: var(--mui-input-bg, var(--portal-bg-surface, #11141d));
    border: 1px solid var(--mui-input-border, var(--portal-border, #1e2a36));
    border-radius: var(--mui-input-radius, 8px);
    color: var(--mui-input-text, var(--portal-text, #ffffff));
    font-family: var(--portal-font, 'Inter', sans-serif);
    font-size: var(--mui-input-font-size, 14px);
    box-sizing: border-box;
}
.miira-textarea {
    min-height: 88px;
    resize: vertical;
}
.miira-input:focus,
.miira-select:focus,
.miira-textarea:focus {
    outline: none;
    border-color: var(--accent, #6366f1);
}
.miira-input::placeholder,
.miira-textarea::placeholder {
    color: var(--portal-text-dim, #5a6a7a);
}
/* Native <select> as a styled control: hide the OS arrow, draw a custom chevron,
   and reserve right padding for it. Matches the portal's bespoke selects
   (.psv2-select / select.portal-input / .connector-settings-select). Box colours,
   radius, padding-Y and font still come from the shared --mui-input-* tokens above. */
.miira-select {
    -webkit-appearance: none;
    appearance: none;
    cursor: pointer;
    padding-right: 34px;
    background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%238a95a5' stroke-width='2.5' 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: right 12px center;
}

/* =============================================================================
   Table
   ========================================================================== */
.miira-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--mui-table-font-size, 13px);
}
.miira-table th,
.miira-table td {
    padding: var(--mui-table-cell-pad-y, 9px) var(--mui-table-cell-pad-x, 12px);
    text-align: left;
    /* Declare cell text colour explicitly — don't rely on inherited body colour
       (a global `.portal-table td`/`button` colour can otherwise win). Body fill +
       text are themable (Theme builder → Tables); the `th` rule below re-overrides
       the header band + muted text on top of these. */
    color: var(--mui-table-body-text, var(--portal-text, #ffffff));
    background: var(--mui-table-body-bg, transparent);
    border-bottom: 1px solid var(--mui-table-divider, var(--portal-border, #1e2a36));
    vertical-align: middle;
}
.miira-table th {
    color: var(--portal-text-muted, #7a8a9a);
    font-weight: 600;
    white-space: nowrap;
    background: var(--mui-table-header-bg);
    /* Header gets its own vertical padding, independent of the body cell pad-y. */
    padding-top: var(--mui-table-header-pad-y, var(--mui-table-cell-pad-y, 9px));
    padding-bottom: var(--mui-table-header-pad-y, var(--mui-table-cell-pad-y, 9px));
}
/* Outer gutter on the first/last columns (header + body), so the leading and
   trailing content sits in from the table's rounded edge. */
.miira-table th:first-child,
.miira-table td:first-child {
    padding-left: var(--mui-table-edge-pad-x, var(--mui-table-cell-pad-x, 12px));
}
.miira-table th:last-child,
.miira-table td:last-child {
    padding-right: var(--mui-table-edge-pad-x, var(--mui-table-cell-pad-x, 12px));
}
.miira-table tbody tr:last-child td {
    border-bottom: none;
}
.miira-table tbody tr:hover td {
    background: var(--mui-table-row-hover, var(--portal-bg-card-hover, #161a24));
}
/* Rounds a .miira-table — a border-collapse <table> can't show its own radius, so the
   corners live on this wrapper. The portal table wrappers (.portal-table-wrap /
   .stock-table-wrap / .psv2-team-table-wrap) read the same --mui-table-radius token. */
.miira-table-wrap {
    background: var(--mui-panel-bg, var(--portal-bg-card, #11141d));
    border: 1px solid var(--mui-panel-border, var(--portal-border, #1e2a36));
    border-radius: var(--mui-table-radius, 12px);
    overflow: hidden;
}

/* =============================================================================
   Card  —  .miira-card  +  __header / __body  (+ optional --hover modifier)
   <div class="miira-card">
       <div class="miira-card__header">
           <div><h3 class="miira-card__title">…</h3><p class="miira-card__desc">…</p></div>
       </div>
       <div class="miira-card__body">…</div>
   </div>
   Add .miira-card--hover for interactive tiles (asset / KPI): lift + shadow.
   ========================================================================== */
.miira-card {
    background: var(--mui-panel-bg, var(--portal-bg-card, #11141d));
    border: var(--mui-card-border-width, 1px) solid var(--mui-card-border, var(--portal-border, #1e2a36));
    border-radius: var(--mui-card-radius, 12px);
    overflow: hidden;
    box-sizing: border-box;
}
.miira-card__header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--mui-card-gap, 16px);
    padding: var(--mui-card-header-pad-y, 18px) var(--mui-card-header-pad-x, 22px);
    border-bottom: 1px solid var(--mui-divider, var(--mui-card-header-border, var(--portal-border, #1e2a36)));
}
.miira-card__title {
    margin: 0 0 4px;
    font-family: var(--mui-heading-font, var(--portal-font, sans-serif));
    font-size: var(--mui-card-title-size, 15px);
    font-weight: var(--mui-heading-weight, 600);
    letter-spacing: -0.01em;
    color: var(--portal-text, #ffffff);
}
.miira-card__desc {
    margin: 0;
    line-height: 1.5;
    font-size: var(--mui-card-desc-size, 12px);
    color: var(--portal-text-muted, #7a8a9a);
}
.miira-card__body {
    padding: var(--mui-card-pad, 24px);
}
/* Interactive card (asset tiles, KPI tiles): lift + shadow + border emphasis. */
.miira-card--hover {
    transition: border-color 0.18s ease, transform 0.18s ease, box-shadow 0.18s ease;
}
.miira-card--hover:hover {
    border-color: var(--mui-card-hover-border, var(--portal-border, #1e2a36));
    transform: translateY(var(--mui-card-hover-lift, -2px));
    box-shadow: var(--mui-card-hover-shadow, 0 8px 22px rgba(0, 0, 0, 0.3));
}

/* =============================================================================
   Switch / toggle  (role="switch" + aria-checked contract)
   <button class="miira-switch" role="switch" aria-checked="true">
       <span class="miira-switch__knob"></span>
   </button>
   ========================================================================== */
.miira-switch {
    position: relative;
    display: inline-block;
    flex: 0 0 auto;
    width: var(--mui-switch-w, 34px);
    height: var(--mui-switch-h, 20px);
    max-width: none;
    margin: 0;
    padding: 0;
    border: 0;
    border-radius: 999px;
    background: var(--mui-switch-off, var(--portal-border, #1e2a36));
    /* Indented track (scales with --mui-switch-raised). */
    box-shadow: var(--mui-switch-indent-shadow);
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
    transition: background var(--mui-btn-transition, 150ms ease), box-shadow 150ms ease;
}
.miira-switch__knob {
    position: absolute;
    top: 2px;
    left: 2px;
    width: var(--mui-switch-knob, 16px);
    height: var(--mui-switch-knob, 16px);
    border-radius: 50%;
    background: #fff;
    /* Raised knob (scales with --mui-switch-raised). */
    box-shadow: var(--mui-switch-knob-shadow);
    transition: left var(--mui-btn-transition, 150ms ease);
    pointer-events: none;
}
.miira-switch[aria-checked="true"] {
    background: var(--mui-switch-on, var(--accent, #6366f1));
}
.miira-switch[aria-checked="true"] .miira-switch__knob {
    left: calc(100% - var(--mui-switch-knob, 16px) - 2px);
}
.miira-switch:focus-visible {
    outline: none;
    box-shadow:
        0 0 0 3px rgba(var(--accent-rgb, 99, 102, 241), 0.35),
        var(--mui-switch-indent-shadow);
}
.miira-switch:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* Settings-style row: label + description on the left, switch on the right. */
.miira-switch-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 12px 0;
    border-bottom: 1px solid var(--mui-divider, var(--portal-border, #1e2a36));
}
.miira-switch-row:last-child { border-bottom: none; }
.miira-switch-row__text { min-width: 0; }
.miira-switch-row__title {
    font-size: 13.5px;
    font-weight: 600;
    color: var(--portal-text, #ffffff);
}
.miira-switch-row__desc {
    font-size: 12px;
    color: var(--portal-text-muted, #7a8a9a);
    margin-top: 2px;
    line-height: 1.4;
}

/* =============================================================================
   Badges / status pills (common table + card decoration)
   ========================================================================== */
.miira-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 600;
    border: 1px solid transparent;
}
.miira-badge .dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
}
.miira-badge--success {
    background: rgba(34, 197, 94, 0.12);
    color: var(--portal-accent-green, #22c55e);
}
.miira-badge--warn {
    background: rgba(245, 158, 11, 0.12);
    color: var(--portal-accent-amber, #f59e0b);
}
.miira-badge--danger {
    background: rgba(239, 68, 68, 0.12);
    color: var(--portal-accent-red, #ef4444);
}
.miira-badge--neutral {
    background: transparent;
    color: var(--portal-text-muted, #7a8a9a);
    border-color: var(--portal-border, #1e2a36);
}
.miira-badge--accent {
    background: rgba(var(--accent-rgb, 99, 102, 241), 0.15);
    color: var(--accent, #6366f1);
}
