/* ═══════════════════════════════════════════════════════════════════
   NIO Portaal — design system
   Loaded after MudBlazor.min.css, so plain selectors override it.
   Palette/radius/elevation come from NioTheme.cs as --mud-* variables;
   the aliases below carry fallbacks because MudThemeProvider only emits
   them once the circuit connects (App.razor renders with prerender:false).
   ═══════════════════════════════════════════════════════════════════ */

:root {
    /* Surfaces — canvas sits a shade darker than a card; that's the only
       thing separating them since cards carry neither border nor shadow. */
    --nio-canvas: #eef0f3;
    --nio-surface: var(--mud-palette-surface, #ffffff);
    --nio-surface-muted: #f4f5f7;
    --nio-surface-hover: #f9fafb;

    /* Lines */
    --nio-border: var(--mud-palette-lines-default, #e5e7eb);
    --nio-border-strong: #d1d5db;

    /* Text */
    --nio-ink: var(--mud-palette-text-primary, #111827);
    --nio-text: #374151;
    --nio-text-muted: var(--mud-palette-text-secondary, #6b7280);
    --nio-text-faint: #9ca3af;

    /* Accent — gold is decoration only; actions are ink-coloured */
    --nio-accent: var(--mud-palette-tertiary, #c8900a);

    /* Sidebar — warm off-white, a shade off both the white cards and the grey canvas */
    --nio-sidebar-bg: var(--mud-palette-drawer-background, #f7f6f3);
    --nio-sidebar-border: #e8e6e1;
    --nio-sidebar-text: #374151;
    --nio-sidebar-text-muted: #78746d;
    --nio-sidebar-hover: rgba(17, 24, 39, 0.045);
    --nio-sidebar-active: color-mix(in srgb, var(--nio-accent) 10%, transparent);

    /* Radius */
    --nio-radius-sm: 6px;
    --nio-radius: var(--mud-default-borderradius, 8px);
    --nio-radius-lg: 10px;

    /* Spacing */
    --nio-gap-xs: 4px;
    --nio-gap-sm: 8px;
    --nio-gap: 12px;
    --nio-gap-md: 16px;
    --nio-gap-lg: 20px;
    --nio-gap-xl: 24px;

    /* Motion — colour only, no transforms */
    --nio-transition: 120ms ease;

    /* The one shadow in the system: floating layers only */
    --nio-shadow-pop: 0 8px 24px rgba(17, 24, 39, 0.10), 0 2px 6px rgba(17, 24, 39, 0.06);
}

/* ── Tones ──────────────────────────────────────────────────────────
   Every tinted element (badge, icon box, choice button) reads --tone.
   Set the tone with a class, never with an inline style. */
.t-neutral { --tone: #6b7280; }
.t-ink     { --tone: #111827; }
.t-accent  { --tone: #c8900a; }
.t-green   { --tone: #16a34a; }
.t-amber   { --tone: #d97706; }
.t-red     { --tone: #dc2626; }
.t-blue    { --tone: #2563eb; }
.t-violet  { --tone: #7c3aed; }
.t-teal    { --tone: #0d9488; }
.t-orange  { --tone: #ea580c; }
.t-pink    { --tone: #db2777; }
.t-indigo  { --tone: #4f46e5; }

/* ── Base ────────────────────────────────────────────────────────── */
html, body {
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    margin: 0;
    padding: 0;
    height: 100%;
    background: var(--nio-canvas);
    color: var(--nio-ink);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

:focus-visible {
    outline: 2px solid var(--nio-accent);
    outline-offset: 2px;
}

/* ── App shell ───────────────────────────────────────────────────── */
.nio-page {
    padding: 32px 40px 64px;
    min-height: 100vh;
}

.mud-appbar {
    background: var(--nio-sidebar-bg);
    border-bottom: 1px solid var(--nio-border);
}

@media (min-width: 960px) {
    .mud-appbar { display: none; }
    /* .mud-appbar-dense~.mud-main-content in MudBlazor.min.css has no media
       query and higher specificity (two simple selectors); match it here so
       hiding the mobile appbar actually reclaims its reserved top padding. */
    .mud-main-content,
    .mud-appbar-dense ~ .mud-main-content { padding-top: 0; }
}

@media (max-width: 959px) {
    .mud-main-content { padding-top: 56px; }
    .nio-page { padding: 20px 16px 48px; }

    /* Below the drawer's breakpoint MudBlazor already turns an *open* mini drawer into an
       overlay with a scrim, but it leaves the docked-sidebar geometry in place: every
       .mud-drawer-{open,close}-mini-*-left rule in MudBlazor.min.css sits outside a media
       query. Closed, that reserves a 64px rail; open, it shoves the page 248px sideways
       behind the very scrim that is covering it. Neither belongs on a phone — the drawer
       should slide over the page and leave it alone. app.css loads after MudBlazor.min.css,
       so these win on source order at equal specificity. */
    .mud-drawer-close-mini-md-left .mud-main-content,
    .mud-drawer-open-mini-md-left .mud-main-content { margin-left: 0; }

    .mud-drawer-close-mini-md-left.mud-drawer-left-clipped-never .mud-appbar,
    .mud-drawer-open-mini-md-left.mud-drawer-left-clipped-never .mud-appbar {
        margin-left: 0;
        width: 100%;
    }

    .mud-drawer.mud-drawer-mini.mud-drawer-md.mud-drawer--closed {
        width: 0;
        border-right: none;
        overflow: hidden;
    }
}

.mud-drawer {
    border-right: 1px solid var(--nio-border);
}

/* ── Mobile top bar ──────────────────────────────────────────────── */
/* Only ever visible below 960px (see the min-width rule above). Mirrors the parent portal's
   header: brand on the left, avatar on the right, nothing competing in between. */
.nio-topbar-logo {
    height: 26px;
    width: auto;
    margin-left: var(--nio-gap-sm);
    flex-shrink: 0;
}

.nio-topbar-title {
    margin-left: var(--nio-gap-sm);
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--nio-ink);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ── Sidebar ─────────────────────────────────────────────────────── */
.sidebar-layout {
    display: flex;
    flex-direction: column;
    height: 100%;
    overflow: hidden;
}

.sidebar-logo {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 18px 16px;
    flex-shrink: 0;
    border-bottom: 1px solid var(--nio-sidebar-border);
}

.sidebar-logo-text {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--nio-ink);
    white-space: nowrap;
}

.sidebar-logo-img {
    height: 32px;
    width: auto;
    flex-shrink: 0;
}

.sidebar-collapse-btn {
    margin-left: auto;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    flex-shrink: 0;
    border-radius: var(--nio-radius-sm);
    color: var(--nio-sidebar-text-muted);
    cursor: pointer;
    transition: background var(--nio-transition), color var(--nio-transition);
}

.sidebar-collapse-btn:hover {
    background: var(--nio-sidebar-hover);
    color: var(--nio-ink);
}

.sidebar-nav {
    flex: 1;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 8px 0;
}

.sidebar-nav::-webkit-scrollbar { width: 0; }

.sidebar-footer {
    flex-shrink: 0;
    padding: 8px;
    border-top: 1px solid var(--nio-sidebar-border);
}

.sidebar-divider {
    height: 1px;
    background: var(--nio-sidebar-border);
    margin: 4px 8px;
}

.sidebar-footer-row,
.sidebar-profile {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    border-radius: var(--nio-radius);
    cursor: pointer;
    transition: background var(--nio-transition);
}

.sidebar-footer-row:hover,
.sidebar-profile:hover {
    background: var(--nio-sidebar-hover);
}

.sidebar-footer-icon {
    width: 28px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    color: var(--nio-sidebar-text-muted);
}

.sidebar-footer-label {
    font-size: 0.8rem;
    color: var(--nio-sidebar-text-muted);
    white-space: nowrap;
}

.sidebar-profile-info {
    flex: 1;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    min-width: 0;
}

.sidebar-profile-name {
    font-size: 0.82rem;
    font-weight: 500;
    color: var(--nio-ink);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sidebar-profile-role {
    font-size: 0.7rem;
    color: var(--nio-sidebar-text-muted);
    white-space: nowrap;
}

.sidebar-avatar {
    background: var(--nio-sidebar-border);
    color: var(--nio-ink);
    font-weight: 600;
    font-size: 0.75rem;
    width: 30px;
    height: 30px;
    flex-shrink: 0;
}

.sidebar-avatar-lg {
    width: 40px;
    height: 40px;
    font-size: 0.9rem;
}

.nio-menu-header {
    padding: 12px 16px;
    border-bottom: 1px solid var(--nio-border);
    min-width: 230px;
    display: flex;
    align-items: center;
    gap: 12px;
}

.nio-menu-header .sidebar-avatar {
    background: var(--nio-surface-muted);
    color: var(--nio-ink);
}

.nio-menu-header-name {
    font-size: 0.85rem;
    font-weight: 500;
    color: var(--nio-ink);
}

.nio-menu-header-email {
    font-size: 0.75rem;
    color: var(--nio-text-muted);
}

.nio-menu-item-danger { color: var(--mud-palette-error, #dc2626); }
.nio-menu-item-muted { color: var(--nio-text-muted); font-style: italic; }

.nio-lang-item {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 0.85rem;
}

.nio-lang-check { margin-left: auto; color: var(--nio-accent); }

.sidebar-profile-chevron { color: var(--nio-sidebar-text-muted); flex-shrink: 0; }

.nio-hidden { display: none; }

/* ── Nav links ───────────────────────────────────────────────────────
   Scoped to the drawer: these are sidebar colours, so a MudNavMenu used
   anywhere else in the app must not inherit them. */
.nio-nav { padding: 0 8px; }

/* Headings in the menu (Beheer mijn locatie, Organisatie). */
.nio-nav-section {
    display: block;
    padding: 20px 14px 6px;
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--nio-sidebar-text-muted);
}

/* Separator lines between nav groups — mini rail only. Expanded already has the
   section headings to tell groups apart, so a line there would double up. */
.nio-nav-separator {
    display: none;
}

.mud-drawer-mini.mud-drawer--closed .nio-nav-separator {
    display: block;
    height: 1px;
    background: var(--nio-sidebar-border);
    margin: 8px 8px;
}

.mud-drawer .mud-nav-link {
    border-radius: var(--nio-radius);
    margin: 1px 0;
    font-size: 0.855rem;
    font-weight: 450;
    color: var(--nio-sidebar-text);
    transition: background var(--nio-transition), color var(--nio-transition);
}

.mud-drawer .mud-nav-link:hover {
    background: var(--nio-sidebar-hover);
    color: var(--nio-ink);
}

/* The one bold state in the sidebar: a solid ink pill. Hover stays a tint. */
.mud-drawer .mud-nav-link.active {
    background: var(--nio-ink);
    color: var(--nio-surface);
    border-radius: 999px;
    font-weight: 600;
    box-shadow: none;
}

.mud-drawer .mud-nav-link .mud-icon-root {
    color: var(--nio-sidebar-text-muted);
    font-size: 18px;
    transition: color var(--nio-transition);
}

.mud-drawer .mud-nav-link:hover .mud-icon-root { color: var(--nio-sidebar-text); }
/* Gold lightened so it stays legible on the dark pill — still decoration only. */
.mud-drawer .mud-nav-link.active .mud-icon-root { color: color-mix(in srgb, var(--nio-accent) 70%, white); }

/* ── Mini rail (64px) ────────────────────────────────────────────────
   MudBlazor puts .mud-drawer--closed on the mini drawer. Everything with a
   label collapses to its icon; nothing is hidden from the menu itself. */
.mud-drawer-mini.mud-drawer--closed .sidebar-logo-text,
.mud-drawer-mini.mud-drawer--closed .sidebar-footer-label,
.mud-drawer-mini.mud-drawer--closed .sidebar-profile-info,
.mud-drawer-mini.mud-drawer--closed .sidebar-profile-chevron {
    display: none;
}

/* Logo + toggle no longer fit side by side in a 64px rail (the logo isn't
   square), so stack them: logo on top, toggle centered underneath. */
.mud-drawer-mini.mud-drawer--closed .sidebar-logo {
    flex-direction: column;
    padding: 14px 6px 12px;
    gap: 10px;
    justify-content: center;
}

.mud-drawer-mini.mud-drawer--closed .sidebar-logo-img { height: 28px; }

.mud-drawer-mini.mud-drawer--closed .sidebar-collapse-btn {
    margin-left: 0;
    width: 26px;
    height: 26px;
}

.mud-drawer-mini.mud-drawer--closed .sidebar-footer-row,
.mud-drawer-mini.mud-drawer--closed .sidebar-profile {
    justify-content: center;
    padding: 8px 4px;
}

.mud-drawer-mini.mud-drawer--closed .sidebar-footer-icon { width: auto; }

/* No room for the word — the heading becomes the divider it stands for. */
.mud-drawer-mini.mud-drawer--closed .nio-nav-section {
    height: 0;
    padding: 0;
    margin: 12px 6px;
    overflow: hidden;
    border-top: 1px solid var(--nio-sidebar-border);
}

/* ── Surfaces ────────────────────────────────────────────────────────
   Cards are flat: the colour lives in the label above them, not in the
   surface. Radius/padding are literals here on purpose — --nio-radius-lg
   also drives tables, dialogs and the icon box, which stay at 10px. */
.nio-card {
    background: var(--nio-sidebar-bg);
    border-radius: 20px;
    padding: 24px;
}

.nio-card-full { height: 100%; box-sizing: border-box; }

/* Label + card as one unit, so FullHeight still fills the grid row. */
.nio-card-block-full {
    height: 100%;
    display: flex;
    flex-direction: column;
}

.nio-card-block-full .nio-card { flex: 1; min-height: 0; }

/* Header actions sit on the card; the title lives above it. */
.nio-card-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    margin-bottom: var(--nio-gap-md);
}

/* Card that continues directly below another surface. */
.nio-card-joined {
    border-top: none;
    border-radius: 0 0 var(--nio-radius-lg) var(--nio-radius-lg);
}

/* Clickable card: colour-only feedback, no lift or scale.
   A card that acts as a button keeps its tone tint — the colour is what
   identifies it (subject, section), so these stay tinted while plain
   cards went flat. Hover deepens the same tint rather than shifting hue. */
.nio-card-action {
    cursor: pointer;
    background: color-mix(in srgb, var(--tone, var(--nio-text-muted)) 5%, var(--nio-surface));
    transition: background var(--nio-transition);
}

.nio-card-action:hover {
    background: color-mix(in srgb, var(--tone, var(--nio-text-muted)) 10%, var(--nio-surface));
}

/* ── Navigation tile ─────────────────────────────────────────────── */
.nio-tile {
    display: flex;
    flex-direction: column;
    gap: var(--nio-gap-md);
}

.nio-tile-label {
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--nio-ink);
    line-height: 1.35;
}

.nio-tile-sublabel {
    font-size: 0.8rem;
    color: var(--nio-text-muted);
    margin-top: 3px;
    line-height: 1.45;
}

.nio-tile-arrow { color: var(--nio-text-faint); align-self: flex-end; }
.nio-card-action:hover .nio-tile-arrow { color: var(--nio-text-muted); }

/* ── Class tile ──────────────────────────────────────────────────── */
.nio-class-tile {
    display: flex;
    flex-direction: column;
    gap: var(--nio-gap-md);
}

.nio-class-tile-head {
    display: flex;
    align-items: center;
    gap: var(--nio-gap);
}

.nio-class-tile-subject {
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--tone, var(--nio-text-muted));
}

.nio-class-tile-name {
    font-size: 1rem;
    font-weight: 600;
    color: var(--nio-ink);
    line-height: 1.3;
}

.nio-class-tile-sub {
    font-size: 0.78rem;
    color: var(--nio-text-muted);
}

/* ── Metric ──────────────────────────────────────────────────────── */
.nio-metric-row {
    display: flex;
    gap: var(--nio-gap);
    margin-top: auto;
}

.nio-metric {
    flex: 1;
    text-align: center;
    padding: 10px 8px;
    border-radius: var(--nio-radius);
    background: color-mix(in srgb, var(--tone, var(--nio-ink)) 10%, var(--nio-surface-muted));
}

.nio-metric-value {
    font-size: 1.15rem;
    font-weight: 600;
    color: var(--tone, var(--nio-ink));
    line-height: 1.2;
}

.nio-metric-label {
    font-size: 0.7rem;
    color: var(--nio-text-muted);
    margin-top: 2px;
}

/* ── Misc labels ─────────────────────────────────────────────────── */
.nio-group-label {
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--nio-text-faint);
    margin-bottom: var(--nio-gap);
}

/* Icon-led variant: the icon box carries the margin, not the text. */
.nio-group-label-row {
    display: flex;
    align-items: center;
    gap: var(--nio-gap-sm);
    margin-bottom: var(--nio-gap);
}

.nio-group-label-inline { margin-bottom: 0; }

.nio-subsection {
    display: flex;
    align-items: baseline;
    gap: var(--nio-gap-sm);
    margin-bottom: var(--nio-gap);
}

.nio-page-header-action { flex-shrink: 0; }

/* ── Hero card (entity detail header) ────────────────────────────── */
.nio-hero {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--nio-gap-md);
    flex-wrap: wrap;
}

.nio-hero-main {
    display: flex;
    align-items: center;
    gap: var(--nio-gap-md);
    min-width: 0;
}

.nio-hero-title {
    font-size: 1.375rem;
    font-weight: 600;
    color: var(--nio-ink);
    letter-spacing: -0.02em;
}

.nio-hero-meta {
    display: flex;
    align-items: center;
    gap: var(--nio-gap-md);
    flex-wrap: wrap;
    font-size: 0.85rem;
    color: var(--nio-text-muted);
}

.nio-hero-actions {
    display: flex;
    gap: var(--nio-gap-sm);
    flex-wrap: wrap;
}

.nio-row-between { justify-content: space-between; }

.nio-form-actions {
    display: flex;
    justify-content: flex-end;
    margin-top: var(--nio-gap-lg);
}

.nio-form-actions-row { gap: var(--nio-gap); margin-top: 0; }

/* ── Profile summary card ────────────────────────────────────────── */
.nio-profile-card { text-align: center; }

.nio-profile-name {
    font-size: 1.05rem;
    font-weight: 600;
    color: var(--nio-ink);
    margin-top: var(--nio-gap);
}

.nio-profile-details {
    display: flex;
    flex-direction: column;
    gap: var(--nio-gap-sm);
    text-align: left;
    font-size: 0.82rem;
    color: var(--nio-text);
}

.mud-paper,
.mud-card {
    background: var(--nio-surface);
    border-radius: var(--nio-radius-lg);
}

/* ── Layout helpers ──────────────────────────────────────────────── */
.nio-stack { display: flex; flex-direction: column; gap: var(--nio-gap-md); }
.nio-row   { display: flex; align-items: center; gap: var(--nio-gap-sm); flex-wrap: wrap; }
.nio-fill  { flex: 1; min-width: 0; }

/* Responsive grid of equal cards, no media queries needed. */
.nio-card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: var(--nio-gap-md);
}

.nio-page-intro { margin: 0 0 var(--nio-gap-xl); }

/* A NioCard laid out as a horizontal row: icon · content · trailing control. */
.nio-row-card {
    display: flex;
    align-items: center;
    gap: var(--nio-gap);
}

.nio-row-card-title {
    font-size: 0.925rem;
    font-weight: 600;
    color: var(--nio-ink);
}

.nio-row-card-meta {
    font-size: 0.75rem;
    color: var(--tone, var(--nio-text-muted));
}

/* ── Page header ─────────────────────────────────────────────────── */
.nio-page-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--nio-gap-md);
    margin-bottom: 24px;
    padding-bottom: 16px;
    border-bottom: 1px solid var(--nio-border);
    flex-wrap: wrap;
}

.nio-page-header-main {
    display: flex;
    align-items: flex-start;
    gap: var(--nio-gap);
    min-width: 0;
}

.nio-page-title {
    font-size: 1.375rem;
    font-weight: 600;
    color: var(--nio-ink);
    letter-spacing: -0.02em;
    line-height: 1.3;
}

.nio-page-subtitle {
    font-size: 0.85rem;
    color: var(--nio-text-muted);
    margin-top: 4px;
}

.nio-back-btn {
    border: 1px solid var(--nio-border);
    border-radius: var(--nio-radius);
    color: var(--nio-text-muted);
}

.nio-back-btn:hover { background: var(--nio-surface-muted); }

.nio-sticky-header {
    position: sticky;
    top: 0;
    z-index: 30;
    background: var(--nio-canvas);
    margin: -32px -40px 20px;
    padding: 24px 40px 0;
}

.nio-sticky-header .nio-page-header { margin-bottom: 16px; }

@media (max-width: 959px) {
    .nio-sticky-header { margin: -20px -16px 16px; padding: 16px 16px 0; }
}

/* ── Subsection labels ───────────────────────────────────────────── */
.nio-subsection-title {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--nio-ink);
}

.nio-subsection-subtitle {
    font-size: 0.75rem;
    color: var(--nio-text-muted);
    margin-bottom: var(--nio-gap);
}

/* ── Badge ───────────────────────────────────────────────────────── */
.nio-badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 2px 8px;
    border-radius: var(--nio-radius-sm);
    font-size: 0.75rem;
    font-weight: 500;
    line-height: 1.6;
    white-space: nowrap;
    color: var(--tone, var(--nio-text-muted));
    background: color-mix(in srgb, var(--tone, var(--nio-text-muted)) 13%, white);
    border: 1px solid color-mix(in srgb, var(--tone, var(--nio-text-muted)) 26%, white);
}

.nio-badge .mud-icon-root { font-size: 14px; }
.nio-badge-caps { text-transform: capitalize; }
.nio-badge-fixed { min-width: 26px; justify-content: center; }

/* ── Icon box ────────────────────────────────────────────────────── */
.nio-iconbox {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 36px;
    height: 36px;
    border-radius: var(--nio-radius);
    color: var(--tone, var(--nio-text-muted));
    background: color-mix(in srgb, var(--tone, var(--nio-text-muted)) 15%, white);
}

.nio-iconbox .mud-icon-root { font-size: 18px; }

.nio-iconbox-sm { width: 28px; height: 28px; border-radius: var(--nio-radius-sm); }
.nio-iconbox-sm .mud-icon-root { font-size: 15px; }

.nio-iconbox-lg { width: 44px; height: 44px; }
.nio-iconbox-lg .mud-icon-root { font-size: 22px; }

.nio-iconbox-xl { width: 64px; height: 64px; border-radius: var(--nio-radius-lg); }
.nio-iconbox-xl .mud-icon-root { font-size: 30px; }

/* ── Avatar ──────────────────────────────────────────────────────── */
.nio-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 36px;
    height: 36px;
    border-radius: 999px;
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--tone, var(--nio-text-muted));
    background: color-mix(in srgb, var(--tone, var(--nio-text-muted)) 17%, white);
}

.nio-avatar-sm { width: 28px; height: 28px; font-size: 0.68rem; }
.nio-avatar-lg { width: 48px; height: 48px; font-size: 1rem; }
.nio-avatar-xl { width: 64px; height: 64px; font-size: 1.25rem; }
.nio-avatar-xl .mud-icon-root { font-size: 30px; }
.nio-avatar-lg .mud-icon-root { font-size: 24px; }

/* ── Timeline ────────────────────────────────────────────────────── */
.nio-timeline { display: flex; flex-direction: column; }

.nio-timeline-item {
    position: relative;
    padding-left: 30px;
    padding-bottom: var(--nio-gap);
}

.nio-timeline-item:last-child { padding-bottom: 0; }

/* Connector line to the next step. */
.nio-timeline-item::before {
    content: "";
    position: absolute;
    left: 7px;
    top: 22px;
    bottom: 0;
    width: 2px;
    background: var(--nio-border);
}

.nio-timeline-item:last-child::before { display: none; }

.nio-timeline-dot {
    position: absolute;
    left: 0;
    top: 5px;
    width: 16px;
    height: 16px;
    border-radius: 999px;
    box-sizing: border-box;
    background: color-mix(in srgb, var(--tone, var(--nio-text-muted)) 25%, white);
    border: 2px solid var(--tone, var(--nio-text-muted));
}

.nio-timeline-body {
    border-radius: var(--nio-radius);
    padding: 10px 14px;
    background: color-mix(in srgb, var(--tone, var(--nio-text-muted)) 12%, white);
}

.nio-timeline-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--nio-gap-sm);
}

.nio-timeline-label {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--tone, var(--nio-text-muted));
}

.nio-timeline-meta {
    display: flex;
    align-items: center;
    gap: var(--nio-gap-xs);
    font-size: 0.75rem;
    font-weight: 500;
    color: var(--nio-text-muted);
    white-space: nowrap;
}

.nio-timeline-notes {
    font-size: 0.8rem;
    color: var(--nio-text-muted);
    font-style: italic;
    border-top: 1px solid color-mix(in srgb, var(--tone, var(--nio-text-muted)) 20%, white);
    padding-top: 6px;
    margin-top: 6px;
}

/* Step not reached yet — dashed carries the "expected but missing" meaning. */
.nio-timeline-item-pending .nio-timeline-dot {
    background: var(--nio-surface);
    border: 2px dashed var(--nio-border-strong);
}

.nio-timeline-item-pending .nio-timeline-body {
    background: var(--nio-surface-muted);
    border: 1px dashed var(--nio-border-strong);
}

.nio-timeline-item-pending .nio-timeline-label { color: var(--nio-text-faint); }

/* ── Stat card ───────────────────────────────────────────────────── */
/* Stat tiles keep their tone tint — the colour is the metric's identity. */
.nio-stat-card {
    display: flex;
    align-items: center;
    gap: var(--nio-gap-md);
    height: 100%;
    box-sizing: border-box;
    padding: 24px;
    background: color-mix(in srgb, var(--tone, var(--nio-ink)) 8%, var(--nio-surface));
    border-radius: 20px;
}

.nio-stat-value {
    font-size: 1.5rem;
    font-weight: 600;
    color: var(--nio-ink);
    line-height: 1.2;
    letter-spacing: -0.02em;
}

.nio-stat-label {
    font-size: 0.78rem;
    color: var(--nio-text-muted);
    margin-top: 2px;
}

/* Cards carry more inner padding than the page has outer at mobile widths
   (.nio-page drops to 16px), so pull it back in. */
@media (max-width: 959px) {
    .nio-card,
    .nio-stat-card,
    .nio-empty { padding: 18px; }
}

/* ── Choice button (attendance / rating pickers) ─────────────────── */
.nio-choice {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    min-height: 40px;
    padding: 0 14px;
    border-radius: var(--nio-radius);
    border: 1px solid var(--nio-border);
    background: var(--nio-surface);
    color: var(--nio-text);
    font-family: inherit;
    font-size: 0.85rem;
    font-weight: 500;
    cursor: pointer;
    transition: background var(--nio-transition), border-color var(--nio-transition), color var(--nio-transition);
}

.nio-choice:hover:not(:disabled) {
    background: var(--nio-surface-muted);
    border-color: var(--nio-border-strong);
}

.nio-choice[aria-pressed="true"] {
    color: var(--tone, var(--nio-text-muted));
    background: color-mix(in srgb, var(--tone, var(--nio-text-muted)) 13%, white);
    border-color: color-mix(in srgb, var(--tone, var(--nio-text-muted)) 42%, white);
}

.nio-choice:disabled { opacity: 0.5; cursor: default; }

.nio-choice .mud-icon-root { font-size: 17px; }

.nio-choice-group {
    display: flex;
    flex-wrap: wrap;
    gap: var(--nio-gap-sm);
}

/* Attendance picker: subcategory buttons grouped under their category heading. */
.nio-choice-categories {
    display: flex;
    flex-direction: column;
    gap: var(--nio-gap);
}

.nio-choice-category-label {
    display: block;
    margin-bottom: var(--nio-gap-xs);
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--tone, var(--nio-text-muted));
}

/* Compact variant: category and its buttons on one line, categories flowing side by side.
   Used for the bulk "set all as" shortcut, which shouldn't outweigh the student list. */
.nio-choice-categories-compact {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--nio-gap-sm) var(--nio-gap);
}

.nio-choice-categories-compact .nio-choice-category {
    display: flex;
    align-items: center;
    gap: var(--nio-gap-sm);
}

.nio-choice-categories-compact .nio-choice-category + .nio-choice-category {
    padding-left: var(--nio-gap);
    border-left: 1px solid var(--nio-border);
}

.nio-choice-categories-compact .nio-choice-category-label {
    margin-bottom: 0;
    white-space: nowrap;
}

.nio-choice-categories-compact .nio-choice {
    min-height: 34px;
    padding: 0 10px;
    font-size: 0.8rem;
}

/* Below tablet the single row cannot hold three categories: fall back to the stacked block,
   which wraps its buttons instead of forcing the page to scroll sideways. */
@media (max-width: 959px) {
    .nio-choice-categories-compact {
        flex-direction: column;
        align-items: stretch;
        gap: var(--nio-gap);
    }

    .nio-choice-categories-compact .nio-choice-category {
        display: block;
    }

    .nio-choice-categories-compact .nio-choice-category + .nio-choice-category {
        padding-left: 0;
        border-left: none;
    }

    .nio-choice-categories-compact .nio-choice-category-label {
        margin-bottom: var(--nio-gap-xs);
    }
}


/* Two-line variant (label + count), used for picker/tab-style selectors. */
.nio-choice-text {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    line-height: 1.3;
}

.nio-choice-label { font-weight: 600; }

.nio-choice-sublabel {
    font-size: 0.72rem;
    font-weight: 400;
    color: var(--nio-text-muted);
}

.nio-choice-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: var(--nio-gap-sm);
    margin-bottom: var(--nio-gap-xl);
}

.nio-choice-grid .nio-choice {
    min-height: 56px;
    justify-content: flex-start;
}

/* ── Action list (quick links inside a card) ─────────────────────── */
.nio-action-list {
    display: flex;
    flex-direction: column;
    gap: var(--nio-gap-xs);
}

.nio-action-link { justify-content: flex-start; }

/* ── Proportion bar ──────────────────────────────────────────────── */
.nio-bar + .nio-bar { margin-top: var(--nio-gap); }

.nio-bar-head {
    display: flex;
    justify-content: space-between;
    gap: var(--nio-gap-sm);
    margin-bottom: 4px;
}

.nio-bar-label {
    font-size: 0.82rem;
    font-weight: 500;
    color: var(--nio-text);
}

.nio-bar-value {
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--tone, var(--nio-ink));
}

.nio-bar-track {
    --fill: 0%;
    height: 8px;
    border-radius: 999px;
    background: var(--nio-surface-muted);
    overflow: hidden;
}

.nio-bar-fill {
    width: var(--fill);
    height: 100%;
    border-radius: 999px;
    background: var(--tone, var(--nio-ink));
}

/* ── Person row ──────────────────────────────────────────────────── */
.nio-person-row {
    display: flex;
    align-items: center;
    gap: var(--nio-gap);
    padding: 10px 12px;
    border-radius: var(--nio-radius);
    background: var(--nio-surface-muted);
}

.nio-person-row + .nio-person-row { margin-top: var(--nio-gap-sm); }

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

.nio-person-meta {
    font-size: 0.78rem;
    color: var(--nio-text-muted);
}

.nio-person-roles { margin-top: 6px; gap: var(--nio-gap-xs); }

/* Inline label preceding a row of badges, e.g. "Other roles:". */
.nio-inline-label {
    font-size: 0.78rem;
    color: var(--nio-text-muted);
    align-self: center;
}

.nio-loading {
    display: flex;
    justify-content: center;
    padding: 80px;
}

.nio-note-centered { text-align: center; padding: 24px 0; }

/* ── Dialog title ────────────────────────────────────────────────── */
.nio-dialog-title {
    display: flex;
    align-items: center;
    gap: var(--nio-gap);
    padding: 4px 0;
}

.nio-dialog-title-text {
    font-size: 1rem;
    font-weight: 600;
    color: var(--nio-ink);
    line-height: 1.3;
}

/* ── Dialog body / actions padding ───────────────────────────────── */
.nio-dialog-body { padding: 8px 0 0; }

.nio-dialog-actions {
    display: flex;
    gap: var(--nio-gap-sm);
    padding: 4px 8px;
}

/* ── Stat grid ───────────────────────────────────────────────────── */
.nio-stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: var(--nio-gap-xl);
    margin-bottom: var(--nio-gap-xl);
}

/* ── Empty state ─────────────────────────────────────────────────── */
/* Matches the card recipe above — keep the two in step. */
.nio-empty {
    display: flex;
    align-items: center;
    gap: var(--nio-gap);
    padding: 24px;
    background: var(--nio-sidebar-bg);
    border-radius: 20px;
}

.nio-empty-centered {
    flex-direction: column;
    justify-content: center;
    text-align: center;
    gap: var(--nio-gap-sm);
    padding: 48px 24px;
}

.nio-empty-title {
    font-size: 0.925rem;
    font-weight: 600;
    color: var(--nio-ink);
}

.nio-empty-text {
    font-size: 0.85rem;
    color: var(--nio-text-muted);
    margin-top: 2px;
}

.nio-empty-action {
    display: flex;
    justify-content: center;
    margin-top: var(--nio-gap-md);
}

/* ── Inline stats ────────────────────────────────────────────────── */
.nio-inline-stats {
    display: flex;
    align-items: center;
    gap: var(--nio-gap-md);
    flex-wrap: wrap;
}

.nio-inline-stat {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: 0.78rem;
    font-weight: 500;
    color: var(--nio-text-muted);
}

.nio-inline-stat .mud-icon-root { font-size: 15px; }

/* ── Toolbars & bars ─────────────────────────────────────────────── */
.nio-toolbar {
    display: flex;
    align-items: center;
    gap: var(--nio-gap-md);
    flex-wrap: wrap;
}

/* The previous-day-incomplete alert sits beside the date picker rather than stacking below it. */
.nio-toolbar-alert {
    flex: 1 1 320px;
    margin: 0;
}

.nio-save-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--nio-gap-md);
    flex-wrap: wrap;
    padding: 16px 20px;
    background: var(--nio-surface);
    border-radius: var(--nio-radius-lg);
}

.nio-save-bar-title {
    font-size: 0.925rem;
    font-weight: 600;
    color: var(--nio-ink);
}

.nio-field-group {
    border-radius: var(--nio-radius);
    padding: 16px;
}

.nio-field-label {
    font-size: 0.82rem;
    font-weight: 500;
    color: var(--nio-ink);
    margin-bottom: 4px;
}

.nio-date-input { max-width: 320px; }
.nio-date-input-sm { max-width: 150px; }

/* ── Inline notes & list rows ────────────────────────────────────── */
.nio-note {
    font-size: 0.8rem;
    color: var(--nio-text-muted);
}

.nio-note-strong {
    font-size: 0.85rem;
    color: var(--nio-text);
}

.nio-note-inline {
    font-size: 0.72rem;
    color: var(--nio-text-faint);
    margin-left: 4px;
}

.nio-list { display: flex; flex-direction: column; gap: var(--nio-gap-sm); }

.nio-list-row {
    background: var(--nio-surface-muted);
    border-radius: var(--nio-radius);
    padding: 10px 14px;
}

.nio-list-row-title {
    font-size: 0.82rem;
    font-weight: 500;
    color: var(--nio-ink);
}

.nio-list-row-meta {
    font-size: 0.72rem;
    color: var(--nio-text-muted);
    margin-top: 2px;
}

/* ── Log cards (phone rendering of a data grid row) ───────────────── */
/* Same information as the grid, stacked instead of columned. A button, not a div, so the row
   is reachable by keyboard the way the grid's RowClick never was. */
.nio-logcards {
    display: flex;
    flex-direction: column;
    gap: var(--nio-gap-sm);
}

.nio-logcard {
    display: flex;
    flex-direction: column;
    /* Not redundant: the UA stylesheet centres a button's flex children, which would centre
       every row of this card instead of lining them up on one left edge. */
    align-items: flex-start;
    gap: var(--nio-gap-sm);
    width: 100%;
    padding: 12px 14px;
    text-align: left;
    font: inherit;
    color: var(--nio-text);
    background: var(--nio-surface-muted);
    border: 0;
    border-radius: var(--nio-radius);
    cursor: pointer;
    transition: background var(--nio-transition);
}

.nio-logcard:hover { background: var(--nio-surface-hover); }

/* Leading label, trailing badge pushed to the far edge — the day cards on the student page. */
.nio-logcard-head {
    display: flex;
    align-items: center;
    gap: var(--nio-gap-sm);
    width: 100%;
}

/* Only in that row does the name take the slack; elsewhere it is plain typography and the
   badge beside it sits right up against it. */
.nio-logcard-head .nio-logcard-name {
    flex: 1;
    min-width: 0;
}

.nio-logcard-name {
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--nio-ink);
}

/* Everything packed to the left and wrapping when it runs out of room, rather than any of it
   being truncated. */
.nio-logcard-row,
.nio-logcard-ratings {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--nio-gap-sm) var(--nio-gap);
}

.nio-logcard-rating {
    display: inline-flex;
    align-items: center;
    gap: var(--nio-gap-xs);
}

/* The grid abbreviates these to H / I / G in its column headers; there is room for the real
   word here, and no header row to carry the meaning otherwise. */
.nio-logcard-rating-label {
    font-size: 0.72rem;
    color: var(--nio-text-muted);
}

.nio-logcard-parent {
    display: flex;
    flex-direction: column;
    gap: var(--nio-gap-xs);
    /* Full width so the rule above it spans the card, not just the text under it. */
    width: 100%;
    padding-top: var(--nio-gap-sm);
    border-top: 1px solid var(--nio-border);
}

.nio-logcard-parent-line {
    display: flex;
    align-items: flex-start;
    gap: var(--nio-gap-xs);
    font-size: 0.75rem;
    color: var(--nio-text-muted);
}

.nio-logcard-parent-line .mud-icon-root { flex-shrink: 0; }

/* ── Data grid helpers ───────────────────────────────────────────── */
.nio-row-clickable { cursor: pointer; }
.nio-cell-icon { width: 32px; padding-right: 0; }
.nio-cell-strong { font-weight: 500; color: var(--nio-ink); }
.nio-cell-empty { color: var(--nio-border-strong); }

.nio-col-header {
    display: flex;
    align-items: center;
    gap: 2px;
}

/* Rows awaiting a decision sit at the top of the list and read as unfinished business.
   Pair with a t-* class for the tint, same as .nio-card-action does. */
.nio-row-pending td {
    background: color-mix(in srgb, var(--tone, var(--nio-text-muted)) 8%, var(--nio-surface));
}

.nio-row-pending td:first-child {
    box-shadow: inset 3px 0 0 0 var(--tone, var(--nio-text-muted));
}

/* A sub-section inside a dialog: same flat tint as a card, sized for nesting. */
.nio-subpanel {
    background: var(--nio-sidebar-bg);
    border-radius: var(--nio-radius-lg);
    padding: var(--nio-gap-md);
}

/* Scrollable picker list inside a dialog. */
.nio-dialog-list {
    max-height: 400px;
    overflow-y: auto;
}

.nio-dialog-list-sm { max-height: 300px; }

.nio-row-tight {
    display: flex;
    align-items: center;
    gap: 6px;
}

.nio-link-accent { color: var(--nio-accent); }
.nio-link-muted { color: var(--nio-text-muted); }
.nio-icon-tone { color: var(--tone, var(--nio-text-muted)); }
.nio-icon-faint { color: var(--nio-border-strong); }
.nio-tile-action {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    padding: 0;
    border: 1px solid var(--nio-border);
    border-radius: var(--nio-radius-sm);
    background: var(--nio-surface);
    color: var(--nio-accent);
    cursor: pointer;
    transition: background var(--nio-transition), border-color var(--nio-transition);
}

.nio-tile-action:hover {
    background: color-mix(in srgb, var(--nio-accent) 8%, white);
    border-color: color-mix(in srgb, var(--nio-accent) 35%, white);
}

/* ── Tables ──────────────────────────────────────────────────────── */
.mud-table {
    background: var(--nio-surface);
    border-radius: var(--nio-radius-lg);
    overflow: hidden;
}

.mud-table-head .mud-table-cell {
    background: var(--nio-surface-muted);
    color: var(--nio-text-muted);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0;
    text-transform: none;
    border-bottom: 1px solid var(--nio-border);
}

.mud-table-cell {
    border-bottom: 1px solid var(--nio-border);
    color: var(--nio-text);
}

.mud-table-row:hover td { background: var(--nio-surface-hover); }

/* ── Buttons ─────────────────────────────────────────────────────── */
.mud-button-root { letter-spacing: normal; }

.mud-button-outlined {
    border-color: var(--nio-border);
    background: var(--nio-surface);
    color: var(--nio-text);
}

.mud-button-outlined:hover {
    background: var(--nio-surface-muted);
    border-color: var(--nio-border-strong);
}

/* Tone-coloured outlined button: add a .t-* class alongside .mud-button-outlined. */
.mud-button-outlined[class*="t-"] {
    color: var(--tone, var(--nio-text));
    border-color: color-mix(in srgb, var(--tone, var(--nio-border)) 35%, white);
}

.mud-button-outlined[class*="t-"]:hover {
    background: color-mix(in srgb, var(--tone, var(--nio-text-muted)) 10%, white);
    border-color: color-mix(in srgb, var(--tone, var(--nio-border)) 55%, white);
}

/* ── Chips ───────────────────────────────────────────────────────── */
.mud-chip {
    border-radius: var(--nio-radius-sm);
    font-size: 0.75rem;
    font-weight: 500;
}

/* ── Dialogs & menus — the only layers that carry a shadow ───────── */
.mud-dialog {
    background: var(--nio-surface);
    border: 1px solid var(--nio-border);
    border-radius: var(--nio-radius-lg);
    box-shadow: var(--nio-shadow-pop);
}

.mud-dialog-title {
    font-size: 1rem;
    font-weight: 600;
    color: var(--nio-ink);
    border-bottom: 1px solid var(--nio-border);
    padding-bottom: 14px;
}

.mud-popover .mud-list {
    background: var(--nio-surface);
    border: 1px solid var(--nio-border);
    border-radius: var(--nio-radius);
    box-shadow: var(--nio-shadow-pop);
    overflow-x: hidden;
    overflow-y: auto;
}

.mud-list-item {
    border-radius: var(--nio-radius-sm);
    margin: 2px 4px;
    transition: background var(--nio-transition);
}

/* ── Inputs ──────────────────────────────────────────────────────── */
.mud-input-outlined .mud-input-outlined-border {
    border-color: var(--nio-border-strong);
    transition: border-color var(--nio-transition), box-shadow var(--nio-transition);
}

.mud-input-outlined:hover .mud-input-outlined-border { border-color: var(--nio-text-faint); }

.mud-input-outlined.mud-focused .mud-input-outlined-border {
    border-color: var(--nio-accent);
    border-width: 1px;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--nio-accent) 15%, white);
}

/* ── Scrollbar ───────────────────────────────────────────────────── */
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: #d1d5db; border-radius: 999px; }
::-webkit-scrollbar-thumb:hover { background: var(--nio-text-faint); }

/* ── Blazor error ────────────────────────────────────────────────── */
.blazor-error-boundary {
    padding: 16px;
    background: color-mix(in srgb, #dc2626 8%, white);
    color: #b91c1c;
    border: 1px solid color-mix(in srgb, #dc2626 20%, white);
    border-radius: var(--nio-radius);
}

.blazor-error-boundary::after { content: "Er is een fout opgetreden."; }

/* ── Scoreboard ──────────────────────────────────────────────────────
   The one place in the app that leans on motion: a podium that rises in
   on load and a confetti burst on demand. Everything else stays flat. */
.nio-scoreboard {
    display: flex;
    flex-direction: column;
    gap: var(--nio-gap-sm);
}

/* ── Podium ─────────────────────────────────────────────────────── */
.nio-podium {
    display: flex;
    align-items: flex-end;
    justify-content: center;
    gap: var(--nio-gap-md);
    padding-top: 28px;
}

.nio-podium-place {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    flex: 1;
    max-width: 180px;
    animation: nio-podium-rise 520ms cubic-bezier(.34, 1.4, .64, 1) backwards;
}

/* Gold last so it lands after the runners-up. */
.nio-podium-2 { animation-delay: 60ms; }
.nio-podium-3 { animation-delay: 140ms; }
.nio-podium-1 { animation-delay: 260ms; }

.nio-podium-crown {
    color: var(--nio-accent);
    font-size: 30px;
    margin-bottom: 2px;
    animation: nio-podium-float 2.4s ease-in-out infinite;
}

.nio-podium-avatar { margin-bottom: var(--nio-gap-sm); }

.nio-podium-1 .nio-podium-avatar {
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--nio-accent) 45%, transparent);
}

.nio-podium-name {
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--nio-ink);
    text-align: center;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.nio-podium-points {
    font-size: 1.5rem;
    font-weight: 700;
    color: var(--nio-ink);
    letter-spacing: -0.02em;
    line-height: 1.1;
}

.nio-podium-points-label {
    font-size: 0.65rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--nio-text-faint);
    margin-bottom: var(--nio-gap-sm);
}

/* Block height is the ranking, so the middle column reads as first place. */
.nio-podium-block {
    width: 100%;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding-top: var(--nio-gap-sm);
    border-radius: var(--nio-radius-lg) var(--nio-radius-lg) 0 0;
    background: color-mix(in srgb, var(--tone, var(--nio-text-muted)) 18%, var(--nio-surface));
}

.nio-podium-1 .nio-podium-block { height: 112px; }
.nio-podium-2 .nio-podium-block { height: 76px; }
.nio-podium-3 .nio-podium-block { height: 50px; }

.nio-podium-medal { color: var(--tone, var(--nio-text-muted)); }
.nio-podium-medal .mud-icon-root { font-size: 22px; }

/* ── Shared class goal ──────────────────────────────────────────── */
/* ── Period picker (school year + month dropdowns) ─────────────────── */
.nio-period-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--nio-gap-sm);
}

.nio-period-select { min-width: 200px; flex: 0 1 220px; }

@media (max-width: 600px) {
    .nio-period-select { flex-basis: 100%; }
}

.nio-goal { display: flex; flex-direction: column; gap: var(--nio-gap-sm); }

.nio-goal-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--nio-gap-sm);
    flex-wrap: wrap;
}

.nio-goal-text { font-size: 0.9rem; font-weight: 600; color: var(--nio-ink); }
.nio-goal-remaining { font-size: 0.8rem; color: var(--nio-text-muted); }

.nio-goal-track {
    height: 14px;
    border-radius: 999px;
    background: var(--nio-surface-muted);
    overflow: hidden;
}

.nio-goal-fill {
    height: 100%;
    width: var(--fill, 0%);
    border-radius: 999px;
    background: var(--tone, var(--nio-accent));
    transition: width 700ms cubic-bezier(.34, 1.2, .64, 1);
}

/* ── Awards ─────────────────────────────────────────────────────── */
.nio-award-row {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    gap: var(--nio-gap-md);
}

.nio-award {
    display: flex;
    align-items: center;
    gap: var(--nio-gap);
    padding: var(--nio-gap);
    border-radius: var(--nio-radius-lg);
    background: color-mix(in srgb, var(--tone, var(--nio-text-muted)) 8%, var(--nio-surface));
}

.nio-award-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    flex-shrink: 0;
    border-radius: 999px;
    color: var(--tone, var(--nio-text-muted));
    background: color-mix(in srgb, var(--tone, var(--nio-text-muted)) 18%, var(--nio-surface));
}

.nio-award-label {
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--nio-text-muted);
}

.nio-award-holder { font-size: 0.95rem; font-weight: 600; color: var(--nio-ink); }

/* Shown only on a phone (see the phone layer at the end of this file); everywhere else the
   same text is one hover away in the tooltip. */
.nio-award-hint {
    display: none;
    margin-top: 2px;
    font-size: 0.72rem;
    color: var(--nio-text-muted);
}

/* ── Ranking rows ───────────────────────────────────────────────── */
.nio-sb-row {
    display: flex;
    align-items: center;
    gap: var(--nio-gap);
    padding: 10px 14px;
    border-radius: var(--nio-radius-lg);
    background: var(--nio-surface);
}

.nio-sb-row-top { background: color-mix(in srgb, var(--nio-accent) 6%, var(--nio-surface)); }

.nio-sb-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; }

.nio-sb-name {
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--nio-ink);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Stacked base+bonus bar, total width relative to the leader. */
.nio-sb-bar {
    display: flex;
    width: var(--width, 0%);
    height: 8px;
    border-radius: 999px;
    overflow: hidden;
    background: var(--nio-surface-muted);
    transition: width 600ms cubic-bezier(.34, 1.2, .64, 1);
}

.nio-sb-bar-base  { width: var(--base, 100%); background: var(--tone, var(--nio-ink)); }
.nio-sb-bar-bonus { flex: 1; background: var(--tone, var(--nio-accent)); }

.nio-sb-encourage { font-size: 0.75rem; color: var(--nio-text-faint); }

.nio-sb-split { display: flex; gap: var(--nio-gap-xs); flex-shrink: 0; }

.nio-sb-rank {
    width: 32px;
    height: 32px;
    flex-shrink: 0;
    border-radius: var(--nio-radius-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 600;
    font-size: 0.85rem;
    color: var(--tone, var(--nio-text-muted));
    background: color-mix(in srgb, var(--tone, var(--nio-text-muted)) 15%, white);
}

.nio-sb-rank .mud-icon-root { font-size: 19px; }

.nio-sb-total {
    font-size: 1rem;
    font-weight: 600;
    color: var(--nio-ink);
    min-width: 36px;
    text-align: right;
}

/* Confetti burst over the winner. Replays because the podium's @key changes,
   so there is no timer to wait on or reset. */
.nio-confetti-piece {
    position: absolute;
    top: 34%;
    left: 50%;
    width: 8px;
    height: 8px;
    border-radius: 2px;
    background: var(--tone, var(--nio-accent));
    pointer-events: none;
    animation: nio-confetti 1.1s ease-out forwards;
}

@keyframes nio-confetti {
    from { transform: translate(0, 0) rotate(0deg); opacity: 1; }
    /* --dx is set per piece inline and spreads to ±85px, which is wider than a podium place
       on a phone. --dx-scale reins the burst in without touching the markup. */
    to   { transform: translate(calc(var(--dx, 20px) * var(--dx-scale, 1)), -70px) rotate(var(--dr, 220deg)); opacity: 0; }
}

@keyframes nio-podium-rise {
    from { transform: translateY(18px); opacity: 0; }
    to   { transform: translateY(0); opacity: 1; }
}

@keyframes nio-podium-float {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(-4px); }
}

/* Respect a reduced-motion preference: keep the layout, drop the movement. */
@media (prefers-reduced-motion: reduce) {
    .nio-podium-place,
    .nio-podium-crown,
    .nio-confetti-piece { animation: none; }

    .nio-confetti-piece { display: none; }
    .nio-goal-fill, .nio-sb-bar { transition: none; }
}

@media (max-width: 700px) {
    .nio-podium { gap: var(--nio-gap-sm); }
    .nio-podium-points { font-size: 1.2rem; }

    /* A place is barely 100px wide here, so a single nowrap line cuts most names off after a
       few letters. Two lines fit the tallest block without pushing the podium around. */
    .nio-podium-name {
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
        white-space: normal;
        line-height: 1.25;
    }
    .nio-podium-1 .nio-podium-block { height: 72px; }
    .nio-podium-2 .nio-podium-block { height: 52px; }
    .nio-podium-3 .nio-podium-block { height: 36px; }

    .nio-sb-row { flex-wrap: wrap; padding: 12px; }
    .nio-sb-main { flex-basis: 100%; order: 3; }
    .nio-sb-split { order: 4; }
    .nio-sb-total { margin-left: auto; }
}

/* ═══════════════════════════════════════════════════════════════════
   Parent portal ("Mijn Logboekje")
   The one mobile-first surface in the app: its own header and bottom tab
   bar instead of the sidebar, so the base rules here are the phone and a
   single min-width query widens the column for tablet and desktop.
   Same tokens and components as everywhere else — only the shell differs.
   ═══════════════════════════════════════════════════════════════════ */
.nio-parent-shell {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    background: var(--nio-canvas);
}

/* ── Header ──────────────────────────────────────────────────────── */
/* Grid, not flex: two equal side columns guarantee the title sits on the header's true
   centre line, regardless of the logo and avatar having different widths. */
.nio-parent-header {
    position: sticky;
    top: 0;
    z-index: 20;
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: var(--nio-gap);
    padding: 10px 16px;
    padding-top: calc(10px + env(safe-area-inset-top));
    background: var(--nio-sidebar-bg);
    border-bottom: 1px solid var(--nio-border);
}

/* Matches .nio-avatar's default (medium) size, so the two ends of the header read as the same weight. */
.nio-parent-logo { height: 36px; width: auto; flex-shrink: 0; justify-self: start; }

.nio-parent-title {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    min-width: 0;
}

.nio-parent-title-main {
    font-size: 1.0rem;
    font-weight: 600;
    color: var(--nio-ink);
    letter-spacing: -0.02em;
    line-height: 1.25;
}

.nio-parent-title-sub {
    display: flex;
    align-items: center;
    gap: 2px;
    font-size: 0.78rem;
    color: var(--nio-text-muted);
    line-height: 1.3;
}

/* The child switcher is a button but reads as the subtitle it replaces. */
.nio-parent-title-switch {
    appearance: none;
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    color: inherit;
    cursor: pointer;
}

.nio-parent-title-switch .mud-icon-root { font-size: 16px; }

/* MudMenu renders its own wrapper around the activator, so the grid item that actually needs
   pinning to the right is this wrapper, not the button inside it. */
.nio-parent-header-end { justify-self: end; }

.nio-parent-profile {
    appearance: none;
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
    flex-shrink: 0;
}

/* ── Body ────────────────────────────────────────────────────────── */
/* Bottom padding clears the fixed tab bar plus the home indicator. */
.nio-parent-body {
    flex: 1;
    padding: 20px 16px calc(76px + env(safe-area-inset-bottom));
}

.nio-parent-h1 {
    font-size: 1.375rem;
    font-weight: 600;
    color: var(--nio-ink);
    letter-spacing: -0.02em;
    line-height: 1.3;
    margin: 0 0 var(--nio-gap-md);
}

.nio-parent-intro {
    font-size: 0.85rem;
    color: var(--nio-text-muted);
    margin: calc(-1 * var(--nio-gap-sm)) 0 var(--nio-gap-md);
}

.nio-parent-filter {
    display: flex;
    align-items: center;
    gap: var(--nio-gap-sm);
    margin-bottom: var(--nio-gap-md);
}

/* ── Tab bar ─────────────────────────────────────────────────────── */
.nio-parent-tabbar {
    position: fixed;
    inset: auto 0 0 0;
    z-index: 20;
    display: flex;
    width: 100%;
    background: var(--nio-sidebar-bg);
    border-top: 1px solid var(--nio-border);
    padding-bottom: env(safe-area-inset-bottom);
}

.nio-parent-tab {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    padding: 10px 4px;
    font-size: 0.7rem;
    font-weight: 500;
    text-decoration: none;
    color: var(--nio-text-muted);
    transition: color var(--nio-transition);
}

.nio-parent-tab .mud-icon-root { font-size: 22px; }

.nio-parent-tab.active {
    color: var(--nio-ink);
    font-weight: 600;
}

.nio-parent-tab.active .mud-icon-root { color: var(--nio-accent); }

/* ── Two figures side by side ────────────────────────────────────── */
/* .nio-stat-grid's minmax(220px) drops to one column on a phone; here the
   two tiles are meant to stay paired at any width. */
.nio-parent-stat-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--nio-gap);
}

.nio-stat-card-compact { padding: 16px; }
.nio-stat-card-compact .nio-stat-value { font-size: 1.6rem; }

/* ── Enrolments on the child card ────────────────────────────────── */
.nio-parent-enrollments {
    display: flex;
    flex-direction: column;
    gap: var(--nio-gap-sm);
    margin-top: 6px;
}

/* Pill above its class/teacher line: on a phone the pair rarely fits side by
   side, and wrapping only some of them reads as a mistake. */
.nio-parent-enrollment {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 3px;
}

/* The child card leads with a block of enrolments, so the avatar tracks the
   name at the top instead of floating to the middle. */
.nio-parent-child-row { align-items: flex-start; }

.nio-parent-enrollment-meta {
    font-size: 0.75rem;
    color: var(--nio-text-muted);
}

/* ── Open sign-offs banner ───────────────────────────────────────── */
/* The one outlined card in the app: it is a call to action, not a surface. */
.nio-parent-alert {
    border: 1px solid color-mix(in srgb, var(--tone, var(--nio-accent)) 45%, transparent);
    background: color-mix(in srgb, var(--tone, var(--nio-accent)) 8%, var(--nio-surface));
}

.nio-parent-alert-text {
    font-size: 0.78rem;
    color: var(--nio-text-muted);
    margin-top: 2px;
}

/* ── Day card ────────────────────────────────────────────────────── */
.nio-parent-day-head {
    display: flex;
    align-items: center;
    gap: var(--nio-gap-sm);
    flex-wrap: wrap;
    margin-bottom: var(--nio-gap);
}

.nio-parent-day-name {
    font-size: 1rem;
    font-weight: 600;
    color: var(--nio-ink);
    text-transform: capitalize;
}

.nio-parent-day-date {
    font-size: 0.85rem;
    color: var(--nio-text-muted);
    margin-left: 6px;
}

/* Each subject the child had that day, separated by a hairline. */
.nio-parent-subject + .nio-parent-subject {
    margin-top: var(--nio-gap);
    padding-top: var(--nio-gap);
    border-top: 1px solid var(--nio-border);
}


.nio-parent-lesson {
    display: flex;
    align-items: baseline;
    gap: var(--nio-gap-sm);
    flex-wrap: wrap;
    margin-top: 6px;
}

.nio-parent-lesson-type {
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--nio-text-faint);
}

.nio-parent-lesson-text {
    font-size: 0.85rem;
    color: var(--nio-text);
}

/* Same specificity as .nio-parent-lesson-text alone, so this needs the extra class to win the
   cascade regardless of stylesheet order. */
.nio-parent-lesson-text.t-red {
    color: var(--tone);
}

.nio-parent-noclass {
    font-size: 0.85rem;
    color: var(--nio-text-muted);
    margin-top: 6px;
}

/* Leervoortgang / Beoordelingen / Huiswerk — a hairline per subsection so a subject block with
   all three doesn't read as one undifferentiated wall of text. */
.nio-parent-subsection {
    margin-top: var(--nio-gap);
    padding-top: var(--nio-gap-sm);
    border-top: 1px solid var(--nio-border);
}

/* ── Ratings row ─────────────────────────────────────────────────── */
.nio-parent-ratings {
    display: flex;
    gap: var(--nio-gap-lg);
    margin-top: var(--nio-gap);
}

.nio-parent-rating {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--nio-gap-xs);
}

.nio-parent-rating-label {
    font-size: 0.66rem;
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--nio-text-faint);
}

.nio-parent-rating-empty {
    font-size: 0.75rem;
    color: var(--nio-text-faint);
    padding: 2px 8px;
}

/* ── Teacher remark ──────────────────────────────────────────────── */
.nio-parent-remark {
    display: flex;
    flex-direction: column;
    gap: 1px;
    margin-top: var(--nio-gap);
    padding: 8px var(--nio-gap);
    border-left: 3px solid var(--tone, var(--nio-border-strong));
    border-radius: 0 var(--nio-radius-sm) var(--nio-radius-sm) 0;
    background: var(--nio-surface-muted);
}

.nio-parent-remark-label {
    font-size: 0.7rem;
    font-weight: 600;
    color: var(--tone, var(--nio-text-muted));
}

.nio-parent-remark-text {
    font-size: 0.85rem;
    color: var(--nio-text);
}

.nio-popover-anchor {
    display: inline-flex;
    position: relative;
}

.nio-popover-content {
    max-width: 260px;
    padding: 10px 14px;
    border-radius: var(--nio-radius-sm);
    background: var(--nio-ink);
    color: var(--nio-surface);
    font-size: 0.85rem;
    box-shadow: var(--nio-shadow-pop);
}

/* ── Parent's own row: note + paraaf ─────────────────────────────── */
.nio-parent-note { margin-top: var(--nio-gap-md); }

.nio-parent-day-actions {
    display: flex;
    align-items: center;
    gap: var(--nio-gap-sm);
    flex-wrap: wrap;
    margin-top: var(--nio-gap);
}

/* ── Tablet and up ───────────────────────────────────────────────── */
/* The portal stays a single column — it is designed for the phone; on a
   wider screen it centres rather than stretching. */
@media (min-width: 700px) {
    .nio-parent-header { padding: 12px 24px; }

    .nio-parent-body {
        width: 100%;
        max-width: 620px;
        margin: 0 auto;
        padding: 28px 24px 48px;
    }

    /* Chrome, not content: stays full-bleed like the header, unlike .nio-parent-body which
       narrows for readability. Sticky (not fixed) so it sits right under short content
       instead of floating detached over empty space, only glueing to the viewport bottom
       once you scroll past it. */
    .nio-parent-tabbar {
        position: sticky;
        inset: auto 0 0 0;
        width: 100%;
        border-top: 1px solid var(--nio-border);
    }
}

/* Role badge under the avatar row on the parent profile page. */
.nio-parent-role-badge { margin-top: var(--nio-gap); }

/* ── Reconnect overlay ──────────────────────────────────────────────────────
   Blazor toggles these classes on #components-reconnect-modal when the circuit
   drops. All of the show/hide logic is CSS, so the overlay still works at the
   moment the circuit — and with it every interactive component — is gone. */

#components-reconnect-modal {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 20000;
    align-items: center;
    justify-content: center;
    background: color-mix(in srgb, var(--nio-ink) 45%, transparent);
}

#components-reconnect-modal.components-reconnect-show,
#components-reconnect-modal.components-reconnect-failed,
#components-reconnect-modal.components-reconnect-rejoin-failed {
    display: flex;
}

#components-reconnect-modal.components-reconnect-hide,
#components-reconnect-modal.components-reconnect-rejoined {
    display: none;
}

.components-reconnect-container {
    min-width: 280px;
    max-width: 360px;
    padding: 28px 24px;
    text-align: center;
    background: var(--nio-surface);
    border: 1px solid var(--nio-border);
    border-radius: var(--nio-radius-lg);
}

.components-reconnect-container p {
    margin: 0;
    font-size: 0.9rem;
    color: var(--nio-text);
}

#components-reconnect-button {
    margin-top: 16px;
    padding: 9px 18px;
    background: var(--nio-accent);
    color: #ffffff;
    border: 1px solid var(--nio-accent);
    border-radius: var(--nio-radius);
    font: inherit;
    font-size: 0.875rem;
    cursor: pointer;
}

/* Which line is visible depends on which stage Blazor has reached. */
.components-reconnect-first-attempt-visible,
.components-reconnect-repeated-attempt-visible,
.components-reconnect-failed-visible { display: none; }

.components-reconnect-show .components-reconnect-first-attempt-visible { display: block; }
.components-reconnect-failed .components-reconnect-failed-visible,
.components-reconnect-rejoin-failed .components-reconnect-failed-visible { display: block; }
#components-reconnect-modal.components-reconnect-failed .components-reconnect-first-attempt-visible,
#components-reconnect-modal.components-reconnect-rejoin-failed .components-reconnect-first-attempt-visible { display: none; }

button#components-reconnect-button.components-reconnect-failed-visible { display: none; }
.components-reconnect-failed button#components-reconnect-button,
.components-reconnect-rejoin-failed button#components-reconnect-button { display: inline-block; }

/* Two dots pulsing while a rejoin is in flight. */
.components-rejoining-animation {
    display: flex;
    gap: 8px;
    justify-content: center;
    margin-bottom: 16px;
}

.components-rejoining-animation div {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--nio-accent);
    animation: nio-rejoin-pulse 1.2s ease-in-out infinite;
}

.components-rejoining-animation div:last-child { animation-delay: 0.4s; }

@keyframes nio-rejoin-pulse {
    0%, 100% { opacity: 0.25; transform: scale(0.85); }
    50%      { opacity: 1;    transform: scale(1); }
}

@media (prefers-reduced-motion: reduce) {
    .components-rejoining-animation div { animation: none; opacity: 0.6; }
}

/* ═══════════════════════════════════════════════════════════════════
   Phone layer
   Everything above bottoms out at the 959px tablet rule; this is the
   step below it. Last in the file on purpose: these rules override
   same-specificity 959px ones, which also match at this width, and
   source order is what decides between them.
   The parent portal is exempt — it is mobile-first already and scoped
   to its own .nio-parent-* selectors.
   ═══════════════════════════════════════════════════════════════════ */
@media (max-width: 599px) {
    .nio-page { padding: 16px 12px 40px; }

    /* Mirrors .nio-page exactly — the negative margins are what let the header
       bleed to the page edges, so the two must move together. */
    .nio-sticky-header {
        margin: -16px -12px 12px;
        padding: 12px 12px 0;
    }

    .nio-card,
    .nio-stat-card,
    .nio-empty { padding: 14px; }

    /* Four StatCards sit two-up here. Between the padding and the 44px icon box
       a label like "Aanwezigheidspercentage" has nowhere to go, so give it room. */
    .nio-stat-card { gap: var(--nio-gap-sm); }
    .nio-stat-value { font-size: 1.25rem; }

    /* Three or four metrics in one row do not fit; wrapping beats truncating. */
    .nio-metric-row { flex-wrap: wrap; }

    /* Both caps leave the control narrower than the card it sits in, which on a
       phone only costs tap area. */
    .nio-date-input { max-width: none; }
    .nio-toolbar-alert { flex-basis: 100%; }

    /* MudChart is a flex box with min-width: fit-content, so a donut plus seven attendance
       labels simply refuses to shrink and pushes the card sideways. Letting it shrink is the
       actual fix; the column direction just guarantees the legend-bottom layout even for a
       chart configured with a side legend. */
    .mud-chart {
        flex-direction: column;
        min-width: 0;
    }

    .mud-chart .mud-chart-legend {
        order: 3;
        width: 100%;
        margin: 10px 0 0;
        justify-content: center;
    }

    /* 40px (34px in the compact row) is a comfortable mouse target and a poor thumb one.
       These pickers are what a teacher taps all lesson long, so give them the 44px that
       both platform guidelines ask for. */
    .nio-choice,
    .nio-choice-categories-compact .nio-choice { min-height: 44px; }

    .nio-confetti-piece { --dx-scale: 0.5; }

    /* FullWidth dialogs are calc(100% - 64px) and the content another 24px each side, which
       leaves a phone under 280px of usable form. Buy most of that back. */
    .mud-dialog-width-full { width: calc(100% - 24px); }
    .mud-dialog-width-false { max-width: calc(100% - 24px); }
    .mud-dialog .mud-dialog-title { padding: 14px 16px; }
    .mud-dialog .mud-dialog-content { padding: 8px 16px; }

    /* The awards carry their explanation in a MudTooltip, which a touch screen has no way to
       trigger. Print it instead — it is the only copy of that text. */
    .nio-award-hint { display: block; }
}
