/* Cinema layer: entrance choreography and launch bloom.
   Loaded last on purpose — it only adds motion polish on top of the existing
   systems (terminal.css entry cascade, entry-scene.js orbit arrival, GSAP
   canvas intro). Every effect here is transform/opacity/filter only, runs
   once, and rests in a state identical to the plain page. Reduced-motion
   users (system preference or the in-app toggle) get the plain page. */

/* -------------------------------------------------------------------------
   1. Hero cascade: sharper, more cinematic reveal
   ------------------------------------------------------------------------- */

/* Motion budget (L1): the name, role and availability are what a visitor
   opens the page for, so they read within 0.6s and never blur; the focus
   pull is for the supporting lines only, and the last of them lands by
   1.2s. Every line rises with terminal.css's --entry-rise. */

/* Print-head sweep on the name: the mask slides off like a terminal printing
   the headline, and the caret rides along before it settles into its blink.
   The mask exists only inside the keyframes (fill: backwards), so it is gone
   once the sweep ends; a resting mask would clip the name's soft shadow to
   its box and leave a visible edge. Reduced motion never sees it. */
.entry-name {
    --name-sweep: linear-gradient(100deg, #000 44%, rgba(0, 0, 0, 0.25) 55%, transparent 66%);
    -webkit-mask-size: 260% 100%;
    mask-size: 260% 100%;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    animation:
        entryRise var(--entry-rise) forwards,
        entryNameSweep 0.42s cubic-bezier(0.5, 0, 0.15, 1) backwards;
}

@keyframes entryNameSweep {
    from { -webkit-mask-image: var(--name-sweep); mask-image: var(--name-sweep); -webkit-mask-position: 128% 0; mask-position: 128% 0; }
    to { -webkit-mask-image: var(--name-sweep); mask-image: var(--name-sweep); -webkit-mask-position: 0% 0; mask-position: 0% 0; }
}

/* The supporting lines: rise + a short focus pull. :where() keeps this at
   .terminal-line's specificity so the reduced-motion resets still win. */
.terminal-line:where(:not(.entry-name, .entry-role, .entry-status)) {
    animation:
        entryRise var(--entry-rise) forwards,
        entryFocusIn 0.5s cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
}

@keyframes entryFocusIn {
    from { filter: blur(7px); }
    to { filter: blur(0); }
}

/* Availability pill pops in with a small spring. */
.entry-status {
    animation:
        entryRise var(--entry-rise) forwards,
        entryPop 0.52s cubic-bezier(0.34, 1.7, 0.5, 1) backwards;
}

@keyframes entryPop {
    0% { transform: translateY(12px) scale(0.9); }
    100% { transform: translateY(0) scale(1); }
}

/* One sheen across the CTA as the cascade reaches it: the button announces
   itself as the primary action, then stays quiet. */
.entry-cta {
    position: relative;
    overflow: hidden;
}

.entry-cta::after {
    content: '';
    position: absolute;
    top: -10%;
    bottom: -10%;
    left: 0;
    width: 34%;
    pointer-events: none;
    opacity: 0;
    transform: translateX(-140%) skewX(-18deg);
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
    animation: ctaSheen 1s 1.02s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}

@keyframes ctaSheen {
    0% { opacity: 0; transform: translateX(-140%) skewX(-18deg); }
    12% { opacity: 1; }
    100% { opacity: 0; transform: translateX(440%) skewX(-18deg); }
}

/* -------------------------------------------------------------------------
   2. Stage light sweep: one soft spotlight washes across the world while the
   cascade plays, then dissolves. Sits inside the atmosphere layer so it
   never intercepts pointers.
   ------------------------------------------------------------------------- */

.entry-atmosphere::after {
    content: '';
    position: absolute;
    inset: -22%;
    pointer-events: none;
    opacity: 0;
    background: radial-gradient(40% 32% at 26% 18%, rgba(255, 252, 243, 0.66), transparent 72%);
    animation: stageLightSweep 1.9s 0.08s cubic-bezier(0.3, 0, 0.2, 1) forwards;
}

body[data-theme='dark'] .entry-atmosphere::after {
    background: radial-gradient(40% 32% at 26% 18%, rgba(189, 241, 255, 0.2), transparent 72%);
}

@keyframes stageLightSweep {
    0% { opacity: 0; transform: translate3d(-16%, -6%, 0) scale(1); }
    22% { opacity: 1; }
    100% { opacity: 0; transform: translate3d(13%, 4%, 0) scale(1.05); }
}

/* -------------------------------------------------------------------------
   3. Launch bloom: a brief light swell that bridges the entry world and the
   canvas dive. Created by app.animateLaunchBloom() (animations.js) only when
   motion is allowed; removed from the DOM when it finishes.
   ------------------------------------------------------------------------- */

.launch-bloom {
    position: fixed;
    inset: 0;
    z-index: 60;
    pointer-events: none;
    opacity: 0;
    background: radial-gradient(56% 46% at 50% 46%, rgba(255, 250, 240, 0.88), rgba(244, 238, 227, 0.3) 56%, transparent 80%);
}

body[data-theme='dark'] .launch-bloom {
    background: radial-gradient(56% 46% at 50% 46%, rgba(189, 241, 255, 0.3), rgba(143, 182, 255, 0.12) 56%, transparent 80%);
}

/* -------------------------------------------------------------------------
   4. Featured-card tilt (cinematic.js B1). GSAP owns these cards' transform,
   so .card's transform transition is dropped here: a CSS transition would
   re-ease every quickTo frame. The other .card transitions stay. Both
   pseudo-elements are already taken (::before is the tone strip in
   cards.css, ::after the motion sheen in animations.css), so the tilt only
   deepens the shadow. The dark shadow lives in the luminosity pass (§8).
   ------------------------------------------------------------------------- */

.card.card-featured {
    transition: box-shadow 0.22s ease, border-color 0.22s ease, opacity 0.3s ease;
}

.card-featured.is-tilting {
    box-shadow:
        0 18px 44px -18px rgba(60, 40, 30, 0.28),
        0 2px 8px rgba(60, 40, 30, 0.08);
}

/* -------------------------------------------------------------------------
   5. Canvas aurora (cinematic.js B4): slow blurred glows drifting behind the
   world. Injected only when motion is allowed; compositor transforms only.
   ------------------------------------------------------------------------- */

.canvas-aurora {
    position: absolute;
    inset: 0;
    overflow: hidden;
    pointer-events: none;
    z-index: 0;
}

.aurora-blob {
    position: absolute;
    display: block;
    border-radius: 50%;
    will-change: transform;
}

.aurora-a {
    width: 46vw;
    height: 46vw;
    left: -12vw;
    top: -18vw;
    background: radial-gradient(circle, rgba(178, 58, 72, 0.09), transparent 68%);
    filter: blur(52px);
    animation: auroraDriftA 38s ease-in-out infinite alternate;
}

.aurora-b {
    width: 52vw;
    height: 52vw;
    right: -16vw;
    top: 22vh;
    background: radial-gradient(circle, rgba(110, 151, 194, 0.1), transparent 68%);
    filter: blur(58px);
    animation: auroraDriftB 46s ease-in-out infinite alternate;
}

.aurora-c {
    width: 40vw;
    height: 40vw;
    left: 30vw;
    bottom: -20vw;
    background: radial-gradient(circle, rgba(156, 139, 176, 0.08), transparent 68%);
    filter: blur(48px);
    animation: auroraDriftC 52s ease-in-out infinite alternate;
}

body[data-theme='dark'] .aurora-a {
    background: radial-gradient(circle, rgba(178, 58, 72, 0.17), transparent 68%);
}

body[data-theme='dark'] .aurora-b {
    background: radial-gradient(circle, rgba(143, 182, 255, 0.11), transparent 68%);
}

body[data-theme='dark'] .aurora-c {
    background: radial-gradient(circle, rgba(189, 241, 255, 0.07), transparent 68%);
}

@keyframes auroraDriftA {
    from { transform: translate3d(0, 0, 0) scale(1); }
    to { transform: translate3d(9vw, 6vh, 0) scale(1.12); }
}

@keyframes auroraDriftB {
    from { transform: translate3d(0, 0, 0) scale(1.06); }
    to { transform: translate3d(-7vw, -8vh, 0) scale(0.96); }
}

@keyframes auroraDriftC {
    from { transform: translate3d(0, 0, 0) scale(0.98); }
    to { transform: translate3d(5vw, -7vh, 0) scale(1.1); }
}

/* -------------------------------------------------------------------------
   6. Modal depth: dim-and-blur behind the panel. The panel's lift shadow is
   modal.css's own box-shadow. Static styling, not motion, so it stays under
   reduced motion.
   ------------------------------------------------------------------------- */

.modal-overlay.active {
    -webkit-backdrop-filter: blur(9px) saturate(1.06);
    backdrop-filter: blur(9px) saturate(1.06);
}

/* -------------------------------------------------------------------------
   7. Expressive hovers: CTA sheen + arrow nudge, featured-action sweep,
   timeline column lift. Hover-only and transform/opacity based.
   ------------------------------------------------------------------------- */

.entry-cta:hover::after {
    animation: ctaSheen 0.9s cubic-bezier(0.4, 0, 0.2, 1);
}

.featured-action {
    position: relative;
    overflow: hidden;
}

.featured-action::after {
    content: '';
    position: absolute;
    top: -12%;
    bottom: -12%;
    left: 0;
    width: 32%;
    pointer-events: none;
    opacity: 0;
    transform: translateX(-150%) skewX(-18deg);
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.55), transparent);
}

.featured-action:hover::after {
    animation: ctaSheen 0.85s cubic-bezier(0.4, 0, 0.2, 1);
}

.featured-action > span:last-child {
    transition: transform 0.28s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.featured-action:hover > span:last-child {
    transform: translate(2px, -2px);
}

.journey-column-card {
    transition: box-shadow 0.35s ease, transform 0.35s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.journey-column:hover .journey-column-card {
    transform: translateY(-3px);
    box-shadow: var(--shadow-hover);
}

/* -------------------------------------------------------------------------
   8. Dark-theme luminosity pass (task-4). Dark keeps the brand hues but sat
   value-flat: tint identities faded, ghost numerals went murky, connections
   sank into the ink. Every rule here is dark-scoped, color/opacity only, and
   centralized in this layer so the source files keep one light truth.
   ------------------------------------------------------------------------- */

/* Ghost numerals: the section's signature mark deserves to read. */
body[data-theme='dark'] .region-ghost {
    color: color-mix(in srgb, var(--hue) 22%, transparent);
    text-shadow: 0 0 42px color-mix(in srgb, var(--hue) 16%, transparent);
}

/* Featured cards regain their per-hue identity: a tinted edge ring, an inset
   top light so the surface reads as raised, and a whisper-deeper base. */
body[data-theme='dark'] .card-featured {
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.055),
        0 0 0 1px color-mix(in srgb, var(--hue) 26%, transparent),
        0 16px 36px -20px rgba(0, 0, 0, 0.5);
}

body[data-theme='dark'] .card-featured.is-tilting {
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.075),
        0 0 0 1px color-mix(in srgb, var(--hue) 38%, transparent),
        0 22px 48px -20px rgba(0, 0, 0, 0.62);
}

/* Canvas section panels: a single top hairline light turns flat dark slabs
   into raised planes. */
body[data-theme='dark'] .canvas-region {
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.045);
}

/* Connections: lift out of the ink. Color-token only — no filters, so panning
   keeps its repaint budget. */
body[data-theme='dark'] {
    --connection-path: rgba(247, 242, 232, 0.3);
    --connection-primary: rgba(228, 166, 172, 0.7);
    --connection-secondary: rgba(157, 189, 224, 0.55);
    --connection-project: rgba(157, 189, 224, 0.62);
    --connection-outreach: rgba(235, 196, 140, 0.58);
}

/* List rows: the dense table was the muddiest dark surface. A top hairline
   plus a whisper of fill separates rows from the page at a glance. */
body[data-theme='dark'] .portfolio-row {
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04);
    background: rgba(247, 242, 232, 0.028);
}

body[data-theme='dark'] .portfolio-row:hover,
body[data-theme='dark'] .portfolio-row:focus-visible {
    background: rgba(228, 166, 172, 0.07);
}

/* Timeline connector threads: double their presence so year markers read as
   one continuous journey instead of floating chips. */
body[data-theme='dark'] .journey-column::before {
    opacity: 0.62;
}

/* -------------------------------------------------------------------------
   Reduced motion: every effect above collapses to the plain page.
   ------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
    .terminal-line,
    .entry-name,
    .entry-status {
        animation: none;
        opacity: 1;
        transform: none;
        filter: none;
    }

    .entry-cta::after,
    .entry-atmosphere::after {
        animation: none;
    }

    .aurora-blob {
        animation: none;
    }

    .journey-column:hover .journey-column-card {
        transform: none;
    }

    .entry-cta:hover .entry-cta-arrow,
    .featured-action:hover > span:last-child {
        transform: none;
    }
}

body[data-motion='reduced'] :is(.terminal-line, .entry-name, .entry-status) {
    animation: none;
    opacity: 1;
    transform: none;
    filter: none;
}

/* Pseudo-elements are not valid inside :is(), so these are listed out. */
body[data-motion='reduced'] .entry-cta::after,
body[data-motion='reduced'] .entry-atmosphere::after,
body[data-motion='reduced'] .aurora-blob {
    animation: none;
}

body[data-motion='reduced'] :is(.entry-cta:hover .entry-cta-arrow, .featured-action:hover > span:last-child, .journey-column:hover .journey-column-card) {
    transform: none;
}
