// =============================================================================
// Global stylesheet — imported exactly once, in main.tsx. Contains only
// truly app-wide rules: the theme tokens and a minimal reset/base styling
// that every page inherits. Anything specific to one component or page
// belongs in a .scss file colocated next to that component/page instead.
// =============================================================================

@use "./theme";

// Include borders/padding in an element's declared width/height everywhere,
// rather than the browser default of adding them on top.
*,
*::before,
*::after {
  box-sizing: border-box;
}

// Minimal reset: remove the default body margin so pages can control their
// own layout without fighting the browser's default 8px margin.
body {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--font-size-base);
  line-height: 1.55;
  color: var(--color-text);
  background: var(--color-background);
}

// Headings use the condensed "label" face app-wide — see _theme.scss for
// the rationale. `text-wrap: balance` avoids a lone short word wrapping
// onto its own line in multi-line titles.
h1,
h2,
h3,
h4,
h5,
h6 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  text-wrap: balance;
}

// Default to the page-title size; a heading used as a smaller component
// title (e.g. the auth card's <h1>) overrides this in its own stylesheet.
h1 {
  font-size: var(--font-size-2xl);
}

// A visible, consistent focus ring for keyboard navigation — the browser
// default varies a lot between elements and browsers.
:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

// Checkbox/radio appearance, app-wide — "selectable card" style: the native
// control itself is visually hidden (still real, focusable and
// screen-reader-visible — see the `input[type=...]` rule below, not
// `display: none`) and the whole label row it lives in becomes the
// interactive surface instead: a flat bordered box that fills in with a
// tinted background + primary border once selected, with a checkmark
// fading in on the leading edge.
//
// The base (unselected) look below is detected structurally with `:has()`
// — safe, since "does this label contain a checkbox/radio" never changes
// after mount. The *selected* look is instead driven by the `is-selected`
// class {@link CheckboxOption}/{@link RadioOption} (components/ui/) toggle
// in JS from the same boolean their caller already passes to `checked` —
// chaining a second `:has(:checked)` to react to that live state turned
// out to be unreliable across browsers, so this only needs one
// always-true `:has()`.
//
// Every checkbox/radio in the app goes through this one place (the allergy
// grid, the theme picker, anywhere future) rather than each feature styling
// its own — see profile-forms.scss / settings-pages.scss, which only
// arrange these within their own layout (grid vs. stacked list) and
// intentionally don't re-style the control/label look itself.
label:has(> input[type="checkbox"]),
label:has(> input[type="radio"]) {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  padding: var(--space-xs) var(--space-sm);
  // Overrides the generic `label { font-weight: 600 }` base rule
  // (profile-forms.scss) — without this, an *unselected* row reads just as
  // bold as a selected one (only `.allergy-select__option` happened to set
  // its own 400 already; `.theme-select__option` didn't, so its rows were
  // all permanently bold until this was centralized here).
  font-weight: 400;
  border: 1.5px solid var(--color-border);
  border-radius: var(--radius-base);
  background: var(--color-surface);
  cursor: pointer;
  transition:
    background-color 0.15s ease,
    border-color 0.15s ease;

  &:hover {
    border-color: var(--color-primary);
  }

  &.is-selected {
    border-color: var(--color-primary);
    background: color-mix(in srgb, var(--color-primary) 12%, var(--color-surface));
    color: var(--color-primary);
    font-weight: 600;
  }

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

// The control itself is removed from the visual flow — hidden the
// "sr-only" way (not `display: none`) so it stays focusable/tabbable and
// announced correctly by screen readers; the label above carries the
// entire visible selected/unchecked look.
input[type="checkbox"],
input[type="radio"] {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  opacity: 0;
}

// The checkmark — a real element (see components/ui/Checkbox.tsx /
// Radio.tsx) shown via the same `is-selected` class as the label's own
// look above, not a separate CSS-only trigger. Scaled in from nothing so
// toggling has a bit of motion. Same mark for both checkbox and radio: one
// consistent "selected" language app-wide rather than a checkmark here and
// a dot there. Sits first in the row (before the label text, per DOM
// order) — a classic "control on the left" layout rather than trailing.
.check-mark {
  flex: none;
  width: 0.9rem;
  height: 0.9rem;
  background: var(--color-primary);
  clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
  transform: scale(0);
  transition: transform 0.1s ease;
}

.is-selected .check-mark {
  transform: scale(1);
}
