/*
  Application-wide element styles. Everything here reads its values from theme.css; nothing here
  declares a colour or a size of its own. Component-specific rules belong in that component's
  scoped `.razor.css` file instead.
*/

html {
	box-sizing: border-box;
}

*, *::before, *::after {
	box-sizing: inherit;
}

body {
	margin: 0;
	background-color: var(--colour-canvas);
	color: var(--colour-text);
	font-family: var(--font-body);
	font-size: var(--font-size-body);
	line-height: 1.5;
	/*
	  The shell (.app-shell, in MainLayout.razor.css) is `position: fixed; inset: 0`, which sizes it
	  from the viewport directly rather than from an ancestor's height — the html/body/#app chain
	  never needs `height: 100%` at all, and so never breaks when one link in that chain is
	  forgotten. Scrolling then belongs to the shell's own regions (the drawer, the content area),
	  not to the page; this is the backstop against anything that would otherwise scroll behind them.
	*/
	overflow: hidden;
}

h1 {
	font-size: var(--font-size-heading);
	margin-top: 0;
}

/*
  The router moves focus to the heading on every navigation, and the outline is noise there.
  Qualified with the attribute rather than left as a bare `h1:focus`, because suppressing a focus
  ring is only defensible for focus nobody asked for: `FocusOnNavigate` renders `tabindex="-1"`,
  so this heading can be focused programmatically and never by tabbing to it. A heading that is
  ever made keyboard-reachable falls outside this selector and keeps its ring.
*/
h1[tabindex="-1"]:focus {
	outline: none;
}

a {
	color: var(--colour-accent);
}

/*
  The content area (.content-area, in MainLayout.razor.css) is full bleed by default, because the
  map it will hold in #92 has to be. A page that is not the map — everything today, and every form
  and list page still to come — opts into this instead of getting it for free, which is what keeps
  full bleed from being the thing every later page has to fight.

  The top padding is wider than the others: it clears the drawer toggle, which is fixed in the same
  corner regardless of what .content-area holds. --content-clearance (theme.css) is shared with the
  drawer's own top padding, so the one thing that must clear the toggle in both places moves as one.

  The left margin at a desktop width is not simply `auto`, and that is a fix rather than the
  original design (task 172): centring --layout-max-width (60rem) with a plain `margin: 0 auto`
  gives a left margin of only (viewport − 60rem) / 2, which is *less* than --drawer-width (20rem)
  at every viewport under 100rem — nearly every laptop screen, including Playwright's own default —
  so a page relying on centring alone to clear the drawer does not, in fact, clear it. The drawer
  defaults open at exactly this same breakpoint (Drawer.razor.cs's own WideViewportQuery), so at
  first render on a desktop-width viewport the two overlap by construction. `max()` guarantees the
  left margin is never less than --drawer-width regardless of how the centring math comes out;
  right stays a genuine `auto` so a viewport wide enough for the naive centred margin to already
  clear the drawer on its own renders exactly as it always did — nothing changes once the drawer's
  own width is no longer the binding constraint. This is a *static* guarantee, not one that reacts
  to the drawer's own open/closed state — this class carries no Blazor state — so a page rendered
  this way keeps its reserved space even after the reader manually closes the drawer, on purpose:
  the drawer is an overlay that never pushes content around when it opens or closes (Rob's
  direction, ADR-0059), and reserving space unconditionally at the breakpoint where the drawer
  *defaults* open is the only way to guarantee day-one clickability without adding a second,
  reflowing layout this class would otherwise need Blazor state to drive.
*/
.page-content {
	max-width: var(--layout-max-width);
	margin: 0 auto;
	padding: var(--content-clearance) var(--space-large) var(--space-large);
}

@media (min-width: 64rem) {
	.page-content {
		margin-left: max(var(--drawer-width), calc((100% - var(--layout-max-width)) / 2));
		margin-right: auto;
	}
}

/*
  Text for screen readers that should not be seen. `display: none` and `visibility: hidden` both
  take the text out of the accessibility tree as well, which is the opposite of what this is for.
*/
.visually-hidden {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/*
  Both blocks below are styling for markup that lives in index.html rather than in a component:
  the boot-time progress ring, and the banner Blazor unhides when an unhandled error reaches it.
  Neither has a component to be scoped to, which is why they are global.

  Their dimensions are literals. They draw one fixed thing that appears nowhere else and belongs
  to no scale, so a token per value would be bookkeeping rather than theming — ADR-0027 exempts
  exactly this and no colour.
*/

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

.loading-progress circle {
	fill: none;
	stroke: var(--colour-border);
	stroke-width: 0.6rem;
	transform-origin: 50% 50%;
	transform: rotate(-90deg);
}

.loading-progress circle:last-child {
	stroke: var(--colour-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;
	font-weight: bold;
	inset: calc(20vh + 3.25rem) 0 auto 0.2rem;
}

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

#blazor-error-ui {
	display: none;
	position: fixed;
	bottom: 0;
	left: 0;
	width: 100%;
	padding: var(--space-small) var(--space-medium);
	background: var(--colour-surface);
	color: var(--colour-text);
	border-top: 1px solid var(--colour-border);
	z-index: 1000;
}

/*
  Task 139: a <button>, not the template's original <span>, so Enter and Space dismiss it as well
  as a click — a span is never part of the browser's own tab order or its Enter/Space-to-click
  mapping, and no amount of CSS or a bare click handler gives it either.

  The pointer cursor is honest despite the button being unhidden and inert most of the time, which
  is worth stating because checking it the obvious way says otherwise. Blazor wires the click
  handler lazily, inside the same function that unhides the banner, so a banner revealed by hand
  for inspection has no listener on it and a click does nothing — measured, and misleading. Trigger
  a real unhandled error and the handler is attached and a click (or Enter, or Space) dismisses it.
*/
#blazor-error-ui .dismiss {
	position: absolute;
	right: var(--space-medium);
	top: var(--space-small);
	font: inherit;
	color: inherit;
	background: none;
	border: none;
	padding: 0;
	cursor: pointer;
}
