/*
 * Base styles: reset, typography, and layout primitives. Values come from
 * tokens.css only — never a literal colour, size, or radius here.
 *
 * The header and the content column moved into base.html as the prototype's
 * utility classes (ADR-020, issue 131). The floating menu did NOT: it keeps the
 * design of #74 by PM decision, and its rules are below, unchanged.
 */

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

html {
  -webkit-text-size-adjust: 100%;
  /* Reserve the scrollbar's width even on a page that does not scroll: opening
     a dialog locks the page (.u-modal-open), and without the reserved gutter
     every screen would jump sideways by the scrollbar's width as it opens. */
  scrollbar-gutter: stable;
}

/* The page behind an open dialog does not scroll. Set by components/modal_base.html
   while a modal is on screen: without it a flick over the backdrop scrolls the
   page under the dialog — and on macOS the elastic bounce drags the fixed
   overlay with it, which is the empty frame that flashes at the edge. */
.u-modal-open {
  overflow: hidden;
}

/* The page is the prototype's slate --background; every raised surface (header,
   nav, modal, card, input) is white. Before the re-seed both were the same white,
   so this is the one rule that has to name the palette directly. */
/* Lets `height: auto` be an animation endpoint (.c-collapse, components.css).
   A browser without it ignores the property and arrives instantly instead —
   the same jump the screens have today, never a broken layout. */
:root {
  interpolate-size: allow-keywords;
}

body {
  margin: var(--space-none);
  background-color: var(--page-bg);
  color: var(--foreground);
  font-family: var(--font-family-base);
  font-size: var(--font-size-body1);
  font-weight: var(--font-weight-regular);
  line-height: var(--line-height-body1);
}

h1,
h2,
h3,
h4,
p,
figure,
blockquote,
dl,
dd {
  margin: var(--space-none);
}

ul,
ol {
  margin: var(--space-none);
  padding: var(--space-none);
  list-style: none;
}

img,
svg,
canvas {
  display: block;
  max-width: 100%;
}

/* …except the math. MathJax (ADR-022) renders a formula as an <svg> inside <mjx-container>, so
   the reset above turns inline math into a block: 「(1) $P_n$ の式を…」 breaks into three lines,
   one per fragment. `max-width` goes with it — an SVG SCALES, so 100% would shrink a long formula
   until it is unreadable instead of letting the element around it scroll. Written here, beside
   the rule it excepts, because that is where the next person looks for why an svg is a block. */
mjx-container svg {
  display: inline;
  max-width: none;
}

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

table {
  border-collapse: collapse;
}

code,
kbd,
samp {
  font-family: var(--font-family-mono);
  font-size: var(--font-size-caption1);
}

:focus-visible {
  outline: var(--border-width-thick) solid var(--focus-ring);
  outline-offset: var(--border-width-thin);
}

/* The heading ramp, one rung down the scale from the sizes that shipped (#216).
   The ramp itself is untouched — tokens.css is Fluent's scale and a screen that
   wants 32px still has --font-size-title1. What changed is which rung a heading
   ELEMENT takes: on a roster or a score table the body text is 14px, and an h1
   at 32px was more than twice it, which read as a poster over a spreadsheet.
   Every step still differs from its neighbour, so the hierarchy survives the
   move; only its loudest end came down. */
h1 {
  font-size: var(--font-size-title3);
  line-height: var(--line-height-title3);
  font-weight: var(--font-weight-strong);
}

h2 {
  font-size: var(--font-size-subtitle1);
  line-height: var(--line-height-subtitle1);
  font-weight: var(--font-weight-strong);
}

h3 {
  font-size: var(--font-size-subtitle2);
  line-height: var(--line-height-subtitle2);
  font-weight: var(--font-weight-medium);
}

h4 {
  font-size: var(--font-size-body1);
  line-height: var(--line-height-body1);
  font-weight: var(--font-weight-strong);
}

/* Prose links, scoped to the content column on purpose. The header's links are
   chrome and carry their own colour, and no utility class can take an underline
   back off them: generated utilities live in a cascade layer, and every unlayered
   rule in this file outranks every layer regardless of specificity. Scoping this
   rule is what lets base.html be written in the prototype's utility classes at
   all (issue 131). The tab strips do not need it — .c-navtabs__tab sets its own
   text-decoration. */
/* :where() so the scope costs nothing. This rule is a default for links nobody
   styled; every component class has to beat it, and the way to guarantee that is
   to weigh (0,0,1) — a bare element — not to out-specify each control in turn.

   Issue 131 wrote `.site-main a` (0,1,1) and link-shaped buttons went blue on
   blue. Issue 132 first answered with `:not(.c-button)`, which weighs (0,2,1) and
   broke the pager's hover as well: narrowing a selector RAISES its specificity,
   so an opt-out list makes the problem worse with every entry. :where() drops the
   weight back to what a bare `a` rule had before 131, while keeping the scope
   that rule was added for — the shell's links are still outside .site-main. */
:where(.site-main) a {
  color: var(--link);
  text-decoration: underline;
}

:where(.site-main) a:hover {
  color: var(--primary);
}

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

.text-caption {
  font-size: var(--font-size-caption1);
  line-height: var(--line-height-caption1);
}

.text-end {
  text-align: end;
}

/* Layout primitives. */
.l-stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-l);
}

.l-cluster {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-s);
}

/* A filter/search bar: one or more form_field includes plus an inline submit
   button, never anything else. align-items: center (l-cluster's default)
   centers the button against the field's full height — label, gap, AND
   input — so the button visibly droops below the input boxes it sits next
   to. flex-end lines the button up against the input row itself, because a
   button's own box height already matches an input's. */
.c-filter-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-s);
}

/* Up to three short form fields share one line (long modals fold to a third
   of their height); each cell still stacks its own label, widget, and help. */
.l-form-row {
  display: grid;
  grid-template-columns: repeat(3, minmax(var(--space-none), 1fr));
  gap: var(--space-l);
  align-items: start;
}

/* Alpine hides x-cloak elements until it has initialised — without this the
   floating menus flash open while the deferred script loads. */
[x-cloak] {
  display: none !important;
}

.u-visually-hidden {
  position: absolute;
  width: var(--border-width-thin);
  height: var(--border-width-thin);
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* The shell — header and content column — is built from the prototype's utility
   classes in base.html (ADR-020 §Decision 1: what the client approved is what
   renders, copied rather than re-derived). The MENU is deliberately not part of
   that: the multi-level floating menu of #74 is unchanged, by PM decision on
   2026-08-04, so its rules stay here exactly as they were. Two more rules survive
   below, both because a utility class cannot beat an unlayered rule in this file:
   `.site-main a` above scopes the prose underline off the shell's links, and the
   page title cannot use `text-xl` against the `h1` rule. */

/* ── The content column ─────────────────────────────────────────────────────
   The prototype's centred column, and the app's again (#216). It was full width
   from 2026-08-04 to #216 on the argument that a roster wants every pixel; what
   that actually produced was a card stretched to 1920px with the reader's eye
   travelling the whole bezel, and the prototype the design was approved from
   does not look like that. A table wider than the column scrolls inside its own
   .c-grid__scroll / .c-table__scroll box, which is where the width goes now.

   The header uses it too, so the brand sits over the first card rather than out
   at the screen edge. */
.site-column {
  width: 100%;
  max-width: var(--layout-content-max-width);
  margin-inline: auto;
  padding-inline: var(--space-l);
}

/* ── The shell: a title band and, under it, the tab bar (#216) ───────────────
   The floating multi-level menu of #74 is gone. Both bands stick together, and
   the tab strip scrolls sideways instead of wrapping — a wrapped strip changes
   the header's height with the viewport. The surface spans the viewport; only
   its contents are held to the column. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  border-bottom: var(--border-width-thin) solid var(--border);
  background-color: var(--card-bg);
}

.site-main {
  padding-block: var(--space-l);
}

.site-header__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-m);
  padding-block: var(--space-xs);
}

.site-header__brand {
  font-size: var(--font-size-body1);
  font-weight: var(--font-weight-strong);
  white-space: nowrap;
  color: var(--primary-dark);
}

/* The right-hand end of the header band: the 年度 in force, then who you are.
   年度 first, because it is the one that changes what the page under it says —
   the identity chip is reached for once a session. */
.site-header__actions {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  min-width: 0;
}

/* ── The 年度 picker ─────────────────────────────────────────────────────────
   components/year_picker.html. Same shape as the user chip beside it — a
   toggle and the shared .site-menu — because they are the same kind of thing:
   a small piece of current state you occasionally change. */
.site-year {
  position: relative;
  display: flex;
  align-items: center;
}

.site-year__toggle {
  display: flex;
  align-items: center;
  gap: var(--space-xxs);
  padding: var(--space-xxs) var(--space-s);
  /* --border-strong, not --border: this is a form control's boundary and it has
     to hold its own against the header's own hairline (ADR-020 Decision 3). */
  border: var(--border-width-thin) solid var(--border-strong);
  border-radius: var(--radius);
  background: none;
  color: inherit;
  white-space: nowrap;
  cursor: pointer;
}

.site-year__toggle:hover {
  background-color: var(--accent);
}

.site-year__value {
  font-size: var(--font-size-caption1);
  font-weight: var(--font-weight-medium);
  font-variant-numeric: tabular-nums;
}

/* The same fact for a reader who may not change it (academic-year:switch). No
   border and no chevron: those two are what say "press me", and a control that
   looks pressable and is not is worse than a label. The padding matches the
   toggle's so the header band does not change height between roles. */
.site-year__static {
  display: flex;
  align-items: center;
  gap: var(--space-xxs);
  padding: var(--space-xxs) var(--space-s);
  border: var(--border-width-thin) solid transparent;
  color: var(--muted);
  white-space: nowrap;
}

/* ── The user chip ──────────────────────────────────────────────────────────
   Was a string of Tailwind utilities in base.html; it is a control like any
   other and now says so in one place (#216). */
.site-user {
  position: relative;
  display: flex;
  align-items: center;
}

.site-user__toggle {
  display: flex;
  align-items: center;
  gap: var(--space-s);
  padding: var(--space-xxs) var(--space-s);
  border: var(--border-width-thin) solid transparent;
  border-radius: var(--radius);
  background: none;
  cursor: pointer;
}

.site-user__toggle:hover {
  background-color: var(--accent);
}

/* A tile, not a disc — the initial is text and reads as a label, not as a photo.
   It takes the app's corner like every other box; --radius-circular belongs to
   plotted points and nothing else (tokens.css). */
.site-user__avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--space-xxl);
  height: var(--space-xxl);
  border-radius: var(--radius);
  background-color: var(--accent);
  color: var(--primary-dark);
  font-size: var(--font-size-caption1);
  font-weight: var(--font-weight-strong);
}

.site-user__name {
  font-size: var(--font-size-caption1);
  font-weight: var(--font-weight-medium);
}

.site-user__role {
  font-size: var(--font-size-caption2);
  color: var(--muted);
}

/* The name and the role are the first things to go on a phone: the avatar and
   the menu they open are the whole control, and the header band is one line. */
@media (max-width: 40rem) {
  .site-user__name,
  .site-user__role {
    display: none;
  }
}

/* ── The header's popover ────────────────────────────────────────────────────
   Dropped by both controls in the band — the user chip and the 年度 picker —
   so it is named for the shell rather than for either of them (CLAUDE.md
   promotion rule). Anchored to whichever .site-user / .site-year holds it. */
.site-menu {
  position: absolute;
  top: 100%;
  right: 0;
  min-width: calc(var(--space-xxxxl) * 4);
  padding: var(--space-xxs);
  border: var(--border-width-thin) solid var(--border);
  border-radius: var(--radius);
  background-color: var(--card-bg);
  box-shadow: var(--shadow-overlay);
}

/* One rule for both an <a> and a <button>: the year entries are links because
   each is a real URL, the account entries are buttons because they act. A
   reader should not be able to tell which is which by looking. */
.site-menu__item {
  display: block;
  width: 100%;
  padding: var(--space-xs) var(--space-s);
  border: none;
  background: none;
  color: inherit;
  font-size: var(--font-size-caption1);
  font-weight: var(--font-weight-medium);
  text-align: left;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}

.site-menu__item:hover {
  background-color: var(--accent);
}

/* The year already on screen. Weight rather than a tick: the menu is a list of
   years, and a mark in a column of its own would widen every row for one. */
.site-menu__item--current {
  font-weight: var(--font-weight-strong);
  color: var(--primary-dark);
}

/* Flash messages moved to components.css together with components/toast.html —
   the region's markup and its styles stay in one place. */
