/* spring */
.spring-slide {
  animation: spring-slide var(--p-spring-spring-duration, 1203ms) var(--p-spring-spring, linear(0, 0.038, 0.13, 0.257, 0.405, 0.559, 0.708, 0.844, 0.961, 1.055, 1.125, 1.173, 1.199, 1.207, 1.2, 1.18, 1.154, 1.123, 1.092, 1.061, 1.033, 1.008, 0.989, 0.974, 0.964, 0.959, 0.957, 0.959, 0.962, 0.968, 0.974, 0.981, 0.987, 0.993, 0.998, 1.002, 1.005, 1.007, 1.008, 1.009, 1.009, 1.008, 1.007, 1.005, 1.004, 1.003, 1.001, 1, 1, 0.999, 0.999, 0.998, 0.998, 0.998, 0.998, 0.999, 0.999, 0.999, 0.999, 1, 1)) both;
}

.spring-pop {
  animation: spring-pop var(--p-spring-spring-duration, 1203ms) var(--p-spring-spring, linear(0, 0.038, 0.13, 0.257, 0.405, 0.559, 0.708, 0.844, 0.961, 1.055, 1.125, 1.173, 1.199, 1.207, 1.2, 1.18, 1.154, 1.123, 1.092, 1.061, 1.033, 1.008, 0.989, 0.974, 0.964, 0.959, 0.957, 0.959, 0.962, 0.968, 0.974, 0.981, 0.987, 0.993, 0.998, 1.002, 1.005, 1.007, 1.008, 1.009, 1.009, 1.008, 1.007, 1.005, 1.004, 1.003, 1.001, 1, 1, 0.999, 0.999, 0.998, 0.998, 0.998, 0.998, 0.999, 0.999, 0.999, 0.999, 1, 1)) 120ms both;
}

@keyframes spring-slide {
  from { transform: translateX(-90px); }
}

@keyframes spring-pop {
  from { transform: scale(0.3); }
}

@media (prefers-reduced-motion: reduce) {
  .spring-slide,
  .spring-pop { animation: none; }
}

/* clip-reveal */
.clip-wipe {
  animation: clip-wipe var(--p-clip-reveal-duration, 900ms) var(--p-clip-reveal-easing, cubic-bezier(0.65, 0, 0.35, 1)) both;
}

.clip-circle {
  animation: clip-circle var(--p-clip-reveal-duration, 900ms) var(--p-clip-reveal-easing, cubic-bezier(0.65, 0, 0.35, 1)) var(--p-clip-reveal-delay, 250ms) both;
}

@keyframes clip-wipe {
  from { clip-path: inset(0 100% 0 0); }
  to { clip-path: inset(0 0 0 0); }
}

@keyframes clip-circle {
  from { clip-path: circle(0% at 50% 50%); }
  to { clip-path: circle(75% at 50% 50%); }
}

@media (prefers-reduced-motion: reduce) {
  .clip-wipe,
  .clip-circle { animation: none; }
}

/* word-reveal */
.word-reveal .word {
  display: inline-block;
  overflow: hidden;
  /* 받침이나 descender가 잘리지 않게 아래쪽 여유를 줌 */
  padding-bottom: 0.1em;
  margin-bottom: -0.1em;
  vertical-align: top;
}

.word-reveal .word > span {
  display: inline-block;
  animation: word-up var(--p-word-reveal-duration, 700ms) var(--p-word-reveal-easing, cubic-bezier(0.2, 0.7, 0.2, 1)) both;
  animation-delay: calc(var(--i, 0) * var(--p-word-reveal-stagger, 70ms));
}

@keyframes word-up {
  from { transform: translateY(110%); }
}

@keyframes word-fade {
  from { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .word-reveal .word > span { animation-name: word-fade; }
}

/* flip-3d */
/* 카드 */
.flip-card {
  width: 120px;
  height: 84px;
  perspective: 600px;
}

.flip-card-inner {
  position: relative;
  height: 100%;
  transform-style: preserve-3d;
  transition: transform var(--p-flip-3d-duration, 600ms) var(--p-flip-3d-easing, cubic-bezier(0.2, 0.7, 0.2, 1));
}

.flip-card:hover .flip-card-inner,
.flip-card:focus-visible .flip-card-inner { transform: rotateY(180deg); }

.flip-card-front,
.flip-card-back {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  border-radius: 12px;
  font-weight: 700;
  backface-visibility: hidden;
}

.flip-card-front { background: #fff; border: 1px solid #e3e5ea; }
.flip-card-back { background: #1f2937; color: #fff; transform: rotateY(180deg); }

/* 플립 시계 숫자판 */
.flap {
  position: relative;
  width: 56px;
  height: 72px;
  color: #fff;
  font: 700 44px/72px system-ui, sans-serif;
  text-align: center;
  perspective: 300px;
}

.flap > span {
  position: absolute;
  left: 0;
  right: 0;
  height: 50%;
  overflow: hidden;
  background: #1f2937;
  backface-visibility: hidden;
}

.flap-top,
.flap-leaf-top {
  top: 0;
  border-radius: 8px 8px 0 0;
  transform-origin: 50% 100%;
}

/* line-height를 0으로 두면 글자의 아래쪽 절반만 보임 */
.flap-bottom,
.flap-leaf-bottom {
  bottom: 0;
  line-height: 0;
  border-radius: 0 0 8px 8px;
  transform-origin: 50% 0;
}

.flap-leaf-top,
.flap-leaf-bottom { z-index: 1; }
.flap-leaf-bottom { transform: rotateX(90deg); }

.flap.is-flipping .flap-leaf-top {
  animation: flap-top var(--p-flip-3d-flap-duration, 260ms) ease-in forwards;
}

.flap.is-flipping .flap-leaf-bottom {
  animation: flap-bottom var(--p-flip-3d-flap-duration, 260ms) ease-out var(--p-flip-3d-flap-duration, 260ms) forwards;
}

@keyframes flap-top {
  to { transform: rotateX(-90deg); }
}

@keyframes flap-bottom {
  from { transform: rotateX(90deg); }
  to { transform: rotateX(0deg); }
}

@media (prefers-reduced-motion: reduce) {
  .flip-card-inner { transition: none; }
  /* animationend가 발생해야 숫자가 확정되므로 none 대신 아주 짧게 줄임 */
  .flap.is-flipping .flap-leaf-top,
  .flap.is-flipping .flap-leaf-bottom {
    animation-duration: 1ms;
    animation-delay: 0s;
  }
}

/* hover-patterns */
/* 밑줄 슬라이드 */
.hover-underline {
  position: relative;
  font-weight: 600;
  text-decoration: none;
}

.hover-underline::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  height: 2px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform var(--p-hover-patterns-duration, 300ms) var(--p-hover-patterns-easing, cubic-bezier(0.2, 0.7, 0.2, 1));
}

.hover-underline:hover::after,
.hover-underline:focus-visible::after {
  transform: scaleX(1);
  transform-origin: left;
}

/* 이미지 확대 */
.hover-zoom {
  overflow: hidden;
  border-radius: 10px;
}

.hover-zoom > * { transition: transform var(--p-hover-patterns-duration, 300ms) var(--p-hover-patterns-easing, cubic-bezier(0.2, 0.7, 0.2, 1)); }
.hover-zoom:hover > * { transform: scale(var(--p-hover-patterns-zoom, 1.08)); }

/* 화살표 이동 */
.hover-arrow .arrow {
  display: inline-block;
  transition: transform var(--p-hover-patterns-duration, 300ms) var(--p-hover-patterns-easing, cubic-bezier(0.2, 0.7, 0.2, 1));
}

.hover-arrow:hover .arrow,
.hover-arrow:focus-visible .arrow { transform: translateX(var(--p-hover-patterns-shift, 4px)); }

@media (prefers-reduced-motion: reduce) {
  .hover-underline::after,
  .hover-zoom > *,
  .hover-arrow .arrow { transition: none; }
}

/* pointer-tilt */
/* 위치는 기울지 않는 이 틀에서 잼 */
.tilt { perspective: 600px; }

.tilt-card {
  --x: 0.5;
  --y: 0.5;
  position: relative;
  box-sizing: border-box;
  width: min(220px, 100%);
  padding: 20px;
  border-radius: 16px;
  background: #1f2329;
  color: #fff;
  transform:
    rotateX(calc((0.5 - var(--y)) * var(--p-pointer-tilt-tilt, 10deg) * 2))
    rotateY(calc((var(--x) - 0.5) * var(--p-pointer-tilt-tilt, 10deg) * 2));
  transition: transform var(--p-pointer-tilt-return, 500ms) cubic-bezier(0.2, 0.7, 0.2, 1);
}

.tilt:hover .tilt-card { transition-duration: 100ms; }

.tilt-card strong { font-size: 16px; }
.tilt-card p { margin: 4px 0 0; color: #c4c9d2; }

/* 조명 */
.tilt-card::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(
    var(--p-pointer-tilt-glow, 180px) circle at calc(var(--x) * 100%) calc(var(--y) * 100%),
    rgb(255 255 255 / 0.18),
    transparent
  );
  opacity: 0;
  transition: opacity 300ms;
  pointer-events: none;
}

.tilt:hover .tilt-card::after { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .tilt-card { transform: none; }
}

/* flip-technique */
.flip-list {
  --flip-duration: var(--p-flip-technique-duration, 500ms);
  --flip-easing: var(--p-flip-technique-easing, cubic-bezier(0.2, 0.7, 0.2, 1));
}

@media (prefers-reduced-motion: reduce) {
  .flip-list { --flip-duration: 0ms; }
}

/* view-transitions */
.vt-list > li { view-transition-class: vt-tile; }

::view-transition-group(*.vt-tile) {
  animation-duration: var(--p-view-transitions-duration, 500ms);
  animation-timing-function: var(--p-view-transitions-easing, cubic-bezier(0.2, 0.7, 0.2, 1));
}

@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*.vt-tile) { animation-duration: 0s; }
}

/* horizontal-scroll */
.h-scroll-sticky { overflow-x: auto; }

.h-scroll-track {
  display: flex;
  gap: 12px;
  width: max-content;
  margin: 0;
  padding: 16px;
  list-style: none;
}

.h-scroll-track > li {
  display: grid;
  place-items: end start;
  width: 150px;
  height: 110px;
  padding: 12px;
  box-sizing: border-box;
  border-radius: 12px;
  background: #1f2937;
  color: #fff;
  font-weight: 700;
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .h-scroll {
      /* 컨테이너가 없으면 cqh·cqw는 화면 크기를 기준으로 계산됨 */
      height: var(--p-horizontal-scroll-length, 300cqh);
      view-timeline-name: --h-scroll;
    }

    .h-scroll-sticky {
      position: sticky;
      top: 0;
      display: flex;
      align-items: center;
      height: 100cqh;
      overflow: hidden;
    }

    .h-scroll-track {
      animation: h-scroll linear both;
      animation-timeline: --h-scroll;
      animation-range: contain 0% contain 100%;
    }
  }
}

@keyframes h-scroll {
  to { transform: translateX(calc(-100% + 100cqw)); }
}

/* motion-path */
.path-area {
  position: relative;
  width: 220px;
  height: 120px;
}

.path-traveler {
  position: absolute;
  top: 0;
  left: 0;
  offset-path: path("M 10 100 C 60 0, 150 0, 200 70");
  offset-rotate: 0deg;
  offset-distance: 100%;
  animation: follow-path var(--p-motion-path-duration, 1200ms) var(--p-motion-path-easing, cubic-bezier(0.65, 0, 0.35, 1)) both;
}

/* 진행 방향을 따라 회전 */
.path-traveler.is-rotating {
  offset-rotate: auto;
  animation-delay: var(--p-motion-path-delay, 180ms);
}

@keyframes follow-path {
  from { offset-distance: 0%; }
}

@media (prefers-reduced-motion: reduce) {
  .path-traveler { animation: none; }
}

/* shape-morph */
.morph-toggle {
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  border: 0;
  border-radius: 50%;
  background: #1f2937;
  cursor: pointer;
}

.morph-icon {
  width: 20px;
  height: 22px;
  background: #fff;
  /* shape()를 모르는 브라우저용: 모양만 바뀌고 애니메이션은 없음 */
  clip-path: polygon(0% 0%, 100% 50%, 0% 100%);
  transition: clip-path var(--p-shape-morph-duration, 320ms) var(--p-shape-morph-easing, cubic-bezier(0.65, 0, 0.35, 1));
}

.morph-toggle[aria-pressed="true"] .morph-icon {
  clip-path: polygon(0% 0%, 35% 0%, 35% 100%, 65% 100%, 65% 0%, 100% 0%, 100% 100%, 0% 100%);
}

@supports (clip-path: shape(from 0% 0%, line to 100% 100%)) {
  /* 두 모양 모두 [시작, 선 3개, 닫기] × 2 구조라서 서로 보간됨 */
  .morph-icon {
    clip-path: shape(
      from 0% 0%, line to 50% 25%, line to 50% 75%, line to 0% 100%, close,
      move to 50% 25%, line to 100% 50%, line to 100% 50%, line to 50% 75%, close
    );
  }

  .morph-toggle[aria-pressed="true"] .morph-icon {
    clip-path: shape(
      from 0% 0%, line to 35% 0%, line to 35% 100%, line to 0% 100%, close,
      move to 65% 0%, line to 100% 0%, line to 100% 100%, line to 65% 100%, close
    );
  }

  .morph-blob {
    width: 96px;
    height: 96px;
    background: linear-gradient(135deg, #2f4bd8, #22c1c3);
    clip-path: shape(
      from 50% 0%, curve to 100% 50% with 90% 5%, curve to 50% 100% with 95% 95%,
      curve to 0% 50% with 5% 95%, curve to 50% 0% with 10% 5%, close
    );
    animation: blob-morph var(--p-shape-morph-blob-duration, 4s) ease-in-out infinite alternate;
  }

  @keyframes blob-morph {
    to {
      clip-path: shape(
        from 60% 8%, curve to 92% 60% with 100% 0%, curve to 40% 92% with 100% 100%,
        curve to 8% 40% with 0% 100%, curve to 60% 8% with 0% 0%, close
      );
    }
  }
}

@media (prefers-reduced-motion: reduce) {
  .morph-icon { transition: none; }
  .morph-blob { animation: none; }
}

/* odometer */
.odometer {
  display: inline-flex;
  font: 700 32px/1.2 system-ui, sans-serif;
  font-variant-numeric: tabular-nums;
}

.odo-digit {
  height: 1.2em;
  overflow: hidden;
}

/* 0~9를 세로로 쌓은 띠를 --d 칸만큼 위로 올림 */
.odo-digit::before {
  content: "0\A 1\A 2\A 3\A 4\A 5\A 6\A 7\A 8\A 9";
  display: block;
  white-space: pre;
  transform: translateY(calc(var(--d, 0) * -1.2em));
  transition: transform var(--p-odometer-duration, 900ms) var(--p-odometer-easing, cubic-bezier(0.2, 0.7, 0.2, 1));
  transition-delay: calc(var(--i, 0) * var(--p-odometer-digit-delay, 60ms));
}

@media (prefers-reduced-motion: reduce) {
  .odo-digit::before { transition: none; }
}

/* typewriter */
.typewriter {
  display: inline-block;
  width: calc(var(--chars) * 1ch);
  overflow: hidden;
  white-space: nowrap;
  border-right: 0.12em solid currentColor;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  animation:
    typing calc(var(--chars) * var(--p-typewriter-char-time, 90ms)) steps(var(--chars)) both,
    caret var(--p-typewriter-caret-time, 800ms) step-end infinite;
}

@keyframes typing {
  from { width: 0; }
}

@keyframes caret {
  50% { border-color: transparent; }
}

@media (prefers-reduced-motion: reduce) {
  .typewriter { animation: none; }
}

/* snap-carousel */
.snap-carousel {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  /* 첫 항목과 마지막 항목도 가운데에 올 수 있게 양쪽 여백을 줌 */
  padding-inline: calc(50% - 60px);
}

.snap-carousel > li {
  flex: none;
  width: 120px;
  scroll-snap-align: center;
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .snap-carousel > li {
      animation: snap-focus linear both;
      animation-timeline: view(inline);
    }
  }
}

@keyframes snap-focus {
  0%, 100% {
    opacity: var(--p-snap-carousel-min-opacity, 0.45);
    transform: scale(var(--p-snap-carousel-min-scale, 0.78));
  }
  50% {
    opacity: 1;
    transform: none;
  }
}

/* aurora */
.aurora {
  position: relative;
  isolation: isolate;
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  overflow: hidden;
  border-radius: 12px;
  background: #0f172a;
}

.aurora-blob {
  position: absolute;
  z-index: -1;
  width: 60%;
  aspect-ratio: 1;
  border-radius: 50%;
  filter: blur(var(--p-aurora-blur, 32px));
  opacity: 0.8;
  animation: aurora-drift var(--p-aurora-duration, 6s) ease-in-out infinite alternate;
}

.aurora-blob:nth-child(1) { top: -10%; left: -10%; background: #2f4bd8; }
.aurora-blob:nth-child(2) { top: 10%; right: -15%; background: #db2777; animation-delay: calc(var(--p-aurora-duration, 6s) * -0.3); }
.aurora-blob:nth-child(3) { bottom: -25%; left: 20%; background: #22c1c3; animation-delay: calc(var(--p-aurora-duration, 6s) * -0.6); }

.aurora-text {
  margin: 0;
  color: #fff;
  font-size: 22px;
  font-weight: 800;
}

@keyframes aurora-drift {
  to { transform: translate(var(--x), var(--y)) scale(1.15); }
}

@media (prefers-reduced-motion: reduce) {
  .aurora-blob { animation: none; }
}

/* fade-up */
.fade-up {
  animation: fade-up var(--p-fade-up-duration, 600ms) var(--p-fade-up-easing, cubic-bezier(0.2, 0.7, 0.2, 1)) both;
}

@keyframes fade-up {
  from {
    opacity: 0;
    transform: translateY(var(--p-fade-up-distance, 16px));
  }
}

@keyframes fade-up-reduced {
  from { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .fade-up { animation-name: fade-up-reduced; }
}

/* stagger */
.stagger > li {
  animation: stagger-in var(--p-stagger-duration, 480ms) var(--p-stagger-easing, cubic-bezier(0.2, 0.7, 0.2, 1)) both;
  animation-delay: calc(var(--i, 0) * var(--p-stagger-stagger, 80ms));
}

/* 순번을 CSS가 직접 셈 (sibling-index()는 1부터 시작) */
@supports (animation-delay: calc(sibling-index() * 1ms)) {
  .stagger > li { animation-delay: calc((sibling-index() - 1) * var(--p-stagger-stagger, 80ms)); }
}

@keyframes stagger-in {
  from {
    opacity: 0;
    transform: translateY(var(--p-stagger-distance, 12px));
  }
}

@media (prefers-reduced-motion: reduce) {
  .stagger > li { animation: none; }
}

/* scroll-reveal */
@supports (animation-timeline: view()) {
  .reveal {
    animation: reveal var(--p-scroll-reveal-easing, ease-out) both;
    animation-timeline: view();
    /* 화면에 들어오기 시작할 때부터 요소가 화면을 지정한 비율만큼 지나갈 때까지 재생 */
    animation-range: entry 0% cover var(--p-scroll-reveal-range-end, 40%);
  }
}

@keyframes reveal {
  from {
    opacity: 0;
    transform: translateY(var(--p-scroll-reveal-distance, 80px)) scale(var(--p-scroll-reveal-scale, 0.8));
  }
}

@media (prefers-reduced-motion: reduce) {
  .reveal { animation: none; }
}

/* button-press */
.lift-btn {
  padding: 10px 18px;
  border: 0;
  border-radius: 10px;
  background: #1f2937;
  color: #fff;
  font: 600 14px/1 system-ui, sans-serif;
  cursor: pointer;
  box-shadow: 0 1px 2px rgb(0 0 0 / 0.2);
  transition: transform var(--p-button-press-duration, 160ms) ease, box-shadow var(--p-button-press-duration, 160ms) ease;
}

@media (hover: hover) {
  .lift-btn:hover {
    transform: translateY(var(--p-button-press-lift, -2px));
    box-shadow: 0 8px 18px rgb(0 0 0 / 0.18);
  }
}

.lift-btn:active {
  transform: translateY(0) scale(var(--p-button-press-press-scale, 0.97));
  transition-duration: 60ms;
}

.lift-btn:focus-visible {
  outline: 2px solid #2f4bd8;
  outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {
  .lift-btn { transition: none; }
}

/* toggle-switch */
.switch {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font: 500 14px system-ui, sans-serif;
  cursor: pointer;
}

.switch input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.switch-track {
  position: relative;
  width: 44px;
  height: 26px;
  border-radius: 999px;
  background: #c5c9d2;
  transition: background-color var(--p-toggle-switch-duration, 200ms) ease;
}

.switch-track::before {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgb(0 0 0 / 0.25);
  transition: transform var(--p-toggle-switch-duration, 200ms) var(--p-toggle-switch-easing, cubic-bezier(0.3, 0.7, 0.4, 1.4));
}

.switch input:checked + .switch-track { background: #16a34a; }
.switch input:checked + .switch-track::before { transform: translateX(18px); }

.switch input:focus-visible + .switch-track {
  outline: 2px solid #2f4bd8;
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .switch-track,
  .switch-track::before { transition: none; }
}

/* check-draw */
.check-circle,
.check-mark {
  stroke: #16a34a;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: var(--len);
}

.check-circle {
  stroke-width: 3;
  /* 12시 방향에서 그리기 시작 */
  transform: rotate(-90deg);
  transform-origin: center;
  transform-box: fill-box;
  animation: check-draw var(--p-check-draw-circle-duration, 600ms) var(--p-check-draw-easing, cubic-bezier(0.65, 0, 0.45, 1)) both;
}

.check-mark {
  stroke-width: 4;
  animation: check-draw var(--p-check-draw-mark-duration, 360ms) var(--p-check-draw-mark-delay, 480ms) var(--p-check-draw-easing, cubic-bezier(0.65, 0, 0.45, 1)) both;
}

@keyframes check-draw {
  from { stroke-dashoffset: var(--len); }
}

@media (prefers-reduced-motion: reduce) {
  .check-circle,
  .check-mark { animation: none; }
}

/* skeleton */
.skeleton-card {
  display: flex;
  gap: 12px;
  width: min(240px, 100%);
  padding: 14px;
  border-radius: 12px;
  background: #fff;
}

.skeleton-lines {
  display: grid;
  flex: 1;
  gap: 8px;
  align-content: center;
}

.skeleton {
  position: relative;
  overflow: hidden;
  border-radius: 6px;
  background: #e4e7ec;
}

.skeleton::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, rgb(255 255 255 / 0.7), transparent);
  transform: translateX(-100%);
  animation: shimmer var(--p-skeleton-duration, 1400ms) var(--p-skeleton-easing, ease-in-out) infinite;
}

.skeleton-avatar { flex: none; width: 40px; height: 40px; border-radius: 50%; }
.skeleton-line { height: 10px; }
.skeleton-line.is-short { width: 60%; }

@keyframes shimmer {
  to { transform: translateX(100%); }
}

@media (prefers-reduced-motion: reduce) {
  .skeleton::after { animation: none; }
}

/* spinner */
.spinner {
  display: inline-block;
  width: 32px;
  height: 32px;
  border: 3px solid #d5d9e0;
  border-top-color: #2f4bd8;
  border-radius: 50%;
  animation: spinner-rotate var(--p-spinner-duration, 800ms) linear infinite;
}

@keyframes spinner-rotate {
  to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
  .spinner { animation-duration: calc(var(--p-spinner-duration, 800ms) * 3); }
}

/* modal */
.modal {
  width: min(320px, calc(100% - 32px));
  padding: 20px;
  border: 0;
  border-radius: 14px;
  box-shadow: 0 20px 50px rgb(0 0 0 / 0.25);
  opacity: 0;
  scale: var(--p-modal-start-scale, 0.96);
  transition:
    opacity var(--p-modal-duration, 200ms) var(--p-modal-easing, ease-out),
    scale var(--p-modal-duration, 200ms) var(--p-modal-easing, ease-out),
    overlay var(--p-modal-duration, 200ms) allow-discrete,
    display var(--p-modal-duration, 200ms) allow-discrete;
}

.modal[open] {
  opacity: 1;
  scale: 1;
}

@starting-style {
  .modal[open] {
    opacity: 0;
    scale: var(--p-modal-start-scale, 0.96);
  }
}

.modal::backdrop {
  background: rgb(15 17 20 / 0);
  transition:
    background-color var(--p-modal-duration, 200ms),
    overlay var(--p-modal-duration, 200ms) allow-discrete,
    display var(--p-modal-duration, 200ms) allow-discrete;
}

.modal[open]::backdrop { background: rgb(15 17 20 / 0.45); }

@starting-style {
  .modal[open]::backdrop { background: rgb(15 17 20 / 0); }
}

.modal p { margin: 0 0 8px; }

@media (prefers-reduced-motion: reduce) {
  .modal,
  .modal::backdrop { transition: none; }
}

/* bottom-sheet */
.sheet {
  width: min(480px, 100%);
  max-width: 100%;
  margin: auto auto 0;
  padding: 0;
  border: 0;
  border-radius: 16px 16px 0 0;
  box-shadow: 0 -8px 32px rgb(0 0 0 / 0.16);
  translate: 0 100%;
  transition:
    translate var(--p-bottom-sheet-duration, 320ms) var(--p-bottom-sheet-easing, cubic-bezier(0.32, 0.72, 0, 1)),
    overlay var(--p-bottom-sheet-duration, 320ms) allow-discrete,
    display var(--p-bottom-sheet-duration, 320ms) allow-discrete;
}

.sheet[open] { translate: 0 var(--drag, 0px); }

@starting-style {
  .sheet[open] { translate: 0 100%; }
}

/* 끄는 동안에는 손가락을 바로 따라오게 함 */
.sheet.is-dragging { transition: none; }

.sheet::backdrop {
  background: rgb(15 17 20 / 0);
  transition:
    background-color var(--p-bottom-sheet-duration, 320ms),
    overlay var(--p-bottom-sheet-duration, 320ms) allow-discrete,
    display var(--p-bottom-sheet-duration, 320ms) allow-discrete;
}

.sheet[open]::backdrop { background: rgb(15 17 20 / 0.45); }

@starting-style {
  .sheet[open]::backdrop { background: rgb(15 17 20 / 0); }
}

/* 바깥 클릭을 dialog 자체에 대한 클릭으로 구분하기 위해 안쪽 여백은 여기에 둠 */
.sheet-body { padding: 8px 20px 24px; }

.sheet-body h3 { margin: 0 0 4px; font-size: 16px; }
.sheet-body p { margin: 0 0 16px; color: #5b6270; }

.sheet-handle {
  width: 40px;
  height: 5px;
  margin: 0 auto 12px;
  /* 손가락으로 잡기 쉽게 보이는 막대보다 넓게 잡히게 함 */
  border: solid transparent;
  border-width: 10px 30px;
  border-radius: 999px;
  background: #d1d5db padding-box;
  cursor: grab;
  touch-action: none;
}

.sheet.is-dragging .sheet-handle { cursor: grabbing; }

@media (prefers-reduced-motion: reduce) {
  .sheet,
  .sheet::backdrop { transition: none; }
}

/* accordion */
.accordion {
  width: min(260px, 100%);
  border: 1px solid #e3e5ea;
  border-radius: 12px;
  background: #fff;
}

.accordion-item + .accordion-item { border-top: 1px solid #e3e5ea; }

.accordion-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  padding: 12px 14px;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  font-weight: 600;
  text-align: left;
  cursor: pointer;
}

.accordion-trigger::after {
  content: "";
  flex: none;
  width: 7px;
  height: 7px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
  transition: transform var(--p-accordion-duration, 300ms) var(--p-accordion-easing, cubic-bezier(0.2, 0.7, 0.2, 1));
}

.accordion-trigger[aria-expanded="true"]::after { transform: rotate(-135deg); }

.accordion-panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--p-accordion-duration, 300ms) var(--p-accordion-easing, cubic-bezier(0.2, 0.7, 0.2, 1));
}

.accordion-trigger[aria-expanded="true"] + .accordion-panel { grid-template-rows: 1fr; }

.accordion-inner {
  overflow: hidden;
  visibility: hidden;
  transition: visibility var(--p-accordion-duration, 300ms);
}

.accordion-trigger[aria-expanded="true"] + .accordion-panel .accordion-inner { visibility: visible; }

.accordion-inner p {
  margin: 0;
  padding: 0 14px 12px;
  color: #4b5563;
}

@media (prefers-reduced-motion: reduce) {
  .accordion-panel,
  .accordion-inner,
  .accordion-trigger::after { transition: none; }
}

/* toast */
.toast {
  position: fixed;
  left: 50%;
  bottom: 20px;
  padding: 10px 16px;
  border-radius: 10px;
  background: #15171b;
  color: #fff;
  font-size: 13px;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transform: translate(-50%, var(--p-toast-distance, 12px));
  transition:
    opacity var(--p-toast-duration, 240ms) var(--p-toast-easing, cubic-bezier(0.2, 0.7, 0.2, 1)),
    transform var(--p-toast-duration, 240ms) var(--p-toast-easing, cubic-bezier(0.2, 0.7, 0.2, 1));
}

.toast.is-visible {
  opacity: 1;
  transform: translate(-50%, 0);
}

@media (prefers-reduced-motion: reduce) {
  .toast { transform: translate(-50%, 0); }
}

/* read-progress */
.read-progress {
  position: sticky;
  top: 0;
  z-index: 1;
  height: 4px;
  background: #2f4bd8;
  transform: scaleX(0);
  transform-origin: 0 50%;
}

@supports (animation-timeline: scroll()) {
  .read-progress {
    animation: read-progress linear both;
    animation-timeline: scroll();
  }
}

@keyframes read-progress {
  to { transform: scaleX(1); }
}

/* 스크롤과 1:1로 움직여서 동작 줄이기 대상에서 제외함 */

/* marquee */
.marquee {
  width: 100%;
  overflow: hidden;
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}

.marquee-track {
  display: flex;
  width: max-content;
  animation: marquee var(--p-marquee-duration, 12s) linear infinite;
}

/* gap 대신 margin을 써야 -50% 지점이 정확히 맞음 */
.marquee-track > span {
  margin-right: 10px;
  padding: 6px 14px;
  border: 1px solid #e3e5ea;
  border-radius: 999px;
  background: #fff;
  font-weight: 600;
}

@keyframes marquee {
  to { transform: translateX(-50%); }
}

@media (prefers-reduced-motion: reduce) {
  .marquee { overflow-x: auto; }
  .marquee-track { animation: none; }
}

/* count-up */
@property --num {
  syntax: "<integer>";
  initial-value: 0;
  inherits: false;
}

.count-up {
  counter-reset: num var(--num);
  font-variant-numeric: tabular-nums;
  animation: count-up var(--p-count-up-duration, 1600ms) var(--p-count-up-easing, cubic-bezier(0.2, 0.7, 0.2, 1)) both;
}

.count-up::after { content: counter(num); }

@keyframes count-up {
  from { --num: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .count-up { animation: none; }
}

/* gradient-border */
@property --glow-angle {
  syntax: "<angle>";
  initial-value: 0deg;
  inherits: false;
}

.glow-border {
  padding: 16px 20px;
  border: var(--p-gradient-border-border, 2px) solid transparent;
  border-radius: 16px;
  background:
    linear-gradient(#fff, #fff) padding-box,
    conic-gradient(from var(--glow-angle), #2f4bd8, #22c1c3, #f5a400, #2f4bd8) border-box;
  animation: glow-rotate var(--p-gradient-border-duration, 4s) linear infinite;
}

.glow-border p { margin: 2px 0 0; color: #5b6270; }

@keyframes glow-rotate {
  to { --glow-angle: 360deg; }
}

@media (prefers-reduced-motion: reduce) {
  .glow-border { animation: none; }
}

/* shake */
.shake-form {
  display: flex;
  align-items: flex-end;
  gap: 8px;
}

.shake-form label {
  display: grid;
  gap: 4px;
  font-size: 12px;
  color: #4b5563;
}

.shake-form input {
  width: 150px;
  padding: 8px 10px;
  border: 1px solid #cfd4dc;
  border-radius: 8px;
  font: inherit;
}

.shake-form input[aria-invalid="true"] { border-color: #dc2626; }

.shake-form.is-shaking {
  animation: shake-x var(--p-shake-duration, 400ms) var(--p-shake-easing, cubic-bezier(0.36, 0.07, 0.19, 0.97));
}

@keyframes shake-x {
  20%, 60% { transform: translateX(calc(var(--p-shake-distance, 6px) * -1)); }
  40%, 80% { transform: translateX(var(--p-shake-distance, 6px)); }
}

@media (prefers-reduced-motion: reduce) {
  .shake-form.is-shaking { animation: none; }
}

/* popover-menu */
.dropdown {
  display: grid;
  /* Safari 26.3에서 popover 높이가 화면 높이만큼 늘어나 항목이 나눠 갖는 문제를 막음 */
  align-content: start;
  min-width: 140px;
  padding: 6px;
  border: 1px solid #e3e5ea;
  border-radius: 12px;
  box-shadow: 0 12px 32px rgb(0 0 0 / 0.16);
  opacity: 0;
  transform: translateY(var(--p-popover-menu-offset, -6px));
  transition:
    opacity var(--p-popover-menu-duration, 180ms) var(--p-popover-menu-easing, cubic-bezier(0.2, 0.7, 0.2, 1)),
    transform var(--p-popover-menu-duration, 180ms) var(--p-popover-menu-easing, cubic-bezier(0.2, 0.7, 0.2, 1)),
    overlay var(--p-popover-menu-duration, 180ms) allow-discrete,
    display var(--p-popover-menu-duration, 180ms) allow-discrete;
}

/* 닫혀 있을 때는 display: none을 유지해야 함 */
.dropdown:not(:popover-open) { display: none; }

.dropdown:popover-open {
  opacity: 1;
  transform: none;
}

@starting-style {
  .dropdown:popover-open {
    opacity: 0;
    transform: translateY(var(--p-popover-menu-offset, -6px));
  }
}

.dropdown button {
  padding: 8px 10px;
  border: 0;
  border-radius: 8px;
  background: none;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.dropdown button:hover,
.dropdown button:focus-visible { background: #f2f3f6; }

/* 버튼 바로 아래에 붙임 (지원하지 않으면 화면 가운데에 열림) */
@supports (position-area: bottom) {
  .dropdown {
    inset: auto;
    margin: 6px 0 0;
    position-area: bottom span-right;
  }
}

@media (prefers-reduced-motion: reduce) {
  .dropdown { transition: none; }
}

/* tooltip */
.tip {
  position: relative;
  display: inline-block;
}

.tooltip {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  width: max-content;
  max-width: 220px;
  padding: 6px 10px;
  border-radius: 8px;
  background: #1f2329;
  color: #fff;
  font: 13px/1.4 system-ui, sans-serif;
  opacity: 0;
  visibility: hidden;
  transform: translate(-50%, var(--p-tooltip-offset, 4px));
  /* 사라질 때: 100ms 기다렸다가 흐려지고, 다 흐려진 뒤에 visibility를 끔 */
  transition:
    opacity var(--p-tooltip-duration, 150ms) ease-out 100ms,
    transform var(--p-tooltip-duration, 150ms) ease-out 100ms,
    visibility 0s calc(100ms + var(--p-tooltip-duration, 150ms));
}

/* 버튼과 툴팁 사이의 틈을 덮어서, 마우스가 툴팁으로 넘어가는 동안 hover가 끊기지 않게 함 */
.tooltip::after {
  content: "";
  position: absolute;
  inset: 100% 0 -8px;
}

.tip:not(.is-dismissed):hover .tooltip,
.tip:not(.is-dismissed) :focus-visible + .tooltip {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0);
  transition-delay: var(--p-tooltip-delay, 400ms);
}

@media (prefers-reduced-motion: reduce) {
  .tooltip { transform: translate(-50%, 0); }
}

/* tab-indicator */
.tab-list {
  position: relative;
  display: grid;
  grid-template-columns: repeat(var(--count), 1fr);
  width: min(260px, 100%);
  padding: 4px;
  border-radius: 12px;
  background: #e9ebf0;
}

.tab-list [role="tab"] {
  position: relative;
  z-index: 1;
  padding: 8px 0;
  border: 0;
  background: none;
  color: #5b6270;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  transition: color var(--p-tab-indicator-duration, 280ms);
}

.tab-list [aria-selected="true"] { color: #15171b; }

.tab-indicator {
  position: absolute;
  top: 4px;
  bottom: 4px;
  left: 4px;
  width: calc((100% - 8px) / var(--count));
  border-radius: 8px;
  background: #fff;
  box-shadow: 0 1px 3px rgb(0 0 0 / 0.12);
  /* 자기 너비의 --index배만큼 이동 */
  transform: translateX(calc(var(--index) * 100%));
  transition: transform var(--p-tab-indicator-duration, 280ms) var(--p-tab-indicator-easing, cubic-bezier(0.3, 0.7, 0.4, 1.2));
}

@media (prefers-reduced-motion: reduce) {
  .tab-indicator,
  .tab-list [role="tab"] { transition: none; }
}

/* like-burst */
.like-btn {
  position: relative;
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  border: 0;
  border-radius: 50%;
  background: none;
  cursor: pointer;
}

.like-heart {
  width: 32px;
  height: 32px;
  fill: transparent;
  stroke: #9ca3af;
  stroke-width: 2;
  transition: fill 150ms, stroke 150ms;
}

.like-btn[aria-pressed="true"] .like-heart {
  fill: #ef4444;
  stroke: #ef4444;
  animation: like-pop var(--p-like-burst-duration, 600ms) cubic-bezier(0.3, 0.7, 0.4, 1.5);
}

/* 링 */
.like-btn::before {
  content: "";
  position: absolute;
  inset: 4px;
  border: 2px solid #ef4444;
  border-radius: 50%;
  opacity: 0;
}

/* 퍼지는 점 여섯 개 */
.like-btn::after {
  content: "";
  position: absolute;
  inset: -8px;
  background:
    radial-gradient(circle, #ef4444 45%, transparent 50%) 50% 0% / 7px 7px no-repeat,
    radial-gradient(circle, #f59e0b 45%, transparent 50%) 93% 25% / 7px 7px no-repeat,
    radial-gradient(circle, #ef4444 45%, transparent 50%) 93% 75% / 7px 7px no-repeat,
    radial-gradient(circle, #f59e0b 45%, transparent 50%) 50% 100% / 7px 7px no-repeat,
    radial-gradient(circle, #ef4444 45%, transparent 50%) 7% 75% / 7px 7px no-repeat,
    radial-gradient(circle, #f59e0b 45%, transparent 50%) 7% 25% / 7px 7px no-repeat;
  opacity: 0;
}

.like-btn[aria-pressed="true"]::before { animation: like-ring var(--p-like-burst-duration, 600ms) ease-out; }
.like-btn[aria-pressed="true"]::after { animation: like-dots var(--p-like-burst-duration, 600ms) ease-out; }

@keyframes like-pop {
  30% { transform: scale(0.7); }
  60% { transform: scale(var(--p-like-burst-pop-scale, 1.25)); }
}

@keyframes like-ring {
  from { opacity: 1; transform: scale(0.3); }
  to { opacity: 0; transform: scale(1.3); }
}

@keyframes like-dots {
  from { opacity: 1; transform: scale(0.5); }
  to { opacity: 0; transform: scale(1.25); }
}

@media (prefers-reduced-motion: reduce) {
  .like-btn[aria-pressed="true"] .like-heart,
  .like-btn[aria-pressed="true"]::before,
  .like-btn[aria-pressed="true"]::after { animation: none; }
}

/* progress-ring */
.progress-ring {
  width: 88px;
  height: 88px;
  fill: none;
  stroke-width: var(--p-progress-ring-stroke, 3);
}

.ring-track { stroke: #e4e7ec; }

.ring-value {
  stroke: #16a34a;
  stroke-linecap: round;
  stroke-dasharray: 100;
  stroke-dashoffset: calc(100 - var(--value));
  /* 12시 방향에서 시작 */
  transform: rotate(-90deg);
  transform-origin: center;
  transform-box: fill-box;
  animation: ring-fill var(--p-progress-ring-duration, 1200ms) var(--p-progress-ring-easing, cubic-bezier(0.2, 0.7, 0.2, 1)) both;
}

.progress-ring.is-warning .ring-value { stroke: #f59e0b; }

@keyframes ring-fill {
  from { stroke-dashoffset: 100; }
}

@media (prefers-reduced-motion: reduce) {
  .ring-value { animation: none; }
}

/* typing-indicator */
.typing {
  display: inline-flex;
  gap: 5px;
  padding: 12px 16px;
  border-radius: 18px 18px 18px 4px;
  background: #e9ebf0;
}

.typing span {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #6b7280;
  animation: typing-bounce var(--p-typing-indicator-duration, 1200ms) ease-in-out infinite;
}

.typing span:nth-child(2) { animation-delay: calc(var(--p-typing-indicator-duration, 1200ms) * 0.15); }
.typing span:nth-child(3) { animation-delay: calc(var(--p-typing-indicator-duration, 1200ms) * 0.3); }

@keyframes typing-bounce {
  0%, 60%, 100% { opacity: 0.4; transform: none; }
  30% { opacity: 1; transform: translateY(calc(var(--p-typing-indicator-height, 5px) * -1)); }
}

@media (prefers-reduced-motion: reduce) {
  .typing span { animation: none; }
}

/* ripple */
.ripple-btn {
  position: relative;
  overflow: hidden;
  padding: 14px 24px;
  border: 0;
  border-radius: 10px;
  background: #2f4bd8;
  color: #fff;
  font: 600 14px system-ui, sans-serif;
  cursor: pointer;
}

.ripple {
  position: absolute;
  border-radius: 50%;
  background: rgb(255 255 255 / 0.45);
  pointer-events: none;
  transform: scale(0);
  animation: ripple var(--p-ripple-duration, 600ms) var(--p-ripple-easing, ease-out) forwards;
}

@keyframes ripple {
  to {
    opacity: 0;
    transform: scale(1);
  }
}