@import '_content/Ds.DesignSystem.Blazor/Ds.DesignSystem.Blazor.f05zn7jv8v.bundle.scp.css';
@import '_content/Microsoft.AspNetCore.Components.QuickGrid/Microsoft.AspNetCore.Components.QuickGrid.boiwgh0w5b.bundle.scp.css';

/* /Components/App.razor.rz.scp.css */
/* INFRA-002 (issue #328) — the reconnect/refresh bar (App.razor). Hidden by default; the
   framework (blazor.web.js) is the only thing that ever adds a state class to #components-
   reconnect-modal, so a static page (no circuit, no state class ever added) never shows this. */
.reconnect-bar[b-cw1r7mtaqo] {
    display: none;
    position: fixed;
    inset-block-start: 0;
    inset-inline: 0;
    /* Above the sticky app bar/drawer (--ds-zIndex-appBar/-drawer), same tier as a toast: this is
       a transient system notice, not part of the page chrome underneath it. */
    z-index: var(--ds-zIndex-toast);
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: var(--ds-space-xs) var(--ds-space-md);
    padding: var(--ds-space-xs) var(--ds-space-lg);
    font-size: var(--ds-typography-bodySmall-font-size);
    text-align: center;
    border-block-end: var(--ds-border-width-thin) solid var(--ds-color-outlineVariant);
}

/* "Reconnecting" — the SAME tone as the demo banner's own warning use, deliberately: this is an
   in-progress state, not yet a failure. Blazor adds -retrying alongside -show once it starts
   counting attempts (see blazor.web.js's Xo.update); both read the same here. */
.reconnect-bar.components-reconnect-show[b-cw1r7mtaqo],
.reconnect-bar.components-reconnect-retrying[b-cw1r7mtaqo] {
    display: flex;
    background-color: var(--ds-color-warningContainer);
    color: var(--ds-color-onWarningContainer);
}

/* "Gave up" — firm error tone, and the only state that shows the reload button. -failed is a
   client-side retry budget exhausted; -rejected is the server explicitly saying it does not know
   this circuit any more (e.g. it restarted) — reload is the ONLY way back from -rejected, and the
   honest big hammer for -failed too, rather than silently retrying forever. */
.reconnect-bar.components-reconnect-failed[b-cw1r7mtaqo],
.reconnect-bar.components-reconnect-rejected[b-cw1r7mtaqo] {
    display: flex;
    background-color: var(--ds-color-errorContainer);
    color: var(--ds-color-onErrorContainer);
}

.reconnect-bar__failed[b-cw1r7mtaqo] {
    display: none;
    align-items: center;
    gap: var(--ds-space-sm);
}

.reconnect-bar.components-reconnect-failed .reconnect-bar__retrying[b-cw1r7mtaqo],
.reconnect-bar.components-reconnect-rejected .reconnect-bar__retrying[b-cw1r7mtaqo] {
    display: none;
}

.reconnect-bar.components-reconnect-failed .reconnect-bar__failed[b-cw1r7mtaqo],
.reconnect-bar.components-reconnect-rejected .reconnect-bar__failed[b-cw1r7mtaqo] {
    display: inline-flex;
}
/* /Components/Layout/MainLayout.razor.rz.scp.css */
/* DEMO-001 banner — only rendered in demo mode. A loud, unmissable strip so nobody
   mistakes the sandbox for the real club. Colours/spacing from the warning tokens. */
.demo-banner[b-keca402jku] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ds-space-sm) var(--ds-space-md);
    padding: var(--ds-space-xs) var(--ds-space-lg);
    background-color: var(--ds-color-warningContainer, var(--ds-color-primaryContainer));
    color: var(--ds-color-onWarningContainer, var(--ds-color-onPrimaryContainer));
    border-bottom: var(--ds-border-width-thin) solid var(--ds-color-outlineVariant);
    font-size: var(--ds-typography-bodySmall-font-size);
}

.demo-banner__badge[b-keca402jku] {
    font-weight: var(--ds-badge-typography-font-weight);
    letter-spacing: 0.08em;
    padding: 0 var(--ds-space-xs);
    border-radius: var(--ds-radius-sm);
    background-color: var(--ds-color-error);
    color: var(--ds-color-onError);
}

.demo-banner__text[b-keca402jku] { flex: 1 1 16rem; }

.demo-banner__links[b-keca402jku] {
    display: flex;
    gap: var(--ds-space-md);
}

.demo-banner__links a[b-keca402jku] {
    color: inherit;
    font-weight: var(--ds-typography-label-font-weight);
    text-decoration: underline;
    white-space: nowrap;
}

/* NOTE (Takt slice 5, Task 2): the .page / .sidebar / .top-row / article.content scaffolding
   that used to live here is gone with NavMenu — DsAppShell owns the grid now, and SMM's own
   chrome classes live in wwwroot/css/takt-shell.css. The skip link moved there too: it is
   rendered by TaktPublicNav, and CSS isolation scopes this file to elements authored in
   MainLayout.razor, so a rule here would never have matched it. */
/* /Components/Pages/AdminOverview.razor.rz.scp.css */
/* Overblik — the "I aften" rows (wireframe: time · track+venue · paired role meter) and the
   attention card's action column (TAKT-256). Tokens-first; SMM-owned class names composing
   DS components, never a ds-c-* rule. */

/* TAKT-256 — "Kræver din opmærksomhed": each row's verb ("Se listen", "Godkend", "Opret
   betaling", …) is a DsButton sized to its own label, so the trailing edge of the card was
   ragged. A shared min-width on the action itself — not a hard-coded width per label — gives
   every verb one column. Anchored on `.attention-list__row`, the literal wrapper AdminOverview
   writes around each AttentionRow: a bare `::deep` compiles to `[scope] .x` and needs an
   ancestor that carries the scope — DsCard/DsStack roots do not, so the bare form this rule
   used to have never matched at all. The target is our own data hook (`data-attention-action`,
   splatted by AttentionRow onto DsButton's root), never a component class name. `ch`
   is a layout measurement (the widest label, "Opret betaling"/"See the season", is 14
   characters) — not a design value, so it is not one of the things `--ds-*` covers. 16ch
   is the smallest floor that puts every current label — Danish and English — ON the floor
   rather than past it (measured: 14ch/15ch still left "Opret betaling" wider than its
   siblings; at 16ch all four sit at the same rendered width). */
.attention-list__row[b-icbru9yijr]  [data-attention-action] {
    min-inline-size: 16ch;
    justify-content: center;
}

/* TAKT-278 — on a phone the row is badge · sentence · verb in ~330px, and DsItem keeps its
   three slots on one line, so the sentence ("2 forfaldne betalinger — 501 kr. i MobilePay-
   overførsler.") got ~80px and broke one word per line beside a full-width button. Below the
   900px switch the row wraps and the verb takes its own line under the sentence, right-aligned
   as the verb column is on desktop; the 16ch floor is dropped because there is no column left
   to align. The trailing slot is DsItem's own `<span>` — no class of ours can ride it and the
   component's own class name is off-limits in this file — so it is reached by POSITION (the
   last span of the row), which DsItem's markup fixes as leading · content · trailing. */
@media (max-width: 899px) {
    /* The class is doubled on purpose: DsItem's own scoped rules are (0,2,0) and load AFTER
       this stylesheet, so a plain `[scope] .takt-attention` (also 0,2,0) loses every tie —
       the trailing slot's `flex: 0 0 auto` kept winning and nothing wrapped. (0,3,0) wins. */
    .attention-list__row[b-icbru9yijr]  .takt-attention.takt-attention {
        flex-wrap: wrap;
        row-gap: var(--ds-space-xs);
    }

    /* The sentence (the middle slot) shares the first line with the badge: a zero flex
       basis lets it take the remaining width instead of asking for its full text width,
       which would push the badge onto a line of its own. */
    .attention-list__row[b-icbru9yijr]  .takt-attention.takt-attention > span:nth-child(2) {
        flex: 1 1 0;
        min-inline-size: 0;
    }

    .attention-list__row[b-icbru9yijr]  .takt-attention.takt-attention > span:last-child {
        flex: 1 0 100%;
        display: flex;
        justify-content: flex-end;
    }

    .attention-list__row[b-icbru9yijr]  [data-attention-action] {
        min-inline-size: 0;
    }
}

.tonight-row[b-icbru9yijr] {
    display: flex;
    align-items: center;
    gap: var(--ds-space-sm);
    flex-wrap: wrap;
    row-gap: var(--ds-space-xs);
}

/* Times align as a column: tabular figures come from DsTypography Variant="Data"; the fixed
   inline-size is what lines the titles up under each other. `::deep` because the class rides a
   DsTypography's own root, which the scope attribute does not reach. */
.tonight-row[b-icbru9yijr]  .tonight-row__time {
    inline-size: var(--ds-space-2xl);
    flex: none;
    color: var(--ds-color-onSurfaceVariant);
}

/* Title with the venue nested under it, the members list's identity idiom — the pair
   can never wrap apart. */
.tonight-row__what[b-icbru9yijr] {
    display: inline-flex;
    flex-direction: column;
    min-width: 0;
}

/* The wireframe pins the meter to the right edge at a readable minimum width; below
   that the row wraps and the meter takes its own line rather than squeezing. */
.tonight-row__meter[b-icbru9yijr] {
    margin-inline-start: auto;
    /* Wider than the wireframe's ~130px (96 + 48) on purpose: DsCapacityMeter puts the ROLE NAME
       in the row as well as the bar and the count, which the prototype's bare bars did not, so at
       130px the bar itself collapsed to a dash and the reading — how full is this class — was the
       part that got squeezed out. Two 4xl steps, said in the spacing scale. */
    min-inline-size: calc(var(--ds-space-4xl) * 2);
}
/* /Components/Pages/ClubCalendar.razor.rz.scp.css */
/* TAKT — Kalender (slice 5, Task 6). Our own composition and layout, under our own class
   names; the grid and the chips belong to DsCalendar. The legend does not any more (app issue
   #302 — see ClubCalendar.razor's header comment for the measured contrast numbers). Tokens
   only. */

.takt-calendar[b-aebzxoa986] {
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-md);
}

.takt-calendar__nav[b-aebzxoa986] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ds-space-xs);
}

/* The month arrows are LINKS (the month lives in the URL), so they need the quiet-button
   shape spelled out here rather than inherited from a button component. */
.takt-calendar__navlink[b-aebzxoa986] {
    display: inline-flex;
    align-items: center;
    /* TAKT-250 finding K3 — these are LINKS, not buttons, so they never picked up a button
       component's own touch-target floor. min-block-size is the D10 44px baseline; the
       block-only padding above was sized for a mouse and measured 31px tall. */
    min-block-size: 2.75rem;
    padding-block: var(--ds-space-xs);
    padding-inline: var(--ds-space-sm);
    border: var(--ds-border-width-thin) solid var(--ds-color-outlineVariant);
    border-radius: var(--ds-radius-sm);
    color: var(--ds-color-onSurface);
    font-family: var(--ds-typography-label-font-family);
    font-size: var(--ds-typography-label-font-size);
    font-weight: var(--ds-typography-label-font-weight);
    text-decoration: none;
    white-space: nowrap;
}

.takt-calendar__navlink:hover[b-aebzxoa986] {
    background: var(--ds-color-surfaceContainerHigh);
}

.takt-calendar__navlink:focus-visible[b-aebzxoa986] {
    outline: var(--ds-border-focusRing-width) solid var(--ds-color-focusRing);
    outline-offset: var(--ds-border-focusRing-offset);
}

/* TAKT-250 finding K4 — suppressing the calendar toolbar is a real DsCalendar parameter
   (Toolbar="false", see ClubCalendar.razor), so no structural `> div:first-child { display:
   none }` rule lives here. That hack also stripped the grid's accessible name outright;
   Toolbar="false" keeps DsCalendar's own visually-hidden, aria-live title instead. */

/* The legend is app-owned because it must serve BOTH calendar views: DsCalendar's own legend
   renders inside the grid, which hides below 900px — the mobile agenda (also app-owned) would
   have no key at all. Same list/role/aria-label shape and category fills as DsCalendar's, and
   the dot ring binds the SAME tokens DsCalendar's own legend uses since DS 1.12.0, so the two
   cannot drift apart on colour. */
.takt-calendar__legend[b-aebzxoa986] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ds-calendar-legendGap);
    list-style: none;
    margin: 0;
    padding: 0;
}

.takt-calendar__legend-item[b-aebzxoa986] {
    display: inline-flex;
    align-items: center;
    gap: var(--ds-space-xs);
}

/* The ring is DS 1.12.0's own legend-dot pairing (it ships the same fix upstream after the
   contrast finding this page surfaced): the dedicated legendDotBorder role at the calendar's
   own border width, box-sizing keeping the dot on its token diameter. */
.takt-calendar__legend-dot[b-aebzxoa986] {
    flex: none;
    box-sizing: border-box;
    inline-size: var(--ds-calendar-legendDotSize);
    block-size: var(--ds-calendar-legendDotSize);
    border-radius: var(--ds-radius-full);
    border: var(--ds-calendar-borderWidth) solid var(--ds-calendar-legendDotBorder);
}

.takt-calendar__legend-dot--info[b-aebzxoa986] { background-color: var(--ds-calendar-eventInfoContainer); }
.takt-calendar__legend-dot--success[b-aebzxoa986] { background-color: var(--ds-calendar-eventSuccessContainer); }
.takt-calendar__legend-dot--warning[b-aebzxoa986] { background-color: var(--ds-calendar-eventWarningContainer); }

.takt-calendar__legend-label[b-aebzxoa986] {
    color: var(--ds-color-onSurface);
    font-family: var(--ds-typography-caption-font-family);
    font-size: var(--ds-typography-caption-font-size);
}

/* TAKT-305c — the agenda is the mobile replacement for the grid, not a companion to it: hidden
   by default, shown only below the shared 900px rung, where the grid hides in turn. Both exist
   in the DOM at all times (prerender has no viewport to test), so this is the only place that
   decides which one a real browser paints. */
.takt-calendar__agenda[b-aebzxoa986] {
    display: none;
    flex-direction: column;
    gap: var(--ds-space-lg);
}

.takt-calendar__agendaDay[b-aebzxoa986] {
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-xs);
}

.takt-calendar__agendaHeading[b-aebzxoa986] {
    color: var(--ds-color-onSurfaceVariant);
}

/* A <button>, not a link: it opens the same in-page drawer OnEventClick does, never a
   navigation. TAKT-250 finding K3's 44px floor applies here too — this is a thumb target. */
.takt-calendar__agendaEvent[b-aebzxoa986] {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--ds-space-xxs);
    inline-size: 100%;
    min-block-size: 2.75rem;
    padding-block: var(--ds-space-sm);
    padding-inline: var(--ds-space-md);
    border: var(--ds-border-width-thin) solid var(--ds-color-outlineVariant);
    /* The category stripe: same semantic colour the grid chip and the legend dot use for this
       entry, as a left border rather than a fill — the row's own text stays --ds-color-onSurface
       contrast regardless of which category it is. */
    border-inline-start-width: var(--ds-border-width-emphasis);
    border-radius: var(--ds-radius-sm);
    background: var(--ds-color-surface);
    color: var(--ds-color-onSurface);
    font-family: var(--ds-typography-body-font-family);
    text-align: start;
    cursor: pointer;
}

.takt-calendar__agendaEvent:hover[b-aebzxoa986] { background: var(--ds-color-surfaceContainerHigh); }

.takt-calendar__agendaEvent:focus-visible[b-aebzxoa986] {
    outline: var(--ds-border-focusRing-width) solid var(--ds-color-focusRing);
    outline-offset: var(--ds-border-focusRing-offset);
}

.takt-calendar__agendaEvent--info[b-aebzxoa986] { border-inline-start-color: var(--ds-calendar-eventInfoContainer); }
.takt-calendar__agendaEvent--success[b-aebzxoa986] { border-inline-start-color: var(--ds-calendar-eventSuccessContainer); }
.takt-calendar__agendaEvent--warning[b-aebzxoa986] { border-inline-start-color: var(--ds-calendar-eventWarningContainer); }

.takt-calendar__agendaEvent--cancelled .takt-calendar__agendaTitle[b-aebzxoa986] { text-decoration: line-through; }

.takt-calendar__agendaTime[b-aebzxoa986] {
    font-family: var(--ds-typography-label-font-family);
    font-weight: var(--ds-typography-label-font-weight);
}

.takt-calendar__agendaReason[b-aebzxoa986] {
    color: var(--ds-color-error);
    font-size: var(--ds-typography-caption-font-size);
}

/* TAKT-324 (#344)'s overflow-gated fade lives in the COMPONENT now: DsScrollView's
 * FadeEdgesAuto (the 1.16 wave, from this page's own gap report) masks only while the box can
 * actually scroll, so the container-query workaround that used to hard-code the grid's 768px
 * floor here is gone with the reason for it. */
@media (max-width: 900px) {
    .takt-calendar__gridWrap[b-aebzxoa986] { display: none; }

    .takt-calendar__agenda[b-aebzxoa986] { display: flex; }
}
/* /Components/Pages/ClubDashboard.razor.rz.scp.css */
/* Members dashboard (MEMBER-001 UX pass; Takt slice 5 / Task 7 restyle). Tokens-first.
   The generic admin-list vocabulary (md-stats, md-kebab, md-table, md-subnav, md-bulkbar,
   md-pager, …) lives globally in member-management.css so every admin list shares it
   (see spec/app-ux-pass.md). Only members-specific bits stay scoped here. */

/* One column, one rhythm. The page's own sections stack at the shell's spacing step; the
   KPI row and the bulk bar are siblings of the table, not chrome around it. */
.takt-members[b-sg1tii5ab1] {
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-md);
    /* The shell's <main> is a grid COLUMN. Without this the table's intrinsic width becomes
       the column's min-content width and the whole page grows a horizontal scrollbar
       instead of the table scrolling inside itself. This is the `minmax(0, 1fr)` rule
       stated from the child's side, which is where a page can state it. */
    min-width: 0;
}

/* Identity cell: avatar + name, with the e-mail nested INSIDE the name (handover §8) so the
   two can never wrap apart. From the table's md rung up the E-mail column carries it and the sub
   is hidden; below, DsTable drops the column (data-priority, see the @container block at the
   foot of this file) and the sub is the only place the address appears. */
/* TAKT-323: `max-width: 100%` is what makes the ellipsis on .md-name__primary below reachable at
   all. An inline-flex box is shrink-to-fit — it sizes to max(min-content, available) — and its
   min-content here is the avatar plus the whole unwrapped name, so with nothing capping it the
   cell simply overflowed and the name PAINTED ACROSS the e-mail column instead of truncating.
   Capping it at the cell hands the shrink down through .md-name's own min-width: 0 to the span
   that carries the overflow rule. It never bit before because the name column was as wide as its
   content by construction; the DS's data-col="grow" policy is what lets that column be narrower. */
.md-identity[b-sg1tii5ab1] { display: inline-flex; align-items: center; gap: var(--ds-space-sm); text-decoration: none; min-width: 0; max-width: 100%; }
.md-identity:hover .md-name[b-sg1tii5ab1] { text-decoration: underline; }
.md-name[b-sg1tii5ab1] {
    display: inline-flex;
    flex-direction: column;
    min-width: 0;
    font-weight: var(--ds-typography-label-font-weight);
    color: var(--ds-color-primary);
}
/* TAKT-257: nowrap + ellipsis instead of the two-line wrap the owner flagged ("Alfred / Hansen").
   Its own span (not the whole .md-name column, which also holds the hidden mobile sub-line) is
   what gets truncated. This is a backstop, not the fix itself — the header row's data-col="fit"
   columns are what actually free the width a normal full name needs; ellipsis only bites on a
   name long enough to still overrun that. max-width is a content MEASURE, not a spacing step — no
   --ds-* token expresses that (#ds-gap: token-content-measure, same gap already noted on
   .takt-members__search above). */
.md-name__primary[b-sg1tii5ab1] {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 32ch;
}
/* App issue #427: the address WRAPS where it shows (below md, in the name cell and in the
   phone's stacked card) instead of truncating — the consumer gate measured
   "seed057@probe-klub.example" ellipsised at 116px while a sibling cell had 190px of slack, on
   phone and tablet alike. `overflow-wrap: anywhere` breaks the one unbreakable token an address
   is; a row that grows a line for a long e-mail is honest, an ellipsis beside empty width is
   not. The primary name keeps its TAKT-257 single-line ellipsis. */
.md-name__sub[b-sg1tii5ab1] {
    display: none;
    font-weight: var(--ds-typography-body-font-weight);
    font-size: var(--ds-typography-caption-font-size);
    line-height: var(--ds-typography-caption-line-height);
    color: var(--ds-color-onSurfaceVariant);
    min-width: 0;
    overflow-wrap: anywhere;
}

/* The toolbar above the table: search, role, sort, apply/clear and the visible count. It
   wraps rather than scrolls — these are independent controls, not a sequence. */
.takt-members__filter[b-sg1tii5ab1] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ds-space-sm);
}
/* ::deep — the count is a DsTypography root, which carries the component's scope attribute, not
   this file's; without it the rule compiled to `.takt-members__count[b-…]` and matched nothing,
   which is why the count sat squeezed beside the sort select (#424). */
.takt-members__filter[b-sg1tii5ab1]  .takt-members__count { margin-inline-start: auto; }

/* A measure, not a spacing step: how much of a name or an e-mail you can read at once.
   No --ds-* token expresses content measure (#ds-gap: token-content-measure). */
.takt-members__filter[b-sg1tii5ab1]  .takt-members__search { flex: 1 1 24ch; min-width: 16ch; max-width: 32ch; }
.takt-members__filter[b-sg1tii5ab1]  .takt-members__select { flex: 0 1 18ch; min-width: 12ch; }

/* The table scrolls inside its own box (DsTable's own `ds-c-table-wrapper`); the card must not
   re-clip the row menus the wrapper lets out while one is open. */
.takt-members__card[b-sg1tii5ab1] { overflow: visible; }

/* TAKT-323 (#343) — the address was the row's most expensive column and the only one with no
   give at all: hugging its content, the column's MINIMUM width was whatever the longest address
   in the club happened to be, and the table's minimum with it. Measured at 1440 against 1020px
   of card: full-name addresses take the table's minimum from 891px to 1178px, past which it
   scrolls inside DsTable's own `overflow-x: auto` wrapper — and what a left-to-right reader
   loses first is the trailing column, the row kebab, behind an edge that carries no scrollbar
   at rest on either desktop platform to say the column is still there.

   Since DS 1.34 that bargain is the table's own per-column width policy (sizing-contract §2,
   the harvest of GAP-TABLE-COLUMN-SLACK): the address is data-col="flex" — it shows in full
   wherever the row has the width for it, truncates with an ellipsis where it does not, and
   never shrinks below --ds-table-columnFlexMinWidth — and the empty Membership column is
   data-col="fit", so it no longer keeps slack the address is truncating out of. The floor and
   ellipsis this file used to set on .takt-members__email are the DS's now; the class stays on
   the body cell only, as the register's hook for the tests. */

/* TAKT-257: the pager above the table — right-aligned, same as the one below (.md-pager, global). */
.takt-members__pager-top[b-sg1tii5ab1] {
    display: flex;
    justify-content: flex-end;
    margin-bottom: var(--ds-space-sm);
}

/* TAKT-257: row height. An unwrapped name frees a whole line per row (see .md-name__primary
   above); this takes that height back. --ds-table-cellPaddingYDense is the DS's own dense-density
   token (5px vs the default cellPaddingY's 10px) — the same one DsTable's own Dense flag would
   apply, except that flag's generated CSS can never reach cells WE authored (the
   member-management.css "DS-gap bridge" comment on .md-table explains why: Blazor CSS isolation
   stamps its scope attribute onto the dense table rule's cell selector, and that attribute
   belongs to DsTable's own component scope, not ours). This extends that same bridge, scoped to
   just this page rather than every .md-table. Horizontal padding is untouched — the X-axis dense
   token is a value-preserving no-op in the DS's own tokens (dense never touched X), and the row's
   touch targets (checkbox, sort header) set their OWN min-height independent of cell padding, so
   they hold their 44px floor regardless. */
.md-table thead th[b-sg1tii5ab1],
.md-table td[b-sg1tii5ab1] {
    padding-block: var(--ds-table-cellPaddingYDense);
}

/* TAKT-332 (#379): `.md-import { margin-top: …; max-width: 48rem }` used to sit here — the same
   48rem form cap `.md-formcard` carried, on a class no markup under src/ references any more.
   A dead rule, deleted rather than migrated. */

/* 899.98px, one spelling of the md edge (design-system spec/responsive-contract.md §1) — this
   file used to say 899, one pixel short of the shell's own partner rung. */
@media (max-width: 899.98px) {
    .takt-members__filter[b-sg1tii5ab1]  .takt-members__count { margin-inline-start: 0; }

    /* TAKT-251: the row's own link into the member is a thumb target below this breakpoint —
       the two-line name+e-mail already renders ~42px, so this is the last 2px rather than a
       re-layout, and it stays scoped to the phone: a mouse does not need a 44px row on desktop
       and the table would grow 16px per row for nothing. */
    .md-identity[b-sg1tii5ab1] { min-block-size: var(--ds-button-minHeight); }

    /* The bottom pager drops its right-alignment so the "Viser X af Y" count and the arms stack
       instead of fighting for one line. (The overflow-x: auto this block used to carry is gone
       with #424: under sm the pager is DsPagination's Compact variant and fits; between sm and md
       the arms fit a 700px card.) */
    .takt-members__pager-top[b-sg1tii5ab1],
    .md-pager[b-sg1tii5ab1] {
        justify-content: flex-start;
        flex-wrap: wrap;
        gap: var(--ds-space-xs);
    }
}

/* App issues #424 / #427 — the register's md rung is the TABLE's, not the viewport's: DsTable
   drops the marked columns (priority 3: E-mail, Tilmeldt; priority 4: Rolle, #457 — stamped in
   ClubDashboard.razor) when its own wrapper is under 899.98px, in Stack as well as Auto since DS 1.34 (the app's md media
   query used to carry that drop itself, its measurement: at 820 with only E-mail hidden the
   eight-column table still scrolled 24px inside a 708px wrapper). The address then moves into
   the name cell's sub-line — the same fact, in the one column that is always visible — and it
   has to move on the SAME rung, so the sub-line follows the DS's named container rather than a
   viewport width that would leave a 900–1100px desktop with a dropped column and no sub-line.
   `ds-table` is the container name DsTable.razor.css declares on its wrapper. */
@container ds-table (max-width: 899.98px) {
    .md-name__sub[b-sg1tii5ab1] { display: block; }
}

/* design-system#2097 (GAP-TABLE-CARD-REDROPS) — under the table's own sm rung the DS's card
   rule (`--narrow-stack[data-ds-stacked][b-ds] > tbody > tr > td { display: grid }`, compiled
   specificity 0,3,3) outranks its own md drop (`--narrow-stack[b-ds] > tbody > tr >
   [data-priority='3'] { display: none }`, 0,3,2), so the two columns the md rung just dropped
   come BACK as card rows — measured at 390: the E-mail cell 279×42 and Tilmeldt 279×21, the
   address shown twice per card. Only the DS's Priority mode re-states its drop inside the sm
   block; Stack and Auto do not. This is that missing re-statement on the app's side. The class
   is doubled on purpose: a single `.md-table [data-priority="3"]` compiles with our scope on the
   cell to 0,3,0 and LOSES to the card's 0,3,3 — measured, the E-mail card row still 279×42.
   Doubled it is 0,4,0 (the same idiom as takt-shell.css's tripled `.takt-bottomnav`). Both
   priorities the register marks (3: E-mail, Tilmeldt; 4: Rolle — #457) — the DS's own md drop
   covers "3" and "4" alike, so the re-statement does too. Rendered pin: ViewportSmokeTests'
   phone case. Harvest: delete this rule and its citation when #2097 ships. */
@container ds-table (max-width: 599.98px) {
    .md-table.md-table [data-priority="3"][b-sg1tii5ab1],
    .md-table.md-table [data-priority="4"][b-sg1tii5ab1] { display: none; }
}

/* App issue #424 — the phone. 599.98px is the DS `sm` rung, the same edge the ⋯ overflow in
   takt-shell.css and DsTable's own container query switch on. */
@media (max-width: 599.98px) {
    /* The three filters take ONE width — the card's — stacked, and the count sits under them
       on a line of its own. They used to be three widths (search 330 / selects 192 / count 76,
       measured) because each carried its own `ch` measure; a phone has no row to share, so the
       measures give way to the fill. */
    .takt-members__filter[b-sg1tii5ab1]  .takt-members__search,
    .takt-members__filter[b-sg1tii5ab1]  .takt-members__select {
        flex: 1 1 100%;
        min-width: 0;
        max-width: none;
    }

    .takt-members__filter[b-sg1tii5ab1]  .takt-members__count {
        flex-basis: 100%;
    }

    /* App issue #424 — the compact pager itself, at its Large touch size (48px arms,
       unshrinkable — the touch floor stays), still ran 287px against a card measured as
       narrow as 250px at 360px: « (48) + "Page 1 af 4" (79) + » (48) + the page-size select
       (64), joined by three `--ds-pagination-gap` (16px) and padded with two
       `--ds-pagination-paddingY` (10px) each on the status and the select. Both are the DS's
       own component tokens (components/pagination.json) — the sanctioned density seam, not a
       width override on a DS-owned box (QUESTIONS 214) — scoped to THIS pager alone so the
       page-number variant above sm keeps its normal-density rhythm. `::deep`: the class lands
       on DsPagination's own <nav>, which carries the component's scope attribute, not this
       file's. Down to 227px (48+61+48+56, gaps 12) — 23px of slack at the narrowest phone
       this ladder measures (360px), comfortably under 280px at 390. `::deep`, off the two
       pager wrappers (both plain divs carrying THIS file's scope) — the class itself lands on
       DsPagination's own <nav>, which carries the component's scope, not this file's. */
    .takt-members__pager-top[b-sg1tii5ab1]  .takt-members__pagination--compact,
    .md-pager[b-sg1tii5ab1]  .takt-members__pagination--compact {
        --ds-pagination-gap: var(--ds-space-xs);
        --ds-pagination-paddingY: var(--ds-space-xxs);
    }
}
/* /Components/Pages/CreateClub.razor.rz.scp.css */
/* TAKT-332 (#379) — the container half of "width is the container's job".
 *
 * This page's card used to wear `.md-formcard`'s 48rem cap. That rule is retired app-wide: a form
 * fills what it is given, and what it is given is a CONTAINER's decision. This page is one field
 * and a submit — a single form column — so the container takes the design system's own rung for
 * exactly that measure rather than a number of its own. Login.razor's door states it identically;
 * `min(100%, …)` is what keeps it honest on a phone, where the cap must never become a floor.
 */
.createclub__column[b-k9w6gt52u7] {
    max-inline-size: min(100%, var(--ds-layout-formColumnMaxWidth));
    margin-inline: auto;
}
/* /Components/Pages/DemoCheckout.razor.rz.scp.css */
.demo-checkout[b-bts77z607t] {
    display: flex;
    justify-content: center;
    padding: var(--ds-space-xl) var(--ds-space-md);
}

.demo-checkout__card[b-bts77z607t] {
    width: 100%;
    max-width: 26rem;
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-md);
}

.demo-checkout__brand[b-bts77z607t] {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.demo-checkout__logo[b-bts77z607t] {
    font-weight: var(--ds-typography-heading6-font-weight);
    font-size: var(--ds-typography-heading6-font-size);
    color: var(--ds-color-primary);
}

.demo-checkout__sim[b-bts77z607t] {
    font-weight: var(--ds-badge-typography-font-weight);
    letter-spacing: 0.08em;
    padding: 0 var(--ds-space-xs);
    border-radius: var(--ds-radius-sm);
    background-color: var(--ds-color-error);
    color: var(--ds-color-onError);
    font-size: var(--ds-typography-bodySmall-font-size);
}

.demo-checkout__amount[b-bts77z607t] {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    margin: 0;
    padding: var(--ds-space-sm) 0;
    border-top: var(--ds-border-width-thin) solid var(--ds-color-outlineVariant);
    border-bottom: var(--ds-border-width-thin) solid var(--ds-color-outlineVariant);
}

.demo-checkout__amount dt[b-bts77z607t] { color: var(--ds-color-onSurfaceVariant); }

.demo-checkout__amount dd[b-bts77z607t] {
    margin: 0;
    font-size: var(--ds-typography-heading5-font-size);
    font-weight: var(--ds-typography-heading5-font-weight);
}

.demo-checkout__field[b-bts77z607t] {
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-xs);
    color: var(--ds-color-onSurfaceVariant);
}

.demo-checkout__field input[b-bts77z607t] {
    padding: var(--ds-space-sm);
    border: var(--ds-border-width-thin) solid var(--ds-color-outline);
    border-radius: var(--ds-radius-md);
    background-color: var(--ds-color-surfaceContainer, var(--ds-color-surface));
    color: var(--ds-color-onSurfaceVariant);
    font-family: var(--ds-typography-body-font-family);
}

.demo-checkout__actions[b-bts77z607t] {
    display: flex;
    gap: var(--ds-space-sm);
}

.demo-checkout__actions form[b-bts77z607t] { flex: 1; }
.demo-checkout__actions button[b-bts77z607t] { width: 100%; }
/* /Components/Pages/DemoHome.razor.rz.scp.css */
.demo-home[b-nhs5ei0z3k] {
    max-width: 60rem;
    margin: 0 auto;
}

.demo-home__personas[b-nhs5ei0z3k] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    gap: var(--ds-space-md);
    margin: var(--ds-space-lg) 0;
}

.demo-home__persona[b-nhs5ei0z3k] {
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-sm);
}

.demo-home__persona p[b-nhs5ei0z3k] { flex: 1; }

.demo-home__note[b-nhs5ei0z3k] {
    color: var(--ds-color-onSurfaceVariant);
    font-style: italic;
}

.demo-home__reset[b-nhs5ei0z3k] {
    margin-top: var(--ds-space-xl);
    padding-top: var(--ds-space-md);
    border-top: var(--ds-border-width-thin) solid var(--ds-color-outlineVariant);
}
/* /Components/Pages/FeedbackAdmin.razor.rz.scp.css */
/* FEAT-004 — the two blocks in the triage drawer that need a shape the DS does not express:
   pre-formatted JSON, and a member's own multi-line prose. Both are about PRESERVING the line
   breaks the source already has, which no typography variant can do on its own. */

/* The consented system info, as the browser wrote it (re-indented by FeedbackIssueMarkdown).
   Monospace via the DS's own code font token, wrapped rather than side-scrolled: a user-agent
   string is one very long line, and a horizontal scrollbar inside a drawer is a trap. */
.feedback-detail__json[b-f538v1tauj] {
    margin: 0;
    padding: var(--ds-space-sm);
    border-radius: var(--ds-radius-sm);
    background-color: var(--ds-color-surfaceContainer);
    color: var(--ds-color-onSurfaceVariant);
    font-family: var(--ds-typography-code-font-family);
    font-size: var(--ds-typography-code-font-size);
    line-height: var(--ds-typography-code-line-height);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* The member typed paragraphs; rendering them as one run would silently merge their steps into
   a single sentence, which is exactly the detail a reproduction recipe lives on. */
.feedback-detail__text[b-f538v1tauj] {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* TAKT-322 (#342) — the pager above the triage table, right-aligned, mirroring the global
   .md-pager below it (the same pairing /members and /payments carry). */
.takt-feedback__pager-top[b-f538v1tauj] {
    display: flex;
    justify-content: flex-end;
    margin-bottom: var(--ds-space-sm);
}

@media (max-width: 899px) {
    /* DsPagination's Large arms run past a 430px card and its row does not wrap: scroll the
       control in its own container rather than push the table's edge off-screen — the same rule
       ClubDashboard.razor.css already applies to the members pagers. */
    .takt-feedback__pager-top[b-f538v1tauj] {
        overflow-x: auto;
        justify-content: flex-start;
    }
}
/* /Components/Pages/Locations.razor.rz.scp.css */
/* TAKT-234 -- venue identity cards.
 *
 * Matches design-system's own reference build of this screen
 * (packages/takt/stories/TaktLocations.stories.tsx) rather than the wireframe's hand-painted
 * CSS: two token-bound gradient stops, alternating per venue.
 *
 * The band itself is DsCard's own Media slot now (MediaHeight="Sm"): the package bleeds it out
 * to the card's inline edges, clips it to the card radius and sizes it from --ds-card-mediaHeight*.
 * All that is left here is the PAINT -- the two gradients and where the name sits inside the band.
 * The card no longer needs a wrapper element or squared-off top corners, so both are gone.
 */

.locations-grid[b-wyz749mkn9] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
    gap: var(--ds-space-md);
    align-items: stretch;
}

/* The class is doubled on purpose: inside DsCard's Media slot the component's own scoped rule
   for the slot's child sets `display: block` at (0,2,0) and loads after this file, so a plain
   `.location-card__banner` (also 0,2,0) lost the tie and the name floated to the top of the
   band. (0,3,0) keeps the flex box and the bottom-aligned name. */
.location-card__banner.location-card__banner[b-wyz749mkn9] {
    display: flex;
    align-items: flex-end;
    padding: var(--ds-space-sm) var(--ds-space-md);
}

/* Two token-bound gradient stops, alternating per venue (index derived from the location's own
 * Id — stable across a rename or an address edit, unlike a row position). Mirrors
 * ClubDirectoryView's own --g0/--g1 identity-tile pattern and the DS story's BANNER_STOPS. */
.location-card__banner--g0[b-wyz749mkn9] {
    background: linear-gradient(120deg, var(--ds-color-inverseSurface), var(--ds-color-tertiary));
}

.location-card__banner--g1[b-wyz749mkn9] {
    background: linear-gradient(120deg, var(--ds-color-inverseSurfaceHigh), var(--ds-color-primary));
}

/* Anchored on the band and reached with `::deep`: the band is our own literal element (it
   carries this file's scope), the name is a DsTypography whose root does not — inside DsCard's
   Media fragment the bare class selector silently stopped matching and the name fell back to
   onSurface ink over the gradient (caught by sweep #17 after the Media-slot harvest). */
.location-card__banner[b-wyz749mkn9]  .location-card__banner-name {
    color: var(--ds-color-onInverseSurface);
}

.location-card__stats[b-wyz749mkn9] {
    border-top: var(--ds-border-width-thin) solid var(--ds-color-outlineVariant);
    padding-top: var(--ds-space-sm);
}
/* /Components/Pages/Login.razor.rz.scp.css */
/* TAKT — the one door.
 *
 * Scoped to Login.razor. `::deep` only where a rule has to reach an element a Ds* component
 * renders. Tokens only; no hex, no design px. No `.ds-c-*` selector is defined here (DS-004).
 */

.login[b-iwq923q6zc] {
    display: block;
}

/* One readable column of form, at the DS's own form-column measure. It used to be 48ch: nothing
 * between the reading cap (768px) and a popover (320px) expressed "one column of form", so the
 * width was stated font-relative rather than frozen. DS 1.6.0 added the token every form column
 * shares, and the owner chose it over the local measure (~60px wider than 48ch at the body size). */
.login__column[b-iwq923q6zc] {
    max-inline-size: min(100%, var(--ds-layout-formColumnMaxWidth));
    margin-inline: auto;
}

/* TAKT-268: .login__title hand-copied the heading4 token set for the door's own <h1> — deleted
 * now that it's a DsTypography(Heading4); its "color: onSurface" was already the ambient body
 * colour, so DsTypography's Default (inherits, no colour class) reproduces it with no rule. */

/* The accent full stop every public headline wears. */
.login__dot[b-iwq923q6zc] {
    color: var(--ds-color-primary);
}

.login__form[b-iwq923q6zc] {
    margin: 0;
}

.login[b-iwq923q6zc]  .login__fineprint {
    text-align: center;
}
/* /Components/Pages/MemberDetail.razor.rz.scp.css */
/* Member-detail "360" (MEMBER-001 UX pass; Takt slice 5 / Task 7 restyle).
   Tokens-first; pairs with member-management.css atoms. */

.takt-member[b-6m66r12uev] {
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-md);
    /* The shell's <main> is a grid COLUMN: without this the payments table's intrinsic width
       becomes the column's min-content width and the page grows a horizontal scrollbar
       instead of the table scrolling inside itself. */
    min-width: 0;
}

/* The way back is a control, so it keeps a control's hit area — but it is not part of the
   header's action row and must not read as one. */
.takt-member__back[b-6m66r12uev] { align-self: flex-start; }

.takt-member__badges[b-6m66r12uev] { display: inline-flex; gap: var(--ds-space-xs); flex-wrap: wrap; align-items: center; }

/* The pending banner's verb goes UNDER the sentence, on its own row, rather than into
   DsInfoBanner's non-wrapping action slot (#ds-gap: info-banner-action-no-wrap). */
.takt-member__pending[b-6m66r12uev] {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--ds-space-sm);
}

/* Six tabs do not fit 430px — and DsTabs already scrolls its own strip over nowrap tabs, so
   there is nothing for this file to add. Noted rather than left silent, because "the tab strip
   pans on a phone" is a claim the audit checks and somebody will look here for it. */

/* A panel is a measure, not a canvas: prose and label/value pairs stop being readable much
   past this. The tables inside it get their own scroller rather than widening it. */
.takt-member__panel[b-6m66r12uev] { max-width: 60rem; }
.takt-member__tablewrap[b-6m66r12uev] { overflow-x: auto; }
.takt-member__subhead[b-6m66r12uev] { margin-top: var(--ds-space-md); }
.takt-member__lead[b-6m66r12uev] { margin-bottom: var(--ds-space-md); }

/* The exemption row used to be hand-rolled here, under the contact card, because the card's
   field had no action slot. DS 1.7.0 ships one — the verb now sits in the Fritagelse row it
   belongs to (TAKT-235) and the rule that faked it is gone. */

.member-detail__actions[b-6m66r12uev] { display: flex; gap: var(--ds-space-sm); flex-wrap: wrap; }

.md-activity[b-6m66r12uev] { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--ds-space-sm); }
.md-activity li[b-6m66r12uev] { display: flex; align-items: center; gap: var(--ds-space-sm); flex-wrap: wrap; }
/* /Components/Pages/MemberHome.razor.rz.scp.css */
/* TAKT — MemberHome (slice 5, Task 10). SMM-owned wrapper elements only (S5-P): grid layout and
   a quiet "→" link, never a rule against a Ds* component's own root. */

/* The hero is DsCard Variant="Hero" — a brand gradient wash, not the inverse variant. The DS's
 * inverse card re-points the core ink roles for its descendants since 1.6.0, but the Hero
 * variant deliberately does not (its job is the wash), so anything inside that pins an ink
 * would still render near-black on the dark wash — the Task 10 audit measured an unstyled
 * <h1> at 1.13:1 here. Every value is another --ds-color-* role; the scope is one
 * composition, never :root. ClubLanding.razor.css carries the same block for its hero. */
.memberhome[b-wegnpmih4b]  .memberhome__hero {
    --ds-color-onSurface: var(--ds-color-onInverseSurface);
    --ds-color-onSurfaceVariant: var(--ds-color-onInverseSurface);
    --ds-color-onSurfaceSubtle: var(--ds-color-onInverseSurface);
    color: var(--ds-color-onInverseSurface);
}

.memberhome__title[b-wegnpmih4b] {
    margin: 0;
    font-size: 1.5rem;
    font-weight: 700;
    color: var(--ds-color-onInverseSurface);
}

.memberhome__grid2[b-wegnpmih4b] {
    display: grid;
    /* W6-6 (DS check:consumer consumer-width-override): a bare `1fr` track's automatic
       minimum is the largest item's min-content, not 0 — so the four DsCard children
       (min-width: auto by contract) can size this single-column track past the
       viewport at 390/820. `minmax(0, 1fr)` is the same one-column layout with the
       track allowed to shrink. See design-system spec/responsive-contract.md §5. */
    grid-template-columns: minmax(0, 1fr);
    gap: var(--ds-space-md);
}

@media (min-width: 900px) {
    .memberhome__grid2[b-wegnpmih4b] {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    }
}

/* Parity audit (WCAG 2.5.8 AA): "Kalender →" / "Tilmeld flere →" / "Se alle →" measured
   20px tall — under the 24px floor every device is held to, mouse included. inline-flex +
   min-block-size grows the click box without growing the caption text; margin-left:auto
   still floats it to the card's corner since it stays a flex item either way. */
.memberhome__quiet[b-wegnpmih4b] {
    display: inline-flex;
    align-items: center;
    min-block-size: var(--ds-size-targetMin);
    margin-left: auto;
    color: var(--ds-color-primary);
    font-size: 0.8125rem;
    font-weight: 600;
    text-decoration: none;
}

.memberhome__quiet:hover[b-wegnpmih4b] {
    text-decoration: underline;
}

/* TAKT-211: the "Betal nu →" pointer inside the unpaid alert. A thumb target (WCAG 2.5.5,
   the AAA/touch tier — 44px, not the 24px AA floor of 2.5.8) that still sits on the
   sentence's own line — inline-flex with a min-height, not a block button, so the alert
   reads as one sentence with a verb at the end rather than a card with a CTA glued on. */
.memberhome__paynow[b-wegnpmih4b] {
    display: inline-flex;
    align-items: center;
    min-height: var(--ds-size-touchTarget);
    padding-inline: var(--ds-space-xs);
    color: var(--ds-color-primary);
    font-weight: 600;
    text-decoration: none;
}

.memberhome__paynow:hover[b-wegnpmih4b] {
    text-decoration: underline;
}

.memberhome__workshoprow[b-wegnpmih4b] {
    display: block;
    padding: var(--ds-space-xs) 0;
    color: inherit;
    text-decoration: none;
}

.memberhome__workshoprow:hover strong[b-wegnpmih4b] {
    color: var(--ds-color-primary);
}

/* The wrong-code contact address inside the orders footer — inline in running caption text,
   so it inherits the caption's size and only takes the link colour, unlike the card-corner
   .memberhome__quiet which floats itself right with margin-left:auto.
   Parity audit (WCAG 2.5.8 AA): the mail address measured 148x15 — under the 24px floor.
   inline-flex + min-block-size grows the tap/click box without growing the caption text,
   and still reads on the sentence's own line since it stays an inline flex item. */
.memberhome__quietmail[b-wegnpmih4b] {
    display: inline-flex;
    align-items: center;
    min-block-size: var(--ds-size-targetMin);
    color: var(--ds-color-primary);
    text-decoration: none;
}

.memberhome__quietmail:hover[b-wegnpmih4b] {
    text-decoration: underline;
}

/* TAKT-304 / app #299 finding 3: colour and size now come from the DsTypography
   (BodySmall/Subtle) MemberHome.razor wraps this in — only the layout reset is ours. */
.memberhome[b-wegnpmih4b]  .memberhome__newsbody {
    margin: 0;
}

@media (max-width: 899px) {
    /* Parity 2026-09-02: the quiet card-corner links hold the 24px AA floor above, but on the
       phone captures that sits under the 44px AAA/touch tier (WCAG 2.5.5) — below the shell's
       breakpoint they grow to the design system's own touch-target size. Desktop keeps the
       denser floor so the card headers don't inflate. */
    .memberhome__quiet[b-wegnpmih4b] {
        min-block-size: var(--ds-size-touchTarget);
    }

    /* TAKT-250 H1: DsItem's own root element is `display:flex; align-items:center` — one row
       for badge | purpose+code | amount, with no stacking variant of its own. At 430 the three
       collide (audit slices/06-min-klub-light-430-s2.png). `memberhome__orderrow` is OUR class,
       appended to that same root via DsItem's own `Class` parameter (MemberHome.razor) — we
       never select a design-system internal class name here (DS-004) — so `flex-direction:
       column` simply re-stacks DsItem's existing Leading/ChildContent/Trailing slots as three
       lines: badge, then purpose · code, then the amount, exactly the audit's suggested fix. */
    .memberhome[b-wegnpmih4b]  .memberhome__orderrow {
        flex-direction: column;
        align-items: flex-start;
        gap: var(--ds-space-xxs);
    }
}
/* /Components/Pages/MemberHomeNextSession.razor.rz.scp.css */
/* TAKT — MemberHomeNextSession (slice 5, Task 10). An SMM-owned wrapper element (S5-P): a
   plain <button>, not a Ds* component root, so every rule below is this repo's own to lose. */

.memberhome-next[b-9vxbi83xqw] {
    display: flex;
    align-items: center;
    gap: var(--ds-space-md);
    width: 100%;
    padding: var(--ds-space-sm);
    background: transparent;
    border: none;
    border-radius: var(--ds-radius-md);
    text-align: left;
    cursor: pointer;
    font: inherit;
    color: inherit;
}

.memberhome-next:hover[b-9vxbi83xqw],
.memberhome-next:focus-visible[b-9vxbi83xqw] {
    background: var(--ds-color-surfaceContainerHover);
}

.memberhome-next__date[b-9vxbi83xqw] {
    flex: none;
    min-width: 3.4rem;
    padding: var(--ds-space-xxs) var(--ds-space-xs);
    border-radius: var(--ds-radius-sm);
    /* NOT --ds-color-primary on --ds-color-primarySubtle: that pairing measured 3.88:1 at this
       font size (axe, the Task 10 audit) — below the 4.5:1 a 12px label needs. onSurface on
       surfaceContainer is the DS's own body-text pairing, so it is guaranteed AA. */
    background: var(--ds-color-surfaceContainer);
    color: var(--ds-color-onSurface);
    font-weight: 600;
    font-size: 0.75rem;
    line-height: 1.25;
    text-align: center;
}

.memberhome-next__body[b-9vxbi83xqw] {
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-xxs);
    min-width: 0;
}

.memberhome-next__title[b-9vxbi83xqw] {
    font-weight: 600;
}

.memberhome-next__meta[b-9vxbi83xqw] {
    color: var(--ds-color-onSurfaceSubtle);
    font-size: 0.8125rem;
}

.memberhome-next__list[b-9vxbi83xqw] {
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-xxs);
}

/* The trailing slot (role chip or waitlist badge) hugs the row's far edge, like the
   wireframe's rows — and never shrinks under a long track title. */
.memberhome-next__trailing[b-9vxbi83xqw] {
    flex: none;
    margin-left: auto;
}

/* The role chip. Fører is violet, Følger is teal — IDENTITY colours, not status colours,
   the exact pairing the dansekort chip (takt-compositions.css) and the roster's capacity
   meter already use: Tertiary for leaders, Indigo for followers. Same tokens, this
   component's own class — a .takt-dansekort__* rule reused here would couple two screens'
   markup to one component's namespace. */
.memberhome-next__role[b-9vxbi83xqw] {
    display: inline-block;
    padding-inline: var(--ds-space-xs);
    border-radius: var(--ds-radius-sm);
    font-family: var(--ds-typography-labelSmall-font-family);
    font-size: var(--ds-typography-labelSmall-font-size);
    font-weight: var(--ds-typography-labelSmall-font-weight);
    line-height: var(--ds-typography-labelSmall-line-height);
}

.memberhome-next__role--leader[b-9vxbi83xqw] {
    background: var(--ds-color-tertiarySubtle);
    color: var(--ds-color-onTertiarySubtle);
}

.memberhome-next__role--follower[b-9vxbi83xqw] {
    background: var(--ds-color-indigoSubtle);
    color: var(--ds-color-onIndigoSubtle);
}
/* /Components/Pages/MyOrders.razor.rz.scp.css */
/* TAKT — "Alle ordrer" row (issue #252). One grid, two templates; our own class names built
   from --ds-* tokens (DS-004 — never a .ds-c-* rule). The row's chrome (padding, radius,
   hairline rule) is still DsItem's; this only lays out the facts inside its content slot.

   EVERY CHILD RULE IS `::deep`, and that is not decoration. Scoped CSS stamps its `b-…`
   attribute only on plain HTML written in THIS file — a `<DsBadge Class="…">` renders its span
   inside the design-system component, which carries the RCL's scope, not ours. Written as plain
   `.orders__row-title { … }` the rules compile to `.orders__row-title[b-…]` and silently match
   nothing: the first cut of this fix looked correct in the stylesheet and still rendered the
   old squeezed row, because only the two elements we author ourselves ever matched. */

.orders__row[b-qc4fg3oyke] {
    display: grid;
    align-items: center;
    /* Mobile first — the phone card of tools/takt-ds-adoption.md §6b/§6c:
         Betalt   600 kr.            ⋯
         Sæson — Repro Medlem · Intro
         WCS-4F2A   Kopiér
         28. aug. 2026
       The kebab is the only thing pinned right; everything else reads from the left edge,
       which is what stops the one-word-per-line column the customer photographed. */
    /* The SLACK is in the kebab's column, not in the facts'. With `auto 1fr auto` the middle
       track claimed every spare pixel and the two `auto` tracks were squeezed under their own
       content — at 360px that broke "WCS-77E4" across two lines and wrapped the long
       "Afventer din betaling" badge into a blob. Giving column 3 the `1fr` lets the badge and
       the amount take exactly what they need and parks the ⋯ against the right edge regardless. */
    grid-template-columns: auto auto 1fr;
    grid-template-areas:
        "status amount menu"
        "title  title  title"
        "code   copy   copy"
        "date   date   date";
    column-gap: var(--ds-space-sm);
    row-gap: var(--ds-space-xxs);
    /* "A list of CARDS" (issue #252), not a wall of text: four lines per order with only
       DsStack's hairline between them left no seam for the eye to find. The rule sits inside
       DsItem's own inline padding, so it reads as a divider between orders rather than an edge. */
    padding-block-start: var(--ds-space-xs);
    border-block-start: var(--ds-border-width-thin) solid var(--ds-color-outlineVariant);
}

.orders__row[b-qc4fg3oyke]  .orders__row-status {
    grid-area: status;
    justify-self: start;
}

.orders__row[b-qc4fg3oyke]  .orders__row-title {
    grid-area: title;
    /* A long "Sæson — Navn Navnesen · Intro" is allowed to wrap onto a second line; what it must
       never do is push the grid wider than the card (the reference code overflowing its own card
       was half of what the customer saw). */
    min-width: 0;
    overflow-wrap: anywhere;
}

/* A reference code is quoted verbatim into a MobilePay comment field — a member who reads it
   off two lines mistypes it. Same for the date and the amount below: each is one fact. */
.orders__row[b-qc4fg3oyke]  .orders__row-code {
    grid-area: code;
    justify-self: start;
    white-space: nowrap;
}

.orders__row[b-qc4fg3oyke]  .orders__row-amount {
    grid-area: amount;
    justify-self: start;
    white-space: nowrap;
}

.orders__row[b-qc4fg3oyke]  .orders__row-date {
    grid-area: date;
    justify-self: start;
    white-space: nowrap;
}

/* `!important` is not a shortcut here: DsInline writes `display:flex` as an INLINE style on
   purpose (see ChatDrawer.razor's own note — it is how the RCL's scoped rules are kept from
   silently winning), and an inline style beats every selector. tools/takt-ds-adoption.md §7
   names this exact case: "Inline styles beat media queries — responsive overrides need
   !important or classes". Dissolving the row is what lets "kopiér" sit beside the code while
   the ⋯ stays in the corner; scoped under .orders__row, so the identical island in the
   outstanding-payment panel above is untouched. */
.orders__row[b-qc4fg3oyke]  .orders__actions {
    display: contents !important;
}

.orders__row[b-qc4fg3oyke]  .orders__copy {
    grid-area: copy;
    justify-self: start;
}

.orders__row[b-qc4fg3oyke]  .orders__menu {
    grid-area: menu;
    justify-self: end;
}

/* The desktop row, unchanged from what shipped in Task 10: badge · purpose over
   code/amount/date · actions. The same five children, five areas instead of four rows —
   nothing is rendered twice, so each row still mounts exactly one interactive island. */
@media (min-width: 900px) {
    .orders__row[b-qc4fg3oyke] {
        grid-template-columns: auto max-content max-content minmax(0, 1fr) auto;
        grid-template-areas:
            "status title title  title actions"
            "status code  amount date  actions";
        /* A one-line-per-order list needs no divider of its own — DsStack's hairline is enough. */
        padding-block-start: 0;
        border-block-start: 0;
    }

    .orders__row[b-qc4fg3oyke]  .orders__row-title {
        overflow-wrap: normal;
    }

    .orders__row[b-qc4fg3oyke]  .orders__actions {
        grid-area: actions;
        justify-self: end;
        /* Back to DsInline's own row once the mobile override stops applying. */
        display: flex !important;
    }
}
/* /Components/Pages/OrdersInteractive.razor.rz.scp.css */
/* TAKT — OrdersInteractive (slice 5, Task 10). SMM-owned wrapper element only (S5-P): a plain
   <button>, not a Ds* component root. */

.orders__quiet[b-c36k5o6db7] {
    /* TAKT-211 mobile pass: "Kopiér" is THE action on the outstanding-payment card, and at
       0.75rem with no padding it was a ~40×15px target — under WCAG 2.5.8's 24px floor, well
       under the 44px thumb target the rest of this app's phone affordances use. inline-flex +
       min-height grows the hit area without moving the label off the code's own line. */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: var(--ds-size-touchTarget);
    min-width: var(--ds-size-touchTarget);
    padding: 0 var(--ds-space-xs);
    background: transparent;
    border: none;
    color: var(--ds-color-primary);
    font-size: 0.75rem;
    font-weight: 600;
    cursor: pointer;
}

.orders__quiet:hover[b-c36k5o6db7] {
    text-decoration: underline;
}
/* /Components/Pages/Payments.razor.rz.scp.css */
/* Payments — SMM-owned wrapper markup only; the page's own CSS covers the one plain <a> it
   emits (the wrong-code contact mail address), everything else being Ds* components or the
   shared member-management.css utility classes (.form-field, .app-lead, …).

   Parity audit (WCAG 2.5.8 AA): the mailto link measured 197x20 — under the 24px floor every
   device is held to, mouse included, not only touch. inline-flex + min-block-size grows the
   click box without growing the link's text, and it still reads on the sentence's own line
   since it stays an inline flex item — same technique as MemberHome.razor.css's
   .memberhome__quietmail for the identical wrong-code sentence on the member side. */
.payments__contactlink[b-yq26hjkonj] {
    display: inline-flex;
    align-items: center;
    min-block-size: var(--ds-size-targetMin);
}

/* #224 — the reference-code box is a DsTextField now, and a DS field fills its column by
   default. This is the sizing .admin-filter-row input[type="search"] used to give the
   hand-rolled input, restated for the component: ::deep because the class lands on the
   component's own root, which never carries this page's scope attribute (same shape as
   ClubDashboard.razor.css's .takt-members__search rule). */
.payments-search[b-yq26hjkonj]  .payments-searchbox { flex: 1 1 16rem; min-width: 12rem; max-width: 24rem; }

/* TAKT-322 (#342) — the wrapper that opts this screen into the theme's Wide content measure
   (takt-shell.css) and carries the same rules `.takt-members` does for the same reason: the
   shell's <main> is a grid COLUMN, so without min-width: 0 the register's intrinsic width becomes
   the column's minimum and the whole PAGE scrolls sideways instead of the table scrolling inside
   its own wrapper. */
.takt-payments[b-yq26hjkonj] {
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-md);
    min-width: 0;
}

/* App issue #433 — a flex COLUMN stretches its children to the column's full cross-axis width by
   default (`align-items: stretch`), and DsSegmentedControl's own `inline-flex` root does not
   exempt it from that: at 768px the "Betalinger | Abonnementer" bar's own background painted the
   full 710px content width with the two tabs left-aligned and ~460px of empty beige trailing them.
   `align-self: flex-start` shrinks the bar's box back to its content, same as a `width: fit-content`
   would, without touching anything DsSegmentedControl itself renders (DS-004: no `.ds-c-*`
   selector here — `[data-payments-tabs]` is this call site's own attribute). */
.takt-payments[b-yq26hjkonj] >  [data-payments-tabs] {
    align-self: flex-start;
}

/* The pager above the table, right-aligned — the mirror of the global .md-pager below it, the
   same pairing /members has carried since TAKT-257. */
.takt-payments__pager-top[b-yq26hjkonj] {
    display: flex;
    justify-content: flex-end;
}

@media (max-width: 899px) {
    /* DsPagination's Large arms plus their gaps run past a 430px card and its row does not wrap,
       so the control scrolls in its own container rather than pushing the table's edge off-screen
       — the same rule ClubDashboard.razor.css already applies to the members pagers. */
    .takt-payments__pager-top[b-yq26hjkonj] {
        overflow-x: auto;
        justify-content: flex-start;
    }
}
/* /Components/Pages/Privacy.razor.rz.scp.css */
/* TAKT-268: every paragraph on this page used to carry `.app-lead`'s own `max-width: 60ch`
 * measure clamp individually. Converting them to DsTypography (which has no width parameter)
 * would have dropped that reading measure from a full legal policy document — so the clamp
 * moves up to the ARTICLE itself instead, which also now clamps the headings and any future
 * markup, not just the paragraphs a class happened to be pasted onto. */
.privacy[b-7c9nr5s4y0] {
    max-inline-size: var(--ds-layout-contentMaxWidthNarrow);
}
/* /Components/Pages/Profile.razor.rz.scp.css */
/* TAKT — Din profil (slice 5, Task 6). Our own layout, under our own class names. Tokens
   only; the single px in this file is the 900px (md) breakpoint the whole slice uses. */

/* App issue #423 — `minmax(0, 1fr)`, never a bare `1fr`, on EVERY track here. A `1fr` track's
   minimum is `auto`, i.e. its content's min-content width, so one child that will not shrink
   (a DsFormSection stack measured 453px, a long club name, an unwrapped button label) sizes
   the track to itself and the page scrolls sideways — measured on a 390px phone: the column
   451px wide, the document 469. `minmax(0, 1fr)` makes the viewport the floor, and whatever
   inside cannot shrink then overflows its own card visibly instead of silently widening the
   page. The same rule stated once more from the child's side: `min-inline-size: 0` on the
   column, because an implicit grid track is `auto` too. */
.takt-profile__grid[b-udxq6o322p] {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--ds-space-lg);
    align-items: start;
}

.takt-profile__col[b-udxq6o322p] {
    display: grid;
    /* An IMPLICIT column track is `auto` — content-sized — which is exactly the trap above,
       measured: `grid-template-columns: 452.6px` on a 330px column. Stated explicitly. */
    grid-template-columns: minmax(0, 1fr);
    gap: var(--ds-space-lg);
    align-content: start;
    /* Without this a grid track is min-content-sized by its widest child, and one long club
       name pushes the whole column past the viewport. */
    min-inline-size: 0;
}

@media (min-width: 900px) {
    .takt-profile__grid[b-udxq6o322p] {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    }
}

/* A setting whose control acts immediately: label left, control right, wrapping on a phone.
   TAKT-242: the control is now a DsSegmentedControl showing which theme is live, so the row
   only ever holds a name and a state — the two plain buttons this file used to style (a
   theme-cycle button and a form submit) are gone, and so are their rules. */
.takt-profile__setting[b-udxq6o322p] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--ds-space-sm);
    font-family: var(--ds-typography-bodySmall-font-family);
    font-size: var(--ds-typography-bodySmall-font-size);
}

.takt-profile__notice[b-udxq6o322p] {
    margin: 0;
    color: var(--ds-color-onSurfaceVariant);
    font-family: var(--ds-typography-bodySmall-font-family);
    font-size: var(--ds-typography-bodySmall-font-size);
}

/* TAKT-255: the per-club newsletter switch now renders on its own line below the
   DsItem row (Profile.razor's comment on the club loop has the full "why" — DsItem's
   leading/content/trailing never wrap, so a switch sharing that row with the avatar
   and the "Åbn →" link had only a sliver of width left for its own [track][label]
   pair, and the label wrapped one word per line at 430px). Indenting it to the
   DsAvatar's own width plus its gap to the text — both read from the SAME tokens
   DsItem itself is built from, never a guessed pixel — lines the switch up under the
   club name instead of the avatar, so it still reads as "this club's setting" even
   though it is no longer inside that club's row.

   ::deep — DsSwitch renders its own root <label>; Blazor CSS isolation only stamps
   THIS file's scope attribute on elements Profile.razor itself renders, and a DS
   component's own root never carries it (see the "Blazor scoped CSS" note in the
   task's hard rules). Without ::deep this rule would compile with the scope
   attribute appended and silently match nothing. */
[b-udxq6o322p] .takt-profile__club-newsletter {
    padding-inline-start: calc(var(--ds-avatar-sizeSm) + var(--ds-menu-itemGap));
}
/* /Components/Pages/ProjectBoard.razor.rz.scp.css */
/* Takt slice 5 / Task 9 — the project workspace's one piece of layout: the board beside its
   collaboration rail.

   It is a media query and not an intrinsic `auto-fit` track list because the two columns are
   NOT peers: the board takes whatever is left and the rail is a fixed reading width. 900px is
   the slice-wide breakpoint (the shell's own), never 880. Below it the rail stacks under the
   board, which is what the wireframe's phone layout does.

   Scoped CSS: every selector below names an element THIS component writes, so the b-* scope
   attribute lands on it. Nothing here reaches into a Ds* component's own markup. */

.takt-project__split[b-s4g3d9t8vt] {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--ds-space-lg);
  align-items: start;
}

/* min-inline-size:0 is load-bearing, not tidiness: a grid item's default `min-width:auto` lets
   the Kanban's own horizontal scroller push the column wider than the page instead of scrolling
   inside itself — which is exactly the overflow the audit fails on. */
.takt-project__work[b-s4g3d9t8vt] {
  min-inline-size: 0;
}

@media (min-width: 900px) {
  .takt-project__split[b-s4g3d9t8vt] {
    /* The rail IS a sidebar, so it takes the design system's sidebar track rather than a
       number this file made up. */
    grid-template-columns: minmax(0, 1fr) var(--ds-layout-sidebarWidth);
  }
}
/* /Components/Pages/SeasonBuilder.razor.rz.scp.css */
/* Season planner (EVENT-001 / M2; Takt slice 5 / Task 7 — the four-view restyle).
   Tokens only. The season-level vocabulary (md-tracks, season-settings, md-track__*, …) stays
   global in member-management.css; only what the four views added lives here. */

/* TAKT-331 (#375) — ONE header block: the season switcher and the season's own header.
   They were two page-level siblings a full `page-sections` rung apart, so a strip of selectable
   CARDS (the heaviest surface on the page) read as the headline and the <h1> under it read as a
   second one saying the same name and the same dates. `sm` between them and `lg` below the whole
   block is what makes them one composition with an internal rhythm, rather than two competing
   ones. `.app-pageheader` already owns the rung BELOW the header, so this block only has to state
   its own internal step. */
.takt-seasonhead[b-z5ix7d7j65] {
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-sm);
    /* Both the strip and the header wrap wide content; without this the strip's intrinsic width
       becomes the shell column's minimum and the page scrolls sideways instead of the strip
       scrolling inside itself. */
    min-width: 0;
}

/* The switcher's own label (`Skift sæson`) needs no rule of its own: the block above is a flex
   COLUMN, so it takes a row whatever its own display is. Named here rather than left silent
   because a rule for it would have to be `::deep` — the class rides DsTypography's `Class` onto an
   element the design system renders, which this file's scope attribute never reaches. */

.takt-season__titlemeta[b-z5ix7d7j65] {
    display: inline-flex;
    align-items: center;
    gap: var(--ds-space-xs);
    flex-wrap: wrap;
}

/* The schedule band: a heading and the four-way switch on one line above the view. Wraps rather
   than scrolls — the heading and the control are two things, not a sequence. */
.takt-season__schedule[b-z5ix7d7j65] {
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-sm);
    /* The shell's <main> is a grid COLUMN, and both the week grid and the skoleskema are wider
       than a phone. Without this their intrinsic width becomes the column's minimum and the whole
       page scrolls sideways instead of the view scrolling inside itself. */
    min-width: 0;
}
.takt-season__schedulehead[b-z5ix7d7j65] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--ds-space-sm);
}
.takt-season__schedulehead .section-title[b-z5ix7d7j65] { margin: 0; }
/* TAKT-331 (#375) — the printable timetable, down from the page header. Trailing edge, so the
   band reads heading → the four readings → the one that leaves the page. `auto` rather than a
   `justify-content` on the row, because the row wraps: on a phone the link lands under the
   segmented control instead of being pushed off it.
   `::deep` is load-bearing: the class rides DsButton's `Class` onto the BUTTON the design system
   renders, and this file's scope attribute is only stamped on elements from our own markup — so
   the plain selector compiled to `.takt-season__printlink[b-…]`, which matches nothing. */
[b-z5ix7d7j65] .takt-season__printlink { margin-inline-start: auto; }
/* …and on a phone the row has already wrapped, so the auto margin would only strand the link on a
   line of its own, hard right, away from the switch it belongs beside. */
@media (max-width: 899px) {
    [b-z5ix7d7j65] .takt-season__printlink { margin-inline-start: 0; }
}

.takt-season__viewcard[b-z5ix7d7j65] { min-width: 0; }

/* Ugekalender: the week nav is three controls on one row, and the calendar itself scrolls in its
   own box — seven day columns do not fit 430px. */
.takt-season__weeknav[b-z5ix7d7j65] {
    display: flex;
    align-items: center;
    gap: var(--ds-space-sm);
    flex-wrap: wrap;
    margin-bottom: var(--ds-space-sm);
}
.takt-season__calendar[b-z5ix7d7j65] { overflow-x: auto; }

/* The exception panel — what you can still do to the evening you just picked. It is an answer to
   a click, so it sits directly under the thing that was clicked and says which evening it means. */
.takt-season__exception[b-z5ix7d7j65] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--ds-space-sm);
    margin-top: var(--ds-space-md);
    padding-top: var(--ds-space-md);
    border-top: var(--ds-border-width-thin) solid var(--ds-color-outlineVariant);
}
/* /Components/Pages/Seasons.razor.rz.scp.css */
/* Season index (EVENT-001 / M2; TAKT-259 rich season cards). Tokens only. */

.takt-seasons[b-gwetec4g2o] {
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-md);
    /* The shell's <main> is a grid column: without this the grid's intrinsic width becomes the
       column's minimum and the page scrolls sideways instead of the cards reflowing. */
    min-width: 0;
}

/* The card's own "open the season" caption, and the dashed create cell's label — the two places
   this page composes around a Ds* component rather than inside one. Nothing here restyles the card;
   it only gives the caption its own rhythm and a full-height tap row (adoption §6c: 44px). */
.season-card__cta[b-gwetec4g2o] {
    display: flex;
    align-items: center;
    gap: var(--ds-space-xs);
    min-height: var(--ds-size-touchTarget);
}

.season-card__cta--center[b-gwetec4g2o] {
    justify-content: center;
    /* The create cell is a card-sized target, so its label centres in whatever height the tallest
       season card sets — the wireframe's dashed "+ Ny sæson" chip, at grid scale. */
    height: 100%;
}
/* /Components/Pages/TrackRoster.razor.rz.scp.css */
/* TrackRoster — SMM-owned wrapper markup only; the roster table and its actions are all Ds*
   components, so the one thing this page's own CSS owns is the plain "← Alle sæsoner" back
   link above it.

   Parity audit (WCAG 2.5.8 AA): the bare <a> measured 112x20 — under the 24px floor every
   device is held to, mouse included, not only touch. inline-flex + min-block-size grows the
   click box without growing the link's text, same technique as the other parity-audit fixes
   in this pass (MemberHome.razor.css, ClubDirectoryView.razor.css, takt-shell.css). */
.roster__navback[b-7l4qk2qico] {
    display: inline-flex;
    align-items: center;
    min-block-size: var(--ds-size-targetMin);
}

/* Parity 2026-09-02: on the phone captures the 24px AA floor above still sits under the 44px
   AAA/touch tier (WCAG 2.5.5), so below the shell's breakpoint the click box grows to the
   design system's own touch-target size. Desktop keeps the denser 24px floor. */
@media (max-width: 899px) {
    .roster__navback[b-7l4qk2qico] {
        min-block-size: var(--ds-size-touchTarget);
    }
}
/* /Components/Pages/Workshops.razor.rz.scp.css */
/* TAKT-239 — the workshops master–detail. Structural only: every value is a --ds-* token, and
   every selector is one of OUR class names (never a .ds-c-* rule — DesignSystemVocabularyTests
   fails the build on one). */

.workshops__editor[b-x6lodkq1ak] {
    min-inline-size: 0;
}

/* Which role a count belongs to is said in a WORD as well as a colour (A11Y-08); the colour is
   the identity pair the roster and the capacity meters already use. One token per role — the
   `*Ink` tokens resolve to an AA text ink in BOTH themes, so the hand-written dark override this
   file used to carry (needed while the follower read a static `indigo`) is gone. Never a raw hex. */
.workshops__cap[b-x6lodkq1ak] {
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* The leader/follower identity inks. Each *Ink token already resolves per theme (light
   #7242DE / dark #A99EF5 for tertiary; #006855 / #8FE3CE for indigo), so no [data-theme="dark"]
   override is needed — the two that used to sit here existed only because the follower read
   the STATIC --ds-color-indigo (#2D8379 in both themes) and had to be repainted by hand for
   dark. The dark leader moves from tertiary (#8B7CF0) to tertiaryInk (#A99EF5): same violet,
   the Ink value being the one tuned to clear AA as text. */
.workshops__cap--leader[b-x6lodkq1ak] {
    color: var(--ds-color-tertiaryInk);
}

.workshops__cap--follower[b-x6lodkq1ak] {
    color: var(--ds-color-indigoInk);
}
/* /Components/Pages/WorkshopSignup.razor.rz.scp.css */
/* Takt slice 5 / Task 5 — the workshop signup's own two-column layout (content + dansekort),
   scoped to this page. Structural only: every value is --ds-* (S5-S), never a raw literal.
   S5-P: this is an SMM-owned wrapper (.takt-workshop-signup__*), never a .ds-c-* selector. */

.takt-workshop-signup__layout[b-jpxatdjntj] {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--ds-space-lg);
    align-items: start;
}

@media (min-width: 900px) {
    .takt-workshop-signup__layout[b-jpxatdjntj] {
        grid-template-columns: minmax(0, 1fr) 22rem;
    }
}

/* Wireframe rebuild: the content column is a plain stack of its sections (who-chips, cards,
   options, role) — grid gap instead of per-child margins, tokens only. */
.takt-workshop-signup__content[b-jpxatdjntj] {
    display: grid;
    gap: var(--ds-space-md);
    align-content: start;
}

/* The inline choice picker sits indented under its option's own checkbox row, hugging its
   labels rather than stretching — a chips row, not a form-wide control. */
.takt-workshop-signup__choices[b-jpxatdjntj] {
    margin-inline-start: var(--ds-space-lg);
    inline-size: fit-content;
}
/* /Components/Signup/BasketSignupCard.razor.rz.scp.css */
/* Takt slice 5 / Task 5 — the season signup's own step machine + two-column layout. Structural
   only: every value is --ds-* (S5-S) or a bare breakpoint, never a raw color/spacing literal.
   S5-P: these are SMM-owned wrapper elements (.takt-signup*), never a .ds-c-* selector — the
   scoped RCL stylesheet loads after this file and would silently out-specify a rule that tried
   to reach into DsStepper/DsCard/DsButton's own root. */

.takt-signup[b-isln83xnbv] {
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-lg);
}

/* TAKT-308 / app #303 finding 2 — the wizard's vertical rhythm, on the DS scale and in ONE
   place. Below 900px everything above the fold on step 1 (the club hero, the season header, the
   step line, the help box, the first dancer card) was competing for the same short screen at the
   desktop rhythm, which is what read as "crammed": the gaps were not too small, they were the
   same size as the content between them. One step down the scale on a phone, one step up in the
   space between the step machine and the panel it labels — no new structure, no new colours. */
@media (max-width: 899px) {
    .takt-signup[b-isln83xnbv] {
        gap: var(--ds-space-md);
    }
}

/* The step machine is two mutually exclusive controls (DsStepper above 900px, the step spans
   below) plus nothing else, so this only has to say how far the header sits from itself when
   both are in the DOM — and it is the element the step change scrolls to, so it owns the space
   under it rather than leaving it to whichever panel happens to render next. */
.takt-signup__stepheader[b-isln83xnbv] {
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-xs);
}

/* Every step panel is a column of blocks — a help box, a stack of cards, a button, a checkbox —
   that had no shared rhythm at all: each child brought whatever margin its own component
   happened to carry, so the distance between the help box and the first dancer card was not the
   distance between that card and "+ Tilføj en person". One gap, from the token scale, tightened
   a step on a phone. `[data-steppanel]` is this component's own element, so the scoped selector
   really does match it (a DS component's own root never carries our scope attribute). */
[data-steppanel][b-isln83xnbv] {
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-lg);
}

@media (max-width: 899px) {
    [data-steppanel][b-isln83xnbv] {
        gap: var(--ds-space-md);
    }
}

/* DsStepper is the visible control from 900px up; the mobile step line below takes over under
   it — never both at once, so the DOM always carries both without ever showing two step UIs. */
.takt-stepper[b-isln83xnbv] {
    display: none;
}

@media (min-width: 900px) {
    .takt-stepper[b-isln83xnbv] {
        display: block;
    }
}

.takt-signup__mobile-steps[b-isln83xnbv] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--ds-space-sm);
    font-family: var(--ds-typography-body-font-family);
    font-size: var(--ds-typography-bodySmall-font-size);
    color: var(--ds-color-onSurfaceVariant);
}

@media (min-width: 900px) {
    .takt-signup__mobile-steps[b-isln83xnbv] {
        display: none;
    }
}

.takt-signup__mobile-steps [data-takt-step][b-isln83xnbv] {
    cursor: default;
}

.takt-signup__mobile-steps [data-takt-step].is-clickable[b-isln83xnbv] {
    cursor: pointer;
    text-decoration: underline;
}

.takt-signup__mobile-steps [data-takt-step].is-current[b-isln83xnbv] {
    font-weight: 600;
    color: var(--ds-color-onSurface);
}

/* The "vælger for" block is its own band above the class list — TAKT-238 gave it a tab strip and
   a helper line, and at `sm` the first series heading collided with that helper.
   TAKT-308: the margin that used to live here is gone — the panel's own `gap` above now sets this
   distance, and keeping both meant this one band sat a whole step further from the classes than
   every other pair of blocks in the wizard. The class stays as the band's hook. */

/* Content beside the dansekort on desktop; the dansekort drops below on a narrow screen
   (Dansekort's own Sticky prop releases the pin at the same 900px breakpoint — adoption §3). */
.takt-signup__layout[b-isln83xnbv] {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--ds-space-lg);
    align-items: start;
}

@media (min-width: 900px) {
    .takt-signup__layout[b-isln83xnbv] {
        grid-template-columns: minmax(0, 1fr) 22rem;
    }
}

/* TAKT-271 / app #247 — the phone's sticky summary line. Hidden from 900px up, where the
   dansekort is pinned beside the page and says all of this already (the same breakpoint
   .takt-dansekort--sticky uses, so the two hand over to each other exactly).

   `position: sticky`, never `fixed`: a sticky element keeps its row in the flow, so it pins
   to the bottom of whatever scrolls and can never cover the bottom tab bar the app shell
   reserves its own grid row for — no safe-area arithmetic, no z-index race with the chat FAB.
   The containing block is `.takt-signup`, so the line rides along for the whole signup and
   releases at its end, which is where the dansekort itself takes over. */
.takt-signup__summary[b-isln83xnbv] {
    display: none;
}

@media (max-width: 899px) {
    .takt-signup__summary[b-isln83xnbv] {
        display: block;
        position: sticky;
        /* NOT 0. The app shell's <main> is the scrolling region, and it carries
           `padding-bottom: --ds-appShell-floatingClearance` (96px) so page content clears the
           floating chat button — every club page fills that slot. A sticky child pins to the
           PADDING box, so `inset-block-end: 0` left this bar hovering 96px up the screen with
           class cards showing underneath it, reading as a misplaced panel rather than an action
           bar. Cancelling exactly that token (read, never redefined) puts it back on the
           scrollport edge — immediately above the bottom tab bar, which is the shell's own grid
           row outside <main> and therefore still never covered. No raw fallback: the token is
           in the generated theme (TaktShellCssTests forbids one, and a literal here would be a
           second, silently diverging definition of the package's own clearance). */
        inset-block-end: calc(-1 * var(--ds-appShell-floatingClearance));
        z-index: var(--ds-zIndex-sticky);
        padding: var(--ds-space-sm) var(--ds-space-md);
        background-color: var(--ds-color-surface);
        border-block-start: var(--ds-border-width-thin) solid var(--ds-color-outlineVariant);
        border-start-start-radius: var(--ds-radius-md);
        border-start-end-radius: var(--ds-radius-md);
        box-shadow: var(--ds-elevation-level-002);
    }
}

.takt-signup__summary-row[b-isln83xnbv] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--ds-space-sm);
}

.takt-signup__summary-text[b-isln83xnbv] {
    font-family: var(--ds-typography-label-font-family);
    font-size: var(--ds-typography-label-font-size);
    font-weight: var(--ds-typography-label-font-weight);
    color: var(--ds-color-onSurface);
    font-variant-numeric: tabular-nums;
}

/* Owner design pass (2026-08-27): "Dine tilmeldinger" / "Åbne workshops", folded into the
   step-1 content column (BasketSignupCard.razor's own note on the render site explains why).
   Plain vertical rhythm — the two sections are already DsCards, so only the gap between them
   and the panel above is this file's job. */
.takt-signup__supplemental[b-isln83xnbv] {
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-lg);
    margin-block-start: var(--ds-space-lg);
}
/* /Components/Signup/BirthDateField.razor.rz.scp.css */
/* TAKT-317 / app #317 — the three typed birth-date boxes on one row.

   The whole point of the change is a birth date you can type on a phone, so the group has to FIT on
   a phone: at 390px all three sit side by side. They are sized in `ch` — the honest unit here,
   because each box is sized to the characters it holds (two digits, a month name, four digits)
   rather than to a design value the theme owns; the GAP is a --ds-* token, as every gap is.

   The boxes shrink before they wrap: flex-basis is the comfortable size, min-width is the smallest
   the content stays readable at. `flex-wrap` is the graceful fallback for a narrower viewport or a
   larger text size, not the plan. */
.takt-birthdate__parts[b-lccxmalhqp] {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: var(--ds-space-sm);
}

.takt-birthdate__day[b-lccxmalhqp] {
    flex: 0 1 5ch;
    min-width: 4.5ch;
}

/* The widest of the three: it holds a month NAME ("september"), plus the native select's chevron.
   It also takes ALL the slack (flex-grow: 1), so the basis stays small enough that the row never
   wraps at 390px and every spare pixel then lands where the longest word is. */
.takt-birthdate__month[b-lccxmalhqp] {
    flex: 1 1 8ch;
    min-width: 7ch;
}

.takt-birthdate__year[b-lccxmalhqp] {
    flex: 0 1 6.5ch;
    min-width: 6ch;
}
/* /Components/Signup/ManualPaymentPanel.razor.rz.scp.css */
/* Structural layout only — themable values stay var(--ds-*) (component-design.md). */

.manual-pay__head[b-5dg7j5ccvh] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ds-space-sm);
}

/* TAKT-268: the panel's own <h2> is a DsTypography(Heading5) now, whose base class already
 * sets `margin: 0` — the margin reset that used to live here is redundant. */

/* QR beside the facts (the wireframe's outstanding-payment card), stacking when narrow. */
.manual-pay__body[b-5dg7j5ccvh] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ds-space-lg);
}

.manual-pay__grid[b-5dg7j5ccvh] {
    display: grid;
    gap: var(--ds-space-sm);
    margin: var(--ds-space-md) 0;
    flex: 1;
    min-width: 16rem;
    /* Issue #308/#304 — with no cap this grid stretched across the panel's full width (label
       far left, value far right, reading like a spreadsheet rather than a receipt). Capped to
       the DS "lg" reading measure — wide enough for a line like "Reference  WCSAA-XXXX", never
       the panel's whole width. Same panel renders on the signup step/landing AND MyOrders. */
    max-inline-size: var(--ds-measure-lg);
}

.manual-pay__row[b-5dg7j5ccvh] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--ds-space-sm);
}

.manual-pay__row dt[b-5dg7j5ccvh] {
    color: var(--ds-color-onSurfaceVariant);
}

/* Keeps the copy affordance on the code's own baseline instead of a second dl column. */
.manual-pay__codecell[b-5dg7j5ccvh] {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ds-space-sm);
}

/* Large and selectable-in-one-click ("copyable type") — a member reading this off their own phone
   needs to grab the whole code without carefully dragging a selection. */
.manual-pay__code[b-5dg7j5ccvh] {
    font-family: var(--ds-typography-code-font-family);
    font-size: var(--ds-typography-heading2-font-size);
    font-weight: var(--ds-typography-heading2-font-weight);
    letter-spacing: 0.05em;
    color: var(--ds-color-primary);
    user-select: all;
    cursor: text;
    /* task-5 audit (430×932): heading2-sized, letter-spaced text plus its own label overran a
       narrow row (right edge past the viewport) — the row now wraps (flex-wrap above) and this
       is the belt-and-braces fallback for the code itself, which never contains a space to wrap
       on otherwise. */
    overflow-wrap: anywhere;
}

/* Issue #308: heading2 (44px) held at every width, so a code like "WCSAA-XXXX" — with its own
   0.05em letter-spacing — could not fit beside the Kopiér action on one line at the repo's
   phone width (390px), even with flex-wrap. Stepped down below the repo's single 900px
   breakpoint; overflow-wrap above stays as the belt-and-braces fallback. */
@media (max-width: 900px) {
    .manual-pay__code[b-5dg7j5ccvh] {
        font-size: var(--ds-typography-heading4-font-size);
        font-weight: var(--ds-typography-heading4-font-weight);
    }
}

.manual-pay__qr[b-5dg7j5ccvh] {
    display: block;
    width: 12rem;
    height: 12rem;
    border-radius: var(--ds-radius-md);
}
/* /Components/Takt/CalendarDetailPanel.razor.rz.scp.css */
/* TAKT — calendar detail panel (slice 5, Task 6). Our own composition classes only; the
   drawer's own chrome belongs to the design system. Tokens only — no hex, no design px. */

.takt-caldetail__body[b-yo8y4clott] {
    display: grid;
    gap: var(--ds-space-md);
}

.takt-caldetail__status[b-yo8y4clott] {
    justify-self: start;
}

/* The .ics is an <a download>, not a button: handing over a data: URI file needs an anchor,
   and DsButton's href renders a navigational link. Wearing the quiet-button shape keeps it in
   the same row as the secondary action without inventing a colour. */
.takt-caldetail__ics[b-yo8y4clott] {
    display: inline-flex;
    align-items: center;
    padding-block: var(--ds-space-sm);
    padding-inline: var(--ds-space-md);
    border: var(--ds-border-width-thin) solid var(--ds-color-outlineVariant);
    border-radius: var(--ds-radius-sm);
    color: var(--ds-color-onSurface);
    font-family: var(--ds-typography-label-font-family);
    font-size: var(--ds-typography-label-font-size);
    font-weight: var(--ds-typography-label-font-weight);
    text-decoration: none;
}

.takt-caldetail__ics:hover[b-yo8y4clott] {
    background: var(--ds-color-surfaceContainerHigh);
}

.takt-caldetail__ics:focus-visible[b-yo8y4clott] {
    outline: var(--ds-border-focusRing-width) solid var(--ds-color-focusRing);
    outline-offset: var(--ds-border-focusRing-offset);
}

/* TAKT-305d — the reachable close on a phone: DsDrawer's own ✕ sits top-right, above where a
   thumb naturally rests. Hidden ≥900px, where that top-right close is already comfortable. */
.takt-caldetail__closeMobile[b-yo8y4clott] {
    display: none;
}

@media (max-width: 900px) {
    .takt-caldetail__closeMobile[b-yo8y4clott] {
        display: flex;
    }
}
/* /Components/Takt/ClubDirectoryView.razor.rz.scp.css */
/* TAKT — the public club directory (#103), restyled to the wireframe's front door.
 *
 * Scoped to ClubDirectory.razor. `::deep` is only used where a rule has to reach an element a Ds*
 * component renders — Blazor stamps its scope attribute on the elements THIS page emits, never on
 * a child component's root.
 *
 * Tokens only: no hex, no design px. The one literal length is the 900px breakpoint, which is the
 * adoption contract's `md`. No `.ds-c-*` selector is defined here (DS-004).
 */

.dir[b-r4bk8r5z1w] {
    display: block;
}

/* The accent full stop every public headline wears. */
.dir__dot[b-r4bk8r5z1w] {
    color: var(--ds-color-primary);
}

/* ── Search ─────────────────────────────────────────────────────────────────────────────── */

.dir__search[b-r4bk8r5z1w] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--ds-space-sm);
    max-inline-size: var(--ds-layout-contentMaxWidthNarrow);
}

.dir__input[b-r4bk8r5z1w] {
    flex: 1 1 auto;
    min-inline-size: 0;
    padding: var(--ds-space-sm) var(--ds-space-md);
    border: var(--ds-border-width-thin) solid var(--ds-color-outline);
    border-radius: var(--ds-radius-md);
    background-color: var(--ds-color-surface);
    color: var(--ds-color-onSurface);
    font-family: inherit;
    font-size: var(--ds-typography-body-font-size);
    line-height: var(--ds-typography-body-line-height);
}

/* D10 — the search field measured 326x42 on every phone capture the parity harness has ever
 * taken, and 572x42 on a 768 tablet in the 2026-09-14 consumer capture: two pixels under the
 * touch floor, and it is the first control on the front door. Its own padding + body line-height
 * land it there, so a floor is the fix rather than more padding (which would move the Søg button
 * beside it out of alignment). Keyed on the POINTER, not a width: a tablet is a touch device at
 * every width, a desktop mouse never needs the floor. */
@media (pointer: coarse) {
    .dir__input[b-r4bk8r5z1w] {
        min-block-size: var(--ds-size-touchTarget);
    }
}

.dir__input:focus-visible[b-r4bk8r5z1w] {
    outline: var(--ds-border-focusRing-width) solid var(--ds-color-focusRing);
    outline-offset: var(--ds-border-focusRing-offset);
}

/* ── City chips ────────────────────────────────────────────────────────────────────────────
 * DsChip renders the pill itself (container/border/selected tokens, hover, focus ring,
 * aria-current styling) — this file only lays the row out and gives the in-chip count its own
 * (non-status) typography. */

.dir__chips[b-r4bk8r5z1w] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ds-space-xs);
}

/* No colour of its own: it inherits the chip's own ink (onContainer / onContainerSelected),
 * which is what keeps it legible in both states without reaching into DsChip's classes. */
.dir__chipcount[b-r4bk8r5z1w] {
    font-family: var(--ds-typography-code-font-family);
}

/* ── The identity tiles ────────────────────────────────────────────────────────────────────
 * DsCard renders the card's own chrome (container/border/radius, interactive hover/focus) —
 * this file only fills the grid cell and clips the media band's full bleed to the radius. */

.dir__grid[b-r4bk8r5z1w] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    /* minmax(0, …), never a bare 1fr (handover §8): a bare track refuses to shrink below its
     * widest child, so one long club name pushes the whole row past the viewport. */
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 1fr));
    gap: var(--ds-space-md);
}

.dir__cell[b-r4bk8r5z1w] {
    display: flex;
}

/* DsCard's own CSS supplies the container/border/radius, the interactive hover elevation, the
 * click layer's focus ring AND — since the media band moved into its `Media` slot (TAKT-301
 * finding 1) — the full bleed and the radius clip. Filling the grid cell is the grid's own
 * `justify-items: stretch` default on a block-level card root, so the `inline-size: 100%` this
 * file used to set on the DS box (app issue #435's consumer-width-override) is gone — measured
 * at 2560: eight 261px cells, every card 261px. */

/* The gradient identity tile. Each of the four pairs is a ROLE and its own ramp's dark end, which
 * is what makes a tile read as one hue deepening rather than two unrelated colours — and it means
 * a brand flip repaints the directory instead of freezing one brand's hexes into the page.
 *
 * TAKT-301 finding 1: the negative margins that used to live here are gone. The band sits in
 * DsCard's `Media` slot now, and the slot owns the bleed (its own `calc(-1 * var(--ds-card-
 * padding))`) and the clip (its `--hasMedia` overflow) — restating either here would fight it.
 * What is left is ours: the gradient, the centring, and filling the band the slot's MediaHeight
 * fixes. `block-size: 100%` because DsCard's own "stretch the child" rule is scoped to elements
 * DsCard emits and cannot reach a child this file renders. */
.dir__media[b-r4bk8r5z1w] {
    display: grid;
    place-items: center;
    block-size: 100%;
    overflow: hidden;
}

.dir__media--g0[b-r4bk8r5z1w] {
    background: linear-gradient(130deg, var(--ds-color-tertiary), var(--ds-color-inverseSurface));
    color: var(--ds-color-onTertiary);
}

.dir__media--g1[b-r4bk8r5z1w] {
    background: linear-gradient(130deg, var(--ds-color-primary), var(--ds-color-primaryActive));
    color: var(--ds-color-onPrimary);
}

.dir__media--g2[b-r4bk8r5z1w] {
    background: linear-gradient(130deg, var(--ds-color-indigo), var(--ds-color-indigoStrong));
    color: var(--ds-color-onIndigo);
}

.dir__media--g3[b-r4bk8r5z1w] {
    background: linear-gradient(130deg, var(--ds-color-warning), var(--ds-color-warningStrong));
    color: var(--ds-color-onWarning);
}

.dir__image[b-r4bk8r5z1w] {
    inline-size: 100%;
    block-size: 100%;
    object-fit: cover;
}

.dir__initial[b-r4bk8r5z1w] {
    font-family: var(--ds-typography-display-font-family);
    font-size: var(--ds-typography-heading1-font-size);
    line-height: 1;
    text-transform: uppercase;
    color: inherit;
}

/* No padding of its own: it sits inside DsCard's own padded content box (the media band above is
 * the one element that bleeds out of it), and the gap from the media band above is DsCard's own
 * --ds-card-bodyGap, not a value restated here. */
.dir__body[b-r4bk8r5z1w] {
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-hairline);
    min-inline-size: 0;
}

/* App issue #434 — a club name that is a single unbroken word (or close to it: "Vestkystens
 * Svømmeklub") did not fit a ~152px card cell at 360px and DsCard's own `overflow: hidden` (the
 * media-band clip, DsCard.razor.css) silently cut it mid-word instead of wrapping it — the DS's
 * own wrap-floor convention (spec's recipes/_shared.md §6, `break-word` not `anywhere`) never
 * reached this element because it is app markup, not a DS component. `break-word` gives the
 * browser a soft-wrap point inside the one long word rather than letting it overflow the card's
 * clipped box. */
.dir__name[b-r4bk8r5z1w] {
    font-family: var(--ds-typography-heading5-font-family);
    font-size: var(--ds-typography-heading5-font-size);
    line-height: var(--ds-typography-heading5-line-height);
    font-weight: var(--ds-typography-heading5-font-weight);
    overflow-wrap: break-word;
}

.dir__where[b-r4bk8r5z1w] {
    font-size: var(--ds-typography-bodySmall-font-size);
    line-height: var(--ds-typography-bodySmall-line-height);
    color: var(--ds-color-onSurfaceVariant);
}

/* ── The unlisted-club hint ─────────────────────────────────────────────────────────────── */

.dir__hiddenlinks[b-r4bk8r5z1w] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ds-space-sm);
}

/* Underlined, not colour-only: a link inside a block of text has to be distinguishable without
 * relying on hue (axe's link-in-text-block, found on this page by the Task 2 audit). */
.dir__hiddenlinks a[b-r4bk8r5z1w] {
    text-decoration: underline;
    /* The consumer gate's tap-target audit (2026-09-06): a bare inline link measured 72x21, under
       the 24px floor WCAG 2.5.8 applies on every pointer. The row grows to the DS's own minimum
       target; the caption-sized text does not. */
    display: inline-flex;
    align-items: center;
    min-block-size: var(--ds-size-targetMin);
}

/* ── "Sådan virker Takt" ─────────────────────────────────────────────────────────────────
 * TAKT-268: the "how it works" heading/sub-heading used to hand-copy the heading3/heading5
 * token sets here (raw <h2>/<h3> + this CSS). Converted to DsTypography (Heading3/Heading5),
 * which renders the same composite from its own stylesheet — nothing local left to keep in
 * sync with a brand change. */

/* TAKT-301 finding 3: no `align-items: start`. The three boxes are three equal explanations, and
 * `start` let each shrink to its own copy — the row read as three unrelated blocks at three
 * heights. The grid's default `stretch` gives every card the row's height; DsCard's FillHeight
 * (set at the call site) is the other half, since stretch resizes the card box but not what is
 * inside it. */
.dir__howgrid[b-r4bk8r5z1w] {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--ds-space-md);
}

.dir__footnote[b-r4bk8r5z1w] {
    margin: 0;
    font-size: var(--ds-typography-caption-font-size);
    line-height: var(--ds-typography-caption-line-height);
    color: var(--ds-color-onSurfaceVariant);
}

/* Same reason as the hint's links: it sits inside a sentence.
   Parity audit (WCAG 2.5.8 AA): "Opret en ny klub" / "Hvad er Takt?" measured 90x15 and
   75x15 — well under the 24px floor every device is held to, not only touch. inline-flex +
   min-block-size grows the click/tap box without growing the caption text, and still sits
   on the sentence's own line since it stays an inline flex item, not a block. */
.dir__footnote a[b-r4bk8r5z1w] {
    display: inline-flex;
    align-items: center;
    min-block-size: var(--ds-size-targetMin);
    color: var(--ds-color-onSurfaceVariant);
    text-decoration: underline;
}

/* ── Below 900px (the adoption contract's `md`, never 880) ──────────────────────────────── */

@media (max-width: 900px) {
    .dir__howgrid[b-r4bk8r5z1w] {
        grid-template-columns: minmax(0, 1fr);
    }

    /* TAKT-303 — TWO UP ON A PHONE, with a real card minimum (app issue #434). `auto-fill,
     * minmax(min(100%, 16rem), 1fr)` resolves to a single ~358px column at 390px, so the front
     * door showed ONE club per screen and a visitor scrolled a full viewport per candidate. A
     * directory card is a picture, a name and a town — it carries half the width without losing
     * any of the three, and two per row is what lets a stranger COMPARE clubs rather than page
     * through them.
     *
     * `repeat(2, …)` UNCONDITIONALLY (no floor) is what #434 found: at 360px the shell's
     * `--ds-space-lg` gutters (24px each side) plus this row's `--ds-space-sm` gap (8px) leave
     * 312px for two cells, 152px each — too narrow for a longer club name even wrapped
     * ("Aarhus Vestkystens Svømmeklub"), and DsCard's own media-band `overflow: hidden` (the
     * radius clip) turned the overrun into a silent mid-word cut instead of a third line.
     * `auto-fill` with a 10rem (160px) floor keeps the same math everywhere ELSE it fits — two
     * columns survive from 390px up (342px content, 167px/cell) exactly as before — and folds to
     * ONE column only at the width where two cannot: 312px content cannot hold two 160px+8px
     * tracks (328px needed), so 360px alone drops to one, full-width card. `break-word` on
     * `.dir__name` (above) is the belt for whatever name still runs long inside its column. */
    .dir__grid[b-r4bk8r5z1w] {
        grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
        gap: var(--ds-space-sm);
    }

    /* The card's own measures follow it down: DsCard's standard 24px padding leaves ~120px of
     * usable width in a half-width cell (a club name wraps three times inside it), and a 160px
     * media band on a ~170px card is a square of gradient with a caption under it. Both are the
     * DS's OWN component tokens re-pointed to the DS's OWN other rung — the compact padding it
     * ships for dense contexts, and the Sm media height — on our grid cell, never a literal. */
    .dir__cell[b-r4bk8r5z1w] {
        --ds-card-padding: var(--ds-card-paddingCompact);
        --ds-card-mediaHeightMd: var(--ds-card-mediaHeightSm);
    }

    /* A club name at heading5 (20px) in a ~140px measure is three lines of two words. One rung
     * down keeps the name the loudest thing on the card without letting it own the whole cell. */
    .dir__name[b-r4bk8r5z1w] {
        font-size: var(--ds-typography-heading6-font-size);
        line-height: var(--ds-typography-heading6-line-height);
    }

    /* ONE row that scrolls, not a block that wraps. A city filter is a row of peers; wrapped onto
     * two or three lines it reads as three groups, and every line of it pushes the grid further
     * below the fold on the one screen whose whole job is showing clubs.
     *
     * NOT DsScrollView, which is the house answer everywhere the scrolling applies at every width
     * (the calendar's month grid, StatusCardStrip, KpiPeekRow): this row wraps perfectly well on a
     * desktop and changing that is outside a phone-density pass, and a component cannot be swapped
     * in by a media query. Our own class, the DS's own tokens — no `ds-c-*` rule, and nothing of
     * DsChip's own is touched. If the row ever needs to scroll at every width, the swap is one
     * element and this block goes away. */
    .dir__chips[b-r4bk8r5z1w] {
        flex-wrap: nowrap;
        overflow-x: auto;
        /* Without this the last chip can sit flush against the cut edge and read as clipped
         * rather than as a row that visibly continues. */
        padding-inline-end: var(--ds-space-xs);
        /* D10 — the chips clear the touch floor. DsChip's own minHeight (28px) plus its padding
         * lands the pill at 39px, which the parity audit has flagged on every phone capture of
         * this screen; on a filter row a thumb is meant to work through, 5px short is the
         * difference between choosing a city and choosing the one beside it. The component's OWN
         * minHeight token, set on our row — not a rule of ours competing with DsChip's — and the
         * desktop row (where a dense 39px pill is right) is untouched. */
        --ds-chip-minHeight: 2.75rem;
    }

    /* A flex item shrinks by default, and in a nowrap row that is not "scroll" — it is four chips
     * squeezed to a third of their labels, each breaking "Alle byer" and "København N" over two
     * lines inside a pill. `flex: 0 0 auto` is what turns the overflow into the scroll the rule
     * above intends. `::deep`: DsChip emits the pill, so Blazor never stamps this file's scope
     * attribute on it — `.dir__chips` is ours and carries it, and every anchor inside this row is
     * a chip (they are GET links, not buttons). */
    .dir__chips[b-r4bk8r5z1w]  a {
        flex: 0 0 auto;
        white-space: nowrap;
    }

    /* The section heading steps down with the rest of the page's type (the H1's own re-point is
     * in takt-shell.css). `::deep`: DsTypography emits this element, so Blazor never stamps this
     * file's scope attribute on it — `.dir__how` is ours and carries it. */
    .dir__how[b-r4bk8r5z1w]  h2 {
        font-size: var(--ds-typography-heading4-font-size);
        line-height: var(--ds-typography-heading4-line-height);
    }
}
/* /Components/Takt/ClubLanding.razor.rz.scp.css */
/* TAKT — the public Klubside (#155).
 *
 * Scoped to ClubHome.razor. Everything under `::deep` targets an element a Ds* component renders
 * (Blazor stamps the scope attribute only on the elements THIS page's own markup emits), which is
 * why every rule below hangs off `.klubside` — the one plain wrapper the page owns.
 *
 * Tokens only: no hex, no design px. The single literal length is the 900px breakpoint, which is
 * the adoption contract's own `md` and not a design value. No `.ds-c-*` selector is defined here
 * (DS-004 / DesignSystemVocabularyTests).
 */

.klubside[b-jhlwn1esda] {
    display: block;
}

/* ── Hero ───────────────────────────────────────────────────────────────────────────────────
 * The night ramp sliding into the brand accent past the far corner. Both stops and the ink are
 * ROLES, so a brand flip repaints the hero instead of breaking it, and the panel stays a night
 * panel in both themes — it is the club's identity surface, not a theme surface.
 */
.klubside[b-jhlwn1esda]  .klubside__hero {
    background: linear-gradient(
        115deg,
        var(--ds-color-inverseSurface) 0%,
        var(--ds-color-inverseSurfaceHigh) 50%,
        var(--ds-color-primary) 135%);
    border-color: var(--ds-color-inverseSurface);
}

/* The hero is DsCard Variant="Hero" — a brand gradient wash, NOT the inverse variant. DS 1.6.0's
 * inverse card now re-points the core ink roles for its descendants (which is why the pitch
 * card below and the dansekort no longer carry this block), but the HERO variant does not: its
 * job is the wash, and it leaves ink alone. So anything inside it that PINS an ink (a subtle
 * body line, an eyebrow) would still render near-black on the dark wash without this. Every
 * value is another --ds-color-* role and the scope is one composition, never :root. */
.klubside[b-jhlwn1esda]  .klubside__hero {
    --ds-color-onSurface: var(--ds-color-onInverseSurface);
    --ds-color-onSurfaceVariant: var(--ds-color-onInverseSurface);
    --ds-color-onSurfaceSubtle: var(--ds-color-onInverseSurface);
    --ds-color-outlineVariant: var(--ds-color-inverseSurfaceHigh);
    color: var(--ds-color-onInverseSurface);
}

.klubside[b-jhlwn1esda]  .klubside__pitch {
    border-color: var(--ds-color-inverseSurface);
}

/* TAKT-268: the display-sized composite (family/size/line-height/weight/tracking) used to be
 * hand-copied here — deleted now that the headline is a DsTypography(Display), which renders
 * the same composite from its own stylesheet. What is left is NOT typography: a reading-measure
 * clamp (the hero gradient's third stop is --ds-color-primary past 135%, and an uncapped
 * headline runs the full card width and lands its ink on that region) and the ink itself, which
 * is bound directly to the inverse-surface role rather than left to DsTypography's Default
 * (no *OnInverseSurface color exists on DsTypographyColor, and the Hero card variant leaves
 * ink alone — see the hero block above). Reached via ::deep: Blazor's CSS
 * isolation stamps the scope attribute on elements THIS file renders, never on a child
 * component's root (same reasoning as .klubside__hero above). */
.klubside[b-jhlwn1esda]  .klubside__title {
    max-inline-size: var(--ds-layout-contentMaxWidthNarrow);
    color: var(--ds-color-onInverseSurface);
}

/* The accent full stop every public headline wears — brand punctuation, so it binds the role. */
.klubside__dot[b-jhlwn1esda] {
    color: var(--ds-color-primary);
}

.klubside__lead[b-jhlwn1esda] {
    margin: 0;
    max-inline-size: var(--ds-layout-contentMaxWidthNarrow);
    font-size: var(--ds-typography-bodyLarge-font-size);
    line-height: var(--ds-typography-bodyLarge-line-height);
    color: var(--ds-color-onInverseSurface);
}

.klubside__where[b-jhlwn1esda] {
    margin: 0;
    font-family: var(--ds-typography-code-font-family);
    font-size: var(--ds-typography-bodySmall-font-size);
    color: var(--ds-color-onInverseSurface);
}

/* ── Sections ───────────────────────────────────────────────────────────────────────────── */

.klubside__section[b-jhlwn1esda] {
    /* The public header is sticky, so an in-page anchor would otherwise land its heading
     * underneath it. The offset is the app bar's own height token, so it moves if the bar's
     * density does. */
    scroll-margin-block-start: var(--ds-appBar-height);
}

/* TAKT-268: .klubside__h2 / __h3 / __h4 hand-copied the heading3/heading5/heading6 token sets
 * for three plain <h2>/<h3> elements — deleted now that those call sites are DsTypography
 * (Heading3/Heading5/Heading6). Their "color: inherit" was already the ambient text colour
 * (the hero/pitch surfaces re-point the *onSurface roles for their descendants, and a plain
 * <section> heading has nothing to override), so DsTypography's Default (no colour class,
 * inherits) reproduces it with no local rule at all. */

.klubside__sectionlead[b-jhlwn1esda],
.klubside__prose[b-jhlwn1esda] {
    margin: 0;
    max-inline-size: var(--ds-layout-contentMaxWidthNarrow);
    color: var(--ds-color-onSurfaceVariant);
}

/* ── The instructors ────────────────────────────────────────────────────────────────────────
 * Three across at desktop, one at mobile — the same auto-fit idiom the two-up grids below use,
 * with a narrower floor because a person row is an avatar plus two short lines, not a card.
 */
.klubside__people[b-jhlwn1esda] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr));
    align-items: start;
    gap: var(--ds-space-md);
}

.klubside__person[b-jhlwn1esda] {
    display: flex;
    align-items: center;
    gap: var(--ds-space-sm);
    min-inline-size: 0;
}

.klubside__persontext[b-jhlwn1esda] {
    display: grid;
    gap: var(--ds-space-xxs);
    min-inline-size: 0;
}

/* ── The two-up card grids ──────────────────────────────────────────────────────────────────
 * minmax(0, 1fr), never a bare 1fr (handover §8): a bare 1fr column refuses to shrink below its
 * widest child, so one long class name pushes the row past the viewport. `align-items: start`
 * rather than the default stretch: hug-height cards have no stretch-void to leave under a short
 * one, which is the same defect from the other side.
 */
.klubside__grid[b-jhlwn1esda] {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: start;
    gap: var(--ds-space-md);
}

/* ── One class / one workshop, read-only ──────────────────────────────────────────────────── */

/* Two columns, not one wrapping row: the name+badge group wraps on its own when it must, but the
 * price never becomes an orphan line of its own. */
.klubside__trackrow[b-jhlwn1esda] {
    display: flex;
    align-items: flex-start;
    gap: var(--ds-space-sm);
    flex-wrap: nowrap;
}

.klubside__trackname[b-jhlwn1esda] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--ds-space-sm);
    flex: 1 1 auto;
    min-inline-size: 0;
}

.klubside[b-jhlwn1esda]  .klubside__price {
    flex-shrink: 0;
    white-space: nowrap;
}

.klubside__cardcta[b-jhlwn1esda] {
    display: flex;
    gap: var(--ds-space-xs);
}

/* ── The membership pitch ───────────────────────────────────────────────────────────────── */

.klubside__benefits[b-jhlwn1esda] {
    list-style: none;
    margin: 0;
    padding-inline: 0;
    display: grid;
    gap: var(--ds-space-xs);
    font-size: var(--ds-typography-bodySmall-font-size);
    line-height: var(--ds-typography-bodySmall-line-height);
    color: var(--ds-color-onInverseSurface);
}

.klubside__fineprint[b-jhlwn1esda] {
    margin: 0;
    font-size: var(--ds-typography-caption-font-size);
    line-height: var(--ds-typography-caption-line-height);
    color: var(--ds-color-onInverseSurface);
}

.klubside__privacy[b-jhlwn1esda] {
    margin: 0;
    padding-block-start: var(--ds-space-sm);
    border-block-start: var(--ds-border-width-thin) solid var(--ds-color-inverseSurfaceHigh);
    font-size: var(--ds-typography-caption-font-size);
    line-height: var(--ds-typography-caption-line-height);
    color: var(--ds-color-onInverseSurface);
}

/* ── Below 900px (the adoption contract's `md`, never 880) ──────────────────────────────── */

@media (max-width: 900px) {
    .klubside__grid[b-jhlwn1esda] {
        grid-template-columns: minmax(0, 1fr);
        /* See the Praktisk note further down for why the definition values read left here. */
        --ds-definitionList-valueAlign: left;
    }

    /* Not a hand-copy of the full composite (that would be exactly the pattern this task
     * removes) — a deliberate per-instance override of ONE property for the mobile
     * breakpoint: the headline steps down from Display to the Heading2 SIZE, still reading
     * as a display headline everywhere else. DsTypography's Variant is chosen at Razor
     * render time and cannot itself respond to viewport width under static SSR (no circuit,
     * no JS state on this page — see the file's own header comment), so this is the only
     * lever available; the size wins over DsTypography's own rule because our scoped CSS is
     * bundled after the RCL's in the app's styles bundle at equal specificity (same
     * assumption .klubside__price already relies on above).
     *
     * TAKT-303: heading3, not heading2. One rung down from Display still left a 44px headline —
     * a size drawn for a laptop canvas. The seeded club's own sentence ("Vi danser west coast
     * swing. Hver onsdag og torsdag i Aarhus.") ran to SIX lines at 390px and pushed both hero
     * CTAs off the first screen, which on the one page whose whole job is a first impression is
     * the fold that matters most. Same lever, one rung further. */
    .klubside[b-jhlwn1esda]  .klubside__title {
        font-size: var(--ds-typography-heading3-font-size);
        line-height: var(--ds-typography-heading3-line-height);
    }

    /* TAKT-303 — and the five section headings step down with it. "Workshops & events" at
     * heading3 (36px) wrapped to two lines and read as loud as the hero it sits under; the page
     * had two competing display sizes on a 390px screen. One rung down keeps the section break
     * unmistakable at a size the column can hold on one line. `::deep` for the same reason as the
     * title above: DsTypography emits these h2s, `.klubside__section` is ours. */
    .klubside__section[b-jhlwn1esda]  h2 {
        font-size: var(--ds-typography-heading4-font-size);
        line-height: var(--ds-typography-heading4-line-height);
    }

    /* TAKT-303 — Praktisk's values read LEFT on a phone. The label column ("Undervisning") leaves
     * ~200px for a two-venue address, so every value wraps three or four times; right-aligned, each
     * of those lines starts at a different x and the block has no edge to read down. That is
     * DsDefinitionList's own `valueAlign` knob, set on our grid so it inherits into the card —
     * the component's seam, not a rule of ours competing with it.
     *
     * The better answer at this width is a STACKED row (label above value, both full-width).
     * The DS shipped that as DsDefinitionList Layout="stacked" (the 1.16 wave, from this
     * surface's own gap report) — but Layout is a static parameter, and this one list serves
     * both widths from the same markup, so a consumer cannot choose stacked below ~400px and
     * two-column above it. valueAlign stays as the best per-width move the vocabulary offers;
     * the responsive seam is asked for upstream on the same thread. (Set on .klubside__grid
     * above.) */

    /* The price stays PINNED to the title row at every width (mobile-audit L2 / S6). This rule
     * used to set `flex-wrap: wrap` here, which let the price drop under the name — but only
     * when the name happened to be long enough, so the alignment flipped from card to card down
     * the list and read as a rendering fault rather than a layout. The name+badge group already
     * wraps inside itself and carries `min-inline-size: 0`, which is what keeps a long class
     * name from squeezing the price rather than the price moving out of its way. Same shape as
     * the canonical story, which has no mobile override here at all. */
}

/* Followers (owner 2026-09-03 round 2) — the follow form: field + button on one line,
 * wrapping to stacked full-width on a phone. Round 3 moved it from a foot card into the
 * :target dialog below. */
.klubside__followform[b-jhlwn1esda] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ds-space-sm);
    align-items: center;
}

.klubside__followform[b-jhlwn1esda]  .klubside__followfield {
    flex: 1 1 16rem;
}

/* The signed-in one-click follow is a one-field form living INSIDE the hero's DsInline —
 * display:contents lets its button lay out as a plain sibling of the other CTAs instead of
 * the form introducing a box of its own into the row. */
.klubside__followinline[b-jhlwn1esda] {
    display: contents;
}

/* The follow state line under the hero CTAs (round 3): the ?fulgt= outcome and the
 * "already following" line live with the button that causes them, on the hero wash —
 * so they inherit the hero's re-pointed ink rather than carrying a colour of their own. */
.klubside__followstate[b-jhlwn1esda] {
    margin: 0;
    font: var(--ds-typography-caption);
}

/* The margin, not markup whitespace, separates the stop link from the sentence — Blazor
 * drops the bare text node between two razor blocks, so "opens.Stop following" it was. */
.klubside__followstate a[b-jhlwn1esda] {
    color: inherit;
    margin-inline-start: var(--ds-space-xs);
}

/* The follow dialog (owner 2026-09-03 round 3): "Følg klubben" is a hero button; a stranger's
 * click opens this small dialog to write an address. The page is static SSR by design, so the
 * dialog is the native HTML popover — popovertarget opens it, Escape/light-dismiss/the close
 * button hide it, ::backdrop is the scrim; no script, no circuit. (Not CSS :target: Blazor's
 * enhanced nav turns fragment clicks into pushState, which never re-evaluates :target.)
 * DsModal is circuit-only — a Static variant is filed as design-system#1263; this block is
 * modal anatomy under our own class names, built from the modal's own tokens, and it gets
 * DELETED on harvest. The UA popover rules already centre it (fixed, inset 0, margin auto). */
.klubside__followdialog[b-jhlwn1esda] {
    inline-size: min(28rem, calc(100% - 2 * var(--ds-space-lg)));
    background: var(--ds-modal-container);
    border: 0;
    border-radius: var(--ds-modal-containerRadius);
    padding: var(--ds-space-lg);
}

.klubside__followdialog[b-jhlwn1esda]::backdrop {
    background: var(--ds-modal-overlay);
}

/* The close affordance is a native popovertarget BUTTON (a link can't carry popover actions),
 * dressed down to the quiet text link the panel wants rather than a second call to action. */
.klubside__followdialog-close[b-jhlwn1esda] {
    align-self: flex-start;
    border: 0;
    padding: 0;
    background: none;
    cursor: pointer;
    font: var(--ds-typography-caption);
    color: var(--ds-color-onSurfaceSubtle);
    text-decoration: underline;
}
/* /Components/Takt/EnglishNameField.razor.rz.scp.css */
/* TAKT-215 — the translation field and its AI shortcut on one line, the button hugging its
   right. Both selectors anchor on elements this component literally renders, so the scoped-CSS
   attribute lands on them directly; the one ::deep reaches only the DS field's own root to let
   it fill the free space, and names no package class. */

.en-name-row[b-hf838nfnb1] {
    display: flex;
    align-items: flex-end;
    gap: var(--ds-space-xs);
    flex-wrap: wrap;
}

.en-name-input[b-hf838nfnb1] {
    flex: 1 1 12rem;
    min-width: 0;
}

.en-name-input[b-hf838nfnb1]  > * {
    width: 100%;
}
/* /Components/Takt/FormulaDisplay.razor.rz.scp.css */
/* FEAT-007b round 2 — LaTeX-look typesetting for the balance formula, pure CSS.
   Every colour/space is a --ds-* token; the bracket strokes stretch with the content
   (a fraction inside ⌊⌋ grows the brackets with it), which is what a glyph could not do. */

.formula[b-2k578bdkmt] {
    display: inline-flex;
    align-items: center;
    gap: 0.15em;
    font-size: var(--ds-typography-bodyLarge-font-size);
    line-height: 1.2;
}

/* Variables in the italic maths tradition; numbers and operators upright. */
.formula__var[b-2k578bdkmt] {
    font-style: italic;
}

.formula__fn[b-2k578bdkmt] {
    font-style: normal;
}

.formula__op[b-2k578bdkmt] {
    margin-inline: 0.25em;
}

/* The stacked fraction: numerator over a rule over the denominator, centred. */
.formula__frac[b-2k578bdkmt] {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    vertical-align: middle;
    margin-inline: 0.15em;
}

.formula__frac-num[b-2k578bdkmt] {
    display: inline-flex;
    align-items: center;
    padding-inline: 0.25em;
}

.formula__frac-den[b-2k578bdkmt] {
    display: inline-flex;
    align-items: center;
    padding-inline: 0.25em;
    border-block-start: var(--ds-space-hairline) solid currentColor;
}

/* Floor/ceil brackets drawn as strokes so they stretch with their content. */
.formula__group[b-2k578bdkmt] {
    display: inline-flex;
    align-items: center;
    align-self: stretch;
    margin-inline: 0.1em;
}

.formula__group[b-2k578bdkmt]::before,
.formula__group[b-2k578bdkmt]::after {
    content: "";
    align-self: stretch;
    inline-size: 0.3em;
}

.formula__group--floor[b-2k578bdkmt]::before {
    border-inline-start: var(--ds-space-hairline) solid currentColor;
    border-block-end: var(--ds-space-hairline) solid currentColor;
    margin-inline-end: 0.15em;
}

.formula__group--floor[b-2k578bdkmt]::after {
    border-inline-end: var(--ds-space-hairline) solid currentColor;
    border-block-end: var(--ds-space-hairline) solid currentColor;
    margin-inline-start: 0.15em;
}

.formula__group--ceil[b-2k578bdkmt]::before {
    border-inline-start: var(--ds-space-hairline) solid currentColor;
    border-block-start: var(--ds-space-hairline) solid currentColor;
    margin-inline-end: 0.15em;
}

.formula__group--ceil[b-2k578bdkmt]::after {
    border-inline-end: var(--ds-space-hairline) solid currentColor;
    border-block-start: var(--ds-space-hairline) solid currentColor;
    margin-inline-start: 0.15em;
}
/* /Components/Takt/SeasonPatternEditor.razor.rz.scp.css */
/* The weekly pattern's host. Tokens only — the grid itself is DsWeekPatternGrid and carries all
   of its own colour, spacing and type. */

.takt-pattern[b-vjlltybtpd] {
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-sm);
    min-width: 0;
}

/* Seven day columns do not fit a 430px phone — and they do not have to: DsWeekPatternGrid
   scrolls inside itself, over a column minimum that is a design token. Nothing here needs to
   re-state either half of that. `min-width: 0` is the only thing a flex column has to say, so
   the grid's intrinsic width cannot become this component's minimum and push the page sideways. */
