/* 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-size: 16px;
    width: 16px;
    height: 16px;
}

.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; }
}
