/* ============================================================
   Tab Switch — replica of Framer Marketplace "Swtich on hover tabs"
   (Suraj Kale). Measured from switchonhover.framer.website.
   Numbers here are measured, not guessed. See SPEC.md.
   ============================================================ */

.tabswitch {
  /* ---- geometry (measured) ---- */
  --ts-rail-w: 300px;
  --ts-pad: 18px 14px 22px 22px;
  --ts-gap: 8px;
  --ts-radius: 12px;
  --ts-notch: 20px;

  /* ---- palette (measured) ---- */
  --ts-active-bg: rgb(226, 232, 240);
  --ts-title: rgb(0, 0, 0);
  --ts-body: rgb(100, 116, 139);
  --ts-panel-pad: 10px;

  /* ---- motion (measured) ----
     Three channels, three different timings. The description has NO
     opacity animation at all: measured effective opacity is 1 from the
     first frame it exists, and it is revealed purely by the growing
     container clipping it.

     The background colour does NOT ride the height spring - measured
     separately at 190ms on its own curve, so the active pill has
     finished colouring while the height is still settling. */
  --ts-bg-dur: 190ms;
  --ts-bg-ease: cubic-bezier(0.196, 0.028, 0.38, 0.993);

  /* The reference hard-swaps the panel image (one <img>, src replaced,
     opacity never leaves 1). 0ms reproduces that; raise it if you want
     a crossfade the original does not have. */
  --ts-shot-fade: 0ms;

  /* Height is a Framer Motion spring: stiffness 300, damping 50, mass 1
     (overdamped; poles -43.03 and -6.97). A cubic-bezier cannot express
     it - any bezier fitted to the tail launches far too fast at the
     start, which cost 6.6px in the first take. CSS linear() samples the
     real spring and lands within 0.55px across the 71px travel.
     Regenerate with _process/spring2linear.js if you retune it. */
  --ts-expand-dur: 1120ms;
  --ts-expand-ease: linear(0.0000 0.0%, 0.0654 2.3%, 0.1848 4.5%, 0.3065 6.8%, 0.4156 9.1%, 0.5095 11.4%, 0.5888 13.6%, 0.6555 15.9%, 0.7115 18.2%, 0.7584 20.5%, 0.7977 22.7%, 0.8306 25.0%, 0.8581 27.3%, 0.8812 29.5%, 0.9005 31.8%, 0.9167 34.1%, 0.9302 36.4%, 0.9416 38.6%, 0.9511 40.9%, 0.9590 43.2%, 0.9657 45.5%, 0.9713 47.7%, 0.9760 50.0%, 0.9799 52.3%, 0.9831 54.5%, 0.9859 56.8%, 0.9882 59.1%, 0.9901 61.4%, 0.9917 63.6%, 0.9931 65.9%, 0.9942 68.2%, 0.9951 70.5%, 0.9959 72.7%, 0.9966 75.0%, 0.9971 77.3%, 0.9976 79.5%, 0.9980 81.8%, 0.9983 84.1%, 0.9986 86.4%, 0.9988 88.6%, 0.9990 90.9%, 0.9992 93.2%, 0.9993 95.5%, 0.9994 97.7%, 0.9995 100.0%);

  display: flex;
  align-items: center;
  font-family: Geist, ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
}

/* ---- left rail ---- */
.tabswitch__rail {
  display: flex;
  flex-direction: column;
  width: var(--ts-rail-w);
  flex: none;
  position: relative;
  z-index: 1;
}

.tabswitch__item {
  position: relative;
  padding: var(--ts-pad);
  border-radius: var(--ts-radius) 0 0 var(--ts-radius);
  background: transparent;
  cursor: pointer;
  text-align: left;
  border: 0;
  font: inherit;
  color: inherit;
  transition: background-color var(--ts-bg-dur) var(--ts-bg-ease);
}

.tabswitch__item.is-active {
  background: var(--ts-active-bg);
}

.tabswitch__title {
  margin: 0;
  font-size: 26px;
  line-height: 32.5px;
  font-weight: 600;
  color: var(--ts-title);
}

/* The 0fr -> 1fr grid row is what gives an auto-height animation with
   no JS measurement, and it is what the reference's height curve is
   actually doing. */
.tabswitch__reveal {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--ts-expand-dur) var(--ts-expand-ease);
}

.tabswitch__item.is-active .tabswitch__reveal {
  grid-template-rows: 1fr;
}

.tabswitch__reveal > div {
  overflow: hidden;
  min-height: 0;
}

.tabswitch__desc {
  margin: var(--ts-gap) 0 0;
  font-size: 14px;
  line-height: 21px;
  color: var(--ts-body);
}

/* ---- the notch: two concave corners that weld the active pill to the
   panel, so the two shapes read as one. Reference draws these as a pair
   of 20x20 inline SVGs; a radial-gradient corner is the same picture
   with no markup. ---- */
.tabswitch__item::before,
.tabswitch__item::after {
  content: "";
  position: absolute;
  right: 0;
  width: var(--ts-notch);
  height: var(--ts-notch);
  background: var(--ts-active-bg);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--ts-bg-dur) var(--ts-bg-ease);
}

.tabswitch__item::before {
  bottom: 100%;
  -webkit-mask: radial-gradient(circle at 0 0, transparent var(--ts-notch), #000 calc(var(--ts-notch) + 0.5px));
  mask: radial-gradient(circle at 0 0, transparent var(--ts-notch), #000 calc(var(--ts-notch) + 0.5px));
}

.tabswitch__item::after {
  top: 100%;
  -webkit-mask: radial-gradient(circle at 0 100%, transparent var(--ts-notch), #000 calc(var(--ts-notch) + 0.5px));
  mask: radial-gradient(circle at 0 100%, transparent var(--ts-notch), #000 calc(var(--ts-notch) + 0.5px));
}

.tabswitch__item.is-active::before,
.tabswitch__item.is-active::after {
  opacity: 1;
}

/* ---- right panel ---- */
.tabswitch__panel {
  flex: 1;
  min-width: 0;
  background: var(--ts-active-bg);
  border-radius: var(--ts-radius);
  padding: var(--ts-panel-pad);
}

.tabswitch__stack {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 10;
  border-radius: calc(var(--ts-radius) - 2px);
  overflow: hidden;
}

.tabswitch__shot {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity var(--ts-shot-fade) linear;
}

.tabswitch__shot.is-active { opacity: 1; }

@media (max-width: 820px) {
  .tabswitch { flex-direction: column; }
  .tabswitch__rail { width: 100%; }
  .tabswitch__item { border-radius: var(--ts-radius); }
  .tabswitch__item::before, .tabswitch__item::after { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .tabswitch * { transition-duration: 1ms !important; }
}
