/* /Components/Layout/NavMenu.razor.rz.scp.css */
/* ── Navigation Menu ──────────────────────────────────────────
   Sidebar chrome: brand, the two switchers, the link list.
   docs/08-design-system-v2.md §3.4 (application frame), §2 (type scale)

   THE RAIL IS LIGHT NOW. Everything here used to be drawn on a near-black
   #0b1120 slab, which is the only reason --tm-primary-on-dark and a set of
   white-alpha overlays derived with color-mix ever existed. §3.4 makes the
   sidebar --tm-sidebar-bg (#FFFFFF), so all of that is gone: the rail is an
   ordinary surface and uses the ordinary ramp.

   Measured against --tm-sidebar-bg (#FFFFFF), which is what every rule below
   paints on:
     --tm-sidebar-item          6.18:1  ✔ AA — resting link label
     --tm-sidebar-item-active   8.20:1  ✔ AA — current page label
     --tm-sidebar-item-active on --tm-sidebar-item-active-bg   7.17:1  ✔ AA
     --tm-text-secondary        6.18:1  ✔ AA — switcher captions
     --tm-primary               5.91:1  ✔    — the brand mark
   The active tint itself is 1.14:1 against the rail, which is deliberate: the
   label's colour and weight carry "you are here", the fill only groups them.

   --tm-text-muted is NOT used anywhere in this file even for the small print.
   It measures 2.55:1 and tokens.css is explicit that it is decoration only.
   The signed-off mock-up sets the switcher captions in it; they are set in
   --tm-text-secondary here instead, which is the quietest token that is
   actually legible.

   SPECIFICITY, AND WHY THE CLASS IS REPEATED. NavMenu.razor renders
   `<div class="ui inverted vertical menu tm-nav-menu">` and this file may not
   change that markup, so Fomantic's whole inverted-menu theme still applies and
   still wants white-on-charcoal. Repeating `.tm-nav-menu` raises the class tier
   to match, and this stylesheet is linked after Fomantic, so a tie falls to us.
   That is what replaces !important nearly everywhere:

     .ui.inverted.menu .item              0,4,0  <  our 0,5,0
     .ui.inverted.menu a.item:hover       0,5,1  <  our 0,6,1
     .ui.vertical.menu>.item:first-child  0,5,0  =  our 0,5,0, we load later
     .ui.vertical.menu>.active.item:first-child 0,6,0 < our 0,6,1
     .ui.vertical.menu .item::before      0,4,1  <  our 0,5,1

   !important survives in exactly ONE declaration in this file, and it is named
   at the rule: Fomantic marks `.ui.inverted.menu .active.item { color: #fff
   !important }`, which no amount of specificity can beat. */

.tm-nav[b-pr0e84buze] {
    display: flex;
    flex-direction: column;
    height: 100%;
    position: relative;
}

/* ── Brand / Logo Area ────────────────────────────────────── */
.tm-nav-brand[b-pr0e84buze] {
    padding: var(--tm-space-4);
    border-bottom: 1px solid var(--tm-sidebar-border);
    position: relative;
}

/* The wordmark is the one place in the rail that carries --tm-text (18.32:1):
   it is a logotype, not a navigation label, and it anchors the top of the list. */
.tm-nav-brand a[b-pr0e84buze] {
    display: flex;
    align-items: center;
    color: var(--tm-text);
    font-size: var(--tm-text-md);
    line-height: var(--tm-leading-md);
    /* Semibold is the ceiling of the system (§2). */
    font-weight: var(--tm-weight-semibold);
    text-decoration: none;
    letter-spacing: -0.01em;
    transition: opacity var(--tm-transition);
}

.tm-nav-brand a:hover[b-pr0e84buze] {
    opacity: 0.9;
}

/* "Management", the second line of the wordmark. --tm-text-secondary rather
   than the mock-up's --ink-3: it is real text, so it owes AA (6.18:1). */
.tm-nav-brand small[b-pr0e84buze] {
    font-size: var(--tm-text-sm);
    line-height: var(--tm-leading-sm);
    font-weight: var(--tm-weight-normal);
    color: var(--tm-text-secondary);
}

/* The mark is the one accented glyph in the rail (§3.2 lists where the accent
   may appear). No gradient — §3.4 retires the clipped violet it used to carry. */
.tm-nav-brand i.icon[b-pr0e84buze] {
    font-size: var(--tm-text-lg);
    margin-right: var(--tm-space-3);
    color: var(--tm-primary);
}

/* ── Site / Group switchers ───────────────────────────────────
   Two containers styled identically; the controls inside them live in
   components/navigation.css. */
.tm-nav-site-switcher[b-pr0e84buze],
.tm-nav-group-switcher[b-pr0e84buze] {
    padding: var(--tm-space-3) var(--tm-space-4);
    border-bottom: 1px solid var(--tm-sidebar-border);
}

[b-pr0e84buze] .tm-site-switcher {
    width: 100%;
}

.tm-nav-site-label[b-pr0e84buze],
.tm-nav-group-label[b-pr0e84buze] {
    font-size: var(--tm-text-xs);
    line-height: var(--tm-leading-xs);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-weight: var(--tm-weight-medium);
    color: var(--tm-text-secondary);
    margin-bottom: var(--tm-space-2);
    display: flex;
    align-items: center;
    gap: var(--tm-space-1);
}

.tm-nav-site-label i.icon[b-pr0e84buze],
.tm-nav-group-label i.icon[b-pr0e84buze] {
    font-size: var(--tm-text-xs);
    margin: 0;
}

/* ── Navigation Menu ──────────────────────────────────────────
   Doubled to reach 3 classes, tying Fomantic's `.ui.vertical.menu` and
   `.ui.inverted.menu`; source order then falls to us. That is what replaces the
   five !important declarations this rule used to carry. It also outranks our own
   `.ui.menu:not(.attached)` radius rule in components/navigation.css.

   The horizontal padding is what makes the active row's rounded corners visible
   — §9 asks for the items to sit off the edge of the rail. */
.tm-nav-menu.tm-nav-menu[b-pr0e84buze] {
    flex: 1;
    margin: 0;
    border: none;
    border-radius: 0;
    width: 100%;
    background: transparent;
    box-shadow: none;
    overflow-y: auto;
    padding: var(--tm-space-2);
}

/* Resting item. Tripled to 5 classes so it beats `.ui.inverted.menu .item`
   (colour, 0,4,0) without !important and ties `.ui.vertical.menu>.item:first-child`
   (radius, 0,5,0), where loading later settles it.

   min-height --tm-control-height keeps nav rows, buttons and inputs on one
   height. --tm-text-md is the v2 default and §2 names navigation as one of its
   consumers — the old --tm-text-base would now render a step small. */
.tm-nav-menu.tm-nav-menu.tm-nav-menu[b-pr0e84buze]  .item {
    display: flex;
    align-items: center;
    gap: var(--tm-space-3);
    min-height: var(--tm-control-height);
    padding: var(--tm-space-2) var(--tm-space-3);
    margin: 0;
    border-radius: var(--tm-radius-sm);
    font-size: var(--tm-text-md);
    line-height: var(--tm-leading-md);
    font-weight: var(--tm-weight-normal);
    color: var(--tm-sidebar-item);
    letter-spacing: 0;
    transition: background var(--tm-transition), color var(--tm-transition);
    position: relative;
}

/* Fomantic draws a 1px divider across the top of every vertical-menu item
   (`.ui.vertical.menu .item::before`, 0,4,1, re-tinted by
   `.ui.vertical.inverted.menu .item::before`). Seventeen hairlines between
   rounded tinted rows is the 2015 admin-template look §3.4 is removing, and the
   mock-up has none. 0,5,1 beats both without !important.

   This is also where the old accent bar lived. §3.4 retires it: the tint plus
   the semibold label is the whole active state now, and ThemeTokenTests
   measures the geometry to make sure no tall narrow strip comes back. */
.tm-nav-menu.tm-nav-menu.tm-nav-menu[b-pr0e84buze]  .item::before {
    display: none;
}

/* Spacing between glyph and label comes from the item's flex `gap`, so
   Fomantic's `.ui.menu .item>i.icon` margin (0,4,1) has to go. Fixed width so
   the labels line up whether or not a row has an icon. */
.tm-nav-menu.tm-nav-menu.tm-nav-menu[b-pr0e84buze]  .item > i.icon {
    margin: 0;
    width: var(--tm-space-4);
    font-size: var(--tm-text-md);
    opacity: 0.75;
    transition: opacity var(--tm-transition);
}

/* ── Hover ────────────────────────────────────────────────────
   --tm-surface-2 is the same hover fill §5.2 gives every table row, so "the
   pointer is on this" means one thing across the application.
   0,6,1 beats Fomantic's `.ui.inverted.menu a.item:hover` (0,5,1), which is
   what lets both declarations drop their !important. */
.tm-nav-menu.tm-nav-menu.tm-nav-menu[b-pr0e84buze]  a.item:hover {
    background: var(--tm-surface-2);
    color: var(--tm-text);
}

.tm-nav-menu.tm-nav-menu.tm-nav-menu[b-pr0e84buze]  a.item:hover > i.icon {
    opacity: 1;
}

/* ── Active ───────────────────────────────────────────────────
   A quiet tint plus a saturated, semibold label (§3.4). Written after the hover
   rule on purpose: the two tie on nothing — this one is 0,6,1 like the hover
   rule — so source order decides, and hovering the current page must not make
   it look like an ordinary row.

   The one !important left in this file. Fomantic ships
   `.ui.inverted.menu .active.item { color: #fff !important }`, and !important
   is not a specificity contest — nothing but !important beats it. Background
   and radius need none: 0,6,1 already outranks `.ui.inverted.menu .active.item`
   (0,4,0) and `.ui.vertical.menu>.active.item:first-child` (0,6,0), the latter
   being what would otherwise flatten the Dashboard row's bottom corners. */
.tm-nav-menu.tm-nav-menu.tm-nav-menu[b-pr0e84buze]  a.item.active {
    background: var(--tm-sidebar-item-active-bg);
    color: var(--tm-sidebar-item-active) !important; /* beats .ui.inverted.menu .active.item{color:#fff!important} */
    font-weight: var(--tm-weight-semibold);
    border-radius: var(--tm-radius-sm);
}

/* The icon travels with the label. Nothing in Fomantic sets a colour on the
   glyph itself — it merely inherits — so this needs no help. ThemeTokenTests
   measures it against both the tint and the bare rail (7.17:1 / 8.20:1). */
.tm-nav-menu.tm-nav-menu.tm-nav-menu[b-pr0e84buze]  a.item.active > i.icon {
    opacity: 1;
    color: var(--tm-sidebar-item-active);
}

/* ── Section Headers ──────────────────────────────────────────
   "ADMINISTRATION" is the only grouping in a seventeen-item list, so it is
   drawn as a quiet separator rather than a heading: the smallest size in the
   scale and generous space above.

   0,6,0 because the resting-item rule above is 0,5,0 and would otherwise hand
   this <div> a 36px row and the link colour. */
.tm-nav-menu.tm-nav-menu.tm-nav-menu .header.item[b-pr0e84buze] {
    font-size: var(--tm-text-xs);
    line-height: var(--tm-leading-xs);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-weight: var(--tm-weight-medium);
    color: var(--tm-text-secondary);
    margin-top: var(--tm-space-4);
    padding: var(--tm-space-2) var(--tm-space-3) var(--tm-space-1);
    min-height: 0;
    border-radius: 0;
    cursor: default;
}

.tm-nav-menu.tm-nav-menu.tm-nav-menu .header.item i.icon[b-pr0e84buze] {
    font-size: var(--tm-text-xs);
    opacity: 1;
}

/* ── Divider ──────────────────────────────────────────────────
   Fomantic draws a divider as two stacked 1px borders; only the top one is
   wanted, so the bottom is cleared instead of being tinted to match. */
.tm-nav-menu .ui.divider[b-pr0e84buze] {
    margin: var(--tm-space-2) var(--tm-space-3);
    border-top-color: var(--tm-sidebar-border);
    border-bottom-color: transparent;
}
/* /Components/Layout/ReconnectModal.razor.rz.scp.css */
.components-reconnect-first-attempt-visible[b-5jc20yg7et],
.components-reconnect-repeated-attempt-visible[b-5jc20yg7et],
.components-reconnect-failed-visible[b-5jc20yg7et],
.components-pause-visible[b-5jc20yg7et],
.components-resume-failed-visible[b-5jc20yg7et],
.components-rejoining-animation[b-5jc20yg7et] {
    display: none;
}

#components-reconnect-modal.components-reconnect-show .components-reconnect-first-attempt-visible[b-5jc20yg7et],
#components-reconnect-modal.components-reconnect-show .components-rejoining-animation[b-5jc20yg7et],
#components-reconnect-modal.components-reconnect-paused .components-pause-visible[b-5jc20yg7et],
#components-reconnect-modal.components-reconnect-resume-failed .components-resume-failed-visible[b-5jc20yg7et],
#components-reconnect-modal.components-reconnect-retrying[b-5jc20yg7et],
#components-reconnect-modal.components-reconnect-retrying .components-reconnect-repeated-attempt-visible[b-5jc20yg7et],
#components-reconnect-modal.components-reconnect-retrying .components-rejoining-animation[b-5jc20yg7et],
#components-reconnect-modal.components-reconnect-failed[b-5jc20yg7et],
#components-reconnect-modal.components-reconnect-failed .components-reconnect-failed-visible[b-5jc20yg7et] {
    display: block;
}


/* docs/08-design-system-v2.md §4 (geometry, shadows), §6 (modal shape).
   --tm-radius-xl (16px) was retired along with the 12px+ "toy" end of the scale;
   --tm-radius-md is the shape of a dialog. The three-literal drop shadow becomes
   --tm-shadow-lg, which is the elevation every other overlay in the app uses.
   `width` stays a raw dimension: it is the dialog's measure, and the system has
   no token for one. */
#components-reconnect-modal[b-5jc20yg7et] {
    background-color: var(--tm-surface);
    color: var(--tm-text);
    width: 22rem;
    margin: 20vh auto;
    padding: var(--tm-space-6);
    border: 1px solid var(--tm-border);
    border-radius: var(--tm-radius-md);
    box-shadow: var(--tm-shadow-lg);
    font-size: var(--tm-text-md);
    line-height: var(--tm-leading-md);
    opacity: 0;
    transition: display 0.5s allow-discrete, overlay 0.5s allow-discrete;
    animation: components-reconnect-modal-fadeOutOpacity-b-5jc20yg7et 0.5s both;
    &[open]

{
    animation: components-reconnect-modal-slideUp-b-5jc20yg7et 1.5s cubic-bezier(.05, .89, .25, 1.02) 0.3s, components-reconnect-modal-fadeInOpacity-b-5jc20yg7et 0.5s ease-in-out 0.3s;
    animation-fill-mode: both;
}

}

/* The dimmer was a hardcoded slate at .5 alpha — the exact Tailwind pair §3.1
   names as "the shade every generic dashboard ships with". Mixed from --tm-text
   instead, so it stays in the palette's own hue family and follows the theme. */
#components-reconnect-modal[b-5jc20yg7et]::backdrop {
    background-color: color-mix(in srgb, var(--tm-text) 50%, transparent);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    animation: components-reconnect-modal-fadeInOpacity-b-5jc20yg7et 0.5s ease-in-out;
    opacity: 1;
}

@keyframes components-reconnect-modal-slideUp-b-5jc20yg7et {
    0% {
        transform: translateY(30px) scale(0.95);
    }

    100% {
        transform: translateY(0);
    }
}

@keyframes components-reconnect-modal-fadeInOpacity-b-5jc20yg7et {
    0% {
        opacity: 0;
    }

    100% {
        opacity: 1;
    }
}

@keyframes components-reconnect-modal-fadeOutOpacity-b-5jc20yg7et {
    0% {
        opacity: 1;
    }

    100% {
        opacity: 0;
    }
}

.components-reconnect-container[b-5jc20yg7et] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--tm-space-4);
}

#components-reconnect-modal p[b-5jc20yg7et] {
    margin: 0;
    text-align: center;
}

/* The Retry button is an ordinary primary button now (§5.1 / buttons.css): flat
   --tm-primary fill, --tm-radius-sm, --tm-control-height, semibold, no gradient,
   no coloured glow, no translateY hop on hover.

   What went: `linear-gradient(135deg, var(--tm-primary), #7c3aed)` — a violet
   second stop that never had a token at all, which is the worst form of the
   TM-35 defect, since no palette change could ever reach it. And a hardcoded
   `font-family: 'Inter'`, which §2 retires; the dialog now inherits
   --tm-font-sans from the document like everything else.

   Flattening the gradient is safe for ThemeTokenTests: its probe reads
   backgroundImage first and falls back to backgroundColor, precisely so the
   button may flatten. It asserts the leading colour equals --tm-primary
   (5.91:1 for a white label) and the hover equals --tm-primary-hover (8.20:1).

   The label was the literal `#fff`, on the note that there was no white token —
   --tm-surface is #FFFFFF only in the light theme and flips to a near-black in
   the dark one. TM-143 step 1 made the token: --tm-on-accent is #FFFFFF light, so
   this dialog is unchanged there, and #0D1116 dark, where white on the dark
   --tm-primary would have measured 2.9:1 and --tm-on-accent measures 6.49:1.
   Same token, and the same reasoning, as the solid confirm button in
   components/buttons.css.

   Custom properties inherit through the scoped-CSS attribute selector the same
   as anywhere else — the b-… attribute narrows which elements match, not where
   var() resolves from — so --tm-on-accent reaches here from :root unchanged. */
#components-reconnect-modal button[b-5jc20yg7et] {
    border: 1px solid var(--tm-primary);
    background: var(--tm-primary);
    color: var(--tm-on-accent);
    min-height: var(--tm-control-height);
    padding: 0 var(--tm-space-4);
    border-radius: var(--tm-radius-sm);
    font-family: inherit;
    font-size: var(--tm-text-sm);
    font-weight: var(--tm-weight-semibold);
    cursor: pointer;
    transition: background var(--tm-transition), border-color var(--tm-transition),
        box-shadow var(--tm-transition);
}

    #components-reconnect-modal button:hover[b-5jc20yg7et] {
        background: var(--tm-primary-hover);
        border-color: var(--tm-primary-hover);
    }

    /* §6: one focus treatment across the application. Never removed. */
    #components-reconnect-modal button:focus-visible[b-5jc20yg7et] {
        outline: none;
        box-shadow: 0 0 0 3px var(--tm-primary-light);
    }

.components-rejoining-animation[b-5jc20yg7et] {
    position: relative;
    width: 80px;
    height: 80px;
}

    .components-rejoining-animation div[b-5jc20yg7et] {
        position: absolute;
        border: 3px solid var(--tm-primary);
        opacity: 1;
        border-radius: 50%;
        animation: components-rejoining-animation-b-5jc20yg7et 1.5s cubic-bezier(0, 0.2, 0.8, 1) infinite;
    }

        .components-rejoining-animation div:nth-child(2)[b-5jc20yg7et] {
            animation-delay: -0.5s;
        }

@keyframes components-rejoining-animation-b-5jc20yg7et {
    0% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 0;
    }

    4.9% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 0;
    }

    5% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 1;
    }

    100% {
        top: 0px;
        left: 0px;
        width: 80px;
        height: 80px;
        opacity: 0;
    }
}
/* /Components/Layout/SiteSwitcher.razor.rz.scp.css */
/* ── Site Switcher ────────────────────────────────────────────
   The component is only ever rendered inside the sidebar (NavMenu.razor), so it
   is styled for the rail's ground — which since the v2 redesign is LIGHT in the
   light theme and dark only in the dark one, so anything here has to be written
   in --tm-sidebar-* tokens rather than assumed. Widths are fluid: the fixed 200px minimum
   this file used to declare overflowed the sidebar at the 220px
   --tm-sidebar-width the narrow-viewport breakpoint sets. */

.tm-site-switcher[b-x3vemmu1e7] {
    display: flex;
    align-items: center;
    width: 100%;
    min-width: 0;
}

/* Fomantic's own `.ui.selection.dropdown` carries `min-width: 14em`, which is
   what forced the control wider than its container; the sizing that matters is
   set once in components/navigation.css. */
.tm-site-switcher[b-x3vemmu1e7]  .ui.dropdown {
    width: 100%;
    min-width: 0;
}

.tm-site-switcher[b-x3vemmu1e7]  .ui.dropdown .menu {
    max-height: 300px;
    overflow-y: auto;
}

/* "No sites available" used to be painted rgba(0,0,0,.4) — near-black text on
   the near-black sidebar, effectively invisible. The E2E cover
   (SiteSwitcherLiveUpdateTests) asserts the element is *visible* in the layout
   sense, which it was, so nothing caught it.

   The first fix wrote `color-mix(in srgb, var(--tm-sidebar-item) 65%, transparent)`
   and this comment recorded 4.59:1 for it. THAT NUMBER WAS RIGHT — for a rail that
   no longer exists. It was measured when --tm-sidebar-item was white on the v1
   near-black rail, so 65% of it was white at .455 alpha over a dark ground. The v2
   redesign turned the light-theme rail white (--tm-sidebar-bg: #FFFFFF) and made
   --tm-sidebar-item the dark #59626E, so the identical declaration now mixes dark
   ink *towards white over white* — it lightens the text instead of darkening it,
   the exact opposite of what it was derived to do. Measured in Chromium: 2.87:1
   light, 3.83:1 dark, against a 4.5:1 requirement (13px, normal weight — this is
   not large text, so the 3:1 relaxation does not apply).

   So the alpha is gone rather than retuned. A transparent colour has no ratio of
   its own: it resolves against whatever is painted behind it, and this text has to
   clear AA over TWO different grounds — the white rail and the #151A21 one. One
   alpha cannot be correct for both, and the next time the rail changes colour the
   same silent drift happens again.

   --tm-sidebar-item at full strength is the token whose ratio against
   --tm-sidebar-bg is measured in tokens.css for both themes — 6.18:1 light,
   7.29:1 dark — because it is the colour the rail's own labels are painted in.
   The italic and the smaller size still tell the reader this is a placeholder
   rather than a site name; the colour no longer has to carry that on its own. */
.tm-no-sites[b-x3vemmu1e7] {
    color: var(--tm-sidebar-item);
    font-style: italic;
    font-size: var(--tm-text-base);
    line-height: var(--tm-leading-base);
}
/* /Components/Pages/Public/Signature.razor.rz.scp.css */
/* Anonymous signature page — scoped styles.
   docs/08-design-system-v2.md §6 (labels) / §3.1 (neutrals).

   Colours and typography now come from the token set; the literals that were
   here (#374151, #6b7280, #cbd5e1, #ffffff, 0.85rem) predate it. The pad's
   geometry is deliberately NOT tokenised — see the note on .tm-signature-pad. */

/* §6: a field label is --tm-text-sm / medium / --tm-text-secondary.
   6.18:1 on --tm-surface. */
.tm-signature-label[b-4z7h74fo95] {
    display: block;
    font-size: var(--tm-text-sm);
    line-height: var(--tm-leading-sm);
    font-weight: var(--tm-weight-medium);
    margin-bottom: var(--tm-space-2);
    color: var(--tm-text-secondary);
}

/* Declaration and item list (TM-77). Same rules as the in-app pad
   (Sessions/SignatureModal.razor.css) — CSS isolation means they cannot be shared, so the two
   are kept looking alike deliberately: the same declaration should not read differently
   depending on which screen a person happened to sign on. */

/* The declaration is the thing being agreed to, so it is body text, not a caption. */
.tm-signature-declaration[b-4z7h74fo95] {
    margin: 0 0 var(--tm-space-3);
    font-size: var(--tm-text-md);
    line-height: var(--tm-leading-md);
    color: var(--tm-text);
}

.tm-signature-items[b-4z7h74fo95] {
    margin: 0 0 var(--tm-space-4);
    padding-left: var(--tm-space-5);
    /* Long agendas scroll inside the list rather than pushing the pad off a phone screen. */
    max-height: 11rem;
    overflow-y: auto;
}

.tm-signature-items li[b-4z7h74fo95] {
    margin-bottom: var(--tm-space-1);
    line-height: var(--tm-leading-md);
}

.tm-signature-items-empty[b-4z7h74fo95] {
    margin: 0 0 var(--tm-space-4);
    color: var(--tm-text-secondary);
    font-style: italic;
}

.tm-signature-note[b-4z7h74fo95] {
    margin: 0;
    color: var(--tm-text-secondary);
    font-size: var(--tm-text-sm);
    line-height: var(--tm-leading-sm);
}

/* The pad itself.

   GEOMETRY IS INTENTIONALLY UNCHANGED. The 200px height is the drawing area:
   signature-pad.js sizes the canvas from this box and the captured strokes are
   stored in its coordinate space, so altering the height would change what
   gets recorded, not just how it looks. Only the colours moved to tokens.

   The dashed edge stays — it is the affordance that says "draw here", and it
   is the one thing on this page a person has to identify before interacting
   with it. --tm-border-strong is the §3.1 value chosen precisely so a control
   edge clears WCAG 1.4.11 at 3.11:1. */
.tm-signature-pad[b-4z7h74fo95] {
    border: 2px dashed var(--tm-border-strong);
    border-radius: var(--tm-radius-sm);
    background: var(--tm-surface);
    height: 200px;
    overflow: hidden;
}

.tm-signature-canvas[b-4z7h74fo95] {
    display: block;
    width: 100%;
    height: 100%;
    cursor: crosshair;
    /* Prevent the browser from scrolling/zooming while drawing on touch devices. */
    touch-action: none;
}

.tm-signature-actions[b-4z7h74fo95] {
    margin-top: var(--tm-space-2);
    margin-bottom: var(--tm-space-4);
    text-align: right;
}
/* /Components/Pages/Sessions/AttendanceChecklist.razor.rz.scp.css */
/* TM-62 — the attendance sheet on its narrow shape: requirements down the page instead of
   across it. The point of the layout is that nothing ever scrolls sideways, so every rule
   here is about keeping the two columns inside the page width. */

.tm-attendance-checklist[b-0kvc2l64ub] {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
    /* Belt and braces against the very thing this layout exists to remove. */
    max-width: 100%;
}

.tm-checklist-person[b-0kvc2l64ub] {
    border: 1px solid var(--tm-border);
    border-radius: var(--tm-radius-md);
    padding: 0.85rem 1rem 1rem;
}

.tm-checklist-person-header[b-0kvc2l64ub] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin-bottom: 0.85rem;
}

.tm-checklist-person-identity strong[b-0kvc2l64ub] {
    font-size: var(--tm-text-lg);
    line-height: var(--tm-leading-lg);
    font-weight: var(--tm-weight-semibold);
}

.tm-checklist-person-attendance[b-0kvc2l64ub],
.tm-checklist-signature[b-0kvc2l64ub] {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.tm-checklist-signature[b-0kvc2l64ub] {
    flex-wrap: wrap;
    margin-top: 0.85rem;
    padding-top: 0.75rem;
    border-top: 1px solid var(--tm-border-light);
}

.tm-checklist-field-label[b-0kvc2l64ub] {
    font-weight: var(--tm-weight-medium);
    color: var(--tm-text-secondary);
}

/* Was #888 — 2.9:1, under the AA floor, and this line carries the personal number,
   which is data rather than decoration. --tm-text-secondary is 6.18:1. */
.tm-checklist-subtext[b-0kvc2l64ub] {
    font-size: var(--tm-text-sm);
    line-height: var(--tm-leading-sm);
    color: var(--tm-text-secondary);
}

.tm-checklist-table[b-0kvc2l64ub] {
    width: 100%;
    /* Fixed layout so a long requirement name wraps instead of widening the table. */
    table-layout: fixed;
}

/* The result column holds one glyph; everything left over belongs to the name. */
.tm-checklist-result-heading[b-0kvc2l64ub],
.tm-checklist-result-cell[b-0kvc2l64ub] {
    width: 7rem;
    white-space: nowrap;
}

.tm-checklist-requirement-cell[b-0kvc2l64ub] {
    /* Long, unbroken document codes must break rather than push the table wider. */
    overflow-wrap: anywhere;
}

/* Phone: the two columns still fit, so unlike the matrix (TM-58) this table is not stacked
   into cards — it only gives the name more of the width. */
@media only screen and (max-width: 700px) {
    .tm-checklist-result-heading[b-0kvc2l64ub],
    .tm-checklist-result-cell[b-0kvc2l64ub] {
        width: 4.5rem;
    }

    .tm-checklist-person[b-0kvc2l64ub] {
        padding: 0.6rem 0.7rem 0.75rem;
    }
}
/* /Components/Pages/Sessions/AttendanceMatrixCell.razor.rz.scp.css */
/* TM-60 — one cell of the attendance matrix: the frame says how much the requirement
   applies to this person, the glyph says where they stand, and everything editable is
   one click away in a popover. Nothing is rendered twice. */

/* TM-98 shrank the cell from 2.6 × 2rem to a 1.75rem square. The sheet grows a column per
   agenda requirement, so every millimetre here is paid for once per requirement per row; at
   the old size a five-requirement sheet already spent more width on padding than on glyphs.
   Nothing about what the cell *says* changed — only how much room it takes to say it. */
.tm-matrix-cell[b-fublk5n5of] {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;
    padding: 0;
    border-radius: var(--tm-radius-sm);
}

/* ── The frame is the relevance ────────────────────────────────────────────────
   Mandatory reads as a firm box, recommended as a tentative one, and something that
   does not apply to this person has no box at all — the eye can skip it.

   The frame is a non-text graphic carrying meaning by itself, so WCAG 1.4.11 puts a
   3:1 floor under it — and the old pair missed it at the quiet end (#9ca3af measures
   2.55:1 on white). Mandatory takes --tm-text-secondary at 6.18:1, which is also the
   right way round: the firm box should be the darker one. Recommended takes
   --tm-border-strong at 3.11:1, the lightest edge the criterion allows. The two now
   differ in weight as well as in solid-versus-dashed, so neither the distinction nor
   the floor rests on the other. */
.tm-matrix-cell--mandatory[b-fublk5n5of] {
    border: 1.5px solid var(--tm-text-secondary);
}

.tm-matrix-cell--recommended[b-fublk5n5of] {
    border: 1.5px dashed var(--tm-border-strong);
    background: var(--tm-border-light);
}

.tm-matrix-cell--not-relevant[b-fublk5n5of] {
    border: 1.5px solid transparent;
    background: var(--tm-surface-2);
}

/* A closed session shows no relevance at all, so the cell wears no frame either. */
.tm-matrix-cell--plain[b-fublk5n5of] {
    border: none;
    padding: 0;
}

/* TM-112 — settled by a signature. Deliberately not the quiet dash of TM-95: that says "nobody
   has to decide this", and this says "this was decided and is now attested to". The result
   stays exactly as legible as it was; only the cursor and the faint tint say it is done being
   argued with. Anything louder would put a warning on the normal, correct end state of a row. */
.tm-matrix-cell--signed[b-fublk5n5of] {
    background: var(--tm-surface-2);
    cursor: default;
}

/* The result label fills the frame instead of sitting in it (TM-98). SemLabel renders its
   own element, which never inherits this file's scope — hence ::deep. The colours come from
   the shared label rules in components/feedback.css, where each result tint is measured
   against its own foreground; this file owns the geometry only.

   0.72rem is NOT a step of the type scale and deliberately does not take a token. It is the
   size at which a glyph fits a 1.25rem box, i.e. a consequence of the box, and the box is
   what keeps a twenty-requirement sheet from scrolling sideways. Tying it to --tm-text-sm
   would let a change in the reading scale silently resize the matrix. TM.Web.styles.css is
   linked after feedback.css, so this rule wins the specificity tie against .ui.mini.label
   and the box holds. */
.tm-matrix-cell[b-fublk5n5of]  .ui.label {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.25rem;
    height: 1.25rem;
    min-width: 0;
    min-height: 0;
    margin: 0;
    padding: 0;
    border-radius: var(--tm-radius-sm);
    font-size: 0.72rem;
    line-height: 1;
}

/* The glyph is the label's only content here — there is no word after it, because a matrix
   cell has a column header instead of a legend. Its trailing margin therefore has nothing to
   separate it from and only pushes it off the centre of the box. Zeroing it re-centres the
   mark and gives the larger v2 glyph (pages/sessions.css) the room it needs. */
.tm-matrix-cell[b-fublk5n5of]  .attendance-result-glyph {
    margin-right: 0;
}

.tm-cell-trigger[b-fublk5n5of] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: none;
    background: none;
    cursor: pointer;
    font: inherit;
    color: inherit;
}

/* One focus treatment for the whole application (§6): the accent, never a second colour. */
.tm-cell-trigger:focus-visible[b-fublk5n5of] {
    outline: 2px solid var(--tm-primary);
    outline-offset: 2px;
    border-radius: var(--tm-radius-sm);
}

/* The resting face of a cell nobody has to do anything about. Grey enough to recede, dark
   enough to stay legible — --tm-text-secondary is 6.18:1 on --tm-surface. It is not
   --tm-text-muted: that token is for decoration sitting beside a label that already carries
   the meaning, and here the dash IS the meaning. */
.tm-cell-blank[b-fublk5n5of] {
    color: var(--tm-text-secondary);
    font-weight: var(--tm-weight-semibold);
}

/* ── Popover ──────────────────────────────────────────────────────────────────── */

.tm-cell-backdrop[b-fublk5n5of] {
    position: fixed;
    inset: 0;
    z-index: 90;
}

.tm-cell-popover[b-fublk5n5of] {
    position: absolute;
    top: calc(100% + 4px);
    left: 50%;
    transform: translateX(-50%);
    z-index: 100;
    min-width: 12rem;
    padding: var(--tm-space-2);
    text-align: left;
    white-space: normal;
    background: var(--tm-surface);
    border: 1px solid var(--tm-border);
    border-radius: var(--tm-radius-md);
    box-shadow: var(--tm-shadow-lg);
}

/* TM-93 — the same panel once cell-popover.js has promoted it into the top layer.
   The browser's own popover styling assumes a centred, self-sized dialog (inset: 0 with
   auto margins, its own border and padding), so all of that is taken back: the script
   supplies `left`/`top` in viewport coordinates and the panel keeps the look it has in
   flow. Without the promotion — an old browser, or the phone card layout — the rules
   above still stand on their own and nothing regresses beyond the old clipping. */
.tm-cell-popover[popover][b-fublk5n5of] {
    position: fixed;
    inset: auto;
    margin: 0;
    transform: none;
    max-width: min(22rem, calc(100vw - 1rem));
    max-height: calc(100vh - 1rem);
    overflow: auto;
    padding: var(--tm-space-2);
    border: 1px solid var(--tm-border);
    color: inherit;
}

.tm-cell-popover-heading[b-fublk5n5of] {
    font-size: var(--tm-text-sm);
    line-height: var(--tm-leading-sm);
    font-weight: var(--tm-weight-semibold);
    color: var(--tm-text-secondary);
    margin: 0.25rem 0 0.3rem;
}

.tm-cell-popover-note[b-fublk5n5of] {
    margin: 0.25rem 0 0.4rem;
    font-size: var(--tm-text-base);
    line-height: var(--tm-leading-base);
    color: var(--tm-text-secondary);
}

.tm-cell-popover-options[b-fublk5n5of] {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    margin-bottom: 0.35rem;
}

.tm-cell-option[b-fublk5n5of] {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    width: 100%;
    padding: 0.3rem 0.45rem;
    border: none;
    border-radius: var(--tm-radius-sm);
    background: none;
    font: inherit;
    font-size: var(--tm-text-md);
    color: var(--tm-text);
    text-align: left;
    cursor: pointer;
}

.tm-cell-option:hover[b-fublk5n5of],
.tm-cell-option:focus-visible[b-fublk5n5of] {
    background: var(--tm-surface-2);
}

/* The selected option is a selected state, which §3.2 lists as the accent's job.
   --tm-primary-hover on --tm-primary-light measures 7.17:1. The weight change is kept
   alongside the tint so the current choice is not signalled by colour alone (1.4.1). */
.tm-cell-option.is-current[b-fublk5n5of] {
    background: var(--tm-primary-light);
    color: var(--tm-primary-hover);
    font-weight: var(--tm-weight-semibold);
}

.tm-cell-option-glyph[b-fublk5n5of] {
    display: inline-block;
    width: 1rem;
    text-align: center;
    font-weight: var(--tm-weight-semibold);
}

/* ── Phone ─────────────────────────────────────────────────────────────────────
   The matrix collapses into cards under 700px (TM-58) and each card clips its own
   overflow for the rounded corners, so an absolutely positioned popover would be cut
   off. There it expands the card instead of floating above it. */
@media only screen and (max-width: 700px) {
    .tm-matrix-cell[b-fublk5n5of] {
        flex-direction: column;
        align-items: flex-end;
    }

    /* cell-popover.js leaves the panel alone below this width, so it never carries the
       `popover` attribute here and these rules are the only ones positioning it. */
    .tm-cell-popover[b-fublk5n5of] {
        position: static;
        transform: none;
        margin-top: 0.4rem;
        min-width: 0;
        width: 100%;
        box-shadow: none;
    }

    .tm-cell-backdrop[b-fublk5n5of] {
        display: none;
    }
}
/* /Components/Pages/Sessions/Create.razor.rz.scp.css */
/* Hint shown next to a start date that lies in the past (TM-27).
   Deliberately not a SemMessage: Fomantic hides `.ui.form .warning.message`
   until its own JS switches the form into that state, which this app never does. */
.tm-past-date-hint[b-9vc3r72xpz] {
    margin-top: 0.4rem;
    padding: var(--tm-space-2) var(--tm-space-3);
    border-left: 3px solid var(--tm-warning);
    border-radius: 0 var(--tm-radius-sm) var(--tm-radius-sm) 0;
    background: var(--tm-warning-light);
    color: var(--tm-text-secondary);
    font-size: var(--tm-text-sm);
    line-height: var(--tm-leading-sm);
}

.tm-past-date-hint i.icon[b-9vc3r72xpz] {
    margin-right: 0.35rem;
    color: var(--tm-warning);
}

/* An untouched form must look neutral (TM-28). Hiding the messages is not enough:
   SemFormField puts `error` on the field straight from the validation state, and
   SemanticBlazor dropdowns validate their field while Fomantic initialises them.
   So the field keeps the class, and the colours are undone here until the first
   submit switches the form out of `is-pristine`. */
.tm-session-form.is-pristine[b-9vc3r72xpz]  .field.error > label,
.tm-session-form.is-pristine[b-9vc3r72xpz]  .field.error .input {
    color: inherit;
}

.tm-session-form.is-pristine[b-9vc3r72xpz]  .field.error input,
.tm-session-form.is-pristine[b-9vc3r72xpz]  .field.error textarea,
.tm-session-form.is-pristine[b-9vc3r72xpz]  .field.error select {
    background: var(--tm-surface);
    border-color: var(--tm-border);
    color: var(--tm-text);
}

.tm-session-form.is-pristine[b-9vc3r72xpz]  .field.error .ui.dropdown,
.tm-session-form.is-pristine[b-9vc3r72xpz]  .field.error .ui.dropdown .text {
    background: var(--tm-surface);
    color: var(--tm-text);
}

.tm-session-form.is-pristine[b-9vc3r72xpz]  .field.error .ui.dropdown,
.tm-session-form.is-pristine[b-9vc3r72xpz]  .field.error .ui.dropdown:hover {
    border-color: var(--tm-border) !important;
}

/* The error belongs to the field, not to the values it offers: Fomantic paints the
   whole menu red once the field is in the error state (TM-28). The red border and
   the red text of the closed control carry the message on their own. */
.tm-session-form[b-9vc3r72xpz]  .field.error .ui.dropdown .menu > .item {
    background: var(--tm-surface);
    color: var(--tm-text);
}
/* /Components/Pages/Sessions/Detail.razor.rz.scp.css */
/* TM-17 — merged attendance sheet (matrix + toolbar + evidence + "what's missing" panel).
   Scoped to Detail.razor, so the Fomantic globals stay untouched. */

.tm-sheet-toolbar[b-qs8m3aw39h] {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
    margin-bottom: 1rem;
}

/* The matrix can be wider than the page (one column per agenda requirement); it scrolls
   inside its own box instead of pushing the page sideways.
   A box that scrolls on one axis clips the other, so this box clips vertically as well as
   it scrolls horizontally. TM-60 accepted that and let a cell popover opened on the bottom
   row extend the scrollable area instead of escaping it; in practice it read as broken UI
   and part of the menu disappeared under the signature cards. Since TM-93 the popovers are
   promoted into the browser's top layer by wwwroot/js/cell-popover.js, which is outside
   every overflow on the page — so nothing here has to give the popovers room any more. */
.tm-sheet-scroll[b-qs8m3aw39h] {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

.tm-attendance-matrix[b-qs8m3aw39h] {
    min-width: 100%;
}

.tm-sheet-subtext[b-qs8m3aw39h] {
    font-size: var(--tm-text-sm);
    line-height: var(--tm-leading-sm);
    color: var(--tm-text-secondary);
}

.tm-sheet-result-cell[b-qs8m3aw39h] {
    white-space: nowrap;
}

/* TM-98/TM-113: the signature column has a fixed width, and everything in it is sized to fit
   that width on one line — a signed row must not be taller than an unsigned one. */
.tm-sheet-signature-face[b-qs8m3aw39h] {
    display: flex;
    align-items: center;
    flex-wrap: nowrap;
    gap: 0.3rem;
}

.tm-sheet-signed[b-qs8m3aw39h] {
    display: inline-flex;
    align-items: center;
    gap: 0.1rem;
    white-space: nowrap;
    font-weight: var(--tm-weight-semibold);
}

/* Fomantic paints `i.green.icon` #21BA45 with its own !important — a 2.35:1 green out of
   its 2014 palette that matches nothing else in v2. These are the two places the sheet
   uses it and both mean the same thing, "this is signed", so both take --tm-success.
   !important is the only thing that gets past Fomantic's !important; it is confined to
   this sheet rather than being a global colour override. The icon is decorative either
   way (aria-hidden, or beside a word that already says "Signed"), so nothing rests on it. */
.tm-sheet-signed i.icon[b-qs8m3aw39h],
.tm-sheet-role-signature i.check.circle.icon[b-qs8m3aw39h] {
    color: var(--tm-success) !important;
}

/* Was three copies of an inline `style="margin-left: .5rem; color: #888"` in the Lifecycle
   tab — a colour in no palette, measuring 2.9:1, on the sentence that explains what each
   irreversible transition will do. --tm-text-secondary is 6.18:1. */
.tm-lifecycle-hint[b-qs8m3aw39h] {
    margin-left: var(--tm-space-2);
    color: var(--tm-text-secondary);
    font-size: var(--tm-text-base);
    line-height: var(--tm-leading-base);
}


/* The result cell no longer holds a control of its own (TM-60) — it is a frame, a glyph
   and a popover, all owned by AttendanceMatrixCell. */
.tm-sheet-signature-cell select[b-qs8m3aw39h] {
    margin-top: 0.35rem;
}

/* Pushes the overflow trigger to the far end of the toolbar (TM-98), so the two buttons that
   are always there stay together on the left and the ⋮ is always in the same corner. */
.tm-sheet-toolbar-spacer[b-qs8m3aw39h] {
    flex: 1 1 auto;
}

/* ── The progress strip (TM-98) ─────────────────────────────────────────────────
   Replaces the "mark rest N/A" message box. It is a status line, not a control: quiet
   surface, no border, and nothing in it is clickable. */
.tm-sheet-progress[b-qs8m3aw39h] {
    margin-bottom: var(--tm-space-4);
    padding: 0.55rem 0.85rem;
    background: var(--tm-surface-2);
    border-radius: var(--tm-radius-md);
}

.tm-sheet-progress-line[b-qs8m3aw39h] {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    flex-wrap: wrap;
    gap: var(--tm-space-2);
    font-size: var(--tm-text-sm);
    line-height: var(--tm-leading-sm);
    color: var(--tm-text-secondary);
    margin-bottom: 0.4rem;
}

.tm-sheet-progress-pending[b-qs8m3aw39h] {
    color: var(--tm-text);
    font-weight: var(--tm-weight-semibold);
}

.tm-sheet-progress-track[b-qs8m3aw39h] {
    height: 4px;
    border-radius: 2px;
    background: var(--tm-border);
    overflow: hidden;
}

.tm-sheet-progress-bar[b-qs8m3aw39h] {
    height: 100%;
    background: var(--tm-primary);
    transition: width 0.2s ease;
}

/* ── Column geometry (TM-98) ────────────────────────────────────────────────────
   The left-hand block — actions, name, signature, attendance — has a fixed width; only the
   requirement columns multiply. Keeping the fixed part fixed is the whole point of having
   moved the signature off the right-hand end. */
.tm-sheet-menu-heading[b-qs8m3aw39h],
.tm-sheet-menu-cell[b-qs8m3aw39h] {
    width: 2.25rem;
    padding-left: 0.35rem !important;
    padding-right: 0.35rem !important;
    text-align: center;
}

/* Time and ⋮ on one line (TM-113). TM-115 took the seal badge out of the cell, so the 4rem it
   was costing goes back to the requirement columns. */
.tm-sheet-signature-heading[b-qs8m3aw39h] {
    width: 7rem;
}

.tm-sheet-attendance-heading[b-qs8m3aw39h] {
    width: 7rem;
}

/* A heading turned on its side, so a column is as wide as the glyph it holds rather than as
   wide as a course name. `vertical-rl` + a half turn puts the text bottom-up, which is the
   direction a reader tilts their head for. */
.tm-sheet-requirement-heading[b-qs8m3aw39h] {
    width: 2.5rem;
    vertical-align: bottom !important;
    padding: 0.4rem 0.15rem !important;
}

/* Capped, because the header row is as tall as the longest name in it and that cost is paid
   whether the sheet has ten requirement columns or two. Past this the name ellipsises; the
   whole of it is on the `title` and in the accessible name either way.

   Set generously on purpose. A tighter cap buys perhaps 30px of height and costs the reader
   the end of every name — and two requirements from the same family ("Fire Safety Training",
   "Fire Safety Refresher") truncate to the same prefix, on a sheet where ticking the wrong
   column is the mistake that matters. Height is the cheaper thing to spend. */
.tm-sheet-requirement-heading-text[b-qs8m3aw39h] {
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    margin: 0 auto;
    max-height: 10rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--tm-text-sm);
    font-weight: var(--tm-weight-semibold);
    color: var(--tm-text-secondary);
}

.tm-sheet-result-cell[b-qs8m3aw39h] {
    padding-left: 0.15rem !important;
    padding-right: 0.15rem !important;
    text-align: center;
}

/* A thin rule on both sides of the attendance column, so "was this person here" reads as its
   own thing and not as the first of the requirements. */
.tm-sheet-attendance-heading[b-qs8m3aw39h],
.tm-attendance-matrix tbody td[data-label="Attendance"][b-qs8m3aw39h] {
    border-left: 1px solid var(--tm-border);
    border-right: 1px solid var(--tm-border);
}

/* Trainer / translator signatures sit below the matrix, side by side on a wide screen. */
.tm-sheet-role-signatures[b-qs8m3aw39h] {
    display: flex;
    flex-wrap: wrap;
    gap: 1.5rem;
    margin-top: 1.25rem;
}

.tm-sheet-role-signature[b-qs8m3aw39h] {
    flex: 1 1 260px;
    min-width: 240px;
    padding: 0.85rem 1rem;
    border: 1px solid var(--tm-border);
    border-radius: var(--tm-radius-md);
    background: var(--tm-surface-2);
}



/* ── Scanned attendance lists (TM-47, restyled) ─────────────────────────────────
   A file list, not a form: each scan is one row — type glyph, name, size and date —
   with its actions outlined rather than solid, so the file name stays the loudest
   thing in the row. The upload is a drop tile; the browser's native
   "Choose File / no file selected" chrome is covered by it, not shown beside it. */
.tm-sheet-scans[b-qs8m3aw39h] {
    margin-top: 1.25rem;
    padding: 1rem 1.1rem 1.1rem;
    border: 1px solid var(--tm-border);
    border-radius: var(--tm-radius-md);
}

.tm-scans-header[b-qs8m3aw39h] {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
}

.tm-scans-header .ui.header[b-qs8m3aw39h] {
    margin: 0;
}

.tm-scans-count[b-qs8m3aw39h] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.35rem;
    height: 1.35rem;
    padding: 0 0.4rem;
    border-radius: 999px;
    background: var(--tm-surface-2);
    color: var(--tm-text-secondary);
    font-size: var(--tm-text-sm);
    font-weight: var(--tm-weight-semibold);
    font-variant-numeric: tabular-nums;
}

.tm-scans-empty[b-qs8m3aw39h] {
    display: flex;
    align-items: center;
    gap: var(--tm-space-2);
    margin: 0;
    color: var(--tm-text-secondary);
    font-size: var(--tm-text-md);
}

.tm-scans-list[b-qs8m3aw39h] {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.tm-scan[b-qs8m3aw39h] {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.6rem 0.75rem;
    border: 1px solid var(--tm-border-light);
    border-radius: var(--tm-radius-md);
    background: var(--tm-surface);
    transition: border-color var(--tm-transition), background var(--tm-transition);
}

.tm-scan:hover[b-qs8m3aw39h] {
    border-color: var(--tm-border);
    background: var(--tm-surface-2);
}

.tm-scan-thumb[b-qs8m3aw39h] {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 2.25rem;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: var(--tm-radius-sm);
    background: var(--tm-surface-2);
    color: var(--tm-text-secondary);
}

.tm-scan-thumb i.icon[b-qs8m3aw39h] {
    margin: 0;
    font-size: 1.05rem;
}

/* min-width:0 is what lets the name ellipsise instead of stretching the row. */
.tm-scan-body[b-qs8m3aw39h] {
    display: flex;
    flex-direction: column;
    min-width: 0;
    flex: 1 1 auto;
    gap: 0.1rem;
}

.tm-scan-name[b-qs8m3aw39h] {
    font-weight: var(--tm-weight-semibold);
    color: var(--tm-text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.tm-scan-meta[b-qs8m3aw39h] {
    font-size: var(--tm-text-sm);
    line-height: var(--tm-leading-sm);
    color: var(--tm-text-secondary);
}

.tm-scan-actions[b-qs8m3aw39h] {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    flex: 0 0 auto;
}

.tm-scan-actions .ui.button[b-qs8m3aw39h] {
    margin: 0;
}

.tm-scan-drop[b-qs8m3aw39h] {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-top: 0.85rem;
    padding: 0.8rem 1rem;
    border: 1px dashed var(--tm-border-strong);
    border-radius: var(--tm-radius-md);
    background: var(--tm-surface-2);
    cursor: pointer;
    transition: border-color var(--tm-transition), background var(--tm-transition);
}

/* The tile is a drop target, so its live state is the accent — the same role
   --tm-primary carries on a focus ring (§3.2), not decoration. */
.tm-scan-drop:hover[b-qs8m3aw39h],
.tm-scan-drop.tm-drop-over[b-qs8m3aw39h] {
    border-color: var(--tm-primary);
    background: var(--tm-primary-light);
}

/* Set by js/scan-drop.js while a file is over the tile. */
.tm-scan-drop.tm-drop-over[b-qs8m3aw39h] {
    border-style: solid;
}

.tm-scan-drop > i.icon[b-qs8m3aw39h] {
    margin: 0;
    font-size: 1.35rem;
    color: var(--tm-primary);
}

.tm-scan-drop-text[b-qs8m3aw39h] {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    line-height: 1.25;
}

.tm-scan-drop-text strong[b-qs8m3aw39h] {
    color: var(--tm-primary);
    font-weight: var(--tm-weight-semibold);
}

.tm-scan-drop-hint[b-qs8m3aw39h] {
    font-size: var(--tm-text-sm);
    line-height: var(--tm-leading-sm);
    color: var(--tm-text-secondary);
}

/* Stretched over the tile, so the whole tile is the click target while the browser's own
   "Choose File / no file selected" chrome stays out of the layout.

   ::deep is not optional here (TM-136): InputFile is a component, and scoped CSS stamps its
   attribute only on elements written in this .razor file — never on markup a child component
   renders. Without it the rule matched nothing and the native chrome sat in the tile. */
.tm-scan-drop[b-qs8m3aw39h]  .tm-sheet-upload-input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
}

.tm-sheet-missing[b-qs8m3aw39h] {
    margin-top: 1.25rem;
}

/* Online signature-link status pill (TM-23). */
.tm-token-status[b-qs8m3aw39h] {
    font-weight: var(--tm-weight-semibold);
}

.tm-token-status[data-token-status="signed"][b-qs8m3aw39h] {
    color: var(--tm-success);
}

.tm-token-status[data-token-status="expired"][b-qs8m3aw39h] {
    color: var(--tm-danger);
}

.tm-token-status[data-token-status="pending"][b-qs8m3aw39h] {
    color: var(--tm-warning);
}

.tm-token-status[data-token-status="none"][b-qs8m3aw39h] {
    color: var(--tm-text-secondary);
}

.tm-sheet-token-actions[b-qs8m3aw39h] {
    display: flex;
    gap: 0.35rem;
    margin-top: 0.35rem;
}

/* ── Phone: the matrix becomes a stack of cards ─────────────────────────────
   The prezenční listina is the one screen a trainer opens on a phone in the room,
   so under 700px each row turns into a card with the column name as a label.

   The table carries the `unstackable` class (TM-58) so Fomantic's own phone
   stacking is off and these rules are the only ones stacking it. The !important
   below is belt-and-braces: Fomantic's stacking rules are !important themselves,
   so without it the header would come back as an empty "ghost" card the moment
   `unstackable` was ever dropped from the markup. */
@media only screen and (max-width: 700px) {
    .tm-attendance-matrix.ui.table thead[b-qs8m3aw39h] {
        display: none !important;
    }

    .tm-attendance-matrix.ui.table[b-qs8m3aw39h],
    .tm-attendance-matrix.ui.table tbody[b-qs8m3aw39h],
    .tm-attendance-matrix.ui.table tr[b-qs8m3aw39h],
    .tm-attendance-matrix.ui.table td[b-qs8m3aw39h] {
        display: block !important;
        width: auto !important;
    }

    .tm-attendance-matrix.ui.table tr[b-qs8m3aw39h] {
        margin-bottom: 0.9rem;
        border: 1px solid var(--tm-border);
        border-radius: var(--tm-radius-md);
        overflow: hidden;
    }

    .tm-attendance-matrix.ui.table td[b-qs8m3aw39h] {
        display: flex !important;
        justify-content: space-between;
        align-items: center;
        gap: 0.75rem;
        text-align: right;
        border: none !important;
        border-bottom: 1px solid var(--tm-border-light) !important;
    }

    .tm-attendance-matrix.ui.table td[b-qs8m3aw39h]::before {
        content: attr(data-label);
        font-weight: var(--tm-weight-semibold);
        text-align: left;
        color: var(--tm-text-secondary);
        flex: 0 0 40%;
    }

    /* TM-98: the wide-screen geometry is undone here. A card is a stack of full-width rows,
       so fixed column widths mean nothing, a heading turned on its side has no heading row to
       live in, and the rule marking off the attendance column would draw a box round one line
       of a card. The matrix keeps stacking exactly as TM-58 left it. */
    .tm-attendance-matrix.ui.table .tm-sheet-menu-cell[b-qs8m3aw39h],
    .tm-attendance-matrix.ui.table td[data-label="Attendance"][b-qs8m3aw39h] {
        width: auto !important;
        text-align: right;
        border-left: none !important;
        border-right: none !important;
    }

    .tm-attendance-matrix.ui.table .tm-sheet-menu-cell[b-qs8m3aw39h] {
        justify-content: space-between;
    }

    .tm-sheet-result-cell[b-qs8m3aw39h] {
        padding-left: 0.75rem !important;
        padding-right: 0.75rem !important;
        text-align: right;
    }

    .tm-sheet-role-signatures[b-qs8m3aw39h] {
        flex-direction: column;
    }

    /* Name and actions stop competing for the same line; the actions drop below the
       file and align right, where the thumb is not. */
    .tm-scan[b-qs8m3aw39h] {
        flex-wrap: wrap;
    }

    .tm-scan-actions[b-qs8m3aw39h] {
        flex: 1 1 100%;
        justify-content: flex-end;
    }
}

/* The reason behind a retraining flag, under the "Yes" badge in the overview grid.
   It used to be an inline `style="margin-top: .3rem; font-size: .9em; color: #888"` —
   a raw colour that is in no palette (#888 measures 2.9:1 on white, under the AA floor)
   and two raw lengths where tokens exist. --tm-text-secondary is 7.58:1. */
.tm-session-retraining-reason[b-qs8m3aw39h] {
    margin-top: var(--tm-space-1);
    font-size: var(--tm-text-sm);
    line-height: var(--tm-leading-sm);
    color: var(--tm-text-secondary);
}
/* /Components/Pages/Sessions/ParticipantStatusCell.razor.rz.scp.css */
/* TM-61 — the attendance column of the sheet. Deliberately the same shape as
   AttendanceMatrixCell (trigger + popover), because it sits in the same table and a second
   interaction idiom in the same row would be one too many. Blazor's scoped CSS cannot be
   shared between components, so the popover rules are repeated here rather than lifted into
   a global stylesheet nobody would find. */

.tm-status-cell[b-3b5w7u54ru] {
    position: relative;
    display: inline-flex;
    align-items: center;
}

.tm-status-trigger[b-3b5w7u54ru] {
    display: inline-flex;
    align-items: center;
    padding: 0;
    border: none;
    background: none;
    cursor: pointer;
    font: inherit;
    color: inherit;
}

/* Same focus treatment as the result cells and the rest of the application (§6). */
.tm-status-trigger:focus-visible[b-3b5w7u54ru] {
    outline: 2px solid var(--tm-primary);
    outline-offset: 2px;
    border-radius: var(--tm-radius-sm);
}

/* ── Popover ──────────────────────────────────────────────────────────────────── */

.tm-status-backdrop[b-3b5w7u54ru] {
    position: fixed;
    inset: 0;
    z-index: 90;
}

.tm-status-popover[b-3b5w7u54ru] {
    position: absolute;
    top: calc(100% + 4px);
    left: 50%;
    transform: translateX(-50%);
    z-index: 100;
    min-width: 10rem;
    padding: var(--tm-space-2);
    text-align: left;
    white-space: normal;
    background: var(--tm-surface);
    border: 1px solid var(--tm-border);
    border-radius: var(--tm-radius-md);
    box-shadow: var(--tm-shadow-lg);
}

/* TM-93 — the same panel once cell-popover.js has promoted it into the browser's top layer,
   which is outside the sheet's horizontal scroll box and therefore outside its clipping.
   The UA's popover styling (inset: 0, auto margins, its own border) is taken back; the
   script supplies left/top in viewport coordinates. See AttendanceMatrixCell.razor.css. */
.tm-status-popover[popover][b-3b5w7u54ru] {
    position: fixed;
    inset: auto;
    margin: 0;
    transform: none;
    max-width: min(22rem, calc(100vw - 1rem));
    max-height: calc(100vh - 1rem);
    overflow: auto;
    padding: var(--tm-space-2);
    border: 1px solid var(--tm-border);
    color: inherit;
}

.tm-status-popover-heading[b-3b5w7u54ru] {
    font-size: var(--tm-text-sm);
    line-height: var(--tm-leading-sm);
    font-weight: var(--tm-weight-semibold);
    color: var(--tm-text-secondary);
    margin: 0.25rem 0 0.3rem;
}

.tm-status-popover-options[b-3b5w7u54ru] {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}

.tm-status-option[b-3b5w7u54ru] {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    width: 100%;
    padding: 0.3rem 0.45rem;
    border: none;
    border-radius: var(--tm-radius-sm);
    background: none;
    font: inherit;
    font-size: var(--tm-text-md);
    color: var(--tm-text);
    text-align: left;
    cursor: pointer;
}

.tm-status-option:hover[b-3b5w7u54ru],
.tm-status-option:focus-visible[b-3b5w7u54ru] {
    background: var(--tm-surface-2);
}

/* Selected state = the accent (§3.2); 7.17:1. Weight carries it too, so the current
   choice is never signalled by colour alone (WCAG 1.4.1). */
.tm-status-option.is-current[b-3b5w7u54ru] {
    background: var(--tm-primary-light);
    color: var(--tm-primary-hover);
    font-weight: var(--tm-weight-semibold);
}

/* ── Phone ─────────────────────────────────────────────────────────────────────
   Under 700px the matrix becomes cards (TM-58) that clip their own overflow, so a
   floating popover would be cut off. It expands the card instead. */
@media only screen and (max-width: 700px) {
    .tm-status-cell[b-3b5w7u54ru] {
        flex-direction: column;
        align-items: flex-end;
    }

    /* cell-popover.js leaves the panel alone below this width, so it never carries the
       `popover` attribute here and these rules are the only ones positioning it. */
    .tm-status-popover[b-3b5w7u54ru] {
        position: static;
        transform: none;
        margin-top: 0.4rem;
        min-width: 0;
        width: 100%;
        box-shadow: none;
    }

    .tm-status-backdrop[b-3b5w7u54ru] {
        display: none;
    }
}
/* /Components/Pages/Sessions/SheetMenu.razor.rz.scp.css */
/* TM-98 — the on-demand menu of the attendance sheet.

   Deliberately the same look as the cell popovers (AttendanceMatrixCell.razor.css): the
   screen already teaches "click the quiet thing, get a panel", and a second visual language
   for the same gesture would be one to learn for nothing. */

.tm-sheet-menu[b-vftdeqitjo] {
    position: relative;
    display: inline-flex;
}

/* The trigger carries no visible word — its meaning is in the accessible name, the way the
   cells of this sheet have done since TM-60. It is grey at rest so a column of them down the
   left edge reads as a margin rather than as a column of controls. */
.tm-sheet-menu-trigger[b-vftdeqitjo] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;
    padding: 0;
    border: none;
    border-radius: var(--tm-radius-sm);
    background: none;
    color: var(--tm-text-secondary);
    font: inherit;
    cursor: pointer;
}

.tm-sheet-menu-trigger:hover:not(:disabled)[b-vftdeqitjo],
.tm-sheet-menu-trigger[aria-expanded="true"][b-vftdeqitjo] {
    background: var(--tm-surface-2);
    color: var(--tm-text);
}

/* A disabled control is exempt from the contrast minimum (WCAG 1.4.3), and it has to
   read as unavailable — --tm-text-muted is the token for exactly that. */
.tm-sheet-menu-trigger:disabled[b-vftdeqitjo] {
    color: var(--tm-text-muted);
    cursor: default;
}

.tm-sheet-menu-trigger:focus-visible[b-vftdeqitjo] {
    outline: 2px solid var(--tm-primary);
    outline-offset: 1px;
}

.tm-sheet-menu-trigger .icon[b-vftdeqitjo] {
    margin: 0;
}

.tm-sheet-menu-backdrop[b-vftdeqitjo] {
    position: fixed;
    inset: 0;
    z-index: 90;
}

/* The in-flow fallback, used before cell-popover.js takes over and on any browser where it
   cannot (see the [popover] block below). It anchors by an edge for the same reason the script
   does: a menu trigger sits at an edge of the sheet, and a centred panel would hang off it. */
.tm-sheet-menu-panel[b-vftdeqitjo] {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    z-index: 100;
    min-width: 13rem;
    padding: 0.35rem 0;
    text-align: left;
    white-space: normal;
    background: var(--tm-surface);
    border: 1px solid var(--tm-border);
    border-radius: var(--tm-radius-md);
    box-shadow: var(--tm-shadow-lg);
}

.tm-sheet-menu-panel[data-align="end"][b-vftdeqitjo] {
    left: auto;
    right: 0;
}

/* The same panel once cell-popover.js has promoted it into the top layer (TM-93): the
   script supplies left/top in viewport coordinates, so the browser's own centring is undone. */
.tm-sheet-menu-panel[popover][b-vftdeqitjo] {
    position: fixed;
    inset: auto;
    margin: 0;
    transform: none;
    max-width: min(20rem, calc(100vw - 1rem));
    max-height: calc(100vh - 1rem);
    overflow: auto;
    border: 1px solid var(--tm-border);
    color: inherit;
}

/* Items are passed in as child content, so they carry the *caller's* CSS scope, not this
   component's — ::deep is what lets the menu style them anyway. */
.tm-sheet-menu-panel[b-vftdeqitjo]  .tm-sheet-menu-item {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    width: 100%;
    padding: 0.4rem 0.75rem;
    border: none;
    background: none;
    font: inherit;
    font-size: var(--tm-text-md);
    color: var(--tm-text);
    text-align: left;
    cursor: pointer;
}

.tm-sheet-menu-panel[b-vftdeqitjo]  .tm-sheet-menu-item:hover:not(:disabled),
.tm-sheet-menu-panel[b-vftdeqitjo]  .tm-sheet-menu-item:focus-visible {
    background: var(--tm-surface-2);
}

.tm-sheet-menu-panel[b-vftdeqitjo]  .tm-sheet-menu-item:disabled {
    color: var(--tm-text-muted);
    cursor: default;
}

/* An icon standing beside its own caption is the one thing --tm-text-muted is for —
   the word carries the meaning, the glyph only points at it. */
.tm-sheet-menu-panel[b-vftdeqitjo]  .tm-sheet-menu-item .icon {
    width: 1.1rem;
    margin: 0;
    color: var(--tm-text-muted);
    text-align: center;
}

.tm-sheet-menu-panel[b-vftdeqitjo]  .tm-sheet-menu-item:disabled .icon {
    color: var(--tm-text-muted);
}

/* Destructive items are separated and coloured — the one thing in the menu that cannot be
   undone by clicking again. The separator above them is the other half of the signal, so
   the colour is not carrying it alone (WCAG 1.4.1). --tm-danger is 6.69:1 on --tm-surface
   and 5.81:1 on its own tint, which is the hover fill. */
.tm-sheet-menu-panel[b-vftdeqitjo]  .tm-sheet-menu-item--danger,
.tm-sheet-menu-panel[b-vftdeqitjo]  .tm-sheet-menu-item--danger .icon {
    color: var(--tm-danger);
}

.tm-sheet-menu-panel[b-vftdeqitjo]  .tm-sheet-menu-item--danger:hover:not(:disabled) {
    background: var(--tm-danger-light);
}

.tm-sheet-menu-panel[b-vftdeqitjo]  .tm-sheet-menu-separator {
    height: 0;
    margin: 0.35rem 0;
    border-top: 1px solid var(--tm-border-light);
}

/* Phone: the sheet is a stack of cards (TM-58) and cell-popover.js leaves the panel in flow
   below 700px, so these rules are the only ones positioning it there. */
@media only screen and (max-width: 700px) {
    .tm-sheet-menu-panel[b-vftdeqitjo] {
        position: static;
        transform: none;
        margin-top: 0.4rem;
        min-width: 0;
        width: 100%;
        box-shadow: none;
    }

    .tm-sheet-menu-backdrop[b-vftdeqitjo] {
        display: none;
    }
}
/* /Components/Pages/Sessions/SignatureModal.razor.rz.scp.css */
/* Signature pad styling for the in-app signature modal (TM-19). Mirrors the anonymous
   /sign page (Public/Signature.razor.css); CSS isolation means the styles cannot be
   shared, so the pad look is kept in sync here deliberately. */
/* Field label, same shape as every other label in the system (§6). */
.tm-signature-label[b-ozxjrxh68t] {
    display: block;
    font-size: var(--tm-text-sm);
    line-height: var(--tm-leading-sm);
    font-weight: var(--tm-weight-medium);
    margin-bottom: var(--tm-space-2);
    color: var(--tm-text-secondary);
}

.tm-signature-signer-name[b-ozxjrxh68t] {
    margin: 0 0 0.25rem;
    font-size: var(--tm-text-lg);
    line-height: var(--tm-leading-lg);
    font-weight: var(--tm-weight-semibold);
    color: var(--tm-text);
}

/* Personal number sits directly under the name: the two together are the identity, and
   splitting them across the screen would invite reading the name on its own (TM-63). */
/* The personal number is an identifier, so it is set in the mono face (§2) — the same
   treatment it gets everywhere else it appears. */
.tm-signature-signer-id[b-ozxjrxh68t] {
    margin: 0 0 var(--tm-space-4);
    color: var(--tm-text-secondary);
}

/* The declaration is the thing being agreed to, so it is body text, not a caption. */
.tm-signature-declaration[b-ozxjrxh68t] {
    margin: 0 0 0.75rem;
    line-height: 1.5;
}

.tm-signature-items[b-ozxjrxh68t] {
    margin: 0 0 1rem;
    padding-left: 1.25rem;
    /* Long agendas scroll inside the list rather than pushing the pad off the screen. */
    max-height: 11rem;
    overflow-y: auto;
}

.tm-signature-items li[b-ozxjrxh68t] {
    margin-bottom: 0.25rem;
    line-height: 1.4;
}

.tm-signature-items-empty[b-ozxjrxh68t] {
    margin: 0 0 var(--tm-space-4);
    color: var(--tm-text-secondary);
    font-style: italic;
}

.tm-signature-note[b-ozxjrxh68t] {
    margin: 0;
    color: var(--tm-text-secondary);
    font-size: var(--tm-text-sm);
    line-height: var(--tm-leading-sm);
}

/* The pad is the one control this modal exists for, and the dashed edge is the whole of
   its affordance — an empty canvas on a white dialog says nothing by itself. That puts it
   under WCAG 1.4.11, which the old #cbd5e1 missed at 1.42:1. --tm-border-strong is 3.11:1
   and is the token §3.1 nominates for exactly this. */
.tm-signature-pad[b-ozxjrxh68t] {
    border: 2px dashed var(--tm-border-strong);
    border-radius: var(--tm-radius-sm);
    background: var(--tm-surface);
    /* Fixed drawing height; the canvas fills the box. */
    height: 200px;
    overflow: hidden;
}

.tm-signature-canvas[b-ozxjrxh68t] {
    display: block;
    width: 100%;
    height: 100%;
    cursor: crosshair;
    /* Prevent the browser from scrolling/zooming while drawing on touch devices. */
    touch-action: none;
}

.tm-signature-actions[b-ozxjrxh68t] {
    margin-top: 0.5rem;
    margin-bottom: 0.5rem;
    text-align: right;
}
/* /Components/Shared/DefinitionGrid.razor.rz.scp.css */
/* Definition grid — the label/value block on every detail page.
   docs/08-design-refresh.md §5.2 / docs/08-design-audit-phase3.md §3.3, §3.7

   `::deep` because the pairs are DefinitionItem components: they carry their caller's CSS
   scope, not this component's, so a plain descendant selector would never reach them. Same
   device as SheetMenu.razor.css. */

/* v2: each pair is its own tile, not a cell in one undivided block.

   This grid was written in the first round, when the whole Overview sat inside a
   card and the pairs were plain text inside it. The v2 mock-up that was signed off
   draws them as separate rectangles — surface, hairline, radius — and the round
   that adopted v2 never reached this file, because `Shared/**` was not in any
   agent's ownership. The result shipped as "one big block" and was spotted by the
   reader, not by a test.

   Four columns rather than two: at a tile per pair, two columns leave each tile
   half the content width for about twenty characters of value, which is why the
   block read as heavy. Four keeps a tile close to the width of what it holds. */
.tm-c-def-grid[b-o6y98zfr66] {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--tm-space-2);
    margin: 0;
}

/* Below the desktop breakpoint the tiles get too narrow to hold a date plus a
   badge, so the grid halves before it collapses (see the 767px rule below). */
@media only screen and (max-width: 1099px) {
    .tm-c-def-grid[b-o6y98zfr66] {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

.tm-c-def-grid.tm-c-def-grid--single[b-o6y98zfr66] {
    grid-template-columns: minmax(0, 1fr);
}

/* One column below the tablet breakpoint: two columns of label+value at 375px leaves about
   twelve characters per value. */
@media only screen and (max-width: 767px) {
    .tm-c-def-grid[b-o6y98zfr66] {
        grid-template-columns: minmax(0, 1fr);
    }
}

.tm-c-def-grid[b-o6y98zfr66]  .tm-c-def-item {
    display: flex;
    flex-direction: column;
    gap: var(--tm-space-1);
    /* Lets a long value shrink and truncate instead of widening its grid column. */
    min-width: 0;

    /* The tile itself (§4 geometry, matching the approved mock-up's `.cell`).
       --tm-border and not --tm-border-strong: this is a panel edge, not a control
       edge, so it is not under the WCAG 1.4.11 3:1 floor that --tm-border-strong
       exists to clear. */
    background: var(--tm-surface);
    border: 1px solid var(--tm-border);
    border-radius: var(--tm-radius-md);
    padding: var(--tm-space-3) var(--tm-space-4);
}

/* The label is the quiet half — but quiet is --tm-text-secondary, never --tm-text-muted:
   #94a3b8 measures 2.56:1 on --tm-surface, under the WCAG AA 4.5:1 floor. #475569 is 7.58:1.
   §5.6 says this in as many words, and phase 2 already found two live failures this way. */
.tm-c-def-grid[b-o6y98zfr66]  .tm-c-def-label {
    margin: 0;
    font-size: var(--tm-text-sm);
    line-height: var(--tm-leading-sm);
    font-weight: var(--tm-weight-normal);
    color: var(--tm-text-secondary);
}

/* `min-width: 0` plus the wrapping rules below are what stop the audit's §3.3 complaint that
   the Employee-detail email wraps to two lines and breaks the grid's rhythm: a long value now
   truncates with an ellipsis, and `title` on the caller's side supplies the full text — the
   same contract tables.css uses for a long cell. */
.tm-c-def-grid[b-o6y98zfr66]  .tm-c-def-value {
    margin: 0;
    min-width: 0;
    font-size: var(--tm-text-base);
    line-height: var(--tm-leading-base);
    color: var(--tm-text);
    font-variant-numeric: tabular-nums;
    overflow-wrap: anywhere;
}

/* The agreed "there is no value here" rendering — one em dash, quiet, with a title so it is
   not a mystery character to a screen reader. A zero is not this: `0` renders as `0`
   (UiConsistencyTests). */
.tm-c-def-grid[b-o6y98zfr66]  .tm-c-def-empty {
    color: var(--tm-text-secondary);
}
/* /Components/Shared/EmptyState.razor.rz.scp.css */
/* Shared empty state — docs/08-design-refresh.md §5.6.

   No coloured background, no coloured left bar, no icon, no illustration. An empty list is
   not an event; the only thing on screen is the sentence explaining it and, at most, one
   thing to do about it. See PageHeader.razor.css for why the class prefix is `tm-c-`. */

.tm-c-empty-state[b-06hsw7fs2h] {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--tm-space-3);
    padding: var(--tm-space-6) var(--tm-space-4);
    text-align: center;
    /* --tm-surface-2 rather than a tint: it is the same inset surface used by table headers
       and hover rows, so an empty table reads as the same object as a filled one. */
    background: var(--tm-surface-2);
    border: 1px solid var(--tm-border);
    border-radius: var(--tm-radius-md);
}

/* Contrast: --tm-text-secondary (#475569) on --tm-surface-2 (#f8fafc) measures 7.25:1,
   comfortably past the WCAG AA 4.5:1 floor for normal text (it clears AAA's 7:1 too). The
   dark-theme pair, #94a3b8 on #172033, measures 6.34:1. "Quiet" here means low-chroma, not
   low-contrast — --tm-text-muted (#94a3b8) would drop this to 2.45:1 and is deliberately
   not used for the message. */
.tm-c-empty-state-message[b-06hsw7fs2h] {
    margin: 0;
    max-width: 46ch;   /* measure, not a spacing value — keeps a long sentence readable */
    font-size: var(--tm-text-base);
    line-height: var(--tm-leading-base);
    font-weight: var(--tm-weight-normal);
    color: var(--tm-text-secondary);
}

.tm-c-empty-state-action[b-06hsw7fs2h] {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--tm-space-2);
}
/* /Components/Shared/PageHeader.razor.rz.scp.css */
/* Shared page header — docs/08-design-refresh.md §5.5.

   Class prefix note (applies to all three phase-2 primitives): the root class is
   `tm-c-page-header`, NOT `tm-page-header`. The latter already exists as a global rule in
   base.css and still carries the old treatment (font-weight 700, font-size 1.75rem) that
   §5.5 replaces. Reusing the name would inherit exactly what this component exists to undo,
   and would tie the component to a file owned by another phase-2 branch. The `tm-c-` prefix
   keeps every primitive self-contained. Phase 3 selects on data-testid, not on the class. */

.tm-c-page-header[b-xdxcwhj92c] {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--tm-space-3);
    margin-bottom: var(--tm-space-5);
}

.tm-c-page-header-text[b-xdxcwhj92c] {
    /* Lets a long title wrap instead of pushing the action slot off the row. */
    min-width: 0;
}

/* §5.5: --tm-text-xl / semibold / -.02em. Weight 700 is gone from the system — the old
   header shouted at 700/28px, and a page title does not need to.

   `min-height` is the fix for the measured defect in docs/08-design-audit-phase3.md §3.2: the
   header rendered 36px tall with an action and 28px without, because the action button is
   --tm-control-height and the title's line box is only --tm-leading-xl (28px). The content
   below therefore started 8px higher on every page that has no action — table top at 223px on
   Announcements against 215px on Settings — and the vertical rhythm never settled.

   Giving the title box the control height makes the title row identical either way, and
   centring the text inside it keeps the type optically where it was rather than sliding it up
   against the breadcrumb. */
.tm-c-page-header-title[b-xdxcwhj92c] {
    display: flex;
    align-items: center;
    min-height: var(--tm-control-height);
    margin: 0;
    font-size: var(--tm-text-xl);
    line-height: var(--tm-leading-xl);
    font-weight: var(--tm-weight-semibold);
    letter-spacing: -0.02em;
    color: var(--tm-text);
}

/* ── Breadcrumb ───────────────────────────────────────────────
   The trail sits above the title, quiet and small: it is orientation, not content. Every step
   is a real <a href> — the thing the hand-rolled "Back" buttons on Employee, Position and
   Session detail were not (audit §3.3), which is why none of them could be middle-clicked or
   reached from the keyboard.

   --tm-text-secondary (#475569) on --tm-surface (#ffffff) measures 7.58:1, well past the WCAG
   AA 4.5:1 floor. --tm-text-muted is NOT usable here (2.56:1) even though the trail is meant
   to read quietly — §5.6: quiet means low chroma, not low contrast. */
.tm-c-breadcrumb[b-xdxcwhj92c] {
    margin-bottom: var(--tm-space-1);
}

.tm-c-breadcrumb-list[b-xdxcwhj92c] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--tm-space-1);
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: var(--tm-text-sm);
    line-height: var(--tm-leading-sm);
}

.tm-c-breadcrumb-item[b-xdxcwhj92c] {
    display: inline-flex;
    align-items: center;
    gap: var(--tm-space-1);
}

/* The separator is a pseudo-element rather than a character in the markup, so it stays out of
   textContent and a screen reader reads "Employees, John Doe" instead of "Employees slash
   John Doe". The <nav aria-label> and the <ol> carry the structure for assistive tech. */
.tm-c-breadcrumb-item + .tm-c-breadcrumb-item[b-xdxcwhj92c]::before {
    content: "/";
    color: var(--tm-text-muted);   /* decoration, not text — the one thing muted is for */
    speak: never;
}

.tm-c-breadcrumb-link[b-xdxcwhj92c] {
    color: var(--tm-text-secondary);
    text-decoration: none;
    border-radius: var(--tm-radius-sm);
    transition: color var(--tm-transition);
}

.tm-c-breadcrumb-link:hover[b-xdxcwhj92c] {
    color: var(--tm-text);
    text-decoration: underline;
}

/* Focus rings are never removed (§8). Same 3px ring as every button, derived the same way. */
.tm-c-breadcrumb-link:focus-visible[b-xdxcwhj92c] {
    outline: none;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--tm-text-secondary) 25%, transparent);
}

.tm-c-breadcrumb-current[b-xdxcwhj92c] {
    color: var(--tm-text-secondary);
}

/* --tm-text-secondary (#475569) on --tm-surface (#fff) measures 7.58:1 — well clear of the
   WCAG AA 4.5:1 floor for normal text. In dark theme it is #94a3b8 on #111827, 6.92:1. */
.tm-c-page-header-subtitle[b-xdxcwhj92c] {
    margin: var(--tm-space-1) 0 0;
    font-size: var(--tm-text-base);
    line-height: var(--tm-leading-base);
    font-weight: var(--tm-weight-normal);
    color: var(--tm-text-secondary);
}

.tm-c-page-header-actions[b-xdxcwhj92c] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--tm-space-2);
    /* Keeps the actions on the title's baseline row rather than stretching to its full
       height when a subtitle is present. */
    flex-shrink: 0;
}

/* Below the tablet breakpoint the actions drop under the title and go full width, so a
   "Create …" button does not end up squeezed into a two-word-wide column. */
@media only screen and (max-width: 767px) {
    .tm-c-page-header[b-xdxcwhj92c] {
        flex-direction: column;
        align-items: stretch;
    }

    .tm-c-page-header-actions[b-xdxcwhj92c] {
        width: 100%;
    }
}
/* /Components/Shared/Skeleton.razor.rz.scp.css */
/* Shared loading skeleton — docs/08-design-refresh.md §5.6.
   See PageHeader.razor.css for why the class prefix is `tm-c-`. */

.tm-c-skeleton[b-fi6h4l7ebs] {
    display: flex;
    flex-direction: column;
    width: 100%;
}

/* ── The bar ──────────────────────────────────────────────────────────────────
   Contrast note. --tm-border (#e5e7eb) on --tm-surface (#fff) measures 1.24:1, and that is
   correct rather than a failure to fix. WCAG 1.4.11 sets its 3:1 floor for non-text content
   "required to understand the content"; a skeleton bar is a placeholder for content that is
   not there yet, carries no information, and is aria-hidden, so it is decoration under
   1.4.11 and exempt. The substance is carried by the role="status" label on the parent,
   which is real text and is announced. Pushing these bars to 3:1 (--tm-text-muted #94a3b8
   is 2.45:1; it would take roughly --tm-text-secondary, 7.58:1) would render them as solid
   grey slabs that read as actual content — the opposite of what a placeholder should say.

   The 1600ms duration is a literal on purpose: the motion tokens are interaction-feedback
   timings (150ms / 250ms) and an ambient loop at that speed strobes. There is no ambient
   duration in the scale, and inventing a --tm-* name here would imply a global token that
   tokens.css does not define. */
.tm-c-skeleton-shape[b-fi6h4l7ebs] {
    box-sizing: border-box;
    background: var(--tm-border);
    animation: tm-c-skeleton-pulse-b-fi6h4l7ebs 1600ms ease-in-out infinite;
}

/* Rests at full opacity, so a frozen animation leaves the bar visible — see the
   reduced-motion note at the bottom of this file. */
@keyframes tm-c-skeleton-pulse-b-fi6h4l7ebs {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.45; }
}

/* ── Variants ─────────────────────────────────────────────────────────────────
   The variants differ in height, radius and rhythm only. No percentage widths and no
   "short last line" trick: every value here comes from the scale. */

/* A line of body text. */
.tm-c-skeleton--text .tm-c-skeleton-shape[b-fi6h4l7ebs] {
    height: var(--tm-leading-base);
    border-radius: var(--tm-radius-sm);
}

.tm-c-skeleton--text .tm-c-skeleton-shape + .tm-c-skeleton-shape[b-fi6h4l7ebs] {
    margin-top: var(--tm-space-2);
}

/* A card, panel or chart. */
.tm-c-skeleton--block .tm-c-skeleton-shape[b-fi6h4l7ebs] {
    height: var(--tm-space-8);
    border-radius: var(--tm-radius-md);
}

.tm-c-skeleton--block .tm-c-skeleton-shape + .tm-c-skeleton-shape[b-fi6h4l7ebs] {
    margin-top: var(--tm-space-3);
}

/* A table row. The element occupies exactly --tm-row-height so the placeholder reserves the
   real height of the table it replaces and the page does not jump when data lands; the
   vertical padding (clipped out of the background) insets the bar so it reads as a cell in
   a row rather than as a solid slab. Rows butt against each other and are divided by the
   same hairline a real table uses — §5.2: one 1px --tm-border-light between rows, no
   per-cell borders. */
.tm-c-skeleton--table-row .tm-c-skeleton-shape[b-fi6h4l7ebs] {
    height: var(--tm-row-height);
    padding: var(--tm-space-3) 0;
    background-clip: content-box;
    border-bottom: 1px solid var(--tm-border-light);
    border-radius: var(--tm-radius-sm);
}

/* ── Reduced motion ───────────────────────────────────────────────────────────
   tokens.css already carries the global kill switch (animation-duration: 0.01ms and
   animation-iteration-count: 1, both !important). That alone stops the pulse, and because
   the keyframes rest at opacity 1 the frozen bar is fully visible rather than stuck at 45%
   — which is why they are written 0%/100% = 1 and not `from 0.45 to 1`.

   This rule is belt and braces on top of it: it drops the animation outright, so the bars
   stay visible even if the global block is ever narrowed, reordered or scoped away (it
   lives in a file this component does not own). `animation: none` also removes the
   animation rather than racing it to completion in 0.01ms. */
@media (prefers-reduced-motion: reduce) {
    .tm-c-skeleton-shape[b-fi6h4l7ebs] {
        animation: none;
        opacity: 1;
    }
}
/* /Components/Shared/ThemeSwitcher.razor.rz.scp.css */
/* ============================================================
   Theme switcher — the light / dark / system control in the top bar (TM-143 step 3)
   docs/08-design-system-v2.md §3.5 (dark theme and its switch)
   ------------------------------------------------------------
   Scoped to the component rather than added to base.css, where the rest of the
   header lives, for two reasons: base.css belongs to another owner in this
   round, and a segmented control with three states is a component, not a frame
   rule. Nothing here is reachable from any other markup, so none of it needs a
   specificity fight with Fomantic — the buttons carry no `ui` class and no
   `item` class, which is what keeps `.ui.menu .item` and `.ui.button` away from
   them.

   Contrast (WCAG 1.4.11, 3:1 — every glyph here is an icon-only control, so the
   glyph IS the control and the floor applies to it):

     resting  --tm-text-secondary on --tm-surface-2   5.56:1 light · 6.67:1 dark
     chosen   --tm-primary        on --tm-primary-light  5.17:1 light · 5.00:1 dark

   The tray's own 1px --tm-border is decorative: it groups the three, it does not
   carry the state. The state is carried by the glyph's colour AND by
   aria-pressed, so it survives both a monochrome display and a screen reader.
   ============================================================ */

/* The tray is the only FILLED thing in the header — the user pill and the
   sign-out link share its 36px baseline but are transparent until :hover, so
   all you see of them is a glyph. A filled box next to that read as the heaviest
   object in the bar, which is backwards: the switcher is the least important
   control up there. It started at 34px in a 56px header, i.e. most of the bar's
   height.

   It is now a STRIP: 24px tall (16 + 2×3 padding + 2×1 border), 43% of the bar.
   The reader asked for the vertical inset to feel like the horizontal one, so
   the padding is equal on all four sides and the difference that remains comes
   from the buttons being wider than they are tall — which is what makes it read
   as a segmented strip rather than three square keys.

   THE POINTER TARGET IS THE TRADE, AND IT IS DELIBERATE. Each button is 24×16,
   under the 24×24 that WCAG 2.2 SC 2.5.8 asks for. It rests on that rule's
   spacing exception instead: the buttons are 24 wide with a 2px gap, so their
   centres are 26px apart and the 24px circles the exception measures do not
   intersect. Keep the WIDTH at 24 and the gap at 2 — those two numbers are what
   the exception stands on. If the strip ever needs to be lighter again, take the
   fill out; do not take the width. */
.tm-theme-switch[b-to4l56tutp] {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    flex: 0 0 auto;
    margin: 0 var(--tm-space-1);
    padding: 3px;
    border: 1px solid var(--tm-border-light);
    border-radius: var(--tm-radius-sm);
    background: var(--tm-surface-2);
}

.tm-theme-switch__option[b-to4l56tutp] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 16px;
    padding: 0;
    border: none;
    border-radius: calc(var(--tm-radius-sm) - 2px);
    background: transparent;
    color: var(--tm-text-secondary);
    font: inherit;
    cursor: pointer;
    transition: background var(--tm-transition), color var(--tm-transition);
}

.tm-theme-switch__option:hover[b-to4l56tutp] {
    background: var(--tm-border-light);
    color: var(--tm-text);
}

/* Declared after :hover so that pointing at a button still answers the pointer,
   the same ordering rule the filter-chip menu and the dropdowns use. */
.tm-theme-switch__option--active[b-to4l56tutp] {
    background: var(--tm-primary-light);
    color: var(--tm-primary);
}

/* :focus-visible, not :focus — a pointer click must not leave a ring behind,
   and keyboard focus must always show one. The ring is an outline rather than
   the box-shadow the buttons in buttons.css use: these sit 2px apart inside a
   tray, and a 3px shadow ring would be clipped between them. */
.tm-theme-switch__option:focus-visible[b-to4l56tutp] {
    outline: 2px solid var(--tm-primary);
    outline-offset: 1px;
}

/* Fomantic gives every `i.icon` a right margin and a fixed 1.18em box, both of
   which push the glyph off centre in a square button. */
.tm-theme-switch__option i.icon[b-to4l56tutp] {
    margin: 0;
    width: auto;
    height: auto;
    font-size: var(--tm-text-base);
    line-height: 1;
}
