/* =====================================================================
   Compuservicios — shared accessibility layer (D-195 #65, 2026-09-01)
   One file for every surface: public site, portal, admin, Odysseus.
   Pairs with a11y.js. Loaded AFTER each page's own stylesheet.

   State lives on <html>:
     data-theme    light | dark           (pre-existing convention, key cs_theme)
     data-fs       100 | 115 | 130        font scale, rem-based pages cascade
     data-contrast none | hc              high contrast (≥7:1, WCAG AAA)
     data-cvd      0 | 1                  colour-vision-deficiency safe palette
     data-motion   auto | reduce          kill animations/transitions
   ===================================================================== */

/* ---------- 1. Font scale ---------- */
html[data-fs="115"] { font-size: 115% !important; }
html[data-fs="130"] { font-size: 130% !important; }

/* ---------- 2. Motion ---------- */
html[data-motion="reduce"] *,
html[data-motion="reduce"] *::before,
html[data-motion="reduce"] *::after {
  animation-duration: 0.001ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0.001ms !important;
  scroll-behavior: auto !important;
}
@media (prefers-reduced-motion: reduce) {
  html:not([data-motion="auto"]) *,
  html:not([data-motion="auto"]) *::before,
  html:not([data-motion="auto"]) *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------- 3. Keyboard: skip link + visible focus everywhere ---------- */
.a11y-skip {
  position: absolute; left: -999px; top: 0; z-index: 100000;
  background: #F97316; color: #fff; font-weight: 700; padding: .6rem 1rem;
  border-radius: 0 0 10px 0; text-decoration: none;
}
.a11y-skip:focus { left: 0; outline: 3px solid #08225E; outline-offset: 2px; }

:focus-visible {
  outline: 3px solid #F97316 !important;
  outline-offset: 3px !important;
  box-shadow: 0 0 0 5px rgba(8, 34, 94, .35) !important;
}
html[data-theme="dark"] :focus-visible { box-shadow: 0 0 0 5px rgba(255, 255, 255, .35) !important; }
/* mouse users don't get rings on click */
:focus:not(:focus-visible) { outline: none; }

/* ---------- 4. Widget ---------- */
.a11y-fab {
  position: fixed; left: 14px; bottom: 14px; z-index: 99990;
  width: 48px; height: 48px; border-radius: 50%; border: 2px solid #fff;
  background: #08225E; color: #fff; font-size: 22px; line-height: 1;
  display: grid; place-items: center; cursor: pointer;
  box-shadow: 0 6px 20px rgba(8, 34, 94, .35);
  transition: transform .15s ease, box-shadow .15s ease;
}
.a11y-fab:hover { transform: translateY(-2px); box-shadow: 0 10px 26px rgba(8, 34, 94, .45); }
.a11y-fab[aria-expanded="true"] { background: #F97316; }
@media print { .a11y-fab, .a11y-panel, .a11y-skip { display: none !important; } }

.a11y-panel {
  position: fixed; left: 14px; bottom: 72px; z-index: 99991;
  width: min(92vw, 320px); background: #fff; color: #1A1A2E;
  border: 1px solid #E8E8E8; border-radius: 14px;
  box-shadow: 0 12px 40px rgba(8, 34, 94, .25); padding: 14px 14px 10px;
  font: 14px/1.4 'Segoe UI', system-ui, -apple-system, sans-serif;
}
html[data-theme="dark"] .a11y-panel { background: #111C33; color: #E2E8F0; border-color: #1E293B; }
.a11y-panel[hidden] { display: none; }
.a11y-panel h2 { margin: 0 0 8px; font-size: 15px; color: #08225E; }
html[data-theme="dark"] .a11y-panel h2 { color: #7BB4FF; }
.a11y-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin: 8px 0; }
.a11y-row > span { font-weight: 600; }
.a11y-group { display: inline-flex; gap: 4px; }
.a11y-btn {
  min-width: 40px; min-height: 36px; padding: 4px 10px; border-radius: 8px;
  border: 1.5px solid #CBD5E1; background: transparent; color: inherit;
  font: inherit; font-weight: 700; cursor: pointer;
}
.a11y-btn[aria-pressed="true"] { background: #08225E; color: #fff; border-color: #08225E; }
html[data-theme="dark"] .a11y-btn[aria-pressed="true"] { background: #F97316; border-color: #F97316; }
.a11y-btn:hover { border-color: #F97316; }
.a11y-foot { display: flex; justify-content: space-between; align-items: center; margin-top: 10px; font-size: 12px; color: #5A5A5A; }
html[data-theme="dark"] .a11y-foot { color: #94A3B8; }
.a11y-link { background: none; border: none; color: inherit; text-decoration: underline; cursor: pointer; font: inherit; padding: 2px 4px; }

/* ---------- 5. HIGH CONTRAST (data-contrast="hc") ----------
   Black on white (light) / white on black (dark), yellow for actionable,
   every border forced visible. Overrides brand tokens on purpose — the user
   asked for contrast over brand. */
html[data-contrast="hc"] {
  --navy: #000000; --orange: #FFD400; --green: #00A000; --white: #FFFFFF;
  --off-white: #FFFFFF; --gray: #000000; --light-gray: #000000;
  --text-primary: #000000; --text-body: #000000; --text-muted: #000000;
  --text-brand: #000000; --bg: #FFFFFF; --surface: #FFFFFF; --border: #000000;
  --gray-100: #FFFFFF; --gray-200: #FFFFFF; --gray-300: #000000; --gray-500: #000000;
  --gray-600: #000000; --gray-700: #000000; --gray-800: #000000;
}
html[data-contrast="hc"][data-theme="dark"] {
  --navy: #FFFFFF; --white: #000000; --off-white: #000000; --gray: #FFFFFF; --light-gray: #FFFFFF;
  --text-primary: #FFFFFF; --text-body: #FFFFFF; --text-muted: #FFFFFF; --text-brand: #FFFF00;
  --bg: #000000; --surface: #000000; --border: #FFFFFF;
  --gray-100: #000000; --gray-200: #000000; --gray-300: #FFFFFF; --gray-500: #FFFFFF;
  --gray-600: #FFFFFF; --gray-700: #FFFFFF; --gray-800: #FFFFFF;
}
html[data-contrast="hc"] body { background: var(--bg) !important; color: var(--text-body) !important; }
html[data-contrast="hc"] a { color: var(--text-brand) !important; text-decoration: underline !important; }
html[data-contrast="hc"] button, html[data-contrast="hc"] .btn, html[data-contrast="hc"] input,
html[data-contrast="hc"] select, html[data-contrast="hc"] textarea, html[data-contrast="hc"] .card,
html[data-contrast="hc"] .kpi-card, html[data-contrast="hc"] table, html[data-contrast="hc"] th,
html[data-contrast="hc"] td, html[data-contrast="hc"] .badge, html[data-contrast="hc"] .tbl {
  border: 2px solid var(--border) !important; box-shadow: none !important;
  background-image: none !important;
}
/* D-195 Phase 4, D4-5 (2026-09-02): d121_contrast_check.py's new HC pass
   found 37 real failures -- status badges, secondary buttons, and panel
   surfaces across admin/Odysseus/portal sitting on their own component
   CSS's hardcoded or semantic colour, unaffected by the border-only rule
   above, well under HC's own stated 7:1 AAA bar (many at 3:1-6.4:1). Per
   this spec's D4-5 point 4: "do not silently retune a brand token ... the
   fix belongs in a11y.css." Rather than hand-patching 37 individual
   component rules across three files this phase never touches
   (admin_dashboard.html's own rules stay as literal architecture per AC-1;
   odysseus_social_workspace.html and static/site-portal.css belong to
   other phases), this forces the SAME neutral black-on-white /
   white-on-black pair already used for body text onto every one of these
   surfaces. No information is lost: the badge/status TEXT still names the
   state, and CVD mode (a separate, independent toggle, already built
   above) is the tool for a non-colour status cue -- HC's own job is
   contrast, not colour differentiation, exactly the "contrast over brand"
   philosophy this file's own header already states. Attribute-substring
   selectors ([class*="x"]) are used for every modifier-heavy family so a
   new modifier added later (a future badge--x, wa-type-badge--y, ...) is
   covered automatically -- same "enumerated invariant, not a hand list"
   principle D4-5 point 3 states for the CVD check two sections up.
   d121_contrast_check.py's build_hc_pairs() parses this exact selector
   list back out of this file (never hand-duplicated) so it can report
   these pairs as verified-forced rather than silently still red.
   Specificity: every selector below is a single class/attribute selector
   (0,0,1,0) with !important, identical to .btn--primary below it -- ties
   are broken by SOURCE ORDER, so .btn--primary (declared after, and also
   matched by the [class*="btn--"] entry below) still wins its own
   deliberately-chosen orange/black pair for elements carrying that exact
   class. */
html[data-contrast="hc"] .badge, html[data-contrast="hc"] [class*="badge--"],
html[data-contrast="hc"] .pago-badge, html[data-contrast="hc"] [class*="pago-badge--"],
html[data-contrast="hc"] .deploy-chip, html[data-contrast="hc"] [class*="deploy-chip--"],
html[data-contrast="hc"] .status-pill, html[data-contrast="hc"] [class*="status-pill--"],
html[data-contrast="hc"] .status-badge, html[data-contrast="hc"] [class*="status-badge"],
html[data-contrast="hc"] .kpi-delta, html[data-contrast="hc"] [class*="kpi-delta--"],
html[data-contrast="hc"] .alert, html[data-contrast="hc"] [class*="alert-"], html[data-contrast="hc"] [class*="alert--"],
html[data-contrast="hc"] .success, html[data-contrast="hc"] .error-box, html[data-contrast="hc"] .violation-flag,
html[data-contrast="hc"] [class*="btn--"], html[data-contrast="hc"] [class*="wa-type-badge--"],
html[data-contrast="hc"] [class*="wa-intent-"], html[data-contrast="hc"] [class*="wa-review-btn"],
html[data-contrast="hc"] [class*="wa-paused-badge"], html[data-contrast="hc"] .topbar__badge,
html[data-contrast="hc"] [class*="topbar__badge"], html[data-contrast="hc"] .log-box,
html[data-contrast="hc"] .acct-toggle__btn, html[data-contrast="hc"] [class*="dl-add"],
html[data-contrast="hc"] [class*="dl-del"], html[data-contrast="hc"] .btn-pay,
html[data-contrast="hc"] .btn-pay[disabled],
html[data-contrast="hc"] [class*="wa-bubble"], html[data-contrast="hc"] [class*="wa-delivery"],
html[data-contrast="hc"] [class*="wa-qa"], html[data-contrast="hc"] [class*="pay-block__status"],
html[data-contrast="hc"] .btn-primary, html[data-contrast="hc"] .btn-receipt,
/* D-195 Phase 4 / D4-4 (2026-09-02): admin-changelog__event's 6 event-type
   badges (deploy/rollback/create/delete/dep_audit/backup) -- 4 of 6 measured
   under 7:1 (6.37-6.80:1) once static/admin-theme.css was added to the
   checker's own scan targets. Same badge-family treatment as everything
   else in this list: event type is still named in the text, CVD mode
   already covers non-colour differentiation, HC's job here is contrast. */
html[data-contrast="hc"] .admin-changelog__event, html[data-contrast="hc"] [class*="admin-changelog__event--"],
/* D-195 Phase 4 / D4-3 (2026-09-02): the bottom bar / Más sheet's "active
   item" indicator -- 4.61:1 measured under HC, the same --orange-ink
   figure as every other Item-9-class instance this phase. Forcing neutral
   here still leaves a real, non-colour "this one is active" signal: the
   border-top/border-left accent these selectors already carry in
   admin-theme.css (independent of colour) becomes THIS rule's own
   `border: 2px` under HC, and aria-current="page" carries the state for
   assistive tech regardless of either border. */
html[data-contrast="hc"] .admin-bottombar__item[aria-current="page"],
html[data-contrast="hc"] .admin-mas-sheet__item[aria-current="page"],
html[data-contrast="hc"] input[readonly] {
  background: var(--bg) !important; color: var(--text-body) !important; border: 2px solid var(--border) !important;
}

html[data-contrast="hc"] .btn--primary, html[data-contrast="hc"] button[type="submit"] {
  background: var(--orange) !important; color: #000 !important;
}
html[data-contrast="hc"] img:not([alt=""]) { filter: contrast(1.25); }

/* ---------- 6. COLOUR-BLIND SAFE (data-cvd="1") ----------
   Deuteranopia/protanopia-safe: red/green status pairs become blue/orange
   (Okabe-Ito) AND every status carries a glyph, so colour is never the only
   signal. Class hooks cover every badge family across the four surfaces. */
html[data-cvd="1"] {
  --green: #0072B2; --red-500: #D55E00; --error: #D55E00; --brand-green: #0072B2;
  --success: #0072B2; --danger: #D55E00; --warning: #E69F00;
}
html[data-cvd="1"] .badge::after, html[data-cvd="1"] .pago-badge::after,
html[data-cvd="1"] .deploy-chip::after, html[data-cvd="1"] .kpi-delta::after,
html[data-cvd="1"] .status-pill::after, html[data-cvd="1"] .alert::before {
  font-weight: 900; margin-left: .35em; letter-spacing: 0;
}
html[data-cvd="1"] .kpi-delta--up::after     { content: " ▲"; }
html[data-cvd="1"] .kpi-delta--down::after   { content: " ▼"; }
html[data-cvd="1"] .kpi-delta--flat::after   { content: " ="; }
html[data-cvd="1"] .pago-badge--cobrado::after   { content: " ✓"; }
html[data-cvd="1"] .pago-badge--pendiente::after { content: " ⏳"; }
html[data-cvd="1"] .deploy-chip--ready::after    { content: " ●"; }
html[data-cvd="1"] .deploy-chip--none::after     { content: " ○"; }
html[data-cvd="1"] .badge--entregado::after, html[data-cvd="1"] .badge[data-status="entregado"]::after { content: " ✓"; }
html[data-cvd="1"] .badge--listo::after,     html[data-cvd="1"] .badge[data-status="listo"]::after     { content: " ●"; }
html[data-cvd="1"] .badge--recibido::after,  html[data-cvd="1"] .badge[data-status="recibido"]::after  { content: " ▲"; }
html[data-cvd="1"] .badge--diagnostico::after, html[data-cvd="1"] .badge[data-status="diagnostico"]::after { content: " ◆"; }
html[data-cvd="1"] .alert--error::before, html[data-cvd="1"] .alert-error::before, html[data-cvd="1"] .error-box::before { content: "✖ "; }
html[data-cvd="1"] .alert--success::before, html[data-cvd="1"] .alert-success::before { content: "✓ "; }
/* charts: Chart.js reads CSS vars only if the page passes them — a11y.js exposes a palette hook */
