/* Link this stylesheet from core/templates/core/base.html after core/app.css. */
.mz-panel{background:var(--mz-surface);border:1px solid var(--mz-border);border-radius:var(--mz-r-panel,8px);overflow:hidden}.mz-panel__row{padding:10px 14px;border-top:1px solid var(--mz-border)}.mz-panel__row:first-child{border-top:0}.mz-panel__row:hover{background:var(--mz-hover,rgba(255,255,255,.04))}
.mz-list{border-bottom:1px solid var(--mz-border)}.mz-list__row{padding:10px 2px;border-top:1px solid var(--mz-border)}.mz-panel .mz-list__row{padding-left:14px;padding-right:14px}.mz-panel>.mz-list{border-bottom:0}.mz-list__row:hover{background:var(--mz-hover,rgba(255,255,255,.04))}
/* A stat's own descriptive sub-line (core/ui/_stat.html), same tone/size as the other quiet
   meta text (.mz-row__meta, .mz-bound) rather than an inline var()-styled one-off. */
.mz-stat__sub{font-size:.78125rem;color:var(--mz-faint);margin-top:4px}
.mz-card--raised{background:var(--mz-surface);border:1px solid var(--mz-border);border-radius:var(--mz-r-panel,8px);box-shadow:0 18px 40px -28px #000}.mz-callout{background:var(--mz-surface-2);border:1px solid var(--mz-border);border-radius:var(--mz-r-panel,8px);font-size:.8125rem}
.mz-callout--proposed{background:color-mix(in srgb,var(--mz-warning) 8%,var(--mz-surface));border-color:color-mix(in srgb,var(--mz-warning) 35%,transparent)}
.mz-callout--danger{background:color-mix(in srgb,var(--mz-danger) 8%,var(--mz-surface));border-color:color-mix(in srgb,var(--mz-danger) 35%,transparent)}
/* A callout's own eyebrow wears MUTED, not faint: faint is tuned for --mz-surface and
   lands at 4.38:1 on a raised surface in the light theme, under the 4.5:1 AA floor for
   13px text. Muted holds 5.16:1 there and 10.76:1 in the dark theme. */
.mz-callout .mz-eyebrow{color:var(--mz-muted)}
.mz-eyebrow{font-family:var(--font-mono,ui-monospace,monospace);font-size:.6875rem;font-weight:500;letter-spacing:.12em;text-transform:uppercase;color:var(--mz-faint)}
.mz-tabs{display:flex;gap:2px;border-bottom:1px solid var(--mz-border);overflow-x:auto;overscroll-behavior-x:contain;scrollbar-width:none}.mz-tabs::-webkit-scrollbar{height:0}.mz-tab{display:inline-flex;align-items:baseline;gap:.35rem;padding:7px 10px;color:var(--mz-muted);font-size:.8125rem;font-weight:500;text-decoration:none;background:none;border:0;white-space:nowrap}
.mz-tab:hover{color:var(--mz-ink)}.mz-tab>.mz-tab__count{font-family:var(--font-mono,ui-monospace,monospace);font-size:.6875rem;color:var(--mz-faint);font-weight:500}.mz-tab[aria-current="page"]{color:var(--mz-ink);box-shadow:inset 0 -2px var(--mz-jade)}
/* A tab row that scrolls has to LOOK like it scrolls. Seven pod tabs on a 375px screen
   leave three off-screen, and `scrollbar-width:none` above means nothing says so - the row
   simply ends. The fade is a MASK rather than a gradient overlay, so it works over a panel
   and over the page ground alike, in both themes. base.html's kit script sets
   `data-mz-scroll` to whichever edges have content beyond them, so a row with nothing to
   scroll to carries no attribute and is not masked at all. */
.mz-tabs[data-mz-scroll]{--mz-tabs-fade-l:0px;--mz-tabs-fade-r:0px;
  -webkit-mask-image:linear-gradient(to right,transparent,#000 var(--mz-tabs-fade-l),#000 calc(100% - var(--mz-tabs-fade-r)),transparent);
  mask-image:linear-gradient(to right,transparent,#000 var(--mz-tabs-fade-l),#000 calc(100% - var(--mz-tabs-fade-r)),transparent)}
.mz-tabs[data-mz-scroll~="start"]{--mz-tabs-fade-l:1.75rem}
.mz-tabs[data-mz-scroll~="end"]{--mz-tabs-fade-r:1.75rem}
/* Pill tabs (DESIGN_SYSTEM.md Section 8: counted filter pills, e.g. "All - 214") are a
   FILTER control, not page navigation - they must not share .mz-tabs/.mz-tab (the
   underline tab-row is Section 7.4's second-level-navigation grammar). Discrete rounded
   pills in a wrapping row, matching the mocks. */
.mz-pilltabs{display:flex;flex-wrap:wrap;gap:6px}.mz-pilltab{display:inline-flex;align-items:center;gap:.35rem;height:26px;padding:0 10px;border-radius:999px;border:1px solid var(--mz-border-2);background:transparent;color:var(--mz-muted);font-size:.78125rem;font-weight:500;text-decoration:none;white-space:nowrap}
.mz-pilltab__count{font-family:var(--font-mono,ui-monospace,monospace);font-size:.6875rem;color:var(--mz-faint);font-weight:500}.mz-pilltab[aria-current="page"]{background:var(--mz-accent-soft);color:var(--mz-jade);border-color:color-mix(in srgb,var(--mz-jade) 45%,transparent)}.mz-pilltab[aria-current="page"] .mz-pilltab__count{color:var(--mz-jade)}
.mz-seg{display:inline-flex;padding:2px;gap:2px;border:1px solid var(--mz-border);border-radius:var(--mz-r-ctl,6px);background:var(--mz-surface-2)}.mz-seg__item{height:26px;padding:0 10px;border:0;border-radius:4px;background:transparent;color:var(--mz-muted);font:inherit;font-size:.78125rem;font-weight:500;line-height:1}.mz-seg__item:hover{color:var(--mz-ink)}.mz-seg__item[aria-current="true"]{background:var(--mz-surface);color:var(--mz-ink);box-shadow:0 0 0 1px var(--mz-border-2)}html[data-theme="mz-light"] .mz-seg__item[aria-current="true"]{box-shadow:0 1px 2px rgba(10,10,11,.08),0 0 0 1px var(--mz-border)}.mz-chip{display:inline-flex;align-items:center;gap:6px;height:26px;padding:0 9px;border:1px solid var(--mz-border-2);border-radius:var(--mz-r-ctl,6px);background:transparent;color:var(--mz-muted);font-size:.78125rem;font-weight:500;line-height:1;white-space:nowrap}.mz-chip:hover{color:var(--mz-ink);border-color:var(--mz-faint)}.mz-chip--on,.mz-chip--success{border-color:color-mix(in srgb,var(--mz-success) 45%,transparent);background:var(--mz-accent-soft);color:var(--mz-success)}.mz-chip--warning{border-color:color-mix(in srgb,var(--mz-warning) 45%,transparent);background:var(--mz-warning-soft);color:var(--mz-warning)}.mz-chip--danger{border-color:color-mix(in srgb,var(--mz-danger) 45%,transparent);background:var(--mz-danger-soft);color:var(--mz-danger)}.mz-chip--info{border-color:color-mix(in srgb,var(--mz-info) 45%,transparent);background:var(--mz-info-soft);color:var(--mz-info)}.mz-chip--applied{background:transparent;border-color:var(--mz-border-2);color:var(--mz-muted);font-weight:500}.mz-chip--applied:hover{color:var(--mz-ink)}
/* The Models roster's two row chips. LOCKED is the answer to "why is there no button on
   this row", so it has to read as a state rather than a label - solid accent fill and the
   padlock, never the neutral chip the roles use. ROLE is deliberately quieter and smaller:
   a row can carry three of them and three loud chips would outshout the model's own name,
   which is the thing the cell exists to say. */
.mz-chip--locked{border-color:color-mix(in srgb,var(--mz-jade) 45%,transparent);background:var(--mz-accent-soft);color:var(--mz-jade);font-size:.75rem;height:22px;padding:0 8px;gap:4px}
.mz-chip--role{border-color:var(--mz-border);background:transparent;color:var(--mz-muted);font-size:.75rem;font-weight:500;height:20px;padding:0 7px;gap:3px;margin-right:3px;margin-top:2px;border-radius:4px}
.mz-models-roles{display:flex;flex-wrap:wrap;align-items:center;gap:3px}
/* A segmented control with five choices is wider than a phone. Let the ROW wrap rather
   than the labels: on one line each choice keeps its natural width, and only a choice too
   wide for the line at all wraps its own text (the access page's sentence-long options).
   Unwrapped, "Built-in action" stacked three words deep and the last choice hung off the
   page. A fieldset defaults to min-inline-size:min-content, which is what stopped the
   group shrinking to its container at all. */
.mz-seg{flex-wrap:wrap;min-width:0;max-width:100%}
.mz-seg--scroll{flex-wrap:nowrap;overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain}
.mz-seg--scroll>.mz-seg__item{flex:none;white-space:nowrap}
fieldset:has(>.mz-seg){min-width:0}
/* A glossary definition is centred on the term it defines, which is right in the middle of
   a line and wrong at the end of one: a 19rem bubble on a term near the right edge of a
   375px screen hangs 84px off the page and gives the whole document a horizontal scrollbar
   while it is open. The bubble is clamped to the viewport here, and base.html's kit script
   sets `--mz-tip-shift` to nudge it back on screen when the centred position would leave
   it. The shift defaults to zero, so a definition with room stays exactly where it was.
   (A CLOSED bubble is not laid out at all - see the .tooltip rule in core/base.html.) */
.tooltip:has(>.mz-term)::before{max-width:min(19rem,calc(100vw - 2rem));
  transform:translateX(calc(-50% + var(--mz-tip-shift,0px)))}
/* The remove control inside a roster chip. Quiet until it is hovered or focused, and it
   takes the danger ink only then - a row of permanently red x's reads as an alarm. */
.mz-chip__x{display:grid;place-items:center;flex:none;width:1.25rem;height:1.25rem;border:0;border-radius:999px;background:none;color:var(--mz-faint);font:inherit;font-size:.75rem;line-height:1}
.mz-chip__x:hover,.mz-chip__x:focus-visible{color:var(--mz-danger);background:var(--mz-danger-soft)}
.mz-popover,.mz-picker{position:absolute;z-index:40;max-width:calc(100vw - 2rem);min-width:0;overflow-wrap:anywhere;padding:8px;background:var(--mz-surface-2);border:1px solid var(--mz-border-2);border-radius:var(--mz-r-panel,8px);box-shadow:0 20px 50px -18px #000;font-size:.8125rem}.mz-picker{min-width:min(16rem,calc(100vw - 2rem))}.mz-hintbar{font-family:var(--font-mono,ui-monospace,monospace);font-size:.6875rem;color:var(--mz-faint)}.mz-hintbar{display:flex;justify-content:space-between;padding:8px 4px 0;border-top:1px solid var(--mz-border)}
.mz-picker [role="option"]{border-radius:var(--mz-r-ctl,6px)}.mz-picker [role="option"]:hover,.mz-picker [role="option"].mz-token-active{background:var(--mz-accent-soft)}
.mz-drawer{position:fixed;z-index:60;inset:0 0 0 auto;display:flex;flex-direction:column;width:min(560px,100%);background:var(--mz-surface);border-left:1px solid var(--mz-border-2);box-shadow:-30px 0 80px -30px #000}.mz-drawer__body{flex:1;overflow-y:auto}.mz-drawer__body{min-width:0;overflow-wrap:anywhere}.mz-modal{position:fixed;z-index:60;top:12vh;left:50%;width:min(640px,92vw);max-height:76vh;overflow-y:auto;min-width:0;overflow-wrap:anywhere;transform:translateX(-50%);background:var(--mz-surface);border:1px solid var(--mz-border-2);border-radius:var(--mz-r-panel,8px);box-shadow:0 40px 100px -30px #000}.mz-toast{position:fixed;z-index:70;bottom:26px;left:50%;max-width:min(560px,92vw);min-width:0;overflow-wrap:anywhere;transform:translateX(-50%);padding:8px 14px;font-size:.8125rem;background:var(--mz-surface-2);border:1px solid color-mix(in srgb,var(--mz-jade) 30%,transparent);border-radius:var(--mz-r-panel,8px)}.mz-overlay-scrim{position:fixed;z-index:55;inset:0;background:color-mix(in srgb,#000 60%,transparent)}
.mz-diff{font: .78125rem/1.7 var(--font-mono,ui-monospace,monospace);padding:10px;border-radius:var(--mz-r-panel,8px)}.mz-diff--del{background:color-mix(in srgb,var(--mz-danger) 5%,transparent);border:1px solid color-mix(in srgb,var(--mz-danger) 20%,transparent);color:var(--mz-danger)}.mz-diff--add{background:color-mix(in srgb,var(--mz-jade) 5%,transparent);border:1px solid color-mix(in srgb,var(--mz-jade) 22%,transparent);color:var(--mz-jade)}.mz-document-diff{padding:16px;border:1px solid color-mix(in srgb,var(--mz-jade) 22%,transparent);border-radius:var(--mz-r-panel,8px);background:color-mix(in srgb,var(--mz-jade) 5%,transparent);color:var(--mz-ink)}.mz-document-diff ins{color:var(--mz-jade)}.mz-document-diff del{color:var(--mz-danger)}.mz-prov{border-left:1px solid var(--mz-border-2);padding-left:16px}.mz-bound{font-size:.78125rem;color:var(--mz-faint)}.mz-pager{display:inline-flex;gap:4px;align-items:center}.mz-pager a,.mz-pager button{display:inline-flex;align-items:center;height:24px;padding:0 7px;border:1px solid var(--mz-border-2);border-radius:var(--mz-r-ctl,6px);background:var(--mz-surface-2);color:var(--mz-ink);font-size:.78125rem;line-height:1}.mz-pager a:hover,.mz-pager button:hover:not(:disabled){border-color:var(--mz-faint)}.mz-pager button:disabled,.mz-pager [aria-disabled="true"]{color:var(--mz-faint);border-color:var(--mz-border);pointer-events:none}.mz-empty{padding:28px 20px;color:var(--mz-faint);font-size:.84375rem;text-align:center;border:1px dashed var(--mz-border-2);border-radius:var(--mz-r-panel,8px)}.mz-panel :where(.mz-empty){border:0;border-radius:0}.mz-swatch{width:8px;height:8px;border-radius:2px;background:var(--mz-jade);display:inline-block}.mz-check{width:15px;height:15px;accent-color:var(--mz-jade)}.mz-toggle{width:30px;height:18px;accent-color:var(--mz-jade)}
/* ---------------------------------------------------------------------------
   Motion + interaction layer (DESIGN_SYSTEM.md Section 4 Motion, Section 7).

   Four tokens carry every transition in the product shell, defined once in the
   base token block: --mz-ease-out (the signature curve), --mz-t-fast (hover ink),
   --mz-t-med (chips, tabs, toggles, row chevrons), --mz-t-panel (things that
   ARRIVE - drawers, popovers, accordions, toasts). The fallback values here are
   the documented ones, so this stylesheet still reads and renders standalone.

   A workspace is not a landing page: nothing scroll-reveals, nothing overshoots,
   and CONTENT never animates - a count that changes is content, not chrome. Each
   rule below is either a hover/selection transition or a one-shot entrance on
   something the user just opened.
   --------------------------------------------------------------------------- */
.mz-tab{transition:color var(--mz-t-fast,.15s) ease,box-shadow var(--mz-t-med,.22s) var(--mz-ease-out,cubic-bezier(.22,.9,.3,1))}
.mz-pilltab{transition:background var(--mz-t-med,.22s) var(--mz-ease-out,cubic-bezier(.22,.9,.3,1)),border-color var(--mz-t-fast,.15s) ease,color var(--mz-t-fast,.15s) ease}
.mz-pilltab:hover:not([aria-current]){color:var(--mz-ink);border-color:var(--mz-border-2)}
.mz-chip,.mz-seg__item,.mz-pill,.mz-pager a,.mz-pager button{transition:color var(--mz-t-fast,.15s) ease,border-color var(--mz-t-fast,.15s) ease,background var(--mz-t-med,.22s) var(--mz-ease-out,cubic-bezier(.22,.9,.3,1))}
.mz-list__row,.mz-panel__row{transition:background var(--mz-t-fast,.15s) ease}
/* Things that arrive. A server-rendered overlay is present on first paint, so the
   entrance is an animation (a transition has no prior state to move from). */
@keyframes mzPanelIn{from{opacity:0;transform:translateX(12px)}to{opacity:1;transform:translateX(0)}}
@keyframes mzScrimIn{from{opacity:0}to{opacity:1}}
@keyframes mzPopIn{from{opacity:0;transform:scale(.98)}to{opacity:1;transform:scale(1)}}
@keyframes mzToastIn{from{opacity:0;transform:translate(-50%,10px)}to{opacity:1;transform:translate(-50%,0)}}
@keyframes mzModalIn{from{opacity:0;transform:translateX(-50%) scale(.98)}to{opacity:1;transform:translateX(-50%) scale(1)}}
@keyframes mzRevealIn{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}
.mz-drawer{animation:mzPanelIn var(--mz-t-panel,.3s) var(--mz-ease-out,cubic-bezier(.22,.9,.3,1)) both}
.mz-overlay-scrim{animation:mzScrimIn var(--mz-t-panel,.3s) ease both}
.mz-popover,.mz-picker{transform-origin:top right;animation:mzPopIn var(--mz-t-panel,.3s) var(--mz-ease-out,cubic-bezier(.22,.9,.3,1)) both}
.mz-modal{animation:mzModalIn var(--mz-t-panel,.3s) var(--mz-ease-out,cubic-bezier(.22,.9,.3,1)) both}
.mz-toast{animation:mzToastIn var(--mz-t-panel,.3s) var(--mz-ease-out,cubic-bezier(.22,.9,.3,1)) both}
/* Disclosure: the chevron rotation lives with summary.mz-summary; the revealed body
   fades down. Height is not animated - a details element has no measurable target
   height without script, and a half-measured collapse is worse than none. */
details[open]>:not(summary){animation:mzRevealIn var(--mz-t-panel,.3s) var(--mz-ease-out,cubic-bezier(.22,.9,.3,1)) both}
/* One-time reveal for content that just appeared and is not a disclosure (a freshly
   completed run's findings list, DESIGN_SYSTEM.md Section 7.8) - the SAME shared
   keyframe as the disclosure reveal above, applied without a per-child stagger: every
   element carrying this class animates together, not in sequence. */
.mz-reveal-once{animation:mzRevealIn var(--mz-t-panel,.3s) var(--mz-ease-out,cubic-bezier(.22,.9,.3,1)) both}
/* Glossary term ({% help_term %}, core/templatetags/mosaic_help.py). A <button> painted
   back into prose, so the definition is reachable by keyboard and under a finger rather
   than by hover alone. The underline wears an ink token: `border-dotted` on its own
   inherits preflight's grey, which reads on the dark shell and disappears on paper. */
.mz-term{font:inherit;color:inherit;background:none;border:0;padding:0;border-bottom:1px dotted var(--mz-faint);cursor:help}
.mz-term:hover{border-bottom-color:var(--mz-ink)}
/* DaisyUI reveals a tooltip on :hover and on :focus-visible. A TAP fires focus without
   focus-visible, so without this a touch reader can reach the term and still not see the
   definition - the one audience most likely to have no hover at all. */
.tooltip:focus-within:before,.tooltip:focus-within:after{opacity:1;transition-delay:75ms}
/* ---------------------------------------------------------------------------
   Row grammar (DESIGN_SYSTEM.md Section 7.5 + Section 7.6). One list row reads:
   kind bubble / title + meta line of middot-separated plain words / a
   right-aligned verdict + why line / a chevron where the row opens something.
   Sizes come from Section 7.6's mapping (13.5px title, 12.5px meta).
   --------------------------------------------------------------------------- */
.mz-row{display:flex;align-items:center;gap:12px}
.mz-tile{width:28px;height:28px;flex:none;border-radius:var(--mz-r-ctl,6px);display:grid;place-items:center;font-size:.75rem;border:1px solid transparent}
.mz-tile--jade{background:var(--mz-accent-soft);color:var(--mz-accent)}
.mz-tile--amber{background:var(--mz-warning-soft);color:var(--mz-warning)}
.mz-tile--lapis{background:var(--mz-info-soft);color:var(--mz-info)}
.mz-tile--coral{background:var(--mz-danger-soft);color:var(--mz-danger)}
.mz-tile--muted{background:var(--mz-surface-2);color:var(--mz-faint);border-color:var(--mz-border)}
.mz-row__main{flex:1;min-width:0}
.mz-row__title{display:block;font-size:.84375rem;font-weight:500;line-height:1.35;color:var(--mz-ink)}
.mz-row__meta{display:block;margin-top:1px;font-size:.78125rem;line-height:1.45;color:var(--mz-faint)}
.mz-row__aside{flex:none;text-align:right;max-width:15rem}
.mz-row__verdict{display:block;font-size:.78125rem;font-weight:500;line-height:1.4;color:var(--mz-accent)}
.mz-row__verdict--muted{color:var(--mz-faint);font-weight:500}
.mz-row__why{display:block;margin-top:2px;font-size:.78125rem;line-height:1.4;color:var(--mz-faint)}
.mz-row__chev{flex:none;font-size:.625rem;color:var(--mz-faint);transition:transform var(--mz-t-med,.22s) var(--mz-ease-out,cubic-bezier(.22,.9,.3,1)),color var(--mz-t-fast,.15s) ease}
/* The whole row is the affordance: hover moves the chevron rather than the row. */
a:hover>.mz-row__chev,a:hover .mz-row__chev,.mz-row:hover>.mz-row__chev{transform:translateX(2px);color:var(--mz-muted)}
/* ---------------------------------------------------------------------------
   The data table (DESIGN_SYSTEM.md Section 13) - toolbar, sortable header,
   bounded footer. Layered ON TOP of daisyUI's .table, which base.html already
   gives the 13px smallcaps header row, hairline row borders and the hover
   tint: the kit adds only what a sortable, searchable, bounded table needs, so
   there is one table look in the product rather than two.
   --------------------------------------------------------------------------- */
/* A component class ships its own `display`, which beats the plain `[hidden]` attribute
   on specificity ties by source order - so anything the kit's progressive enhancement
   hides (the no-JS Apply button most visibly) stayed on screen. One rule, because the
   attribute is meant to be absolute. */
[hidden]{display:none!important}
.mz-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:8px}
.mz-toolbar__search{flex:1 1 16rem;min-width:11rem;max-width:20rem}
/* Sort sits at the right end of the row, after the filters (Section 8.1's fixed
   order: free text, filters, then sort/density). */
.mz-toolbar__end{margin-left:auto;display:flex;flex-wrap:wrap;align-items:center;gap:8px}
.mz-search{position:relative;display:block}
.mz-search input[type=search]{padding-right:2.75rem}
/* The browser's own cancel affordance is a 10px unlabelled glyph that only some
   engines draw; ours is a real button with a name and a 44px target. */
.mz-search input[type=search]::-webkit-search-cancel-button{display:none}
.mz-search__clear{position:absolute;top:50%;right:1px;transform:translateY(-50%);display:grid;place-items:center;min-width:32px;min-height:32px;border:0;background:none;color:var(--mz-faint);border-radius:var(--mz-r-ctl,6px);line-height:1}
.mz-search__clear:hover{color:var(--mz-ink)}
/* Sortability has to be VISIBLE: an inactive sortable column carries a dim double
   chevron, the active one a single accent chevron. Inline SVG, never an icon font -
   a webfont 404 turned half the reference implementation into tofu. */
.mz-datatable__sort{display:inline-flex;align-items:center;gap:5px;color:inherit;text-decoration:none}
.mz-datatable__sort:hover{color:var(--mz-ink)}
.mz-sortmark{flex:none;width:8px;height:11px;opacity:.4;transition:opacity var(--mz-t-fast,.15s) ease}
.mz-datatable__sort:hover .mz-sortmark{opacity:.7}
.mz-sortmark--active{opacity:1;color:var(--mz-jade)}
.mz-cell--right{text-align:right}
.mz-cell--center{text-align:center}
/* "Page 2 of 7" between the arrows - the third question the footer answers. */
.mz-pager__at{align-self:center;color:var(--mz-faint)}
/* An applied chip is the whole hit area (the x is a label, not a second target), so
   the chip itself carries the touch floor and the x widens it to 44px without
   changing how big the chip looks. */
.mz-chip--applied{min-height:34px}
.mz-chip__x{position:relative;display:inline-flex;align-items:center;justify-content:center;min-width:1.25rem;line-height:1}
.mz-chip__x::after{content:"";position:absolute;top:50%;left:50%;width:44px;height:44px;transform:translate(-50%,-50%)}
/* A filter trigger goes accent-styled when its panel is OPEN as well as when it holds a
   selection (.mz-chip--on), so the control that owns the open panel is never ambiguous.
   The panels themselves start collapsed even with filters applied - the chips row is the
   always-visible truth about what is narrowing the table. */
.mz-chip[aria-expanded=true]{border-color:var(--mz-jade);color:var(--mz-jade)}
/* Facet options past the panel's cap wait behind its own search box. */
.mz-facet__more{display:block;width:100%;margin-top:6px;padding:4px 0;border:0;background:none;color:var(--mz-accent);font-size:.78125rem;font-weight:500;text-align:left}
/* A quiet sticky action bar for a bulk selection - secondary weight, because the
   per-item flow is the primary one (DESIGN_SYSTEM.md Section 8.2: one primary). */
.mz-bulkbar{position:sticky;bottom:14px;z-index:20;display:flex;flex-wrap:wrap;align-items:center;gap:12px;margin-top:14px;padding:8px 12px;background:var(--mz-surface-2);border:1px solid var(--mz-border-2);border-radius:var(--mz-r-panel,8px);box-shadow:0 18px 40px -28px #000;font-size:.8125rem}
.mz-bulkbar[hidden]{display:none}

/* ---------------------------------------------------------------------------
   Charts (DESIGN_SYSTEM.md Section 6.2). The canvas needs an explicit box -
   Chart.js sizes to its parent, and a parent with no height collapses to zero
   on first paint and then never recovers. Held by aspect-ratio rather than a
   fixed pixel height so it keeps its proportions down to the mobile column.
   Series colours are NOT here: they resolve from the tokens in
   core/usage_charts.js, so light theme is free and there is one palette.
   --------------------------------------------------------------------------- */
.mz-chart{position:relative;width:100%;aspect-ratio:16/6;min-height:200px}
.mz-chart--tall{aspect-ratio:16/9;min-height:260px}
.mz-chart[hidden]{display:none}
.mz-chart>canvas{position:absolute;inset:0}
/* The chart legend is real HTML, not a canvas-drawn one, so each series toggle is a named,
   keyboard-reachable, instrumentable control. Off state dims the swatch, never the word. */
.mz-legend{display:flex;flex-wrap:wrap;gap:14px;align-items:center}
.mz-legend__item{display:inline-flex;align-items:center;gap:6px;padding:2px 0;border:0;background:none;color:var(--mz-muted);font:inherit;font-size:.75rem;font-weight:500}
.mz-legend__item:hover{color:var(--mz-ink)}
.mz-legend__item[hidden]{display:none}
.mz-legend__swatch{width:12px;height:3px;border-radius:2px;background:var(--mz-jade);flex:none}
.mz-legend__swatch--muted{background:var(--mz-chart-mute);height:0;border-top:2px dashed var(--mz-chart-mute)}
.mz-legend__item[aria-pressed="false"]{color:var(--mz-faint)}
.mz-legend__item[aria-pressed="false"] .mz-legend__swatch{opacity:.3}
/* A ranked value row beside the chart: the numbers, the keyboard path to a focus drill, and
   what a screen reader reads. No bar - the canvas draws the bars, this row states the facts. */
.mz-valuerow{display:flex;align-items:baseline;gap:10px;padding:8px 4px;border-top:1px solid var(--mz-border);font-size:.8125rem}
.mz-valuerow:first-child{border-top:0}
.mz-valuerow__label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--mz-ink)}
.mz-valuerow__val{flex:none;font-variant-numeric:tabular-nums;font-weight:600;color:var(--mz-ink)}
.mz-valuerow__pct{flex:none;width:3.5rem;text-align:right;font-variant-numeric:tabular-nums;font-size:.78125rem;color:var(--mz-faint)}
.mz-valuerow--rollup .mz-valuerow__label,.mz-valuerow--rollup .mz-valuerow__val{color:var(--mz-chart-mute)}
a.mz-valuerow{text-decoration:none}
a.mz-valuerow:hover{background:color-mix(in srgb,var(--mz-ink) 3%,transparent)}
a.mz-valuerow:hover .mz-valuerow__label{color:var(--mz-jade)}
.mz-valuerow[aria-current="true"] .mz-valuerow__label{color:var(--mz-jade);font-weight:600}
/* The focus banner: what the page is narrowed to, and the way out, in one line. Lapis
   (informational), never amber - a focus is a choice the reader made, not a warning. */
.mz-focusbar{display:flex;flex-wrap:wrap;align-items:center;gap:10px;padding:8px 12px;border-radius:var(--mz-r-panel,8px);background:var(--mz-info-soft);border:1px solid color-mix(in srgb,var(--mz-info) 26%,transparent);font-size:.8125rem;color:var(--mz-ink)}
#custom-servers .mz-hint.truncate{white-space:normal;overflow:visible;text-overflow:clip;overflow-wrap:anywhere}

@media (prefers-reduced-motion:reduce){.mz-drawer,.mz-modal,.mz-toast,.mz-toasts .mz-toast,.mz-popover,.mz-picker,.mz-overlay-scrim,details[open]>:not(summary),.mz-reveal-once{animation:none!important}
  .mz-tab,.mz-pilltab,.mz-chip,.mz-seg__item,.mz-pill,.mz-pager a,.mz-pager button,.mz-list__row,.mz-panel__row,.mz-row__chev,.mz-sortmark{transition:none!important}
  a:hover>.mz-row__chev,a:hover .mz-row__chev,.mz-row:hover>.mz-row__chev{transform:none}}

/* Phone: a list row stacks instead of competing for one line.
   `.mz-row` is a single flex line with `.mz-row__aside` at `flex:none;max-width:15rem`,
   so on a 390px screen the aside claimed up to 240px and left the TITLE about 54px - the
   one thing the reader is scanning for was the one thing clipped. Wrapping the aside onto
   its own line gives the title the full width and costs nothing but vertical space, which
   is the dimension a phone has. */
@media (max-width:640px){
  /* Stepper labels are sized by the step, not by the word, so the longest one is clipped
     on a narrow screen. Let them wrap and sit a size down rather than lose their ends. */
  .step{font-size:.75rem;line-height:1.2;white-space:normal;word-break:break-word}
  .mz-row{flex-wrap:wrap}
  .mz-row__main{flex:1 1 60%}
  .mz-row__aside{flex:1 1 100%;max-width:none;text-align:left;margin-top:6px}
  /* Once the aside takes a whole line the chevron has nothing left to share one with, so
     it wrapped onto a line of its own - a dead row of vertical space per item, and on the
     review queue that is one per proposal. It is aria-hidden decoration and the whole row
     is the link, so a phone simply does without it. `--fa-display` is set as well as
     `display`, because the icon font's own rule loads after this sheet and wins on equal
     specificity - that variable is the seam Font Awesome provides for exactly this. */
  .mz-row__chev{--fa-display:none;display:none}
  /* A tab strip wraps rather than scrolls: a pod's seven tabs showed four, and the edge
     fade was too faint to say there were three more. Two short rows beat hidden tabs. */
  .mz-tabs{flex-wrap:wrap;overflow-x:visible;-webkit-mask-image:none;mask-image:none}
}
/* A document title in a knowledge list wraps rather than truncating: on a phone the
   'Core - ' prefix left most titles as 'Core - Commercial an...', which says nothing. */
.mz-title-wrap{white-space:normal;overflow-wrap:anywhere}

/* THE TOUCH FLOOR, IN ONE PLACE. Every control the kit ships reaches a 44px hit area on a
   finger. This is deliberately keyed on the INPUT DEVICE rather than on width: a narrow
   desktop window still gets the compact rhythm the tables and toolbars were designed for,
   and a tablet in landscape still gets the target. It is also deliberately ONE rule rather
   than padding added per template - a sweep found 57 controls under 40px on a single
   screen, and patching them one surface at a time guarantees the next surface starts
   under the floor again.

   Two mechanisms, and which one applies is about what the control IS. A button or a field
   OWNS its box, so it simply grows. A tab, a sort link or a chip's x is a word inside a
   line of other words, and growing its box would push that line apart - those get a
   centred pseudo-element that widens the hit area and changes nothing you can see (the
   .mz-chip__x pattern above, which this generalises). Replaced controls - a checkbox, a
   radio, a toggle - can carry neither: a pseudo-element does not render on them and a
   44px box draws a 44px checkbox. They grow modestly, and the LABEL that wraps them takes
   the floor instead, which is the house pattern and the real target anyway.

   The `!important` on the button and field floors is deliberate: core/base.html pins
   `.btn`/`.input` heights in a style block that loads after this one and with higher
   specificity, so a plain rule here loses silently. A floor that the next sizing tweak can
   out-specify is not a floor. */
@media (pointer:coarse){
  .btn,.select,.textarea,.input,.mz-seg__item,.mz-summary{min-height:2.75rem!important}
  .btn.btn-square{min-width:2.75rem!important}
  button.mz-chip,a.mz-chip{min-height:2.75rem}
  .mz-tab,.mz-datatable__sort,.mz-pilltab,.mz-pager a,.mz-pager button{position:relative}
  .mz-tab::after,.mz-datatable__sort::after,.mz-pilltab::after,
  .mz-pager a::after,.mz-pager button::after{content:"";position:absolute;top:50%;left:50%;
    width:100%;height:2.75rem;min-width:2.75rem;transform:translate(-50%,-50%)}
  .mz-toggle,.mz-check,.checkbox,.radio,.toggle{min-width:1.5rem;min-height:1.5rem}
  label:has(>.checkbox),label:has(>.radio),label:has(>.mz-check),
  label:has(>.toggle),label:has(>.mz-toggle){min-height:2.75rem}
}
