/* AI Cloud component plugin: Surfaces & Data */
/* ===== Cards ===== */
.card,
.stat-card{
    backdrop-filter:blur(18px);
    border:1px solid var(--border);
    border-radius:5px;
    padding:22px;
    box-shadow:var(--shadow);
}

section.card{
    margin-bottom: 18px;
}

.notice-card{border-color:var(--mpdg-hl-22)}

/* ===== Tables ===== */
table{
    border-collapse:separate;
    border-spacing:0;
    width: 100%;
}

/*
   Generic table overflow guard.
   Overflow handling is active at all viewport sizes, but it only has a
   visible effect when table content exceeds its container. Tables keep
   full available width before overflow, then scroll horizontally.
   Calendar / FullCalendar tables are explicitly excluded and reset below.
*/


:where(.table-wrap,.table-responsive,.data-table-wrap,.admin-table-wrap):not(.mp-calendar-wrap):not(.calendar-wrap):not(.calendar-shell):not(.fc):not(#planner-calendar),
:where(.card,.stat-card):has(> table:not(.fc-scrollgrid):not(.fc-col-header):not(.fc-scrollgrid-sync-table):not(.fc-list-table)){
    min-width:100%;
    overflow-x:auto;
    overflow-y:hidden;
    -webkit-overflow-scrolling:touch;
}

:where(.mp-calendar-wrap,#planner-calendar,.fc) table{
    max-width:none;
    overflow:visible;
}

th{
    color:var(--mpdg-ink-muted);
    text-align:left;
    font-size:var(--mp-fs-sm,12px);
    text-transform:uppercase;
    letter-spacing:var(--mp-ls-wider,0.08em);
    padding:10px 12px;
}

td{
    padding:5px 5px;
    border-top:1px solid var(--mpdg-fill-06);
}

tr:hover{background:var(--mpdg-fill-025)}

.module-table td{vertical-align:middle}

.admin-table td:last-child a{margin-right:8px}
.admin-table td:last-child a:last-child{margin-right:0}

/* ===== Table inline action links ===== */




/* ===== Module table helpers ===== */
.module-name{display:flex;flex-direction:column;gap:3px}
.module-name strong{color:var(--mpdg-ink-strong)}
.module-name span{color:var(--mpdg-ink-muted);font-size:var(--mp-fs-base,13px)}
.module-legacy-message{margin-top:7px;max-width:300px;line-height:var(--mp-lh-normal,1.4)}
.pending-migrations{margin-top:8px;font-size:var(--mp-fs-sm,12px);line-height:var(--mp-lh-normal,1.4);max-width:360px}

/* ===== Utility classes ===== */
.muted{color:var(--muted)}
.danger-text{color:var(--mpdg-danger)}
.inline{display:inline}


.module-table .module-package-cell{
    white-space:nowrap;
    vertical-align:middle;
}
.module-table .module-package-cell .action-download{width:max-content;}
.module-table th:nth-child(5),
.module-table td:nth-child(5){width:190px;}
.module-table th:nth-child(6),
.module-table td:nth-child(6){width:220px;}
@media(max-width:1200px){
    .module-table th:nth-child(5),
    .module-table td:nth-child(5),
    .module-table th:nth-child(6),
    .module-table td:nth-child(6){width:auto;}
}


/* ===== Responsive tables ===== */
/*
   Keep FullCalendar/calendar module tables untouched.
   FullCalendar renders structural tables (.fc-scrollgrid, .fc-col-header,
   .fc-scrollgrid-sync-table, .fc-list-table) inside #planner-calendar.
   The responsive data-table layer below deliberately excludes those tables.
*/
@media (max-width:999px){
    .card,
    .stat-card{
        padding:14px;
    }

    table:not(.fc-scrollgrid):not(.fc-col-header):not(.fc-scrollgrid-sync-table):not(.fc-list-table){
        width:max-content;
        min-width:100%;
        max-width:none;
        border:1px solid var(--mpdg-line-08);
        border-radius:5px;
        background:var(--mpdg-table-bg);
        box-shadow:0 16px 40px var(--mpdg-sh-18);
    }

    table:not(.fc-scrollgrid):not(.fc-col-header):not(.fc-scrollgrid-sync-table):not(.fc-list-table) th,
    table:not(.fc-scrollgrid):not(.fc-col-header):not(.fc-scrollgrid-sync-table):not(.fc-list-table) td{
        white-space:nowrap;
        padding:9px 10px;
    }

    table:not(.fc-scrollgrid):not(.fc-col-header):not(.fc-scrollgrid-sync-table):not(.fc-list-table) td:last-child,
    table:not(.fc-scrollgrid):not(.fc-col-header):not(.fc-scrollgrid-sync-table):not(.fc-list-table) th:last-child{
        padding-right:12px;
    }

    .task-actions,
    .row-actions,
    .table-actions,
    .mp-inline-actions{
        justify-content:flex-start;
    }



    .mp-calendar-wrap table,
    #planner-calendar table,
    .fc table{
        width:auto;
        min-width:0;
        max-width:none;
        overflow:visible;
        border:0;
        border-radius:0;
        background:transparent;
        box-shadow:none;
    }

    .mp-calendar-wrap th,
    .mp-calendar-wrap td,
    #planner-calendar th,
    #planner-calendar td,
    .fc th,
    .fc td{
        white-space:normal;
    }

    .admin-table td:last-child a,
    td a[href*="edit"],
    td a[href*="delete"],
    td a[href*="tasks/delete"],
    td a[href*="projects/delete"],
    td a[href*="admin/users/delete"],
    .mp-action-link,
    .task-action-btn,
    .row-action-btn,
    .table-action-btn{
        min-height:30px;
    }
}

@media (max-width:999px){
    table:has(td[data-label]):not(.fc-scrollgrid):not(.fc-col-header):not(.fc-scrollgrid-sync-table):not(.fc-list-table){
        display:block;
        overflow:visible;
        border:0;
        background:transparent;
        box-shadow:none;
    }

    table:has(td[data-label]):not(.fc-scrollgrid):not(.fc-col-header):not(.fc-scrollgrid-sync-table):not(.fc-list-table) thead{
        position:absolute;
        width:1px;
        height:1px;
        overflow:hidden;
        clip:rect(0 0 0 0);
        clip-path:inset(50%);
        white-space:nowrap;
    }

    table:has(td[data-label]):not(.fc-scrollgrid):not(.fc-col-header):not(.fc-scrollgrid-sync-table):not(.fc-list-table) tbody,
    table:has(td[data-label]):not(.fc-scrollgrid):not(.fc-col-header):not(.fc-scrollgrid-sync-table):not(.fc-list-table) tr,
    table:has(td[data-label]):not(.fc-scrollgrid):not(.fc-col-header):not(.fc-scrollgrid-sync-table):not(.fc-list-table) td{
        display:block;
        width:100%;
    }

    table:has(td[data-label]):not(.fc-scrollgrid):not(.fc-col-header):not(.fc-scrollgrid-sync-table):not(.fc-list-table) tr{
        margin:0 0 10px;
        padding:10px;
        border:1px solid var(--mpdg-line-09);
        border-radius:5px;
        background:linear-gradient(180deg,var(--mpdg-fill-045),var(--mpdg-fill-025));
        box-shadow:0 12px 28px var(--mpdg-sh-18);
    }

    table:has(td[data-label]):not(.fc-scrollgrid):not(.fc-col-header):not(.fc-scrollgrid-sync-table):not(.fc-list-table) tr:hover{
        background:linear-gradient(180deg,var(--mpdg-fill-06),var(--mpdg-fill-032));
    }

    table:has(td[data-label]):not(.fc-scrollgrid):not(.fc-col-header):not(.fc-scrollgrid-sync-table):not(.fc-list-table) td{
        position:relative;
        display:grid;
        grid-template-columns:minmax(100px,34%) 1fr;
        gap:10px;
        align-items:center;
        min-height:34px;
        padding:7px 3px;
        border-top:1px solid var(--mpdg-fill-06);
        white-space:normal;
        word-break:break-word;
    }

    table:has(td[data-label]):not(.fc-scrollgrid):not(.fc-col-header):not(.fc-scrollgrid-sync-table):not(.fc-list-table) td:first-child{
        border-top:0;
    }

    table:has(td[data-label]):not(.fc-scrollgrid):not(.fc-col-header):not(.fc-scrollgrid-sync-table):not(.fc-list-table) td::before{
        content:attr(data-label);
        color:var(--mpdg-ink-muted);
        font-size:var(--mp-fs-xs,11px);
        font-weight:var(--mp-fw-heavy,800);
        line-height:var(--mp-lh-snug,1.25);
        text-transform:uppercase;
        letter-spacing:var(--mp-ls-wide,0.04em);
    }

    table:has(td[data-label]):not(.fc-scrollgrid):not(.fc-col-header):not(.fc-scrollgrid-sync-table):not(.fc-list-table) td:last-child{
        padding-right:3px;
    }

    table:has(td[data-label]):not(.fc-scrollgrid):not(.fc-col-header):not(.fc-scrollgrid-sync-table):not(.fc-list-table) td:last-child .task-actions,
    table:has(td[data-label]):not(.fc-scrollgrid):not(.fc-col-header):not(.fc-scrollgrid-sync-table):not(.fc-list-table) td:last-child .row-actions,
    table:has(td[data-label]):not(.fc-scrollgrid):not(.fc-col-header):not(.fc-scrollgrid-sync-table):not(.fc-list-table) td:last-child .table-actions,
    table:has(td[data-label]):not(.fc-scrollgrid):not(.fc-col-header):not(.fc-scrollgrid-sync-table):not(.fc-list-table) td:last-child .mp-inline-actions{
        justify-content:flex-end;
    }

    table:has(td[data-label]):not(.fc-scrollgrid):not(.fc-col-header):not(.fc-scrollgrid-sync-table):not(.fc-list-table) .module-name,
    table:has(td[data-label]):not(.fc-scrollgrid):not(.fc-col-header):not(.fc-scrollgrid-sync-table):not(.fc-list-table) .module-legacy-message,
    table:has(td[data-label]):not(.fc-scrollgrid):not(.fc-col-header):not(.fc-scrollgrid-sync-table):not(.fc-list-table) .pending-migrations{
        max-width:none;
    }
}

@media (max-width:640px){
    table:has(td[data-label]):not(.fc-scrollgrid):not(.fc-col-header):not(.fc-scrollgrid-sync-table):not(.fc-list-table) td{
        grid-template-columns:1fr;
        gap:3px;
        align-items:start;
    }

    table:has(td[data-label]):not(.fc-scrollgrid):not(.fc-col-header):not(.fc-scrollgrid-sync-table):not(.fc-list-table) td:last-child .task-actions,
    table:has(td[data-label]):not(.fc-scrollgrid):not(.fc-col-header):not(.fc-scrollgrid-sync-table):not(.fc-list-table) td:last-child .row-actions,
    table:has(td[data-label]):not(.fc-scrollgrid):not(.fc-col-header):not(.fc-scrollgrid-sync-table):not(.fc-list-table) td:last-child .table-actions,
    table:has(td[data-label]):not(.fc-scrollgrid):not(.fc-col-header):not(.fc-scrollgrid-sync-table):not(.fc-list-table) td:last-child .mp-inline-actions{
        justify-content:flex-start;
    }
}

/* ===== Notice auto-dismiss state ===== */
.notice-card{
    transition:opacity .24s ease, transform .24s ease, max-height .28s ease, margin .28s ease, padding .28s ease, border-width .28s ease;
}

.notice-card.is-notice-expiring{
    opacity:0;
    transform:translateY(-6px);
    max-height:0!important;
    margin-top:0!important;
    margin-bottom:0!important;
    padding-top:0!important;
    padding-bottom:0!important;
    border-width:0!important;
    overflow:hidden!important;
    pointer-events:none;
}

/* ── Tabs ─────────────────────────────────────────────────────────────────────
   Underline tabs: a flex row of transparent buttons; the active tab gets a green
   underline and brighter text. Single shared definition so the mail template editor,
   the calendar's To-schedule drawer and any other surface use one source — consumers add
   their own container padding/background/flex where the layout needs it. */
.mp-tabs{
    display:flex;
    gap:4px;
    border-bottom:1px solid var(--border, var(--mpdg-ghost-14));
}
.mp-tab{
    background:transparent;
    border:0;
    border-bottom:2px solid transparent;
    cursor:pointer;
    color:var(--muted, var(--mpdg-ink-muted));
    font-size:var(--mp-fs-base,13px);
    font-weight:var(--mp-fw-semibold,600);
    padding:8px 6px 9px;
    transition:var(--transition, .15s ease);
}
.mp-tab:hover{ color:var(--text, var(--mpdg-ink-tab)); }
.mp-tab.is-active{ color:var(--text, var(--mpdg-ink-tab)); border-bottom-color:var(--green, var(--highlight)); }

/* Count inside a tab label. Lives here rather than in a consumer because a tab that reports how
   many rows it holds is the general shape, not a calendar detail — and the second copy of it is
   how two tab bars start looking almost the same. Inherits the tab's own colour so the active
   tab's count brightens with its label instead of needing a second active rule. */
.mp-tab-count{
    display:inline-block;
    margin-left:5px;
    min-width:16px;
    padding:0 5px;
    border-radius:999px;
    background:var(--mp-fill-09, rgba(255,255,255,.09));
    color:inherit;
    font-size:var(--mp-fs-2xs,10px);
    font-weight:var(--mp-fw-heavy,800);
    line-height:16px;
    text-align:center;
}

/* ===== Notice tone =====
   .notice-card had exactly one appearance, so any screen needing a banner that reads as good,
   cautionary or bad built its own. It belongs here: the surface is shared, only the accent
   differs, and a module-local copy of a shared surface is the thing that makes two screens look
   almost the same. Default (no data-tone) is unchanged. */
.notice-card[data-tone="good"]{border-color:var(--mp-hl-45);background:var(--mp-hl-075);}
.notice-card[data-tone="busy"]{border-color:var(--mp-blue-22);background:var(--mp-blue-10);}
.notice-card[data-tone="warn"]{border-color:var(--mp-yellow-28);background:var(--mp-yellow-10);}
.notice-card[data-tone="bad"]{border-color:var(--mp-red-26);background:var(--mp-red-10);}

/* ===== Shared data table (.mp-dtable) =====
   THE GRID'S SURFACE, FOR A TABLE THAT IS NOT THE GRID.

   mpdg is a <div> engine: it owns sorting, filtering, virtualisation and inline edit, and its
   frame is inseparable from that machinery. A screen that renders a genuine <table> — an aggregate
   with a tfoot, which mpdg has no concept of — could therefore either hand-roll a look that
   resembles the grid or become a grid it has no use for. Reports did the first, and the copy was
   already drifting: 10px against the grid's 14px corner, a 1px border in module CSS, and head cells
   at 12px/600 where every grid on the platform reads 11px/800.

   So the FRAME is named here and the ENGINE is left alone. The numbers below are data-grid.css's
   own — .mpdg-list's 14px and overflow, .mpdg-head's 44px and bottom rule, .mpdg-h's type — read off
   that file rather than invented, so the two surfaces move together. When the radius scale lands
   (see the register), this is one of the two places that changes, not one of seventeen.

   Tokens: the --mpdg-* primitives are declared on :root and html[data-mp-scheme="light"], NOT
   inside .mpdg, so they resolve here. The four semantic aliases ARE scoped to .mpdg, so they are
   restated on this root — deliberately from the same primitives, not from hardcoded colours. */
.mp-dtable{
    --mp-dtable-line:var(--mpdg-fill-07);
    --mp-dtable-line-strong:var(--mpdg-fill-10);
    --mp-dtable-surface:var(--mpdg-table-bg);
    --mp-dtable-row-hover:var(--mp-fill-025);
    width:100%;
    border:1px solid var(--mp-dtable-line-strong);
    border-radius:14px;
    background:var(--mp-dtable-surface);
    overflow:hidden;
}
html[data-mp-scheme="light"] .mp-dtable{
    --mp-dtable-row-hover:rgba(15,23,42,.03);
}

/* SEPARATE, NOT COLLAPSE, and the reason is the sticky head below. Under border-collapse:collapse
   a cell's borders belong to the TABLE's border grid rather than to the cell, so a sticky <thead>
   scrolls with its background and leaves its bottom rule behind on the first body row — the head
   detaches from its own hairline. With separate borders the cell owns its edge and travels with it.
   border-spacing:0 keeps the geometry identical to collapse. */
.mp-dtable table{width:100%;border-collapse:separate;border-spacing:0;font-size:var(--mp-fs-base,13px);}
.mp-dtable th,.mp-dtable td{padding:10px 14px;text-align:left;}

/* The head band: .mpdg-head's geometry and .mpdg-h's type, on a real <thead>. */
.mp-dtable thead th{
    height:44px;
    padding-top:0;
    padding-bottom:0;
    border-bottom:1px solid var(--mp-dtable-line-strong);
    background:var(--mpdg-deep-30);
    white-space:nowrap;
}
.mp-dtable-h{
    display:inline-flex;
    align-items:center;
    gap:7px;
    color:var(--mpdg-ink-muted);
    font-size:var(--mp-fs-xs,11px);
    font-weight:var(--mp-fw-heavy,800);
    text-transform:uppercase;
    letter-spacing:var(--mp-ls-wider,0.08em);
}
.mp-dtable-h .mp-icon{width:13px;height:13px;opacity:.8;}

/* ON THE CELLS, NOT ON THE ROW. A <tr> border is only painted under border-collapse:collapse; with
   separate it is silently dropped, so moving the table to separate above would have taken every row
   rule with it. Stated here rather than discovered on the screen. */
.mp-dtable tbody td,.mp-dtable tbody th{border-bottom:1px solid var(--mp-dtable-line);}
.mp-dtable tbody tr:hover td,.mp-dtable tbody tr:hover th{background:var(--mp-dtable-row-hover);}

/* A ROW HEADER IS DATA, NOT A HEADING, and this is the one rule the shared surface must carry
   rather than leave to its consumers. The theme ships a bare `th{}` — uppercase, muted, wide
   tracking — which is right for a column header and wrong for every <th scope="row">. Its
   specificity is one element, so a consumer overriding only colour and weight inherits the rest in
   silence: that is how the reports table rendered people's names as FREDERIC ROUCKHOUT beside an
   avatar of the same person the grids show in sentence case. Fixed once, here, so the next table to
   use this surface does not rediscover it. */
.mp-dtable tbody th{
    font-weight:var(--mp-fw-semibold,600);
    color:var(--text);
    font-size:var(--mp-fs-base,13px);
    text-transform:none;
    letter-spacing:var(--mp-ls-normal,0);
    min-width:0;
}

.mp-dtable tfoot th,.mp-dtable tfoot td{
    border-top:1px solid var(--mp-dtable-line-strong);
    font-weight:var(--mp-fw-bold,700);
    color:var(--text);
}
/* The last body row's rule would double with the foot's top rule. */
.mp-dtable tbody tr:last-child td,.mp-dtable tbody tr:last-child th{border-bottom:0;}

/* Numeric column: tabular figures so a column of durations lines up on the digit rather than on
   the glyph width. Without it "6h 20m" and "11h 05m" wander, and a column that wanders cannot be
   scanned. Named on the surface because every aggregate table wants it. */
.mp-dtable-num{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap;}

/* ===== Expander (.mp-dtable-expander) =====
   The grid's own disclosure affordance, for a table row that has children. Same 18px box and same
   caret mask the mpdg group heads use, so opening a company here and opening a group there are
   visibly the same gesture. Rotation is driven by aria-expanded rather than a class: the state is
   already in the attribute for assistive tech, and a second copy in a class is a second thing that
   can disagree with it. */
.mp-dtable-expander{
    display:inline-flex;
    align-items:center;
    justify-content:center;
    width:18px;
    height:18px;
    flex:0 0 18px;
    margin-right:2px;
    padding:0;
    border:0;
    border-radius:var(--radius,5px);
    background:none;
    color:var(--mpdg-ink-muted);
    cursor:pointer;
    transition:transform .12s ease,color .12s ease,background .12s ease;
}
.mp-dtable-expander:hover{color:var(--text);background:var(--mp-fill-09,rgba(255,255,255,.09));}
/* A row with no children keeps the slot so every name in the column starts on the same x. */
.mp-dtable-expander[data-empty]{visibility:hidden;pointer-events:none;}

/* Child rows. Indented under their parent and quieter than it — they are a partition of the row
   above, not peers of it.
   DEEPER LEVELS (.mp-dtable-child--2, --3) each sit one disclosure step further in. The step is
   what a row spends before its name on its expander slot: the 18px box, its 2px margin and a 9px
   gap. Every child row draws that slot (empty where there is nothing to open), so the padding is
   indent + (depth - 1) steps and each level's names start exactly one step past its parent's —
   depth, not a number somebody picked. Since v1.12.536 the second level carries a slot of its own
   (a project row opens onto its tasks), so it moved from two steps to one; its NAME did not move. */
.mp-dtable{--mp-dtable-child-indent:38px;--mp-dtable-child-step:29px;}
/* SCOPED UNDER .mp-dtable ON PURPOSE. Unscoped, this rule was (0,1,1) against the row-header rule
   `.mp-dtable tbody th` at (0,1,2), so its weight and colour never won anywhere: every child row
   rendered at the parent's 600 weight in text ink, and "quieter than it" was a comment, not a
   style (measured, v1.12.535). (0,2,1) outranks it on class count; no !important needed. */
.mp-dtable .mp-dtable-child > th{padding-left:var(--mp-dtable-child-indent);font-weight:var(--mp-fw-normal,400);color:var(--muted);}
.mp-dtable .mp-dtable-child--2 > th{padding-left:calc(var(--mp-dtable-child-indent) + var(--mp-dtable-child-step));}
.mp-dtable .mp-dtable-child--3 > th{padding-left:calc(var(--mp-dtable-child-indent) + 2 * var(--mp-dtable-child-step));}
.mp-dtable-child > td{color:var(--muted);}
.mp-dtable-child[hidden]{display:none;}

/* ===== A data table that owns its height (.mp-dtable.mp-page-fill-body) =====
   THE GRID'S FRAME CONTRACT, FOR A REAL <table>.

   mpdg gets this for free: .mpdg-list is a flex column and .mpdg-head is a SIBLING of .mpdg-rows,
   so bounding the card puts the header outside the scrolling region by construction — no sticky,
   no second element. A <table> cannot be taken apart that way without giving up the semantics that
   made it a table, and a tbody is not a flex item.

   So the scroller is the CARD and the head sticks inside it. One scroll container, one set of
   column widths, and thead/tfoot pinned to its edges. The row group scrolls between them.

   STICKY ON THE CELLS, NOT ON <thead>. Sticky applies to table SECTIONS only from a fairly recent
   Chrome, and never reliably to <tr>; the cell is the element every engine has honoured for years.
   z-index is stated because a sticky cell and a scrolled cell are in the same stacking context and
   the later one wins otherwise — the body would paint over the head it is scrolling under.

   NOT A SECOND FRAME CONTRACT. This borrows foundation's .mp-page-fill on the page root and only
   describes what the CARD does once the page is bounded; it declares no shell geometry, knows no
   rail width and no bar height, which is the coupling .mp-page-fill exists to prevent. */
/* SCOPED WITH :has(), AND THE FIRST CUT WAS NOT — which broke a page this file had never heard of.
   `.content > .mp-page-fill > *{flex-shrink:0}` reads like it is about tables and is about EVERY
   filling page on the platform: the projects chart took it, could no longer shrink, and overflowed
   its pane by 6082px at forty projects. projects_chart_fill_test caught it. A shared component may
   describe the page it is ON, never every page that asked foundation for the same contract.
   So the band rule applies only where a .mp-dtable is actually the remainder. */
.content > .mp-page-fill:has(> .mp-dtable) > *{flex-shrink:0;}
.content > .mp-page-fill:has(> .mp-dtable) > .mp-dtable{
    flex:1 1 auto;
    min-height:0;
    overflow:auto;
}

/* THE STICKY EDGES MUST BE OPAQUE OR THE ROWS TRAVEL THROUGH THEM, and neither token that paints
   this card is. --mpdg-table-bg is rgba(15,23,42,.34) and --mpdg-deep-30 is rgba(2,6,23,.30):
   correct while the head sits still on a card, a smear the moment anything scrolls underneath it.
   mpdg never hit this because its head is a SIBLING of the scroller and nothing passes behind it.

   So the opaque panel token goes underneath and the head's own tint is layered on top, which
   reproduces what the head looks like in place while guaranteeing nothing shows through. Two
   backgrounds in one declaration rather than a pseudo-element: a ::after would need a z-index
   against a sticky cell that is already its own stacking context, and negative z-index there
   paints behind the cell's own background instead of above it. */
.mp-dtable thead th{
    position:sticky;
    top:0;
    z-index:2;
    background:linear-gradient(var(--mpdg-deep-30),var(--mpdg-deep-30)),var(--mpdg-panel-solid);
}
.mp-dtable tfoot th,.mp-dtable tfoot td{
    position:sticky;
    bottom:0;
    z-index:2;
    background:var(--mpdg-panel-solid);
}

/* ---- Disclosure twist ---------------------------------------------------
   ONE CONTROL, DECLARED ONCE. A row that folds open shows a twist, and this component draws
   rows on two engines: the timeline's group header (.mpt-twist) and its capacity header
   (.mpt-cap-head) in timeline.css, the grid's row expander (.mpdg-expand) in data-grid.css.
   Each used to declare its own glyph, and the two agreed on nothing — 6px against 9px, a 1.5px
   stroke against 2px, pointing down by default against pointing right, and both drawn as a
   rotated box with two currentColor borders while modules/icons already shipped chevron-down.
   That is exactly how the Calendar and the Projects chart ended up with visibly different
   arrows: a glyph of the icon vocabulary living outside the registry cannot be kept consistent
   with the one the registry ships. Both engines now read that entry, and the turn is declared
   here rather than twice — component.css loads before either engine sheet, so this is the one
   place both can see.

   THE STATE IS THE BUTTON'S OWN aria-expanded. The grid's twist used to paint from
   .mpdg-row.is-open, a class on its ANCESTOR, while announcing its state on itself. One click
   handler sets both, so nothing was broken — but the Buttons registry makes the opposite case
   in its own source for btn--trigger, and it is the right one: hang the paint on the attribute
   assistive technology already reads and the two cannot drift. .is-open still shows and hides
   the detail panel; it no longer turns the glyph.

   Open points down, closed points right: chevron-down turned a quarter anticlockwise IS
   chevron-right — same path, same round caps — so one entry covers both states and the
   transition is free. */
/* The Reports table expander joins them. v1.12.508 folded three and said “one control,
   declared once”; there was a fourth, a few hundred lines above that rule in this same file.
   It escaped both probes — the ratchet counted glyphs drawn in currentColor borders and this
   one already read the registry, and the suite measured the timeline against the grid and never
   looked wider. It asked for chevron-right at 12px and turned the whole BUTTON ninety degrees,
   which also turned its hover background and its focus ring. */
.mpt-twist .mp-icon,
.mpt-cap-head .mp-icon,
.mpdg-expand .mp-icon,
.mp-dtable-expander .mp-icon{
    width:10px;
    height:10px;
    flex:0 0 10px;
    transition:transform .16s ease;
}
.mpt-twist[aria-expanded="false"] .mp-icon,
.mpt-cap-head[aria-expanded="false"] .mp-icon,
.mpdg-expand[aria-expanded="false"] .mp-icon,
.mp-dtable-expander[aria-expanded="false"] .mp-icon{
    transform:rotate(-90deg);
}
