/* -- Slider component ------------------------------------------- */

@layer components {
  /* Everything runs through a few private variables so a .slider-range
     wrapper (two thumbs) can hand its size and color down to both inputs:
     --_track / --_thumb (set by data-size, on the slider or on the range),
     --_c (set by data-tone) and the public --slider-color for any color.
     --_fill resolves them once, here, on the input. */
  .slider {
    --slider-value: 50%;
    --_fill: var(--_c, var(--slider-color, var(--primary)));
    --_t: var(--_track, 0.5rem);
    --_d: var(--_thumb, 1.25rem);
    --_dir: to right;
    -webkit-appearance: none;
    appearance: none;
    width: 100%;
    /* the UA gives a range a 2px margin: with width 100% the track would
       overflow its box and drift off a .slider-marks scale */
    margin-inline: 0;
    height: var(--_t);
    border-radius: 9999px;
    background: var(--secondary);
    cursor: pointer;
    outline: none;
    border: none;
    accent-color: var(--_fill);

    /* Track - WebKit (filled via gradient) */
    &::-webkit-slider-runnable-track {
      height: var(--_t);
      border-radius: 9999px;
      background: linear-gradient(
        var(--_dir),
        var(--_fill) 0%,
        var(--_fill) var(--slider-value),
        var(--secondary) var(--slider-value),
        var(--secondary) 100%
      );
    }

    /* Track - Firefox */
    &::-moz-range-track {
      height: var(--_t);
      border-radius: 9999px;
      background: var(--secondary);
      border: none;
    }

    /* Filled portion - Firefox */
    &::-moz-range-progress {
      height: var(--_t);
      border-radius: 9999px;
      background: var(--_fill);
    }

    /* Thumb - WebKit (re-centered on the track: (track - thumb) / 2).
       --slider-thumb-image paints a picture (an emoji, see data-thumb) */
    &::-webkit-slider-thumb {
      -webkit-appearance: none;
      width: var(--_d);
      height: var(--_d);
      border-radius: 50%;
      background: var(--slider-thumb-image, none) center / 100% no-repeat, var(--background);
      border: 2px solid var(--_fill);
      margin-top: calc((var(--_t) - var(--_d)) / 2);
      cursor: pointer;
      transition: box-shadow 150ms, scale 150ms;
    }

    /* Thumb - Firefox */
    &::-moz-range-thumb {
      width: var(--_d);
      height: var(--_d);
      border-radius: 50%;
      background: var(--slider-thumb-image, none) center / 100% no-repeat, var(--background);
      border: 2px solid var(--_fill);
      cursor: pointer;
      transition: box-shadow 150ms, scale 150ms;
    }

    /* Hover */
    &:hover:not(:disabled) {
      &::-webkit-slider-thumb {
        box-shadow: 0 0 0 4px color-mix(in oklch, var(--_fill) 15%, transparent);
      }
      &::-moz-range-thumb {
        box-shadow: 0 0 0 4px color-mix(in oklch, var(--_fill) 15%, transparent);
      }
    }

    /* Focus */
    &:focus-visible {
      &::-webkit-slider-thumb {
        outline: 2px solid var(--ring);
        outline-offset: 2px;
      }
      &::-moz-range-thumb {
        outline: 2px solid var(--ring);
        outline-offset: 2px;
      }
    }

    /* Disabled */
    &:disabled {
      opacity: 0.5;
      cursor: not-allowed;

      &::-webkit-slider-thumb { cursor: not-allowed; }
      &::-moz-range-thumb { cursor: not-allowed; }
    }

    /* RTL: the range runs right to left, so does the fill */
    &:dir(rtl) { --_dir: to left; }

    /* Vertical orientation */
    &[data-orientation="vertical"] {
      --_dir: to top;
      writing-mode: vertical-lr;
      direction: rtl;
      width: var(--_t);
      height: 12rem;

      &::-webkit-slider-runnable-track { width: var(--_t); height: auto; }
      &::-webkit-slider-thumb {
        margin-top: 0;
        margin-left: calc((var(--_t) - var(--_d)) / 2);
      }
    }

    /* -- Emoji thumb: data-thumb="emoji" (slider.js draws the emoji from
       data-thumb-emoji into --slider-thumb-image) - no ring, no fill disc,
       a bit larger than the plain thumb. */
    &[data-thumb="emoji"] {
      --_d: var(--_thumb, 2rem);

      &::-webkit-slider-thumb { border: 0; background-color: transparent; }
      &::-moz-range-thumb { border: 0; background-color: transparent; }
      &:active::-webkit-slider-thumb { scale: 1.15; }
      &:active::-moz-range-thumb { scale: 1.15; }
    }
  }

  /* -- Sizes: track thickness + thumb diameter (md == the default) ----
     On a .slider or on a .slider-range (both inputs inherit). */
  :is(.slider, .slider-range, .slider-marks) {
    &[data-size="xs"] { --_track: 0.25rem; --_thumb: 0.75rem; }
    &[data-size="sm"] { --_track: 0.375rem; --_thumb: 1rem; }
    &[data-size="md"] { --_track: 0.5rem; --_thumb: 1.25rem; }
    &[data-size="lg"] { --_track: 0.625rem; --_thumb: 1.5rem; }
    &[data-size="xl"] { --_track: 0.75rem; --_thumb: 1.75rem; }

    /* -- Tones: success / warning / info / destructive; any other color
       via style="--slider-color: …" */
    &[data-tone="success"] { --_c: oklch(0.6 0.15 150); }
    &[data-tone="warning"] { --_c: oklch(0.78 0.16 75); }
    &[data-tone="info"] { --_c: oklch(0.6 0.16 250); }
    &[data-tone="destructive"] { --_c: var(--destructive); }
  }

  /* -- Marks: a CSS-only tick scale under a stepped slider ------------
     <div class="slider-marks" aria-hidden="true"> right after the slider
     (or range); each child is a zero-width flex item, so space-between
     lands the tick centres on the thumb-centre travel (inset by half a
     thumb at each end). The tick is generated, the child's text is the
     optional label. It follows the slider's data-size when it is the
     slider's next sibling (or set data-size on the marks). */
  .slider-marks {
    display: flex;
    justify-content: space-between;
    padding-inline: calc(var(--_thumb, 1.25rem) / 2);
    margin-top: 0.375rem;
    font-size: 0.6875rem;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    color: var(--muted-foreground);

    & > * {
      /* zero-width: flex-basis 0 alone leaves min-width:auto, which would
         widen the item to its label and push the tick off its step */
      flex: 0 0 0;
      min-width: 0;
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 0.25rem;
      white-space: nowrap;
    }
    & > *::before {
      content: "";
      width: 1px;
      height: 0.375rem;
      background: var(--border);
    }
    /* a tick without a label (an empty child) stays a short tick */
    & > :empty::before { height: 0.25rem; }
  }
  :is(.slider, .slider-range)[data-size="xs"] + .slider-marks:not([data-size]) { --_thumb: 0.75rem; }
  :is(.slider, .slider-range)[data-size="sm"] + .slider-marks:not([data-size]) { --_thumb: 1rem; }
  :is(.slider, .slider-range)[data-size="lg"] + .slider-marks:not([data-size]) { --_thumb: 1.5rem; }
  :is(.slider, .slider-range)[data-size="xl"] + .slider-marks:not([data-size]) { --_thumb: 1.75rem; }

  /* -- Range: two thumbs on one track ---------------------------------
     Two .slider inputs stacked in a .slider-range; only their thumbs take
     the pointer, the wrapper paints one track with the span between the
     thumbs filled (slider.js keeps --range-from / --range-to in sync and
     the low value <= the high one). Each input keeps its own keyboard,
     label and State API. */
  .slider-range {
    --range-from: 25%;
    --range-to: 75%;
    --_fill: var(--_c, var(--slider-color, var(--primary)));
    --_dir: to right;
    position: relative;
    display: block;
    width: 100%;
    height: var(--_thumb, 1.25rem);

    &::before {
      content: '';
      position: absolute;
      inset-inline: 0;
      top: 50%;
      height: var(--_track, 0.5rem);
      translate: 0 -50%;
      border-radius: 9999px;
      background: linear-gradient(
        var(--_dir),
        var(--secondary) var(--range-from),
        var(--_fill) var(--range-from),
        var(--_fill) var(--range-to),
        var(--secondary) var(--range-to)
      );
    }
    &:dir(rtl) { --_dir: to left; }

    & > .slider {
      position: absolute;
      inset-inline: 0;
      top: 50%;
      translate: 0 -50%;
      margin: 0;
      background: none;
      pointer-events: none;

      &::-webkit-slider-runnable-track { background: none; }
      &::-moz-range-track { background: none; }
      &::-moz-range-progress { background: none; }
      &::-webkit-slider-thumb { pointer-events: auto; }
      &::-moz-range-thumb { pointer-events: auto; }
    }
    /* the thumb last moved stays on top (both can reach the same value) */
    & > .slider[data-active] { z-index: 1; }

    &:has(.slider:disabled) { opacity: 0.5; }
  }

  /* -- Field: icons, emojis and values around a slider ----------------- */
  .slider-field {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    width: 100%;

    & > :is(.slider, .slider-range) { flex: 1 1 auto; min-width: 0; }
  }
  .slider-icon {
    display: inline-grid;
    place-items: center;
    flex-shrink: 0;
    width: 1.25rem;
    height: 1.25rem;
    font-size: 1.125rem;
    line-height: 1;
    color: var(--muted-foreground);

    & svg { width: 1.125rem; height: 1.25rem; }
  }
  .slider-value {
    flex-shrink: 0;
    min-width: 3.5em;
    text-align: end;
    font-size: 0.875rem;
    font-variant-numeric: tabular-nums;
    color: var(--foreground);
  }
  /* a scale under the track: the first and last labels align to the ends */
  .slider-scale {
    display: flex;
    justify-content: space-between;
    margin-top: 0.375rem;
    font-size: 0.75rem;
    font-variant-numeric: tabular-nums;
    color: var(--muted-foreground);
  }

  /* Reduced motion */
  @media (prefers-reduced-motion: reduce) {
    .slider {
      &::-webkit-slider-thumb { transition: none; }
      &::-moz-range-thumb { transition: none; }
    }
  }

  /* High contrast */
  @media (prefers-contrast: more) {
    .slider-marks { color: var(--foreground); & > *::before { background: var(--foreground); } }
    .slider {
      &::-webkit-slider-thumb {
        border-width: 3px;
      }
      &::-moz-range-thumb {
        border-width: 3px;
      }
    }
  }

  /* Forced colors (Windows High Contrast Mode) */
  @media (forced-colors: active) {
    .slider-marks { color: CanvasText; & > *::before { background: CanvasText; } }
    .slider {
      &::-webkit-slider-runnable-track {
        background: ButtonFace;
        border: 1px solid ButtonText;
      }
      &::-moz-range-track {
        background: ButtonFace;
        border: 1px solid ButtonText;
      }
      &::-moz-range-progress {
        background: Highlight;
      }
      &::-webkit-slider-thumb {
        background: ButtonText;
        border-color: ButtonText;
      }
      &::-moz-range-thumb {
        background: ButtonText;
        border-color: ButtonText;
      }

      &:focus-visible {
        &::-webkit-slider-thumb {
          outline-color: Highlight;
        }
        &::-moz-range-thumb {
          outline-color: Highlight;
        }
      }
    }
    .slider-range::before { background: Highlight; }
  }
}
