/* ═══════════════════════════════════════════════════════════════════════════
 * Kallisto Design System v4 — Transitions Lab
 * 25 reusable animation keyframes + tlab card components
 * ═══════════════════════════════════════════════════════════════════════════ */

    :root {
      /* Emil Kowalski / animations.dev easing curves
         These are stronger than the built-in CSS easings — the built-in
         curves lack the punch that makes UI motion feel intentional. */
      --ease-out:    cubic-bezier(0.23, 1, 0.32, 1);          /* entrance, hover — starts fast, feels responsive */
      --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);         /* on-screen movement / morphing */
      --ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);          /* iOS-like drawers */
      --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);       /* playful overshoot — keep subtle */
      --ease-smooth: var(--ease-out);                          /* alias — default for cards */

      /* Durations follow Emil's table */
      --d-press: 120ms;     /* button feedback */
      --d-tip:   160ms;     /* tooltips / small popovers */
      --d-drop:  200ms;     /* dropdowns / selects */
      --d-modal: 320ms;     /* modals / drawers */

      --t-card:  280ms var(--ease-out);
      --t-quick: 160ms var(--ease-out);
    }

    /* ── Universal hover-lift (desktop) + tap-press (mobile) ─────── */
    .kal-tile, .kal-card, .kal-kpi, .kal-statcard, .kal-liquid,
    .kal-nowplay, .kal-live, .kal-map, .kal-hero-card,
    .ds-demo-card, .ds-swatch {
      transition:
        transform var(--t-card),
        box-shadow var(--t-card),
        border-color var(--t-quick),
        background var(--t-quick);
      will-change: transform;
    }
    @media (hover: hover) {
      .kal-tile:hover, .kal-card:hover, .kal-kpi:hover,
      .kal-statcard:hover, .kal-liquid:hover,
      .kal-nowplay:hover, .kal-live:hover, .kal-map:hover {
        transform: translateY(-4px);
        box-shadow:
          0 1px 2px rgba(0,0,0,0.04),
          0 12px 32px rgba(0,0,0,0.10),
          0 30px 60px -20px rgba(0,0,0,0.12);
      }
      .ds-swatch:hover { transform: translateY(-2px) scale(1.02); }
      .kal-hero-card:hover { transform: translateY(-3px) scale(1.005); }
    }
    /* Touch devices get a brief press-down on tap */
    .kal-tile:active, .kal-card:active, .kal-kpi:active,
    .kal-statcard:active, .kal-liquid:active,
    .kal-nowplay:active, .kal-live:active, .kal-map:active,
    .kal-hero-card:active {
      transform: scale(0.985);
      transition-duration: 120ms;
    }

    /* Inner detail micro-motion */
    .kal-tile__icon,
    .kal-tile__corner,
    .kal-tile__power {
      transition: transform var(--t-quick), background var(--t-quick),
                  color var(--t-quick), border-color var(--t-quick);
    }
    .kal-tile:hover .kal-tile__icon { transform: scale(1.06) rotate(-2deg); }
    .kal-tile:hover .kal-tile__corner { transform: rotate(45deg) scale(1.05); }
    .kal-tile:active .kal-tile__icon { transform: scale(0.92); transition-duration: 100ms; }

    /* ── Button + chip presses ────────────────────────────────────── */
    .kal-btn, .kal-tag, .ds-themechip,
    .kal-toolbar__btn, .kal-roompill__item, .kal-applauncher__app,
    .kal-live__ctrl, .kal-nowplay__ctrl, .kal-fab,
    .kal-avstack__item, .kal-avstack__add {
      transition: transform var(--t-quick), background var(--t-quick),
                  color var(--t-quick), box-shadow var(--t-quick),
                  border-color var(--t-quick);
    }
    /* Buttons — must feel responsive. scale(0.97) on press for instant feedback. */
    .kal-btn, .kal-btn--primary, .kal-btn--dark, .kal-btn--ghost, .kal-btn--danger {
      transition:
        transform var(--d-press) var(--ease-out),
        background var(--d-tip) var(--ease-out),
        color var(--d-tip) var(--ease-out),
        border-color var(--d-tip) var(--ease-out),
        box-shadow var(--d-tip) var(--ease-out);
    }
    @media (hover: hover) and (pointer: fine) {
      .kal-btn:hover { transform: translateY(-1px); }
    }
    /* Asymmetric press/release: scale-down is snappy (release also snappy). */
    .kal-btn:active { transform: scale(0.97); transition-duration: 80ms; }
    .kal-tag:hover { transform: translateY(-1px); }
    .ds-themechip:hover { transform: translateY(-1px); }
    .ds-themechip:active { transform: translateY(0) scale(0.97); }
    .kal-avstack__item { transition: transform var(--t-card); }
    .kal-avstack:hover .kal-avstack__item { transform: translateX(-4px); }
    .kal-avstack__item:hover { transform: translateY(-3px) scale(1.08); z-index: 10; }
    .kal-applauncher__app:hover { transform: translateY(-2px) rotate(-3deg); }
    .kal-roompill__item:hover { transform: translateY(-1px); }
    .kal-live__ctrl:hover, .kal-nowplay__ctrl:hover { transform: scale(1.12); }

    /* ── Forecast day cells ───────────────────────────────────────── */
    .kal-forecast__day {
      transition: transform var(--t-card), background var(--t-quick),
                  box-shadow var(--t-card);
    }
    .kal-forecast__day:hover { transform: translateY(-3px); }
    .kal-forecast__day:hover .kal-forecast__icon {
      animation: kal-sway 1.2s var(--ease-smooth) infinite;
    }

    /* ── Progress bars: fill grows smoothly ───────────────────────── */
    .kal-bar__fill { transition: width 1.4s var(--ease-smooth); }

    /* ── Scroll-in entrance: each card fades up as it enters view ── */
    [data-rise] {
      opacity: 0;
      transform: translateY(18px);
      transition: opacity 600ms var(--ease-smooth),
                  transform 600ms var(--ease-smooth);
      transition-delay: calc(var(--rise-i, 0) * 55ms);
    }
    [data-rise].is-in { opacity: 1; transform: translateY(0); }

    /* ── Section headers slide in ─────────────────────────────────── */
    .ds-section { transition: opacity 500ms var(--ease-smooth); }
    .ds-section h2 {
      transition: transform 500ms var(--ease-smooth);
    }

    /* ── Theme switcher: smoother cross-fade on all themed surfaces  */
    body, .ds-page, .kal-tile, .kal-card, .kal-kpi, .kal-btn,
    .kal-nowplay, .kal-live, .kal-map, .kal-hero-card,
    .kal-toolbar, .kal-roompill, .kal-statcard, .kal-liquid {
      transition-property: background-color, color, border-color,
                           box-shadow, transform;
      transition-duration: 420ms;
      transition-timing-function: var(--ease-smooth);
    }

    /* ── Mobile tuning: shorter distances, no fancy shadow lift ───── */
    @media (max-width: 720px) {
      :root { --t-card: 320ms var(--ease-smooth); }
      [data-rise] { transform: translateY(12px); }
      [data-rise] { transition-delay: calc(var(--rise-i, 0) * 40ms); }
      /* Mobile shadow lift is lighter to avoid jank */
      .kal-tile:active, .kal-card:active, .kal-kpi:active,
      .kal-statcard:active, .kal-liquid:active {
        transform: scale(0.98);
      }
    }

    /* ===========================================================
     * DARK-THEME TEXT + BUTTON LEGIBILITY FIXES
     * Some btn variants were authored for light surfaces and look
     * washed out on dark themes. Tighten contrast across the board.
     * =========================================================== */
    [data-theme="dark-glass"] .kal-btn,
    [data-theme="dark-yellow"] .kal-btn,
    [data-theme="midnight"] .kal-btn,
    [data-theme="obsidian"] .kal-btn,
    [data-theme="neumorph"] .kal-btn {
      background: rgba(255,255,255,0.06);
      color: #fff;
      border-color: rgba(255,255,255,0.14);
    }
    /* Primary keeps its gradient on dark themes */
    [data-theme="dark-glass"] .kal-btn--primary,
    [data-theme="dark-yellow"] .kal-btn--primary,
    [data-theme="midnight"] .kal-btn--primary,
    [data-theme="obsidian"] .kal-btn--primary,
    [data-theme="neumorph"] .kal-btn--primary {
      background: linear-gradient(135deg, var(--violet), var(--sky));
      color: oklch(1 0 0);
      border-color: transparent;
      text-shadow: 0 1px 2px oklch(0 0 0 / 0.2);
    }
    [data-theme="dark-glass"] .kal-btn--primary:hover,
    [data-theme="dark-yellow"] .kal-btn--primary:hover,
    [data-theme="midnight"] .kal-btn--primary:hover,
    [data-theme="obsidian"] .kal-btn--primary:hover,
    [data-theme="neumorph"] .kal-btn--primary:hover {
      background: linear-gradient(135deg, var(--violet), var(--sky));
      color: oklch(1 0 0);
      filter: brightness(1.18);
      box-shadow: 0 6px 24px oklch(from var(--violet) l c h / 0.35), inset 0 1px 0 rgba(255,255,255,0.4);
    }
    [data-theme="dark-glass"] .kal-btn:hover,
    [data-theme="midnight"] .kal-btn:hover,
    [data-theme="obsidian"] .kal-btn:hover,
    [data-theme="neumorph"] .kal-btn:hover {
      background: rgba(255,255,255,0.12);
      border-color: rgba(255,255,255,0.22);
    }
    /* Ghost button needs visible color on dark */
    [data-theme="dark-glass"] .kal-btn--ghost,
    [data-theme="dark-yellow"] .kal-btn--ghost,
    [data-theme="midnight"] .kal-btn--ghost,
    [data-theme="obsidian"] .kal-btn--ghost,
    [data-theme="neumorph"] .kal-btn--ghost {
      background: transparent;
      border-color: rgba(255,255,255,0.10);
      color: rgba(255,255,255,0.82);
    }
    [data-theme="dark-glass"] .kal-btn--ghost:hover,
    [data-theme="midnight"] .kal-btn--ghost:hover,
    [data-theme="obsidian"] .kal-btn--ghost:hover,
    [data-theme="neumorph"] .kal-btn--ghost:hover {
      background: rgba(255,255,255,0.06); color: #fff;
    }
    /* Danger button — white pill on dark = jarring. Re-skin to a
       red-tinted outlined pill that lives in the dark surface. */
    [data-theme="dark-glass"] .kal-btn--danger,
    [data-theme="dark-yellow"] .kal-btn--danger,
    [data-theme="midnight"] .kal-btn--danger,
    [data-theme="obsidian"] .kal-btn--danger,
    [data-theme="neumorph"] .kal-btn--danger {
      background: color-mix(in oklch, var(--bad) 14%, transparent);
      color: color-mix(in oklch, var(--bad) 60%, #fff);
      border-color: color-mix(in oklch, var(--bad) 45%, transparent);
    }
    [data-theme="dark-glass"] .kal-btn--danger:hover,
    [data-theme="midnight"] .kal-btn--danger:hover,
    [data-theme="obsidian"] .kal-btn--danger:hover,
    [data-theme="neumorph"] .kal-btn--danger:hover {
      background: color-mix(in oklch, var(--bad) 28%, transparent);
      color: #fff;
    }
    /* Dark button — was a near-black pill on a near-black background.
       Make it stand out with a lighter chrome on dark themes. */
    [data-theme="dark-glass"] .kal-btn--dark,
    [data-theme="dark-yellow"] .kal-btn--dark,
    [data-theme="midnight"] .kal-btn--dark,
    [data-theme="obsidian"] .kal-btn--dark {
      background: rgba(255,255,255,0.92);
      color: #0c0c10;
      border-color: rgba(255,255,255,0.92);
    }
    [data-theme="dark-glass"] .kal-btn--dark:hover,
    [data-theme="midnight"] .kal-btn--dark:hover,
    [data-theme="obsidian"] .kal-btn--dark:hover { background: #fff; }

    /* Chat suggestion chips — more visible on dark themes */
    [data-theme="dark-glass"] .odin-suggest .chip,
    [data-theme="dark-yellow"] .odin-suggest .chip,
    [data-theme="midnight"] .odin-suggest .chip,
    [data-theme="obsidian"] .odin-suggest .chip,
    [data-theme="neumorph"] .odin-suggest .chip,
    [data-theme="dark-glass"] .c-chat-suggest .chip,
    [data-theme="dark-yellow"] .c-chat-suggest .chip,
    [data-theme="midnight"] .c-chat-suggest .chip,
    [data-theme="obsidian"] .c-chat-suggest .chip,
    [data-theme="neumorph"] .c-chat-suggest .chip {
      background: rgba(255,255,255,0.08);
      border-color: rgba(255,255,255,0.14);
      color: rgba(255,255,255,0.70);
    }
    [data-theme="dark-glass"] .odin-suggest .chip:hover,
    [data-theme="dark-yellow"] .odin-suggest .chip:hover,
    [data-theme="midnight"] .odin-suggest .chip:hover,
    [data-theme="obsidian"] .odin-suggest .chip:hover,
    [data-theme="neumorph"] .odin-suggest .chip:hover,
    [data-theme="dark-glass"] .c-chat-suggest .chip:hover,
    [data-theme="dark-yellow"] .c-chat-suggest .chip:hover,
    [data-theme="midnight"] .c-chat-suggest .chip:hover,
    [data-theme="obsidian"] .c-chat-suggest .chip:hover,
    [data-theme="neumorph"] .c-chat-suggest .chip:hover {
      background: oklch(from var(--violet) l c h / 0.18);
      border-color: oklch(from var(--violet) l c h / 0.40);
      color: rgba(255,255,255,0.95);
      box-shadow: 0 4px 20px oklch(from var(--violet) l c h / 0.20),
                  0 0 0 1px oklch(from var(--violet) l c h / 0.12);
    }

    /* Eyebrow labels ("COMPONENTS", "PILL (ROUNDED)" …) lose contrast on
       dark themes — the warm gold tint is OK on dark-glass but too low
       on midnight/obsidian. Bump ink-3 a touch only where needed. */
    [data-theme="midnight"]  .ds-label,
    [data-theme="obsidian"]  .ds-label,
    [data-theme="neumorph"]  .ds-label {
      color: rgba(255,255,255,0.72);
    }
    [data-theme="midnight"]  .ds-section-title,
    [data-theme="obsidian"]  .ds-section-title,
    [data-theme="neumorph"]  .ds-section-title {
      color: rgba(255,255,255,0.78);
    }

    /* ===========================================================
     * EXTRA MOTION — more places now animate smoothly
     * =========================================================== */

    /* Inputs, textareas, selects */
    .kal-input, .kal-select, .kal-input--textarea {
      transition:
        border-color var(--t-quick),
        box-shadow var(--t-card),
        background var(--t-quick),
        transform var(--t-quick);
    }
    .kal-input:focus, .kal-select:focus, .kal-input--textarea:focus {
      transform: translateY(-1px);
    }

    /* Segmented control — thumb glides between options */
    .kal-seg__item {
      transition: color var(--t-quick), background var(--t-card),
                  transform var(--t-quick), box-shadow var(--t-card) !important;
    }
    .kal-seg__item:hover { transform: translateY(-1px); }

    /* Radio + checkbox — spring-pop on select */
    .kal-radio__dot, .kal-check__box {
      transition: background var(--t-quick), border-color var(--t-quick),
                  transform 220ms var(--ease-spring), box-shadow var(--t-quick) !important;
    }
    .kal-radio:hover .kal-radio__dot,
    .kal-check:hover .kal-check__box { transform: scale(1.08); }
    .kal-radio--on .kal-radio__dot { animation: kal-pop 280ms var(--ease-spring); }
    .kal-check--on .kal-check__box { animation: kal-pop 280ms var(--ease-spring); }
    @keyframes kal-pop {
      0% { transform: scale(0.6); }
      55% { transform: scale(1.18); }
      100% { transform: scale(1); }
    }

    /* Toggle thumb */
    .kal-toggle::after { transition: transform 280ms var(--ease-spring), background var(--t-quick) !important; }
    .kal-toggle:hover::after { box-shadow: 0 2px 8px rgba(0,0,0,.22); }

    /* Range slider thumb pulse on hover */
    .kal-range::-webkit-slider-thumb { transition: transform 200ms var(--ease-spring), box-shadow var(--t-quick); }

    /* Tags / chips */
    .kal-tag { transition: transform var(--t-quick), background var(--t-quick), color var(--t-quick), box-shadow var(--t-quick); }
    .kal-tag:hover { transform: translateY(-1px) scale(1.04); box-shadow: 0 4px 12px rgba(0,0,0,.08); }

    /* Avatars (single, non-stack) */
    .kal-avatar { transition: transform var(--t-card) var(--ease-spring), box-shadow var(--t-card); }
    .kal-avatar:hover { transform: scale(1.08); box-shadow: 0 6px 18px rgba(0,0,0,.18); }

    /* Theme swatches in the picker grid */
    .ds-section button[onclick], .ds-section button { transition: transform var(--t-card), box-shadow var(--t-card); }

    /* Tables: row hover */
    .kal-table tbody tr {
      transition: background var(--t-quick), transform var(--t-quick);
    }
    .kal-table tbody tr:hover {
      background: color-mix(in oklch, var(--violet) 5%, transparent);
      transform: translateX(2px);
    }

    /* Liquid fill height eases when the value changes */
    .kal-liquid__body { transition: --fill 1s var(--ease-smooth); }

    /* Dial fill already animates — add gentle scale on hover */
    .kal-dial { transition: transform var(--t-card) var(--ease-spring); }
    .kal-tile:hover .kal-dial { transform: scale(1.03); }

    /* Toolbar buttons pop on tap/hover */
    .kal-toolbar__btn:hover { transform: translateY(-1px) scale(1.06); }
    .kal-toolbar__btn:active { transform: scale(0.92); }

    /* Eyebrow + section title shimmer in */
    .ds-section-title { transition: color var(--t-quick), opacity var(--t-card), transform var(--t-card); }

    /* Icon library cells — hover lift */
    [data-rise].kal-card, .ds-section > div[style*="grid"] > div { transition: transform var(--t-card), background var(--t-quick), color var(--t-quick), border-color var(--t-quick); }

    /* Spectrum slider thumb */
    .kal-spectrum__thumb { transition: left 260ms var(--ease-smooth), transform var(--t-quick); }
    .kal-spectrum:hover .kal-spectrum__thumb { transform: translate(-50%, -50%) scale(1.15); }

    /* Smooth links + footnote text */
    a, code { transition: color var(--t-quick), background var(--t-quick); }

    /* Respect reduced-motion across all of the above */
    @media (prefers-reduced-motion: reduce) {
      *, *::before, *::after {
        transition-duration: 1ms !important;
        animation-duration: 1ms !important;
        animation-iteration-count: 1 !important;
      }
      [data-rise] { opacity: 1; transform: none; }
    }
  /* ── Transitions Lab — showcase animations (tlab-*) ──────────────── */
    /* =========================================================
     * TRANSITIONS LAB — self-contained looping showcases
     * Each card runs its animation forever so devs can spot &
     * pick the named transition for their own work.
     * ========================================================= */
    .tlab-grid {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
      gap: 0;
      border: 1px solid var(--glass-stroke-2);
      border-radius: var(--r-xl);
      overflow: hidden;
      box-shadow: var(--shadow-md);
    }
    .tlab {
      position: relative;
      padding: 36px 28px 28px;
      background: var(--glass-bg-strong);
      backdrop-filter: blur(20px);
      -webkit-backdrop-filter: blur(20px);
      border-right: 1px solid var(--glass-stroke-2);
      border-bottom: 1px solid var(--glass-stroke-2);
      min-height: 240px;
      display: flex; flex-direction: column; align-items: center;
      text-align: center;
      overflow: hidden;
      gap: 18px;
      transition: background var(--t-quick);
    }
    .tlab:hover {
      background: color-mix(in oklch, var(--violet) 4%, var(--glass-bg-strong));
    }
    /* Remove trailing borders so outer container border shows cleanly */
    .tlab:nth-child(4n)   { border-right: none; }
    .tlab:last-child      { border-right: none; }
    @media (max-width: 1100px) { .tlab:nth-child(3n) { border-right: none; } }
    @media (max-width: 800px)  { .tlab:nth-child(2n) { border-right: none; } }
    @media (max-width: 560px)  { .tlab { border-right: none; } }
    @media (max-width: 720px)  { .tlab--wide { grid-column: span 1 !important; } }
    .tlab__stage {
      flex: 1;
      width: 100%;
      display: flex; align-items: center; justify-content: center;
      min-height: 110px;
      padding: 8px;
      position: relative;
    }
    .tlab__foot {
      width: 100%;
      display: flex; flex-direction: column; align-items: center;
      gap: 4px;
    }
    .tlab__name {
      font-size: 14px;
      font-family: var(--font-sans);
      letter-spacing: -0.005em;
      color: var(--ink);
      font-weight: 600;
    }
    .tlab__desc {
      font-size: 11.5px;
      font-family: var(--font-mono);
      letter-spacing: 0.04em;
      color: var(--ink-3);
    }
    .tlab__chip {
      position: absolute; top: 10px; right: 10px;
      padding: 3px 8px;
      font-size: 9px;
      font-family: var(--font-mono);
      letter-spacing: 0.06em;
      text-transform: uppercase;
      color: var(--ink-3);
      background: var(--glass-bg);
      border: 1px solid var(--glass-stroke-2);
      border-radius: var(--r-full);
    }

    /* Generic demo shapes */
    .tlab-chip {
      width: 52px; height: 52px; border-radius: 14px;
      background: linear-gradient(135deg, var(--violet), var(--sky));
      display: flex; align-items: center; justify-content: center;
      color: #fff;
      box-shadow: 0 8px 24px color-mix(in oklch, var(--violet) 30%, transparent);
    }
    .tlab-pill {
      padding: 8px 16px; border-radius: var(--r-full);
      background: var(--ink); color: var(--bg-1);
      font-size: 12px; font-weight: 500;
      display: inline-flex; align-items: center; gap: 6px;
    }
    .tlab-card {
      width: 84px; height: 60px; border-radius: 12px;
      background: var(--bg-1);
      border: 1px solid var(--glass-stroke-2);
      box-shadow: var(--shadow-sm);
    }

    /* ── LOOPS ── */
    @keyframes tlab-fadeUp {
      0%, 15%   { opacity: 0; transform: translateY(18px); }
      35%, 75%  { opacity: 1; transform: translateY(0); }
      100%      { opacity: 0; transform: translateY(-18px); }
    }
    .tlab-anim-fadeUp { animation: tlab-fadeUp 3.2s var(--ease-smooth) infinite; }

    @keyframes tlab-lift {
      0%, 100% { transform: translateY(0); box-shadow: 0 4px 12px rgba(0,0,0,0.06); }
      50%      { transform: translateY(-10px); box-shadow: 0 18px 38px rgba(0,0,0,0.18); }
    }
    .tlab-anim-lift { animation: tlab-lift 2.4s var(--ease-smooth) infinite; }

    @keyframes tlab-pressSpring {
      0%, 100% { transform: scale(1); }
      30%      { transform: scale(0.92); }
      55%      { transform: scale(1.06); }
      75%      { transform: scale(0.98); }
    }
    .tlab-anim-pressSpring { animation: tlab-pressSpring 2.2s var(--ease-spring) infinite; }

    @keyframes tlab-rotate45 {
      0%, 30%, 100% { transform: rotate(0); }
      50%, 75%      { transform: rotate(45deg) scale(1.05); }
    }
    .tlab-anim-rotate45 { animation: tlab-rotate45 2.6s var(--ease-smooth) infinite; }

    @keyframes tlab-slideX {
      0%, 100% { transform: translateX(-22px); opacity: 0.4; }
      50%      { transform: translateX(22px); opacity: 1; }
    }
    .tlab-anim-slideX { animation: tlab-slideX 2.4s var(--ease-smooth) infinite; }

    @keyframes tlab-scaleIn {
      0%, 15%  { transform: scale(0.4); opacity: 0; }
      35%, 75% { transform: scale(1); opacity: 1; }
      100%     { transform: scale(1.4); opacity: 0; }
    }
    .tlab-anim-scaleIn { animation: tlab-scaleIn 2.6s var(--ease-spring) infinite; }

    @keyframes tlab-tilt {
      0%, 100% { transform: rotate(-3deg); }
      50%      { transform: rotate(3deg); }
    }
    .tlab-anim-tilt { animation: tlab-tilt 1.8s var(--ease-smooth) infinite; }

    @keyframes tlab-pulse {
      0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 color-mix(in oklch, var(--violet) 50%, transparent); }
      50%      { transform: scale(1.04); box-shadow: 0 0 0 16px transparent; }
    }
    .tlab-anim-pulse { animation: tlab-pulse 1.8s var(--ease-smooth) infinite; }

    @keyframes tlab-float {
      0%, 100% { transform: translateY(0); }
      50%      { transform: translateY(-12px); }
    }
    .tlab-anim-float { animation: tlab-float 2.6s ease-in-out infinite; }

    @keyframes tlab-shimmer {
      0%   { background-position: -200% 0; }
      100% { background-position: 200% 0; }
    }
    .tlab-anim-shimmer {
      width: 120px; height: 28px; border-radius: 8px;
      background: linear-gradient(110deg,
        var(--lavender) 8%,
        color-mix(in oklch, var(--violet) 18%, var(--bg-1)) 18%,
        var(--lavender) 33%);
      background-size: 220% 100%;
      animation: tlab-shimmer 1.6s linear infinite;
    }

    @keyframes tlab-typewriter {
      0%, 5%   { width: 0; }
      45%, 55% { width: 100%; }
      95%, 100%{ width: 0; }
    }
    .tlab-anim-typewriter {
      overflow: hidden; white-space: nowrap;
      border-right: 2px solid var(--violet);
      font-family: var(--font-mono); font-size: 12px; color: var(--ink);
      animation: tlab-typewriter 3.6s steps(28) infinite, tlab-blink 0.8s steps(1) infinite;
    }
    @keyframes tlab-blink { 50% { border-color: transparent; } }

    @keyframes tlab-stagger {
      0%, 100% { transform: translateY(0); opacity: 0.4; }
      50%      { transform: translateY(-10px); opacity: 1; }
    }
    .tlab-stagger-row { display: flex; gap: 6px; }
    .tlab-stagger-row > span {
      width: 12px; height: 28px; border-radius: 4px;
      background: var(--violet);
      animation: tlab-stagger 1.4s ease-in-out infinite;
    }
    .tlab-stagger-row > span:nth-child(2) { animation-delay: 0.12s; background: color-mix(in oklch, var(--violet) 80%, var(--sky)); }
    .tlab-stagger-row > span:nth-child(3) { animation-delay: 0.24s; background: var(--sky); }
    .tlab-stagger-row > span:nth-child(4) { animation-delay: 0.36s; background: color-mix(in oklch, var(--sky) 60%, var(--mint)); }
    .tlab-stagger-row > span:nth-child(5) { animation-delay: 0.48s; background: var(--mint); }

    @keyframes tlab-progress {
      0%   { width: 0%; }
      80%  { width: 100%; }
      100% { width: 100%; opacity: 0; }
    }
    .tlab-bar-track {
      width: 80%; height: 8px; border-radius: 999px;
      background: var(--lavender);
      overflow: hidden;
    }
    .tlab-bar-fill {
      height: 100%;
      background: linear-gradient(90deg, var(--violet), var(--sky));
      animation: tlab-progress 2.6s var(--ease-smooth) infinite;
    }

    @keyframes tlab-spin { to { transform: rotate(360deg); } }
    .tlab-anim-spin {
      width: 40px; height: 40px; border-radius: 50%;
      border: 3px solid var(--lavender);
      border-top-color: var(--violet);
      animation: tlab-spin 0.9s linear infinite;
    }

    @keyframes tlab-counterTick {
      0%, 100% { transform: translateY(0); }
      45%, 55% { transform: translateY(-26px); }
    }
    .tlab-counter {
      height: 26px; overflow: hidden;
      font-family: var(--font-mono); font-size: 22px;
      font-weight: 600; color: var(--ink);
      line-height: 26px;
    }
    .tlab-counter > div { animation: tlab-counterTick 2.2s var(--ease-smooth) infinite; }

    @keyframes tlab-blob {
      0%, 100% { border-radius: 60% 40% 50% 50% / 40% 60% 40% 60%; transform: rotate(0); }
      25%      { border-radius: 40% 60% 65% 35% / 55% 45% 55% 45%; }
      50%      { border-radius: 55% 45% 35% 65% / 60% 40% 60% 40%; transform: rotate(8deg); }
      75%      { border-radius: 45% 55% 50% 50% / 35% 65% 35% 65%; }
    }
    .tlab-anim-blob {
      width: 64px; height: 64px;
      background: linear-gradient(135deg, var(--violet), var(--sky));
      animation: tlab-blob 5s ease-in-out infinite;
      box-shadow: 0 10px 30px color-mix(in oklch, var(--violet) 30%, transparent);
    }

    @keyframes tlab-ripple {
      0%   { transform: scale(0.4); opacity: 0.6; }
      100% { transform: scale(2.6); opacity: 0; }
    }
    .tlab-ripple-wrap { position: relative; width: 52px; height: 52px; display: flex; align-items: center; justify-content: center; }
    .tlab-ripple-wrap .tlab-ripple-core { width: 18px; height: 18px; border-radius: 50%; background: var(--violet); z-index: 2; }
    .tlab-ripple-wrap::before, .tlab-ripple-wrap::after {
      content: ""; position: absolute; inset: 0; border-radius: 50%;
      background: color-mix(in oklch, var(--violet) 40%, transparent);
      animation: tlab-ripple 1.8s ease-out infinite;
    }
    .tlab-ripple-wrap::after { animation-delay: 0.9s; }

    @keyframes tlab-marquee {
      0%   { transform: translateX(0); }
      100% { transform: translateX(-50%); }
    }
    .tlab-marquee-track {
      display: inline-flex; gap: 14px; white-space: nowrap;
      animation: tlab-marquee 8s linear infinite;
      font-family: var(--font-mono); font-size: 11px; color: var(--ink-2);
    }
    .tlab-marquee-track span { padding: 4px 10px; border-radius: 999px; background: var(--lavender); }

    @keyframes tlab-flipY {
      0%, 40%, 100% { transform: rotateY(0); }
      60%, 90%      { transform: rotateY(180deg); }
    }
    .tlab-anim-flipY { animation: tlab-flipY 3s var(--ease-smooth) infinite; transform-style: preserve-3d; }

    @keyframes tlab-hover-fake {
      0%, 40%, 100% { transform: translateY(0); box-shadow: 0 1px 0 var(--glass-stroke-2), 0 8px 24px rgba(0,0,0,0.05); }
      50%, 80%      { transform: translateY(-4px); box-shadow: 0 1px 0 var(--glass-stroke-2), 0 16px 40px rgba(0,0,0,0.14); }
    }
    .tlab-anim-hover { animation: tlab-hover-fake 3s var(--ease-smooth) infinite; }
    /* =====================================================
     * EASING REFERENCE CARDS — flowchart + curve visualizer
     * From Emil Kowalski / animations.dev
     * ===================================================== */
    .tlab--wide {
      grid-column: span 2;
      min-height: auto;
      padding: 28px 28px 28px;
      align-items: stretch;
      text-align: left;
      gap: 18px;
    }
    .tlab--wide .tlab__legend { padding-bottom: 4px; }
    .tlab--wide .tlab__head {
      display: flex; flex-direction: column; gap: 4px;
      margin-bottom: 4px;
    }
    .tlab--wide .tlab__title {
      font-size: 15px; font-weight: 600; color: var(--ink);
      letter-spacing: -0.01em;
    }
    .tlab--wide .tlab__lede {
      font-size: 11.5px; color: var(--ink-3);
      font-family: var(--font-mono); letter-spacing: 0.02em;
    }
    .tlab--wide .tlab__legend {
      display: flex; justify-content: space-between; align-items: baseline;
      margin-top: 6px;
      padding-top: 12px;
      border-top: 1px solid var(--line);
      font-family: var(--font-mono); font-size: 10px;
      color: var(--ink-3); letter-spacing: 0.08em;
      text-transform: uppercase;
    }

    .tlab-flow {
      font-family: var(--font-mono);
      font-size: 11.5px;
      color: var(--ink);
      line-height: 1.7;
      white-space: pre;
      background: linear-gradient(180deg,
        color-mix(in oklch, var(--violet) 5%, transparent),
        color-mix(in oklch, var(--sky) 5%, transparent));
      padding: 16px 18px;
      border-radius: 10px;
      border: 1px solid var(--glass-stroke-2);
      overflow-x: auto;
    }
    .tlab-flow b { color: var(--violet); font-weight: 600; }

    /* Curve visualizer */
    .tlab-curves { display: grid; grid-template-columns: 1fr; gap: 12px; width: 100%; }
    .tlab-curve {
      display: grid; grid-template-columns: 92px 1fr 72px; align-items: center;
      gap: 14px;
      font-family: var(--font-mono); font-size: 10.5px; color: var(--ink-2);
    }
    .tlab-curve__name { color: var(--ink); font-weight: 500; }
    .tlab-curve__track {
      position: relative;
      height: 8px;
      border-radius: 999px;
      background: var(--lavender);
      overflow: hidden;
    }
    .tlab-curve__ball {
      position: absolute; top: 50%;
      width: 14px; height: 14px;
      border-radius: 50%;
      background: linear-gradient(135deg, var(--violet), var(--sky));
      box-shadow: 0 2px 6px color-mix(in oklch, var(--violet) 30%, transparent);
      transform: translate(-50%, -50%);
      animation: tlab-curve-run 2.4s infinite;
    }
    .tlab-curve__meta { color: var(--ink-3); font-size: 9.5px; text-align: right; }
    @keyframes tlab-curve-run {
      0%   { left: 0%; }
      50%  { left: 100%; }
      100% { left: 0%; }
    }
    .tlab-curve--linear  .tlab-curve__ball { animation-timing-function: linear; }
    .tlab-curve--ease    .tlab-curve__ball { animation-timing-function: ease; }
    .tlab-curve--out     .tlab-curve__ball { animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1); }
    .tlab-curve--inout   .tlab-curve__ball { animation-timing-function: cubic-bezier(0.77, 0, 0.175, 1); }
    .tlab-curve--spring  .tlab-curve__ball { animation-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1); }
    .tlab-curve--drawer  .tlab-curve__ball { animation-timing-function: cubic-bezier(0.32, 0.72, 0, 1); }

    /* Hold-to-delete pattern — asymmetric clip-path animation */
    @keyframes tlab-hold {
      0%   { clip-path: inset(0 100% 0 0); }
      80%  { clip-path: inset(0 0 0 0); }
      82%  { clip-path: inset(0 0 0 0); }
      100% { clip-path: inset(0 100% 0 0); }
    }
    .tlab-hold {
      position: relative;
      padding: 10px 18px; border-radius: var(--r-full);
      background: var(--bg-1); color: var(--ink);
      border: 1px solid var(--glass-stroke-2);
      font-size: 12px; font-weight: 500;
      overflow: hidden;
    }
    .tlab-hold__fill {
      position: absolute; inset: 0;
      background: color-mix(in oklch, var(--bad) 60%, transparent);
      animation: tlab-hold 3s linear infinite;
    }
    .tlab-hold__label { position: relative; z-index: 2; }

    /* Blur-mask crossfade — Emil's trick for smoother state swaps */
    @keyframes tlab-blurfade {
      0%, 45%   { filter: blur(0); opacity: 1; transform: scale(1); }
      50%, 55%  { filter: blur(4px); opacity: 0.6; transform: scale(0.95); }
      60%, 100% { filter: blur(0); opacity: 1; transform: scale(1); }
    }
    .tlab-blurfade {
      width: 80px; height: 60px; border-radius: 12px;
      background: linear-gradient(135deg, var(--violet), var(--sky));
      animation: tlab-blurfade 3s var(--ease-out) infinite;
      box-shadow: 0 10px 24px color-mix(in oklch, var(--violet) 30%, transparent);
    }

    /* Origin-aware popover scale — from corner, not center */
    @keyframes tlab-popfrom {
      0%, 20%  { transform: scale(0.95); opacity: 0; }
      35%, 75% { transform: scale(1); opacity: 1; }
      90%, 100%{ transform: scale(0.95); opacity: 0; }
    }
    .tlab-popfrom {
      width: 90px; height: 60px; border-radius: 10px;
      background: var(--bg-1);
      border: 1px solid var(--glass-stroke-2);
      box-shadow: var(--shadow-md);
      transform-origin: top left;
      animation: tlab-popfrom 3s var(--ease-out) infinite;
    }

    /* 3D coin flip (Perspective Design — depth via 3D) */
    .tlab-coin-wrap { perspective: 600px; }
    @keyframes tlab-coin {
      0%, 100% { transform: rotateY(0); }
      50%      { transform: rotateY(180deg); }
    }
    .tlab-coin {
      width: 56px; height: 56px; border-radius: 50%;
      background: linear-gradient(135deg, var(--violet), var(--sky));
      box-shadow:
        inset 0 -8px 16px rgba(0,0,0,0.18),
        0 12px 28px color-mix(in oklch, var(--violet) 30%, transparent);
      animation: tlab-coin 3s var(--ease-in-out) infinite;
      transform-style: preserve-3d;
    }

    /* Reveal-on-scroll via clip-path (image reveals) */
    @keyframes tlab-clipUp {
      0%, 15%   { clip-path: inset(0 0 100% 0); }
      40%, 75%  { clip-path: inset(0 0 0 0); }
      95%, 100% { clip-path: inset(100% 0 0 0); }
    }
    .tlab-clipUp {
      width: 110px; height: 70px; border-radius: 10px;
      background:
        radial-gradient(120% 100% at 20% 0%, color-mix(in oklch, var(--violet) 55%, var(--sky)), transparent 60%),
        linear-gradient(135deg, var(--sky), var(--mint));
      animation: tlab-clipUp 3.2s var(--ease-in-out) infinite;
    }

    /* Respect reduced-motion — the lab is heavy, so disable loops entirely */
    @media (prefers-reduced-motion: reduce) {
      .tlab *, .tlab *::before, .tlab *::after { animation: none !important; }
    }
