/* SLASHED — core/accessibility.css
   @layer slashed.accessibility
   Focus rings, screen-reader helpers, skip links, and reduced-friction a11y utilities.
   Prefix: .sf-* plus native focus selectors. */

@layer slashed.accessibility {

  /* Focus */
  :focus:not(:focus-visible) {
    outline: none;
  }

  :focus-visible {
    outline:        var(--sf-focus-ring-width) var(--sf-focus-ring-style, solid) var(--sf-focus-ring-color) !important;
    outline-offset: var(--sf-focus-ring-offset) !important;
  }

  /* .sf-focus-shadow: replaces outline ring with box-shadow ring; !important required
     to take over the hardened :focus-visible outline (WCAG 2.4.7 still met). */
  .sf-focus-shadow:focus-visible {
    outline:    none                         !important;
    box-shadow: var(--sf-focus-ring-shadow)  !important;
  }

  /* forced-colors: box-shadow vanishes — restore outline ring for WCAG 2.4.7
     in Windows High Contrast. */
  @media (forced-colors: active) {
    .sf-focus-shadow:focus-visible {
      outline:        var(--sf-focus-ring-width) solid !important;
      outline-offset: var(--sf-focus-ring-offset) !important;
      box-shadow:     none !important;
    }
  }

  /* Reduced motion. Token override helps components that read */
  @media (prefers-reduced-motion: reduce) {
    :root {
      --sf-duration-instant: 0.01ms;
      --sf-duration-fast:    0.01ms;
      --sf-duration-normal:  0.01ms;
      --sf-duration-slow:    0.01ms;
      --sf-duration-slower:  0.01ms;
    }

    *,
    *::before,
    *::after {
      animation-duration:        0.01ms !important;
      animation-iteration-count: 1      !important;
      transition-duration:       0.01ms !important;
      scroll-behavior:           auto   !important;
    }
  }

  .no-motion,
  .no-motion *,
  .no-motion *::before,
  .no-motion *::after {
    animation-duration:        0.01ms !important;
    animation-iteration-count: 1      !important;
    transition-duration:       0.01ms !important;
    scroll-behavior:           auto   !important;
  }

  /* High contrast */
  @media (prefers-contrast: more) {
    :root {
      --sf-focus-ring-width: 3px;

      --sf-contrast-bias: 0.06;
    }

    hr {
      border-block-start-width: var(--sf-border-width-2);
    }
  }

  @media (prefers-reduced-transparency: reduce) {
    ::backdrop {
      background-color: var(--sf-color-neutral);
      opacity:          1;
    }
  }

  /* Reduced data */
  @media (prefers-reduced-data: reduce) {
    :root {
      --sf-shadow-strength: 0;
      --sf-blur: 0px;
    }
  }

  /* Minimum touch targets — a backstop for genuinely bare, unstyled controls.
     The floor targets only controls that carry NO class at all. The moment a
     control has any class it is considered *owned* — by SLASHED itself (.sf-btn
     owns a deliberate XS–XL size ladder via --sf-btn-min-height / --sf-size-*
     rungs), by the author, or by a third-party widget (a page-builder hamburger
     toggle, a plugin control) — and its sizing belongs to whoever put that class
     there, not to this blanket rule.

     Why so conservative: a blanket floor on *every* button/control silently
     overrode its owners. It collapsed .sf-btn's whole size ladder to one height
     on touch, and it stretched narrow custom widgets (e.g. a hamburger icon
     button) to 44px on BOTH axes — at a specificity higher than a single class,
     so the owner couldn't even override it without !important. Element-level
     selectors that reach for someone else's markup are the "too aggressive base
     style" trap; scoping the floor to classless controls keeps it from ever
     touching markup the framework doesn't own. It extends the "un-styled
     element" idiom already used for `a:not([class])` in base.

     "Un-styled" here means *no effective class* — no class attribute at all, OR
     an empty one (`class=""`), which templating/component renderers routinely
     emit for a control the author never styled. Both keep the floor. The test
     is written `:not([class]:not([class=""]))` — read it as "not (has a
     non-empty class)": it excludes only controls carrying a real class token.
     (A whitespace-only `class=" "` is treated as owned; that pathological case
     isn't worth widening the selector for.) `:where()` keeps the element list
     at zero specificity so the whole rule stays a low, easily-reasoned weight.

     Bare `<button>text</button>` and un-classed native controls — almost always
     the author's own quick markup — keep the WCAG 2.5.5 44px floor on both axes.
     To opt a control OUT, give it any class. To put the floor back ON an owned
     control, add the .sf-touch-target opt-in class below, set its own
     min-block/inline-size, or on .sf-btn use
     `--sf-btn-min-height: var(--sf-touch-target)`. */
  @media (pointer: coarse) {
    :where(
      button,
      input[type="button"], input[type="submit"], input[type="reset"],
      select, summary,
      input[type="checkbox"], input[type="radio"]
    ):not([class]:not([class=""])) {
      min-block-size:  var(--sf-touch-target);
      min-inline-size: var(--sf-touch-target);
    }
  }

  /* .sf-touch-target — the explicit opt-IN counterpart to the class-less floor
     above. Because the automatic floor deliberately never touches a control
     that carries a class, put this class on any control you own (a button with
     your own class, a third-party widget you can add a class to) to guarantee
     the WCAG 2.5.5 44px minimum hit area on both axes. Unlike the automatic
     floor it is NOT gated to a coarse pointer — an explicit opt-in is
     predictable everywhere. Size follows --sf-touch-target, so a wrapper (or
     the element itself) can retune it locally.

       <button class="my-menu-toggle sf-touch-target" aria-label="Menu">…</button>

     It sets ONLY the two min-size properties — deliberately no `display` — so it
     never strips a native affordance (e.g. a <summary>'s list-item marker, a
     control's baseline alignment). It therefore expects a target whose display
     already honours min-inline-size: buttons and native form controls
     (inline-block/flex) do. On a purely inline element (a bare <a>) add your own
     `display: inline-flex` (or inline-block) alongside it.

     No !important: it's a single class (specificity 0,1,0), so your own
     component rule can still override it when a specific control needs to opt
     back out. */
  .sf-touch-target {
    min-block-size:  var(--sf-touch-target);
    min-inline-size: var(--sf-touch-target);
  }

  /* Disabled states */
  [disabled],
  [aria-disabled="true"] {
    cursor:  not-allowed;
    opacity: var(--sf-opacity-disabled);
  }

  /* Screen-reader-only. Atomic contract: partial override either exposes hidden content
     or hides intended content — all-or-nothing, whole set hardened. */
  .sr-only,
  .sr-only-focusable:not(:focus, :focus-within) {
    position:    absolute            !important;
    width:       1px                 !important;
    height:      1px                 !important;
    padding:     0                   !important;
    margin:      -1px                !important;
    overflow:    hidden              !important;
    overflow:    clip                !important;
    clip-path:   inset(50%)          !important;
    white-space: nowrap              !important;
    border:      0                   !important;
  }

  /* Skip link */
  .skip-link {
    position:          absolute;
    inset-block-start: -100%;
    inset-inline-start: var(--sf-space-m);
    z-index:           var(--sf-z-tooltip);
    padding:           var(--sf-space-s) var(--sf-space-m);
    background:        var(--sf-color-bg);
    color:             var(--sf-color-text);
    border:            var(--sf-border-width-1) solid var(--sf-color-border);
    border-radius:     var(--sf-radius-m);
    transition:        inset-block-start var(--sf-duration-fast) var(--sf-ease-out);
  }
  .skip-link:focus {
    inset-block-start: var(--sf-space-m);
  }

  /* Focus-parent */

  .sf-focus-parent:focus-within {
    outline:        var(--sf-focus-ring-width) var(--sf-focus-ring-style, solid) var(--sf-focus-ring-color);
    outline-offset: var(--sf-focus-ring-offset);
  }

  /* Clickable-parent */
  /* Perf note (SL-002): the two selector groups below each combine multiple
     :has()-bearing branches, forcing subtree re-evaluation on DOM mutation
     inside .sf-clickable-parent. Fine for typical card/list-item usage; avoid
     applying this class to large (100+ node) grids or lists without profiling
     first. */
  .sf-clickable-parent {
    --sf-clickable-overlay-z: 1;
    position: relative;
    cursor:   pointer;
  }

  .sf-clickable-parent:not(:has([data-overlay-link], .sf-clickable-parent__overlay)) a:where(:any-link)::after,
  .sf-clickable-parent [data-overlay-link]::after,
  .sf-clickable-parent .sf-clickable-parent__overlay::after {
    content:        "";
    position:       absolute;
    inset:          0;
    z-index:        var(--sf-clickable-overlay-z);
    pointer-events: auto;
  }

  .sf-clickable-parent :is(
    button, input, textarea, select,
    summary, video, audio,
    [role="button"], [data-no-overlay]
  ),
  .sf-clickable-parent:has([data-overlay-link]) a:where(:any-link):not([data-overlay-link]),
  .sf-clickable-parent:has(.sf-clickable-parent__overlay) a:where(:any-link):not(.sf-clickable-parent__overlay),
  .sf-clickable-parent:not(:has([data-overlay-link], .sf-clickable-parent__overlay)) a:where(:any-link):not(:first-of-type) {
    position: relative;
    z-index:  calc(var(--sf-clickable-overlay-z) + 1);
  }

  .sf-clickable-parent:focus-within {
    outline:        var(--sf-focus-ring-width) var(--sf-focus-ring-style, solid) var(--sf-focus-ring-color);
    outline-offset: var(--sf-focus-ring-offset);
  }

  /* Forced colors (Windows High Contrast). Outline-based focus */
  @media (forced-colors: active) {
    :root {
      --sf-focus-ring-color: Highlight;
    }

    :focus-visible {
      outline-color: Highlight !important;
    }

    :where(*) {
      box-shadow:  none;
      text-shadow: none;
    }

    input,
    select,
    textarea {
      border: var(--sf-border-width-1) solid;
    }

    button,
    input[type="submit"],
    input[type="reset"],
    input[type="button"] {
      border-color: ButtonBorder !important;
    }

    .sf-text-gradient {
      background-image:         none !important;
      /* stylelint-disable-next-line property-no-vendor-prefix */
      -webkit-background-clip:  unset !important;
      background-clip:          unset !important;
      color:                    CanvasText !important;
    }

    .sf-is-loading::after {
      border-color:             ButtonText !important;
      border-block-start-color: Highlight !important;
    }
  }

}
