/* Matrix MLM Pro - Dashboard Styles */

.matrix-dashboard {
    display: grid;
    grid-template-columns: 260px 1fr;
    min-height: 80vh;
    background: var(--matrix-light);
    border-radius: 12px;
    overflow: hidden;
    box-shadow: var(--matrix-shadow);
    margin: 20px 0;
}

/* Sidebar */
.matrix-dashboard-sidebar {
    background: var(--matrix-dark);
    padding: 24px 0;
    overflow-y: auto;
}

.matrix-user-info {
    text-align: center;
    padding: 0 20px 20px;
    border-bottom: 1px solid rgba(255,255,255,0.1);
    margin-bottom: 16px;
}

.matrix-user-info .matrix-avatar img {
    border-radius: 50%;
    border: 3px solid var(--matrix-primary);
}

.matrix-user-info h4 {
    color: #fff;
    margin: 10px 0 4px;
    font-size: 16px;
}

.matrix-user-info .matrix-balance {
    color: var(--matrix-success);
    font-size: 20px;
    font-weight: 700;
    margin: 0;
}

.matrix-dashboard-nav {
    display: flex;
    flex-direction: column;
}

.matrix-dashboard-nav a {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 11px 24px;
    color: #d1d5db;
    text-decoration: none;
    font-size: 13px;
    transition: all 0.2s;
    border-left: 3px solid transparent;
}

.matrix-dashboard-nav a:hover {
    background: rgba(255,255,255,0.05);
    color: #fff;
}

.matrix-dashboard-nav a.active {
    background: rgba(79, 70, 229, 0.2);
    color: #fff;
    border-left-color: var(--matrix-primary);
}

.matrix-dashboard-nav a .dashicons {
    /* font-family is set with !important because some themes ship
       a `nav a span { font-family: inherit !important }` (or
       similarly worded) reset that wins on the cascade and stops
       the WP core dashicons font from resolving. Symptom: every
       sidebar icon renders as an empty 16x16 box (the dashicons
       span keeps its layout box, but the glyph code points fall
       back to the theme body font, which has nothing mapped at
       those Private Use Area positions). The genealogy toolbar's
       dashicons keep working in that scenario because they're
       not inside <nav> — only the sidebar is hit. Locking the
       font-family here makes the rendering theme-independent.
       Reported on a fresh production deploy onto a new theme
       after PR #334 enqueued dashicons globally. */
    font-family: dashicons !important;
    font-size: 16px;
    width: 16px;
    height: 16px;
    line-height: 1;
}

.matrix-nav-logout {
    margin-top: 16px;
    border-top: 1px solid rgba(255,255,255,0.1);
    padding-top: 16px !important;
}

/* Dashboard Content */
.matrix-dashboard-content {
    padding: 30px;
    overflow-y: auto;
}

.matrix-dashboard-content h2 {
    font-size: 22px;
    color: var(--matrix-dark);
    margin: 0 0 20px;
}

.matrix-dashboard-content h3 {
    font-size: 16px;
    color: var(--matrix-dark);
    margin: 24px 0 12px;
}

/* Stats Grid */
.matrix-stats-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 16px;
    margin-bottom: 24px;
}

.matrix-stat-card {
    background: #fff;
    border-radius: 10px;
    padding: 20px;
    border: 1px solid var(--matrix-border);
    transition: transform 0.2s;
}

.matrix-stat-card:hover {
    transform: translateY(-2px);
}

.matrix-stat-card .stat-value {
    font-size: 24px;
    font-weight: 700;
    margin-bottom: 4px;
}

.matrix-stat-card .stat-label {
    font-size: 13px;
    color: #6b7280;
}

.matrix-stat-card.primary .stat-value { color: var(--matrix-primary); }
.matrix-stat-card.success .stat-value { color: var(--matrix-success); }
.matrix-stat-card.warning .stat-value { color: var(--matrix-warning); }
.matrix-stat-card.danger .stat-value { color: var(--matrix-danger); }
.matrix-stat-card.info .stat-value { color: var(--matrix-info); }
.matrix-stat-card.purple .stat-value { color: var(--matrix-secondary); }

/* Security Section */
.matrix-security-section {
    background: #fff;
    border: 1px solid var(--matrix-border);
    border-radius: 8px;
    padding: 24px;
}

.matrix-2fa-status {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 16px 0;
    flex-wrap: wrap;
}

/* M2: inline reauth form for 2FA enable/disable/regen. */
.matrix-2fa-form {
    margin-top: 16px;
    padding: 20px;
    border: 1px solid var(--matrix-border, #e5e7eb);
    border-radius: 8px;
    background: var(--matrix-bg-soft, #f9fafb);
    max-width: 480px;
}

.matrix-2fa-form .matrix-form-row {
    margin-bottom: 14px;
}

.matrix-2fa-form .matrix-form-row label {
    display: block;
    font-weight: 600;
    margin-bottom: 6px;
    font-size: 14px;
}

.matrix-2fa-form .matrix-form-row input[type="password"],
.matrix-2fa-form .matrix-form-row input[type="text"] {
    width: 100%;
    padding: 10px 12px;
    border: 1px solid var(--matrix-border, #d1d5db);
    border-radius: 6px;
    font-size: 14px;
}

.matrix-2fa-form .matrix-form-actions {
    display: flex;
    gap: 8px;
    margin-top: 4px;
}

.matrix-2fa-help {
    color: var(--matrix-text-soft, #6b7280);
    font-size: 13px;
    margin: 0 0 12px;
}

.matrix-2fa-recovery-status {
    margin: 12px 0;
    padding: 10px 14px;
    border-left: 3px solid var(--matrix-warning, #f59e0b);
    background: rgba(245, 158, 11, 0.08);
    font-size: 14px;
}

.matrix-2fa-recovery-block {
    margin-top: 24px;
    padding: 16px 20px;
    border: 1px dashed var(--matrix-border, #d1d5db);
    border-radius: 8px;
    background: #fff;
}

.matrix-2fa-codes {
    list-style: none;
    padding: 0;
    margin: 12px 0;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px 16px;
}

.matrix-2fa-codes li code {
    display: inline-block;
    padding: 6px 10px;
    background: #f3f4f6;
    border-radius: 4px;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 14px;
    letter-spacing: 0.5px;
    user-select: all;
}

/* Plans in dashboard */
.matrix-plan-card.active {
    border-color: var(--matrix-success);
    border-width: 2px;
}

.matrix-plan-card .plan-matrix {
    font-size: 28px;
    font-weight: 700;
    color: var(--matrix-primary);
    margin: 8px 0;
}

.matrix-plan-card .plan-details p {
    margin: 4px 0;
    font-size: 13px;
    color: #6b7280;
}

/* Responsive */
@media (max-width: 900px) {
    .matrix-dashboard {
        grid-template-columns: 1fr;
    }
    .matrix-dashboard-sidebar {
        padding: 16px;
    }
    .matrix-dashboard-nav {
        flex-direction: row;
        flex-wrap: wrap;
        gap: 4px;
    }
    .matrix-dashboard-nav a {
        padding: 8px 12px;
        font-size: 12px;
        border-left: none;
        border-radius: 6px;
    }
    .matrix-dashboard-nav a.active {
        background: var(--matrix-primary);
        border-left-color: transparent;
    }
    .matrix-dashboard-content {
        padding: 20px;
    }
    .matrix-stats-grid {
        grid-template-columns: 1fr 1fr;
    }
}

@media (max-width: 480px) {
    .matrix-stats-grid {
        grid-template-columns: 1fr;
    }
}


/* Genealogy Tree Styles */
.matrix-genealogy-plan-selector {
    margin-bottom: 20px;
    display: flex;
    align-items: center;
    gap: 10px;
}

.matrix-genealogy-plan-selector label {
    font-weight: 600;
    color: var(--matrix-dark);
}

.matrix-genealogy-plan-selector select {
    padding: 8px 12px;
    border: 1px solid var(--matrix-border);
    border-radius: 6px;
    font-size: 14px;
}

.matrix-genealogy-wrapper {
    /*
     * Mirrors the public share page's tree wrapper
     * (.mma-share-tree-wrapper) so the classic dashboard view
     * and a prospect's share link look like the same product:
     * a panel with a thin border and rounded corners, the tree
     * centred inside, scrollable horizontally only when the
     * tree itself is wider than the panel.
     */
    background: #fff;
    border: 1px solid var(--matrix-border);
    border-radius: 10px;
    box-shadow: 0 1px 2px rgba(0,0,0,0.03);
    overflow-x: auto;
    padding: 18px;
    margin-bottom: 20px;
}

.matrix-genealogy-tree {
    display: flex;
    justify-content: center;
    min-width: fit-content;
}

/* Tree Item */
.matrix-tree-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    position: relative;
    padding: 0 6px;
}

/* Tree Node
 *
 * Sized to match the public share page's .mma-share-node so the
 * two surfaces look consistent. Slightly thinner border (1.5px)
 * and tighter padding than the previous dashboard-only style;
 * the avatar + info layout is preserved because the dashboard's
 * classic view is interactive in ways the share page is not.
 */
.matrix-tree-node {
    display: flex;
    align-items: center;
    gap: 10px;
    background: #fff;
    border: 2px solid #e2e8f0;
    border-radius: 8px;
    padding: 8px 12px;
    min-width: 160px;
    transition: all 0.2s;
    cursor: default;
    box-shadow: 0 1px 3px rgba(0,0,0,0.04);
}

.matrix-tree-node:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}

.matrix-tree-node-you {
    border-color: var(--matrix-primary);
    background: linear-gradient(135deg, #eef2ff, #e0e7ff);
}

/*
 * Direct referral: tree owner personally sponsored this member.
 * Keeps the green "active" look the previous undifferentiated state
 * used, so the visual change is opt-in — existing members who only
 * have direct referrals see no regression. The legend dot below
 * still points at the same colour for continuity.
 */
.matrix-tree-node-direct {
    border-color: var(--matrix-success);
    background: #f0fdf4;
}

/*
 * Spillover: the member sits in the tree owner's downline because
 * they were placed there structurally (the spillover BFS placement
 * in the importer / plan engine), but a different upline member is
 * their actual sponsor. Amber border + tinted fill makes the
 * distinction obvious at a glance without screaming "warning" — red
 * would feel punitive for what is in fact a positive event for the
 * tree owner (a downline member is filling out their matrix).
 */
.matrix-tree-node-spillover {
    border-color: #f59e0b;
    background: #fffbeb;
}

/*
 * Username row: needs to be flex so the relationship pill sits
 * inline with the name without wrapping or overflowing on long
 * usernames. min-width:0 on the strong allows the username to
 * truncate (via the existing line-height rule) before the badge
 * is pushed out of frame.
 */
.tree-node-name-row {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
}

.tree-node-name-row strong {
    min-width: 0;
}

/*
 * Relationship pill rendered next to the username on every non-root
 * node. Compact (10px font, 1px/6px padding) so it doesn't push the
 * card layout around — the existing tree-node-info block is sized
 * for a single-line username + meta.
 */
.tree-node-badge {
    display: inline-block;
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.4px;
    padding: 1px 6px;
    border-radius: 4px;
    line-height: 1.5;
    white-space: nowrap;
}

.tree-node-badge-direct {
    background: #d1fae5;
    color: #047857;
}

.tree-node-badge-spillover {
    background: #fef3c7;
    color: #92400e;
}

/*
 * "Viewing" badge variant — only appears on a pivoted view's root
 * card to flag that this isn't the actual viewer's home tree. Uses
 * the indigo palette to coordinate with the .matrix-tree-node-you
 * card styling that always wraps the tree's root, so the colour
 * cues stay consistent regardless of whether the root is the
 * viewer themselves or a pivoted member.
 */
.tree-node-badge-viewing {
    background: #e0e7ff;
    color: #4338ca;
}

/*
 * Username pivot link.
 *
 * Clicking any non-root, non-empty member's username re-roots the
 * tree on them via ?pivot_user_id=X. Style is intentionally subtle:
 * the username should still read as a username, with the link
 * affordance only emerging on hover / focus. Underline-on-hover is
 * conventional enough that members understand it as "you can click
 * this" without a louder cue. Keyboard focus picks up the same
 * underline plus the standard outline so tab nav stays legible.
 *
 * Inherits color so the badge classes (direct/spillover) on the
 * surrounding node still drive the username's tone.
 */
.tree-node-pivot-link {
    color: inherit;
    text-decoration: none;
    border-bottom: 1px dashed transparent;
    transition: border-color 0.15s ease, color 0.15s ease;
}

.tree-node-pivot-link:hover,
.tree-node-pivot-link:focus {
    border-bottom-color: currentColor;
    color: var(--matrix-primary);
    text-decoration: none;
}

.matrix-tree-node-empty {
    border-color: #e5e7eb;
    border-style: dashed;
    background: #f9fafb;
    opacity: 0.7;
}

.tree-node-avatar img {
    border-radius: 50%;
    width: 36px;
    height: 36px;
}

.tree-node-empty-avatar {
    width: 36px;
    height: 36px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #f3f4f6;
    border-radius: 50%;
    color: #9ca3af;
}

.tree-node-empty-avatar .dashicons {
    font-size: 18px;
    width: 18px;
    height: 18px;
}

.tree-node-info {
    display: flex;
    flex-direction: column;
}

.tree-node-info strong {
    font-size: 13px;
    color: var(--matrix-dark);
    line-height: 1.3;
}

.tree-node-info small {
    font-size: 11px;
    color: #6b7280;
}

/* Tree Children / Lines
 *
 * Connector styling deliberately mirrors the public share page
 * (.mma-share-* in includes/class-matrix-share.php) so the
 * dashboard's classic view and a prospect-facing share link
 * look like the same product. The two surfaces should converge
 * visually — the only differences are the cards (the dashboard
 * keeps avatars + interactive pivot links, the public page is
 * read-only), not the connector geometry.
 *
 * Geometry: a thin 1px slate-300 line drops from the parent
 * card's bottom edge (::before on .matrix-tree-children), then
 * each child reaches up with its own 1px riser (::before on
 * the child .matrix-tree-item) and joins a horizontal sibling
 * bar (::after on the child). The first child's sibling bar is
 * trimmed back to start at 50%, the last child's is trimmed to
 * end at 50%, so the bar only ever spans between the children
 * — giving the centred-T look the share page uses, instead of
 * the previous over-extended T-bar.
 *
 * For a single child we still get a clean straight drop because
 * the sibling bar is collapsed away by the :only-child rule
 * below.
 */
.matrix-tree-children {
    display: flex;
    gap: 12px;
    padding-top: 24px;
    margin-top: 0;
    position: relative;
    justify-content: center;
}

/* Vertical drop line FROM the parent card down into the
 * children block. Anchored to the top of .matrix-tree-children
 * so it visually emerges from underneath the parent node.
 */
.matrix-tree-children::before {
    content: '';
    position: absolute;
    top: 0;
    left: 50%;
    width: 1px;
    height: 12px;
    background: #cbd5e1;
    transform: translateX(-50%);
}

.matrix-tree-children > .matrix-tree-item {
    position: relative;
    padding-top: 12px;
}

/* Each child's vertical riser, joining the horizontal sibling
 * bar to the child's card. Same colour + 1px weight as the
 * parent drop so the network reads as one continuous line.
 */
.matrix-tree-children > .matrix-tree-item::before {
    content: '';
    position: absolute;
    top: 0;
    left: 50%;
    width: 1px;
    height: 12px;
    background: #cbd5e1;
    transform: translateX(-50%);
}

/* Horizontal sibling bar segment that ties this child to its
 * neighbours. Each .matrix-tree-item draws the segment for its
 * own half of the bar; first/last children trim the outer half
 * so the bar only spans between children rather than poking out
 * past the leftmost/rightmost card.
 */
.matrix-tree-children > .matrix-tree-item:not(:only-child)::after {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 1px;
    background: #cbd5e1;
}

.matrix-tree-children > .matrix-tree-item:first-child:not(:only-child)::after {
    left: 50%;
}

.matrix-tree-children > .matrix-tree-item:last-child:not(:only-child)::after {
    right: 50%;
}

/* Single child: no horizontal bar — just the straight drop
 * (parent ::before) + the child's riser (item ::before). The
 * :has() rule kept the previous behaviour for browsers that
 * support it; the :only-child gate above does the same job
 * universally.
 */
.matrix-tree-children:has(> .matrix-tree-item:only-child)::after {
    display: none;
}

/* Legend */
.matrix-genealogy-legend {
    display: flex;
    gap: 20px;
    justify-content: center;
    padding: 16px;
    background: #f8fafc;
    border-radius: 8px;
    border: 1px solid var(--matrix-border);
}

.legend-item {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 13px;
    color: #4b5563;
}

.legend-dot {
    width: 12px;
    height: 12px;
    border-radius: 50%;
    display: inline-block;
}

.legend-you {
    background: var(--matrix-primary);
}

.legend-direct {
    background: var(--matrix-success);
}

.legend-spillover {
    background: #f59e0b;
}

.legend-empty {
    background: #e5e7eb;
    border: 1px dashed #9ca3af;
}

/*
 * Pivot breadcrumb bar.
 *
 * Sits above the genealogy stats panel on pivoted views. Two halves
 * inside one container: a "Back to my tree" affordance on the left
 * (always visible when pivoted) and a horizontal trail of crumbs on
 * the right showing You › Member1 › … › Pivot. The trail wraps
 * naturally on narrow viewports — see the mobile media query below
 * for the responsive collapse behaviour.
 *
 * Styling is intentionally chrome-like (light surface, muted text)
 * so the bar reads as navigation rather than competing with the tree
 * for attention. The "Back" button picks up the dashboard's primary
 * indigo because exiting the pivoted view is the most-likely follow-
 * up action and we want it to feel like the obvious primary control
 * even though it's left-aligned.
 */
.matrix-genealogy-pivot-bar {
    display: flex;
    align-items: center;
    gap: 16px;
    flex-wrap: wrap;
    background: #f8fafc;
    border: 1px solid var(--matrix-border);
    border-radius: 8px;
    padding: 10px 14px;
    margin-bottom: 16px;
    font-size: 13px;
}

.matrix-genealogy-pivot-back {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    background: var(--matrix-primary);
    color: #fff;
    text-decoration: none;
    border-radius: 6px;
    padding: 6px 12px;
    font-weight: 600;
    transition: background 0.15s ease;
    white-space: nowrap;
}

.matrix-genealogy-pivot-back:hover,
.matrix-genealogy-pivot-back:focus {
    background: #4338ca;
    color: #fff;
    text-decoration: none;
}

.matrix-genealogy-pivot-back .dashicons {
    font-size: 16px;
    width: 16px;
    height: 16px;
}

.matrix-genealogy-pivot-trail {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 4px;
    color: #6b7280;
    /* Lift the trail visually away from the back button so they
     * don't collide on wide screens. flex-wrap above already lets
     * the trail drop to a new row when space is tight. */
    flex: 1 1 auto;
}

.matrix-genealogy-pivot-crumb {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

.matrix-genealogy-pivot-crumb a {
    color: var(--matrix-primary);
    text-decoration: none;
    padding: 2px 6px;
    border-radius: 4px;
    transition: background 0.15s ease;
}

.matrix-genealogy-pivot-crumb a:hover,
.matrix-genealogy-pivot-crumb a:focus {
    background: #eef2ff;
    text-decoration: none;
}

/*
 * Current crumb: the pivoted member themselves. Rendered as plain
 * text (the matching <li> drops its <a> wrapper) so members can't
 * waste a click "going to" the page they're already on.
 */
.matrix-genealogy-pivot-crumb.is-current span {
    color: var(--matrix-dark);
    font-weight: 600;
    padding: 2px 6px;
}

.matrix-genealogy-pivot-sep {
    color: #d1d5db;
    margin: 0 2px;
    user-select: none;
}

/*
 * "Show more" expand affordance.
 *
 * Rendered in place of a .matrix-tree-children block at the bottom
 * edge of the server-rendered tree (initially level 4, but gets
 * pushed deeper as members click to expand). Visually consistent
 * with the empty-slot placeholders — dashed border, muted palette —
 * so it reads as "there is structure below this, you can pull it
 * in" rather than as a primary action button.
 *
 * Sits on its own row under the parent node via the desktop tree's
 * existing flex column layout. The connector line continues from
 * the parent down into the button's box because we leave the
 * preceding ::before pseudo on .matrix-tree-children intact when
 * the button is in its place — small visual lie that keeps the
 * tree's spine continuous even though the children haven't loaded
 * yet.
 */
.matrix-tree-expand {
    margin-top: 12px;
    display: flex;
    justify-content: center;
}

.matrix-tree-expand-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: #fff;
    color: var(--matrix-primary);
    border: 1px dashed #c7d2fe;
    border-radius: 999px;
    padding: 6px 14px;
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.15s ease;
    white-space: nowrap;
}

.matrix-tree-expand-btn:hover:not(:disabled) {
    background: var(--matrix-primary);
    color: #fff;
    border-color: var(--matrix-primary);
    border-style: solid;
}

.matrix-tree-expand-btn:disabled {
    opacity: 0.7;
    cursor: wait;
}

.matrix-tree-expand-btn .dashicons {
    font-size: 16px;
    width: 16px;
    height: 16px;
}

/*
 * Spinner used during the lazy-load fetch. Reuses the existing
 * dashicons-update glyph (curved arrow). The infinite rotate
 * keyframe is plain CSS so it works without bringing in an animation
 * library — every browser the rest of the dashboard targets supports
 * @keyframes natively. Animation is paused for users who've opted
 * out of motion at the OS level.
 */
.matrix-tree-spin {
    animation: matrix-tree-spin 1s linear infinite;
}

@keyframes matrix-tree-spin {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
    .matrix-tree-spin {
        animation: none;
    }
}

/* Responsive tree */
@media (max-width: 768px) {
    .matrix-tree-node {
        min-width: 130px;
        padding: 8px 10px;
    }

    .matrix-tree-children {
        gap: 8px;
    }

    .tree-node-info strong {
        font-size: 11px;
    }

    .tree-node-info small {
        font-size: 10px;
    }

    .matrix-genealogy-legend {
        flex-wrap: wrap;
        gap: 12px;
    }

    /*
     * Mobile layout switch: indented vertical tree.
     *
     * The desktop layout renders children horizontally (.matrix-tree-children
     * is a flex row) with horizontal/vertical connector pseudo-elements
     * fanning out from each parent. That works fine for 3-wide x 4-deep
     * trees on a 1200px screen, but on a 360–414px phone every child
     * past the first overflows horizontally — past two levels deep the
     * rightmost branches scroll off-screen entirely and the connector
     * lines stop matching up because the container can't absorb the
     * width.
     *
     * The mobile fix below repaints the same DOM as a vertical indented
     * tree: each .matrix-tree-children block stacks its children top-to-
     * bottom, anchored to a single vertical guide on the left edge, and
     * each child renders a short horizontal stub from the guide into the
     * node card. Same look-and-feel as a file explorer or a code editor's
     * outline panel.
     *
     * Approach: override the desktop connector pseudo-elements rather
     * than fighting them. The desktop ::before (vertical drop from parent
     * to child band) and ::after (horizontal band across all children) are
     * suppressed; in their place .matrix-tree-children gets a left border
     * acting as the trunk, and each .matrix-tree-item gets a single ::before
     * stub that connects its node to the trunk.
     *
     * Nodes go full-width (no min-width override) so the username, badge
     * and meta line don't truncate in the narrow column.
     */
    .matrix-tree-children {
        flex-direction: column;
        gap: 6px;
        padding-top: 6px;
        padding-left: 22px;
        margin-left: 18px;
        position: relative;

        /* Vertical trunk down the left edge, replacing the desktop's
         * horizontal connector band. Stops short of the bottom by a
         * few pixels so the last child's stub doesn't continue past
         * its own node — visually matches a tree's bottom branch. */
        border-left: 2px solid var(--matrix-border);
    }

    /* Suppress the desktop tee-down ::before and the horizontal
     * cross-bar ::after — they're position:absolute relative to a
     * row layout that no longer exists in column mode. */
    .matrix-tree-children::before,
    .matrix-tree-children::after {
        display: none;
    }

    .matrix-tree-children > .matrix-tree-item {
        padding-top: 0;
        position: relative;
    }

    /* Replace the desktop down-pointing connector with a left-pointing
     * stub from the trunk into each child node. The 18px width matches
     * the parent's 22px padding-left minus a 4px gap so the stub looks
     * "attached" to the node card without touching it. */
    .matrix-tree-children > .matrix-tree-item::before {
        content: '';
        position: absolute;
        top: 22px;             /* aligns with the avatar's vertical centre */
        left: -22px;
        width: 18px;
        height: 2px;
        background: var(--matrix-border);
        transform: none;       /* desktop centred via translateX, undo */
    }

    /*
     * Make the node card stretch across the column. The desktop
     * .matrix-tree-node is sized for inline-level nesting; in column
     * mode the natural sizing still leaves an awkward right gutter.
     * width:100% inside .matrix-tree-item gives a clean indent grid.
     */
    .matrix-tree-item {
        width: 100%;
    }

    .matrix-tree-node {
        width: 100%;
        min-width: 0;
    }

    /* Top-level "You" node still centres on desktop via the wrapper —
     * in column mode it should align flush-left with the rest of the
     * tree so the indent ladder reads correctly. */
    .matrix-genealogy-tree > .matrix-tree-item {
        width: 100%;
    }
    .matrix-genealogy-tree > .matrix-tree-item > .matrix-tree-node {
        width: auto;
        max-width: 100%;
    }
}


/* ---------------------------------------------------------------------
 * Genealogy Branch Heat-Map
 * ---------------------------------------------------------------------
 *
 * The heat-map feature adds a top-of-tree Structure ↔ Activity toggle
 * with three sub-metrics (total downline, recent commissions, active
 * member ratio). Every visible node is pre-baked with three
 * data-heat-* buckets and three data-pill-* labels at server-render
 * time, and the toggle is a pure DOM-state flip:
 *
 *   - .heatmap-active on #genealogy-tree turns tints on
 *   - data-active-metric on #genealogy-tree picks WHICH metric's
 *     buckets paint the cards
 *   - .tree-node-heat-pill text is rewritten in JS from the matching
 *     data-pill-{metric} attribute
 *
 * The CSS below is written to coexist with the existing
 * direct/spillover/you styling: heat tints only apply when
 * .heatmap-active is on, and the selectors include both #genealogy-tree
 * and a metric attribute, giving them strictly higher specificity than
 * any single-class .matrix-tree-node-{direct,spillover,you} selector.
 * That lets a member flip back to Structure mode and instantly see the
 * familiar direct/spillover palette again — no specificity wars, no
 * !important hacks.
 *
 * Empty-slot cards intentionally never get heat data attrs (see
 * compute_heat_data() — the empty slot has no member to score) so the
 * dashed-border placeholder look survives both modes unchanged.
 */

/*
 * Mode toggle bar.
 *
 * Sits between the level-badges panel and the tree wrapper. Two halves
 * share the bar: the segmented Structure/Activity pair on the left and
 * the metric picker on the right (which appears only when Activity is
 * on, via the [hidden] attribute). flex-wrap lets the picker drop to a
 * second row on narrow viewports without crushing the segmented buttons.
 */
.matrix-genealogy-mode-toggle {
    display: flex;
    align-items: center;
    gap: 16px;
    flex-wrap: wrap;
    margin-bottom: 16px;
    padding: 10px 14px;
    background: #f8fafc;
    border: 1px solid var(--matrix-border);
    border-radius: 8px;
    font-size: 13px;
}

.genealogy-mode-segmented {
    display: inline-flex;
    border: 1px solid var(--matrix-border);
    border-radius: 8px;
    overflow: hidden;
    background: #fff;
}

.genealogy-mode-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 7px 14px;
    background: transparent;
    border: 0;
    border-right: 1px solid var(--matrix-border);
    color: #4b5563;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
}

.genealogy-mode-btn:last-child {
    border-right: 0;
}

.genealogy-mode-btn:hover:not(.is-active) {
    background: #eef2ff;
    color: var(--matrix-primary);
}

.genealogy-mode-btn:focus-visible {
    outline: 2px solid var(--matrix-primary);
    outline-offset: -2px;
}

.genealogy-mode-btn.is-active {
    background: var(--matrix-primary);
    color: #fff;
    cursor: default;
}

.genealogy-mode-btn .dashicons {
    font-size: 16px;
    width: 16px;
    height: 16px;
}

.genealogy-mode-metric-picker {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    color: #4b5563;
}

.genealogy-mode-metric-picker[hidden] {
    display: none;
}

.genealogy-mode-metric-picker label {
    font-weight: 600;
    color: var(--matrix-dark);
}

.genealogy-heat-metric-select {
    padding: 6px 10px;
    border: 1px solid var(--matrix-border);
    border-radius: 6px;
    background: #fff;
    font-size: 13px;
    cursor: pointer;
}

.genealogy-heat-metric-select:focus {
    outline: 2px solid var(--matrix-primary);
    outline-offset: 1px;
}

/*
 * Heat-tint overrides.
 *
 * Each metric × bucket pairing gets a single rule. Specificity:
 *   #id.class[attr] descendant .class[attr]  →  (1, 4, 0)
 * which beats the existing single-class .matrix-tree-node-direct (0,1,0).
 * No !important needed.
 *
 * Border colour is deliberately stronger than the tinted background so
 * the direct/spillover identity clue isn't lost — members can still
 * tell whether a hot branch is a direct referral or spillover by the
 * border's saturation, even though the fill is now driven by the heat
 * metric.
 *
 * 'cold' is rendered as a neutral grey so a metric with no signal
 * (e.g. a member with no commissions in the last 30 days) reads as
 * "no data" rather than as a problem branch.
 */
.matrix-genealogy-tree.heatmap-active .matrix-tree-node {
    transition: background 0.25s ease, border-color 0.25s ease;
}

/* Downline metric tints */
.matrix-genealogy-tree.heatmap-active[data-active-metric="downline"] .matrix-tree-node[data-heat-downline="green"] {
    background: #dcfce7;
    border-color: #16a34a;
}
.matrix-genealogy-tree.heatmap-active[data-active-metric="downline"] .matrix-tree-node[data-heat-downline="yellow"] {
    background: #fef9c3;
    border-color: #eab308;
}
.matrix-genealogy-tree.heatmap-active[data-active-metric="downline"] .matrix-tree-node[data-heat-downline="red"] {
    background: #fee2e2;
    border-color: #dc2626;
}
.matrix-genealogy-tree.heatmap-active[data-active-metric="downline"] .matrix-tree-node[data-heat-downline="cold"] {
    background: #f3f4f6;
    border-color: #d1d5db;
}

/* Commission metric tints */
.matrix-genealogy-tree.heatmap-active[data-active-metric="commission"] .matrix-tree-node[data-heat-commission="green"] {
    background: #dcfce7;
    border-color: #16a34a;
}
.matrix-genealogy-tree.heatmap-active[data-active-metric="commission"] .matrix-tree-node[data-heat-commission="yellow"] {
    background: #fef9c3;
    border-color: #eab308;
}
.matrix-genealogy-tree.heatmap-active[data-active-metric="commission"] .matrix-tree-node[data-heat-commission="red"] {
    background: #fee2e2;
    border-color: #dc2626;
}
.matrix-genealogy-tree.heatmap-active[data-active-metric="commission"] .matrix-tree-node[data-heat-commission="cold"] {
    background: #f3f4f6;
    border-color: #d1d5db;
}

/* Active-ratio metric tints */
.matrix-genealogy-tree.heatmap-active[data-active-metric="active"] .matrix-tree-node[data-heat-active="green"] {
    background: #dcfce7;
    border-color: #16a34a;
}
.matrix-genealogy-tree.heatmap-active[data-active-metric="active"] .matrix-tree-node[data-heat-active="yellow"] {
    background: #fef9c3;
    border-color: #eab308;
}
.matrix-genealogy-tree.heatmap-active[data-active-metric="active"] .matrix-tree-node[data-heat-active="red"] {
    background: #fee2e2;
    border-color: #dc2626;
}
.matrix-genealogy-tree.heatmap-active[data-active-metric="active"] .matrix-tree-node[data-heat-active="cold"] {
    background: #f3f4f6;
    border-color: #d1d5db;
}

/*
 * The display root ("you" / "viewing" card) is intentionally NOT
 * heat-tinted — compute_heat_data() skips it and the renderer doesn't
 * emit data-heat-* on it. But the existing .matrix-tree-node-you
 * gradient already coexists with these heat selectors because
 * data-heat-* matches always fail on the root. Documented here as the
 * intended invariant in case a future change ever considers tinting
 * the root.
 */

/* Empty slots: explicit no-op so a future contributor can't be tempted
 * to add data-heat-* attrs to empty slots and inadvertently start
 * tinting them. */
.matrix-genealogy-tree.heatmap-active .matrix-tree-node-empty {
    background: #f9fafb;
    border-color: #e5e7eb;
}

/*
 * Heat pill — small label inline in the node info, showing the metric's
 * value (e.g. "12", "₦1,200", "85%"). Hidden by default; shown only
 * when the wrapper is in heatmap-active mode AND the pill itself isn't
 * marked [hidden] by JS (which it does when the active metric's label
 * is empty for that node).
 */
.tree-node-heat-pill {
    display: none;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.3px;
    padding: 1px 6px;
    margin-top: 2px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.85);
    color: var(--matrix-dark);
    border: 1px solid rgba(0, 0, 0, 0.08);
    width: max-content;
    max-width: 100%;
    line-height: 1.4;
}

.matrix-genealogy-tree.heatmap-active .tree-node-heat-pill:not([hidden]) {
    display: inline-block;
}

/*
 * Legend variants.
 *
 * Two .matrix-genealogy-legend blocks live inside the
 * .matrix-genealogy-legends parent. The parent's data-mode flips
 * between "structure" and "activity"; the matching legend stays
 * visible, the other hides. Inside the heat legend, three
 * .legend-heat-title-{metric} spans sit on top of each other and the
 * parent's data-metric attribute decides which one is shown — that
 * way the legend headline stays in sync with the metric picker
 * (e.g. "Heat by total downline:" vs "Heat by commissions earned…")
 * without needing additional JS rewriting.
 */
.matrix-genealogy-legends[data-mode="structure"] .matrix-genealogy-legend-heat,
.matrix-genealogy-legends[data-mode="activity"] .matrix-genealogy-legend-structure {
    display: none;
}

.matrix-genealogy-legend-heat {
    display: flex;
    gap: 16px;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    padding: 16px;
    background: #f8fafc;
    border-radius: 8px;
    border: 1px solid var(--matrix-border);
}

.legend-heat-title {
    font-weight: 600;
    color: var(--matrix-dark);
    margin-right: 4px;
}

.legend-heat-title > span {
    display: none;
}

.matrix-genealogy-legends[data-metric="downline"]   .legend-heat-title-downline,
.matrix-genealogy-legends[data-metric="commission"] .legend-heat-title-commission,
.matrix-genealogy-legends[data-metric="active"]     .legend-heat-title-active {
    display: inline;
}

.legend-heat-green {
    background: #dcfce7;
    border: 1px solid #16a34a;
}

.legend-heat-yellow {
    background: #fef9c3;
    border: 1px solid #eab308;
}

.legend-heat-red {
    background: #fee2e2;
    border: 1px solid #dc2626;
}

.legend-heat-cold {
    background: #f3f4f6;
    border: 1px solid #d1d5db;
}

/*
 * Reduced-motion: skip the background/border transition when a member
 * has opted out of motion at the OS level. Matches the existing
 * @media (prefers-reduced-motion) block higher up in this file that
 * already pauses the tree spinner.
 */
@media (prefers-reduced-motion: reduce) {
    .matrix-genealogy-tree.heatmap-active .matrix-tree-node {
        transition: none;
    }
}

/*
 * Mobile responsive: stack the toggle's two halves vertically on
 * narrow viewports so the picker doesn't squeeze the segmented
 * buttons off-screen on a 360px phone. Same flex-direction switch
 * the pivot bar uses elsewhere in this file.
 */
@media (max-width: 640px) {
    .matrix-genealogy-mode-toggle {
        flex-direction: column;
        align-items: stretch;
    }

    .genealogy-mode-segmented {
        width: 100%;
    }

    .genealogy-mode-btn {
        flex: 1 1 50%;
        justify-content: center;
    }

    .genealogy-mode-metric-picker {
        flex-wrap: wrap;
    }

    .genealogy-heat-metric-select {
        flex: 1 1 auto;
    }
}


/* ==========================================================================
   D3.js Genealogy Tree View
   --------------------------------------------------------------------------
   Styles for the SVG-based tree (matrix-genealogy-d3-canvas) and its
   surrounding toolbar. The classic recursive HTML tree above keeps its
   own styles untouched — toggling between the two is a runtime concern
   driven by data-active-view attributes on .matrix-genealogy-wrapper
   and .matrix-genealogy-d3-canvas.
   ========================================================================== */

/* ----- Toolbar ----- */

.matrix-genealogy-toolbar {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    margin: 0 0 12px;
    background: #ffffff;
    border: 1px solid var(--matrix-border);
    border-radius: 10px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
}

.matrix-genealogy-toolbar-controls {
    display: flex;
    gap: 4px;
}

.matrix-genealogy-toolbar-spacer {
    flex: 1 1 auto;
}

.matrix-genealogy-tool-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
    background: transparent;
    border: 1px solid transparent;
    border-radius: 8px;
    color: var(--matrix-dark);
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease;
}

.matrix-genealogy-tool-btn:hover {
    background: #f3f4f6;
    border-color: var(--matrix-border);
}

.matrix-genealogy-tool-btn:focus {
    outline: none;
    border-color: var(--matrix-primary);
    box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.15);
}

.matrix-genealogy-tool-btn .dashicons {
    width: 18px;
    height: 18px;
    font-size: 18px;
}

/*
 * Hide zoom/fit/reset buttons when the page is in classic view —
 * they have no meaning over the static HTML tree below. The
 * view-toggle link itself stays visible because that's the way out
 * of classic mode.
 */
.matrix-genealogy-toolbar[data-active-view="classic"] .matrix-genealogy-toolbar-controls {
    display: none;
}

.matrix-genealogy-view-toggle {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    background: var(--matrix-primary);
    color: #ffffff;
    border-radius: 8px;
    font-size: 13px;
    font-weight: 600;
    text-decoration: none;
    transition: background 0.15s ease, transform 0.15s ease;
}

.matrix-genealogy-view-toggle:hover,
.matrix-genealogy-view-toggle:focus {
    background: #4338ca;
    color: #ffffff;
    text-decoration: none;
    transform: translateY(-1px);
}

.matrix-genealogy-view-toggle .dashicons {
    width: 16px;
    height: 16px;
    font-size: 16px;
}

/* ----- D3 canvas ----- */

.matrix-genealogy-d3-canvas {
    position: relative;
    width: 100%;
    /*
     * Fixed-aspect-ratio surface chosen by experimentation: 60vh
     * gives a 4-level tree room to breathe at default zoom on
     * 13" laptops (the most common dashboard viewport) without
     * pushing the legend below the fold. Members can pan/zoom
     * to explore beyond the visible area, so taller doesn't buy
     * us much.
     */
    height: 60vh;
    min-height: 420px;
    background: #f9fafb;
    background-image:
        linear-gradient(rgba(79, 70, 229, 0.04) 1px, transparent 1px),
        linear-gradient(90deg, rgba(79, 70, 229, 0.04) 1px, transparent 1px);
    background-size: 32px 32px;
    border: 1px solid var(--matrix-border);
    border-radius: 12px;
    overflow: hidden;
    cursor: grab;
}

.matrix-genealogy-d3-canvas:active {
    cursor: grabbing;
}

.matrix-genealogy-d3-canvas:focus {
    outline: none;
    box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.2);
}

/*
 * View-toggle visibility is enforced with CSS so the JS module
 * doesn't have to micro-manage display states across the lifecycle.
 *
 *   - data-active-view="classic" on the canvas → hidden, no D3 mount
 *     happens, classic tree below is the only thing visible.
 *   - data-active-view="d3" on the canvas + same on the classic
 *     wrapper means D3 mounted successfully and is in charge.
 */
.matrix-genealogy-d3-canvas[data-active-view="classic"] {
    display: none;
}

.matrix-genealogy-wrapper[data-active-view="d3"] {
    display: none;
}

/*
 * If the JS module fails to mount (data-mounted="failed") we fall
 * back to the classic view by setting the canvas to display:none
 * via inline style — this rule is just belt-and-braces for SSR
 * scenarios where the canvas was forced into d3 mode but the JS
 * never ran.
 */
.matrix-genealogy-d3-canvas[data-mounted="failed"] {
    display: none;
}

/* Loading shimmer shown until the JS mount removes it. */
.matrix-genealogy-d3-loading {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    color: #6b7280;
    font-size: 14px;
}

.matrix-genealogy-d3-loading .dashicons {
    font-size: 24px;
    width: 24px;
    height: 24px;
    color: var(--matrix-primary);
}

.matrix-genealogy-d3-svg {
    display: block;
    width: 100%;
    height: 100%;
}

/* ----- SVG: connector links ----- */

.mtx-link {
    fill: none;
    stroke: #cbd5e1;
    stroke-width: 1.5;
    stroke-linecap: round;
}

/* ----- SVG: nodes ----- */

.mtx-node {
    cursor: pointer;
}

/*
 * Empty slots aren't interactive in v1 (the referral-copy CTA from
 * the classic view hasn't been ported yet) so cursor stays default
 * and the keyboard skips them via tabindex=-1.
 */
.mtx-node-empty {
    cursor: default;
}

.mtx-node-body {
    fill: #ffffff;
    stroke: var(--matrix-border);
    stroke-width: 1.5;
    transition: stroke-width 0.15s ease;
}

.mtx-node-clickable:hover .mtx-node-body,
.mtx-node-clickable:focus .mtx-node-body {
    stroke-width: 2.5;
    filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.08));
}

/* Relationship-driven colour palettes — match the classic view's
 * .matrix-tree-node-* swatches so colour cues port across views. */
.mtx-node-you .mtx-node-body {
    fill: #eef2ff;
    stroke: var(--matrix-primary);
    stroke-width: 2;
}

.mtx-node-direct .mtx-node-body {
    fill: #f0fdf4;
    stroke: var(--matrix-success);
}

.mtx-node-spillover .mtx-node-body {
    fill: #fffbeb;
    stroke: #f59e0b;
}

.mtx-node-empty .mtx-node-body {
    fill: #f9fafb;
    stroke: #cbd5e1;
    stroke-dasharray: 4 4;
}

/* Avatar circles */
.mtx-node-avatar {
    fill: #e0e7ff;
    stroke: #ffffff;
    stroke-width: 2;
}

.mtx-node-you .mtx-node-avatar     { fill: var(--matrix-primary); }
.mtx-node-direct .mtx-node-avatar  { fill: var(--matrix-success); }
.mtx-node-spillover .mtx-node-avatar { fill: #f59e0b; }
.mtx-node-empty .mtx-node-avatar   { fill: #e5e7eb; }

.mtx-node-initial {
    fill: #ffffff;
    font-size: 14px;
    font-weight: 700;
    pointer-events: none;
    user-select: none;
}

.mtx-node-empty .mtx-node-initial {
    fill: #9ca3af;
}

/* Text labels */
.mtx-node-name {
    fill: var(--matrix-dark);
    font-size: 13px;
    font-weight: 600;
    pointer-events: none;
}

.mtx-node-meta {
    fill: #6b7280;
    font-size: 11px;
    pointer-events: none;
}

.mtx-node-you .mtx-node-name { fill: var(--matrix-primary); }

/* ----- SVG: expand badge ----- */

.mtx-expand-badge {
    cursor: pointer;
    transition: opacity 0.15s ease;
}

.mtx-expand-badge rect {
    fill: var(--matrix-primary);
    stroke: none;
}

.mtx-expand-badge text {
    fill: #ffffff;
    font-size: 11px;
    font-weight: 600;
    pointer-events: none;
    user-select: none;
}

.mtx-expand-badge:hover rect,
.mtx-expand-badge:focus rect {
    fill: #4338ca;
}

/* ----- Details mini-card (popover) ----- */

.matrix-genealogy-d3-details {
    position: absolute;
    z-index: 50;
    width: 280px;
    max-width: calc(100% - 32px);
    background: #ffffff;
    border: 1px solid var(--matrix-border);
    border-radius: 12px;
    box-shadow: 0 12px 24px -8px rgba(0, 0, 0, 0.18);
    padding: 14px 16px;
    font-size: 13px;
    color: var(--matrix-dark);
    /*
     * A small entrance animation sells the popover as a response
     * to the click rather than a fixed overlay. Disabled under
     * prefers-reduced-motion below.
     */
    animation: mtx-details-in 0.15s ease;
}

@keyframes mtx-details-in {
    from { opacity: 0; transform: translateY(4px); }
    to   { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
    .matrix-genealogy-d3-details {
        animation: none;
    }
}

.mtx-details-close {
    position: absolute;
    top: 6px;
    right: 8px;
    width: 24px;
    height: 24px;
    padding: 0;
    background: transparent;
    border: none;
    color: #6b7280;
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
    border-radius: 4px;
}

.mtx-details-close:hover,
.mtx-details-close:focus {
    background: #f3f4f6;
    color: var(--matrix-dark);
    outline: none;
}

.mtx-details-loading {
    color: #6b7280;
    text-align: center;
    padding: 8px 0;
}

.mtx-details-error {
    color: var(--matrix-danger);
    padding: 4px 0;
}

.mtx-details-header {
    margin-bottom: 10px;
    padding-right: 24px; /* leave room for the close button */
}

.mtx-details-name {
    font-size: 15px;
    font-weight: 700;
    color: var(--matrix-dark);
}

.mtx-details-username {
    font-size: 12px;
    color: #6b7280;
    margin-top: 2px;
}

.mtx-details-list {
    margin: 0 0 12px;
    padding: 0;
    display: grid;
    grid-template-columns: 1fr 1.4fr;
    gap: 4px 8px;
    font-size: 12px;
}

.mtx-details-list dt {
    color: #6b7280;
    font-weight: 500;
}

.mtx-details-list dd {
    margin: 0;
    color: var(--matrix-dark);
    font-weight: 600;
}

.mtx-details-pivot {
    display: block;
    text-align: center;
    padding: 8px 12px;
    background: var(--matrix-primary);
    color: #ffffff;
    border-radius: 8px;
    font-weight: 600;
    text-decoration: none;
    transition: background 0.15s ease;
}

.mtx-details-pivot:hover,
.mtx-details-pivot:focus {
    background: #4338ca;
    color: #ffffff;
    text-decoration: none;
}

/* ----- Inline error toast (lazy-load failures, etc.) ----- */

.matrix-genealogy-d3-flash {
    position: absolute;
    top: 12px;
    left: 50%;
    transform: translateX(-50%);
    background: var(--matrix-danger);
    color: #ffffff;
    padding: 8px 14px;
    border-radius: 8px;
    font-size: 13px;
    font-weight: 500;
    box-shadow: 0 4px 12px rgba(239, 68, 68, 0.3);
    z-index: 60;
    /* Same fade-in as the details card, so failure feedback feels
     * coherent with success feedback. */
    animation: mtx-details-in 0.15s ease;
}

/* ----- Responsive tweaks ----- */

@media (max-width: 640px) {
    .matrix-genealogy-toolbar {
        flex-wrap: wrap;
    }
    .matrix-genealogy-toolbar-spacer {
        display: none;
    }
    .matrix-genealogy-view-toggle {
        margin-left: auto;
    }
    .matrix-genealogy-d3-canvas {
        height: 70vh;
        min-height: 360px;
    }
    .matrix-genealogy-d3-details {
        /*
         * On narrow viewports the popover would sit awkwardly
         * floating next to the node — center it at the bottom
         * instead, which is a more conventional mobile pattern.
         */
        position: fixed;
        left: 16px;
        right: 16px;
        bottom: 16px;
        top: auto !important;
        width: auto;
        max-width: none;
    }
}


/* ==========================================================================
   D3 Genealogy — Real-time updates (polling + new-referral pulse)
   --------------------------------------------------------------------------
   Visual celebration for nodes that arrive via the polling endpoint
   (fetch_new_descendants). The JS adds `mtx-node-new` to entering
   <g> elements and removes it after PULSE_DURATION_MS (~4s); the
   keyframes here drive a soft green "ring pulse" around the card
   body for two cycles, then settle. The colour matches
   .mtx-node-direct's success-green palette so the highlight reads
   as "good news arrived" without introducing a new accent hue.

   Why drop-shadow (and not box-shadow): we're targeting an SVG
   <rect>, where box-shadow has no effect; filter: drop-shadow is
   the SVG-native equivalent and respects the rect's rounded
   corners cleanly across browsers.
   ========================================================================== */

.mtx-node-new .mtx-node-body {
    /* Two 1.4s cycles + a small fade. Kept short so the pulse
     * registers as "look here" without becoming distracting on a
     * wide tree where multiple new nodes might arrive together. */
    animation: mtx-node-pulse 1.4s ease-out 0s 2;
    transform-origin: center center;
}

@keyframes mtx-node-pulse {
    0% {
        filter: drop-shadow(0 0 0 rgba(16, 185, 129, 0));
    }
    35% {
        /* Same green as --matrix-success at 55% alpha — strong
         * enough to read on the existing card backgrounds without
         * dominating the page. */
        filter: drop-shadow(0 0 18px rgba(16, 185, 129, 0.55));
    }
    100% {
        filter: drop-shadow(0 0 0 rgba(16, 185, 129, 0));
    }
}

/*
 * Success-flavoured variant of the existing flash toast.
 * Reuses the .matrix-genealogy-d3-flash sizing/positioning rules
 * above and only swaps the colour story. Members thus see the
 * same shape & lifetime for both error ("could not load deeper
 * levels") and success ("Alice just joined!") feedback — a tiny
 * but consistent UX detail.
 */
.matrix-genealogy-d3-flash.matrix-genealogy-d3-flash--success {
    background: var(--matrix-success);
    box-shadow: 0 4px 12px rgba(16, 185, 129, 0.3);
}

/*
 * Reduced-motion fallback. Members who've opted out of motion at
 * the OS level shouldn't see a 1.4s drop-shadow pulse — that's
 * exactly the kind of effect the preference exists to silence.
 * We keep a brief background tint so the new-arrival cue still
 * lands visually, but no animated pulse.
 *
 * Mirrors the existing prefers-reduced-motion blocks already in
 * this file (matrix-tree-spin, mtx-details-in) so we degrade
 * consistently across every animated surface.
 */
@media (prefers-reduced-motion: reduce) {
    .mtx-node-new .mtx-node-body {
        animation: none;
        /* Soft mint tint, then transitions back to whatever the
         * relationship-class fill is on the next render. The
         * 1.4s transition matches the would-have-been animation
         * duration so the visual "settle time" feels equivalent.
         */
        fill: #ecfdf5;
        transition: fill 1.4s ease-out;
    }
}



/* ==========================================================================
   Genealogy time machine — date slider + snapshot view tint
   --------------------------------------------------------------------------
   The "time machine" view (?snapshot_at=YYYY-MM-DD) lets members scrub
   through past tree states. When in snapshot mode the bar is forced
   open with a sepia banner; in live mode the bar starts collapsed
   behind a "View past snapshots" disclosure. State is driven by two
   data attributes the PHP and inline JS share:

       data-snapshot-mode="0|1"   — sepia / banner gate
       data-time-machine-open="0|1" — slider visibility gate

   Layout philosophy: the bar lives between the search box and the
   share/export panel above the tree. On desktop it's a single
   horizontal strip; on mobile (max-width: 768px) it stacks vertically
   so the slider isn't squeezed against the floor/today labels.
   ========================================================================== */

.matrix-genealogy-time-machine {
    margin-bottom: 18px;
    background: #f8fafc;
    border: 1px solid var(--matrix-border);
    border-radius: 10px;
    padding: 10px 14px;
    font-size: 13px;
    color: var(--matrix-dark);
    transition: background 0.2s ease, border-color 0.2s ease;
}

/*
 * Snapshot mode: the bar swaps its neutral chrome for a sepia
 * surface that signals "you are looking at the past". Same trick
 * the macOS Time Machine UI uses — desaturate-ish background +
 * warm-tinted accent lines. Strong enough to register at a glance,
 * subtle enough not to dominate the tree below it.
 */
.matrix-genealogy-time-machine[data-snapshot-mode="1"] {
    background: #fef9e7;
    border-color: #f59e0b;
}

/* ----- Disclosure (live-mode collapsed state) ----- */

.mtm-disclosure {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    background: transparent;
    border: 1px dashed var(--matrix-border);
    border-radius: 8px;
    padding: 6px 12px;
    color: var(--matrix-primary);
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease;
}

.mtm-disclosure:hover,
.mtm-disclosure:focus-visible {
    background: #eef2ff;
    border-color: var(--matrix-primary);
    border-style: solid;
    outline: none;
}

.mtm-disclosure .dashicons {
    width: 16px;
    height: 16px;
    font-size: 16px;
}

.mtm-disclosure-chevron {
    transition: transform 0.15s ease;
    font-size: 11px;
    line-height: 1;
}

.matrix-genealogy-time-machine[data-time-machine-open="1"] .mtm-disclosure-chevron {
    transform: rotate(180deg);
}

/*
 * Hide the disclosure once the panel is open. The button's job is
 * pure "show the panel" — keeping it visible alongside an open
 * panel would be redundant chrome and would compete for attention
 * with the slider itself.
 */
.matrix-genealogy-time-machine[data-time-machine-open="1"] .mtm-disclosure {
    display: none;
}

/*
 * Snapshot mode never has a disclosure button at all — the bar is
 * permanently open and the snapshot banner takes the disclosure's
 * spot at the top.
 */
.matrix-genealogy-time-machine[data-snapshot-mode="1"] .mtm-disclosure {
    display: none;
}

/* ----- Snapshot banner (snapshot-mode top strip) ----- */

.mtm-snapshot-banner {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 6px 4px 12px;
    border-bottom: 1px dashed #f59e0b;
    margin-bottom: 12px;
    flex-wrap: wrap;
}

.mtm-snapshot-banner-icon {
    flex: 0 0 36px;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: #f59e0b;
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 2px 8px -2px rgba(245, 158, 11, 0.5);
}

.mtm-snapshot-banner-icon .dashicons {
    font-size: 18px;
    width: 18px;
    height: 18px;
}

.mtm-snapshot-banner-body {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.mtm-snapshot-banner-body strong {
    font-size: 14px;
    color: #78350f;
}

.mtm-snapshot-banner-body small {
    font-size: 12px;
    color: #92400e;
    line-height: 1.4;
}

.mtm-back-to-live {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: #92400e;
    color: #fff;
    text-decoration: none;
    border-radius: 6px;
    padding: 6px 12px;
    font-weight: 600;
    font-size: 13px;
    flex-shrink: 0;
    transition: background 0.15s ease;
}

.mtm-back-to-live:hover,
.mtm-back-to-live:focus {
    background: #78350f;
    color: #fff;
    text-decoration: none;
}

.mtm-back-to-live .dashicons {
    font-size: 14px;
    width: 14px;
    height: 14px;
}

/* ----- Slider panel (the actual scrubber) ----- */

.mtm-panel {
    display: none;
}

.matrix-genealogy-time-machine[data-time-machine-open="1"] .mtm-panel {
    display: block;
}

.mtm-slider-row {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 4px;
}

.mtm-slider-end {
    flex-shrink: 0;
    font-size: 11px;
    color: #6b7280;
    white-space: nowrap;
}

.mtm-slider {
    flex: 1 1 auto;
    height: 24px;
    cursor: pointer;
    accent-color: var(--matrix-primary);
}

/*
 * Snapshot mode dyes the slider thumb amber to match the banner —
 * a small consistency win that anchors the slider visually inside
 * the sepia frame.
 */
.matrix-genealogy-time-machine[data-snapshot-mode="1"] .mtm-slider {
    accent-color: #f59e0b;
}

.mtm-slider-readout {
    margin-top: 8px;
    display: flex;
    align-items: baseline;
    gap: 10px;
}

.mtm-date-label {
    font-size: 14px;
    font-weight: 700;
    color: var(--matrix-dark);
}

.matrix-genealogy-time-machine[data-snapshot-mode="1"] .mtm-date-label {
    color: #78350f;
}

.mtm-days-ago {
    font-size: 12px;
    color: #6b7280;
    font-weight: 500;
}

.matrix-genealogy-time-machine[data-snapshot-mode="1"] .mtm-days-ago {
    color: #92400e;
}

/* ----- Preset buttons row ----- */

.mtm-presets {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
    margin-top: 10px;
}

.mtm-preset-btn {
    background: #fff;
    border: 1px solid var(--matrix-border);
    border-radius: 999px;
    padding: 4px 12px;
    font-size: 12px;
    color: #4b5563;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.mtm-preset-btn:hover,
.mtm-preset-btn:focus-visible {
    background: #eef2ff;
    border-color: var(--matrix-primary);
    color: var(--matrix-primary);
    outline: none;
}

.mtm-preset-btn.is-active {
    background: var(--matrix-primary);
    border-color: var(--matrix-primary);
    color: #fff;
    cursor: default;
}

.matrix-genealogy-time-machine[data-snapshot-mode="1"] .mtm-preset-btn.is-active {
    background: #f59e0b;
    border-color: #f59e0b;
}

.matrix-genealogy-time-machine[data-snapshot-mode="1"] .mtm-preset-btn:hover:not(.is-active),
.matrix-genealogy-time-machine[data-snapshot-mode="1"] .mtm-preset-btn:focus-visible:not(.is-active) {
    background: #fef3c7;
    border-color: #f59e0b;
    color: #92400e;
}

.mtm-caveat {
    margin: 12px 0 0;
    font-size: 11px;
    color: #6b7280;
    line-height: 1.45;
    font-style: italic;
}

/* ==========================================================================
   Snapshot-mode tree tint
   --------------------------------------------------------------------------
   When the tree is rendering a historical snapshot, the wrapper carries
   data-snapshot-mode="1" and we apply a soft sepia filter to the entire
   tree surface (both classic CSS view and D3 SVG view). The point isn't
   to recolour every node — that would clash with the relationship and
   heat-map tints — but to GLOBALLY signal "this is the past" via a
   sepia overlay that desaturates the page below the time-machine bar.

   Filter approach (rather than per-element overrides) keeps the existing
   relationship/heat colours intact while giving the whole surface that
   characteristic time-machine warmth. CSS filter is GPU-accelerated and
   composite-only — no layout cost.
   ========================================================================== */

.matrix-genealogy-wrapper[data-snapshot-mode="1"],
.matrix-genealogy-d3-canvas[data-snapshot-mode="1"] {
    filter: sepia(0.18) saturate(0.92);
    transition: filter 0.3s ease;
}

/*
 * Snapshot-mode canvas also gets a subtle warm-tinted scrim along the
 * top so the boundary between the sepia banner above and the tree
 * below reads as one continuous "past view" rather than two unrelated
 * regions. linear-gradient overlay over the existing dot grid.
 */
.matrix-genealogy-d3-canvas[data-snapshot-mode="1"] {
    background-image:
        linear-gradient(180deg, rgba(245, 158, 11, 0.08) 0%, transparent 60px),
        linear-gradient(rgba(79, 70, 229, 0.04) 1px, transparent 1px),
        linear-gradient(90deg, rgba(79, 70, 229, 0.04) 1px, transparent 1px);
}

/*
 * Reduced-motion: the sepia transition is short (0.3s) and not
 * strictly motion, but we drop it under prefers-reduced-motion for
 * consistency with the rest of the file's reduced-motion blocks. The
 * filter itself stays — it's a static visual cue, not an animation.
 */
@media (prefers-reduced-motion: reduce) {
    .matrix-genealogy-wrapper[data-snapshot-mode="1"],
    .matrix-genealogy-d3-canvas[data-snapshot-mode="1"] {
        transition: none;
    }
}

/* ----- Mobile responsive ----- */

@media (max-width: 768px) {
    .mtm-snapshot-banner {
        flex-direction: column;
        align-items: flex-start;
    }

    .mtm-back-to-live {
        width: 100%;
        justify-content: center;
    }

    .mtm-slider-row {
        flex-direction: column;
        align-items: stretch;
        gap: 4px;
    }

    .mtm-slider-end {
        text-align: center;
    }

    /*
     * On mobile, the floor/today labels stack above and below the
     * slider rather than flanking it. Reorder so floor reads as
     * "older" (top) and today as "newer" (bottom) — matches the
     * vertical stacking convention of timelines.
     */
    .mtm-slider-row .mtm-slider-end-floor  { order: 0; }
    .mtm-slider-row .mtm-slider            { order: 1; }
    .mtm-slider-row .mtm-slider-end-today  { order: 2; }
}


/* ==========================================================================
   Per-position commission attribution overlay ("income map")
   --------------------------------------------------------------------------
   Toolbar toggle, per-node SVG pill, and corner summary chip for the income
   map view. Shares the same visual language as the rest of the genealogy
   toolbar (white surface, var(--matrix-border) strokes) so it reads as part
   of the same control set rather than a bolt-on. The active pressed state
   uses the success colour palette so the green per-node pills feel
   visually rooted in the toggle button itself.
   ========================================================================== */

/*
 * Thin vertical divider between the navigation cluster (zoom/fit/reset)
 * and data-overlay toggles. Functional grouping, not decoration — adding
 * the divider made the toolbar legible at a glance once we crossed three
 * buttons. Uses the same border colour as the toolbar chrome so it reads
 * as a structural separator rather than a coloured accent.
 */
.matrix-genealogy-tool-divider {
    display: inline-block;
    width: 1px;
    height: 22px;
    background: var(--matrix-border);
    margin: 0 4px;
    align-self: center;
}

/*
 * Active state for any toolbar button that behaves as a sticky toggle
 * (aria-pressed="true"). Currently used by the commission-overlay
 * button. Generalised on the .matrix-genealogy-tool-btn-toggle modifier
 * so a future heatmap-toggle or polling-pause button can opt in by
 * adding the same modifier without re-declaring colours.
 */
.matrix-genealogy-tool-btn-toggle[aria-pressed="true"] {
    background: rgba(16, 185, 129, 0.12);
    border-color: rgba(16, 185, 129, 0.4);
    color: #047857;
}

.matrix-genealogy-tool-btn-toggle[aria-pressed="true"]:hover {
    background: rgba(16, 185, 129, 0.18);
    border-color: rgba(16, 185, 129, 0.55);
}

/* ----- Per-node SVG pill ----- */

/*
 * The pill itself — a small rounded rect at the top-right corner of every
 * contributing node card. Green to signal "earnings", positioned so it
 * sticks slightly outside the card body to read as an applied tag rather
 * than a baked-in element.
 *
 * Pointer events are LEFT ENABLED on the pill so the native SVG <title>
 * tooltip fires on hover (members get the per-node breakdown — amount +
 * username + payout count). Clicks on the pill bubble up to the host
 * node group, which already has the click-to-details handler attached,
 * so clicking a pill behaves identically to clicking the rest of the
 * card.
 */
.mtx-commission-overlay {
    /* intentionally no pointer-events override */
}

.mtx-commission-overlay-pill {
    fill: #10b981;            /* matrix success green */
    stroke: #047857;          /* darker green border for definition */
    stroke-width: 1;
    /*
     * Subtle drop-shadow so the pill reads as floating above the card
     * even when the card body is white. SVG filter would be heavier
     * than this on Safari; box-shadow doesn't apply to SVG, so we
     * lean on the colour contrast and a thin stroke instead.
     */
}

.mtx-commission-overlay-amount {
    fill: #ffffff;
    font-size: 11px;
    font-weight: 700;
    /*
     * font-family inherits from the SVG, which inherits from the page —
     * matches the dashboard's body font so the pill doesn't look pasted
     * in from a different design system.
     */
    letter-spacing: 0.2px;
}

/*
 * Slight emphasis on the host node when a contributor pill is rendered
 * — a thicker border on the card body so the eye finds contributors
 * even on a dense tree where individual pills can blur together at
 * zoomed-out scales.
 *
 * Scoped via :has() where supported (modern Chromium, Safari 15.4+,
 * Firefox 121+). Members on older browsers just don't see the
 * thickening — the green pill is still the primary signal so the
 * progressive enhancement is acceptable.
 */
.mtx-node:has(.mtx-commission-overlay) .mtx-node-body {
    stroke: #10b981;
    stroke-width: 2;
}

/* ----- Corner summary chip ----- */

/*
 * Floats over the canvas in the bottom-left so it doesn't fight with
 * the existing flash toast (which lives top-center). Bottom-left is
 * the conventional spot for "status / legend" content on dashboard
 * canvases (Tableau, Datadog) so members read it as ambient
 * information rather than an action.
 *
 * z-index sits above the SVG but below the click-to-details popover
 * (which has z-index: 30 in the existing rules) so the popover wins
 * a stacking conflict.
 */
.matrix-genealogy-d3-commission-summary {
    position: absolute;
    left: 12px;
    bottom: 12px;
    max-width: calc(100% - 24px);
    padding: 6px 12px;
    background: rgba(6, 78, 59, 0.92);   /* dark green, semi-opaque */
    color: #ffffff;
    font-size: 12px;
    font-weight: 600;
    line-height: 1.4;
    border-radius: 999px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
    z-index: 5;
    /*
     * Allow long text to wrap (capped warning extends the line) but
     * keep it on at most two visual lines on narrow viewports so it
     * never towers over the canvas.
     */
    white-space: normal;
    overflow: hidden;
}

/* ----- Mobile tweaks ----- */

@media (max-width: 768px) {
    /*
     * Pull the summary chip in tighter on mobile so the canvas keeps
     * room for the actual tree. Members on small screens are more
     * likely to toggle the overlay briefly to scan totals than to
     * keep it on while panning, so optimising for "compact and
     * dismissable" beats "always-readable rich".
     */
    .matrix-genealogy-d3-commission-summary {
        left: 8px;
        bottom: 8px;
        font-size: 11px;
        padding: 5px 10px;
    }

    /*
     * Toolbar divider is purely visual — drop it on mobile where the
     * toolbar wraps anyway and the visual grouping is already
     * implied by the wrap.
     */
    .matrix-genealogy-tool-divider {
        display: none;
    }
}


/* =====================================================================
 * Genealogy hover-card
 * =====================================================================
 *
 * Originally lived inline in render_hovercard() (in
 * includes/user/class-matrix-user-genealogy.php). Moved here in
 * v1.0.6 because too many production WordPress installs were
 * silently stripping the body-level <style> block before it
 * reached the browser:
 *
 *   - HTML minifiers in caching plugins (LiteSpeed, W3 Total Cache,
 *     WP Rocket, Autoptimize) commonly combine-or-strip inline
 *     <style> tags as part of "Optimize CSS Delivery". The cache is
 *     server-side, so clearing the *browser* cache never helped —
 *     the cached HTML never contained the styles in the first place.
 *   - Strict Content-Security-Policy headers (style-src 'self'
 *     without 'unsafe-inline') block inline <style> elements while
 *     still permitting <link rel="stylesheet"> from the same origin.
 *   - A handful of themes / page builders sanitise shortcode
 *     output via wp_kses_post()-style filters that drop <style>.
 *
 * Serving the same rules from the registered matrix-mlm-dashboard
 * stylesheet sidesteps all three: the URL is cache-busted by
 * MATRIX_MLM_VERSION, the <link> tag is in <head>, and a self-
 * hosted CSS file is the most universally allowed delivery
 * mechanism a CSP can permit.
 *
 * Selector and !important strategy is unchanged from the previous
 * inline form (PR #187):
 *   - Every colour-bearing rule is parent-prefixed with
 *     .matrix-tree-hovercard so specificity beats single-class
 *     theme resets like `.theme-name strong { color: ... }`.
 *   - !important on color, background, font-weight, text-decoration
 *     for properties that themes most commonly reset (Astra,
 *     GeneratePress's popup-hardening module, several Elementor
 *     child themes use !important themselves).
 *
 * Markup contract is owned by render_hovercard() — keep these
 * selectors in sync with the DOM emitted there.
 * --------------------------------------------------------------------- */

/* Avatar becomes the touch trigger on mobile (where hover doesn't
   fire reliably). cursor:pointer + a subtle focus ring announces
   the affordance without bolting on a dedicated info icon next to
   the username — keeps the node card visually quiet. */
.tree-node-info-trigger {
    cursor: pointer;
    outline: 0;
    border-radius: 50%;
    transition: box-shadow .15s ease, transform .15s ease;
}
.tree-node-info-trigger:hover,
.tree-node-info-trigger:focus-visible {
    box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.25);
    transform: translateY(-1px);
}
.matrix-tree-node-empty .tree-node-info-trigger { /* defensive: empty slots don't get this class but just in case */
    cursor: default;
    box-shadow: none;
    transform: none;
}

.matrix-tree-hovercard {
    position: fixed;
    z-index: 9999;
    width: 320px;
    max-width: calc(100vw - 24px);
    /* Subtle gradient wash on the card body itself — keeps the
       readable white card surface but tints the bottom edge with
       the same purple/pink we use on the stripe and field accents.
       Visible even if every other colour rule is somehow overridden
       by the host theme, so members can confirm at a glance that
       the styled card is loading.
       !important defends against themes that aggressively reset
       background on dialog / popup containers. */
    background: linear-gradient(180deg, #ffffff 0%, #ffffff 70%, #faf5ff 100%) !important;
    border: 1px solid #e5e7eb;
    border-radius: 10px;
    box-shadow: 0 18px 36px -10px rgba(99, 102, 241, 0.28),
                0 0 0 1px rgba(139, 92, 246, 0.06);
    padding: 16px 16px 12px;
    font-size: 13px;
    color: #111827;
    line-height: 1.4;
    overflow: hidden;
}
/* Decorative gradient stripe across the top of the card. Pure CSS
   via ::before so the JS-managed markup contract stays untouched.
   Stripe colours echo the per-field accents below (indigo → violet
   → pink → amber) so the card reads as one coordinated palette
   rather than four random colours.
   !important on background defends against themes that force a
   flat colour onto pseudo-elements via aggressive resets (e.g.
   Astra, GeneratePress when their "popup hardening" CSS module is
   on). */
.matrix-tree-hovercard::before {
    content: "" !important;
    position: absolute !important;
    top: 0 !important;
    left: 0 !important;
    right: 0 !important;
    height: 5px !important;
    background: linear-gradient(90deg,
        #6366f1 0%, #8b5cf6 35%, #ec4899 70%, #f59e0b 100%) !important;
    border-top-left-radius: 10px;
    border-top-right-radius: 10px;
    pointer-events: none;
    z-index: 1;
}
.matrix-tree-hovercard[hidden] { display: none; }

.matrix-tree-hovercard-arrow {
    position: absolute;
    width: 12px;
    height: 12px;
    background: #fff;
    border-left: 1px solid #e5e7eb;
    border-top: 1px solid #e5e7eb;
    transform: rotate(45deg);
    display: none; /* JS toggles per placement */
}
.matrix-tree-hovercard.is-below .matrix-tree-hovercard-arrow {
    display: block;
    top: -7px;
    left: 28px;
    transform: rotate(45deg);
}
.matrix-tree-hovercard.is-above .matrix-tree-hovercard-arrow {
    display: block;
    bottom: -7px;
    left: 28px;
    transform: rotate(225deg);
}

.matrix-tree-hovercard-close {
    position: absolute;
    top: 6px;
    right: 6px;
    background: transparent;
    border: 0;
    padding: 4px;
    border-radius: 4px;
    cursor: pointer;
    color: #6b7280;
}
.matrix-tree-hovercard-close:hover { color: #111827; background: #f3f4f6; }
.matrix-tree-hovercard-close .dashicons { font-size: 16px; width: 16px; height: 16px; }

.matrix-tree-hovercard-loading {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 0 0;
    color: #6b7280;
}
.matrix-tree-hovercard-loading[hidden] { display: none; }
.matrix-tree-hovercard-loading .dashicons {
    font-size: 18px;
    width: 18px;
    height: 18px;
    color: #8b5cf6;
}

.matrix-tree-hovercard-error {
    color: #b91c1c;
    background: #fef2f2;
    border: 1px solid #fecaca;
    padding: 8px 10px;
    border-radius: 6px;
    margin-top: 4px;
}
.matrix-tree-hovercard-error[hidden] { display: none; }

.matrix-tree-hovercard-body[hidden] { display: none; }

.matrix-tree-hovercard-header {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
    margin-bottom: 10px;
    padding-right: 22px; /* leave space for the close X */
}
/* Member name. Solid bold indigo + !important so a host theme
   can't reset <strong> back to its body-text colour. We dropped
   the background-clip:text gradient text trick: too many themes
   neutralise it (either by overriding color, by setting
   -webkit-text-fill-color, or by adding a text-shadow that paints
   over the transparent fill), which on those sites left the name
   looking unstyled. A solid bold indigo reliably reads as
   "primary brand colour" everywhere instead. */
.matrix-tree-hovercard .matrix-tree-hovercard-name {
    font-size: 15px !important;
    font-weight: 700 !important;
    color: #4f46e5 !important;
    background: transparent !important;
    -webkit-text-fill-color: #4f46e5 !important;
}
/* Username pill. !important on color/background so themes that
   style <span> with a global colour reset (common in "minimal"
   themes) don't strip the purple. */
.matrix-tree-hovercard .matrix-tree-hovercard-username {
    font-size: 12px !important;
    color: #6d28d9 !important;
    background: #ede9fe !important;
    border-radius: 999px;
    padding: 2px 8px;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    align-self: flex-start;
}

.matrix-tree-hovercard .matrix-tree-hovercard-fields {
    display: grid;
    grid-template-columns: 110px 1fr;
    gap: 6px 10px;
    margin: 0 0 10px;
}
/* Per-field label colours + dot. !important on the color and the
   dot's background because themes that style <dt> globally (most
   do — `dl dt` reset rules are extremely common) win over our
   plain selectors on equal specificity due to source order on
   certain themes that load CSS into the body via late-loading
   customizer overrides. The parent-prefixed selector already
   raises specificity above a bare `dt` rule; the !important is
   the second line of defence. */
.matrix-tree-hovercard .matrix-tree-hovercard-fields dt {
    font-size: 11px !important;
    text-transform: uppercase !important;
    letter-spacing: 0.5px;
    font-weight: 600 !important;
    color: #6b7280 !important;
    margin: 0 !important;
    padding-top: 1px;
    display: flex !important;
    align-items: center;
    gap: 6px;
}
/* Coloured dot before each label, tinted to match the row's
   semantic accent. Order is fixed (Joined / Sponsor / Plans /
   Branch commission) so :nth-of-type is safe — the markup is
   rendered server-side in render_hovercard() in the same order
   on every load. */
.matrix-tree-hovercard .matrix-tree-hovercard-fields dt::before {
    content: "" !important;
    display: inline-block !important;
    width: 8px !important;
    height: 8px !important;
    border-radius: 50%;
    background: #9ca3af !important;
    flex: 0 0 auto;
}
.matrix-tree-hovercard .matrix-tree-hovercard-fields dt:nth-of-type(1) { color: #2563eb !important; }
.matrix-tree-hovercard .matrix-tree-hovercard-fields dt:nth-of-type(1)::before { background: #2563eb !important; }
.matrix-tree-hovercard .matrix-tree-hovercard-fields dt:nth-of-type(2) { color: #db2777 !important; }
.matrix-tree-hovercard .matrix-tree-hovercard-fields dt:nth-of-type(2)::before { background: #db2777 !important; }
.matrix-tree-hovercard .matrix-tree-hovercard-fields dt:nth-of-type(3) { color: #7c3aed !important; }
.matrix-tree-hovercard .matrix-tree-hovercard-fields dt:nth-of-type(3)::before { background: #7c3aed !important; }
.matrix-tree-hovercard .matrix-tree-hovercard-fields dt:nth-of-type(4) { color: #047857 !important; }
.matrix-tree-hovercard .matrix-tree-hovercard-fields dt:nth-of-type(4)::before { background: #047857 !important; }
.matrix-tree-hovercard .matrix-tree-hovercard-fields dd {
    margin: 0 !important;
    font-size: 13px;
    color: #111827;
    word-break: break-word;
}
.matrix-tree-hovercard-fields dd em {
    color: #6b7280;
    font-style: normal;
    font-size: 12px;
}
.matrix-tree-hovercard .matrix-tree-hovercard-commission {
    font-weight: 600 !important;
    color: #047857 !important; /* same emerald the level-badge "complete" pill uses */
}
.matrix-tree-hovercard .matrix-tree-hovercard-commission.is-zero { color: #6b7280 !important; font-weight: 500 !important; }
.matrix-tree-hovercard .matrix-tree-hovercard-commission.is-capped { color: #b45309 !important; }

/* Profile pill button. Theme override-resistant: every visual
   property carries !important, including text-decoration (most
   themes underline links by default and a transparent gradient
   pill with an underline reads visually broken). */
.matrix-tree-hovercard .matrix-tree-hovercard-profile {
    display: inline-block !important;
    margin-top: 4px;
    padding: 6px 12px !important;
    font-size: 12px !important;
    font-weight: 600 !important;
    color: #fff !important;
    text-decoration: none !important;
    background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 55%, #ec4899 100%) !important;
    border: 0 !important;
    border-radius: 999px !important;
    box-shadow: 0 2px 8px -2px rgba(139, 92, 246, 0.5);
    transition: transform .15s ease, box-shadow .15s ease;
}
.matrix-tree-hovercard .matrix-tree-hovercard-profile[hidden] { display: none !important; }
.matrix-tree-hovercard .matrix-tree-hovercard-profile:hover,
.matrix-tree-hovercard .matrix-tree-hovercard-profile:focus-visible {
    text-decoration: none !important;
    color: #fff !important;
    transform: translateY(-1px);
    box-shadow: 0 4px 14px -2px rgba(139, 92, 246, 0.6);
}

/* Mobile: the indented vertical tree leaves no good horizontal
   anchor, so we promote the card to a centered "mini modal" with
   a translucent backdrop click target. */
@media (max-width: 767px) {
    .matrix-tree-hovercard.is-mobile {
        left: 50% !important;
        top: 50% !important;
        transform: translate(-50%, -50%);
        width: calc(100vw - 32px);
    }
    .matrix-tree-hovercard.is-mobile .matrix-tree-hovercard-arrow {
        display: none !important;
    }
}

/* Backdrop overlay used in mobile modal mode. Created by the JS
   on demand so non-mobile renders never pay the cost. */
.matrix-tree-hovercard-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(17, 24, 39, 0.35);
    z-index: 9998;
}
.matrix-tree-hovercard-backdrop[hidden] { display: none; }



/* =====================================================================
 * D3 details panel — colourful overrides
 * =====================================================================
 *
 * The interactive (D3) genealogy view's hover/click details panel
 * (.matrix-genealogy-d3-details, populated by the JS in
 * matrix-genealogy-d3.js → spawnDetailsPanel/fillDetailsPanel) was
 * still rendering in the original plain white-and-grey palette
 * after PRs #186 / #187 / #188 made the *classic*-view hover-card
 * (.matrix-tree-hovercard) colourful. The two surfaces serve the
 * same purpose ("show this member's details on hover") but live in
 * different DOM trees with different class prefixes, so colouring
 * one didn't touch the other — and the genealogy view defaults to
 * the interactive (D3) view, meaning most members were still seeing
 * the plain panel even after the hover-card fix landed.
 *
 * Mirror the hover-card palette here against the .mtx-details-*
 * classes the D3 panel emits, so members on the default
 * interactive view see the same coordinated indigo / violet / pink /
 * amber treatment members on the classic view already see. Keeps
 * the brand visual consistent across both views without changing
 * any markup or JS contract — every selector below targets DOM
 * the JS already builds in matrix-genealogy-d3.js → spawnDetailsPanel
 * and fillDetailsPanel.
 *
 * Selectors are parent-prefixed with .matrix-genealogy-d3-details
 * so they cleanly out-specify the original neutral rules earlier in
 * this file (which use bare .mtx-details-* selectors). !important
 * is layered on the colour, background, font-weight, and
 * text-decoration properties for the same theme-override defence
 * the hover-card uses (Astra, GeneratePress popup-hardening, etc.
 * commonly !important-reset <strong>, <a>, <dt>, and <dl dd>).
 *
 * dt accents use :nth-of-type cycling because the JS conditionally
 * skips fields whose data is empty — Joined / Level / Sponsor /
 * Plans / Branch earnings can each be present or absent on any
 * given hover. The cycle assigns five colours in rotation, so
 * whichever fields are present each get a distinct accent. The
 * "Branch earnings" row — usually rendered last — typically lands
 * on the emerald 5th-position colour, which matches its semantic
 * meaning, but we don't depend on that mapping.
 * --------------------------------------------------------------------- */

/* Card body — gradient wash + tinted shadow + decorative top stripe */
.matrix-genealogy-d3-details {
    background: linear-gradient(180deg, #ffffff 0%, #ffffff 70%, #faf5ff 100%) !important;
    box-shadow: 0 18px 36px -10px rgba(99, 102, 241, 0.28),
                0 0 0 1px rgba(139, 92, 246, 0.06) !important;
    overflow: hidden;
}

.matrix-genealogy-d3-details::before {
    content: "" !important;
    position: absolute !important;
    top: 0 !important;
    left: 0 !important;
    right: 0 !important;
    height: 5px !important;
    background: linear-gradient(90deg,
        #6366f1 0%, #8b5cf6 35%, #ec4899 70%, #f59e0b 100%) !important;
    border-top-left-radius: 12px;
    border-top-right-radius: 12px;
    pointer-events: none;
    z-index: 1;
}

/* Header — bump padding so name/username clear the top stripe and
   close-X without the gradient line bleeding into the text. */
.matrix-genealogy-d3-details .mtx-details-header {
    padding-top: 4px;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
}

/* Member name — solid bold indigo so theme <strong> resets can't
   wash it back to body-text colour. Same colour the hover-card
   uses (#4f46e5) so the two surfaces feel like one product. */
.matrix-genealogy-d3-details .mtx-details-name {
    font-size: 15px !important;
    font-weight: 700 !important;
    color: #4f46e5 !important;
    background: transparent !important;
    -webkit-text-fill-color: #4f46e5 !important;
}

/* Username pill — soft purple, rounded, monospace. */
.matrix-genealogy-d3-details .mtx-details-username {
    font-size: 12px !important;
    color: #6d28d9 !important;
    background: #ede9fe !important;
    border-radius: 999px;
    padding: 2px 8px;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    align-self: flex-start;
    margin-top: 0;
}

/* Per-row label dot + accent colour. Five-cycle through the same
   palette the hover-card uses (blue / violet / pink / indigo /
   emerald) so consecutive rows read as related-but-distinct rather
   than four random hues. The dt itself becomes a flexbox so the
   leading dot pseudo-element sits inline with the label. */
.matrix-genealogy-d3-details .mtx-details-list dt {
    font-size: 11px !important;
    text-transform: uppercase !important;
    letter-spacing: 0.5px;
    font-weight: 600 !important;
    color: #6b7280 !important;
    margin: 0 !important;
    padding-top: 1px;
    display: flex !important;
    align-items: center;
    gap: 6px;
}

.matrix-genealogy-d3-details .mtx-details-list dt::before {
    content: "" !important;
    display: inline-block !important;
    width: 8px !important;
    height: 8px !important;
    border-radius: 50%;
    background: #9ca3af !important;
    flex: 0 0 auto;
}

.matrix-genealogy-d3-details .mtx-details-list dt:nth-of-type(1)         { color: #2563eb !important; }
.matrix-genealogy-d3-details .mtx-details-list dt:nth-of-type(1)::before { background: #2563eb !important; }
.matrix-genealogy-d3-details .mtx-details-list dt:nth-of-type(2)         { color: #7c3aed !important; }
.matrix-genealogy-d3-details .mtx-details-list dt:nth-of-type(2)::before { background: #7c3aed !important; }
.matrix-genealogy-d3-details .mtx-details-list dt:nth-of-type(3)         { color: #db2777 !important; }
.matrix-genealogy-d3-details .mtx-details-list dt:nth-of-type(3)::before { background: #db2777 !important; }
.matrix-genealogy-d3-details .mtx-details-list dt:nth-of-type(4)         { color: #4f46e5 !important; }
.matrix-genealogy-d3-details .mtx-details-list dt:nth-of-type(4)::before { background: #4f46e5 !important; }
.matrix-genealogy-d3-details .mtx-details-list dt:nth-of-type(5)         { color: #047857 !important; }
.matrix-genealogy-d3-details .mtx-details-list dt:nth-of-type(5)::before { background: #047857 !important; }

/* dd values stay dark for readability — bump font-weight a notch
   so the value reads as the foreground content vs the muted label. */
.matrix-genealogy-d3-details .mtx-details-list dd {
    margin: 0 !important;
    color: #111827 !important;
    font-weight: 600 !important;
    word-break: break-word;
}

/* "View their tree →" link — gradient pill button matching the
   hover-card's profile button. Theme override-resistant: every
   visual property carries !important so themes that style anchor
   tags globally (text-decoration: underline, accent-coloured
   colours, etc.) can't wash out the gradient. */
.matrix-genealogy-d3-details .mtx-details-pivot {
    display: block !important;
    margin-top: 4px;
    padding: 8px 12px !important;
    font-size: 12px !important;
    font-weight: 600 !important;
    color: #fff !important;
    text-align: center !important;
    text-decoration: none !important;
    background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 55%, #ec4899 100%) !important;
    border: 0 !important;
    border-radius: 999px !important;
    box-shadow: 0 2px 8px -2px rgba(139, 92, 246, 0.5);
    transition: transform .15s ease, box-shadow .15s ease;
}

.matrix-genealogy-d3-details .mtx-details-pivot:hover,
.matrix-genealogy-d3-details .mtx-details-pivot:focus,
.matrix-genealogy-d3-details .mtx-details-pivot:focus-visible {
    text-decoration: none !important;
    color: #fff !important;
    background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 55%, #ec4899 100%) !important;
    transform: translateY(-1px);
    box-shadow: 0 4px 14px -2px rgba(139, 92, 246, 0.6);
}

/* Loading spinner colour aligned with the brand palette. */
.matrix-genealogy-d3-details .mtx-details-loading {
    color: #6d28d9 !important;
}



/* =====================================================================
 * Genealogy Share & Export panel — colourful
 * =====================================================================
 *
 * Originally lived inline in render_share_export_panel() (in
 * includes/user/class-matrix-user-genealogy.php). Moved here in
 * v1.0.8 for the same reasons we moved the hover-card CSS in
 * v1.0.6 — body-level <style> blocks are silently stripped on
 * production WordPress installs by:
 *
 *   - HTML minifiers in caching plugins (LiteSpeed, W3 Total Cache,
 *     WP Rocket, Autoptimize) when "Optimize CSS Delivery" or
 *     "Combine CSS" is enabled.
 *   - Strict Content-Security-Policy headers (style-src 'self'
 *     without 'unsafe-inline').
 *   - Themes / page builders that route shortcode output through
 *     wp_kses_post()-style sanitisers.
 *
 * Serving the rules from the registered matrix-mlm-dashboard
 * stylesheet (cache-busted by MATRIX_MLM_VERSION, delivered as a
 * <link> in <head>) sidesteps all three.
 *
 * On top of the move, the rules are now styled to match the rest
 * of the genealogy view's palette: indigo / violet / pink / amber
 * gradient stripe across the top of the panel, gradient-pill
 * primary button for "Create link", soft-indigo outlined pills for
 * the export buttons, accent-coloured section dots, and tinted
 * lavender card surface on each share-token row. The plain
 * white-and-grey panel stood out against an otherwise colourful
 * genealogy view, so this brings it in line.
 *
 * Markup contract is owned by render_share_export_panel() in PHP
 * — keep selectors in sync with the DOM emitted there
 * (.matrix-share-export-panel and the .msep-* inner classes).
 * --------------------------------------------------------------------- */

/* Outer panel — same gradient wash + tinted shadow as the
   hover-card so the two surfaces feel like one product. */
.matrix-share-export-panel {
    background: linear-gradient(180deg, #ffffff 0%, #ffffff 70%, #faf5ff 100%);
    border: 1px solid #e9d5ff;
    border-radius: 12px;
    padding: 18px 22px;
    margin: 0 0 18px;
    box-shadow: 0 2px 6px -2px rgba(99, 102, 241, 0.10),
                0 0 0 1px rgba(139, 92, 246, 0.04);
    position: relative;
    overflow: hidden;
}

/* Top stripe (indigo → violet → pink → amber). Pure ::before
   pseudo so we don't have to touch the markup. !important on
   background defends against themes that aggressively reset
   pseudo-elements (Astra, GeneratePress popup-hardening). */
.matrix-share-export-panel::before {
    content: "" !important;
    position: absolute !important;
    top: 0 !important;
    left: 0 !important;
    right: 0 !important;
    height: 5px !important;
    background: linear-gradient(90deg,
        #6366f1 0%, #8b5cf6 35%, #ec4899 70%, #f59e0b 100%) !important;
    border-top-left-radius: 12px;
    border-top-right-radius: 12px;
    pointer-events: none;
    z-index: 1;
}

/* Section headings carry accent dots so the two columns read
   as related-but-distinct (Export = indigo, Share = pink). */
.matrix-share-export-panel h3 {
    margin: 0 0 6px;
    font-size: 14px;
    color: #4f46e5;
    font-weight: 700;
    display: flex;
    align-items: center;
    gap: 8px;
}
.matrix-share-export-panel h3::before {
    content: "";
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #4f46e5;
    flex: 0 0 auto;
}
.matrix-share-export-panel .msep-col-share h3 {
    color: #db2777;
}
.matrix-share-export-panel .msep-col-share h3::before {
    background: #db2777;
}

.matrix-share-export-panel .msep-help {
    margin: 0 0 12px;
    font-size: 12px;
    color: #6b7280;
    line-height: 1.45;
}

.matrix-share-export-panel .msep-row {
    display: grid;
    grid-template-columns: 1fr 1.4fr;
    gap: 28px;
}
@media (max-width: 768px) {
    .matrix-share-export-panel .msep-row { grid-template-columns: 1fr; }
}

.matrix-share-export-panel .msep-actions {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}

.matrix-share-export-panel .msep-form {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    align-items: flex-end;
    margin-bottom: 14px;
}

.matrix-share-export-panel .msep-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: 11px;
    color: #6d28d9;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.4px;
    flex: 1 1 140px;
}

.matrix-share-export-panel .msep-field input[type="text"],
.matrix-share-export-panel .msep-field select {
    border: 1px solid #ddd6fe;
    border-radius: 8px;
    padding: 7px 10px;
    font-size: 13px;
    min-width: 0;
    background: #ffffff;
    color: #111827;
    font-weight: 500;
    text-transform: none;
    letter-spacing: 0;
    transition: border-color .15s ease, box-shadow .15s ease;
}

.matrix-share-export-panel .msep-field input[type="text"]:focus,
.matrix-share-export-panel .msep-field select:focus {
    outline: none;
    border-color: #8b5cf6;
    box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.18);
}

/* ---------- Buttons ----------
 *
 * Override the host theme's `.button` styling with our gradient
 * palette. `!important` on colour / background / border /
 * text-decoration is the same belt-and-braces treatment the
 * hover-card uses against themes (Astra, GeneratePress, Elementor
 * child themes) that aggressively reset anchor and button styling.
 *
 * Three button tiers, each visually distinct:
 *   - Primary: "Create link" — full gradient pill (indigo → violet
 *     → pink). The most-prominent CTA on the panel.
 *   - Secondary: "Export PDF" / "Export PNG" — soft lavender pill
 *     with indigo text. Less visual weight than the primary so
 *     the eye lands on Create first when the panel is empty.
 *   - Tertiary: "Copy link" / "Revoke" inside each token row —
 *     small accent-coloured pills (blue/red) so they read as
 *     row-scoped controls, not panel-level CTAs.
 */
.matrix-share-export-panel .button.button-primary,
.matrix-share-export-panel #msep-create-btn {
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    padding: 8px 18px !important;
    font-size: 13px !important;
    font-weight: 600 !important;
    color: #ffffff !important;
    text-decoration: none !important;
    background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 55%, #ec4899 100%) !important;
    border: 0 !important;
    border-radius: 999px !important;
    box-shadow: 0 2px 8px -2px rgba(139, 92, 246, 0.5) !important;
    text-shadow: none !important;
    cursor: pointer;
    transition: transform .15s ease, box-shadow .15s ease;
}

.matrix-share-export-panel .button.button-primary:hover,
.matrix-share-export-panel .button.button-primary:focus,
.matrix-share-export-panel #msep-create-btn:hover,
.matrix-share-export-panel #msep-create-btn:focus,
.matrix-share-export-panel #msep-create-btn:focus-visible {
    color: #ffffff !important;
    background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 55%, #ec4899 100%) !important;
    transform: translateY(-1px);
    box-shadow: 0 4px 14px -2px rgba(139, 92, 246, 0.6) !important;
}

.matrix-share-export-panel .button.button-primary:disabled,
.matrix-share-export-panel #msep-create-btn:disabled {
    opacity: 0.6;
    transform: none;
    cursor: wait;
}

/* Secondary buttons (Export PDF / Export PNG). Soft lavender
   surface with indigo text — visually quieter than the primary
   but still on-palette. */
.matrix-share-export-panel #msep-export-pdf,
.matrix-share-export-panel #msep-export-png {
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    padding: 7px 16px !important;
    font-size: 13px !important;
    font-weight: 600 !important;
    color: #4f46e5 !important;
    text-decoration: none !important;
    background: linear-gradient(135deg, #ede9fe 0%, #ddd6fe 100%) !important;
    border: 1px solid #c7d2fe !important;
    border-radius: 999px !important;
    text-shadow: none !important;
    cursor: pointer;
    transition: transform .15s ease, box-shadow .15s ease, background .15s ease, border-color .15s ease;
}

.matrix-share-export-panel #msep-export-pdf:hover,
.matrix-share-export-panel #msep-export-pdf:focus,
.matrix-share-export-panel #msep-export-pdf:focus-visible,
.matrix-share-export-panel #msep-export-png:hover,
.matrix-share-export-panel #msep-export-png:focus,
.matrix-share-export-panel #msep-export-png:focus-visible {
    color: #4338ca !important;
    background: linear-gradient(135deg, #ddd6fe 0%, #c7d2fe 100%) !important;
    border-color: #a5b4fc !important;
    transform: translateY(-1px);
    box-shadow: 0 4px 12px -3px rgba(99, 102, 241, 0.4);
}

.matrix-share-export-panel #msep-export-png:disabled {
    opacity: 0.6;
    transform: none;
    cursor: wait;
}

/* Tokens divider with a subtle gradient instead of a flat dash. */
.matrix-share-export-panel .msep-tokens {
    border-top: 1px solid transparent;
    border-image: linear-gradient(90deg,
        rgba(99, 102, 241, 0.25),
        rgba(236, 72, 153, 0.25),
        rgba(245, 158, 11, 0.25)) 1;
    padding-top: 12px;
}

.matrix-share-export-panel .msep-empty {
    margin: 0;
    font-size: 12px;
    color: #9ca3af;
    font-style: italic;
}

.matrix-share-export-panel .msep-token-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* Token rows — soft lavender wash so the panel reads as one
   continuous palette. Non-active rows fade out so members'
   eyes find live tokens first. */
.matrix-share-export-panel .msep-token {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 12px;
    background: linear-gradient(135deg, #faf5ff 0%, #ffffff 100%);
    border: 1px solid #e9d5ff;
    border-radius: 8px;
    font-size: 12px;
    flex-wrap: wrap;
    transition: box-shadow .15s ease, border-color .15s ease;
}

.matrix-share-export-panel .msep-token:hover {
    border-color: #c4b5fd;
    box-shadow: 0 4px 14px -4px rgba(139, 92, 246, 0.18);
}

.matrix-share-export-panel .msep-token.is-revoked,
.matrix-share-export-panel .msep-token.is-expired {
    opacity: 0.55;
    background: linear-gradient(135deg, #f9fafb 0%, #ffffff 100%);
    border-color: #e5e7eb;
}

.matrix-share-export-panel .msep-token-label {
    font-weight: 600;
    color: #4c1d95;
    flex: 1 1 140px;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.matrix-share-export-panel .msep-token-meta {
    color: #6b7280;
    font-size: 11px;
}

/* Status pills — brighter palette than the prior flat fills,
   with darker text for contrast. */
.matrix-share-export-panel .msep-token-status {
    display: inline-block;
    padding: 2px 10px;
    border-radius: 999px;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    border: 1px solid transparent;
}

.matrix-share-export-panel .msep-status-active {
    background: linear-gradient(135deg, #d1fae5 0%, #a7f3d0 100%);
    color: #065f46;
    border-color: #6ee7b7;
}

.matrix-share-export-panel .msep-status-revoked {
    background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%);
    color: #991b1b;
    border-color: #fca5a5;
}

.matrix-share-export-panel .msep-status-expired {
    background: linear-gradient(135deg, #f3f4f6 0%, #e5e7eb 100%);
    color: #4b5563;
    border-color: #d1d5db;
}

/* Token URL — soft purple-tinted readout with a monospaced font
   so the link reads as content rather than chrome. */
.matrix-share-export-panel .msep-token-url {
    flex-basis: 100%;
    margin-top: 4px;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 11px;
    background: #f5f3ff;
    border: 1px solid #e9d5ff;
    border-radius: 6px;
    padding: 5px 10px;
    color: #4f46e5;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Small action buttons inside token rows. WP's .button-small
   would otherwise win on specificity, so override directly with
   the same colour-bearing !important pattern the panel-level
   buttons use. */
.matrix-share-export-panel .msep-copy-btn,
.matrix-share-export-panel .msep-revoke-btn {
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    padding: 3px 12px !important;
    font-size: 11px !important;
    font-weight: 600 !important;
    text-decoration: none !important;
    border-radius: 999px !important;
    border: 1px solid transparent !important;
    text-shadow: none !important;
    cursor: pointer;
    transition: transform .15s ease, background .15s ease, border-color .15s ease;
    min-height: 0 !important;
    line-height: 1.4 !important;
}

.matrix-share-export-panel .msep-copy-btn {
    color: #1d4ed8 !important;
    background: #dbeafe !important;
    border-color: #bfdbfe !important;
}

.matrix-share-export-panel .msep-copy-btn:hover,
.matrix-share-export-panel .msep-copy-btn:focus,
.matrix-share-export-panel .msep-copy-btn:focus-visible {
    color: #1e40af !important;
    background: #bfdbfe !important;
    border-color: #93c5fd !important;
    transform: translateY(-1px);
}

.matrix-share-export-panel .msep-revoke-btn {
    color: #b91c1c !important;
    background: #fee2e2 !important;
    border-color: #fecaca !important;
}

.matrix-share-export-panel .msep-revoke-btn:hover,
.matrix-share-export-panel .msep-revoke-btn:focus,
.matrix-share-export-panel .msep-revoke-btn:focus-visible {
    color: #991b1b !important;
    background: #fecaca !important;
    border-color: #fca5a5 !important;
    transform: translateY(-1px);
}

.matrix-share-export-panel .msep-revoke-btn:disabled {
    opacity: 0.6;
    transform: none;
    cursor: wait;
}

/* Toast — gradient pill so success/info feels celebratory and
   matches the rest of the panel's palette. The error variant
   keeps a strong red so the failure state still reads as
   "something went wrong" at a glance. */
.matrix-share-export-panel .msep-toast {
    position: absolute;
    top: 12px;
    right: 18px;
    background: linear-gradient(135deg, #4f46e5 0%, #8b5cf6 50%, #ec4899 100%);
    color: #fff;
    padding: 7px 14px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 600;
    box-shadow: 0 4px 14px -2px rgba(139, 92, 246, 0.5);
    opacity: 0;
    transform: translateY(-4px);
    transition: opacity 0.15s, transform 0.15s;
    pointer-events: none;
    z-index: 2;
}

.matrix-share-export-panel .msep-toast.is-shown {
    opacity: 1;
    transform: translateY(0);
}

.matrix-share-export-panel .msep-toast.is-error {
    background: linear-gradient(135deg, #b91c1c 0%, #dc2626 100%);
    box-shadow: 0 4px 14px -2px rgba(220, 38, 38, 0.45);
}

@media print {
    .matrix-share-export-panel { display: none !important; }
}
