/* tinyblue-flair.css — Apple-grade motion + material layer for tinyblue.dev.
 *
 * Architecture:
 *   - Layers ON TOP of landing.css / tinyblue-system.css; never replaces.
 *   - One motion vocabulary: spring curve + duration scale defined as
 *     custom properties below.
 *   - Every animation has a reduced-motion fallback.
 *   - GPU only: transform + opacity, no layout-affecting properties.
 *   - Pointer-driven effects degrade silently on touch (no pointer events).
 *
 * Sections:
 *   1. Motion vocabulary
 *   2. View Transitions (cross-route)
 *   3. Aurora backdrop
 *   4. Liquid Glass nav refinement + FLIP active indicator
 *   5. Hero — word-by-word reveal, mouse parallax, spotlight
 *   6. Odometer counters
 *   7. Stat-strip tile lensing
 *   8. Card 3D tilt + cursor shimmer
 *   9. Terminal type-on caret rhythm
 *  10. Dynamic Island pill
 *  11. Magnetic more-link cards + image parallax
 *  12. Section progress rail
 */

/* ─────────────────────────── 1. Motion vocabulary ─────────────────────────── */
:root {
  /* Apple's signature spring-ish curve. Slight overshoot at the start, lazy
     settle. Used for everything that feels "physical". */
  --tb-spring: cubic-bezier(0.32, 0.72, 0, 1);
  --tb-spring-soft: cubic-bezier(0.22, 1, 0.36, 1);
  /* Duration scale. Anything outside this scale should have a reason. */
  --tb-dur-xs: 150ms;
  --tb-dur-sm: 300ms;
  --tb-dur-md: 600ms;
  --tb-dur-lg: 900ms;
  --tb-dur-xl: 1400ms;

  /* Liquid-Glass surfaces — adapt with theme. */
  --tb-glass-bg: rgba(255,255,255,0.62);
  --tb-glass-border: rgba(255,255,255,0.7);
  --tb-glass-shadow: 0 1px 0 rgba(255,255,255,0.9) inset,
                     0 -1px 0 rgba(0,0,0,0.04) inset,
                     0 12px 32px rgba(15,28,52,0.10);
  --tb-glass-blur: 22px;
  --tb-glass-saturate: 180%;
}
[data-theme="dark"] {
  --tb-glass-bg: rgba(20,24,32,0.55);
  --tb-glass-border: rgba(255,255,255,0.10);
  --tb-glass-shadow: 0 1px 0 rgba(255,255,255,0.06) inset,
                     0 -1px 0 rgba(0,0,0,0.5) inset,
                     0 14px 36px rgba(0,0,0,0.45);
}

/* ─────────────────────────── 2. View Transitions ─────────────────────────── */
/* Safari 18+ / Chrome 126+ MPA support. Cross-document fades + named
   transitions on hero/nav. Older browsers ignore these declarations. */
@view-transition { navigation: auto; }

::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: var(--tb-dur-md);
  animation-timing-function: var(--tb-spring-soft);
}
::view-transition-old(tb-hero-title),
::view-transition-new(tb-hero-title) {
  animation-duration: var(--tb-dur-md);
  animation-timing-function: var(--tb-spring);
}
.hero__title { view-transition-name: tb-hero-title; }
.nav { view-transition-name: tb-nav; }

/* ─────────────────────────── 3. Aurora backdrop ─────────────────────────── */
.tb-aurora {
  position: fixed;
  inset: -20%;
  z-index: 0;
  pointer-events: none;
  opacity: 0.55;
  filter: blur(80px) saturate(120%);
  background:
    radial-gradient(closest-side at 30% 32%, rgba(76,140,255,0.55), transparent 70%),
    radial-gradient(closest-side at 70% 28%, rgba(132,98,232,0.45), transparent 75%),
    radial-gradient(closest-side at 45% 70%, rgba(48,200,232,0.40), transparent 75%);
  transform: translate3d(var(--tb-aurora-x, 0px), var(--tb-aurora-y, 0px), 0)
             rotate(var(--tb-aurora-r, 0deg));
  transition: transform 600ms var(--tb-spring-soft);
  animation: tb-aurora-drift 36s linear infinite;
}
[data-theme="dark"] .tb-aurora {
  opacity: 0.42;
  background:
    radial-gradient(closest-side at 30% 32%, rgba(76,140,255,0.55), transparent 70%),
    radial-gradient(closest-side at 70% 28%, rgba(132,98,232,0.55), transparent 75%),
    radial-gradient(closest-side at 50% 78%, rgba(20,180,255,0.40), transparent 75%);
}
@keyframes tb-aurora-drift {
  0%   { transform: rotate(0deg) scale(1.0); }
  50%  { transform: rotate(180deg) scale(1.08); }
  100% { transform: rotate(360deg) scale(1.0); }
}
/* Keep content above the aurora without breaking the sticky nav contract. */
.nav { z-index: 50; }
main, .footer { position: relative; z-index: 1; }

/* ─────────────────────── 4. Liquid Glass nav refinement ─────────────────────── */
.nav {
  /* Stronger backdrop + the inset highlight Apple uses on glass edges */
  background: var(--tb-glass-bg);
  -webkit-backdrop-filter: blur(var(--tb-glass-blur)) saturate(var(--tb-glass-saturate));
  backdrop-filter: blur(var(--tb-glass-blur)) saturate(var(--tb-glass-saturate));
  box-shadow: var(--tb-glass-shadow);
  border-bottom: 1px solid var(--tb-glass-border);
  transition: background var(--tb-dur-sm) var(--tb-spring-soft),
              border-color var(--tb-dur-sm) var(--tb-spring-soft);
}
/* When scrolled, deepen the glass — Apple does this on iCloud.com */
.nav.is-scrolled {
  --tb-glass-bg: rgba(255,255,255,0.78);
}
[data-theme="dark"] .nav.is-scrolled {
  --tb-glass-bg: rgba(20,24,32,0.72);
}

/* FLIP active-section indicator capsule that slides between nav items */
.nav__links {
  position: relative;
}
.nav__rail-pill {
  position: absolute;
  top: 4px;
  height: calc(100% - 8px);
  background: rgba(0,0,0,0.05);
  border-radius: 999px;
  pointer-events: none;
  transition: transform var(--tb-dur-md) var(--tb-spring),
              width var(--tb-dur-md) var(--tb-spring),
              opacity var(--tb-dur-sm) ease;
  opacity: 0;
  transform: translateX(var(--tb-rail-x, 0px));
  width: var(--tb-rail-w, 0px);
  z-index: 0;
}
[data-theme="dark"] .nav__rail-pill {
  background: rgba(255,255,255,0.08);
}
.nav__rail-pill.is-active { opacity: 1; }
.nav__links a { position: relative; z-index: 1; }

/* ─────────────────────────── 5. Hero ─────────────────────────── */
/* Word-by-word reveal. Each word gets wrapped in a clip mask. */
.hero__title .hero-word {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
  line-height: inherit;
  padding-bottom: 0.05em; /* prevent descender clipping */
}
.hero__title .hero-word__inner {
  display: inline-block;
  transform: translateY(110%);
  opacity: 0;
  transition: transform var(--tb-dur-lg) var(--tb-spring),
              opacity var(--tb-dur-md) ease-out;
  transition-delay: calc(var(--tb-word-i, 0) * 80ms + 120ms);
  letter-spacing: -0.02em;
}
.hero__title.is-revealed .hero-word__inner {
  transform: translateY(0);
  opacity: 1;
  letter-spacing: -0.04em;
}

/* Hero copy mouse-spotlight: radial highlight tracks cursor */
.hero__copy {
  position: relative;
  isolation: isolate;
}
.hero__copy::before {
  content: "";
  position: absolute;
  inset: -10% -10%;
  z-index: -1;
  background: radial-gradient(
    420px circle at var(--tb-mx, 50%) var(--tb-my, 50%),
    rgba(110,160,255,0.10),
    transparent 60%
  );
  opacity: 0;
  transition: opacity var(--tb-dur-md) ease;
  pointer-events: none;
}
.hero__copy:hover::before { opacity: 1; }
[data-theme="dark"] .hero__copy::before {
  background: radial-gradient(
    480px circle at var(--tb-mx, 50%) var(--tb-my, 50%),
    rgba(120,170,255,0.14),
    transparent 60%
  );
}

/* Hero visual mouse-tilt */
.hero-visual {
  perspective: 1000px;
  will-change: transform;
}
.hero-visual img {
  transform: rotateX(var(--tb-tilt-x, 0deg)) rotateY(var(--tb-tilt-y, 0deg))
             translateZ(0);
  transition: transform 400ms var(--tb-spring-soft);
}

/* ─────────────────────────── 6. Odometer counters ─────────────────────────── */
.tb-odometer {
  display: inline-flex;
  vertical-align: baseline;
  align-items: flex-end;
  line-height: 1;
  /* Match the strong/value font sizing without growing the surrounding text */
  font-feature-settings: "tnum" 1, "lnum" 1;
}
.tb-odo-digit {
  display: inline-block;
  width: 0.62em;
  height: 1em;
  overflow: hidden;
  text-align: center;
  position: relative;
}
.tb-odo-digit__col {
  display: flex;
  flex-direction: column;
  transform: translateY(calc(var(--tb-digit, 0) * -10%));
  transition: transform var(--tb-dur-lg) var(--tb-spring);
}
.tb-odo-digit__col > span {
  display: block;
  height: 1em;
  line-height: 1em;
}

/* ─────────────────────────── 7. Stat-strip tile lensing ─────────────────────────── */
.stat {
  transition: transform var(--tb-dur-sm) var(--tb-spring),
              box-shadow var(--tb-dur-sm) ease;
  will-change: transform;
}
.stat:hover {
  transform: translateY(-4px) scale(1.015);
  box-shadow: 0 18px 36px rgba(15,28,52,0.08);
}
[data-theme="dark"] .stat:hover {
  box-shadow: 0 22px 44px rgba(0,0,0,0.45);
}

/* ─────────────────────────── 8. Card 3D tilt + shimmer ─────────────────────────── */
.cards .card {
  --tb-mx: 50%;
  --tb-my: 50%;
  --tb-rx: 0deg;
  --tb-ry: 0deg;
  position: relative;
  transform-style: preserve-3d;
  perspective: 1000px;
  transition: transform var(--tb-dur-md) var(--tb-spring),
              box-shadow var(--tb-dur-md) ease;
  will-change: transform;
}
.cards .card.is-tilted {
  transform: perspective(1000px)
             rotateX(var(--tb-rx))
             rotateY(var(--tb-ry))
             translateZ(0);
}
/* Cursor-following shimmer overlay */
.cards .card::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: radial-gradient(
    240px circle at var(--tb-mx) var(--tb-my),
    rgba(255,255,255,0.18),
    transparent 55%
  );
  opacity: 0;
  transition: opacity var(--tb-dur-sm) ease;
  mix-blend-mode: plus-lighter;
}
[data-theme="dark"] .cards .card::after {
  background: radial-gradient(
    260px circle at var(--tb-mx) var(--tb-my),
    rgba(140,180,255,0.22),
    transparent 55%
  );
}
.cards .card.is-tilted::after { opacity: 1; }
.cards .card:hover {
  box-shadow: 0 30px 60px -20px rgba(15,28,52,0.18),
              0 2px 0 rgba(255,255,255,0.05) inset;
}
[data-theme="dark"] .cards .card:hover {
  box-shadow: 0 40px 80px -28px rgba(0,0,0,0.6),
              0 2px 0 rgba(255,255,255,0.04) inset;
}
/* Icon springs forward on tilt */
.cards .card .card__icon {
  transition: transform var(--tb-dur-md) var(--tb-spring);
}
.cards .card.is-tilted .card__icon {
  transform: translateZ(40px) scale(1.06);
}

/* ─────────────────────────── 9. Terminal caret + type-on ─────────────────────────── */
.terminal .term-line.is-typing .term-cmd::after,
.terminal .term-line.is-typing .term-value::after {
  content: "▊";
  display: inline-block;
  margin-left: 2px;
  animation: tb-blink 1s steps(2) infinite;
  color: currentColor;
  opacity: 0.85;
}
@keyframes tb-blink { 0%,49% { opacity: 0.9; } 50%,100% { opacity: 0; } }

.terminal .term-line {
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 200ms ease, transform 200ms var(--tb-spring-soft);
}
.terminal .term-line.is-visible {
  opacity: 1;
  transform: translateY(0);
}
.terminal .term-line.is-stale .term-warn,
.terminal .term-line.is-stale .term-value { opacity: 0.55; }

/* Status pip on terminal — pulses while live */
.terminal__title::before {
  content: "";
  display: inline-block;
  width: 8px; height: 8px;
  border-radius: 50%;
  background: #5fd17a;
  margin-right: 8px;
  vertical-align: 1px;
  box-shadow: 0 0 0 0 rgba(95,209,122,0.5);
  animation: tb-pulse 2s infinite;
}
.terminal.is-stale .terminal__title::before {
  background: #d1a85f;
  animation: none;
}
@keyframes tb-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(95,209,122,0.55); }
  70%  { box-shadow: 0 0 0 10px rgba(95,209,122,0); }
  100% { box-shadow: 0 0 0 0 rgba(95,209,122,0); }
}

/* ─────────────────────────── 11. Magnetic more-link + image parallax ─────────────────────────── */
.more-link {
  --tb-mag-x: 0px;
  --tb-mag-y: 0px;
  transition: transform var(--tb-dur-md) var(--tb-spring),
              box-shadow var(--tb-dur-md) ease;
}
.more-link.is-magnet {
  transform: translate3d(var(--tb-mag-x), var(--tb-mag-y), 0) scale(1.02);
}
.more-link__media {
  overflow: hidden;
}
.more-link__media img {
  transition: transform 900ms var(--tb-spring-soft);
  will-change: transform;
}
.more-link:hover .more-link__media img,
.more-link.is-magnet .more-link__media img {
  transform: scale(1.06) translateY(-1%);
}
/* Corner arrow rotates from chev → arrow-up-right on hover */
.more-link__corner,
.more-link__glyph {
  transition: transform var(--tb-dur-md) var(--tb-spring),
              opacity var(--tb-dur-sm) ease;
}
.more-link:hover .more-link__glyph {
  transform: translate(2px, -2px);
}

/* ─────────────────────────── 12. Section progress rail ─────────────────────────── */
#tb-rail {
  position: fixed;
  right: max(env(safe-area-inset-right, 0px), 14px);
  top: 50%;
  transform: translateY(-50%);
  z-index: 50;
  flex-direction: column;
  gap: 10px;
  padding: 10px 6px;
  background: var(--tb-glass-bg);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  backdrop-filter: blur(14px) saturate(160%);
  border: 1px solid var(--tb-glass-border);
  border-radius: 999px;
  box-shadow: var(--tb-glass-shadow);
  display: none; /* show/hide via display toggle in JS — avoids opacity transition pinning */
  pointer-events: none;
}
#tb-rail,
#tb-rail.is-shown {
  display: none !important;
  pointer-events: none !important;
}
#tb-rail button {
  appearance: none;
  border: 0;
  background: transparent;
  width: 20px;
  height: 20px;
  padding: 0;
  cursor: pointer;
  display: grid;
  place-items: center;
  position: relative;
}
#tb-rail button::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.35;
  transition: opacity var(--tb-dur-sm) ease,
              transform var(--tb-dur-sm) var(--tb-spring),
              width var(--tb-dur-md) var(--tb-spring);
}
#tb-rail button:hover::before { opacity: 0.7; transform: scale(1.2); }
#tb-rail button[aria-current="true"]::before {
  opacity: 1;
  width: 16px;
  border-radius: 4px;
}
#tb-rail button .tb-rail__label {
  position: absolute;
  right: 24px;
  top: 50%;
  transform: translateY(-50%) translateX(8px);
  padding: 4px 10px;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  background: rgba(0,0,0,0.82);
  color: #fff;
  border-radius: 6px;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--tb-dur-sm) ease,
              transform var(--tb-dur-sm) var(--tb-spring);
}
#tb-rail button:hover .tb-rail__label,
#tb-rail button:focus-visible .tb-rail__label {
  opacity: 1;
  transform: translateY(-50%) translateX(0);
}
@media (max-width: 900px) {
  #tb-rail { display: none; }
}

/* ─────────────────────────── 13. Section heading reveals ───────────────────────────
   Reuses the existing inline IntersectionObserver that already adds .is-in
   to every .reveal element — the section h2s already carry .reveal in the
   markup, so we just react to .is-in instead of inventing our own class.
   Saves an IO + makes timing consistent with the rest of the page. */
.section__head h2 .hero-word {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
  line-height: inherit;
  padding-bottom: 0.05em;
}
.section__head h2 .hero-word__inner {
  display: inline-block;
  transform: translateY(110%);
  opacity: 0;
  transition: transform var(--tb-dur-lg) var(--tb-spring),
              opacity var(--tb-dur-md) ease-out;
  transition-delay: calc(var(--tb-word-i, 0) * 60ms);
}
.section__head h2.is-in .hero-word__inner {
  transform: translateY(0);
  opacity: 1;
}

/* ─────────────────────────── 14. Accent gradient sweep ───────────────────────────
   Subtle moving highlight on the .accent span in the hero title. Apple uses
   a similar treatment on iPhone Pro and Mac mini hero headlines. */
.hero__title .accent .hero-word__inner {
  background: linear-gradient(90deg,
    var(--ink, currentColor) 0%,
    color-mix(in oklab, var(--ink, currentColor) 60%, transparent) 40%,
    var(--ink, currentColor) 50%,
    color-mix(in oklab, var(--ink, currentColor) 60%, transparent) 60%,
    var(--ink, currentColor) 100%);
  background-size: 280% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  animation: tb-accent-sweep 6s ease-in-out infinite;
}
@keyframes tb-accent-sweep {
  0%, 100% { background-position: 0% 50%; }
  50% { background-position: 100% 50%; }
}
/* Fallback for browsers without color-mix — solid */
@supports not (color: color-mix(in oklab, red 50%, transparent)) {
  .hero__title .accent .hero-word__inner {
    -webkit-text-fill-color: initial;
    color: inherit;
    background: none;
    animation: none;
  }
}

/* ─────────────────────────── 15. Card icon bloom ───────────────────────────
   When a card tilts, its icon springs forward + scales subtly. The CSS hook
   is already in section 8 (translateZ + scale). Extend with a soft glow ring
   that pulses once on enter. */
.cards .card .card__icon {
  position: relative;
}
.cards .card .card__icon::after {
  content: "";
  position: absolute;
  inset: -8px;
  border-radius: 14px;
  background: radial-gradient(circle, color-mix(in oklab, var(--accent, #7E9CD8) 40%, transparent), transparent 70%);
  opacity: 0;
  transition: opacity var(--tb-dur-md) ease;
  z-index: -1;
  pointer-events: none;
}
.cards .card.is-tilted .card__icon::after { opacity: 1; }
@supports not (color: color-mix(in oklab, red 50%, transparent)) {
  .cards .card .card__icon::after { background: radial-gradient(circle, rgba(126,156,216,0.4), transparent 70%); }
}

/* ─────────────────────────── 16. Magnetic CTAs ───────────────────────────
   Same magnetic-pull pattern as .more-link but for buttons + the nav CTA.
   Hooked via --tb-mag-x / --tb-mag-y CSS vars driven from JS. */
.btn, .hero-inline-link, .nav__cta {
  --tb-mag-x: 0px;
  --tb-mag-y: 0px;
  transition: transform var(--tb-dur-md) var(--tb-spring),
              box-shadow var(--tb-dur-md) ease,
              background-color var(--tb-dur-sm) ease,
              color var(--tb-dur-sm) ease;
}
.btn.is-magnet, .hero-inline-link.is-magnet, .nav__cta.is-magnet {
  transform: translate3d(var(--tb-mag-x), var(--tb-mag-y), 0) scale(1.04);
}

/* ─────────────────────────── 18. Stack item brand shimmer ───────────────────────────
   On hover, a soft accent gradient sweeps across the stack item — gives the
   "Boring tools, used well." block a beat of life without ruining its density. */
.stack__item {
  position: relative;
  overflow: hidden;
  transition: transform var(--tb-dur-md) var(--tb-spring),
              box-shadow var(--tb-dur-md) ease;
}
.stack__item::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(110deg,
    transparent 35%,
    color-mix(in oklab, var(--accent, #7E9CD8) 22%, transparent) 50%,
    transparent 65%);
  transform: translateX(-100%);
  transition: transform 900ms var(--tb-spring-soft);
  pointer-events: none;
  z-index: 0;
}
.stack__item:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 28px -8px rgba(15,28,52,0.10);
}
[data-theme="dark"] .stack__item:hover {
  box-shadow: 0 16px 32px -10px rgba(0,0,0,0.4);
}
.stack__item:hover::before { transform: translateX(100%); }
.stack__item > * { position: relative; z-index: 1; }
@supports not (color: color-mix(in oklab, red 50%, transparent)) {
  .stack__item::before {
    background: linear-gradient(110deg, transparent 35%, rgba(126,156,216,0.22) 50%, transparent 65%);
  }
}

/* ─────────────────────────── 19. Hero particle network ───────────────────────────
   A canvas of slow-drifting dots connected by lines when within proximity —
   the "fleet thinks like one" metaphor made visual. Lives inside .hero with
   z-index:0 so the hero copy + image stay readable on top. */
.hero { position: relative; isolation: isolate; }
.hero > * { position: relative; z-index: 1; }
.tb-particles {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  opacity: 0.55;
  mix-blend-mode: plus-lighter;
}
[data-theme="dark"] .tb-particles { opacity: 0.7; }

/* ─────────────────────────── 20. Card icon hover animations ───────────────────────────
   Each of the 6 "What I build" cards has a distinct SVG icon. On hover we
   give the icon a unifying springy pulse, then layer per-card flourishes
   keyed off :nth-child for cards with multi-part glyphs. */
@keyframes tb-icon-pulse {
  0%   { transform: scale(1) rotate(0deg); }
  35%  { transform: scale(1.10) rotate(2deg); }
  70%  { transform: scale(0.98) rotate(-1deg); }
  100% { transform: scale(1) rotate(0deg); }
}
.cards .card:hover .card__icon svg {
  animation: tb-icon-pulse 800ms var(--tb-spring) both;
  transform-origin: center;
}

/* Card 1 (Self-hosted AI — 4 rects): sequential corner pulse */
@keyframes tb-corner-pulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(0.85); }
}
.cards .card:nth-of-type(1):hover .card__icon svg rect {
  transform-origin: center;
  transform-box: fill-box;
}
.cards .card:nth-of-type(1):hover .card__icon svg rect:nth-of-type(1) { animation: tb-corner-pulse 1200ms 0ms   var(--tb-spring) both; }
.cards .card:nth-of-type(1):hover .card__icon svg rect:nth-of-type(2) { animation: tb-corner-pulse 1200ms 150ms var(--tb-spring) both; }
.cards .card:nth-of-type(1):hover .card__icon svg rect:nth-of-type(4) { animation: tb-corner-pulse 1200ms 300ms var(--tb-spring) both; }
.cards .card:nth-of-type(1):hover .card__icon svg rect:nth-of-type(3) { animation: tb-corner-pulse 1200ms 450ms var(--tb-spring) both; }

/* Card 4 (Agent doctrine — circle with rays): slow rotation */
@keyframes tb-rotate-slow {
  to { transform: rotate(360deg); }
}
.cards .card:nth-of-type(4):hover .card__icon svg {
  animation: tb-icon-pulse 800ms var(--tb-spring) both,
             tb-rotate-slow 8s linear infinite 800ms;
  transform-origin: center;
}

/* Card 5 (Observability — zigzag path): draw-on stroke effect */
.cards .card:nth-of-type(5) .card__icon svg path {
  stroke-dasharray: 60;
  stroke-dashoffset: 0;
  transition: stroke-dashoffset 600ms ease;
}
.cards .card:nth-of-type(5):hover .card__icon svg path {
  animation: tb-draw-on 1200ms var(--tb-spring-soft) both;
}
@keyframes tb-draw-on {
  0%   { stroke-dashoffset: 60; }
  100% { stroke-dashoffset: 0; }
}

/* ─────────────────────────── 21. Snap-scroll (proximity) ───────────────────────────
   Soft section snap — only suggests positions when user is already near a
   boundary, so quick scrolling isn't fought. */
html {
  scroll-snap-type: y proximity;
  scroll-padding-top: 88px; /* clear the fixed glass nav */
}
.section, .section--alt, .section--tight, .hero, .stat-strip {
  scroll-snap-align: start;
}

/* ─────────────────────────── 23. Hero entrance choreography ───────────────────────────
   Apple sequences hero elements in a narrative arc: title first, then sub,
   meta, live status, CTAs. The existing inline IO already toggles .is-in
   on each .reveal element; we layer transition-delays so each beat lands
   in order. Title itself is word-by-word via .hero-word__inner, ~600ms
   total — subsequent elements wait for that to settle. */
.hero .eyebrow.reveal      { transition-delay: 0ms; }
.hero__title.reveal        { transition-delay: 80ms; }
.hero__sub.reveal          { transition-delay: 700ms; }
.hero__meta.reveal         { transition-delay: 850ms; }
.hero-live.reveal          { transition-delay: 950ms; }
.hero__cta-row.reveal      { transition-delay: 1050ms; }
.hero-visual.reveal        { transition-delay: 250ms; }

/* Hero visual gets a subtle entrance blur that clears — Apple does this
   on iCloud.com and product hero photos. */
.hero-visual.reveal img {
  filter: blur(8px);
  transform: scale(1.04);
  transition: filter 1200ms var(--tb-spring-soft) 250ms,
              transform 1400ms var(--tb-spring-soft) 250ms,
              opacity 700ms ease 250ms;
}
.hero-visual.reveal.is-in img {
  filter: blur(0);
  transform: scale(1);
}

/* ─────────────────────────── 24. Fleet topology orb ───────────────────────────
   Small SVG overlay on the hero image: 20 nodes in a perturbed ring with
   mesh connections, slow rotation. Visual metaphor for the 20-machine
   fleet "thinking like one mind". */
.tb-orb {
  position: absolute;
  top: 18px;
  right: 18px;
  width: 96px;
  height: 96px;
  z-index: 2;
  pointer-events: none;
  opacity: 0;
  transform: scale(0.9);
  transition: opacity 800ms var(--tb-spring-soft) 1400ms,
              transform 800ms var(--tb-spring) 1400ms;
}
.tb-orb.is-on {
  opacity: 1;
  transform: scale(1);
}
.tb-orb svg {
  width: 100%;
  height: 100%;
  animation: tb-orb-rotate 24s linear infinite;
  transform-origin: center;
  overflow: visible;
  filter: drop-shadow(0 4px 16px rgba(120,170,255,0.18));
}
.tb-orb-line {
  stroke: rgba(140,180,255,0.45);
  stroke-width: 0.6;
  fill: none;
}
.tb-orb-node {
  fill: rgba(140,180,255,0.85);
  transition: r var(--tb-dur-md) var(--tb-spring);
}
.tb-orb-node.is-online {
  fill: #5fd17a;
}
.tb-orb-node.is-offline {
  fill: #ffb84d;
}
@keyframes tb-orb-rotate {
  to { transform: rotate(360deg); }
}
[data-theme="dark"] .tb-orb-line { stroke: rgba(140,180,255,0.55); }

/* ─────────────────────────── 25. Image blur-up shimmer ───────────────────────────
   Soft animated gradient placeholder on .more-link__media until the inner
   image is decoded. Apple uses similar on its iCloud and Apple TV+ tiles. */
.more-link__media {
  background:
    linear-gradient(110deg,
      color-mix(in oklab, var(--tb-glass-border) 80%, transparent) 25%,
      color-mix(in oklab, var(--tb-glass-bg) 50%, transparent) 50%,
      color-mix(in oklab, var(--tb-glass-border) 80%, transparent) 75%);
  background-size: 220% 100%;
  animation: tb-shimmer 2.4s linear infinite;
}
.more-link__media img {
  position: relative;
  z-index: 1;
  background: transparent;
  opacity: 0;
  transition: opacity 600ms var(--tb-spring-soft);
}
.more-link__media img[data-tb-loaded="1"],
.more-link__media img.is-loaded {
  opacity: 1;
}
@keyframes tb-shimmer {
  0%   { background-position: 0% 50%; }
  100% { background-position: -220% 50%; }
}
@supports not (color: color-mix(in oklab, red 50%, transparent)) {
  .more-link__media {
    background: linear-gradient(110deg, rgba(255,255,255,0.06) 25%, rgba(255,255,255,0.14) 50%, rgba(255,255,255,0.06) 75%);
    background-size: 220% 100%;
  }
}
[data-theme="dark"] .more-link__media {
  background:
    linear-gradient(110deg,
      rgba(255,255,255,0.04) 25%,
      rgba(255,255,255,0.12) 50%,
      rgba(255,255,255,0.04) 75%);
  background-size: 220% 100%;
}

/* ─────────────────────────── 26. Scroll progress bar ───────────────────────────
   Thin accent line at the very top of the viewport that grows as the user
   scrolls. Apple uses this on iCloud, Apple TV+, and Apple Music marketing
   pages. ScrollTimeline-based when available, falls back to JS scaleX. */
#tb-scroll-progress {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  z-index: 70;
  pointer-events: none;
  background: linear-gradient(90deg,
    color-mix(in oklab, var(--accent, #7E9CD8) 80%, transparent),
    color-mix(in oklab, var(--accent, #7E9CD8) 100%, transparent));
  transform-origin: left center;
  transform: scaleX(0);
  transition: opacity var(--tb-dur-sm) ease;
  opacity: 0;
  box-shadow: 0 0 8px color-mix(in oklab, var(--accent, #7E9CD8) 30%, transparent);
}
#tb-scroll-progress.is-shown { opacity: 1; }
@supports (animation-timeline: scroll()) {
  #tb-scroll-progress {
    transform: scaleX(0);
    animation: tb-scroll-progress-grow linear;
    animation-timeline: scroll(root);
  }
  @keyframes tb-scroll-progress-grow {
    to { transform: scaleX(1); }
  }
}
@supports not (color: color-mix(in oklab, red 50%, transparent)) {
  #tb-scroll-progress { background: linear-gradient(90deg, #7E9CD8, #5fd17a); box-shadow: 0 0 8px rgba(126,156,216,0.3); }
}

/* ─────────────────────────── 27. Footer signature pulse ───────────────────────────
   Small detail: the year ticks up subtly on a soft scale pulse, and the
   author name gets a thin underline that draws on hover. Apple-style
   restraint in the footer. */
.footer__inner #year {
  display: inline-block;
  font-variant-numeric: tabular-nums;
  position: relative;
}
.footer__inner #year::after {
  content: "";
  position: absolute;
  inset: -2px -4px;
  background: radial-gradient(circle, color-mix(in oklab, var(--accent, #7E9CD8) 25%, transparent), transparent 70%);
  opacity: 0;
  z-index: -1;
  transition: opacity 600ms var(--tb-spring-soft);
  border-radius: 4px;
}
.footer__inner #year:hover::after { opacity: 1; }
.footer__links a {
  position: relative;
  transition: color var(--tb-dur-sm) ease;
}
.footer__links a::before {
  content: "";
  position: absolute;
  left: 0;
  right: 100%;
  bottom: -2px;
  height: 1px;
  background: currentColor;
  opacity: 0.6;
  transition: right 360ms var(--tb-spring);
}
.footer__links a:hover::before { right: 0; }
@supports not (color: color-mix(in oklab, red 50%, transparent)) {
  .footer__inner #year::after { background: radial-gradient(circle, rgba(126,156,216,0.25), transparent 70%); }
}

/* ─────────────────────────── 29. The network — property grid ───────────────────────────
 * Each tile is a click-throughable card with a kind-tinted glyph,
 * label, tagline, and status pill. Hover lifts slightly and tints the
 * border in the property's kind color. Status reflects what's in
 * data/properties.json — Nick's curated truth.
 */
.tb-props {
  --tb-prop-cols: 3;
  display: grid;
  grid-template-columns: repeat(var(--tb-prop-cols), minmax(0, 1fr));
  gap: 16px;
  margin-top: clamp(20px, 3vw, 36px);
}
.tb-props__placeholder {
  grid-column: 1 / -1;
  padding: 28px 22px;
  border: 1px dashed var(--rule);
  border-radius: 18px;
  color: var(--ink-mute);
  text-align: center;
  font: 500 13px/1 var(--font-sans);
}
.tb-prop {
  position: relative;
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr) auto;
  grid-template-rows: auto auto;
  grid-template-areas:
    "icon title  status"
    "icon tag    tag";
  gap: 4px 12px;
  padding: 16px 18px;
  border: 1px solid var(--rule);
  border-radius: 18px;
  background: var(--bg-elev);
  box-shadow: var(--shadow-1);
  text-decoration: none;
  color: inherit;
  transition: transform 220ms cubic-bezier(0.32, 0.72, 0, 1),
              border-color 220ms ease,
              box-shadow 220ms ease,
              background-color var(--tbpf-theme-dur, 240ms) ease;
  overflow: hidden;
  min-width: 0;
}
.tb-prop::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(circle at 0% 0%, var(--tb-prop-tint, transparent) 0%, transparent 55%);
  opacity: 0.22;
  pointer-events: none;
  transition: opacity 220ms ease;
}
.tb-prop:hover {
  transform: translateY(-2px);
  border-color: color-mix(in srgb, var(--tb-prop-tint, var(--tb-blue)) 36%, var(--rule));
  box-shadow: var(--shadow-2, 0 12px 28px -12px rgba(15, 22, 38, 0.25));
}
.tb-prop:hover::before { opacity: 0.42; }

.tb-prop__icon {
  grid-area: icon;
  width: 40px;
  height: 40px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 12px;
  background: color-mix(in srgb, var(--tb-prop-tint, var(--tb-blue)) 18%, var(--bg));
  color: var(--tb-prop-tint, var(--tb-blue));
  font-size: 18px;
  font-weight: 700;
  overflow: hidden;
  flex: 0 0 auto;
}
/* Real brand logo: sits on a light tile so every mark reads in both themes. */
.tb-prop__icon--img {
  background: #f4f4f6;
  border: 1px solid rgba(0, 0, 0, 0.08);
  padding: 4px;
}
.tb-prop__icon--img img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  border-radius: 7px;
}
/* Glyph fallback keeps the brand-tinted chip. */
.tb-prop__icon--glyph .tb-glyph {
  width: 21px;
  height: 21px;
  color: var(--tb-prop-tint, var(--tb-blue));
}
.tb-prop__title {
  grid-area: title;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.005em;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.tb-prop__tag {
  grid-area: tag;
  font-size: 12.5px;
  color: var(--ink-soft);
  line-height: 1.35;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.tb-prop__status {
  grid-area: status;
  align-self: start;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 9px;
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-mute);
  background: color-mix(in srgb, var(--ink) 6%, transparent);
  white-space: nowrap;
}
.tb-prop__status-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}
.tb-prop[data-status="live"] .tb-prop__status     { color: #2da14a; background: color-mix(in srgb, #5fd17a 18%, transparent); }
.tb-prop[data-status="building"] .tb-prop__status { color: #1a78c9; background: color-mix(in srgb, #6cc8ff 18%, transparent); }
.tb-prop[data-status="paused"] .tb-prop__status   { color: #b07a14; background: color-mix(in srgb, #ffb84d 22%, transparent); }
.tb-prop[data-status="archived"] .tb-prop__status { color: var(--ink-mute); background: color-mix(in srgb, var(--ink) 8%, transparent); }

[data-theme="dark"] .tb-prop[data-status="live"] .tb-prop__status     { color: #5fd17a; }
[data-theme="dark"] .tb-prop[data-status="building"] .tb-prop__status { color: #6cc8ff; }
[data-theme="dark"] .tb-prop[data-status="paused"] .tb-prop__status   { color: #ffb84d; }

/* Kind-based tint palette — each property type gets a distinct hue.
 * Mirrors the visual identity of the actual sites. */
.tb-prop[data-kind="portfolio"] { --tb-prop-tint: #7e9cd8; }
.tb-prop[data-kind="fitness"]   { --tb-prop-tint: #ff7f50; }
.tb-prop[data-kind="arcade"]    { --tb-prop-tint: #7c5cff; }
.tb-prop[data-kind="cards"]     { --tb-prop-tint: #d35aa1; }
.tb-prop[data-kind="ai"]        { --tb-prop-tint: #2dd4bf; }
.tb-prop[data-kind="merch"]     { --tb-prop-tint: #f59e0b; }
.tb-prop[data-kind="service"]   { --tb-prop-tint: #5fd17a; }

@media (max-width: 880px) {
  .tb-props { --tb-prop-cols: 2; }
}
@media (max-width: 540px) {
  .tb-props { --tb-prop-cols: 1; gap: 12px; }
  .tb-prop { padding: 14px 16px; grid-template-columns: 36px minmax(0, 1fr) auto; }
  .tb-prop__icon { width: 36px; height: 36px; font-size: 16px; }
  .tb-prop__title { font-size: 14px; }
  .tb-prop__tag { font-size: 12px; }
}

/* ─────────────────────────── 28. Currently shipping line ───────────────────────────
 * File-backed status pill that slots into the hero arc below the live
 * fleet pip. Reads from /api/now.php (data/now.json). Different visual
 * weight per kind: shipping/building/researching/fixing/thinking/ambient.
 * Click-throughable when the JSON file sets a link.
 */
.tb-now {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin-top: clamp(14px, 1.6vw, 22px);
  padding: 7px 13px 7px 11px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--bg-elev) 92%, transparent);
  border: 1px solid var(--rule);
  box-shadow: 0 6px 18px -10px rgba(15, 22, 38, 0.18);
  font: 500 13px/1.2 var(--font-sans);
  letter-spacing: -0.005em;
  color: var(--ink-soft);
  text-decoration: none;
  max-width: 100%;
  transition: transform 220ms cubic-bezier(0.32, 0.72, 0, 1),
              background-color 240ms ease,
              border-color 240ms ease,
              box-shadow 240ms ease,
              color 240ms ease;
  cursor: default;
}
.tb-now[href] { cursor: pointer; }
.tb-now[href]:hover {
  transform: translateY(-1px);
  border-color: color-mix(in srgb, var(--tb-blue) 32%, var(--rule));
  box-shadow: 0 12px 28px -12px rgba(15, 22, 38, 0.25);
}
.tb-now__dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent, #7e9cd8);
  box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent, #7e9cd8) 50%, transparent);
  animation: tb-pulse 2.4s infinite;
  flex: 0 0 auto;
}
.tb-now__label {
  text-transform: uppercase;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.08em;
  color: var(--ink-mute);
  padding-right: 1px;
}
.tb-now__text {
  color: var(--ink);
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: min(60ch, 100%);
}
.tb-now[data-kind="shipping"]    .tb-now__dot { background: #5fd17a; box-shadow: 0 0 0 0 rgba(95,209,122,0.5); }
.tb-now[data-kind="building"]    .tb-now__dot { background: #6cc8ff; }
.tb-now[data-kind="researching"] .tb-now__dot { background: #c7a4ff; animation: none; }
.tb-now[data-kind="fixing"]      .tb-now__dot { background: #ffb84d; }
.tb-now[data-kind="thinking"]    .tb-now__dot { background: #ff9ad1; animation: none; }
.tb-now[data-kind="ambient"]     .tb-now__dot { background: var(--accent, #7e9cd8); }

[data-theme="dark"] .tb-now {
  background: color-mix(in srgb, var(--bg-elev) 78%, transparent);
  box-shadow: 0 6px 22px -10px rgba(0, 0, 0, 0.55);
}

@media (max-width: 540px) {
  .tb-now { font-size: 12px; padding: 6px 11px 6px 10px; }
  .tb-now__label { display: none; }
  .tb-now__text { max-width: 36ch; }
}

/* ─────────────────────────── Reduced-motion sweep ─────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .hero__title .hero-word__inner {
    transform: none !important;
    opacity: 1 !important;
    transition: none !important;
  }
  .tb-aurora { animation: none !important; }
  .cards .card,
  .cards .card.is-tilted,
  .cards .card .card__icon { transform: none !important; transition: none !important; }
  .cards .card::after { display: none !important; }
  .hero-visual img { transform: none !important; }
  .stat:hover { transform: none !important; }
  .more-link.is-magnet,
  .more-link:hover .more-link__media img,
  .more-link.is-magnet .more-link__media img { transform: none !important; }
  .tb-odo-digit__col { transition: none !important; }
  .section__head h2 .hero-word__inner {
    transform: none !important;
    opacity: 1 !important;
    transition: none !important;
  }
  .hero__title .accent .hero-word__inner { animation: none !important; }
  .btn.is-magnet, .hero-inline-link.is-magnet, .nav__cta.is-magnet { transform: none !important; }
  .stack__item:hover { transform: none !important; }
  .stack__item::before { display: none !important; }
  .tb-particles { display: none !important; }
  .cards .card:hover .card__icon svg,
  .cards .card:nth-of-type(1):hover .card__icon svg rect,
  .cards .card:nth-of-type(4):hover .card__icon svg,
  .cards .card:nth-of-type(5):hover .card__icon svg path { animation: none !important; }
  html { scroll-snap-type: none !important; }
  .hero .eyebrow.reveal,
  .hero__title.reveal,
  .hero__sub.reveal,
  .hero__meta.reveal,
  .hero-live.reveal,
  .hero__cta-row.reveal,
  .hero-visual.reveal { transition-delay: 0ms !important; }
  .hero-visual.reveal img,
  .hero-visual.reveal.is-in img {
    filter: none !important;
    transform: none !important;
    transition: opacity 700ms ease !important;
  }
  .tb-orb svg { animation: none !important; }
  .tb-orb, .tb-orb.is-on { transform: none !important; opacity: 1 !important; transition: opacity 400ms ease !important; }
  .more-link__media { animation: none !important; background: transparent !important; }
  .more-link__media img { opacity: 1 !important; }
  #tb-scroll-progress, .footer__inner #year::after, .footer__links a::before { animation: none !important; transition: none !important; }
}
