/*
 * Task F4.E6.T3 - the "app-" component vocabulary Zalacznik E names (cards,
 * tables-with-headers, status badges, alerts, buttons) plus a handful of
 * semantic-attribute rules ("[role=alert]"/"[role=status]") that dress the
 * SAME markup this codebase already emits everywhere (measured: 165
 * occurrences of role="alert"/role="status" across 55 ".razor" files - the
 * count of FILES read "54" until task F4.E6.T3b re-counted it; the 165 was
 * right) without adding a class to each one. Forms are deliberately NOT
 * re-styled here: base.css (task F4.E6.T1) already gives every bare
 * label/input/select/textarea/button/".validation-message" the full
 * Zalacznik E form treatment (label above field, paper-200 border, teal
 * focus, brick error text) - nothing in this file repeats or narrows that.
 *
 * Every color below is a custom property, never a literal. That sentence
 * used to read "no new hex value is introduced anywhere in this file" and was
 * FALSE when written: this file carried a raw white hex literal on four
 * lines (card background plus three button faces), at lines 47/247/258/265 of
 * the file as it shipped. Task F4.E6.T3b moved that one literal
 * into tokens.css as "--color-white" (see that file's own remark for why the
 * www palette has no white of its own) and pinned the rule with a test
 * instead of a sentence - BrandLayerColorTokenGuardTests reads this file,
 * base.css and app.css and fails on any hex/rgb()/hsl() literal in a
 * declaration value (Zalacznik E's own "brick ZAREZERWOWANY dla pilnosci ...
 * nie dekoracja" is why off-palette colors matter here at all).
 *
 * Two custom properties used below are deliberately NOT from tokens.css:
 * "--partner-primary-color"/"--partner-accent-color" are declared per request
 * on ":root" by the "/branding/theme.css" stylesheet Components/App.razor
 * links (task F2.E2.T2 - tenant branding, N68 app-B: a stylesheet, no longer
 * a nonce'd <style>), and "--branding-preview-*" likewise by
 * "/partner/branding/preview.css" linked from
 * Components/Pages/Partners/PartnerBrandingEditor.razor. Both are tenant
 * DATA, not brand tokens; see the branding section at the foot of this file.
 *
 * AA contrast (WCAG 2.1 SC 1.4.3, >= 4.5:1 for normal-size text), computed
 * with the standard relative-luminance formula against the two backgrounds
 * this file actually paints text on - "measured", not asserted, values in
 * this task's own report:
 *   ink-950   #0b0f17 on paper-50  #f5f6f4 (page text)            17.69:1
 *   ink-950   #0b0f17 on paper-100 #ecefea (card/alert/badge text) 16.53:1
 *   teal-600  #0f766e on paper-100 #ecefea (badge "active" text)    4.72:1
 *   slate-600 #4b5563 on paper-100 #ecefea (badge "pending" text)   6.51:1
 *   brick-600 #9a3412 on paper-100 #ecefea (badge "urgent" text)    6.30:1
 *   paper-50  #f5f6f4 on teal-600  #0f766e (primary button text)    5.05:1
 * All six clear 4.5:1. brick-400 #c2540f on paper-100 is 3.96:1 (below
 * threshold) - that pair is used ONLY as a decorative border-left below
 * (".app-alert--warning"), never as text color, so SC 1.4.3 (text only)
 * does not apply to it; ink-950 carries all warning-alert TEXT instead.
 *
 * N82 adds the secondary <button> ("button.app-btn--secondary" below) on
 * the white card face, computed with the same formula:
 *   ink-900   #131a26 on white     #ffffff (secondary button text)  17.45:1
 *   slate-600 #4b5563 on white     #ffffff (secondary button border) 7.56:1
 *   ink-950   #0b0f17 on paper-100 #ecefea (secondary button hover) 16.53:1
 * The border is the one thing that tells this button apart from the card,
 * so it is held to WCAG 2.1 SC 1.4.11 (non-text contrast, >= 3:1): the
 * paper-200 border ".app-btn--secondary" draws for links is 1.30:1 on
 * white and slate-400 2.56:1 - both below - hence slate-600 on buttons.
 */

/* ---------------------------------------------------------------------- *
 * Cards (Zalacznik E: "karty biale/paper-50 z krawedzia paper-200 i
 * subtelnym cieniem"). Scoped to the bare <section> element rather than a
 * new class: every page this task touches already groups its own content in
 * <section> (measured before writing this rule - Home.razor,
 * UpcomingDeadlinesWidget.razor, PartnerSubscription.razor,
 * PartnerBrandingEditor.razor, PlatformMetricsDashboard.razor were the only
 * five files in the whole Components tree using it), so this one rule
 * dresses every existing and newly-added <section> the same way with zero
 * per-call-site class attribute.
 * ---------------------------------------------------------------------- */
section {
  background-color: var(--color-white);
  border: 1px solid var(--color-paper-200);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
  padding: var(--space-6);
  margin: 0 0 var(--space-6);
}

section > h2:first-child,
section > h3:first-child {
  margin-top: 0;
}

section > :last-child {
  margin-bottom: 0;
}

/* ---------------------------------------------------------------------- *
 * Tables in scroll containers (Zalacznik E: "tabele w overflow-x:auto";
 * this task's own DoD (b)). Deliberately carries NO border/background of its
 * own - every call site below wraps a table that already lives inside a
 * ".app-shell-content section" card, so a second border here would nest
 * uselessly; this class's only job is establishing the scroll boundary
 * MainLayout.razor.css's own ".app-shell-content" remarks describe (that
 * rule stays as the safety net, this container is what actually catches the
 * overflow now - see docs/tech-debt.md "F4.E6.T3" for the measured
 * before/after this produces on the two routes MainLayout.razor.css's own
 * comment named as still needing it).
 * ---------------------------------------------------------------------- */
.app-table-container {
  overflow-x: auto;
}

.app-table-container table {
  width: 100%;
  margin: 0;
}

/* Task F4.E6.T3's own first measured attempt applied "overflow-wrap: anywhere"
   to every cell in every wrapped table, on the theory that it would shrink
   the "Zmienione przez" e-mail column's contribution to the table's
   min-content width. Measured against a real 390px screenshot instead of
   reasoned about: it did the opposite of what a scroll container is FOR -
   the table's auto-layout algorithm shrank every OTHER column too (down to
   one letter per line on header text like "Krytycznosc"), because
   "anywhere" lets it break at any character, not only the one long token
   this was aimed at. Removed: with no "overflow-wrap" at all, the table
   keeps its natural min-content width and ".app-table-container"'s own
   "overflow-x: auto" scrolls it as a whole - measured unchanged after
   removing this rule (document.documentElement.scrollWidth still equals
   innerWidth on every route at both viewports, this task's own DoD (b); see
   this task's own report for the numbers). The 360px e-mail column is a
   genuine content fact - shrinking ITS presentation by breaking words is a
   change this task's own "ZERO zmian tresci" scope does not license doing
   at the expense of every other column's readability. */

/* N87: the gap under a table. base.css gives every heading and paragraph
   "margin: 0 0 var(--space-4)" but a table no margin at all, and
   ".app-table-container table" above sets it to 0 on purpose, so whatever
   follows a table (the "Oczekujace zaproszenia" heading under the users
   table on /partner/clients/users, a "Powrot" link, a "Nastepna strona"
   link) touched its bottom border - census 7.10, 0 to 2 px at 1920 and
   390 px on four pages. The same 16 px rhythm as a paragraph, on the
   outermost box (the scroll container when there is one, else the table),
   and only when something follows it in the same parent: a table that is
   the last child of a <section> card keeps "section > :last-child" at 0,
   so the card's own padding is the only gap there (measured unchanged). */
:is(table, .app-table-container):not(:last-child) {
  margin-bottom: var(--space-4);
}

/* ---------------------------------------------------------------------- *
 * Status badges (Zalacznik E: "badge statusow z tokenow (aktywne=teal,
 * w-toku=slate, pilne/przeterminowane=brick)"). Text-carrying (never color-
 * only - Zalacznik E: "zero informacji wylacznie kolorem"): the localized
 * status word is always the badge's own text content, this only adds a
 * color-coded pill around it.
 * ---------------------------------------------------------------------- */
.app-badge {
  display: inline-flex;
  align-items: center;
  padding: 0.125rem 0.5rem;
  border-radius: 999px;
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.25;
  border: 1px solid transparent;
  background-color: var(--color-paper-100);
}

.app-badge--active {
  color: var(--color-teal-600);
  border-color: var(--color-teal-300);
}

.app-badge--pending {
  color: var(--color-slate-600);
  border-color: var(--color-paper-200);
}

.app-badge--urgent {
  color: var(--color-brick-600);
  border-color: var(--color-brick-400);
}

/* ---------------------------------------------------------------------- *
 * Alerts (Zalacznik E: "alerty 4 warianty (info=slate, sukces=teal,
 * ostrzezenie=brick-400, blad=brick-600)"). Keyed off the ARIA role this
 * codebase already puts on every one of these elements rather than a new
 * class - see this file's own header remarks for the measured occurrence
 * count. Scoped to <p>/<div>/<ul> (":where()" carries zero specificity of
 * its own, so the ".app-alert--success"/"--warning" modifiers below can
 * still override "border-left-color" by source order alone, no higher
 * specificity needed) - NOT <strong>, which this codebase uses exactly once
 * (RegisterSuppliersList.razor's inline "gap" marker inside a table cell) as
 * an inline emphasis, not a block callout; that one keeps its own narrower
 * rule further down.
 * ---------------------------------------------------------------------- */
:where(p, div, ul)[role="status"] {
  display: block;
  padding: var(--space-3) var(--space-4);
  margin: 0 0 var(--space-4);
  border-radius: var(--radius-sm);
  border-left: 4px solid var(--color-slate-600);
  background-color: var(--color-paper-100);
  color: var(--color-ink-950);
}

:where(p, div, ul)[role="alert"] {
  display: block;
  padding: var(--space-3) var(--space-4);
  margin: 0 0 var(--space-4);
  border-radius: var(--radius-sm);
  border-left: 4px solid var(--color-brick-600);
  background-color: var(--color-paper-100);
  color: var(--color-ink-950);
}

/* The two roles above cover every existing call site as either "info"
   (role=status) or "blad" (role=alert, brick-600). "Sukces"/"ostrzezenie"
   are opt-in modifiers for the few call sites this task's own report names
   explicitly (PlanReadOnlyBanner.razor/ImpersonationBanner.razor keep
   role="alert" - an active billing/impersonation state is still the
   "interrupts" ARIA semantic - but read as the softer brick-400 tone, not
   the hard brick-600 error one). */
.app-alert--success {
  border-left-color: var(--color-teal-600);
}

.app-alert--warning {
  border-left-color: var(--color-brick-400);
}

/* RegisterSuppliersList.razor's own inline gap marker used to be selected
   here as strong[role="alert"] - color only, no box, so it stayed inline
   inside its <td> instead of breaking table layout. Session UI1 (finding Z-9)
   took the role off that element: it was an ARIA live region on a static
   cell repeated once per gap row, so a screen-reader user was interrupted
   once per row on entering the list. The rule is removed rather than left
   standing, because after that change nothing in this codebase matches it
   (measured: exactly one <strong role="alert"> existed, and it was that one).
   The paint it used to do now lives on ".app-flag--gap" further down, with
   the identical declaration. */

/* ---------------------------------------------------------------------- *
 * Row/line-item urgency (Zalacznik E: brick reserved for deadline urgency).
 * Replaces two identical inline "style=" attributes this task's own audit
 * found (OrgDeadlinesList.razor / UpcomingDeadlinesWidget.razor, both
 * "font-weight:bold;color:#b00020;" - an off-palette hex, and Zalacznik E's
 * own "ZAKAZY: inline style=" ban) with one shared class using the brick
 * token instead.
 * ---------------------------------------------------------------------- */
.app-text-urgent {
  color: var(--color-brick-600);
  font-weight: 600;
}

/* ---------------------------------------------------------------------- *
 * Risk-matrix cells (RegisterRiskMatrix.razor) - the same "urgent"/"ok"
 * distinction as the badges above, expressed as a cell border rather than a
 * badge (Zalacznik E's own vocabulary does not name a matrix-cell shape
 * explicitly; this reuses the badge palette rather than inventing a new
 * one).
 * ---------------------------------------------------------------------- */
.app-matrix-cell--risk {
  border: 2px solid var(--color-brick-600);
  color: var(--color-brick-600);
  font-weight: 600;
}

.app-matrix-cell--ok {
  color: var(--color-teal-600);
}

/* ---------------------------------------------------------------------- *
 * Buttons (Zalacznik E: "przyciski primary (teal-600, hover teal-500) /
 * secondary (obrys) / destructive (brick-600)"). base.css's own bare
 * <button> rule already IS "primary" (teal-600 fill, teal-500 hover) - nothing
 * repeats that here. These two modifiers are for the <a>-rendered row
 * actions (Edytuj/Usun and similar) this task dresses as buttons instead of
 * plain underlined links, so all three variants are visibly demonstrated on
 * the same screen (e.g. RegisterAssetsList.razor's own action column).
 * ---------------------------------------------------------------------- */
.app-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: inherit;
  font-weight: 600;
  font-size: 0.875rem;
  text-decoration: none;
  border-radius: var(--radius-sm);
  padding: var(--space-1) var(--space-3);
  min-height: 2rem;
  border: 1px solid transparent;
  cursor: pointer;
  transition: background-color var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);
}

.app-btn--secondary {
  background-color: var(--color-white);
  color: var(--color-ink-900);
  border-color: var(--color-paper-200);
}

.app-btn--secondary:hover {
  border-color: var(--color-slate-400);
  color: var(--color-ink-950);
}

.app-btn--destructive {
  background-color: var(--color-white);
  color: var(--color-brick-600);
  border-color: var(--color-brick-400);
}

.app-btn--destructive:hover {
  background-color: var(--color-brick-600);
  color: var(--color-white);
  border-color: var(--color-brick-600);
}

/* N82: the secondary modifier on a real <button> (PartnerSubscription.razor's
   "prepare payment" once the Paddle button is on the screen). Without the
   ".app-btn" base on purpose: that base shrinks a button to 2rem, under the
   2.5rem touch target base.css gives every <button>, and the two buttons sit
   one above the other. The bare "button:hover" rule in base.css would
   otherwise repaint the face teal under dark text, so hover is restated
   here. Contrast pairs: see this file's header. */
button.app-btn--secondary {
  border-color: var(--color-slate-600);
}

button.app-btn--secondary:hover {
  background-color: var(--color-paper-100);
  border-color: var(--color-ink-900);
  color: var(--color-ink-950);
}

/* N82: a vertical run of actions (a form's own submit, then the next step's
   button) with a fixed gap between them at every width. Children keep
   their block behaviour; a direct <button> keeps its own width instead of
   stretching across the card. */
.app-action-stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.app-action-stack > button {
  align-self: flex-start;
}

/* ---------------------------------------------------------------------- *
 * Form grouping (DocumentWizard.razor/QualificationWizard.razor/
 * OrganizationProfile.razor's own repeated <fieldset>/<legend> per
 * question/variable - bare elements base.css does not style, same
 * "component vocabulary belongs to T2/T3" boundary that file's own remarks
 * already draw for cards/badges/alerts).
 * ---------------------------------------------------------------------- */
fieldset {
  border: 1px solid var(--color-paper-200);
  border-radius: var(--radius-sm);
  padding: var(--space-4);
  margin: 0 0 var(--space-4);
}

legend {
  font-family: var(--font-display);
  font-weight: 500;
  padding: 0 var(--space-2);
}

/* ---------------------------------------------------------------------- *
 * Definition lists (RegisterIncidentDetail.razor/PartnerSubscription.razor's
 * own read-only "label: value" summaries) - another bare element base.css
 * leaves alone.
 * ---------------------------------------------------------------------- */
dl {
  margin: 0;
  display: grid;
  grid-template-columns: max-content 1fr;
  column-gap: var(--space-4);
  row-gap: var(--space-2);
}

dt {
  font-weight: 600;
  color: var(--color-slate-600);
}

dd {
  margin: 0;
}

/* ---------------------------------------------------------------------- *
 * Tenant branding - the two places this application paints with a PARTNER's
 * own colors rather than with brand tokens.
 *
 * Why these rules exist here at all (task F4.E6.T3b): both places used to
 * carry their colors in inline "style=" attributes, and this application's
 * Content-Security-Policy (SecurityHeadersMiddleware, task F4.E2.T1) serves
 * "style-src 'self' 'nonce-...'" with no 'unsafe-inline' - and a nonce
 * covers <style> ELEMENTS only, never a style ATTRIBUTE. Measured in real
 * Chromium against "http://demo-it.localhost:5077/login" before this task:
 * the partner header's "style" attribute was dropped entirely
 * (element.style.length === 0), its computed border-top was
 * "0px none rgb(11, 15, 23)" and the partner name rendered in the inherited
 * ink at weight 400, with two "Applying inline style ... violates the
 * following Content Security Policy directive" console violations. The CSS
 * custom properties resolved correctly the whole time - nothing was PAINTING
 * with them, because their only consumers were attributes the browser threw
 * away. Classes here are read from the very stylesheet the policy allows.
 *
 * "--partner-primary-color"/"--partner-accent-color" come from the
 * per-request "/branding/theme.css" stylesheet Components/App.razor links on
 * ":root" (task F2.E2.T2, N68 app-B). Contrast: the accent is used as text on the platform's own
 * light background, which is exactly the "checked against white" assumption
 * PartnerBrandingContrastEvaluator (task F2.E2.T1) warns the partner about in
 * the editor; the primary is a decorative border only, so SC 1.4.3 does not
 * apply to it.
 * ---------------------------------------------------------------------- */
.partner-header {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-2);
  border-top: 4px solid var(--partner-primary-color);
}

.partner-header__logo {
  max-height: 2rem;
}

.partner-header__name {
  color: var(--partner-accent-color);
  font-weight: 600;
}

/* The branding editor's own live preview (task F2.E2.T1). Its colors are the
   partner's not-yet-applied SAVED values, which need not equal the ":root"
   ones above (the editor is reachable on the apex host too, where no partner
   theme is resolved at all), so the page links its own
   "--branding-preview-*" pair from "/partner/branding/preview.css" (N68
   app-B, formerly its own nonce'd <style> element) - see that file's own
   remarks. Every value it interpolates is re-validated to the strict #RRGGBB
   shape first. */
.branding-preview__logo {
  max-height: 4rem;
}

.branding-preview__name {
  color: var(--branding-preview-primary-color);
}

.branding-preview__swatch {
  display: inline-block;
  width: 1rem;
  height: 1rem;
  vertical-align: text-bottom;
  border: 1px solid var(--color-paper-200);
}

.branding-preview__swatch--primary {
  background-color: var(--branding-preview-primary-color);
}

.branding-preview__swatch--accent {
  background-color: var(--branding-preview-accent-color);
}

/* ---------------------------------------------------------------------- *
 * Session UI1 - the vocabulary this session adds. Every rule below exists
 * because a finding from the 2026-08-22 black-box click-through
 * (business-research/docs/2026-08-22-przeklikanie-app-szbihub-pl.md) needed
 * a CLASS rather than a repainted bare element; the bare-element half of
 * the same repairs lives in base.css, per that file's own scope boundary.
 * Zero hex/rgb literals here either - BrandLayerColorTokenGuardTests reads
 * this file.
 * ---------------------------------------------------------------------- */

/* Off-screen but announced (findings Z-9, E.10). Standard clip idiom -
   deliberately NOT "display: none"/"visibility: hidden", which remove the
   text from the accessibility tree, which is the opposite of the point.
   Used for <caption> elements (a table needs a name for a screen reader,
   but every one of these tables already sits under its own visible
   heading, so a second visible title would be noise) and for the
   supplier-register gap marker's screen-reader prefix. */
.app-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* "Przejdz do tresci" (finding E.10) - the first focusable element in the
   document, invisible until it takes keyboard focus. No JavaScript: a
   plain in-page anchor that moves focus to <main>. */
.app-skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 1001;
  padding: var(--space-2) var(--space-4);
  background-color: var(--color-white);
  color: var(--color-ink-950);
  border: 1px solid var(--color-paper-200);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-sm);
}

.app-skip-link:focus {
  left: var(--space-4);
  top: var(--space-2);
}

/* One field: its own <label for> and its own control (finding Z-6). The
   five register forms used to wrap EVERY single field in its own
   <fieldset>/<legend>, which drew a 1152px frame around a 241px control
   and left the control itself with no accessible name at all (measured on
   "/registers/assets/new": 5 of 5 fields with no id, no label[for], no
   aria-label; clicking the caption left document.activeElement on the H1).
   The <fieldset> rule above is untouched and still correct for what its
   own comment describes - a QUESTION with several answers, in the three
   wizards. Zalacznik E: "formularze: etykieta nad polem". */
.app-field {
  margin: 0 0 var(--space-4);
}

.app-field > input,
.app-field > select,
.app-field > textarea {
  display: block;
  width: 100%;
  max-width: 32rem;
}

.app-field > textarea {
  min-height: 6rem;
}

/* N86: the gap between a form's controls and whatever comes next. The focus
   ring is a 2px outline drawn 2px outside the control (base.css), so
   anything closer than 4px gets drawn over, and anything closer than about
   12px reads as glued on. Measured before this block, on a static copy of
   every page in Components rendered with these very stylesheets in Chromium
   at 1920 and 390px: 30 "back to the list" links 2px under a form's last
   button, a "Zapisz" button touching the next form's frame on
   /partner/branding, the "Haslo" field touching "Zaloguj sie" on /login, the
   filter forms' "Filtruj" 4px under the last filter, and eight one-field
   forms with the button 4.5px beside the field - and 0px under it once the
   line wraps at a phone width. Each rule below closes one of those shapes
   and nothing else. The target is 16px, the rhythm this app already uses
   between fields (.app-field, fieldset, p). */

/* A form followed by the paragraph that carries its "back" link, or by the
   next form (whose first child may be a framed fieldset). */
form + :is(p, form) {
  margin-top: var(--space-4);
}

/* A plain wrapper around one label, one field and its validation message
   (Login.razor) spaces like .app-field. Only a wrapper with no class at all,
   so .app-field, .app-honeypot and every other classed block keep their own
   rules. */
form > div:not([class]) {
  margin-bottom: var(--space-4);
}

/* The button under a label that wraps its own field (the register filter
   forms, DocumentApprove, OnboardingChecklist). The label already carries
   4px of bottom margin (base.css), so 12px more gives the same 16px. */
form > label + button {
  margin-top: var(--space-3);
}

/* A field placed directly in the form with its button on the same line
   (LoginWith2fa, LoginWithRecoveryCode, ForgotPassword, ResetPassword,
   AcceptInvitation, TwoFactorSetup, CultureSettings, OrganizationSelector).
   The right margin is the gap beside the button. */
form > :is(input:not([type="hidden"], [type="checkbox"], [type="radio"]), select) {
  margin-right: var(--space-2);
}

/* The bottom margin is the gap under the field when the line wraps on a
   narrow screen and the button drops below it, and before the next label in
   a multi-field form. Only when the button or the label follows the field
   DIRECTLY: once the field is invalid, Blazor puts its validation message
   between the two, and that message has to stay 4px under its own field
   (base.css), not 16px. A browser without ":has()" drops this rule and keeps
   the old look. */
form > :is(input:not([type="hidden"], [type="checkbox"], [type="radio"]), select):has(+ :is(button, label)) {
  margin-bottom: var(--space-3);
}

/* The same forms in the error state: the field, its message, then the
   button or the next label. */
form > .validation-message + :is(button, label) {
  margin-top: var(--space-3);
}

/* N91 U3 (H-N90-11): the filter form above a register table (suppliers, assets,
   risks, incidents, platform audit log). Measured on a static copy of the five
   pages with these very stylesheets (Chromium, 1440 and 390px): the form was a
   bare <form> of <label>s holding text and field in one line, so each field
   started where its own label text ended (left edges 35 to 96px apart), field
   widths followed their content (124 to 319px), "Filtruj" sat 4px under the
   last field and the table container under the form had 0px above it - the
   rule "form + :is(p, form)" above only reaches a paragraph or a form, not the
   .app-table-container that stands there once the rows have loaded.

   A grid of equal columns that wrap (the minimum is capped at the container
   width, so a phone gets one column and no horizontal scroll): the label text
   sits ABOVE its field, every text field and list has the same width, the
   fields of one row share a top edge (align-items: end keeps them level even
   when one label wraps to two lines), the checkbox and the submit button start
   a new, last row, and the form keeps the 16px rhythm below itself, whatever
   follows it. Nothing here touches the filters' markup beyond this class, the
   names of the fields or the labels' wording. */
.app-filter-form {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 13rem), 1fr));
  align-items: end;
  gap: var(--space-3) var(--space-4);
  margin-bottom: var(--space-4);
}

.app-filter-form > label {
  margin-bottom: 0;
}

.app-filter-form > label > :is(input:not([type="checkbox"], [type="radio"], [type="hidden"]), select) {
  display: block;
  width: 100%;
  margin-top: var(--space-1);
}

/* The last row: the first of the checkbox and the button begins it, the button
   next to the checkbox stays in the same row. The general rule "form > label +
   button" above (12px under a label) is replaced by the grid gap. */
.app-filter-form > :is(label:has(> input[type="checkbox"]), button) {
  grid-column-start: 1;
}

.app-filter-form > label:has(> input[type="checkbox"]) + button {
  grid-column-start: auto;
}

.app-filter-form > button {
  margin-top: 0;
  justify-self: start;
}

/* A phone has one column, so the last row would be the checkbox alone and the button
   under it. From here down the grid is "1fr auto": every field label spans both columns
   (still one equal-width column of fields), the checkbox takes the first column and the
   button the narrow second one, side by side in the last row; on a page without the
   checkbox the button starts the row. */
@media (max-width: 30rem) {
  .app-filter-form {
    grid-template-columns: minmax(0, 1fr) auto;
  }

  .app-filter-form > label:not(:has(> input[type="checkbox"])) {
    grid-column: 1 / -1;
  }
}

/* Except in the header's organization switcher from 1024px up, where
   MainLayout.razor.css makes the header sticky at a pinned
   --app-shell-header-height: a bottom margin there would make the header
   taller than that height and slide it over the sticky navigation. The
   switcher's line does not wrap at those widths. */
@media (min-width: 1024px) {
  .app-shell-header form > :is(input:not([type="hidden"], [type="checkbox"], [type="radio"]), select) {
    margin-bottom: 0;
  }
}

/* An inline marker appended to a sentence (finding Z-7). Blazor trims the
   whitespace-only text node between an expression and the block that
   follows it (this app declares no "preservewhitespace" directive
   anywhere), so "Dostawca chmurowej kopii zapasowej" and "(brak oceny
   ryzyka)" rendered glued together. The separator is a margin rather than
   a space character precisely so it cannot be trimmed away again.

   The call sites ALSO emit an explicit @(" ") - an expression, which the
   compiler never trims - immediately before the element. Both are needed and
   neither is redundant: the space is what a screen reader and a
   copy-and-paste get (the margin is invisible to both), and the margin is
   what makes the marker read as a separate thing rather than as the last
   word of the sentence. Hence one space step, not two. */
.app-inline-note {
  margin-left: var(--space-1);
}

/* The interactive half of the same finding: "Odhacz krok" is a link, and
   it was rendering inside a sentence about art. 12c. Its own block, under
   the step text, not appended to it. */
.app-step-action {
  display: block;
  margin-top: var(--space-1);
}

/* Progress indicators (finding Z-15). The census before this session found
   0 <progress>, 0 role="progressbar" and 0 progress/meter/bar classes in
   the whole application, so "77% pokrycia wymagan" - the number a customer
   opens the panel for - read as a note in a grey box.

   The bar is the NATIVE <progress> element, not a pair of divs, for one
   hard reason: a two-div bar needs its fill width set per instance, and
   the only ways to do that are an inline "style=" attribute (banned by
   Zalacznik E, pinned by InlineStyleAttributeGuardTests, and dropped
   outright by this app's own CSP, which carries no 'unsafe-inline') or new
   JavaScript (also banned). A <progress value max> carries its own value,
   its own implicit role="progressbar" and its own accessible value, with
   no attribute and no script. */
.app-progress {
  margin: 0 0 var(--space-4);
}

.app-progress__value {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 2rem;
  line-height: 1.15;
  margin: 0;
}

.app-progress__caption {
  color: var(--color-slate-600);
  font-size: 0.875rem;
  margin: var(--space-1) 0 0;
}

.app-progress__track {
  appearance: none;
  -webkit-appearance: none;
  display: block;
  width: 100%;
  max-width: 24rem;
  height: 0.5rem;
  margin-top: var(--space-2);
  border: 0;
  border-radius: 999px;
  background-color: var(--color-paper-200);
  color: var(--color-teal-600);
}

.app-progress__track::-webkit-progress-bar {
  background-color: var(--color-paper-200);
  border-radius: 999px;
}

.app-progress__track::-webkit-progress-value {
  background-color: var(--color-teal-600);
  border-radius: 999px;
}

.app-progress__track::-moz-progress-bar {
  background-color: var(--color-teal-600);
  border-radius: 999px;
}

/* The supplier-register gap marker (finding Z-9). It used to carry
   role="alert" - an ARIA live region - on a STATIC cell present from first
   paint and repeated on many rows, so a screen-reader user walking onto
   the list was interrupted once per gap row. The visual treatment its own
   earlier rule (the strong[role="alert"] rule above) gave it is kept
   verbatim, on a class instead of on the role. */
.app-flag--gap {
  color: var(--color-brick-600);
}

/* Wide register tables (finding Z-4). Two separate jobs.

   1. The sticky first column. At 1366px the "Akcje" column has been out of
      the panel since task F4.E6.T2 (retry) measured it there and named the
      arithmetic that puts it there (1141 + 240 > 1366). What the audit
      added is that scrolling the panel sideways to REACH those buttons
      scrolls the name column out of view, so the reviewer clicks "Usun" on
      a row whose name they cannot see. Pinning the first cell of each row
      fixes exactly that, and only that - it does not make the table
      narrower.

   2. The panel widening. At 1920px the panel is 1200px with 232px of empty
      margin on each side while 465px of table sits off-view (measured on
      production). The cap is lifted for the ONE case that needs it, keyed
      off the presence of a wide table rather than off a route list, so no
      layout code has to know which routes are registers - see
      MainLayout.razor.css for that half. */
.app-table-container--sticky-first th:first-child,
.app-table-container--sticky-first td:first-child {
  position: sticky;
  left: 0;
  z-index: 1;
  background-color: var(--color-white);
}

.app-table-container--sticky-first th:first-child {
  background-color: var(--color-paper-100);
}

/* base.css's own "tbody tr:hover" paints the ROW, but a sticky cell paints
   its own background over that, so the hover has to be restated here or
   the pinned column would stay white while the rest of the row
   highlights. */
.app-table-container--sticky-first tbody tr:hover td:first-child {
  background-color: var(--color-paper-100);
}

/* Risk-matrix hierarchy (finding Z-16). Two things were wrong on
   "/registers/risks/matrix": the count and its description rendered at the
   same size (nothing for the eye to catch), and the red frame encodes the
   SCORE BAND, not whether anything is in it - so 10 of the 11 red-framed
   cells contained a zero and shouted about nothing. The band stays
   readable (the cell keeps its own "nieakceptowalne" text and its brick
   text color - Zalacznik E: "zero informacji wylacznie kolorem"), but an
   empty cell no longer wears the alarm frame. */
.app-matrix-cell__count {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 1.375rem;
  line-height: 1.2;
}

.app-matrix-cell--empty {
  border-color: var(--color-paper-200);
}

.app-matrix-cell--empty .app-matrix-cell__count {
  color: var(--color-slate-400);
}

/* Task S-L18 - the honeypot wrapper on the public NFR application form
   ("/nfr"). Off-screen rather than "display: none": the point is that an
   indiscriminate form-filling bot, which reads the DOM and not the
   stylesheet, still sees a plain text input and fills it, while no human
   ever does. A human is additionally protected by the field's own
   aria-hidden/tabindex="-1"/autocomplete="off" in the markup - this rule
   only moves it out of sight. */
.app-honeypot {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ---------------------------------------------------------------------- *
 * Empty state for "this page needs an active organization and the caller
 * has none" (session N21, block C - Components/Tenancy/
 * ActiveOrganizationRequiredView.razor, see docs/tech-debt.md's own
 * "N21 - triaz znalezisk N20.E" entry). Rendered on a <section>, so the card
 * rule at the top of this file already supplies background, border, radius
 * and padding; the only thing added here is the same slate accent edge the
 * info callout (:where(p, div, ul)[role="status"]) uses, so the block reads
 * as an explanation rather than as the error it is not. Deliberately NOT the
 * brick accent: nothing failed.
 *
 * The second class on that element, ".app-empty-state--no-organization",
 * carries no paint of its own on purpose. It is the stable,
 * culture-independent marker the completeness-pinning integration test
 * (IntegrationTests.Tenancy.ActiveOrganizationRequiredEmptyStateTests) matches
 * on across all seven routes, next to the localized heading itself.
 * ---------------------------------------------------------------------- */
.app-empty-state {
  border-left: 4px solid var(--color-slate-600);
}

/* N80 - the product tour video under the sign-up form ("/rejestracja"). The
   width/height attributes on the element give the aspect ratio before the
   poster loads; this rule only lets the player shrink with its column. */
.app-tour {
  margin: 2rem 0 0;
}

.app-tour-video {
  display: block;
  max-width: 100%;
  height: auto;
}
