/**
 * MSafe operations panel — design system.
 * ---------------------------------------------------------------------------
 *
 * WHY THIS IS A PLAIN, HAND-WRITTEN STYLESHEET
 *
 * This repository has never had a frontend build: no `node_modules`, no
 * `public/build`, no compiled bundle in version control. Introducing a Vite theme
 * pipeline for a visual pass would make every deployment and every CI run depend
 * on npm, and would commit a generated artifact nobody can review in a diff.
 *
 * So this is the smallest maintainable layer that does the job: one readable
 * file, loaded by a render hook, versioned as source. It is written against
 * Filament's OWN public surface — its `--fi-*` custom properties and its
 * documented `.fi-` component classes — and never against internal markup or
 * generated utility-class combinations, which are the things that move between
 * releases.
 *
 * No rule here uses a priority override, and that is deliberate: if one were needed,
 * the selector would be fighting Filament rather than extending it. A test enforces
 * their absence.
 *
 * DESIGN DIRECTION — industrial compliance tooling
 *
 * Serious, dense, quiet. This is a screen somebody looks at for six hours while
 * deciding whether a safety report is fit to publish, so the visual system spends
 * its budget on STATE rather than on decoration: a control's status, its result
 * and its extraction state should be readable from across a desk, and nothing
 * else should compete with them.
 *
 * - Neutral slate ground, white surfaces, hairline borders.
 * - Radii 6–10px. Nothing pill-shaped except badges, which earn it.
 * - Shadows are separation, never depth theatre: one soft, one softer.
 * - Type: tabular numerals everywhere a number is compared to another number.
 * - Colour carries meaning ONLY alongside a word or a shape. Never alone.
 */

/* ─────────────────────────────────────────────────────────────────────────────
   1. Tokens
   ───────────────────────────────────────────────────────────────────────── */

:root {
    /* Ground and surfaces */
    --msafe-canvas: #f4f5f7;
    --msafe-surface: #ffffff;
    --msafe-surface-sunken: #fafbfc;
    --msafe-border: #e3e6ea;
    --msafe-border-strong: #cdd3da;

    /* Ink */
    --msafe-ink: #171b21;
    --msafe-ink-muted: #5b6572;
    --msafe-ink-faint: #8b95a3;

    /* Semantic state — one hue per meaning, used with a label, never alone */
    --msafe-draft: #6b7280;
    --msafe-review: #b45309;
    --msafe-approved: #1d4ed8;
    --msafe-published: #047857;
    --msafe-rejected: #b91c1c;
    --msafe-pass: #047857;
    --msafe-fail: #b91c1c;
    --msafe-assisted: #4338ca;

    --msafe-radius: 8px;
    --msafe-radius-lg: 10px;

    --msafe-shadow: 0 1px 2px rgb(16 24 40 / 0.04), 0 1px 3px rgb(16 24 40 / 0.06);
    --msafe-shadow-raised: 0 4px 12px rgb(16 24 40 / 0.08);
}

:root .dark,
.dark {
    --msafe-canvas: #0d1117;
    --msafe-surface: #161b22;
    --msafe-surface-sunken: #10151c;
    --msafe-border: #262d36;
    --msafe-border-strong: #364049;

    --msafe-ink: #e6edf3;
    --msafe-ink-muted: #9aa6b2;
    --msafe-ink-faint: #6e7b8a;

    --msafe-draft: #9aa4b2;
    --msafe-review: #f59e0b;
    --msafe-approved: #60a5fa;
    --msafe-published: #34d399;
    --msafe-rejected: #f87171;
    --msafe-pass: #34d399;
    --msafe-fail: #f87171;
    --msafe-assisted: #a5b4fc;

    --msafe-shadow: 0 1px 2px rgb(0 0 0 / 0.3);
    --msafe-shadow-raised: 0 4px 14px rgb(0 0 0 / 0.4);
}

/* ─────────────────────────────────────────────────────────────────────────────
   2. Typography

   Tabular figures are the one non-negotiable. A workplace code, a control ID and
   a date are all read by comparing them against another one directly above; with
   proportional digits the columns do not line up and the eye has to work.
   ───────────────────────────────────────────────────────────────────────── */

.fi-body {
    background-color: var(--msafe-canvas);
    color: var(--msafe-ink);
    -webkit-font-smoothing: antialiased;
    font-feature-settings: 'cv05' 1, 'ss01' 1;
}

.fi-ta-table,
.fi-in-text,
.fi-input,
.fi-badge,
time {
    font-variant-numeric: tabular-nums;
}

.fi-header-heading {
    font-size: 1.375rem;
    font-weight: 640;
    letter-spacing: -0.018em;
    color: var(--msafe-ink);
}

.fi-header-subheading {
    color: var(--msafe-ink-muted);
    font-size: 0.8125rem;
}

.fi-section-header-heading {
    font-size: 0.9375rem;
    font-weight: 620;
    letter-spacing: -0.01em;
}

.fi-section-header-description {
    font-size: 0.8125rem;
    line-height: 1.5;
    color: var(--msafe-ink-muted);
}

/* ─────────────────────────────────────────────────────────────────────────────
   3. Shell — sidebar and topbar

   The sidebar is a tool, not a landmark: it recedes so the working area reads as
   the product. Group labels are the only uppercase text in the interface, which
   is what lets them work at 11px without a border to separate them.
   ───────────────────────────────────────────────────────────────────────── */

.fi-sidebar {
    background-color: var(--msafe-surface);
    border-inline-end: 1px solid var(--msafe-border);
}

.fi-sidebar-header {
    background-color: var(--msafe-surface);
    border-bottom: 1px solid var(--msafe-border);
    box-shadow: none;
}

.fi-sidebar-group-label {
    font-size: 0.6875rem;
    font-weight: 620;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--msafe-ink-faint);
}

.fi-sidebar-item-label {
    font-size: 0.8438rem;
    font-weight: 500;
}

.fi-sidebar-item-button {
    border-radius: var(--msafe-radius);
    padding-block: 0.4375rem;
}

.fi-sidebar-item-icon {
    width: 1.125rem;
    height: 1.125rem;
}

/*
 * The active item is marked by a rail, not only by a tint. Somebody who cannot
 * separate the tint from the ground still sees which page they are on.
 */
.fi-sidebar-item-active .fi-sidebar-item-button {
    position: relative;
    background-color: color-mix(in srgb, var(--msafe-ink) 6%, transparent);
    font-weight: 600;
}

.fi-sidebar-item-active .fi-sidebar-item-button::before {
    content: '';
    position: absolute;
    inset-inline-start: -0.5rem;
    inset-block: 0.25rem;
    width: 3px;
    border-radius: 0 3px 3px 0;
    background-color: var(--msafe-ink);
}

.fi-topbar > nav {
    background-color: color-mix(in srgb, var(--msafe-surface) 88%, transparent);
    backdrop-filter: saturate(140%) blur(6px);
    border-bottom: 1px solid var(--msafe-border);
    box-shadow: none;
}

/* ─────────────────────────────────────────────────────────────────────────────
   4. Surfaces
   ───────────────────────────────────────────────────────────────────────── */

/*
 * `:not(.fi-section-not-contained)` is Filament's own contract, not a workaround.
 *
 * It marks a section that is a LAYOUT GROUPING rather than a card — the wrapper a
 * stats row sits in, for instance. Framing one produces a card inside a card: four
 * bordered tiles inside a fifth border, which is what this rule looked like before
 * the modifier was respected.
 */
.fi-section:not(.fi-section-not-contained),
.fi-wi-stats-overview-stat,
.fi-ta-ctn {
    background-color: var(--msafe-surface);
    border: 1px solid var(--msafe-border);
    border-radius: var(--msafe-radius-lg);
    box-shadow: var(--msafe-shadow);
}

.fi-section-header {
    padding-block: 1rem;
}

.fi-section-content {
    padding-block: 1rem;
}

.fi-modal-window {
    border-radius: var(--msafe-radius-lg);
    box-shadow: var(--msafe-shadow-raised);
}

/* ─────────────────────────────────────────────────────────────────────────────
   5. Tables — density

   Compact but breathable: 0.625rem block padding reads about eleven rows on a
   laptop without the rows touching. The header is sunken rather than bold, so the
   first thing the eye lands on is data.
   ───────────────────────────────────────────────────────────────────────── */

.fi-ta-header-cell {
    background-color: var(--msafe-surface-sunken);
    border-bottom: 1px solid var(--msafe-border);
}

.fi-ta-header-cell-label {
    font-size: 0.6875rem;
    font-weight: 620;
    letter-spacing: 0.045em;
    text-transform: uppercase;
    color: var(--msafe-ink-faint);
}

.fi-ta-cell {
    padding-block: 0.625rem;
}

.fi-ta-row:hover {
    background-color: var(--msafe-surface-sunken);
}

.fi-ta-text-item-label {
    font-size: 0.8438rem;
}

.fi-ta-empty-state {
    padding-block: 3rem;
}

.fi-ta-empty-state-heading {
    font-size: 0.9375rem;
    font-weight: 600;
}

/* ─────────────────────────────────────────────────────────────────────────────
   6. Badges — the status language

   Squared-off, bordered, small caps. A badge is a label first and a colour
   second: the border and the text carry the meaning if the fill is invisible to
   the reader, which is the accessibility requirement stated as a design rule.
   ───────────────────────────────────────────────────────────────────────── */

.fi-badge {
    border-radius: 5px;
    font-size: 0.6875rem;
    font-weight: 620;
    letter-spacing: 0.02em;
    padding-inline: 0.4375rem;
    padding-block: 0.125rem;
    border-width: 1px;
    border-style: solid;
}

/* ─────────────────────────────────────────────────────────────────────────────
   7. Controls
   ───────────────────────────────────────────────────────────────────────── */

.fi-btn {
    border-radius: var(--msafe-radius);
    font-weight: 560;
    letter-spacing: -0.005em;
}

.fi-input-wrp {
    border-radius: var(--msafe-radius);
}

.fi-fo-field-wrp-label {
    font-size: 0.8125rem;
    font-weight: 560;
    color: var(--msafe-ink);
}

.fi-fo-field-wrp-hint,
.fi-fo-field-wrp-helper-text {
    font-size: 0.75rem;
    line-height: 1.5;
    color: var(--msafe-ink-muted);
}

/*
 * Focus is never removed, only restyled. Keyboard users navigate this panel and
 * the outline is how they know where they are.
 */
.fi-btn:focus-visible,
.fi-input:focus-visible,
.fi-sidebar-item-button:focus-visible,
.fi-ta-row a:focus-visible {
    outline: 2px solid var(--msafe-approved);
    outline-offset: 2px;
}

/* ─────────────────────────────────────────────────────────────────────────────
   8. Dashboard KPI tiles
   ───────────────────────────────────────────────────────────────────────── */

.fi-wi-stats-overview-stat-value {
    font-size: 1.75rem;
    font-weight: 660;
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
}

.fi-wi-stats-overview-stat-label {
    font-size: 0.75rem;
    font-weight: 560;
    letter-spacing: 0.02em;
    color: var(--msafe-ink-muted);
}

.fi-wi-stats-overview-stat-description {
    font-size: 0.75rem;
    color: var(--msafe-ink-faint);
}

/* ─────────────────────────────────────────────────────────────────────────────
   9. Narrow viewports

   Desktop is primary, but a supervisor checking a queue from a tablet must not
   meet a horizontally scrolling form. Tables may scroll inside their own box;
   forms collapse to one column instead.
   ───────────────────────────────────────────────────────────────────────── */

@media (max-width: 1024px) {
    .fi-section-content .fi-fo-component-ctn {
        grid-template-columns: 1fr;
    }

    .fi-header {
        gap: 0.75rem;
    }

    .fi-header-heading {
        font-size: 1.1875rem;
    }
}

@media (max-width: 640px) {
    .fi-ta-ctn {
        overflow-x: auto;
    }

    .fi-ta-cell {
        padding-block: 0.5rem;
    }

    .fi-wi-stats-overview-stat-value {
        font-size: 1.5rem;
    }
}

/*
 * Respect a reduced-motion preference. Filament animates panels and modals; a
 * person who has asked the operating system to stop that has asked us too.
 */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms;
        animation-iteration-count: 1;
        transition-duration: 0.01ms;
    }
}

/* ─────────────────────────────────────────────────────────────────────────────
   10. Row rhythm

   Rows should be the same height. A long workplace name wrapping to three lines
   made the list scan like a ransom note and cost a third of the visible rows, so
   text cells clamp to two lines and the full value stays available as a tooltip.
   ───────────────────────────────────────────────────────────────────────── */

.fi-ta-text-item-label {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* ─────────────────────────────────────────────────────────────────────────────
   11. Tenant label

   The brand above says which PRODUCT this is; this says whose data is on screen.
   Quiet by design — it is orientation, not a heading, and somebody who only ever
   belongs to one organization should be able to stop noticing it.
   ───────────────────────────────────────────────────────────────────────── */

.msafe-tenant {
    /*
     * `flex-shrink: 0` — ve bu satır süs değil.
     *
     * `.fi-sidebar-nav` bir flex sütun. Varsayılan `flex-shrink: 1` ile bu etiket,
     * dikey yer daraldığında (kısa laptop ekranı + menüde çok öğe) kendi içeriğinin
     * altına eziliyor: yükseklik 30px'ten 14px'e düşüyor ve `overflow: hidden`
     * firma adının alt yarısını kesiyordu. Menü zaten kaydırılabilir; yer bulması
     * gereken o, bu etiket değil.
     */
    flex-shrink: 0;
    margin: 0 0 0.75rem;
    padding: 0.375rem 0.625rem;
    border: 1px solid var(--msafe-border);
    border-radius: var(--msafe-radius);
    background-color: var(--msafe-surface-sunken);
    font-size: 0.75rem;
    font-weight: 560;
    color: var(--msafe-ink-muted);
    line-height: 1.3;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ─────────────────────────────────────────────────────────────────────────────
   12. System health

   ⚠️ Written as real CSS rather than as Tailwind utilities in the Blade file,
   and that is not a preference. This repository has no frontend build — no
   node_modules, nothing compiled — so `flex`, `gap-4` and friends are not in
   any stylesheet the panel loads. A view written with them renders as an
   unstyled vertical stack, which is exactly how the first cut of this page
   came out: icon, title and text piled on top of each other.

   The classes below are the page's own, prefixed `msafe-health-`, so they
   cannot collide with a `.fi-` class Filament may add later.
   ───────────────────────────────────────────────────────────────────────── */

.msafe-health-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.msafe-health-item {
    display: flex;
    align-items: flex-start;
    gap: 0.875rem;
    padding: 1rem 1.25rem;
    border-bottom: 1px solid var(--msafe-border);
}

.msafe-health-item:last-child {
    border-bottom: 0;
}

/* Fixed size, and `flex-shrink: 0` so a long remedy line cannot squash it. */
.msafe-health-icon {
    flex: 0 0 auto;
    width: 1.25rem;
    height: 1.25rem;
    margin-top: 0.125rem;
}

.msafe-health-icon svg {
    width: 100%;
    height: 100%;
}

/* Reuses the palette's existing semantic hues rather than introducing a
   parallel set. A passing check and a passing inspection should be the same
   green, and both already have a dark-theme value defined above. */
.msafe-health-icon--success { color: var(--msafe-pass); }
.msafe-health-icon--warning { color: var(--msafe-review); }
.msafe-health-icon--danger  { color: var(--msafe-fail); }

.msafe-health-body {
    min-width: 0;
    flex: 1 1 auto;
}

/* Wraps, so a narrow window moves the badge under the name instead of
   overflowing the card. */
.msafe-health-heading {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin: 0 0 0.25rem;
}

.msafe-health-name {
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--msafe-ink);
}

.msafe-health-detail {
    margin: 0;
    font-size: 0.875rem;
    line-height: 1.5;
    color: var(--msafe-ink-muted);
}

/* Quieter than the observation above it: what was measured comes first, what
   to do about it second. */
.msafe-health-remedy {
    margin: 0.375rem 0 0;
    font-size: 0.8125rem;
    line-height: 1.5;
    color: var(--msafe-ink-faint);
}

.msafe-health-note {
    margin: 1rem 0 0;
    font-size: 0.8125rem;
    line-height: 1.6;
    color: var(--msafe-ink-muted);
}

/* ─────────────────────────────────────────────────────────────────────────────
   13. Organization chooser

   Rendered OUTSIDE the Filament panel — every panel route requires the tenant
   context this screen exists to establish — so it inherits none of Filament's
   own styles and sets its own body, font and box model here. It reads as the
   same product because it uses the same tokens, not because it shares markup.
   ───────────────────────────────────────────────────────────────────────── */

.msafe-chooser {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    margin: 0;
    padding: 1.5rem;
    box-sizing: border-box;
    background-color: var(--msafe-canvas);
    font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    color: var(--msafe-ink);
}

.msafe-chooser *,
.msafe-chooser *::before,
.msafe-chooser *::after {
    box-sizing: inherit;
}

.msafe-chooser-card {
    width: 100%;
    max-width: 26rem;
    padding: 2rem;
    border: 1px solid var(--msafe-border);
    border-radius: var(--msafe-radius-lg);
    background-color: var(--msafe-surface);
    box-shadow: var(--msafe-shadow-raised);
}

.msafe-chooser-brand {
    margin: 0 0 1.5rem;
    font-size: 0.8125rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--msafe-ink-muted);
}

.msafe-chooser-title {
    margin: 0 0 0.5rem;
    font-size: 1.25rem;
    font-weight: 620;
    line-height: 1.3;
}

.msafe-chooser-lead {
    margin: 0 0 1.5rem;
    font-size: 0.875rem;
    line-height: 1.6;
    color: var(--msafe-ink-muted);
}

.msafe-chooser-error {
    margin: 0 0 1rem;
    padding: 0.625rem 0.75rem;
    border: 1px solid var(--msafe-fail);
    border-radius: var(--msafe-radius);
    font-size: 0.8125rem;
    color: var(--msafe-fail);
}

.msafe-chooser-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

/* A full-width button rather than a link: choosing is a POST, because it changes
   which tenant the session is bound to. */
.msafe-chooser-option {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    width: 100%;
    padding: 0.875rem 1rem;
    border: 1px solid var(--msafe-border);
    border-radius: var(--msafe-radius);
    background-color: var(--msafe-surface);
    font: inherit;
    text-align: left;
    cursor: pointer;
    transition: border-color 120ms ease, background-color 120ms ease;
}

.msafe-chooser-option:hover {
    border-color: var(--msafe-border-strong);
    background-color: var(--msafe-surface-sunken);
}

.msafe-chooser-option:focus-visible {
    outline: 2px solid var(--msafe-approved);
    outline-offset: 2px;
}

.msafe-chooser-option-name {
    font-size: 0.9375rem;
    font-weight: 560;
    color: var(--msafe-ink);
}

.msafe-chooser-option-go {
    color: var(--msafe-ink-faint);
}

.msafe-chooser-note {
    margin: 1.5rem 0 0;
    font-size: 0.8125rem;
    line-height: 1.5;
    color: var(--msafe-ink-faint);
}


/* ─────────────────────────────────────────────────────────────────────────────
 * Findings read from the report, shown on the create page
 *
 * A control's non-conformities live in a relation manager, which needs a saved
 * record. This is the same information before there is one: what the report says
 * is wrong with the equipment, while the operator still has the PDF open beside
 * the form. Read-only — the rows themselves are created at verification.
 * ───────────────────────────────────────────────────────────────────────────── */

.msafe-findings {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.msafe-finding {
    padding: 0.75rem 0.875rem;
    border: 1px solid var(--msafe-border);
    border-radius: 0.5rem;
    background-color: var(--msafe-surface-sunken);
}

/* The control item: what was checked. Secondary to the defect itself. */
.msafe-finding-item {
    font-size: 0.8125rem;
    line-height: 1.45;
    color: var(--msafe-ink-faint);
}

.msafe-finding-item strong {
    font-variant-numeric: tabular-nums;
    color: var(--msafe-ink);
}

/* The defect: what the inspector actually wrote, and what Migros reads. */
.msafe-finding-text {
    margin-top: 0.25rem;
    font-size: 0.875rem;
    line-height: 1.5;
    color: var(--msafe-ink);
}

/* An item marked UD whose defect the report never described — the operator's to write. */
.msafe-finding-missing {
    color: var(--msafe-ink-faint);
    font-style: italic;
}

/* ─────────────────────────────────────────────────────────────────────────────
 * Bulk intake — three groups, three different actions
 *
 * Ready reports are pressed, incomplete ones are opened and fixed, and files
 * that never became reports are handled outside the system. A single list
 * sorted by status would make the operator work out which is which, so each
 * group is its own panel with its own count.
 *
 * Every action lives in the page header, where this panel keeps them — nothing
 * here is a button.
 * ───────────────────────────────────────────────────────────────────────────── */

.msafe-batch {
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
}

/* ── Waiting ──────────────────────────────────────────────────────────────────
 *
 * The banner shown while items are still queued.
 *
 * This screen used to render nothing at all between the upload and the first
 * finished item — a heading saying files were being processed, above blank space.
 * Twenty reports take minutes on a single worker, so the blank state was the state
 * an operator saw for most of the wait, and it reads as "the upload did not work".
 *
 * The bar is the part that carries the information; the spinner only says the page
 * is still live between the 5s polls, which a bar that sits still at 3/20 cannot.
 * ───────────────────────────────────────────────────────────────────────────── */

.msafe-batch-progress-banner {
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: center;
    gap: 0.25rem 0.75rem;
    padding: 0.875rem 1rem;
    border: 1px solid var(--msafe-border);
    border-radius: 0.625rem;
    background-color: var(--msafe-surface);
}

.msafe-batch-progress-text {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
}

.msafe-batch-progress-text strong {
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--msafe-ink);
}

.msafe-batch-progress-text span {
    font-size: 0.75rem;
    font-variant-numeric: tabular-nums;
    color: var(--msafe-ink-muted);
}

/* Full width under both columns — the count above it is what the bar restates. */
.msafe-progress {
    grid-column: 1 / -1;
    margin-top: 0.5rem;
    height: 0.25rem;
    border-radius: 999px;
    background-color: var(--msafe-border);
    overflow: hidden;
}

.msafe-progress > span {
    display: block;
    height: 100%;
    border-radius: inherit;
    background-color: var(--msafe-approved);
    /* Each poll jumps the width; the transition turns that into movement. */
    transition: width 0.4s ease;
}

.msafe-spinner {
    width: 1rem;
    height: 1rem;
    border: 2px solid var(--msafe-border-strong);
    border-top-color: var(--msafe-approved);
    border-radius: 50%;
    animation: msafe-spin 0.7s linear infinite;
}

@keyframes msafe-spin {
    to {
        transform: rotate(1turn);
    }
}

/*
 * An indefinite spin is exactly the animation vestibular disorders react to, and
 * this one runs for minutes. The bar and the count still say everything the
 * spinner said, so stopping it costs the reader nothing.
 */
@media (prefers-reduced-motion: reduce) {
    .msafe-spinner {
        animation: none;
    }

    .msafe-progress > span {
        transition: none;
    }
}

/* Queued files: present, named, and visibly not yet anybody's to act on. */
.msafe-batch-working .msafe-batch-row {
    opacity: 0.65;
}

.msafe-batch-group {
    padding: 0.875rem 1rem 1rem;
    border: 1px solid var(--msafe-border);
    border-radius: 0.625rem;
    background-color: var(--msafe-surface-sunken);
}

.msafe-batch-group h3 {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0 0 0.75rem;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--msafe-ink-faint);
}

/* The count belongs to the heading, not to a separate column that would drift from it. */
.msafe-batch-count {
    padding: 0.0625rem 0.4375rem;
    border-radius: 999px;
    background-color: var(--msafe-border);
    font-size: 0.6875rem;
    font-variant-numeric: tabular-nums;
    letter-spacing: 0;
    color: var(--msafe-ink);
}

.msafe-batch-group ul {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
}

.msafe-batch-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.625rem 0.75rem;
    border-radius: 0.5rem;
    background-color: var(--msafe-surface);
    border: 1px solid var(--msafe-border);
}

.msafe-batch-main {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    /* So a long blocker sentence wraps instead of pushing "Aç" off the row. */
    min-width: 0;
}

.msafe-batch-name {
    font-size: 0.875rem;
    font-variant-numeric: tabular-nums;
    color: var(--msafe-ink);
}

.msafe-batch-detail {
    font-size: 0.8125rem;
    line-height: 1.45;
    color: var(--msafe-ink-faint);
}

.msafe-batch-open {
    flex-shrink: 0;
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--msafe-ink-faint);
    text-decoration: none;
}

.msafe-batch-open:hover {
    color: var(--msafe-ink);
    text-decoration: underline;
}

.msafe-batch-progress {
    margin: 0;
    font-size: 0.875rem;
    color: var(--msafe-ink-faint);
}

/* ─────────────────────────────────────────────────────────────────────────────
 * "Being read" — a table whose answer has not arrived yet
 *
 * Extraction runs on a worker, so a record's findings table is legitimately empty
 * for the first seconds of its life. It used to say "Uygunsuzluk yok", which is
 * true, final in tone, and was read by operators as the report having failed.
 *
 * The spinner is the same one the bulk intake screen uses, and stops for the same
 * reason under prefers-reduced-motion — the sentence beside it says everything it
 * says.
 * ───────────────────────────────────────────────────────────────────────────── */

.msafe-reading {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
}

.msafe-reading .msafe-spinner {
    width: 1.5rem;
    height: 1.5rem;
    border-width: 2px;
    margin-bottom: 0.25rem;
}
