/* The web app's own styles, alongside MudBlazor's controls in OSE's company theme (PBI 2673). The theme (ThemeService)
   sets the colours, fonts, buttons, fields, tables and alerts; this file has the OSE portal's layout (sidebar and top
   bar, with OSE's genuine logo and kicker from PBI 2662), the font files, the page widths, spacing for the plain text
   that MudBlazor's reset strips, and the viewer's frame. Everything is served from this site (fonts/, brand/), as the
   security policy allows no other source. The engineer's model in the viewer is a separate, sandboxed page and isn't
   touched. */

/* Crete Round and Inter, from the OSE brand toolkit (SIL Open Font License; see docs/Brand-Assets.md): WOFF2 copies
   (under half the size; App.razor preloads the two most used), with the original TrueType files for a browser that
   can't use them. The theme asks for these by name; the weights here are the ones it uses. */
@font-face { font-family: "Crete Round"; src: url("fonts/CreteRound-Regular.woff2") format("woff2"), url("fonts/CreteRound-Regular.ttf") format("truetype"); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: "Crete Round"; src: url("fonts/CreteRound-Italic.woff2") format("woff2"), url("fonts/CreteRound-Italic.ttf") format("truetype"); font-weight: 400; font-style: italic; font-display: swap; }
@font-face { font-family: "Inter"; src: url("fonts/Inter-Regular.woff2") format("woff2"), url("fonts/Inter-Regular.ttf") format("truetype"); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: "Inter"; src: url("fonts/Inter-SemiBold.woff2") format("woff2"), url("fonts/Inter-SemiBold.ttf") format("truetype"); font-weight: 600; font-style: normal; font-display: swap; }
@font-face { font-family: "Inter"; src: url("fonts/Inter-Bold.woff2") format("woff2"), url("fonts/Inter-Bold.ttf") format("truetype"); font-weight: 700; font-style: normal; font-display: swap; }

:root {
    /* OSE's lime, for the kicker's separators only: too pale for text. */
    --lime: #c7d300;
    /* OSE's hairline, under page titles and the viewer's bar. */
    --line: #dce0e6;
    /* OSE's row grey, behind the setup link and code. */
    --row-grey: #f2f2f2;
}

/* The layout, as the OSE portal's (its MainLayout and NavMenu styles): on a phone the sidebar sits above the page; from
   641px wide it's a 250px column the height of the window, beside a top bar that stays put as the page scrolls. The
   theme gives the colours (the sidebar is its primary colour), text colour and font. */
.page { position: relative; display: flex; flex-direction: column; min-height: 100vh; }
.sidebar { background-color: var(--mud-palette-primary); display: flex; flex-direction: column; overflow-y: auto; }
/* OSE's genuine logo on a white strip at the top of the sidebar, level with the top bar. */
.sidebar-brand { display: flex; align-items: center; height: var(--mud-appbar-height); padding: 0 16px; background-color: var(--mud-palette-surface); border-bottom: 1px solid var(--mud-palette-lines-default); flex-shrink: 0; }
.sidebar-brand .brand { display: inline-block; line-height: 0; }
.sidebar-brand .brand img { width: auto; }
.main { flex: 1; display: flex; flex-direction: column; min-width: 0; }
.top-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; height: var(--mud-appbar-height); padding: 0 1.5rem 0 2rem; background-color: var(--mud-palette-surface); border-bottom: 1px solid var(--mud-palette-lines-default); }
.content { flex: 1; padding: 0 1.5rem 0 2rem; }
/* Who's signed in and Sign out, at the right of the top bar. */
.account { display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; }
@media (min-width: 641px) {
    .page { flex-direction: row; }
    .sidebar { width: 250px; height: 100vh; position: sticky; top: 0; }
    .top-row { position: sticky; top: 0; z-index: 1; }
}
@media (max-width: 640px) {
    .top-row { padding: 0 16px; }
    .top-row .kicker { display: none; }
    .content { padding: 0 8px; }
}

/* The router focuses the heading on navigation, for screen readers; it needs no visible ring. */
h1:focus { outline: none; }

/* MudBlazor's reset takes the spacing off everything; the pages' own text gets it back. */
main p, main ul, main ol, main pre { margin-bottom: 12px; }
main ul, main ol { padding-left: 1.5em; }
main li { margin-bottom: 4px; }
main strong { font-weight: 600; }
code { font-family: Consolas, "Courier New", monospace; font-size: .95em; }
/* Section headings on the long pages: room above, a little below. */
main h2.mud-typography { margin: 32px 0 12px; }
main h3.mud-typography { margin: 24px 0 8px; }

/* A page's title, with OSE's thin hairline beneath it as on their content pages: on its own, or in a bar with
   something beside it (the admin page's role). */
main > h1, main > header.bar { border-bottom: 1px solid var(--line); padding-bottom: 10px; margin-bottom: 18px; }
.bar { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px; }

/* OSE's kicker, at the left of the top bar. */
.kicker { font-size: .72rem; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--mud-palette-text-primary); }
.kicker .sep { color: var(--lime); margin: 0 .25em; }
/* The viewer's not-found message brings its own logo, as the viewer's layout has no sidebar. */
.site-header { display: flex; align-items: center; padding: 18px 32px 0; }
.site-header .brand { display: inline-block; line-height: 0; }
.site-header .brand img { height: 48px; width: auto; }

.narrow { max-width: 520px; width: 100%; margin: 40px auto 0; padding: 0 16px; }
.wide { max-width: 1200px; width: 100%; margin: 28px auto 48px; padding: 0 24px; }
/* Get started (PBI 2657): reading width and numbered steps. */
.guide { max-width: 760px; width: 100%; margin: 28px auto 48px; padding: 0 24px; }
.guide .steps > li { margin-bottom: 14px; }
.guide .steps h2.mud-typography { margin: 18px 0 4px; }

.muted { color: var(--mud-palette-text-secondary); }

/* The sign-in pages' forms: fields and buttons one under another. */
form { display: grid; gap: 16px; margin: 16px 0; }
form.inline { display: inline; margin: 0; }
form .mud-button-root { justify-self: start; }
/* "Email me a code", "send another code": a button within a sentence, so it reads as part of it. */
.alternative { display: block; margin: 8px 0; }
.mud-button-root.in-text { text-transform: none; padding: 0 4px; min-width: 0; vertical-align: baseline; font-size: inherit; text-decoration: underline; }

/* A row of controls: choices, fields and their button. */
.row { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; margin-bottom: 12px; }
/* MudBlazor's fields and choices take the row's full width unless told otherwise. A choice's own Class lands inside its
   wrapper, so choices are sized by the wrapper (.mud-select); fields by the class they're given. */
.row > .mud-select { flex: 0 1 320px; }
.row > .field { flex: 0 1 260px; }
/* Room for several emails (Grant access, PBI 2676). */
.row > .field.wide { flex: 0 1 420px; }
/* A date filter's time (DateTimeField, PBI 2676): a field that opens a calendar and clock, with Clear, Cancel and Done
   under them. */
.row > .date-time-field { flex: 0 1 240px; }
.date-time-field input { cursor: pointer; }
.date-time-picker .pickers { display: flex; flex-wrap: wrap; gap: 8px; }
.date-time-picker .actions { display: flex; justify-content: flex-end; gap: 8px; padding: 8px 12px 12px; }
.row .mud-input-control { margin-top: 0; }

/* The admin page's tables: a row's buttons together, at its end for Rename and Delete (PBIs 2656, 2676). MudBlazor
   keeps a table cell a table cell, so they're spaced by margins, which also space them when they wrap. */
td.actions > * { margin: 2px 8px 2px 0; }
td.actions.end { text-align: right; }
td.actions.end > * { margin: 2px 0 2px 8px; }
/* A choice or field opened in a row (Move, Rename, Edit, PBI 2676): wide enough to read, however narrow its column. */
td .mud-select, td .mud-input-control { min-width: 220px; }
.mud-simple-table.small td { font-size: 12.5px; }
.notices { margin: 8px 0 16px; }
.notices > * + * { margin-top: 8px; }
/* A notice with a line per email, when Grant access was given several (PBI 2676). */
.notice.lines .mud-alert-message { white-space: pre-line; }
/* Who last published a version, under its status (PBI 2661). */
.byline { display: block; margin-top: 4px; font-size: .85em; color: var(--mud-palette-text-secondary); }
.mud-alert ul { margin: 4px 0 8px; }

/* The admin page's tabs (PBI 2676): a hairline under the tab names, and each tab's first heading close below them. */
.admin-tabs .mud-tabs-tabbar { border-bottom: 1px solid var(--line); }
.admin-tabs [role=tabpanel] > h2.mud-typography:first-of-type { margin-top: 8px; }
/* A section that can be hidden (CollapsibleSection.razor): its heading is the button, so it looks like the other
   headings, with an arrow before it, and shows it can be clicked on hover and with the keyboard. */
.collapsible-heading button {
    display: inline-flex; align-items: center; gap: 4px; padding: 2px 6px 2px 0; margin-left: -4px;
    font: inherit; color: inherit; background: none; border: 0; border-radius: 4px; cursor: pointer;
}
.collapsible-heading button:hover { color: var(--mud-palette-primary); }
.collapsible-heading button:focus-visible { outline: 2px solid var(--mud-palette-primary); outline-offset: 2px; }
/* Page buttons under a list, at its right. */
.list-pager { display: flex; justify-content: flex-end; margin-top: 8px; }

/* Column widths staff drag (wwwroot/admin.js, PBI 2676): a handle at each header's right edge, drawn as a
   short divider that darkens on hover. Once sized, a table is as wide as its columns and wraps long text (emails, ids)
   inside them, scrolling sideways when they need more room than the page has. */
[data-columns] th { position: relative; }
[data-columns] th::after {
    content: ""; position: absolute; top: 0; right: 0; bottom: 0; width: 8px; cursor: col-resize;
    background: linear-gradient(var(--mud-palette-lines-default), var(--mud-palette-lines-default)) right center / 1px 50% no-repeat;
}
[data-columns] th:hover::after {
    background-image: linear-gradient(var(--mud-palette-primary), var(--mud-palette-primary)); background-size: 2px 100%;
}
[data-columns] .mud-table-container { overflow-x: auto; }
table[data-sized] { table-layout: fixed; }
table[data-sized] :is(th, td) { overflow-wrap: anywhere; }
/* While dragging, the resize cursor everywhere and no text selected, even off the header. */
.resizing-columns, .resizing-columns * { cursor: col-resize !important; user-select: none; }

/* A client's models: each a card in the theme's colours, the whole card the link. */
.cards { list-style: none; padding: 0; display: grid; gap: 10px; }
.cards a { display: block; background: var(--mud-palette-surface); padding: 14px 16px; border-radius: var(--mud-default-borderradius); border: 1px solid var(--mud-palette-lines-default); border-left: 4px solid var(--mud-palette-primary); font-weight: 600; color: var(--mud-palette-primary); }
.cards a:hover { border-color: var(--mud-palette-primary); }
/* Version reference under the project name, e.g. "Version 3, 21 Oct 2026 14:32". */
.cards .reference { display: block; margin-top: 4px; font-size: .85em; font-weight: 400; color: var(--mud-palette-text-secondary); }

/* A setup link to copy, and the key an authenticator can take instead of the QR code. */
pre.token { background: var(--row-grey); padding: 8px; border: 1px solid var(--line); border-radius: var(--mud-default-borderradius); overflow-x: auto; }
/* Authenticator setup: the QR code on a white background (scanners need contrast). */
.qr svg { width: 220px; height: 220px; background: #fff; padding: 8px; border: 1px solid var(--line); border-radius: 6px; margin-bottom: 12px; }
code.key { font-size: 1.05em; letter-spacing: .05em; white-space: nowrap; }

/* The viewer: OSE's bar (logo, Back, the model's name and reference) above the model's sandboxed frame. */
.frame { display: grid; grid-template-rows: auto 1fr; height: 100vh; }
/* It wraps on a narrow screen rather than running off the edge; the model's frame takes what height is left. */
.frame-bar { display: flex; flex-wrap: wrap; gap: 6px 16px; align-items: center; padding: 8px 16px; background: var(--mud-palette-surface); border-bottom: 1px solid var(--line); font-size: 14px; }
.frame-bar .brand { height: 30px; width: auto; }
.frame-body { position: relative; overflow: hidden; }
.frame-body iframe { width: 100%; height: 100%; border: 0; display: block; }
.watermark { position: absolute; inset: -50%; pointer-events: none; display: flex; flex-wrap: wrap; gap: 80px 120px; transform: rotate(-24deg); opacity: .08; font-size: 14px; user-select: none; color: #000; }

/* Blazor's bar for an unhandled error, hidden until Blazor shows it; here rather than in one layout, as both layouts use it. */
#blazor-error-ui { display: none; position: fixed; bottom: 0; left: 0; width: 100%; z-index: 1000; padding: .6rem 1.25rem .7rem; background: lightyellow; box-shadow: 0 -1px 2px rgba(0, 0, 0, .2); color-scheme: light only; }
#blazor-error-ui .dismiss { cursor: pointer; position: absolute; right: .75rem; top: .5rem; }
