/*
 * Minimal reset and typography defaults.
 *
 * Historically avoided bare `button`/`table`/`input`/`form`/`select`/
 * `textarea` tag selectors, which would have reached unmigrated Bootstrap
 * markup by tag rather than by class while Bootstrap and the new system
 * coexisted (ui_ux/migration-plan.md §2.2). Bootstrap is fully removed as
 * of Phase 10, so that risk no longer applies — still exercise the same
 * scrutiny before adding new bare tag-level rules, since they now reach
 * every instance of a tag app-wide, collision or not.
 */

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

/* The `hidden` attribute is a state, toggled throughout the app by both
   server-rendered conditionals and JS (dropdown.js, tabs.js, the various
   edit/cancel toggles) to mean "not part of the page right now" — it must
   always win. Without `!important` it doesn't: the UA stylesheet's
   `[hidden] { display: none }` has the same specificity as any of our own
   class selectors that set `display` (`.pl-btn`, `.tab`, etc.),
   so a later-loaded class rule silently overrides it and the element stays
   visible despite `hidden` being present. */
[hidden] {
  display: none !important;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--font-size-base);
  line-height: var(--line-height-base);
  color: var(--color-text);
  background: var(--color-canvas);
}

/* Headings carry an explicit size from the token scale. Without one they fall
   through to the UA defaults, which are `em`-relative to a 15px body — so h1
   landed near 30px and h3 near 17.6px, close enough to the surrounding text to
   read as accidental, and unrelated to the scale the rest of the UI uses. The
   sizes live here rather than on per-page classes so a heading is sized by what
   it *is*; the handful of components that had grown their own `h1` font-size
   overrides no longer need them. */
h1,
h2,
h3,
h4,
h5,
h6 {
  margin: 0 0 var(--space-2) 0;
  line-height: var(--line-height-tight);
  font-weight: var(--font-weight-semibold);
}

h1 {
  font-size: var(--font-size-2xl);
}

h2 {
  font-size: var(--font-size-xl);
}

h3 {
  font-size: var(--font-size-lg);
}

h4 {
  font-size: var(--font-size-md);
}

h5,
h6 {
  font-size: var(--font-size-base);
}

p {
  margin: 0 0 var(--space-3) 0;
}

/* Underline on hover rather than always. A compliance table is mostly links —
   every document title, every group, every revision — and permanently
   underlining them turns a dense table into a field of blue rules, which is
   the strongest "unstyled document" cue there is. The hover underline keeps
   the affordance where it is actually needed: at the point of interaction.
   Tables restyle links further; see `.data-table a` in components.css. */
a {
  color: var(--color-primary);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

code,
pre {
  font-family: var(--font-mono);
}

code {
  background: var(--color-code-bg);
  padding: 0.15em 0.4em;
  border-radius: var(--radius-sm);
  font-size: 0.9em;
}

pre {
  background: var(--color-code-bg);
  border: 1px solid var(--color-code-border);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  overflow-x: auto;
}

pre code {
  background: none;
  padding: 0;
  border-radius: 0;
  font-size: 0.875em;
}

:focus-visible {
  outline: 2px solid var(--color-focus-ring);
  outline-offset: 2px;
}

/* Bordered fields use their existing edge for focus rather than a second frame.
   Read-only fields and native pickers still need the outline above. */
input.input:not([type="file"], [type="checkbox"], [type="radio"], [readonly]):focus,
textarea:is(.input, .textarea):not([readonly]):focus,
select:is(.input, .select):focus {
  outline: none;
  border-color: var(--color-focus-ring);
}

/* Functional feedback only, per UI-UX-Principles.md §13 ("avoid excessive
   animations"): colour and border on the elements a pointer acts on, at a
   duration short enough to read as responsiveness rather than as motion.
   Nothing here animates size, position, or opacity of page content, so no
   layout ever moves. Enumerated by property rather than `all` so a future
   layout property cannot start animating by accident. */
a,
button,
summary,
.pl-btn,
.tab,
.context-nav a,
.sidebar-nav a,
.data-table tbody tr,
.pl-dropdown-item,
.input,
.select,
.textarea {
  transition:
    background-color var(--duration-fast) ease,
    border-color var(--duration-fast) ease,
    color var(--duration-fast) ease;
}

/* Respect the OS setting: for users who ask for reduced motion, drop to an
   instant state change rather than a shortened one. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }
}

/* Two halves of the same feedback, on two different elements.
 *
 * The trigger — a button or link that fires a swap — dims and stops taking
 * input, which is what prevents a double submit while a slow request is in
 * flight. `:not(form)` because a form issuing a request would otherwise grey
 * out and freeze every control inside it, including the one just used. */
.htmx-request:not(form) {
  opacity: 0.6;
  pointer-events: none;
}

/* The target — the region about to be replaced — is marked by
 * htmx-loading.js. This is the half that is actually visible for a form-
 * triggered swap, where `.htmx-request` lands on the form and the stale
 * results it is replacing would otherwise sit there at full strength.
 * Opacity only: see htmx-loading.js on why it must keep accepting input. */
.is-loading {
  opacity: 0.55;
  transition: opacity var(--duration-fast) ease;
}
