html, body {
    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

h1:focus {
    outline: none;
}

#blazor-error-ui {
    color-scheme: light only;
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

    #blazor-error-ui .dismiss {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

.loading-progress {
    position: absolute;
    display: block;
    width: 8rem;
    height: 8rem;
    inset: 20vh 0 auto 0;
    margin: 0 auto 0 auto;
}

    /* The boot spinner was still the Blazor template's own colours — a grey track and #1b6ec2 blue, never
       themed by anyone. It renders BEFORE the app exists, so it is the first colour a visitor sees, and a blue
       ring in front of a teal product reads as a page that has not finished loading its stylesheet.
       tokens.generated.css is linked ahead of this file in index.html, so the variables resolve here. */
    .loading-progress circle {
        fill: none;
        stroke: var(--sa-hairline);
        stroke-width: 0.6rem;
        transform-origin: 50% 50%;
        transform: rotate(-90deg);
    }

        .loading-progress circle:last-child {
            stroke: var(--sa-accent);
            stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
            transition: stroke-dasharray 0.05s ease-in-out;
        }

.loading-progress-text {
    position: absolute;
    text-align: center;
    color: var(--sa-text-secondary);
    font-weight: 600;
    inset: calc(20vh + 3.25rem) 0 auto 0.2rem;
}

    .loading-progress-text:after {
        content: var(--blazor-load-percentage-text, "Loading");
    }

/* Drag-and-drop upload feedback (ADR "Drag-and-drop document upload" / "Intray file-list drop-zone"). A JS
   handler toggles .drop-target-active on the hovered drop target. */
.drop-target-active {
    outline: 2px dashed var(--sa-accent);
    outline-offset: -3px;
    background: rgba(91, 78, 229, 0.06);
}

/* The intray file-list is itself a drop-zone; a persistent hint sits above the items. */
.wb-intray-drop {
    position: relative;
}

.wb-intray-drophint {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px 10px;
    margin-bottom: 4px;
    font-size: 0.8rem;
    color: var(--mud-palette-text-secondary, #9aa0a6);
    border: 1px dashed rgba(128, 128, 128, 0.4);
    border-radius: 6px;
}

/* ── Selection and the active tab (ADR 0578) ───────────────────────────────────────────────────────────────
   Here rather than in Home.razor's style block: these are global classes that a dozen components apply, so
   they are not the workbench SHELL's markup — and the shell is being decomposed (ADR 0558), which means it may
   only get smaller.

   A selected row is a tint with a 2px leading accent edge, never a fill. A solid row overwrites the row's own
   colours, so the folder gold, the signed badge and the document glyph all disappear at exactly the moment the
   user is looking hardest at that row. box-shadow rather than border-left, so nothing shifts by 2px.

   The active tab is an accent underline for the same family of reason: a filled block makes the current tab
   the loudest thing on screen for a fact the user already knows, and competes with the primary action for the
   one colour that should draw the eye. Both mirror the desktop client (ADR 0511). */
.wb-list-row-selected { background: var(--sa-selection); box-shadow: inset 2px 0 0 0 var(--sa-accent); }
.wb-list-row-selected:hover { background: var(--sa-accent-tint); }
.wb-tab-active { color: var(--sa-accent-text); box-shadow: inset 0 -2px 0 0 var(--sa-accent); }

/* ── Toolbar buttons are icons on a pointer, icon + label on touch ─────────────────────────────────────────
   Moved here from Home.razor's style block when every tab started using it, not just Repositories: the shell
   is being decomposed (ADR 0558) and may only get smaller, and a rule a dozen components apply is not the
   shell's markup.

   The label lives in the button as .wb-rib-label and in `title` + `aria-label`, so hiding it costs nothing a
   mouse user cannot get back by hovering — and costs a screen reader nothing at all, because aria-label is
   what computes the accessible name either way.

   The query is `(hover: hover) and (pointer: fine)`, not a width breakpoint: the question is whether this
   person has a hover to reveal a tooltip with, and that is a property of the input device, not the window
   (ADR 0491). A touch user keeps the visible label, because for them a tooltip does not exist. */
.wb-rib-btn .wb-rib-label { margin-left: 6px; }

@media (hover: hover) and (pointer: fine) {
    .wb-rib-btn .wb-rib-label { display: none; }

    /* With the label gone the button is nothing but its icon, so it takes the icon's own footprint: a 26px
       circle — exactly the MudIconButton the toggles beside it already are. Left as a 30×28 rounded rect it
       sat next to those circles as a visibly different KIND of button, which is what "some buttons are still
       old style" was: not a size difference (every glyph is 20px) but two shapes in one row. A toolbar is one
       row of one button.

       Only under this query: on touch the label is visible, and a labelled control is a pill, not a circle. */
    .wb-rib-btn { min-width: 0; width: 26px; height: 26px; padding: 0; border-radius: 50%; }

    /* Affordances that exist only because touch has no modifier keys — a list's multi-select checkbox column.
       On a device that can Ctrl-click, the list multi-selects natively and the column is a second way to do
       one thing, taking width from every row to say so. Same query, same reason as the labels above. */
    .wb-touch-only { display: none; }
}

/* Month grid (#660). A list answers "what is coming up"; the grid answers "what does this month look like".
   Sized in fr/minmax rather than fixed pixels so it fills the pane the user dragged, and the row height is
   fixed so paging to another month does not change the grid's height under the cursor. */
.wb-cal-month { display: flex; flex-direction: column; height: 100%; min-height: 0; }
.wb-cal-monthbar { display: flex; align-items: center; gap: .25rem; padding: .35rem .5rem;
    border-bottom: 1px solid var(--mud-palette-lines-default); }
.wb-cal-monthname { font-weight: 600; min-width: 11ch; text-align: center; }
.wb-cal-grid { flex: 1 1 auto; min-height: 0; display: grid; grid-template-columns: repeat(7, minmax(0, 1fr));
    /* auto for the weekday header, then six EQUAL week rows. grid-auto-rows would have sized the header as a
       seventh row and given it a full week's height. */
    grid-template-rows: auto repeat(6, minmax(0, 1fr)); overflow: auto; }
.wb-cal-dow { grid-row: 1; padding: .2rem .4rem; font-size: .75rem; text-transform: uppercase;
    letter-spacing: .04em; color: var(--sa-text-secondary); border-bottom: 1px solid var(--mud-palette-lines-default); }
.wb-cal-day { border-right: 1px solid var(--mud-palette-lines-default);
    border-bottom: 1px solid var(--mud-palette-lines-default); padding: .15rem .2rem; overflow: hidden;
    display: flex; flex-direction: column; gap: 1px; }
.wb-cal-daynum { font-size: .75rem; color: var(--sa-text-secondary); font-variant-numeric: tabular-nums; }
/* The days either side of the month are shown so the weeks stay whole, but they are context, not content. */
.wb-cal-outside { opacity: .45; }
.wb-cal-today .wb-cal-daynum { font-weight: 700; color: var(--sa-accent-text); }
.wb-cal-entry { display: flex; align-items: center; gap: .25rem; padding: 0 .15rem; border-radius: 3px;
    font-size: .78rem; white-space: nowrap; overflow: hidden; cursor: pointer; }
.wb-cal-entry:hover { background: var(--sa-accent-tint); }
.wb-cal-entry-sel { background: var(--sa-selection); box-shadow: inset 2px 0 0 0 var(--sa-accent); }
/* A day the entry runs THROUGH rather than starts on: the flattened left edge reads as "carried in from the
   cell before", which is the one thing a chip-per-day layout cannot say by position alone. */
.wb-cal-entry-cont { border-top-left-radius: 0; border-bottom-left-radius: 0; }
.wb-cal-cont-mark { letter-spacing: -.05em; }
/* The repeat marker. Muted and last in the row: it qualifies the entry rather than identifying it, so it must
   not compete with the title for the eye — and it must not be the accent, which on this row already means
   "which calendar" (ADR 0581). */
.wb-cal-repeat { flex: 0 0 auto; color: var(--sa-text-secondary); font-size: .7rem; }

/* A contact's face, or its initials. ONE neutral background, never a hue derived from the name: every row here
   already carries a collection swatch, and colour that encodes identity cannot also be decoration (ADR 0581). */
.wb-avatar { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
    width: 2.25rem; height: 2.25rem; border-radius: 50%; overflow: hidden;
    background: var(--mud-palette-lines-default, #e6e7ec); color: var(--mud-palette-text-primary, #14161c);
    font-size: .8rem; font-weight: 600; line-height: 1; user-select: none; }
.wb-avatar-sm { width: 1.5rem; height: 1.5rem; font-size: .6rem; }
/* object-fit: cover, so a portrait or a panorama both fill the circle instead of stretching a face. */
.wb-avatar img { width: 100%; height: 100%; object-fit: cover; }
.wb-cal-dot { flex: 0 0 auto; width: 7px; height: 7px; border-radius: 4px; }
.wb-cal-time { flex: 0 0 auto; color: var(--sa-text-secondary); font-variant-numeric: tabular-nums; }
.wb-cal-title { overflow: hidden; text-overflow: ellipsis; }
.wb-cal-more { font-size: .72rem; color: var(--sa-accent-text); cursor: pointer; padding: 0 .15rem; }
.wb-cal-more:hover { text-decoration: underline; }
