:root {
  --a11y-panel-bg: #111;
  --a11y-panel-border: rgba(255,255,255,0.18);
  --a11y-panel-text: rgba(255,255,255,0.94);
  --a11y-panel-muted: rgba(255,255,255,0.68);
  --a11y-panel-accent: #D4AF37;
}

.a11y-skip-link {
  position: fixed;
  top: 10px;
  right: 10px;
  z-index: 10000;
  transform: translateY(-140%);
  background: #D4AF37;
  color: #050505;
  border-radius: 10px;
  padding: 10px 14px;
  font: 700 14px/1.3 'Heebo', Arial, sans-serif;
  text-decoration: none;
  box-shadow: 0 12px 32px rgba(0,0,0,0.28);
  transition: transform 0.16s ease;
}
.a11y-skip-link:focus { transform: translateY(0); outline: 3px solid #fff; outline-offset: 3px; }

/* issue 28 Phase 2 — visually-hidden utility (WCAG 4.1.3 status regions, sr-only
   labels). Namespaced so it never collides with a screen's own .sr-only. The
   widget injects this stylesheet into every same-origin iframe, so screens can
   reuse .a11y-sr-only for their own runtime ARIA status spans. */
.a11y-sr-only {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.a11y-toggle {
  position: fixed;
  right: 18px;
  bottom: 18px;
  z-index: 9998;
  /* SHELL-DEMO-POLISH-2 (2026-05-18) — toggle reduced from 56→44px on
     desktop and 40px on mobile so it stops covering UI behind it. The
     SPA shell additionally overrides the corner so the button does
     not overlap the right-side sidebar. */
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: radial-gradient(circle at 32% 28%, #F2D766 0%, #E8C94A 38%, #D4AF37 70%, #9F7E18 100%);
  color: #fff;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-shadow:
    0 10px 26px rgba(0,0,0,0.38),
    0 0 0 3px rgba(212,175,55,0.16),
    inset 0 1px 0 rgba(255,255,255,0.55),
    inset 0 -2px 6px rgba(0,0,0,0.28);
  transition: transform 0.16s ease, box-shadow 0.16s ease, filter 0.16s ease;
}
.a11y-toggle:hover {
  transform: translateY(-1px) scale(1.04);
  filter: brightness(1.05);
  box-shadow:
    0 18px 44px rgba(0,0,0,0.48),
    0 0 0 5px rgba(212,175,55,0.26),
    inset 0 1px 0 rgba(255,255,255,0.55),
    inset 0 -2px 6px rgba(0,0,0,0.28);
}
.a11y-toggle:active {
  transform: translateY(0) scale(0.98);
}
.a11y-toggle__ring {
  position: absolute;
  inset: 4px;
  border-radius: 999px;
  border: 1.5px solid rgba(255,255,255,0.85);
  pointer-events: none;
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.18);
}
.a11y-toggle__icon {
  position: relative;
  width: 22px;
  height: 22px;
  display: block;
  pointer-events: none;
}
.a11y-toggle__icon circle { fill: #fff; }
.a11y-toggle__icon path {
  stroke: #fff;
  stroke-width: 2.4;
  stroke-linecap: round;
  fill: none;
}
/* issue 28 Phase 2 (WCAG 2.4.7 Focus Visible) — a keyboard-focus ring for every
   focusable thing. Beyond native a/button/input/textarea/select, this also
   covers any element made keyboard-operable at runtime by the screen ARIA
   passes ([tabindex], [role="button"], [role="tab"]) so cards/tabs/etc. that
   gain keyboard focus get a visible indicator. :focus-visible (not :focus)
   keeps mouse clicks ring-free, so the pixel-perfect look is untouched. */
.a11y-toggle:focus-visible,
.a11y-panel button:focus-visible,
.a11y-panel a:focus-visible,
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
[tabindex]:focus-visible,
[role="button"]:focus-visible,
[role="tab"]:focus-visible {
  outline: 3px solid #FACC15 !important;
  outline-offset: 3px !important;
}

.a11y-panel {
  position: fixed;
  right: 16px;
  bottom: 78px;
  z-index: 9999;
  width: min(340px, calc(100vw - 32px));
  background: var(--a11y-panel-bg);
  color: var(--a11y-panel-text);
  border: 1px solid var(--a11y-panel-border);
  border-radius: 14px;
  box-shadow: 0 22px 70px rgba(0,0,0,0.42);
  padding: 16px;
  font-family: 'Heebo', Arial, sans-serif;
}
.a11y-panel[hidden] { display: none !important; }
.a11y-panel__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}
.a11y-panel__title {
  margin: 0;
  color: var(--a11y-panel-accent);
  font-size: 16px;
  font-weight: 900;
}
.a11y-panel__close {
  border: 1px solid var(--a11y-panel-border);
  background: transparent;
  color: var(--a11y-panel-text);
  border-radius: 8px;
  padding: 6px 10px;
  cursor: pointer;
  font: 700 13px/1 'Heebo', Arial, sans-serif;
}
.a11y-panel__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}
.a11y-panel__action {
  min-height: 44px;
  border: 1px solid var(--a11y-panel-border);
  border-radius: 10px;
  background: rgba(255,255,255,0.06);
  color: var(--a11y-panel-text);
  cursor: pointer;
  font: 700 13px/1.25 'Heebo', Arial, sans-serif;
  padding: 8px 10px;
}
.a11y-panel__action[aria-pressed="true"] {
  background: rgba(212,175,55,0.20);
  border-color: rgba(212,175,55,0.70);
  color: #fff;
}
.a11y-panel__note {
  margin-top: 12px;
  color: var(--a11y-panel-muted);
  font-size: 12px;
  line-height: 1.55;
}
.a11y-panel__note a {
  color: var(--a11y-panel-accent);
  font-weight: 700;
}

/* issue 28 (P0 a11y compliance) — the in-app text-resize buttons were removed
   (2026-06-28, founder call). On the SPA's px-heavy custom screens a root
   font-size bump could not enlarge everything, so the control felt inert.
   Native browser pinch-zoom (always available since the viewport lock was
   removed) is the conformant WCAG 1.4.4 mechanism per W3C and scales px text
   too, so the data-a11y-font CSS hook is gone. Contrast / underline /
   reduce-motion below remain. */
html.a11y-contrast body {
  background: #000 !important;
  color: #fff !important;
}
html.a11y-contrast .card,
html.a11y-contrast .consent,
html.a11y-contrast .schedule-list li,
html.a11y-contrast .a11y-panel {
  background: #000 !important;
  border-color: #fff !important;
}
html.a11y-contrast a,
html.a11y-contrast h1,
html.a11y-contrast h2,
html.a11y-contrast h3,
html.a11y-contrast .brand .mark,
html.a11y-contrast .brand .tag {
  color: #fff !important;
}
html.a11y-contrast .btn,
html.a11y-contrast .a11y-toggle {
  background: #fff !important;
  color: #000 !important;
}
html.a11y-contrast .a11y-toggle__ring {
  border-color: #000 !important;
}
html.a11y-contrast .a11y-toggle__icon circle { fill: #000 !important; }
html.a11y-contrast .a11y-toggle__icon path  { stroke: #000 !important; }
html.a11y-underline a {
  text-decoration: underline !important;
  text-decoration-thickness: 2px !important;
  text-underline-offset: 3px !important;
}
html.a11y-reduce-motion *,
html.a11y-reduce-motion *::before,
html.a11y-reduce-motion *::after {
  animation-duration: 0.01ms !important;
  animation-iteration-count: 1 !important;
  scroll-behavior: auto !important;
  transition-duration: 0.01ms !important;
}

@media (max-width: 520px) {
  .a11y-toggle {
    right: 12px;
    bottom: 12px;
    width: 40px;
    height: 40px;
  }
  .a11y-toggle__icon { width: 20px; height: 20px; }
  .a11y-panel { right: 12px; bottom: 60px; width: calc(100vw - 24px); }
}

/* ============================================================
   issue 28 Phase 3 — WCAG 2.1 AA gap closure (P0 legal/compliance)
   Every rule below is Rule #1-safe: this stylesheet is loaded by the shell
   AND auto-injected into every same-origin screen iframe (ensureIframeStylesheet),
   so a selector here reaches every screen WITHOUT editing any design HTML/CSS.
   Grouped by WCAG Success Criterion. Ratios re-verified WITH alpha compositing.
   Plan + evidence: docs/issue-sessions/28-P0-ACCESSIBILITY-PHASE3-PLAN.md
   ============================================================ */

/* ---- §A  1.4.3 Contrast (Minimum) — DEFAULT palette, always on ----
   Conformance is a property of the default delivered state, not the
   high-contrast toggle. */

/* Token bumps. --text-muted .45→.55 lifts muted text platform-wide
   (founder-approved; aligns with Noam's "white, never gray") and fixes the
   muted-on-tint badges that resolve var(--text-muted): meetings
   .ev-chip.full / .full-badge (4.32:1) and barber-free's JS-built 'דורג'
   badge (4.35:1). --color-neutral #6b6b7a→#9898A8 fixes barber-free
   .status-badge.cancelled (3.00:1 → 5.55:1); #9898A8 still passes 1.4.11
   where the token is used as a background (members .avatar-gray). */
:root {
  --text-muted: rgba(255, 255, 255, 0.55) !important;
  --color-neutral: #9898A8 !important;
}

/* Account hint text + dashboard JS-injected empty-states use a literal
   rgba(255,255,255,0.40) (NOT the token) → 3.77–3.83:1. Lift the class plus
   any inline white text whose alpha starts 0.4x to 0.65 (→ ~8:1). The
   selector is scoped to `color:` so it never recolours an element that only
   uses a 0.4-alpha white in a shadow/background; both the non-spaced
   (HTML-parsed source) and spaced (CSSOM-serialized) forms are matched.
   !important beats inline styles set without it. */
.field-help { color: rgba(255, 255, 255, 0.65) !important; }
[style*="color:rgba(255,255,255,0.4"],
[style*="color: rgba(255, 255, 255, 0.4"] { color: rgba(255, 255, 255, 0.65) !important; }

/* Notification count badge: var(--text)=white-90% on --danger #EF4444 =
   3.30:1 (even pure white is only 3.76:1). Darken the red, keep the white
   count (Noam prefers white text). The --danger token is left intact — it is
   used as TEXT elsewhere, where darkening it would lower contrast. Count text is
   also forced to pure #fff (5.74:1) so the 0.90-alpha white doesn't shave the
   margin to 4.87:1 — a single digit on a solid badge, so no design impact. */
.nav-badge { background: #C81E1E !important; color: #fff !important; }

/* Danger label text on translucent danger-dim over a card = 4.28:1. Lift the
   text to #F87171 (→ 5.82:1). Covers the token badge and the members
   .role-marketer role chip, which reuses the same #EF4444-on-dim pair. */
.badge-danger,
.role-marketer { color: #F87171 !important; }

/* Out-of-month calendar dates dim to opacity .26 → 4.28:1 for 12px text
   (these dates are not inactive controls). Nudge to .40 → 4.68:1 (layer-correct
   compositing: .34 only reaches 4.14:1, below the 4.5:1 floor). */
.cal-cell.other { opacity: 0.40 !important; }

/* ---- §B  1.4.11 Non-text Contrast — indicator/track ≥3:1, always on ----
   Each unfilled track/dot/indicator is raised to ≥3:1 against its real
   backdrop; the gold FILLED state (var(--accent), ~9.4:1) stays untouched via
   :not()/state guards so the brand fill is preserved. */
.xp-bar-track,
.progress-track { background: rgba(212, 175, 55, 0.55) !important; }            /* 1.32 → 3.45:1, keeps brand gold */
.xp-track { background: rgba(255, 255, 255, 0.35) !important; }                 /* 1.05 → 3.15:1 */
.course-progress-ring .track { stroke: rgba(255, 255, 255, 0.35) !important; }  /* 1.41 → 3.01:1 */
.tally-mark:not(.filled) { background: rgba(255, 255, 255, 0.35) !important; }  /* 1.31 → 3.25:1 */
.tally-mark.cross::after { background: rgba(255, 255, 255, 0.35) !important; }
.dots .dot:not(.active) { background: rgba(255, 255, 255, 0.38) !important; }   /* 1.91 → 3.50:1; scoped to .dots so it never hits content.html's gold eyebrow .dot */
.task-card:not(.completed) .task-checkbox { border-color: rgba(255, 255, 255, 0.35) !important; } /* 1.31 → 3.25:1 */
.progress-marker.future { background: rgba(255, 255, 255, 0.35) !important; }   /* 1.24 → 3.25:1 */
.detail-progress-track { background: rgba(255, 255, 255, 0.35) !important; }    /* programs detail bar, --border-strong (1.31:1) → 3.25:1; neutral, gold fill stays */
#lessonProgressBar { background: rgba(255, 255, 255, 0.35) !important; }        /* deck progress track, inline --bg-surface (~1.6:1) → ≥3:1 (id+!important beats inline) */

/* ---- §C  1.4.10 Reflow — single column at 320px, no 2-D scroll / 200%-zoom overlap ----
   (R6 meetings calendar @320 and R7/members-table are exception-covered — see plan.
   R2 decks reuse the existing fullscreen pill — see content.html note.) */

/* R1 — mentors carousel is horizontal-only (body{overflow:hidden} makes it the
   sole scroll axis). Stack to a single column under 360px. The iOS card-height
   fix uses vw/svh (not %-of-flex-parent) so it is unaffected. */
@media (max-width: 360px) {
  .carousel {
    flex-direction: column !important;
    overflow-x: hidden !important;
    overflow-y: auto;
    scroll-snap-type: none !important;
    align-items: stretch;
  }
  .slide { width: 100% !important; scroll-snap-align: none; }
}

/* R3 — the 6 library category tabs don't shrink and scroll horizontally; wrap
   instead of scroll at phone widths. */
@media (max-width: 480px) {
  .library-tabs { flex-wrap: wrap !important; overflow-x: hidden !important; }
  .library-tab { flex-shrink: 1; }
}

/* R4 — chapter/lesson titles truncate (nowrap+ellipsis) and lose content at
   320px. Let them wrap; both sit in flex parents with min-width:0. */
@media (max-width: 400px) {
  .chapter-title,
  .lesson-title { white-space: normal !important; overflow: visible !important; text-overflow: clip !important; }
}

/* community — reaction bar scrolls horizontally and the post author name caps
   at 140px with ellipsis; wrap both at phone widths so nothing is hidden. */
@media (max-width: 640px) {
  .reactions-bar { flex-wrap: wrap !important; overflow-x: hidden !important; }
  .post-author-name { max-width: none !important; white-space: normal !important; word-break: break-word; }
}

/* R5 — the topbar screen title has no width constraint and can bleed out of the
   fixed-height topbar at 200% text-zoom. Clamp + ellipsis at every width, always
   leaving the button cluster room (applies to the shell directly). */
.topbar-screen-title {
  max-width: clamp(80px, 45vw, 260px);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---- §D  1.4.12 Text Spacing — opt-in via the "ריווח טקסט" toggle ----
   When html.a11y-spacing is set the widget injects the WCAG metric spacing
   (line-height 1.5, letter-spacing .12em, word-spacing .16em, 2em paragraph
   spacing) AND releases every text clip so no content is lost. The widget's
   own chrome is re-normalised so the controls stay legible. */
html.a11y-spacing body,
html.a11y-spacing body * {
  line-height: 1.5 !important;
  letter-spacing: 0.12em !important;
  word-spacing: 0.16em !important;
}
html.a11y-spacing p { margin-block: 2em !important; }
html.a11y-spacing .a11y-panel,
html.a11y-spacing .a11y-panel *,
html.a11y-spacing .a11y-toggle {
  letter-spacing: normal !important;
  word-spacing: normal !important;
  line-height: normal !important;
}
/* Single-glyph avatar initials are decorative, not text runs; letter-spacing
   appends trailing space that visually off-centres them in their flex circles. */
html.a11y-spacing .avatar,
html.a11y-spacing .user-avatar-initial,
html.a11y-spacing .post-avatar-initial,
html.a11y-spacing .admin-avatar {
  letter-spacing: 0 !important;
}

/* Release -webkit-line-clamp / overflow:hidden card clips. */
html.a11y-spacing .mcard-bio,
html.a11y-spacing .card-desc,
html.a11y-spacing .ig-tile-caption,
html.a11y-spacing .presentation-card-cover-title,
html.a11y-spacing .notification-popup-body,
html.a11y-spacing [data-course-desc] {
  display: block !important;
  -webkit-line-clamp: unset !important;
  overflow: visible !important;
}

/* Release nowrap+ellipsis single-line clips → allow wrap. */
html.a11y-spacing .chapter-title,
html.a11y-spacing .lesson-title,
html.a11y-spacing .nav-item,
html.a11y-spacing .user-name,
html.a11y-spacing .user-role,
html.a11y-spacing .toast,
html.a11y-spacing .ns-title,
html.a11y-spacing .ev-chip,
html.a11y-spacing .course-current-lesson,
html.a11y-spacing .post-author-name,
html.a11y-spacing .detail-link span {
  white-space: normal !important;
  overflow: visible !important;
  text-overflow: clip !important;
}
html.a11y-spacing .user-meta { overflow: visible !important; }
html.a11y-spacing .sidebar-nav { overflow-x: visible !important; }
html.a11y-spacing .detail-link span,
html.a11y-spacing .post-author-name { max-width: none !important; }

/* JS-inline clips that need !important: payments tx rows (data hooks added in
   payments.html) + the content auto-advance overlay next-lesson title (the
   #autoAdvanceOverlay id is unique, so a structural path is reliable without a
   screen edit). */
html.a11y-spacing [data-tx-desc],
html.a11y-spacing [data-tx-meta] {
  white-space: normal !important;
  overflow: visible !important;
  text-overflow: clip !important;
}
html.a11y-spacing #autoAdvanceOverlay > div:first-child > div:nth-child(2) {
  white-space: normal !important;
  overflow: visible !important;
  text-overflow: clip !important;
}

/* Uncap the max-height collapsibles in their OPEN state so injected spacing is
   not clipped (the open animation still works; it just sizes to content). */
html.a11y-spacing .prefs-panel.open,
html.a11y-spacing .notes-panel.open { max-height: none !important; }
html.a11y-spacing .chapter.open .chapter-lessons { max-height: none !important; }

/* A released child's overflow:visible cannot escape a parent that still clips.
   Lift the clipping parents of the released captions/chips/popups too (their
   aspect-ratio crop / rounded-corner clip is forfeited under the toggle, which
   is the correct 1.4.12 trade-off). */
html.a11y-spacing .cal-cell,
html.a11y-spacing .ig-tile,
html.a11y-spacing .notification-popup,
html.a11y-spacing .presentation-card-cover {
  overflow: visible !important;
}

/* ---- §E  Extend the high-contrast toggle (secondary) ----
   The original html.a11y-contrast block covers body/.card/.consent/.schedule-list
   li/.a11y-panel/links/headings/.btn/.toggle. These add the screen-specific
   categories it missed so high-contrast mode is uniform. (The primary 1.4.3
   default-palette fixes for .field-help/.nav-badge/.status-badge.cancelled live in
   §A and apply unconditionally, regardless of this toggle.) */

/* Stat / KPI metric containers (not .card) — give them the b/w card treatment. */
html.a11y-contrast .stat-card,
html.a11y-contrast .kpi-card {
  background: #000 !important;
  border-color: #fff !important;
}

/* All badge / status-chip / role-chip variants → uniform black/white with a
   visible border (otherwise their solid-gold or tinted backgrounds survive the
   body:#000 rule). */
html.a11y-contrast .badge-gold,
html.a11y-contrast .badge-success,
html.a11y-contrast .badge-warning,
html.a11y-contrast .badge-danger,
html.a11y-contrast .badge-info,
html.a11y-contrast .badge-xp,
html.a11y-contrast .level-badge,
html.a11y-contrast .admin-badge,
html.a11y-contrast .card-status-badge,
html.a11y-contrast .status-badge,
html.a11y-contrast .content-badge,
html.a11y-contrast .upsell-badge,
html.a11y-contrast .profile-upsell-badge,
html.a11y-contrast .course-tier-badge,
html.a11y-contrast .hero-meeting-badge,
html.a11y-contrast .xp-badge,
html.a11y-contrast .cohort-badge-new,
html.a11y-contrast .welcome-badge,
html.a11y-contrast .product-badge,
html.a11y-contrast .role-marketer,
html.a11y-contrast .role-franchisee,
html.a11y-contrast .role-content_organiser {
  background: #000 !important;
  color: #fff !important;
  border: 1px solid #fff !important;
}

/* Status dots → max-saturation primaries, drop the glow (color halation blurs
   the 3:1 boundary). Adjacent Hebrew labels carry the meaning (1.4.1). */
html.a11y-contrast .dot-active { background: #0f0 !important; box-shadow: none !important; }
html.a11y-contrast .dot-inactive { background: #f00 !important; box-shadow: none !important; }
html.a11y-contrast .dot-new { background: #0ff !important; box-shadow: none !important; }

/* Sidebar section divider labels. */
html.a11y-contrast .nav-section-label { color: #fff !important; }

/* Placeholders → brighter so they survive forced-black inputs. */
html.a11y-contrast .input::placeholder,
html.a11y-contrast input::placeholder,
html.a11y-contrast textarea::placeholder {
  color: rgba(255, 255, 255, 0.85) !important;
}

/* Form controls — the resting border is ~1.32:1; force a real boundary. The
   gold focus ring already passes; checkbox/radio/button types are excluded so
   their distinct treatments survive. */
html.a11y-contrast .input,
html.a11y-contrast input:not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="button"]):not([type="reset"]):not([type="image"]),
html.a11y-contrast textarea,
html.a11y-contrast select {
  background: #000 !important;
  border: 1px solid #fff !important;
  color: #fff !important;
}

/* Filter / category chips — strip the gold active background for b/w. */
html.a11y-contrast .chip,
html.a11y-contrast .filter-chip {
  background: #000 !important;
  color: #fff !important;
  border-color: #fff !important;
}
html.a11y-contrast .chip.active,
html.a11y-contrast .filter-chip.active {
  background: #fff !important;
  color: #000 !important;
  border-color: #fff !important;
}

/* issue 28B / Option A (2026-07-01): the double-tap-zoom block + its release
   toggle were removed. Double-tap works natively everywhere; pinch-zoom is
   always available (WCAG 1.4.4). No touch-action rule is needed here. */
