/* ============================================================
   3Y ACCESSIBILITY CORE
   /src/css/core/a11y.css
   ============================================================
   Load this BEFORE component CSS so component rules can override
   the baseline focus ring where they need to (e.g. card focus).

   Owns:
     - .sr-only          : visually-hidden but screen-reader-available
     - .skip-link        : keyboard skip-to-main-content link
     - :focus-visible    : baseline visible focus indicator
     - prefers-reduced-motion baseline
     - forced-colors (Windows High Contrast Mode) baseline
     - small additions for the signout modal error region

   These rules are deliberately conservative — they set safe
   defaults that work across all 3Y pages without overriding
   any component-specific styling.
   ============================================================ */

/* ---------- Screen-reader-only utility ----------
   The only correct way to visually hide content while keeping
   it accessible. Do NOT use display:none for content screen
   readers need. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* When focused (e.g. for an sr-only "skip" link), reveal it. */
.sr-only-focusable:focus,
.sr-only-focusable:focus-visible {
  position: static;
  width: auto;
  height: auto;
  margin: 0;
  overflow: visible;
  clip: auto;
  clip-path: none;
  white-space: normal;
}

/* ---------- Skip link ----------
   First focusable element on every page. Off-screen by default;
   slides into view on focus. WCAG 2.4.1 (Bypass Blocks). */
.skip-link {
  position: fixed;
  left: max(1rem, env(safe-area-inset-left));
  top: max(1rem, env(safe-area-inset-top));
  z-index: 2147483647;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  max-width: calc(100vw - 2rem);
  padding: 0.625rem 1rem;
  border: 1px solid rgba(141, 193, 67, 0.75);
  border-radius: 10px;
  background: #05070f;
  color: #ffffff;
  box-shadow: none;
  font-weight: 700;
  font-size: 0.95rem;
  line-height: 1.2;
  text-decoration: none;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transform: translate3d(0, calc(-100% - 4rem), 0);
  transition:
    transform 0.18s ease,
    opacity 0.18s ease;
}

.skip-link:hover {
  color: #ffffff;
  text-decoration: none;
}

.skip-link:focus,
.skip-link:focus-visible {
  opacity: 1;
  pointer-events: auto;
  transform: translate3d(0, 0, 0);
  box-shadow:
    0 14px 32px rgba(0, 0, 0, 0.45),
    0 0 0 1px rgba(255, 255, 255, 0.08);
  outline: 3px solid var(--focus-ring, #8dc143);
  outline-offset: 3px;
}

/* ---------- Focus-visible baseline ----------
   The browser default focus ring is inconsistent and frequently
   stripped by reset stylesheets. Establish a known-good ring that
   components inherit unless they choose to replace it.

   Uses :focus-visible (not :focus) so mouse users don't see a ring
   on every click but keyboard users always do. */
:focus-visible {
  outline: 3px solid var(--focus-ring, #8dc143);
  outline-offset: 3px;
  border-radius: 4px;
}

/* Some controls have their own elaborate focus treatment (e.g.
   selection cards with internal animations). They can opt out with
   .a11y-custom-focus and provide their own visible indicator. */
.a11y-custom-focus:focus-visible {
  outline: none;
}

/* ---------- Route outlet ----------
   The route outlet receives programmatic focus on route change.
   Hide the ring when it's focused via script (it's a wrapper,
   not a control); :focus-visible already prevents the ring from
   appearing on mouse-driven focus, but the outlet is focused
   programmatically too. */
#app-route-outlet:focus,
#app-route-outlet:focus-visible {
  outline: none;
}

/* ---------- System-initiated dialogs ----------
   Visual hint that the dialog interrupted the user. Subtle —
   accessibility comes from the assertive announcement and the
   focus capture, not from screaming red borders. */
.modal-container[data-destructive="true"] {
  /* Defer styling to component CSS; this is a structural hook. */
}

/* Signout modal error region (revealed on logout failure). */
.signout-modal .signout-error {
  color: var(--red, #ef4444);
  background: #fef2f2;
  border: 1px solid #fecaca;
  border-radius: 8px;
  padding: 10px 12px;
  margin-top: 12px;
  font-size: 0.9rem;
  line-height: 1.45;
}

/* ---------- Reduced motion ----------
   Respect the user's OS-level animation preference.
   This is a global stop-motion: every transition and animation
   collapses to "instant". Component CSS that wants to preserve
   meaningful motion (e.g. a progress bar) can opt out by
   targeting (prefers-reduced-motion: no-preference) explicitly. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------- Forced colors (Windows High Contrast Mode) ----------
   When the OS forces a custom palette, our background/border
   colors are replaced. Make sure the focus ring still shows up
   (system Highlight color) and modal overlays still read as a
   distinct surface. */
@media (forced-colors: active) {
  :focus-visible {
    outline-color: Highlight;
  }
  .skip-link {
    background: ButtonFace;
    color: ButtonText;
    border: 1px solid ButtonText;
  }
  .modal-overlay {
    background: Canvas;
  }
  .modal-container {
    border: 1px solid CanvasText;
  }
  .form-error-summary {
    border: 2px solid Mark;
  }
}

/* ---------- Touch target safety (WCAG 2.2 SC 2.5.8) ----------
   24×24 CSS px is the minimum. Buttons and links that opt into
   this class are guaranteed to clear it; components can use it
   as a defensive baseline. */
.a11y-tap-target {
  min-width: 24px;
  min-height: 24px;
}

/* ---------- Validation summary ----------
   Used by validation-a11y.js. Visible, focusable, announced
   via role="alert". */
.form-error-summary {
  background: #fef2f2;
  border: 1px solid #fecaca;
  border-radius: 10px;
  padding: 14px 16px;
  margin-bottom: 18px;
  color: #991b1b;
}

.form-error-summary:focus-visible {
  outline: 3px solid var(--focus-ring, #8dc143);
  outline-offset: 3px;
}

.form-error-summary h2 {
  font-size: 1rem;
  font-weight: 700;
  margin: 0 0 8px 0;
  color: #991b1b;
}

.form-error-summary ul {
  margin: 0;
  padding-left: 1.25rem;
}

.form-error-summary a {
  color: inherit;
  text-decoration: underline;
}

.form-error-summary a:hover {
  text-decoration: none;
}

/* Field-level error text (appears under invalid inputs). */
.input-error {
  color: var(--red, #ef4444);
  font-size: 0.85rem;
  margin: 6px 0 0 0;
  min-height: 1.2em; /* reserves space so the layout doesn't jump */
}

/* aria-invalid="true" inputs get a red border by default. */
[aria-invalid="true"] {
  border-color: var(--red, #ef4444) !important;
}

[aria-invalid="true"]:focus-visible {
  outline-color: var(--red, #ef4444);
}