/* =============================================================================
 * Atlas Cloud Tools — the platform COMPONENTS. ACT-87.
 *
 * CANONICAL COPY. scripts\Sync-AtlasTokens.ps1 copies it into every tool;
 * -Check fails on drift. Edit here, never in a copy.
 *
 * WHY THIS FILE EXISTS
 * The busy overlay, the platform dropdown, the platform calendar and the
 * session warning are PLATFORM components: their behaviour is in
 * UnifiedLogin/shared and has been synced to every app for months. Their PAINT
 * was not. It lived in atlas-theme.css, which only the Bootstrap-shaped tools
 * take — so each React app carried its own copy in index.css, byte-identical
 * and separately maintained. Three copies that agree today and drift the moment
 * one is touched, which is exactly what kept happening.
 *
 * A token is not a design system; a component is. Behaviour and paint ship
 * together now, to all six tools, from one file.
 *
 * Load order: atlas-tokens.css, then this, then the app's own stylesheet.
 * ========================================================================== */



/* --- Navigation busy overlay ---------------------------------------------------
 * A tab is a routed page, so switching one is a round trip and the screen sits
 * still while it happens. With nothing moving a slow tab reads as a frozen app,
 * and the natural response is to click again — which queues a second round trip
 * behind the first. The overlay swallows those clicks.
 *
 * IT COVERS THE CONTENT, NOT THE CHROME. It starts below the app bar and stops
 * above the footer, so the company switcher and Return to Tools stay live while
 * a page loads — they are the two things a user reaches for when a screen is
 * taking too long.
 *
 * NO SCRIM AND NO FADE. A translucent layer over the whole page, animating in
 * and straight back out on a quick navigation, read as the page flashing. The
 * overlay is invisible: the spinner and the cursor say what is happening, and
 * nothing under them changes appearance at all. */
.atlas-busy {
    position: fixed;
    /* The whole viewport, and the chrome is lifted OVER it below. It used to be
       inset by --app-bar-h and --app-footer-h, which only lines up while those
       tokens match the header and footer a given tool actually renders — when
       they do not, the scrim starts below the tab strip and the dim looks like
       it has slipped down the page. */
    inset: 0;
    z-index: 3000;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: progress;
    /* A translucent scrim. It was deliberately invisible once, on the argument
       that a layer flashing in and out on a quick navigation read as the page
       blinking — but the 250ms delay before the overlay appears already covers
       that, and with nothing behind it the spinner was easy to miss against a
       busy screen. The page dims, the spinner sits on it, and it is obvious
       that the screen is not accepting input. */
    background: rgba(31, 41, 55, 0.22);
}


.atlas-busy__spinner {
    width: 122px;
    height: 122px;
    border-radius: 50%;
    border: 11px solid var(--color-border);
    border-top-color: var(--color-action-ink);
    animation: atlas-busy-spin 700ms linear infinite;
}


/* The word, in the middle of the ring. Obvious to most, but a spinner alone
   still asks the reader to interpret it, and this costs nothing. It rides on
   the overlay rather than inside the spinner — the spinner is rotating. */
.atlas-busy::after {
    content: "Loading";
    position: absolute;
    font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
    font-size: 15px;
    font-weight: 600;
    letter-spacing: 0.01em;
    color: var(--color-action-ink);
    pointer-events: none;
}


@keyframes atlas-busy-spin {
    to { transform: rotate(360deg); }
}


/* ONLY WHILE THE OVERLAY IS UP.
   Lifting the bar permanently gave .header-wrapper a z-index, and a z-index on
   a positioned element makes it a STACKING CONTEXT: every z-index inside it is
   then scoped to it. BIReports' hamburger is absolutely positioned at 1101 and
   had been winning against .header-left across the whole page; confined to the
   new context it lost, and the button stopped taking clicks — the nav opened on
   load and could not be reopened after a collapse. The lift only matters while
   there is a scrim to sit above, so it only applies then. */
body:has(.atlas-busy) :is(.app-header, .header-wrapper, .header-content, .header-inner, .app-bar) {
    z-index: 3100 !important;
}


body:has(.atlas-busy) :is(.app-footer, .main-content-area > footer) {
    position: relative;
    z-index: 3100;
}



/* --- The platform dropdown ------------------------------------------------------
 * atlas-select.js replaces a native <select>'s popup with this markup, because a
 * closed select's popup is drawn by the OS and its highlighted row is the system
 * accent — the white-on-blue band. No CSS reaches that: not option:hover, not
 * option:checked, not color-scheme. Where the markup is already <fluent-select>
 * atlas-fluent.css paints it; this covers the markup that is still native and
 * the browsers where the script has not run.
 *
 * Same three colours as every other list: the surface at rest, --color-surface-3
 * on hover, --color-surface-2 when chosen. */
/* align-self: center for the same reason .atlas-menu has it: the popup is
   positioned against THIS box, and a wrapper that stretches to a tall flex row
   opens the list below the control rather than against it. */
.atlas-select-wrap { position: relative; display: inline-block; align-self: center; }


/* Clipped rather than display:none, so the select still posts, still raises
   change, and can still take focus for validation. */
.atlas-select-native {
    position: absolute;
    width: 1px; height: 1px;
    margin: 0; padding: 0; border: 0;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    overflow: hidden;
    white-space: nowrap;
}


.atlas-select-button {
    display: inline-flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--control-gap);
    width: 100%;
    min-height: var(--control-h);
    padding: var(--control-pad-y) var(--control-pad-x-tight);
    font-family: inherit;
    font-size: var(--font-size-control);
    line-height: 1.4;
    text-align: left;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-sm);
    background: var(--color-surface);
    color: var(--color-text);
    cursor: pointer;
    box-shadow: none;
}


.atlas-select-button:hover { background: var(--color-surface-3); border-color: var(--color-border-strong); color: var(--color-text-strong); }

.atlas-select-button:focus-visible { outline: var(--focus-ring-w) solid var(--color-focus-ring); outline-offset: var(--focus-ring-offset); }

.atlas-select-button:disabled { background: var(--color-disabled); border-color: var(--color-disabled); color: var(--color-disabled-fg); cursor: not-allowed; }


.atlas-select-value { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }


.atlas-select-caret {
    flex: 0 0 auto;
    width: 0; height: 0;
    border-left: 4px solid transparent;
    border-right: 4px solid transparent;
    border-top: 5px solid currentColor;
}


.atlas-select-list {
    position: absolute;
    z-index: 1080;              /* above a Bootstrap modal's backdrop */
    top: calc(100% + var(--popup-gap));
    left: 0;
    min-width: 100%;
    max-height: 280px;
    overflow-y: auto;
    margin: 0;
    padding: 4px 0;
    list-style: none;
    background: var(--color-surface);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-sm);
    box-shadow: 0 4px 12px rgba(0, 0, 0, .14);
}


.atlas-select-wrap.is-up .atlas-select-list { top: auto; bottom: calc(100% + var(--popup-gap)); }


/* display: block, so a row is a row whatever element it is written on.
   atlas-select.js builds its options as <div>, which is block by default, so the
   rule was never needed — until the style guide wrote the same class on a
   <span> and the open list came out as one horizontal strip of options. A list
   row that only stacks when you pick the right tag is a trap for the next app. */
.atlas-select-option {
    display: block;
    padding: var(--control-pad-y) var(--control-pad-x-tight);
    font-size: var(--font-size-control);
    color: var(--color-text);
    cursor: pointer;
    white-space: nowrap;
}


/* Pointer and keyboard land on the SAME colour: the row under the mouse and the
   row the arrow keys are on are one state, not two. */
.atlas-select-option:hover,
.atlas-select-option.is-active {
    background: var(--color-surface-3);
    color: var(--color-text-strong);
}


.atlas-select-option.is-selected,
.atlas-select-option[aria-selected="true"] {
    background: var(--color-surface-2);
    color: var(--color-text-strong);
    font-weight: 600;
}


.atlas-select-option.is-selected.is-active,
.atlas-select-option.is-selected:hover {
    background: var(--color-surface-3);
}


/* In the dark app bar the button borrows the bar's own field treatment, but the
   LIST is a popup on the page and keeps the page's surface and ink. */
.app-header .atlas-select-button,
.header-inner .atlas-select-button,
.company-selector .atlas-select-button {
    background: var(--color-shell-control-bg);
    border-color: var(--color-shell-field-border);
    color: var(--color-shell-fg);
}


.app-header .atlas-select-button:hover,
.header-inner .atlas-select-button:hover,
.company-selector .atlas-select-button:hover {
    background: var(--color-shell-control-bg-hover);
    color: var(--color-shell-fg);
}


/* --- The platform calendar -------------------------------------------------------
 * atlas-datepicker.js draws this in the page, because <input type="date"> opens a
 * calendar the OPERATING SYSTEM draws — system accent, system type, unreachable
 * by CSS, exactly like a closed select's popup. Sites whose calendars match their
 * design are not styling that popup either; they draw their own.
 *
 * The native field stays, and stays typable. Only the picker is ours. */
.atlas-date-wrap { position: relative; display: inline-flex; align-items: center; align-self: center; }


/* The field has to make room for the trigger that sits inside it. `padding-right`
   alone lost: the bare-input rule in atlas-theme.css is
   `input:not([type=button]):not([type=submit])…` — five :not() compounds, so
   (0,5,1) against this class's (0,1,0) — and set the padding shorthand, which
   reset the right side to 10px. The text then ran under the calendar glyph.
   Stated as the shorthand on the same compound the theme uses, so it wins on
   order rather than on a flag. */
input.atlas-date-input:not([type="button"]):not([type="submit"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]) {
    /* the trigger's own width, plus its inset, plus the same gap again */
    padding-right: calc(var(--space-6) + var(--space-2) * 2);
}


/* Chrome's own calendar button is hidden — the trigger below replaces it, and
   two calendar icons on one field is the tell that a picker was bolted on. */
.atlas-date-input::-webkit-calendar-picker-indicator {
    opacity: 0;
    pointer-events: none;
    width: 0;
}


/* THE CALENDAR BUTTON IS AN ICON, THE SAME ONE A TABLE ROW USES.
 *
 * It is a bare <button>, so atlas-theme.css's `button` rule reached it with the
 * whole control box — Clouds fill, silver edge, 6px corner and `4px 16px`
 * padding. The declared width:20px then measured 34px, because 32px of padding
 * was never reset. A filled, bordered 34×20 box sat inside the field: a boxed
 * glyph in Statements, an empty white blob in Warranty where the 13px svg was
 * swamped by it.
 *
 * These declarations are deliberately the ICON family's, the same ones
 * atlas-fluent.css gives .icon-btn and the row edit/delete glyphs: square, no
 * fill and no edge at rest, muted ink, and the surface only under the pointer.
 * A calendar button in a field and a delete button in a table row are the same
 * affordance and now look it. */
.atlas-date-trigger {
    position: absolute;
    right: var(--space-2);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--space-6);
    min-width: var(--space-6);
    height: var(--space-6);
    min-height: 0;
    padding: 0;
    background: none;
    border: 1px solid transparent;
    border-radius: var(--radius);
    box-shadow: none;
    color: var(--color-text-muted);
    cursor: pointer;
}


.atlas-date-trigger:hover {
    background: var(--color-surface-3);
    border-color: transparent;
    color: var(--color-text-strong);
}

.atlas-date-trigger:focus-visible { outline: var(--focus-ring-w) solid var(--color-focus-ring); outline-offset: var(--focus-ring-offset); }


/* The popup is POSITION ONLY. It used to draw a 232px panel of its own with a
   border, a radius and a shadow, and then the calendar — which carries all of
   that from the theme — was placed inside it at its own intrinsic width. Two
   panels, the inner one wider than the outer, which is the offset edge showing
   behind the calendar. The wrapper now just parks the calendar under the
   field's left edge and lets it be the panel. */
.atlas-date-pop {
    position: absolute;
    z-index: 1080;
    top: calc(100% + var(--popup-gap));
    left: 0;
    display: block;
}


/* The popup is position-only because the React tools put Fluent's calendar in
   it, and that component IS the panel — border, radius, shadow and all. The
   grid this file draws has none of that, so when it is the one in the popup the
   popup has to be the panel. Without this the month title and the days floated
   over the form. */
.atlas-date-pop:has(.atlas-date-grid) {
    min-width: 316px;
    padding: 10px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
}


.atlas-date-wrap.is-up .atlas-date-pop { top: auto; bottom: calc(100% + var(--popup-gap)); }


.atlas-date-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 4px;
}


.atlas-date-month {
    font-size: 1rem;
    font-weight: 600;
    color: var(--color-text-strong);
}


.atlas-date-nav {
    width: 22px; height: 22px;
    min-height: 0;
    padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 15px; line-height: 1;
    border: none; background: none; box-shadow: none;
    color: var(--color-action-ink);
    border-radius: var(--radius);
    cursor: pointer;
}


.atlas-date-nav:hover { background: var(--color-surface-3); color: var(--color-action-hover); }


.atlas-date-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; min-width: 300px; }


/* Matched to Fluent's calendar in the React tools — same cell, same type, same
   spacing, so the platform has one calendar and not two that nearly agree. */
.atlas-date-names span {
    text-align: center;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--color-text-muted);
    padding-bottom: 2px;
}


.atlas-date-day {
    min-height: 0;
    height: 38px;
    padding: 0;
    font-size: 14px;
    font-family: inherit;
    border: none;
    background: none;
    box-shadow: none;
    border-radius: var(--radius-sm);
    color: var(--color-text);
    cursor: pointer;
}


/* The pointer and the arrow keys land on ONE state, as everywhere else. */
.atlas-date-day:hover:not(:disabled),
.atlas-date-day.is-active { background: var(--color-surface-3); color: var(--color-text-strong); }


.atlas-date-day.is-selected {
    background: var(--color-action-hover);
    color: var(--color-action-hover-fg);
    font-weight: 600;
}


/* Today is marked, not filled: filling it competes with the selected day. */
.atlas-date-day.is-today:not(.is-selected) {
    box-shadow: inset 0 -2px 0 var(--color-action-ink);
    font-weight: 600;
}


.atlas-date-day.is-outside { color: var(--color-text-subtle); }


.atlas-date-day:disabled {
    color: var(--color-disabled);
    background: none;
    cursor: not-allowed;
}


.atlas-date-foot {
    display: flex;
    gap: 8px;
    margin-top: 4px;
    padding-top: 4px;
    border-top: 1px solid var(--color-border);
}


.atlas-date-link {
    min-height: 0;
    padding: 2px 4px;
    font-size: 12px;
    font-family: inherit;
    border: none;
    background: none;
    box-shadow: none;
    color: var(--color-action-ink);
    cursor: pointer;
    border-radius: var(--radius);
}


.atlas-date-link:hover { background: var(--color-surface-3); color: var(--color-action-hover); }


/* --- THE SESSION WARNING -------------------------------------------------------
 * The idle-timeout modal. Behaviour is each SPA's useSessionGuard; the paint is
 * here, once, for all three React tools — it was defined separately in each of
 * them, in literals (#fff, #1f2937, white, #4b5563, #111827) that no token could
 * reach. Three copies of one modal, and the only way to notice they had drifted
 * was to idle out in each app in turn (ACT-87).
 *
 * The scrim is heavier than the busy overlay's on purpose: that one dims a page
 * that is still working, this one is a decision that has to be taken. */
.session-warning-overlay {
    position: fixed;
    inset: 0;
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: rgba(31, 41, 55, 0.75);
    z-index: 10000;
}

.session-warning-modal {
    max-width: 345px;
    width: 90%;
    padding: var(--space-6);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    text-align: center;
}

/* ONE HEADING on the platform — the modal names itself, it does not shout. */
.session-warning-modal h2 {
    margin: 0 0 var(--space-6) 0;
    color: var(--color-text-strong);
    font-size: 1rem;
    font-weight: 600;
}

.countdown-circle {
    position: relative;
    width: 165px;
    height: 165px;
    margin: 0 auto var(--space-6) auto;
}

.countdown-circle svg { transform: scaleX(-1); }

.countdown-text {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    font-family: var(--font-stack);
    font-size: 36px;
    font-weight: 600;
    color: var(--color-text-strong);
}

.session-warning-buttons {
    display: flex;
    gap: var(--space-4);
    justify-content: center;
}

/* THE ONE BUTTON. It was its own dark button at #1f2937 with a white label and
   two more literals for hover and active — a fourth button on a platform that
   has one. */
.session-warning-btn {
    flex: 1;
    min-width: 100px;
    min-height: var(--control-h);
    padding: var(--space-2) var(--space-5);
    font-size: var(--font-size-body);
    font-weight: 600;
    background: var(--color-action);
    border: 1px solid var(--color-action-edge);
    border-radius: var(--radius);
    color: var(--color-action-fg);
    box-shadow: var(--shadow-sm);
    cursor: pointer;
    transition: background 120ms, color 120ms, border-color 120ms;
}

.session-warning-btn:hover,
.session-warning-btn:active {
    background: var(--color-action-hover);
    border-color: var(--color-action-hover);
    color: var(--color-action-hover-fg);
}

.session-warning-btn:focus-visible {
    outline: var(--focus-ring-w) solid var(--color-focus-ring);
    outline-offset: var(--focus-ring-offset);
}


/* --- THE BLAZOR TEMPLATE'S OWN CLASSES -----------------------------------------
 * ACT-87. These three arrive with every Blazor project and were repainted
 * separately in each of ACH, Warranty and TV Dashboards. They agreed, because
 * they were repainted from the same tokens on the same day — but three copies
 * is three places to miss next time. */
.blazor-error-boundary {
    padding: var(--space-5);
    background: var(--color-danger);
    color: var(--color-shell-fg);
}

.darker-border-checkbox.form-check-input {
    border-color: var(--color-border-strong);
}

/* Validation is TEXT, not a box. A field that failed already shows it in the
   field; this is the sentence saying why. */
.validation-message {
    color: var(--color-danger);
}

/* A menu row — the Blazor tools' user menu. Same affordance as .atlas-popup's
   rows: full width, left aligned, no box, the LIST hover. */
.dropdown-item {
    display: block;
    padding: var(--space-3) var(--space-4);
    color: var(--color-text);
    font-size: var(--font-size-control);
    text-decoration: none;
    cursor: pointer;
}

.dropdown-item:hover {
    background: var(--color-surface-3);
    color: var(--color-text-strong);
}


/* --- THE LAST FIVE -------------------------------------------------------------
 * ACT-87. Small components, each defined in two apps. Small is the point: nobody
 * hoists a four-line rule, so these are exactly the ones that sit duplicated for
 * years and quietly disagree. */

/* The SPA's own root. The portal's copy was #f8f9fa and a full font stack spelled
   out by hand — the tokens for both have existed since ACT-70. */
.app {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    background-color: var(--color-page-bg);
    font-family: var(--font-stack);
}

/* Nothing here yet, and it says so rather than leaving a blank panel. A dashed
   edge, because the box is a placeholder and not a result. */
.empty-state {
    margin-top: var(--space-4);
    padding: 36px var(--space-5);
    text-align: center;
    font-style: italic;
    color: var(--color-text-muted);
    background: var(--color-surface);
    border: 1px dashed var(--color-border);
    border-radius: var(--radius);
}

/* A labelled field in a form. */
.form-group {
    margin-bottom: var(--space-5);
    text-align: left;
}

.form-group label {
    display: block;
    margin-bottom: var(--space-2);
    font-size: 0.9rem;
    color: var(--color-text-muted);
}

/* The one that failed, said in words on its own tint. Pomegranate, like every
   other red on the platform. */
.error-message {
    margin-bottom: var(--space-5);
    padding: var(--space-3);
    font-size: 0.9rem;
    color: var(--color-danger);
    background-color: var(--color-danger-bg);
    border-radius: var(--radius);
}

/* The sentence under a control explaining it. */
.hint {
    color: var(--color-text-muted);
    font-size: 0.85rem;
}


/* The spinner stops for anyone who has asked the OS to stop motion; the ring
   stays visible so the overlay still reads as busy rather than as broken. */
@media (prefers-reduced-motion: reduce) {
    .atlas-busy__spinner {
        animation: none;
        border-top-color: var(--color-action-ink);
        border-right-color: var(--color-action-ink);
    }
}

/* =============================================================================
 * THE PICKER — atlas-picker.jsx
 *
 * One control, for every tool. It replaces BIReports' ms__* and Statements'
 * multiselect__*, which were the same control written twice with two class
 * families; the platform painted one of them and the other drifted, and a
 * screenshot of a filter panel is how anyone found out.
 *
 * The panel takes .atlas-popup for its surface, so it is the same card as every
 * other popup on the platform, and its rows are --menu-row-h like every other
 * list. Nothing here paints the TRIGGER: that is the FIELD TRIGGER affordance in
 * atlas-fluent.css, which this control asks for by class.
 * ========================================================================== */
.atlas-picker { position: relative; }

.atlas-picker__panel {
    position: fixed;
    z-index: 1200;
    padding: 0;
    max-height: 340px;
    overflow-y: auto;
    overflow-x: hidden;
    /* The trigger sets the minimum inline; these set the readable range. A
       picker whose trigger says "5 selected" is 90px wide, and a 90px panel
       breaks "Clear all" over two lines and truncates every option. */
    min-width: 240px;
    max-width: min(420px, calc(100vw - 16px));
    /* The panel sets its own type. Inside a FluentPopover it otherwise inherits
       Fluent's 16px / 27px content type, which made every row 43px and the
       11px action strip 26px — measured on Customer Statements (ACT-112). */
    font-size: var(--font-size-control);
    line-height: normal;
}

/* THE BLAZOR RENDITION (AtlasPicker.razor, in BI Reports and Customer Statements).
 *
 * AS WIDE AS ITS WIDEST VALUE, and the list exactly as wide as the button: not
 * stretched to whatever cell it sits in, and not floored at 240px, which hung a
 * "5 selected" list of short branch names well past its button (ACT-112). The
 * width comes from a zero-height sizer under the trigger that holds the longest
 * labels at an option row's own inline padding, so the button and its list
 * agree before the list has ever opened. Past the cap a label ends in an
 * ellipsis, with the full text on hover.
 *
 * The list is placed by atlas-picker.js (fixed, under the trigger, at its
 * width), not by Fluent's popover, whose page overlay never closed it. */
.atlas-picker--sized {
    display: inline-grid;
    grid-template-columns: auto;
    max-width: min(100%, 420px);
    vertical-align: top;
    /* A field is often a flex column or a grid cell, which would stretch the
       picker back to the cell's width. A set width is never stretched, so this
       holds it at its own width in either. Not align-self: flex-start, which
       did the same in a column but, in a ROW, lifted the picker to the top
       while the button beside it stayed centred (Customer Statements' Terms
       and List Customers). */
    width: fit-content;
}
.atlas-picker--sized > .atlas-picker__trigger { width: 100%; min-width: 0; }

.atlas-picker__sizer { height: 0; overflow: hidden; visibility: hidden; }
/* An option row's inline extent: its padding, the 16px tick and the gap before
   the label, plus the panel's 1px edges. A list long enough to scroll also
   gives up a scrollbar's width. */
.atlas-picker__sizer-row {
    white-space: nowrap;
    font-size: var(--font-size-control);
    padding-left: calc(1px + var(--space-3) + 16px + var(--space-3));
    padding-right: calc(1px + var(--space-3));
}
.atlas-picker__sizer--single .atlas-picker__sizer-row { padding-left: calc(1px + var(--space-3)); }
.atlas-picker__sizer--scrolls .atlas-picker__sizer-row { padding-right: calc(1px + var(--space-3) + 17px); }

/* The panel is the column: the search and the actions stay put and the
   virtualised list scrolls between them. */
.atlas-picker--sized .atlas-picker__panel {
    min-width: 0;
    max-width: none;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.atlas-picker--sized .atlas-picker__list { flex: 1 1 auto; min-height: 0; max-height: 260px; overflow-y: auto; }
.atlas-picker--sized .atlas-picker__row > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* border-box on every part of the panel, for the reason given on
   .atlas-picker__row: half the platform has no reset to inherit. */
.atlas-picker__panel,
.atlas-picker__search,
.atlas-picker__actions,
.atlas-picker__note { box-sizing: border-box; }

.atlas-picker__search { padding: var(--space-2); border-bottom: 1px solid var(--color-border); }
.atlas-picker__search fluent-text-field { width: 100%; }

/* Select all / Clear / Reset. A row of text actions, not a row of buttons —
   they act on the list below them, they are not the point of the panel. */
.atlas-picker__actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    /* --space-1 top and bottom. These are 11px text actions, not controls: at
       --space-2 the strip stood as tall as an option row and read as one. */
    padding: var(--space-1) var(--space-3);
    border-bottom: 1px solid var(--color-border);
}

/* The HOST has to give up the control height too. atlas-fluent.css pins every
   fluent-button host to --control-h (30px) and the part is 100% of it, so
   min-height: 0 on the part alone changed nothing — the strip measured 55px for
   11px text. height: auto lets the host collapse onto its content. */
.atlas-picker__action {
    height: auto;
}

/* RESET SITS AT THE RIGHT END, AWAY FROM THE OTHERS.
   Select all and Clear All act on what is on screen; Reset throws the selection
   away and puts the defaults back, which is the one action in the strip a
   mis-click cannot be undone from by pressing the neighbour. Pushed to the far
   edge so it is not the button next to the one being aimed at. */
.atlas-picker__action--reset { margin-left: auto; }

.atlas-picker__action::part(control) {
    background: transparent;
    border-color: transparent;
    box-shadow: none;
    color: var(--color-link);
    font-size: var(--font-size-micro);
    font-weight: 500;
    min-height: 0;
    padding: var(--space-1) var(--space-2);
}

.atlas-picker__action:hover::part(control) {
    background: var(--color-surface-3);
    color: var(--color-link-hover);
    border-color: transparent;
}

/* A row, at the platform's row height, with the platform's list hover.
 *
 * box-sizing IS the whole rule. min-height 36 plus 8px of padding top and
 * bottom is 52px in content-box, and there is no global border-box reset in
 * these sheets — Bootstrap supplies one, and only three of the six tools load
 * Bootstrap. So the same picker was 36px in ACH, Warranty and TV Dashboards and
 * 52px in Statements, BIReports and UnifiedLogin. The comment below claimed the
 * row was at the platform's height; in half the platform it was not. */
.atlas-picker__row {
    box-sizing: border-box;
    display: flex;
    align-items: center;
    gap: var(--space-3);
    /* COMPACT, at the control height (ACT-112: "too spread out"). A picker is a
       list of many short values chosen several at a time — terms, branches, GL
       accounts — so it is denser than a menu of a few commands. Every picker on
       the platform takes this one height; it is still a token, not a local
       number. */
    min-height: var(--control-h);
    padding: var(--space-2) var(--space-3);
    font-size: var(--font-size-control);
    color: var(--color-text);
    cursor: pointer;
}

.atlas-picker__row:hover { background: var(--color-surface-3); }
.atlas-picker__row.is-selected { background: var(--color-surface-2); font-weight: 600; }
.atlas-picker__row:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--color-focus-ring); }

.atlas-picker__note {
    padding: var(--space-3);
    font-size: var(--font-size-micro);
    color: var(--color-text-muted);
}

/* The summary line in the trigger. The placeholder is the platform's
   placeholder ink, so an empty picker reads the same as an empty field. */
.atlas-picker__summary,
.atlas-picker__placeholder {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.atlas-picker__placeholder { color: var(--color-text-subtle); }
.atlas-picker__chev { flex: 0 0 auto; opacity: .7; }

/* =============================================================================
 * THE DIALOG — atlas-dialog.jsx
 *
 * One modal shell. There were five: three copies of .session-warning-overlay /
 * .session-warning-modal, Statements' .modal-backdrop and BIReports' .rpm__modal
 * — five scrims, five cards, five sets of Escape-and-focus behaviour.
 * ========================================================================== */
.atlas-dialog {
    position: fixed;
    inset: 0;
    z-index: 2000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-5);
    /* The same scrim the busy overlay uses — one dimming on the platform. */
    background: rgba(31, 41, 55, 0.22);
}

.atlas-dialog__card {
    background: var(--color-surface);
    color: var(--color-text);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: var(--space-6);
    max-height: calc(100vh - var(--space-6) * 2);
    overflow-y: auto;
    outline: none;
}

.atlas-dialog__card--sm { width: 380px; max-width: 100%; }
.atlas-dialog__card--md { width: 560px; max-width: 100%; }
.atlas-dialog__card--lg { width: 860px; max-width: 100%; }

.atlas-dialog__title {
    margin: 0 0 var(--space-4);
    font-size: var(--font-size-body);
    font-weight: 600;
    color: var(--color-text-strong);
}

/* The actions row. Right-aligned, because the confirming action is the last
   thing read — and stated once so four apps stop deciding it separately. */
.atlas-dialog__actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-3);
    margin-top: var(--space-5);
}

/* --- the session timeout warning ---------------------------------------- */
.atlas-session-warning { text-align: center; }

.atlas-session-warning__ring {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* The ring itself is the accent; the track takes --color-border inline. */
    color: var(--color-action-hover);
}

.atlas-session-warning__count {
    position: absolute;
    font-size: 1.6rem;
    font-weight: 600;
    color: var(--color-text-strong);
    font-variant-numeric: tabular-nums;
}

.atlas-session-warning .atlas-dialog__actions { justify-content: center; }

/* A list row and the actions beside it. The row is the control — a
   fluent-button, so it focuses and takes Enter — and the icons sit next to it
   rather than inside it, which is what let the icons stop needing to cancel the
   row's own click. BIReports' report list was a div with an onClick before. */
.nav-report-row {
    display: flex;
    align-items: center;
    gap: var(--space-1);
}

.nav-report-row > .nav-report-item { flex: 1 1 auto; min-width: 0; }
.nav-report-row > .nav-report-sub,
.nav-report-row > .nav-report-edit { flex: 0 0 auto; }

/* =============================================================================
 * THE TABLE — .atlas-table
 *
 * atlas-theme.css has carried the platform's table all along, and only the three
 * BLAZOR tools link that file. So BIReports, Statements and the portal each
 * painted their own: .cr-table, .data-table, .subs__grid — three header tints,
 * three row rules, three cell paddings, for the same object.
 *
 * This is the PAINT only. A tool's own table may still be sticky, sortable,
 * resizable or virtualised on top of it — that is behaviour and it belongs to
 * the screen. What it may not do is decide what a row looks like.
 * ========================================================================== */
.atlas-table {
    width: 100%;
    border-collapse: collapse;
    background: var(--color-surface);
    color: var(--color-text);
    font-size: var(--font-size-table);
}

.atlas-table > thead > tr > th,
.atlas-table th {
    background: var(--color-surface-2);
    color: var(--color-text-muted);
    font-weight: 600;
    text-align: left;
    padding: var(--space-2) var(--space-3);
    border-bottom: 1px solid var(--color-border);
    white-space: nowrap;
}

.atlas-table > tbody > tr > td,
.atlas-table td {
    padding: var(--space-2) var(--space-3);
    border-bottom: 1px solid var(--color-surface-2);
}

.atlas-table > tbody > tr:last-child > td { border-bottom: 0; }

/* ZEBRA, as the Blazor tools' atlas-theme.css has always drawn it: on the cells,
   starting on the FIRST row (a white row right under the darker head reads as a
   gap), with a hover grey deep enough to read over the stripe. */
.atlas-table > tbody > tr:nth-child(odd) > td { background: var(--color-surface-3); }
.atlas-table > tbody > tr:hover > td { background: var(--color-row-hover); }
.atlas-table > tbody > tr.selected > td,
.atlas-table > tbody > tr.is-selected > td { background: var(--color-row-selected, var(--color-surface-2)); }

/* A number reads as a number: right-aligned and lined up digit for digit. */
.atlas-table td.num,
.atlas-table th.num {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* ══════════════════════════════════════════════════════════════════════════════
   THE FAMILIES THE APPS WERE STILL PAINTING THEMSELVES

   Everything below was already in the tools, said three or four times over in
   three or four stylesheets, in colours that had drifted apart. The class names
   are the tools' own — .chip, .modal, .tone-card, .field__input — because the
   markup keeps them; what moves here is the PAINT. An app stylesheet may still
   say where one of these sits and how wide it is. It may no longer say what it
   looks like.
   ══════════════════════════════════════════════════════════════════════════════ */


/* ── CARD ─────────────────────────────────────────────────────────────────────
   A surface that holds content: the login box, a tool tile on the landing page,
   a settings group. Same white, same edge, same 6px corner as every other box.
   .application-card is also a CONTROL — it takes the pointer — so it alone
   lifts under the cursor; a card that does nothing must not pretend to. */
/* .application-card is NOT here. It is a <fluent-button>, and a fill or an
   edge on the host of a Fluent element paints nothing — the box is
   ::part(control) inside the shadow root. atlas-fluent.css draws it, as the
   card-button affordance. */
.atlas-card,
.login-card,
.tone-card,
.settings-card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: none;
}

.atlas-card--action:hover {
    border-color: var(--color-border-strong);
    box-shadow: var(--shadow);
}

.application-card:hover .app-arrow { color: var(--color-action-ink); }

/* The head and foot of a card are tinted bands that must round WITH it, or the
   fill shows through the corner as a square nub. */
.atlas-card__header,
.settings-card__header {
    background: var(--color-surface-2);
    border-bottom: 1px solid var(--color-border);
    border-top-left-radius: var(--radius);
    border-top-right-radius: var(--radius);
    font-size: var(--font-size-micro);
    font-weight: 700;
    color: var(--color-text-muted);
}

.atlas-card__footer,
.card__footer {
    background: var(--color-surface-2);
    border-top: 1px solid var(--color-border);
    border-bottom-left-radius: var(--radius);
    border-bottom-right-radius: var(--radius);
}

.atlas-card__sub,
.settings-card__sub,
.tone-card__hint {
    font-size: var(--font-size-micro);
    font-weight: 500;
    color: var(--color-text-muted);
}


/* ── CHIP ─────────────────────────────────────────────────────────────────────
   A small toggle in a row of them. At rest it is a field: white, stroked, 6px.
   Chosen, it is the ACTION — the same fill the platform's primary button uses,
   so "on" means the same colour everywhere, rather than each tool picking one. */
.atlas-chip,
.chip {
    background: var(--color-surface);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius);
    color: var(--color-text);
    font-size: var(--font-size-control);
}

.atlas-chip:hover,
.chip:hover {
    background: var(--color-surface-3);
    border-color: var(--color-action-edge);
}

.atlas-chip:focus-within,
.chip:focus-within {
    box-shadow: 0 0 0 var(--focus-ring-w) var(--color-focus-ring);
}

/* CHOSEN IS THE LIFTED FILL, NOT THE BUTTON FILL. --color-action is Clouds, two
   shades off the white a chip rests on, so a chip set to it reads as unchosen —
   three near-whites in a row. --color-action-hover is Wet Asphalt lifted, which
   is what Statements' own --color-chip-active resolved to and what a selected
   chip has to be to be seen. */
.atlas-chip.is-active,
.chip--active {
    background: var(--color-action-hover);
    border-color: var(--color-action-hover);
    color: var(--color-action-hover-fg);
}

.atlas-chip.is-active:hover,
.chip--active:hover {
    background: var(--color-action-hover);
    border-color: var(--color-action-hover);
    color: var(--color-action-hover-fg);
}

/* A status pill is a chip that reports rather than toggles: same box, no hover. */
.tone-card__status {
    font-size: var(--font-size-micro);
    font-weight: 600;
    border-radius: var(--radius);
    border: 1px solid var(--color-border);
    background: var(--color-surface);
    color: var(--color-text-muted);
}

.tone-card__status.is-custom {
    color: var(--color-link);
    background: var(--color-info-bg);
    border-color: var(--color-info-border);
}


/* ── FIELD ON A PAGE SURFACE ──────────────────────────────────────────────────
   The label-over-input pair the tools build in their own forms. The Fluent
   fields already look like this; these are the plain ones beside them, and they
   have to match or a form reads as two different products stacked. */
.atlas-field__label,
.field__label,
.cr-field > span {
    font-size: var(--font-size-micro);
    font-weight: 600;
    color: var(--color-text-muted);
}

.cr-field.is-missing > span { color: var(--color-danger); }

/* .field__input and .field__select are NOT here. Every one of them in Statements
   is on a Fluent element, and a rule on the HOST of a Fluent element paints
   nothing — the box is inside the shadow root, on ::part(control). Putting them
   here looked right, changed nothing on screen, and would have sat in the file
   as paint that appears to be doing a job. atlas-fluent.css paints them through
   fluent-text-field::part(root), which is where the boundary actually is.
   What is left below is the NATIVE field, which a host rule does reach. */
.atlas-field__input,
.cr-field > select,
.cr-field > input {
    background: var(--color-surface);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius);
    color: var(--color-text);
    font-size: var(--font-size-control);
}

/* EVERY NATIVE FIELD ON THE PLATFORM, NOT A LIST OF CLASS NAMES.
 *
 * This was .atlas-field__input, .cr-field > select, .cr-field > input — so a
 * field with any other class got the user-agent ring, and every page that
 * minded wrote its own focus rule. That is where the one-offs came from:
 * SubscribePage had four of them, ReportPickerModal a fifth, each a different
 * colour and a different thickness. The rule is the ELEMENT now, so a new field
 * is covered the day it is written and there is nothing left to hand-roll.
 *
 * Same treatment as the Fluent fields in atlas-fluent.css: the ACTIVE field
 * fills and the border is never touched — see the comment there. A native input
 * and a fluent-text-field sit in the same row on several pages and must not
 * behave differently.
 *
 * Buttons and the tick/dot controls are excluded — they take the outline ring,
 * which is a separate rule. */
input:not([type="button"], [type="submit"], [type="reset"], [type="checkbox"], [type="radio"], [type="file"], [type="range"], [type="color"], [type="image"]):focus,
select:focus,
textarea:focus {
    background: var(--color-field-active-bg);
    border-color: var(--color-border-strong);
    outline: none;
    box-shadow: none;
}


/* ── MODAL ────────────────────────────────────────────────────────────────────
   AtlasDialog is the component; these are the class names Statements' own modal
   still carries. Same scrim, same card, same lift — so the two cannot drift. */
/* .modal AND .modal-backdrop ARE BOOTSTRAP CLASSES AND ARE NOT DEFINED HERE.
   Bootstrap.modal is the FULL-SCREEN container — position:fixed, 100% by 100% —
   so a fill and an edge on it paints the whole viewport white the moment any
   modal opens in the three Bootstrap tools, and .modal-backdrop is their scrim.
   This file is loaded after Bootstrap by all six, so it would have won.
   Statements does not use either one: its dialog is AtlasDialog. What survives
   below is the text INSIDE a dialog, which no framework claims. */
.modal__title {
    font-size: var(--font-size-base);
    font-weight: 600;
    color: var(--color-text-strong);
}

.modal__desc { font-size: var(--font-size-control); color: var(--color-text); }

.modal__list {
    background: var(--color-surface-2);
    border-radius: var(--radius);
    font-size: var(--font-size-micro);
}

.modal__list li { border-bottom: 1px solid var(--color-border); }
.modal__list li:last-child { border-bottom: none; }


/* ── ROW ──────────────────────────────────────────────────────────────────────
   A list of rows is divided by ONE hairline in ONE colour, and the last row
   does not carry one — otherwise the list ends in a line that belongs to
   nothing. Five stylesheets each said this, three of them in different greys. */
.atlas-row,
.passkeys-row,
.navbar-pin-row,
.navbar-sub-row,
.settings-test-row,
.search-result-item {
    border-bottom: 1px solid var(--color-border);
}

.atlas-row:last-child,
.passkeys-row:last-child,
.search-result-item:last-child { border-bottom: none; }

.navbar-pin-row,
.navbar-sub-row { background: var(--color-surface); }

/* A row that takes the pointer warms; the platform has one hover grey. */
.atlas-row--action:hover,
.search-result-item:hover,
.folder-row:hover { background: var(--color-surface-3); }


/* ── QUIET TEXT INSIDE A CONTROL ──────────────────────────────────────────────
   "No saved views", "Loading more…", a field's error line. Not decoration: it
   is the text the platform uses when a control has nothing to show, and it was
   four different greys at four different sizes. */
.atlas-quiet,
.cr-menu__empty,
.views-menu-empty,
.company-selector-error,
.cr-table td.cr-loadmore,
.preview-panel__title-btn:disabled {
    color: var(--color-text-muted);
    font-size: var(--font-size-micro);
}

.company-selector-error { color: var(--color-danger); }

/* A link-coloured label INSIDE a menu or a crumb trail: the action ink, never a
   second blue. */
.views-menu-save,
.breadcrumb-item { color: var(--color-action-ink); }
.views-menu-save { font-weight: 600; }

.views-menu-sep { border-top: 1px solid var(--color-border); }

/* A heading that is also a button — Statements' preview title. It carries no box
   of its own: it is the surrounding text, and only the pointer says it acts. */
.preview-panel__title { font-weight: 600; color: var(--color-text-strong); }

.preview-panel__title-btn {
    color: inherit;
    font: inherit;
}


/* ── BADGE ────────────────────────────────────────────────────────────────────
   A small pill that REPORTS a state — it is not a control and takes no pointer.
   Statements drew its payment-tone badge inline: ten hard-coded hex colours, a
   4px corner and its own type scale, in the one place on the platform no
   stylesheet and no audit could reach. The corner is the platform's now, the
   colours come from the tone tokens, and the tone is a data attribute so the
   markup carries no paint at all. */
.atlas-badge {
    display: inline-block;
    padding: 2px 8px;
    /* Almost square: a badge is a mark on the row, not a control in it. */
    border-radius: var(--radius-tight);
    font-size: var(--font-size-micro);
    font-weight: 600;
    letter-spacing: 0.4px;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
    background: var(--color-surface-2);
    color: var(--color-text-muted);
}

/* Inside a dense table the badge gives back the two pixels it does not need. */
.atlas-badge--compact { padding: 1px 5px; font-size: 10px; }

.atlas-badge[data-tone="Good"]           { background: var(--tone-good-bg);        color: var(--tone-good-fg); }
.atlas-badge[data-tone="OccasionalLate"] { background: var(--tone-late-1-bg);      color: var(--tone-late-1-fg); }
.atlas-badge[data-tone="ChronicLate"]    { background: var(--tone-late-2-bg);      color: var(--tone-late-2-fg); }
.atlas-badge[data-tone="Delinquent"]     { background: var(--tone-delinquent-bg);  color: var(--tone-delinquent-fg); }
.atlas-badge[data-tone="Critical"]       { background: var(--tone-critical-bg);    color: var(--tone-critical-fg); }

/* THE DONUT READS THE SAME FIVE TOKENS, so a tone cannot be one colour in the
   ring and another in the row. ToneDonut.tsx held the ramp as raw hex on a
   `stroke` ATTRIBUTE — which is also why it could not simply be pointed at a
   token: an SVG presentation attribute does not resolve var(). Painted here, on
   the class and the data attribute, exactly like the badge above it. */
.tone-donut__track { stroke: var(--tone-empty); }

.tone-donut__slice[data-tone="Good"]           { stroke: var(--tone-good-dot); }
.tone-donut__slice[data-tone="OccasionalLate"] { stroke: var(--tone-late-1-dot); }
.tone-donut__slice[data-tone="ChronicLate"]    { stroke: var(--tone-late-2-dot); }
.tone-donut__slice[data-tone="Delinquent"]     { stroke: var(--tone-delinquent-dot); }
.tone-donut__slice[data-tone="Critical"]       { stroke: var(--tone-critical-dot); }

/* The same state as a dot, for a cell too narrow for a word. A circle is the
   one place 50% is right rather than the platform corner. */
.atlas-badge-dot {
    display: inline-block;
    width: 1em;
    height: 1em;
    border-radius: 50%;
    vertical-align: middle;
    background: var(--color-text-muted);
}

.atlas-badge-dot[data-tone="Good"]           { background: var(--tone-good-dot); }
.atlas-badge-dot[data-tone="OccasionalLate"] { background: var(--tone-late-1-dot); }
.atlas-badge-dot[data-tone="ChronicLate"]    { background: var(--tone-late-2-dot); }
.atlas-badge-dot[data-tone="Delinquent"]     { background: var(--tone-delinquent-dot); }
.atlas-badge-dot[data-tone="Critical"]       { background: var(--tone-critical-dot); }

/* Two more badges the tools were painting themselves.

   .cr-badge is the count on BIReports' Filters button — it was filled with
   var(--accent-fill), a token that does not exist on this platform, so what it
   actually rendered was whatever the browser fell back to.

   .sent-badge is Statements' "sent" marker: success ink, no fill. */
.atlas-badge--count,
.cr-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 17px;
    height: 17px;
    padding: 0 5px;
    border-radius: var(--radius);
    /* THE COUNT SITS ON A BUTTON, so it cannot be the button fill.
       --color-action is Clouds and so is the button under it — the badge was
       Clouds on Clouds and the count on the Filters button was invisible. The
       lifted fill is the one that reads against a button, the same one a chosen
       chip takes. */
    background: var(--color-action-hover);
    color: var(--color-action-hover-fg);
    font-size: var(--font-size-micro);
    font-weight: 700;
    line-height: 1;
}

.atlas-badge--success,
.sent-badge {
    background: transparent;
    color: var(--color-success);
    font-size: var(--font-size-micro);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}


/* --- A COLLAPSIBLE SECTION ---------------------------------------------------
 * A native <details class="atlas-section"> inside the <section> that bands and
 * pads it. Native, because it already does the whole job: independent open
 * state per section, keyboard operation, find-in-page that opens what it lands
 * in, and a closed start that costs no script. It is NOT an accordion — any
 * number may be open at once. atlas-collapse.js adds only the two page-level
 * buttons.
 *
 * The <details> sits inside the <section> rather than replacing it, so the
 * banding, padding and inline offset the section already carries keep working
 * and a collapsed section is still a band with its title in it.
 * ========================================================================== */
details.atlas-section > summary {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    cursor: pointer;
    /* Both are needed: list-style kills the marker everywhere except WebKit,
       which needs its own pseudo-element turned off. */
    list-style: none;
}


details.atlas-section > summary::-webkit-details-marker { display: none; }


/* The platform draws its own twisty, in the ink the heading uses, so a closed
   section is legible as closed rather than as a heading that lost its content.
   A rotation rather than two glyphs: the shape is the same thing pointing
   somewhere else, and it animates. */
details.atlas-section > summary::before {
    content: "";
    flex: 0 0 auto;
    width: 0;
    height: 0;
    border-top: 5px solid transparent;
    border-bottom: 5px solid transparent;
    border-left: 7px solid var(--color-text-muted);
    transition: transform .15s ease;
}


details.atlas-section[open] > summary::before { transform: rotate(90deg); }


details.atlas-section > summary:hover::before { border-left-color: var(--color-action-ink); }


/* The heading keeps its type and gives up its margin: inside a summary it is a
   row, not a block that opens a rhythm. */
details.atlas-section > summary > :is(h1, h2, h3, h4) { margin: 0; }


details.atlas-section > summary:focus-visible {
    outline: var(--focus-ring-w) solid var(--color-focus-ring);
    outline-offset: var(--focus-ring-offset);
    border-radius: var(--radius-sm);
}


/* The gap between the title and what it opens. A summary that is flush against
   its own content reads as a label on the first field rather than as the
   section heading. */
details.atlas-section[open] > summary { margin-bottom: var(--space-4); }
