/*
Switch

A native <input type="checkbox" role="switch"> drawn as a track, with a
thumb that slides by transform. The track never changes size; only its
color and the thumb's position change.

  .switch                       wrapper (inline-grid; track and thumb stack)
  .switch.is-sm                 smaller track
  .switch-input                 the input, drawn as the track
  .switch-thumb                 the knob, pointer-events: none
  .switch[data-state]           checked | unchecked

Size derives from the contract's --check-size; the off edge is
--control-outline, the knob --switch-thumb and --switch-thumb-checked.
*/

@layer components {

.switch {
  --switch-h:     calc(var(--check-size) * 1.15);
  --switch-w:     calc(var(--switch-h) * 1.8);
  --switch-inset: calc(var(--control-border-width) * 2);

  position:       relative;
  display:        inline-grid;
  flex:           none;
  align-items:    center;
  width:          var(--switch-w);
  height:         var(--switch-h);
  vertical-align: middle;
}

.switch.is-sm {
  --switch-h: calc(var(--check-size) * 0.875);
}

.switch > * {
  grid-area: 1 / 1;
}

.switch-input {
  appearance:         none;
  -webkit-appearance: none;
  display:            block;
  width:              100%;
  height:             100%;
  margin:             0;
  border:             0;
  border-radius:      var(--radius-pill);
  background:         var(--rule-strong);
  background-image:   none;
  box-shadow:         var(--control-shadow);
  outline:            var(--control-border-width) solid var(--control-outline);
  outline-offset:     calc(-1 * var(--control-border-width));
  cursor:             pointer;
  transition:         background-color var(--duration-fast) var(--ease-out),
                      box-shadow var(--duration-fast) var(--ease-out);
}

.switch-input:checked {
  background:       var(--accent);
  background-image: none;
  outline:          none;
}

.switch-input:focus-visible {
  outline:    none;
  box-shadow: var(--focus-ring);
}

.switch-thumb {
  justify-self:   start;
  width:          calc(var(--switch-h) - 2 * var(--switch-inset));
  height:         calc(var(--switch-h) - 2 * var(--switch-inset));
  /* start is the inline start, the right under rtl: only the slide flips. */
  margin-inline-start: var(--switch-inset);
  border-radius:  var(--radius-pill);
  /* A light knob in both modes (shadcn), until the contract names one
     (notes/theme-requests.md). */
  background:     var(--switch-thumb);
  box-shadow:     var(--shadow-xs);
  pointer-events: none;
  transform:      translateX(0);
  transition:     transform var(--duration-fast) var(--ease-out),
                  background-color var(--duration-fast) var(--ease-out);
}

.switch[data-state="checked"] > .switch-thumb {
  background: var(--switch-thumb-checked);
  transform:  translateX(calc(var(--switch-w) - var(--switch-h)));
}

.switch:dir(rtl)[data-state="checked"] > .switch-thumb {
  transform: translateX(calc(var(--switch-h) - var(--switch-w)));
}

/* States */

.switch-input:disabled {
  cursor: not-allowed;
}

/* Dimmed by the effective disabled state: its own prop, a disabled Field
   (which disables the input) or a native <fieldset disabled>. */
.switch:is([data-disabled], :has(> .switch-input:disabled)) {
  opacity: var(--opacity-disabled);
}

/* Disabled dims once: the wrapper does it, so the input does not repeat the
   base input rule, and a label or Field that already dims the control's
   whole row leaves the wrapper at full opacity. */
.switch-input:disabled {
  opacity: 1;
}

:is(.label:has(:disabled), .label[data-disabled], .field-label:has(:disabled), .field:is([data-disabled], fieldset:disabled .field) > :is(.field-label, .field-content)) .switch {
  opacity: 1;
}

.switch-input[aria-invalid="true"] {
  box-shadow:    inset 0 0 0 var(--control-border-width) var(--danger);
  outline-color: var(--danger);
}

.switch-input[aria-invalid="true"]:focus-visible {
  box-shadow: var(--focus-ring-danger);
}

}
