/* SLASHED — core/states.css
   @layer slashed.states
   Generic runtime states toggled by JS or ARIA: visibility, interactivity, selection, busy/current.
   Prefix: .sf-is-*; not utilities or component-specific variants.

   Reach for a native mechanism first — a pseudo-class (:disabled, :read-only,
   :empty, :user-invalid), a boolean/enumerated attribute ([hidden], [disabled],
   [readonly]), or an ARIA state ([aria-busy], [aria-current], [aria-expanded],
   [aria-selected], [aria-pressed]) — since the browser (and assistive tech)
   already understands it for free. Add a .sf-is-* class only for states with
   no native equivalent, or ones this file's own tokens/consumers need as a
   hook (see docs/states.md). See docs/states.md § "Prefer native state" for
   the full rationale and the [hidden] precedent that got .sf-is-hidden
   removed in favour of the attribute it duplicated. */

@layer slashed.states {

  /* No visibility classes here: .sf-is-hidden duplicated [hidden] (removed —
     core/reset.css hardens that attribute identically). .sf-invisible /
     .sf-visible moved to optional/utilities.css as single-property helpers
     (same call as Bulma's is-hidden/is-invisible living under "helpers",
     not component/state docs) — still the hook docs/roadmap.md's
     reveal-on-scroll pattern targets, just renamed and relocated. */

  /* -- INTERACTIVITY --
     No .sf-is-readonly here: it duplicated :read-only for real form controls,
     and its pointer-events:none blocked text selection that a genuinely
     read-only field should still allow — reach for :read-only, or
     [aria-readonly] on a non-native widget, instead. */

  /* cursor: not-allowed inherits to children with pointer-events: auto —
     intentional, part of the .sf-is-disabled API surface. */
  .sf-is-disabled {
    opacity:        var(--sf-opacity-disabled);
    pointer-events: none;

    cursor:         not-allowed;
    user-select:    none;
  }

  /* -- LOADING / ASYNC FEEDBACK -- */

  .sf-is-loading {
    color:          transparent !important;
    pointer-events: none;
    position:       relative;
  }

  .sf-is-loading > * {
    opacity: 0 !important;
  }

  .sf-is-loading::after {
    content:             "";
    position:            absolute;
    inset-block-start:   50%;
    inset-inline-start:  50%;
    inline-size:         1em;
    block-size:          1em;
    margin-block-start:  -0.5em;
    margin-inline-start: -0.5em;
    border:        var(--sf-border-width-2) solid var(--sf-color-border--strong);
    border-block-start-color: var(--sf-color-action);
    border-radius: var(--sf-radius-full);

    animation: var(--sf-animation-spin);
  }

  /* No .sf-is-busy / .sf-is-pending here: both were a couple of
     property-value declarations (cursor:progress, plus opacity for
     pending's "optimistic UI" dimming) with no consumer and no native gap
     they filled — [aria-busy="true"] covers the semantic, and the visual
     is two lines to hand-roll in your own component CSS if you want it. */

  /* Shimmer loading placeholder (was .sf-is-skeleton pre-Unreleased; renamed so
     "skeleton" names only the planned .sf-skeleton component, not a state —
     see docs/migration.md and roadmap.md #575). The class name now mirrors its
     driving token, --sf-animation-shimmer. */
  img.sf-is-shimmer,
  .sf-is-shimmer img {
    opacity: 0 !important;
  }

  .sf-is-shimmer {
    color:           transparent !important;
    background:      linear-gradient(
                       90deg,
                       var(--sf-color-inset) 25%,
                       var(--sf-color-raised) 50%,
                       var(--sf-color-inset) 75%
                     );
    background-size: 200% 100%;
    animation: var(--sf-animation-shimmer);
    border-radius:   var(--sf-radius-s);
    pointer-events:  none;
    user-select:     none;
  }

  /* -- SELECTED / HIGHLIGHTED --
     No .sf-is-active / .sf-is-open / .sf-is-collapsed / .sf-is-expanded /
     .sf-is-current / .sf-is-pressed here: these only ever set an
     inheritable --sf-is-* custom property for a hypothetical consumer
     calc() to branch on, with zero consumer anywhere in this codebase or
     its demo. Speculative "might be useful one day" surface, removed —
     see docs/states.md § "Prefer native state". Reach for [aria-current],
     [aria-expanded], [aria-pressed] as the styling hook instead; .sf-is-
     selected / .sf-is-highlighted below cover the two cases (selection,
     transient emphasis) that still need their own visual. */

  .sf-is-selected {
    background-color: var(--sf-color-bg--selected);
  }

  .sf-is-highlighted {
    background-color: var(--sf-color-bg--focus);
  }

  /* -- VALIDATION / FEEDBACK --
     No .sf-is-danger here: identical implementation to .sf-is-invalid/
     .sf-is-error (both only ever wrote --sf-field-*, so it never worked as
     the "destructive-action context" its own docs described outside a form
     field) and, per docs/migration.md, visual variants belong in your own
     component CSS anyway. Use .sf-is-invalid/.sf-is-error, or your own
     `--danger` variant class, instead. */

  .sf-is-valid,
  .sf-is-success {
    --sf-field-border-color: var(--sf-color-success);
    --sf-field-text-color:   var(--sf-color-success-strong);
  }

  .sf-is-invalid,
  .sf-is-error {
    --sf-field-border-color: var(--sf-color-danger);
    --sf-field-text-color:   var(--sf-color-danger-strong);
  }

  .sf-is-warning {
    --sf-field-border-color: var(--sf-color-warning);
    --sf-field-text-color:   var(--sf-color-warning-strong);
  }

  .sf-is-info {
    --sf-field-border-color: var(--sf-color-info);
    --sf-field-text-color:   var(--sf-color-info-strong);
  }

  /* -- DRAG & DROP -- */

  .sf-is-dragging {
    opacity: var(--sf-opacity-muted);
    cursor:  grabbing;
  }

  .sf-is-drop-target {
    outline:        var(--sf-focus-ring-width) dashed var(--sf-color-action);
    outline-offset: var(--sf-focus-ring-offset);
  }

  .sf-is-draggable {
    cursor: grab;
  }

  /* -- EMPTY STATE -- */

  .sf-is-empty:empty {
    display: none;
  }

  /* KEYFRAMES (used by states above) */

}
