/* ============ REVEAL ANIMATION ============ */
/* 
[data-reveal] {
  opacity: 0;
  transform: translateY(24px);
  transition:
    opacity 0.7s ease,
    transform 0.7s ease;
}
[data-reveal].is-visible {
  opacity: 1;
  transform: translateY(0);
}
@keyframes reveal-on-scroll {
  from {
    opacity: 0;
    transform: translateY(34px) scale(0.98);
    clip-path: inset(14% 0 0 0);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
    clip-path: inset(0);
  }
}
@keyframes reveal-media-on-scroll {
  from {
    opacity: 0;
    transform: translateX(34px) scale(0.98);
    clip-path: inset(0 0 0 14%);
  }
  to {
    opacity: 1;
    transform: translateX(0) scale(1);
    clip-path: inset(0);
  }
}
@supports (animation-timeline: view()) {
  [data-reveal] {
    opacity: 1;
    transform: none;
    clip-path: inset(0);
    animation-name: reveal-on-scroll;
    animation-duration: 1s;
    animation-timing-function: ease-out;
    animation-fill-mode: both;
    animation-timeline: view();
    animation-range: entry 0% cover 42%;
    transition: none;
  }

  .hero-media[data-reveal],
  .page-hero-media[data-reveal],
  .learn-preview-video[data-reveal],
  .learn-hero-video[data-reveal],
  .about-section-media[data-reveal],
  .service-hero-media[data-reveal] {
    animation-name: reveal-media-on-scroll;
    animation-range: entry 0% cover 46%;
  }

  .feature-grid > [data-reveal]:nth-child(2),
  .why-grid > [data-reveal]:nth-child(2),
  .hobbies-grid > [data-reveal]:nth-child(2),
  .quality-grid > [data-reveal]:nth-child(2),
  .process-list > [data-reveal]:nth-child(2),
  .tech-grid > [data-reveal]:nth-child(2),
  .learn-bento-grid > [data-reveal]:nth-child(2) {
    animation-range: entry 4% cover 44%;
  }

  .feature-grid > [data-reveal]:nth-child(3),
  .why-grid > [data-reveal]:nth-child(3),
  .hobbies-grid > [data-reveal]:nth-child(3),
  .quality-grid > [data-reveal]:nth-child(3),
  .process-list > [data-reveal]:nth-child(3),
  .tech-grid > [data-reveal]:nth-child(3),
  .learn-bento-grid > [data-reveal]:nth-child(3) {
    animation-range: entry 8% cover 46%;
  }

  .feature-grid > [data-reveal]:nth-child(4),
  .why-grid > [data-reveal]:nth-child(4),
  .hobbies-grid > [data-reveal]:nth-child(4),
  .quality-grid > [data-reveal]:nth-child(4),
  .process-list > [data-reveal]:nth-child(4),
  .tech-grid > [data-reveal]:nth-child(4),
  .learn-bento-grid > [data-reveal]:nth-child(4) {
    animation-range: entry 12% cover 48%;
  }
}
.site-header {
  animation: navbar-slide-in 0.55s ease-out both;
}

@keyframes glass-menu-in {
  from {
    opacity: 0;
    transform: translateY(-6px) scale(0.98);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

@keyframes navbar-slide-in {
  from {
    opacity: 0;
    transform: translateY(-18px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
} */



/* ==========================================================================
   ANIMATIONS: abidbaloch.com
   --------------------------------------------------------------------------
   Pure CSS, no JavaScript needed. Load it last, after style.css and
   media-queries.css (that is already the order in your HTML).

   The idea: one signature motion, the WIPE. Content is uncovered like a
   curtain (clip-path), never faded and never slid in from nowhere.

   1. Page load    Header, hero text and hero image play one sequence.
   2. Scroll       Anything with [data-reveal] is wiped in as it enters the
                   screen, tied to scroll position. Headings, step badges,
                   check marks and the big topic numerals have their own moment.
   3. Interaction  Only where it answers a click or hover: buttons, nav links,
                   icons, form focus.
   4. Pages        Smooth page-to-page transition between your HTML files.

   Everything sits inside prefers-reduced-motion: no-preference, so people who
   ask their system for less motion get a completely static site.
   ========================================================================== */

:root {
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  /* how far clip-paths extend past an element so shadows and the
     process-step badges (which sit outside their card) are not cut off */
  --bleed: -40px;
}

/* anchor links (#youtube) should land below the floating header */
html {
  scroll-padding-top: 96px;
}

@media (prefers-reduced-motion: no-preference) {
  /* horizontal wipes must never create a sideways scrollbar */
  main {
    overflow-x: clip;
  }

  /* ======================================================================
     1. KEYFRAMES
     ====================================================================== */

  /* curtain lifts from the bottom edge (cards, blocks) */
  @keyframes rise {
    from {
      clip-path: inset(100% var(--bleed) var(--bleed) var(--bleed));
    }
    to {
      clip-path: inset(var(--bleed));
    }
  }

  /* curtain drops from the top edge (paragraphs: reads top to bottom) */
  @keyframes drop-down {
    from {
      clip-path: inset(var(--bleed) var(--bleed) 100% var(--bleed));
    }
    to {
      clip-path: inset(var(--bleed));
    }
  }

  /* text wipe, left to right (headings, eyebrows) */
  @keyframes wipe {
    from {
      clip-path: inset(-0.25em 100% -0.25em -0.1em);
      transform: translateX(-14px);
    }
    to {
      clip-path: inset(-0.25em -0.5em -0.25em -0.1em);
      transform: none;
    }
  }

  /* box wipe entering from the left edge */
  @keyframes wipe-x {
    from {
      clip-path: inset(var(--bleed) 100% var(--bleed) var(--bleed));
      transform: translateX(-32px);
    }
    to {
      clip-path: inset(var(--bleed));
      transform: none;
    }
  }

  /* box wipe entering from the right edge */
  @keyframes wipe-left {
    from {
      clip-path: inset(var(--bleed) var(--bleed) var(--bleed) 100%);
      transform: translateX(32px);
    }
    to {
      clip-path: inset(var(--bleed));
      transform: none;
    }
  }

  /* circular iris that opens from the centre, with a small overshoot */
  @keyframes iris {
    from {
      clip-path: circle(0% at 50% 50%);
      transform: scale(0.7) rotate(-8deg);
    }
    60% {
      transform: scale(1.04) rotate(1deg);
    }
    to {
      clip-path: circle(100% at 50% 50%);
      transform: none;
    }
  }

  /* round markers spin open */
  @keyframes spin-in {
    from {
      clip-path: circle(0%);
      transform: rotate(-200deg) scale(0.2);
    }
    to {
      clip-path: circle(100%);
      transform: none;
    }
  }

  /* checkmark draws itself */
  @keyframes draw {
    from {
      stroke-dashoffset: 23;
    }
    to {
      stroke-dashoffset: 0;
    }
  }

  /* big background numerals travel slowly across their card */
  @keyframes drift {
    from {
      transform: translate(70px, 40px);
    }
    to {
      transform: translate(-20px, -30px);
    }
  }

  @keyframes progress {
    from {
      transform: scaleX(0);
    }
    to {
      transform: scaleX(1);
    }
  }

  @keyframes hero-parallax {
    to {
      transform: translateY(70px);
    }
  }

  /* hero title: wipe with a slight skew that straightens out */
  @keyframes title-in {
    from {
      clip-path: inset(-0.15em 100% -0.25em -0.1em);
      transform: translateX(-28px) skewX(-6deg);
    }
    to {
      clip-path: inset(-0.25em -0.4em -0.25em -0.1em);
      transform: none;
    }
  }

  /* hero portrait: arch rises like a curtain */
  @keyframes arch-in {
    from {
      clip-path: inset(100% -80px -80px -80px);
      transform: translateY(40px);
    }
    to {
      clip-path: inset(-80px);
      transform: none;
    }
  }

  @keyframes settle {
    from {
      transform: scale(1.35);
    }
    to {
      transform: none;
    }
  }

  @keyframes header-drop {
    from {
      transform: translateY(-140%) scale(0.94);
    }
    60% {
      transform: translateY(5px) scale(1.004);
    }
    to {
      transform: none;
    }
  }

  /* ======================================================================
     2. PAGE LOAD SEQUENCE
     One choreographed moment: header, then eyebrow, title, copy, buttons,
     and the image, each a beat after the last.
     ====================================================================== */

  /* header drops in on the home page only, so inner pages do not
     replay it on every navigation */
  html:has(#home) .header-inner {
    animation: header-drop 0.9s var(--ease-spring) 0.1s backwards;
  }

  /* hero wrappers carry data-reveal, but their children do the animating */
  .hero [data-reveal],
  .page-hero [data-reveal] {
    animation: none;
  }

  .hero .eyebrow,
  .page-hero .eyebrow {
    animation: wipe 0.9s var(--ease-out) 0.35s backwards;
  }

  .hero .hero-title,
  .page-hero .hero-title {
    width: fit-content;
    animation: title-in 1.1s var(--ease-out) 0.5s backwards;
  }

  .hero .hero-desc,
  .page-hero .hero-desc {
    animation: drop-down 1s var(--ease-out) 0.75s backwards;
  }

  .hero .hero-desc + .hero-desc,
  .page-hero .hero-desc + .hero-desc {
    animation-delay: 0.9s;
  }

  .hero .btn-row,
  .page-hero .btn-row {
    animation: rise 0.9s var(--ease-out) 1.05s backwards;
  }

  /* home: portrait arch rises while the photo settles inside it */
  .hero .arch-frame {
    animation: arch-in 1.2s var(--ease-out) 0.45s backwards;
  }

  .hero .arch-frame img {
    animation: settle 1.8s var(--ease-out) 0.45s backwards;
  }

  /* learn page: video frame wipes open */
  .page-hero .learn-hero-video {
    --bleed: -60px;
    animation: wipe-x 1.1s var(--ease-out) 0.5s backwards;
  }

  /* services page: three site previews arrive one after another */
  .service-hero-image {
    --bleed: -90px;
    animation: rise 1s var(--ease-out) 0.5s backwards;
  }

  .service-hero-image:nth-of-type(2) {
    animation-delay: 0.7s;
  }

  .service-hero-image:nth-of-type(3) {
    animation-delay: 0.85s;
  }

  .service-hero-note {
    animation: drop-down 0.8s var(--ease-out) 1.1s backwards;
  }

  /* the "moved" pages */
  .error-card {
    animation: rise 1s var(--ease-out) 0.1s backwards;
  }

  .error-card > * {
    animation: drop-down 0.8s var(--ease-out) backwards;
  }

  .error-card > :nth-child(1) {
    animation-delay: 0.35s;
  }
  .error-card > :nth-child(2) {
    animation-delay: 0.5s;
  }
  .error-card > :nth-child(3) {
    animation-delay: 0.65s;
  }
  .error-card > :nth-child(4) {
    animation-delay: 0.8s;
  }

  /* ======================================================================
     3. SCROLL-DRIVEN MOTION
     Uses CSS scroll timelines, so it needs no JavaScript and no
     IntersectionObserver. Browsers without support simply show the content
     as normal.
     ====================================================================== */

  @supports (animation-timeline: view()) {
    /* thin gold progress line across the very top of the screen */
    body::before {
      content: "";
      position: fixed;
      inset: 0 0 auto 0;
      height: 3px;
      z-index: 60;
      pointer-events: none;
      background: linear-gradient(90deg, var(--gold-dark), var(--gold));
      transform-origin: 0 50%;
      animation: progress linear both;
      animation-timeline: scroll(root);
    }

    /* hero portrait drifts down slightly slower than the page scrolls */
    .hero-media {
      animation: hero-parallax linear both;
      animation-timeline: scroll(root);
      animation-range: 0px 100vh;
    }

    /* ---- every [data-reveal] block: curtain wipe as it enters ---- */
    [data-reveal] {
      animation: rise var(--ease-out) backwards;
      animation-timeline: view();
      animation-range: entry calc(2% + var(--i, 0) * 7%)
        entry calc(42% + var(--i, 0) * 7%);
    }

    /* keep the hero wrappers static (their children animate on load) */
    .hero [data-reveal],
    .page-hero [data-reveal] {
      animation: none;
    }

    /* stagger by column so a row of cards opens left to right */
    :is(.feature-grid, .tech-grid) > :nth-child(4n + 2) {
      --i: 1;
    }
    :is(.feature-grid, .tech-grid) > :nth-child(4n + 3) {
      --i: 2;
    }
    :is(.feature-grid, .tech-grid) > :nth-child(4n + 4) {
      --i: 3;
    }
    :is(.why-grid, .service-detail-grid, .idea-grid, .process-list)
      > :nth-child(even) {
      --i: 1;
    }
    .hobbies-grid > :nth-child(2),
    .hobbies-grid > :nth-child(5),
    .quality-grid > :nth-child(2),
    .quality-grid > :nth-child(4),
    .learn-bento-grid > :nth-child(2),
    .learn-bento-grid > :nth-child(5) {
      --i: 1;
    }
    .hobbies-grid > :nth-child(3),
    .hobbies-grid > :nth-child(6),
    .quality-grid > :nth-child(5),
    .learn-bento-grid > :nth-child(3) {
      --i: 2;
    }

    /* tech stack: each tile opens as an iris */
    .tech-card[data-reveal] {
      animation-name: iris;
    }

    /* process steps wipe in from their own outer edge; the fifth, being
       full width, lifts like a normal block */
    .process-item[data-reveal] {
      animation-name: wipe-x;
    }
    .process-item[data-reveal]:nth-child(even) {
      animation-name: wipe-left;
    }
    .process-item[data-reveal]:nth-child(5) {
      animation-name: rise;
    }

    /* home: video slides open from the right edge */
    .learn-preview-video[data-reveal] {
      animation-name: wipe-left;
    }

    /* ---- headings and copy outside [data-reveal] blocks ---- */
    :is(.section-title, .eyebrow):not([data-reveal] *) {
      animation: wipe var(--ease-out) backwards;
      animation-timeline: view();
      animation-range: entry 0% entry 55%;
    }

    /* fit-content so the wipe sweeps across the text, not empty space */
    .section-title:not([data-reveal] *) {
      width: fit-content;
    }

    :is(.section-copy, .cta-desc, .contact-form-copy):not([data-reveal] *) {
      animation: drop-down var(--ease-out) backwards;
      animation-timeline: view();
      animation-range: entry 0% entry 60%;
    }

    /* ---- process step badges spin open (01, 02, ...) ---- */
    .process-item {
      view-timeline: --step block;
    }

    .process-item::before {
      animation: spin-in var(--ease-out) backwards;
      animation-timeline: --step;
      animation-range: entry 25% entry 80%;
    }

    /* ---- home "Explore" list: the check marks draw themselves ---- */
    .help-list li {
      view-timeline: --li block;
    }

    .help-list .check-icon {
      animation: spin-in var(--ease-out) backwards;
      animation-timeline: --li;
      animation-range: entry 10% entry 70%;
    }

    .help-list .check-icon path {
      stroke-dasharray: 23;
      animation: draw var(--ease-out) backwards;
      animation-timeline: --li;
      animation-range: entry 30% entry 90%;
    }

    /* ---- learn page: topic sequence ---- */
    .learn-topic-card {
      view-timeline: --topic block;
    }

    .learn-topic-marker {
      animation: spin-in var(--ease-out) backwards;
      animation-timeline: view();
      animation-range: entry 0% entry 60%;
    }

    /* the huge ghost numeral crosses the card as you scroll past */
    .learn-topic-card::after {
      animation: drift linear both;
      animation-timeline: --topic;
      animation-range: cover;
    }

    /* youtube list: entries wipe in one by one down the list */
    .youtube-playlist[data-reveal] {
      animation: none;
    }

    .youtube-playlist-item {
      animation: wipe-x var(--ease-out) backwards;
      animation-timeline: view();
      animation-range: entry 0% entry 65%;
    }
  }

  /* ======================================================================
     4. INTERACTION: motion that answers what the person just did
     ====================================================================== */

  /* ---- buttons: a sheen crosses the gold button on hover ---- */
  .btn-primary {
    position: relative;
    overflow: hidden;
    isolation: isolate;
  }

  .btn-primary::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background: linear-gradient(
      110deg,
      transparent 30%,
      rgba(255, 255, 255, 0.38) 50%,
      transparent 70%
    );
    transform: translateX(-120%);
  }

  .btn-primary:hover::before {
    transform: translateX(120%);
    transition: transform 0.75s var(--ease-out);
  }

  .btn-primary:active {
    transform: scale(0.97);
  }

  /* ---- text links: underline draws from the left ---- */
  .btn-text {
    background: linear-gradient(var(--accent), var(--accent)) left bottom / 0%
      2px no-repeat border-box;
    transition:
      color 0.2s ease,
      background-size 0.45s var(--ease-out);
  }

  .btn-text:hover,
  .btn-text.light:hover {
    background-size: 100% 2px;
    border-color: transparent;
  }

  /* ---- header ---- */
  .main-nav a {
    position: relative;
  }

  .main-nav a:not([aria-current="page"])::after {
    content: "";
    position: absolute;
    left: 13px;
    right: 13px;
    bottom: 4px;
    height: 2px;
    border-radius: 2px;
    background: var(--accent);
    transform: scaleX(0);
    transform-origin: right;
    transition: transform 0.45s var(--ease-out);
  }

  .main-nav a:not([aria-current="page"]):hover::after {
    transform: scaleX(1);
    transform-origin: left;
  }

  .logo img {
    transition: transform 0.6s var(--ease-spring);
  }

  .logo:hover img {
    transform: rotate(-14deg) scale(1.08);
  }

  /* ---- icons respond when their card is hovered ---- */
  .icon-box {
    transition:
      transform 0.45s var(--ease-spring),
      background-color 0.3s ease,
      box-shadow 0.3s ease;
  }

  :is(
      .feature-card,
      .why-card,
      .quality-card,
      .service-detail-card,
      .service-card,
      .process-item
    ):hover
    .icon-box {
    transform: rotate(-8deg) scale(1.1);
    background-color: rgba(181, 138, 69, 0.22);
    box-shadow: 0 0 0 6px rgba(181, 138, 69, 0.1);
  }

  .tech-icon svg {
    transition: transform 0.45s var(--ease-spring);
  }

  .tech-card:hover .tech-icon svg {
    transform: scale(1.14) rotate(-6deg);
  }

  /* hobby cards: the ghost word behind the text shifts toward the cursor */
  .hobbies .feature-card::after {
    transform-origin: right bottom;
    transition: transform 0.9s var(--ease-out);
  }

  .hobbies .feature-card:hover::after {
    transform: translate(-14px, -8px) scale(1.05);
  }

  /* youtube list numbers fill gold */
  .youtube-playlist-item span {
    transition:
      transform 0.45s var(--ease-spring),
      background-color 0.25s ease;
  }

  .youtube-playlist-item:hover span {
    background: var(--accent);
    transform: rotate(-10deg) scale(1.1);
  }

  /* process badges flip when their step is hovered */
  .process-item::before {
    transition:
      transform 0.6s var(--ease-spring),
      background-color 0.3s ease;
  }

  .process-item:hover::before {
    transform: rotate(360deg) scale(1.08);
    background-color: var(--gold);
  }

  /* ---- footer ---- */
  .footer-col a {
    transition:
      color 0.2s ease,
      transform 0.35s var(--ease-out);
  }

  .footer-col a:hover {
    transform: translateX(6px);
  }

  .footer-logo img {
    transition: transform 0.7s var(--ease-spring);
  }

  .footer-logo:hover img {
    transform: rotate(-12deg) scale(1.06);
  }

  /* ---- theme toggle: the sun/moon dial turns ---- */
  .theme-toggle-icon {
    transition: transform 0.6s var(--ease-spring);
  }

  .theme-toggle:hover .theme-toggle-icon {
    transform: rotate(180deg);
  }

  .theme-toggle:active {
    transform: scale(0.94);
  }

  /* ---- forms: the focused field's label lights up ---- */
  .contact-form label,
  .subscribe-form label {
    transition: color 0.25s ease;
  }

  .contact-form label:focus-within,
  .subscribe-form label:focus-within {
    color: var(--accent);
  }

  html[data-theme="light"] .contact-form label:focus-within,
  html[data-theme="light"] .subscribe-form label:focus-within {
    color: var(--accent-dark);
  }

  .contact-form input,
  .contact-form select,
  .contact-form textarea,
  .subscribe-form input {
    transition:
      border-color 0.25s ease,
      box-shadow 0.25s ease,
      background-color 0.25s ease;
  }

  /* confirmation / error text wipes in when it appears */
  #formStatus:not(:empty),
  .subscribe-status:not(:empty) {
    animation: wipe 0.6s var(--ease-out) backwards;
  }

  /* ======================================================================
     5. PAGE-TO-PAGE TRANSITION
     Old page holds still and dims; the new page is uncovered from the
     bottom. Works across your separate HTML files in Chrome, Edge and
     Safari. Delete this block to switch it off.
     ====================================================================== */

  @view-transition {
    navigation: auto;
  }

  @keyframes vt-old {
    to {
      transform: scale(0.97) translateY(-20px);
      filter: brightness(0.5);
    }
  }

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

  ::view-transition-group(root) {
    animation-duration: 0.8s;
  }

  ::view-transition-old(root) {
    animation: vt-old 0.8s var(--ease-out) both;
    mix-blend-mode: normal;
  }

  ::view-transition-new(root) {
    animation: vt-new 0.8s var(--ease-out) both;
    mix-blend-mode: normal;
  }
}