/*
 * IKON Community™ — floating accessibility widget + its two site-wide
 * effects (high contrast, reduced motion). Genuinely shared across all
 * three page families (landing/practitioner/admin) — see
 * partials/accessibility-widget.php's own docblock for why this is a
 * deliberate exception to the usual "duplicate per stylesheet"
 * convention. Loaded after theme.css/admin.css/practitioner.css/
 * landing.css everywhere it appears, so its selectors win ties without
 * needing !important except where noted below.
 *
 * Text-size and the two toggles are all driven by public/js/accessibility.js
 * setting attributes on <html> (`data-a11y-contrast`, `data-a11y-motion`)
 * or a root font-size — this file only defines what those states *look*
 * like, never sets them.
 */

/* ---------------------------------------------------------------
 * Widget chrome — same card/button vocabulary as the rest of the app
 * (--radius-xl for the panel, matching "elevated panels" per theme.css's
 * own token comment; --shadow-md/-lg for real elevation, the kind of
 * floating control that's supposed to look raised).
 * --------------------------------------------------------------- */
.a11y-widget {
  position: fixed;
  right: 20px;
  bottom: 90px;
  z-index: 300; /* above .login-modal-overlay (200) — adjusting contrast/text size while that's open should still work */
}

.a11y-toggle {
  width: 46px;
  height: 46px;
  border-radius: 50%;
  /* A real bug, not a mobile CSS/overflow issue: this button is
     position:fixed sitewide (see .a11y-widget below) and desktop's
     generous side margins meant it always floated over blank space —
     but mobile's cards run edge-to-edge (see practitioner.css's own
     16px-gutter convention), so there's no dead space left for it to
     sit in without landing on top of a card's own text at whatever
     scroll position the user happens to be at. Confirmed directly: a
     real Overview card's "Retake Profiling anytime to refresh your
     matches." was fully present in the DOM, not clipped — this button
     was sitting right on top of "ur", making it *look* like a text-
     overflow bug in a screenshot.

     Fix: a genuinely translucent resting background so covered text
     stays legible underneath, verified with real before/after
     screenshots, not assumed from the CSS alone — which is also how a
     `backdrop-filter: blur()` layer (tried first) got ruled out: it
     silently composited this fixed+alpha element against an opaque
     backdrop instead of the real page content in testing, hiding text
     just as completely as the original bug despite computed style
     correctly reporting the blur as applied. Plain alpha with no
     blur, re-verified after removing it, genuinely shows covered text
     through the button. Solid var(--paper) stays as the fallback for
     browsers without color-mix(). */
  background: var(--paper);
  background: color-mix(in srgb, var(--paper) 50%, transparent);
  border: 1px solid var(--line);
  color: var(--ink);
  box-shadow: var(--shadow-md);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
}

.a11y-toggle:hover {
  border-color: var(--gold);
  color: var(--gold);
  box-shadow: var(--shadow-lg);
}

.a11y-toggle:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}

.a11y-toggle svg {
  width: 22px;
  height: 22px;
}

.a11y-panel {
  position: absolute;
  right: 0;
  bottom: calc(100% + 12px);
  width: 232px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg);
  padding: 14px 16px 12px;
}

.a11y-panel-title {
  font-family: var(--font-mono);
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 10px;
}

.a11y-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 0;
  border-bottom: 1px solid var(--line);
}

.a11y-row:last-of-type {
  border-bottom: none;
}

.a11y-label {
  font-size: 0.82rem;
  color: var(--ink);
}

.a11y-stepper {
  display: flex;
  gap: 6px;
  flex-shrink: 0;
}

.a11y-step-btn {
  width: 28px;
  height: 28px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 0.76rem;
  font-weight: 600;
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease;
}

.a11y-step-btn:hover {
  border-color: var(--gold);
  color: var(--gold);
}

.a11y-step-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

/* Toggle switch — same visual recipe as admin.css's own .switch (34x19px
   pill, off = --line, on = --teal, white 15px knob), given its own class
   here rather than reused directly since this file has to work on the
   landing page too, which never loads admin.css. */
.a11y-switch {
  width: 34px;
  height: 19px;
  border-radius: 20px;
  background: var(--line);
  position: relative;
  flex-shrink: 0;
  border: none;
  padding: 0;
  cursor: pointer;
}

.a11y-switch.on {
  background: var(--teal);
}

.a11y-switch::after {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: #fff;
  transition: left 0.15s ease;
}

.a11y-switch.on::after {
  left: 17px;
}

.a11y-switch:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}

.a11y-reset {
  display: block;
  width: 100%;
  text-align: center;
  margin-top: 10px;
  padding-top: 8px;
  border: none;
  background: none;
  font-size: 0.72rem;
  color: var(--muted);
  cursor: pointer;
}

.a11y-reset:hover {
  color: var(--gold);
  text-decoration: underline;
}

@media (max-width: 480px) {
  .a11y-widget {
    right: 12px;
    bottom: 76px;
  }

  .a11y-panel {
    width: 208px;
  }
}

/* This widget's usual bottom-right corner overlaps the Connect page's
 * own DM chat send button once a thread is open on mobile
 * (practitioner.css's .chat-panel[data-chat-with] deliberately expands
 * to 70dvh there, "closer to a real mobile chat screen" per that file's
 * own comment) — confirmed directly with a real overlapping screenshot,
 * and NOT reliably fixable by nudging the chat input's own margin
 * instead (tried first — see practitioner.css's own comment on why that
 * didn't hold up outside a synthetic/empty test thread). Repositioning
 * this widget itself sidesteps needing an exact pixel gap between two
 * independently-positioned elements (this one fixed to the viewport,
 * the chat card in normal flow) across every real device: relocated to
 * just below the sticky 60px .dash-header (practitioner.css) instead of
 * the bottom corner, which an open thread's own content — no matter how
 * tall real conversation history makes it, no matter how a real
 * phone's dvh settles — never reaches. `:has()` keys off the chat
 * panel's own real, server-rendered state (present only when a thread
 * is actually open, connect/feed.php), not a JS-toggled class, so this
 * needs no script changes on top of practitioner.js's existing chat
 * code. The panel itself (.a11y-panel, directly below) flips to expand
 * downward instead of its usual upward-from-the-toggle direction, since
 * upward from a widget already near the top of the screen would run
 * off-screen. Scoped to the same ≤767px range .chat-panel[data-chat-with]
 * itself uses — desktop already has enough room and is unaffected. */
@media (max-width: 767px) {
  body:has(.chat-panel[data-chat-with]) .a11y-widget {
    top: 70px;
    bottom: auto;
    right: 12px;
  }

  body:has(.chat-panel[data-chat-with]) .a11y-panel {
    top: calc(100% + 12px);
    bottom: auto;
  }
}

/* Same overlap, same fix, different page: IKON Chat's own thread panel
 * (Practitioner\ChatPageController) isn't the small 460px embedded card
 * the rule above was written for — it's a near-viewport-height panel
 * (practitioner.css's .ikon-chat-shell), so its own send button reaches
 * this widget's fixed bottom-right corner at desktop widths too, not
 * just mobile — confirmed directly with a real overlapping click
 * (Playwright's own "<div id="a11y-widget"> intercepts pointer events"
 * failure) while verifying the send button. Unscoped by max-width for
 * that reason; the mobile rule above still also applies at ≤767px since
 * .ikon-chat-panel-wrap carries the plain .chat-panel class too. */
body:has(.ikon-chat-panel-wrap.chat-panel[data-chat-with]) .a11y-widget {
  top: 70px;
  bottom: auto;
  right: 12px;
}

body:has(.ikon-chat-panel-wrap.chat-panel[data-chat-with]) .a11y-panel {
  top: calc(100% + 12px);
  bottom: auto;
}

/* ---------------------------------------------------------------
 * High contrast — overrides the same custom properties every page's
 * own CSS already reads (--muted/--ink-soft for text, --line for
 * borders), so the effect reaches every component on every page
 * without this file needing to know what any of them look like.
 * `html[data-a11y-contrast="on"]` beats a bare `:root` definition on
 * specificity alone (same element, extra attribute selector) — no
 * !important needed here, just normal cascade order.
 *
 * Two variants, not one: the values below assume a light background
 * (dark navy text/borders pushed even darker) and would be nearly
 * invisible if applied on top of dark mode's own already-dark
 * background — so a second, dark-aware rule follows, keyed off both
 * `data-theme="dark"` and `data-a11y-contrast="on"` together. That
 * two-attribute selector outranks this single-attribute one on
 * specificity alone (same "extra attribute wins" rule this file
 * already relies on above), so when both dark mode and high contrast
 * are on, the dark-aware values win automatically — no !important,
 * no JS coordination between the two toggles needed. See
 * public/css/theme.css for where `data-theme` itself comes from.
 * --------------------------------------------------------------- */
html[data-a11y-contrast="on"] {
  --muted: #4B4F58;
  --ink-soft: #16213E;
  --line: rgba(22, 33, 62, 0.4);
}

html[data-theme="dark"][data-a11y-contrast="on"] {
  --muted: #D5D7DE;
  --ink-soft: #FFFFFF;
  --line: rgba(255, 255, 255, 0.4);
}

/* ---------------------------------------------------------------
 * Reduced motion — a deliberate, singular use of !important: this has
 * to beat an unknown, unbounded number of component-specific
 * transition/animation declarations across four separate stylesheets
 * without editing any of them individually. Same "kill switch" pattern
 * browsers themselves apply for `prefers-reduced-motion: reduce`, just
 * driven by an explicit in-app toggle instead of (or on top of) the OS
 * setting — see public/js/accessibility.js for how the two combine
 * (the OS preference is the default; the toggle can override it either
 * direction). Chart.js's own canvas-draw animation isn't CSS and can't
 * be stopped from here — public/js/charts.js reads the same
 * localStorage flag directly and passes `animation: false` to every
 * chart's own options when it's set.
 * --------------------------------------------------------------- */
html[data-a11y-motion="reduced"] *,
html[data-a11y-motion="reduced"] *::before,
html[data-a11y-motion="reduced"] *::after {
  animation-duration: 0.001ms !important;
  animation-delay: 0s !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0.001ms !important;
  transition-delay: 0s !important;
  scroll-behavior: auto !important;
}

/* The block above's own `*` only ever matches DESCENDANTS of
   html[data-a11y-motion="reduced"] — never the <html> element itself.
   That's exactly where `scroll-behavior: smooth` actually lives
   (practitioner.css sets it on `html`, for in-page anchor links like
   Profiling's "See full results ↓"), so without this separate rule a
   smooth in-page scroll kept animating under reduced motion — a real
   gap the `*` selector structurally can't close, confirmed by a real
   computed-style check before adding this, not assumed. */
html[data-a11y-motion="reduced"] {
  scroll-behavior: auto !important;
}
