/* ==========================================================
   THE NEXT BITE — Nova ESHTE
   ========================================================== */

/* ---------- Reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }
ul { list-style: none; padding: 0; margin: 0; }

/* ---------- Cursor pointer for any interactive element ---------- */
button,
[role="button"],
.moment-card,
.bubble,
.start-card,
.modal__close,
.pill,
.pill--cta,
.accordion summary,
[data-close],
[onclick] {
    cursor: pointer;
}

:root {
    --c-ink:        #1A1A1A;
    --c-ink-soft:   #2D2D2D;
    --c-hero-top:   #f7df8e;
    --c-hero-mid:   #F7E8BA;
    --c-hero-bot:   #FCF4DB;
    --c-bg-white:   #FFFFFF;
    --c-yellow:     #F6DA7B;
    --c-yellow-2:   #ecaa16;
    --c-line:       #1A1A1A;

    --font-sans: 'Geist', system-ui, -apple-system, Segoe UI, sans-serif;
    --font-mono: 'JetBrains Mono', ui-monospace, Menlo, monospace;

    --section-pad: 80px;
    --container: 1180px;

    --ease: cubic-bezier(.22, .61, .36, 1);
}

html { scroll-behavior: smooth; }

/* ---------- Letter-by-letter split: word wrapper ----------
   Each split word is wrapped in .split-word so the browser can only line-break
   BETWEEN wrappers (between words) — never inside a word. Applies on every
   viewport, regardless of whether the per-letter animation is active. */
.split-word { display: inline-block; }

/* ---------- Scroll progress bar (fixed top of viewport) ----------
   Hairline indicator that fills from left as the page is scrolled. JS sets
   --scroll-progress (0 → 1) which the .__fill child applies via scaleX. */
.scroll-progress {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 4px;
    background: rgba(0, 0, 0, 0.06);
    z-index: 1000;
    pointer-events: none;
}
.scroll-progress__fill {
    height: 100%;
    background: var(--c-ink);
    transform-origin: left center;
    transform: scaleX(var(--scroll-progress, 0));
    will-change: transform;
}

body {
    font-family: var(--font-sans);
    color: var(--c-ink);
    background: linear-gradient(
        207deg,
        var(--c-hero-top) 0%,
        var(--c-hero-mid) 30%,
        var(--c-hero-bot) 70%,
        var(--c-bg-white) 100%
    ) fixed;
    font-feature-settings: 'ss01', 'cv11';
    overflow-x: hidden;
    line-height: 1.45;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

/* ---------- Reveal animation (scroll-driven, rise only — no fade) ----------
   Each .reveal element gets --reveal-progress (0 → 1) updated by JS based on its
   viewport position. Only the translateY interpolates — elements rise from below. */
.reveal {
    transform: translateY(calc(36px * (1 - var(--reveal-progress, 0))));
    will-change: transform;
}

/* ---------- Vertical line (scroll-driven) ---------- */
.vline {
    position: relative;
    width: 2px;
    background: var(--c-line);
    margin: 0 auto;
    transform-origin: top center;
    transform: scaleY(var(--reveal-progress, 0));
}
.vline--top  { height: 60px; }
.vline--mid  { height: 56px; }
.vline--long { height: 150px; }

/* ---------- Snap-in animation (viewport-triggered, fast) ----------
   IntersectionObserver toggles `.is-in` once the element enters the viewport.
   Default: fade + rise. `.vline.snap` overrides to scaleY. `.timeline__track.snap`
   overrides to a horizontal scaleX from center. */
.snap {
    opacity: 0;
    transform: translateY(14px);
    transition:
        opacity 380ms cubic-bezier(.22,.61,.36,1) var(--snap-delay, 0ms),
        transform 380ms cubic-bezier(.22,.61,.36,1) var(--snap-delay, 0ms);
    will-change: opacity, transform;
}
.snap.is-in {
    opacity: 1;
    transform: none;
}

.vline.snap {
    opacity: 1;
    transform: scaleY(0);
    transform-origin: top center;
    transition: transform 460ms cubic-bezier(.22,.61,.36,1) var(--snap-delay, 0ms);
}
.vline.snap.is-in { transform: scaleY(1); }

/* ============================================================
   SITE HEADER — institutional logos pinned top-left
   ============================================================ */
.site-header {
    position: absolute;
    top: 15px;
    left: 25px;
    z-index: 50;
    display: flex;
    align-items: center;
    gap: 10px;
}
.site-header__logo {
    display: block;
    width: auto;
    object-fit: contain;
    filter: brightness(0);
}
.site-header__logo--eshte {     height: 100px; }
.site-header__logo--nova  { height: 140px; }

/* ============================================================
   HERO
   ============================================================ */
/* HERO is the scroll runway. The sticky inner pins for the duration of the runway
   while JS updates --hero-progress / --hero-sub / --hero-tag / --hero-line based on scroll. */
.hero {
    height: 200vh;
    min-height: 1440px;
    max-height: 2000px;
    position: relative;
    background: transparent;
}
.hero__sticky {
    position: sticky;
    top: 0;
    height: 100vh;
    min-height: 720px;
    /* max-height: 1000px; */
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 0 24px;
    text-align: center;
    /* overflow: visible — let the connector line extend past the sticky bottom. */
}
.hero__inner {
    width: 100%;
    max-width: 1380px;
    display: flex;
    flex-direction: column;
    align-items: center;
}

.hero__title {
    margin: 0;
    line-height: 0;
    color: var(--c-ink);
    transform-origin: center;
    /* Scroll-driven: at progress=0 → scale 2.35 + translated down ~38vh; at progress=1 → identity. */
    transform:
        translateY(calc(clamp(220px, 38vh, 500px) * (1 - var(--hero-progress, 0))))
        scale(calc(1 + 1.35 * (1 - var(--hero-progress, 0))));
}
.hero__title-svg {
    display: block;
    width: clamp(290px, 39vw, 1346px);
    height: auto;
    color: inherit;
}

.hero__subtitle {
    font-size: clamp(16px, 2vw, 33px);
    font-weight: 300;
    margin: 5px 0 0;
    color: var(--c-ink);
    letter-spacing: -0.005em;
    opacity: var(--hero-sub, 0);
    transform: translateY(calc(14px * (1 - var(--hero-sub, 0))));
}
.hero__subtitle strong { font-weight: 500; }

.hero__tag {
    font-size: clamp(12px, 1.5vw, 20px);
    font-weight: 300;
    margin: 5px 0 0;
    color: var(--c-ink);
    text-transform: uppercase;
    opacity: var(--hero-tag, 0);
    transform: translateY(calc(14px * (1 - var(--hero-tag, 0))));
}
.hero__tag strong { font-weight: 500; }

/* Connector line — sits INSIDE the sticky so it stays pinned with the title
   during the hero pin region (scroll 0–100vh). Anchored just below the
   "NA NOVA ESHTE" tag (~62% of sticky) and grows downward via scaleY tied to
   scroll progress. The line bottom reaches the sticky bottom, which equals the
   moments section top once the sticky unpins — giving a continuous visual
   connector to (but not through) the moments intro text. */
.hero__line {
    position: absolute;
    left: 50%;
    /* Top: just below the tag's vertical position inside the sticky. */
    top: calc(58% + 40px);
    /* Height: extends to ~98% of the sticky, getting closer to the
       hero/moments boundary while still leaving a hairline of breathing room. */
    height: calc(33% + 20px);
    width: 2px;
    background: var(--c-line);
    transform: translateX(-50%) scaleY(var(--hero-line, 0));
    transform-origin: top center;
    pointer-events: none;
}

/* ============================================================
   MANIFESTO
   ============================================================ */
.manifesto {
    padding: 30px 24px 0;
    text-align: center;
    max-width: 820px;
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0;
display: none;
}
.manifesto__lead {
    font-size: clamp(20px, 3vw, 36px);
    font-weight: 400;
    line-height: 1.4;
    margin: 0 0 56px;
    max-width: 720px;
    letter-spacing: -0.03em;
}
.manifesto__lead strong { font-weight: 600; }

.manifesto__line {
    font-size: clamp(20px, 3.5vw, 42px);
    font-weight: 400;
    margin: 0;
    line-height: 1.4;
}
.manifesto__line strong { font-weight: 600; }

/* ============================================================
   PILLARS
   ============================================================ */
.pillars {
    padding: 40px 24px 80px;
    text-align: center;
display: none;
}
.pillars__title {
    font-size: clamp(24px, 3vw, 34px);
    font-weight: 600;
    margin: 0 0 24px;
    letter-spacing: -0.01em;
}
.pillars__eyebrow {
    font-family: var(--font-mono);
    font-size: 27px;
    letter-spacing: -1%;
    margin: 0 0 60px;
    color: var(--c-ink);
    text-transform: uppercase;
    font-weight: 300;
}
.pillars__pills {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 14px;
    margin: 0 auto;
}

/* ---------- Pill component ---------- */
.pill {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 24px 65px;
    background: var(--c-yellow);
    border-radius: 999px;
    font-weight: 500;
    font-size: 24px;
letter-spacing: -3%;
    box-shadow: 0 14px 22px -10px rgba(180, 140, 20, 0.45);
    color: var(--c-ink);
    transition: transform .25s var(--ease), box-shadow .25s var(--ease);
    border: none;
}
.pill:hover {
    box-shadow: 0 14px 22px -10px rgba(180, 140, 20, 0.45);
}
.pill--cta {
    background: rgba(255, 255, 255, 0.45);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border: 1px solid rgba(255, 255, 255, 0.75);
    box-shadow:
        0 0 0 1px rgba(255, 255, 255, 0.25),
        inset 0 1px 0 rgba(255, 255, 255, 0.7),
        0 8px 18px -8px rgba(0, 0, 0, 0.18);
    color: var(--c-ink);
    font-family: var(--font-mono);
    font-size: 12px;
    letter-spacing: 0.22em;
    padding: 14px 30px;
    text-transform: uppercase;
    text-decoration: none;
transition: all 0.2s ease-in-out;
}
.pill--cta:hover {
    /* "Pressed in" feel — slightly darker face, tiny push down, and inset
       shadows replace the outer drop so the button looks recessed below
       its rim instead of lifted above the surface. */
    background: rgba(255, 255, 255, 0.72);
    box-shadow:
        inset 0 3px 6px rgba(0, 0, 0, 0.18),
        inset 0 1px 2px rgba(0, 0, 0, 0.1),
        0 1px 2px rgba(0, 0, 0, 0.05);
}

/* ============================================================
   MOMENTS (3 cards)
   ============================================================ */
.moments {
    padding: 0px 24px var(--section-pad);
    max-width: var(--container);
    margin: 0 auto;
    text-align: center;
}
.moments__intro {
     font-size: clamp(20px, 2.6vw, 38px);
    font-weight: 600;
    line-height: 1.1;
    letter-spacing: -3%;
    margin: 0 auto 70px;
    max-width: 540px;
    text-align: center;
}
.moments__title {
    font-size: clamp(20px, 2.4vw, 29px);
    font-weight: 400;
    margin: 0 0 90px;
}
.moments__title strong { font-weight: 600; }

.moments__grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 40px;
    max-width: 920px;
    margin: 0 auto;
}

.moment-card {
    position: relative;
    aspect-ratio: 3 / 4;
    border-radius: 40px;
    overflow: hidden;
    cursor: pointer;
    isolation: isolate;
    box-shadow: 0 5px 6px 0px rgba(60, 40, 0, 0.50);
    transition: box-shadow .3s var(--ease), transform .25s var(--ease);
}
/* Mouse-tracked 3D tilt — variables set by JS (.moment-card-tilt). The
   transform composes perspective + rotateX/Y so the card subtly leans
   toward the cursor. After .is-in completes (snap reset), this rule wins
   thanks to higher specificity. */
.moment-card.snap.is-in {
    transform:
        perspective(1000px)
        rotateX(var(--tilt-x, 0deg))
        rotateY(var(--tilt-y, 0deg))
        translateZ(0);
}
.moment-card:hover,
.moment-card:focus-visible {
    box-shadow: 0 12px 26px -4px rgba(60, 40, 0, 0.35);
}
.moment-card__image {
    position: absolute;
    inset: 0;
    background-size: cover;
    background-position: center;
    transition: transform 2.4s var(--ease), filter 1s var(--ease);
    z-index: 1;
}
.moment-card:hover .moment-card__image {
    transform: scale(1.10);
    filter: saturate(1.12) brightness(0.96);
}

.moment-card::before {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(0,0,0,0) 45%, rgba(0,0,0,0.55) 100%);
    z-index: 2;
}

.moment-card__label {
    position: absolute;
    left: 22px;
    bottom: 18px;
    color: #fff;
    font-weight: 600;
    font-size: 19px;
    line-height: 1.15;
    margin: 0;
    z-index: 4;
    text-align: left;
    transition: opacity .3s var(--ease), transform .3s var(--ease);
}

.moment-card__overlay {
    position: absolute;
    inset: 0;
    z-index: 5;
    padding: 32px 28px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 18px;
    background: #FBF7E8;
    opacity: 0;
    transition: opacity .3s var(--ease);
    pointer-events: none;
}
.moment-card__overlay p {
    color: var(--c-ink);
    font-size: 18px;
    line-height: 1.2;
    margin: 0;
    text-align: center;
    font-weight: 400;
    /* Cascade-in: overlay paragraphs slide up + fade in with stagger */
    opacity: 0;
    transform: translateY(8px);
    transition: opacity .35s var(--ease), transform .35s var(--ease);
}
.moment-card__overlay p strong { font-weight: 600; }
.moment-card:hover .moment-card__overlay p,
.moment-card:focus-visible .moment-card__overlay p { opacity: 1; transform: none; }
.moment-card:hover .moment-card__overlay p:nth-child(1) { transition-delay: .08s; }
.moment-card:hover .moment-card__overlay p:nth-child(2) { transition-delay: .14s; }
.moment-card:hover .moment-card__overlay p:nth-child(3) { transition-delay: .20s; }

.moment-card__pills {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    margin-top: 6px;
}
.moment-card__pill {
    background: var(--c-yellow-2);
    color: #fff;
    border-radius: 999px;
    padding: 9px 20px;
    font-size: 14px;
    font-weight: 500;
    line-height: 1.1;
    width: 100%;
    text-align: center;
    text-decoration: none;
    cursor: pointer;
    /* Pills are <a> links (3 licenciaturas). Override the parent overlay's
       pointer-events:none so the links are clickable when the overlay is visible. */
    pointer-events: auto;
    transition: transform .2s var(--ease), box-shadow .2s var(--ease);
    /* Cascade-in: each pill slides up + fades in with its own delay */
    opacity: 0;
    transform: translateY(8px);
    transition: opacity .35s var(--ease), transform .35s var(--ease);
}
.moment-card:hover .moment-card__pill,
.moment-card:focus-visible .moment-card__pill { opacity: 1; transform: none; }
.moment-card:hover .moment-card__pill:nth-child(1) { transition-delay: .22s; }
.moment-card:hover .moment-card__pill:nth-child(2) { transition-delay: .30s; }
.moment-card:hover .moment-card__pill:nth-child(3) { transition-delay: .38s; }

.moment-card:hover .moment-card__overlay,
.moment-card:focus-visible .moment-card__overlay { opacity: 1; }
.moment-card:hover .moment-card__label,
.moment-card:focus-visible .moment-card__label {
    opacity: 0;
}

/* ============================================================
   START — Tudo começa aqui
   ============================================================ */
.start {
    padding: 40px 24px 0;
    text-align: center;
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 25px;
}
.start__title {
    font-size: clamp(26px, 8vw, 55px);
    font-weight: 600;
    margin: 0;
    letter-spacing: -3%;
    line-height: 1;
}
/* Glass-bubble card — transparent body, soft halo around the perimeter, subtle
   inner highlight on the top edge. The same treatment carries over to .modal__panel. */
.start-card {
    position: relative;
    background: rgba(255, 255, 255, 0.45);
    backdrop-filter: blur(22px) saturate(150%);
    -webkit-backdrop-filter: blur(22px) saturate(150%);
    border: 1px solid rgba(255, 255, 255, 0.7);
    border-radius: 22px;
    padding: 32px 40px;

    /* Same glass-bubble shadow set as .contact-card — golden halo + inner
       sheen — so this CTA reads as a polished interactive card instead of
       a flat panel. */
    box-shadow:
        0 0 0 1px rgba(255, 255, 255, 0.25),
        inset 0 1px 0 rgba(255, 255, 255, 0.7),
        0 14px 28px -10px rgba(180, 140, 20, 0.25),
        0 30px 50px -20px rgba(180, 140, 20, 0.15);
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
    transition:
        transform .25s var(--ease),
        box-shadow .25s var(--ease),
        background .25s var(--ease),
        opacity .25s var(--ease);
}
/* Hide the trigger card while the degree modal is open — the modal panel takes its place. */
body:has(#degree-modal.is-open) .start-card,
body:has(#degree-modal.is-open) .start-card__hint {
    opacity: 0;
    pointer-events: none;
}

/* Wrapper used to anchor the hand-drawn click hint relative to the card. */
.start-card-wrap {
    position: relative;
    display: inline-flex;
    flex-direction: column;
    align-items: center;
}

/* Three equal cards side-by-side (Nutrição | PAR | FCT). The centre one is
   a <button> that opens the degree modal; the sides are <a> links opening
   in new tabs. All three share the same glass-bubble .start-card styling. */
.start__cards {
    display: flex;
    align-items: stretch;
    justify-content: center;
    gap: 28px;
    flex-wrap: wrap;
    /* max-width: 1100px; */
    margin: 0 auto;
    padding: 0 24px;
}
/* Make every direct child share the row equally. The centre slot is the
   .start-card-wrap (it holds the button + hint), the sides are <a> .start-card. */
.start__cards > .start-card,
.start__cards > .start-card-wrap {
    flex: 1 1 0;
    min-width:340px;
}
.start-card-wrap {
    display: flex;
    flex-direction: column;
    align-items: stretch;
}
.start-card-wrap > .start-card {
    width: 100%;
}
/* Side cards are <a> tags — override user-agent link colours (which beat
   `.start-card { color: var(--c-ink) }` because :link / :visited add
   specificity) so titles read in dark ink, never blue or purple. */
.start-card[href],
.start-card[href]:link,
.start-card[href]:visited,
.start-card[href]:hover,
.start-card[href]:active {
    color: var(--c-ink);
    text-decoration: none;
}
/* Tighten typography on the cards so 3 fit comfortably side-by-side
   instead of wrapping under the .start__cards max-width. */
.start__cards .start-card__title {
    font-size: clamp(18px, 1.6vw, 24px);
    line-height: 1.2;
}
.start__cards .start-card {
    padding: 26px 24px;
}

/* "experimenta!" hint — Caveat handwriting + squiggly arrow pointing at the
   card's top-right corner. Same hand-drawn vocabulary as the swipe-hint
   (mobile modal) so the system stays cohesive. */
.start-card__hint {
    position: absolute;
    top: -54px;
    right: -88px;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0;
    color: var(--c-ink);
    opacity: 0.62;
    pointer-events: none;
    z-index: 2;
    /* Subtle bounce — nudges 3px down-left toward the card every 2.6s. */
    animation: startHintBounce 2.6s ease-in-out infinite;
}
.start-card__hint-text {
    font-family: 'Caveat', cursive;
    font-size: 26px;
    font-weight: 600;
    line-height: 1;
    letter-spacing: 0.3px;
    transform: rotate(-8deg);
    white-space: nowrap;
}
.start-card__hint-arrow {
    width: 60px;
    height: auto;
    margin-top: 2px;
    margin-left: 18px;
    color: inherit;
    display: block;
}
@keyframes startHintBounce {
    0%, 100% { transform: translate(0, 0); }
    50%      { transform: translate(-3px, 3px); }
}
.start-card:hover {
    /* Pressed-in feel — mirrors .contact-card / .pill--cta hover. */
    background: rgba(255, 255, 255, 0.32);
    transform: translateY(1px);
    transition:
        transform .15s var(--ease),
        box-shadow .15s var(--ease),
        background .15s var(--ease);
    box-shadow:
        inset 0 3px 6px rgba(0, 0, 0, 0.18),
        inset 0 1px 2px rgba(0, 0, 0, 0.1),
        0 1px 2px rgba(0, 0, 0, 0.05);
}
.start-card__eyebrow {
    font-family: var(--font-mono);
    font-size: 13px;
    letter-spacing: -1%;
    text-transform: uppercase;
    color: var(--c-ink-soft);
    font-weight: 400;
}
.start-card__title {
    font-size: 29px;
    font-weight: 600;
    line-height: 1.15;
    text-align: center;
    letter-spacing: -1%;
}

/* ============================================================
   STORY (Rui Mota timeline)
   ============================================================ */
.story {
    padding: 40px 24px;
    max-width: var(--container);
    margin: 0 auto;
    text-align: center;
}
.story__title {
    font-size: clamp(24px, 3vw, 38px);
    font-weight: 600;
    margin: 0 0 24px;
    letter-spacing: -3%;
}
.story__intro {
    font-size: clamp(15px, 5vw, 30px);
    margin: 0 0 120px;
    color: var(--c-ink);
    font-weight: 400;
    line-height: 1.5;
    letter-spacing: -1%;
}
.story__intro strong { font-weight: 600; }

/* ----- Horizontal timeline ----- */
.timeline {
    --tl-circle: 234px;
    --tl-gap: 20px;
    --tl-dot: 12px;
    position: relative;
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 70px;
    margin: 0 auto;
}
/* Full-page-width line passing through the vertical center of the dot row. */
.timeline__track {
    position: absolute;
    left: 50%;
    top: calc(var(--tl-circle) + var(--tl-gap) + var(--tl-dot) / 2);
    width: 100vw;
    height: 1px;
    background: var(--c-line);
    pointer-events: none;
    z-index: 1;
}
.timeline__track.snap {
    transform: translateX(-50%) scaleX(0);
    transform-origin: center center;
    opacity: 1;
    transition: transform 750ms cubic-bezier(.22,.61,.36,1) var(--snap-delay, 0ms);
}
.timeline__track.snap.is-in { transform: translateX(-50%) scaleX(1); }

.timeline__item {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    z-index: 2;
}

.timeline__circle {
    width: var(--tl-circle);
    height: var(--tl-circle);
    border-radius: 50%;
    background-size: cover;
    background-position: center;
    box-shadow: 0 14px 30px -18px rgba(60,40,0,0.35);
    transition: transform .35s var(--ease);
}
.timeline__item:hover .timeline__circle,
.timeline__item:focus-within .timeline__circle { transform: scale(1.04); }

.timeline__dot {
    width: var(--tl-dot);
    height: var(--tl-dot);
    border-radius: 50%;
    background: var(--c-ink);
    margin-top: var(--tl-gap);
    z-index: 3;
    position: relative;
}

.timeline__caption {
    margin-top: 26px;
    width: 100%;
    max-width: 240px;
    text-align: left;
    font-size: 20px;
    line-height: 1.45;
    color: var(--c-ink);
    opacity: 0;
    pointer-events: none;
    transform: translateY(6px);
    transition: opacity .3s var(--ease), transform .3s var(--ease);
}
.timeline__caption strong { font-weight: 600; }
.timeline__item:hover .timeline__caption,
.timeline__item:focus-within .timeline__caption {
    opacity: 1;
    transform: translateY(0);
}

/* ============================================================
   CLUSTER — 8 circles
   ============================================================ */
.cluster {
    padding: 40px 24px 120px;
    max-width: var(--container);
    margin: 0 auto;
    text-align: center;
}
.cluster__intro {
    font-size: clamp(16px, 5vw, 38px);
    margin: 0px 0 10px;
    color: var(--c-ink);
    font-weight: 600;
    letter-spacing: -3%;
}
.cluster__intro strong { color: var(--c-ink); font-weight: 600; }

.cluster__title {
    font-size: clamp(22px, 5vw, 32px);
    font-weight: 700;
    margin: 0 0 24px;
    letter-spacing: -0.01em;
}
.cluster__cta {
    font-family: var(--font-mono);
    font-size: 26px;
    letter-spacing: -3%;
    text-transform: uppercase;
    color: var(--c-ink);
    margin: 0 0 60px;
    line-height: 1.6;
    font-weight: 400;
}
.cluster__cta span {
    display: block;
    font-size: 20px;
    letter-spacing: -3%;
    color: var(--c-ink-soft);
    margin-top: 4px;
}

/* Bubble cluster — compact, organic arrangement (matches Figma frame_025). */
.cluster__bubbles {
    position: relative;
    width: 100%;
    /* max-width: 720px; */
    height: 440px;
    margin: 80px auto 0;
}
.bubble {
    position: absolute;
    border-radius: 50%;
    background-size: cover;
    background-position: center;
    box-shadow: 0 18px 36px -22px rgba(60,40,0,0.35);
    transition: transform .35s var(--ease), box-shadow .35s var(--ease);
    overflow: hidden;
    isolation: isolate;
    cursor: pointer;
    border: 0;
    padding: 0;
}
/* Permanent dark filter so the label is always legible on top of the photo. */
.bubble::before {
    content: "";
    position: absolute;
    inset: 0;
    background: rgba(0,0,0,0.25);
    z-index: 1;
}
.bubble__label {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    color: #fff;
    font-weight: 800;
    font-size: 14px;
    letter-spacing: 0.06em;
    line-height: 1.15;
    z-index: 2;
}
.bubble:hover {
    transform: scale(1.06);
    box-shadow: 0 26px 44px -18px rgba(60,40,0,0.45);
}

/* Idle float — slow vertical bob, each bubble offset for organic feel.
   Uses `translate` (not `transform`) so the existing `transform: scale(...)`
   on hover doesn't get overridden by the keyframe animation. */
.bubble.snap.is-in {
    animation: bubbleFloat 5.6s ease-in-out infinite;
    animation-delay: var(--bubble-float-delay, 0s);
}
.bubble--1 { --bubble-float-delay: 0s; }
.bubble--2 { --bubble-float-delay: -.7s; }
.bubble--3 { --bubble-float-delay: -1.4s; }
.bubble--4 { --bubble-float-delay: -2.1s; }
.bubble--5 { --bubble-float-delay: -2.8s; }
.bubble--6 { --bubble-float-delay: -3.5s; }
.bubble--7 { --bubble-float-delay: -4.2s; }
.bubble--8 { --bubble-float-delay: -4.9s; }
.bubble:hover { animation-play-state: paused; }
@keyframes bubbleFloat {
    0%, 100% { translate: 0 0; }
    50%      { translate: 0 -8px; }
}

/* sizes & positions — compact organic cluster, top + bottom rows touching/overlapping */
/* top row */
.bubble--1 { width: 226px; height: 226px; left:  8%; top:  8%;  }
.bubble--2 { width: 181px; height: 181px; left:  30%; top:  14%;  }
.bubble--3 {     width: 226px;
    height: 226px;
    left: 30%;
    top: 0%; }
.bubble--4 {     width: 182px;
    height: 182px;
    left: 52%;
    top: 10%;  }
/* bottom row — slight overlap with top row for cluster feel */
.bubble--5 { width: 182px; height: 182px; left:  22%; top:  56%; }
.bubble--6 { width: 182px; height: 182px; left:  40%; top:  52%; }
.bubble--7 { width: 226px; height: 226px; left:  58%; top:  50%; }
.bubble--8 { width: 182px;
    height: 182px;
    left: 70%;
    top: 10%; }

/* ============================================================
   CONTACT CTA — sits between the bubble cluster and the Rui Mota
   timeline. Glass-bubble card matching .start-card / .modal__panel
   aesthetic, with the email as the primary call to action.
   ============================================================ */
.contact {
    text-align: center;
    padding: 0px 24px 80px;
    max-width: 780px;
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
}
.contact__eyebrow {
    font-family: var(--font-mono);
    font-size: 14px;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--c-ink-soft);
    margin: 0 0 18px;
}
.contact__title {
    font-size: clamp(28px, 4.4vw, 56px);
    font-weight: 600;
    letter-spacing: -0.025em;
    line-height: 1.05;
    color: var(--c-ink);
    margin: 0 0 22px;
}
.contact__intro {
    font-size: clamp(16px, 1.6vw, 22px);
    font-weight: 300;
    line-height: 1.5;
    color: var(--c-ink);
    letter-spacing: -0.005em;
    margin: 0 0 44px;
}
.contact__intro strong { font-weight: 600; }

/* Email CTA — glass bubble, mirrors the .start-card treatment but laid
   out horizontally (label + email side by side). */
.contact-card {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    padding: 20px 56px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.45);
    backdrop-filter: blur(22px) saturate(150%);
    -webkit-backdrop-filter: blur(22px) saturate(150%);
    border: 1px solid rgba(255, 255, 255, 0.7);
    box-shadow:
        0 0 0 1px rgba(255, 255, 255, 0.25),
        inset 0 1px 0 rgba(255, 255, 255, 0.7),
        0 14px 28px -10px rgba(180, 140, 20, 0.25),
        0 30px 50px -20px rgba(180, 140, 20, 0.15);
    color: var(--c-ink);
    text-decoration: none;
    cursor: pointer;
    /* `translate` is animated separately from `transform` so the magnetic
       follow (set by JS via --magnet-x/y) composes cleanly with the static
       `transform: translateY(1px)` press-in on hover. */
    translate: var(--magnet-x, 0) var(--magnet-y, 0);
    transition:
        transform .25s var(--ease),
        translate .35s cubic-bezier(.34, 1.56, .64, 1),
        box-shadow .25s var(--ease),
        background .25s var(--ease);
}
.contact-card:hover {
    /* Pressed-in feel — same treatment as .pill--cta:hover. */
    background: rgba(255, 255, 255, 0.32);
    transform: translateY(1px);
    transition:
        transform .15s var(--ease),
        translate .12s var(--ease),
        box-shadow .15s var(--ease),
        background .15s var(--ease);
    box-shadow:
        inset 0 3px 6px rgba(0, 0, 0, 0.18),
        inset 0 1px 2px rgba(0, 0, 0, 0.1),
        0 1px 2px rgba(0, 0, 0, 0.05);
}
.contact-card__label {
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--c-ink-soft);
    line-height: 1;
}
.contact-card__email {
    font-size: clamp(20px, 2vw, 28px);
    font-weight: 500;
    letter-spacing: -0.01em;
    color: var(--c-ink);
    line-height: 1.1;
}

/* Cluster bubble tap-hint (mobile only). A subtle ripple ::after sits
   inside every bubble in the cluster, suggesting they're tappable.
   Hidden by default; the ≤540px media query below enables and animates it.
   JS adds .is-tapped to .cluster__bubbles once any bubble is tapped —
   fades all ripples out permanently for the rest of the session. */
@keyframes bubbleTapRipple {
    0%, 25% { transform: translate(-50%, -50%) scale(0);   opacity: 0; }
    35%     { transform: translate(-50%, -50%) scale(0.4); opacity: 0.55; }
    100%    { transform: translate(-50%, -50%) scale(1.5); opacity: 0; }
}

/* ============================================================
   FOOTER
   ============================================================ */
.footer {
    padding: 60px 48px 36px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    flex-wrap: wrap;
    gap: 36px;
    font-size: 11px;
    color: var(--c-ink);
}

/* Social media — two bordered boxes ("NOVA NAS REDES" / "ESHTE NAS REDES").
   Each box has a label that interrupts the top border (positioned over it,
   with a solid background that "cuts" the line cleanly). */
.footer__socials-grid {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 28px;
    width: 100%;
    margin-bottom: 30px;
}
.footer__socials-box {
    position: relative;
    border: 1px solid var(--c-ink);
    border-radius: 14px;
    padding: 26px 50px 22px;
}
.footer__socials-label {
    position: absolute;
    top: 0;
    left: 22px;
    transform: translateY(-50%);
    background: #fcf5dd; /* matches body gradient cream tone behind footer */
    padding: 2px 12px;
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--c-ink);
    line-height: 1;
    white-space: nowrap;
}
.footer__socials {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 40px;
}
.footer__social {
    width: 26px;
    height: 26px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--c-ink);
    opacity: 0.7;
    text-decoration: none;
    transition: opacity .25s var(--ease), transform .25s var(--ease);
}
.footer__social:hover,
.footer__social:focus-visible {
    opacity: 1;
    transform: translateY(-2px);
}
.footer__social svg {
    width: 100%;
    height: 100%;
    display: block;
}
.footer__group {
    display: flex;
    align-items: flex-end;
    gap: 28px;
    flex-wrap: wrap;
    align-items: center;
}
.footer__group--right {
    gap: 32px;
}

.footer__logo-img {
    display: block;
    width: auto;
    object-fit: contain;
    filter: brightness(0);
}
.footer__logo-img--eshte { height: 81px; }
.footer__logo-img--nova  { height:120px; }
.footer__logo-img--small { height: 47px; }

/* ============================================================
   MODAL
   ============================================================ */
/* Note: no opacity animation on the modal itself — opacity != 1 on any ancestor
   makes backdrop-filter sample opaque black, causing the panel blur to "snap in"
   when opacity finishes. Visibility is toggled via `hidden` and `pointer-events`. */
.modal {
    position: fixed;
    inset: 0;
    z-index: 100;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    pointer-events: none;
}
.modal.is-open {
    pointer-events: auto;
}
.modal[hidden] { display: none; }

/* Backdrop fills the modal viewport so clicking outside the panel closes it.
   Visually transparent — the page behind shows through unaltered. */
.modal__backdrop {
    position: absolute;
    inset: 0;
    background: transparent;
    cursor: pointer;
}

/* Glass-bubble panel — translucent body with strong blur so the page behind
   shows through softly. */
.modal__panel {
    position: relative;
    background: rgba(255, 255, 255, 0.15);
    backdrop-filter: blur(5px);
    -webkit-backdrop-filter: blur(5px);
    border-radius: 28px;
    box-shadow:
        0 0 0 1px rgba(255, 255, 255, 0.35),
        0 20px 56px -10px rgba(255, 255, 255, 0.45),
        0 32px 80px -16px rgba(255, 230, 170, 0.4),
        inset 0 1px 0 rgba(255, 255, 255, 0.7),
        inset 0 -1px 0 rgba(255, 255, 255, 0.25);
    max-width: 920px;
    width: 100%;
    max-height: 90vh;
    overflow-x: hidden;
    overflow-y: auto;
    transform: translateY(20px) scale(.97);
    transition: transform .35s var(--ease);
}

.modal__panel--degree {
    display: grid;
    grid-template-columns: 320px 1fr;
    gap: 0;
    padding: 28px;
}
.modal__panel--category {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 125px;
    padding: 56px 64px;
    max-width: 1080px;
    background: rgba(255, 255, 255, 0.85);
    backdrop-filter: blur(22px) saturate(150%);
    -webkit-backdrop-filter: blur(22px) saturate(150%);
}
.modal__left {
    display: flex;
    flex-direction: column;
    min-height: 100%;
}

.modal__close {
    position: absolute;
    top: 16px;
    right: 18px;
    width: 32px;
    height: 32px;
    font-size: 37px;
    line-height: 1;
    color: var(--c-ink);
    border-radius: 50%;
    z-index: 2;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 300;
}
.modal__close:hover { background: rgba(0,0,0,0.06); }

/* Slider arrows for the category modal — flex siblings of the panel,
   so they sit naturally outside the panel without being clipped by it. */
#category-modal { gap: 24px; }
.modal__nav {
    flex: 0 0 auto;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.65);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border: 1px solid rgba(255, 255, 255, 0.85);
    box-shadow:
        0 0 0 1px rgba(255, 255, 255, 0.3),
        0 6px 18px -4px rgba(0, 0, 0, 0.18),
        inset 0 1px 0 rgba(255, 255, 255, 0.85);
    color: var(--c-ink);
    font-size: 30px;
    font-weight: 300;
    line-height: 1;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    transition: transform .25s var(--ease), background .25s var(--ease);
}
.modal__nav:hover {
    background: rgba(255, 255, 255, 0.85);
    transform: scale(1.05);
}

/* Pagination dots — only visible in mobile, swap-friendly indicator. */
.modal__pagination {
    display: none;
}
.modal__pagination__dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.25);
    transition: background .25s var(--ease), transform .25s var(--ease);
}
.modal__pagination__dot.is-active {
    background: var(--c-ink);
    transform: scale(1.25);
}

/* Swipe hint (mobile-only) — hand-drawn arrow + "swipe" text in Caveat. */
.modal__swipe-hint {
    display: none;
    position: absolute;
    bottom: 56px;
    left: 50%;
    transform: translateX(-50%);
    align-items: center;
    gap: 6px;
    color: var(--c-ink);
    opacity: 0.55;
    pointer-events: none;
    z-index: 5;
    animation: swipeHintBob 2.2s var(--ease) infinite;
}
.modal__swipe-hint__text {
    font-family: 'Caveat', cursive;
    font-size: 22px;
    font-weight: 600;
    line-height: 1;
    letter-spacing: 0.5px;
    transform: rotate(-4deg);
}
.modal__swipe-hint__arrow {
    width: 64px;
    height: auto;
    display: block;
    color: inherit;
}
@keyframes swipeHintBob {
    0%, 100% { transform: translateX(-50%) translateY(0); }
    50%      { transform: translateX(-46%) translateY(0); }
}

/* Fade transition for the swappable category content. */
.modal__panel--category .modal__left,
.modal__panel--category .modal__right {
    transition: opacity .26s var(--ease);
    will-change: opacity;
}

.modal__media { padding-right: 24px; }
.modal__image {
    width: 100%;
    aspect-ratio: 3 / 4;
    border-radius: 14px;
    background-size: cover;
    background-position: center;
    box-shadow: 0 14px 30px -18px rgba(0,0,0,0.4);
}

.modal__body {
    display: flex;
    flex-direction: column;
    align-items: start;
    justify-content: center;
    padding: 12px 8px;
    text-align: start;
}
.modal__heading {
    font-size: 29px;
    font-weight: 600;
    line-height: 1.2;
    letter-spacing: -3%;
    margin: 0 0 22px;
    text-align: center;
}
.modal__body p {
    font-size: 18px;
    line-height: 1.55;
    margin: 0 0 18px;
    color: var(--c-ink);
    max-width: 420px;
    text-align: start;
}
.modal__body p strong { color: var(--c-ink); font-weight: 600; }
.modal__body .pill--cta { 
    margin-top: 16px;     
    background: rgba(255, 255, 255, 1);
        font-size: 13px;
        letter-spacing: -3%;
        padding: 12px 50px;
line-height:1;    
}

.modal__body .pill--cta:hover {
    /* Same pressed-in effect as the global .pill--cta hover, with darker
       background since the modal CTA starts as fully opaque white. */
    background: rgba(255, 255, 255, 0.72);

    box-shadow:
        inset 0 3px 6px rgba(0, 0, 0, 0.18),
        inset 0 1px 2px rgba(0, 0, 0, 0.1),
        0 1px 2px rgba(0, 0, 0, 0.05);
}

.modal__tag {
    display: inline-block;
    align-self: flex-start;
    padding: 16px 27px;
    border-radius: 999px;
    border: 2px solid var(--c-ink);
    font-weight: 600;
    font-size: 31px;
    margin-bottom: 32px;
    letter-spacing: -1%;
line-height: 1;
}
.modal__lead {
    font-size: 24px;
    line-height: 1.45;
    margin: 0 0 10px;
    max-width: 100%;
    color: var(--c-ink);
    letter-spacing: -1%;
}
.modal__footer-line {
    margin-top: auto;
    padding-top: 32px;
    font-size: 20px;
    font-weight: 700;
    color: var(--c-ink);
    letter-spacing: -1%;
    line-height: 1.2;
}

/* Accordion — custom (not <details>) so we can animate open/close via grid rows. */
.modal__right {
    display: flex;
    flex-direction: column;
    gap: 0;
    /* Contain overflow during accordion transitions so the panel never grows. */
    overflow: hidden;
}
.accordion {
    border-bottom: 1px solid rgba(0,0,0,1);
    padding: 22px 0;
}
.accordion:first-child { padding-top: 6px; }

.accordion__summary {
    /* button reset */
    background: none;
    border: 0;
    padding: 0;
    width: 100%;
    text-align: left;
    cursor: pointer;
    color: inherit;
    font: inherit;

    display: flex;
    flex-direction: column;
    gap: 6px;

    /* room for the +/- indicator on the right */
    position: relative;
    padding-right: 32px;
}

/* +/- indicator — two crossed bars. When the accordion opens, the vertical
   bar rotates to horizontal and overlaps the horizontal bar, visually
   collapsing the "+" into a "−". */
.accordion__summary::before,
.accordion__summary::after {
    content: '';
    position: absolute;
    right: 4px;
    top: 10px;
    width: 12px;
    height: 2px;
    background: var(--c-ink);
    transition: transform .3s var(--ease);
    pointer-events: none;
}
.accordion__summary::before {
    /* horizontal bar — never moves */
    transform: translateY(-50%);
}
.accordion__summary::after {
    /* vertical bar — sits perpendicular when closed, collapses to 0° when open */
    transform: translateY(-50%) rotate(90deg);
}
.accordion[data-open="true"] .accordion__summary::after {
    transform: translateY(-50%) rotate(0deg);
}

/* Animated open/close: grid rows go from 0fr to 1fr. The inner content has
   min-height: 0 + overflow: hidden so it can collapse without clipping. */
.accordion__wrapper {
    display: grid;
    grid-template-rows: 0fr;
max-height: 0;
    transition: all .35s var(--ease);
}
.accordion[data-open="true"] .accordion__wrapper {
    grid-template-rows: 1fr;
max-height: 200px;
}
.accordion__wrapper > .accordion__content {
    min-height: 0;
    opacity: 0;
    transform: translateY(-4px);
    /* Closed state: invisible AND uninteractive (no clicks, no keyboard focus).
       The visibility flip is delayed by .35s so the fade-out plays out fully
       before the element is actually pulled out of the focus tree. */
    visibility: hidden;
    pointer-events: none;
    transition:
        opacity .22s var(--ease) 0s,
        transform .3s var(--ease) .01s,
        visibility 0s linear .35s;
}
.accordion[data-open="true"] .accordion__wrapper > .accordion__content {
    opacity: 1;
    transform: translateY(0);
    visibility: visible;
    pointer-events: auto;
    /* Open state: visibility flips immediately so the children fade in. The
       opacity duration is bumped up a touch and given a small delay so the
       SABER MAIS button drifts in gently after the wrapper starts expanding. */
    transition:
        opacity .3s var(--ease) .14s,
        transform .32s var(--ease) .1s,
        visibility 0s linear 0s;
}

.accordion__eyebrow {
    font-family: var(--font-mono);
    font-size: 13px;
    letter-spacing: -1%;
    color: var(--c-ink-soft);
    text-transform: uppercase;
    font-weight: 400;
}
.accordion__title {
    font-size: 17px;
    font-weight: 400;
    color: var(--c-ink);
    letter-spacing: -0.01em;
}
.accordion__content {
    padding-top: 16px;
    font-size: 14px;
    color: var(--c-ink-soft);
}
.accordion .pill--cta {
    background:rgb(249 249 239);
line-height: 1;
letter-spacing: -1%;
font-size: 13px;
    padding: 9px 38px;
}

/* LICENCIATURAS accordion — 3 clickable text links (PAR / Nutrição / FCT),
   each is its own external-link with a discrete ↗ glyph that shifts on hover. */
.licenciatura-link {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    padding: 10px 0;
    color: var(--c-ink);
    text-decoration: none;
    font-size: 14px;
    font-weight: 400;
    letter-spacing: -0.01em;
    line-height: 1.3;
    border-bottom: 1px solid rgba(0, 0, 0, 0.08);
    transition: color .2s var(--ease);
}
.licenciatura-link:last-child {
    border-bottom: none;
}
.licenciatura-link::after {
    content: "↗";
    font-size: 14px;
    color: var(--c-ink-soft);
    opacity: 0.65;
    transition: opacity .2s var(--ease), transform .2s var(--ease);
    flex-shrink: 0;
}
.licenciatura-link:hover {
    color: var(--c-ink);
}
.licenciatura-link:hover::after {
    opacity: 1;
    transform: translate(2px, -2px);
}
.careers li {
    font-size: 14px;
    line-height: 1.7;
    color: var(--c-ink-soft);
}
.careers li::before {
    content: "·  ";
    color: var(--c-ink);
}

/* ============================================================
   RESPONSIVE
   Two breakpoints:
     ≤ 880px  → tablet / large phone
     ≤ 540px  → small phone
   ============================================================ */

/* ---------- Tablet & below ---------- */
@media (max-width: 1200px) {
    .start__cards > .start-card,
    .start__cards > .start-card-wrap {
        flex: 1 1 0;
        min-width:240px;
    }

}
@media (max-width: 880px) {
    /* ----- Mobile-only animations -----
       Tap feedback: every interactive surface scales down briefly when the
       user touches it. Replaces the lack of :hover on touch devices and
       gives every tap a tactile reaction. */
    .bubble:active,
    .moment-card:active,
    .contact-card:active,
    .start-card:active,
    .pill--cta:active,
    .accordion__summary:active,
    .modal__close:active {
        transform: scale(0.97);
        transition: transform .12s ease-out;
    }
    /* Bubble pauses its float while pressed so the tap feels solid. */
    .bubble:active {
        animation-play-state: paused;
        transform: scale(0.95);
    }


    /* Parallax — moment-card images and timeline circles shift slightly
       slower than the page scroll, giving the photos a sense of depth. JS
       sets --parallax-y (~±8px) per element based on viewport position. */
    .moment-card__image,
    .timeline__circle {
        transform: translateY(var(--parallax-y, 0));
        transition: none;
        will-change: transform;
    }

    /* Letter-by-letter title reveal — each letter rises + fades in with
       its own delay. The whole title is force-shown (override snap-in) so
       only the letters animate. JS splits the textContent into spans and
       assigns --letter-delay per span (~25ms stagger). */
    .contact__title.snap,
    .story__title.snap,
    .cluster__intro.snap {
        opacity: 1;
        transform: none;
    }
    .contact__title .split-letter,
    .story__title .split-letter,
    .cluster__intro .split-letter {
        display: inline-block;
        opacity: 0;
        transform: translateY(10px);
        transition:
            opacity .45s var(--ease) var(--letter-delay, 0ms),
            transform .45s var(--ease) var(--letter-delay, 0ms);
        will-change: opacity, transform;
    }
    .contact__title.is-in .split-letter,
    .story__title.is-in .split-letter,
    .cluster__intro.is-in .split-letter {
        opacity: 1;
        transform: none;
    }

    /* Contact CTA breathing animation — slow scale + halo pulse to draw
       attention without movement that competes with content. Kicks in
       after the snap-in completes (delay = 600ms). */
    .contact-card.snap.is-in,
    .start-card.snap.is-in {
        animation: ctaBreathe 4.2s ease-in-out 600ms infinite;
    }
    /* Slight phase offset on the start-card so the two CTAs don't pulse in
       perfect sync — keeps the rhythm interesting when both are on screen. */
    .start-card.snap.is-in { animation-delay: 1.4s; }
    @keyframes ctaBreathe {
        0%, 100% {
            transform: scale(1);
            box-shadow:
                0 0 0 1px rgba(255, 255, 255, 0.25),
                inset 0 1px 0 rgba(255, 255, 255, 0.7),
                0 14px 28px -10px rgba(180, 140, 20, 0.25),
                0 30px 50px -20px rgba(180, 140, 20, 0.15);
        }
        50% {
            transform: scale(1.025);
            box-shadow:
                0 0 0 1px rgba(255, 255, 255, 0.35),
                inset 0 1px 0 rgba(255, 255, 255, 0.85),
                0 18px 38px -10px rgba(180, 140, 20, 0.4),
                0 42px 64px -22px rgba(180, 140, 20, 0.25);
        }
    }

    /* HERO — shorter on mobile so the logos at top, title block in the
       middle, and the connector line at the bottom all live closer
       together. Was 100vh — felt too sparse with content centered in a
       full viewport. 65vh keeps content in the visual mid-band but pulls
       everything tighter; min-height/max-height clamp the result on
       smaller / taller phones. */
    .hero {
        height: 65vh;
        min-height: 460px;
        max-height: 700px;
    }
    .hero__sticky {
        position: relative;
        height: 65vh;
        min-height: 460px;
        max-height: 700px;
    }
    /* Line was tuned for a 100vh sticky — slightly tighten the offsets so
       it stays within the shorter sticky on mobile. */
    .hero__line {
        top: calc(60% + 10px);
        height: 36%;
    }
    .hero__title-svg { width: clamp(240px, 70vw, 540px); }
    /* Mobile: drop the scroll-driven hero animation entirely. Replace with
       an opacity-only sequenced intro that auto-plays on page load, so the
       user doesn't need to scroll to "trigger" the hero. The line grows on
       its own, sequenced after the three text lines. */
    .hero__title {
        transform: none;
        opacity: 0;
        animation: heroFadeIn 600ms 100ms var(--ease) forwards;
    }
    .hero__subtitle {
        transform: none;
        opacity: 0;
        animation: heroFadeIn 500ms 700ms var(--ease) forwards;
    }
    .hero__tag {
        transform: none;
        opacity: 0;
        animation: heroFadeIn 500ms 1200ms var(--ease) forwards;
    }
    .hero__line {
        transform: translateX(-50%) scaleY(0);
        transform-origin: top center;
        animation: heroLineGrow 1300ms 1700ms var(--ease) forwards;
        top: calc(53% + 40px);
        height: calc(35%);
        width: 1px;
    }

    /* MANIFESTO */
    .manifesto { padding: 30px 20px 0; }
    .manifesto__lead { margin-bottom: 40px; }

    /* PILLARS */
    .pillars { padding: 70px 20px 60px; }
    .pillars__eyebrow { font-size: 18px; margin-bottom: 36px; }
    .pillars__pills { gap: 10px; }
    .pill { padding: 14px 28px; font-size: 16px; }

    /* MOMENTS — 2 columns at tablet */
    .moments { padding: 40px 20px var(--section-pad); }
    .moments__grid { grid-template-columns: repeat(2, 1fr); gap: 22px; max-width: 600px; }
    .moments__title { margin-bottom: 36px; }

    /* START */
    .start { padding: 60px 20px 0; gap: 28px; }
    .start-card { padding: 26px 40px; }
    .start-card__title { font-size: 20px; }

    /* STORY / TIMELINE — vertical: line on the left, balls centered on screen.
       Caption fades in only when the item approaches the viewport center. */
    .story { padding: 60px 20px; }
    .timeline {
        --tl-circle: 220px;
        --tl-dot: 12px;
        --tl-line-x: 16px;          /* line offset from the timeline's left edge */
        display: block;
        position: relative;
        max-width: none;
        margin: 0 auto;
        /* No padding-left: items must share the timeline's left edge so the
           dots (positioned absolute inside items) align with the line
           (positioned absolute inside the timeline). */
        padding: 32px 24px 32px 0;
        gap: 0;
        grid-template-columns: none;
    }

    /* Vertical line — grows downward as the user scrolls. The scaleY value is
       driven by --track-progress (0 → 1), updated by JS based on how far the
       viewport center has moved from the first ball to the last. */
    .timeline__track,
    .timeline__track.snap,
    .timeline__track.snap.is-in {
        display: block;
        position: absolute;
        left: var(--tl-line-x);
        top: calc(32px + var(--tl-circle) / 2);
        bottom: calc(32px + var(--tl-circle) / 2);
        width: 1.5px;
        height: auto;
        background: var(--c-line);
        transform: translateX(-50%) scaleY(var(--track-progress, 0));
        transform-origin: top center;
        transition: none;
    }

    /* Item: full-width column. Circle and caption stack centered horizontally,
       the dot is positioned absolutely on the line. */
    .timeline__item {
        display: flex;
        flex-direction: column;
        align-items: center;
        position: relative;
        margin-bottom: 48px;
        grid-template-columns: none;
        column-gap: 0;
    }
    .timeline__item:last-child { margin-bottom: 0; }

    /* Dot sits on the line, vertically aligned with the circle's center.
       Reveals only when the line passes through it (driven by --reveal). */
    .timeline__dot {
        display: block;
        position: absolute;
        left: var(--tl-line-x);
        top: calc(var(--tl-circle) / 2 - var(--tl-dot) / 2);
        transform: translateX(-50%);
        z-index: 2;
        grid-column: auto;
        grid-row: auto;
        margin-top: 0;
        justify-self: auto;
        opacity: var(--reveal, 0);
        transition: none;
    }

    /* Circle centered on the screen. Reveals as the line passes its position.
       Only opacity animates — no transform — so the circle's bounding box
       stays stable for the JS that measures track top/bottom. */
    .timeline__circle {
        width: var(--tl-circle);
        height: var(--tl-circle);
        grid-column: auto;
        grid-row: auto;
        opacity: var(--reveal, 0);
        transition: none;
    }


    /* Caption opacity is bound to a per-item scroll-driven custom property
       (--center-progress) updated by JS on scroll: 0 when the ball is far
       from the viewport center, 1 when centered. */
    .timeline__caption {
        margin-top: 16px;
        max-width: 320px;
        text-align: center;
        opacity: var(--center-progress, 0);
        transform: translateY(calc(12px * (1 - var(--center-progress, 0))));
        transition: none;
        pointer-events: none;
        grid-column: auto;
        grid-row: auto;
    }

    /* CLUSTER bubble rules moved to their own @media (max-width: 1100px) block
       below — at desktop widths between 881–1100px the original % positioning
       was making bubbles touch. The 1100px breakpoint covers small laptops
       too. Padding override stays here for the tablet range only. */
    .cluster { padding: 60px 20px; }

    /* MODALS — single column, image on top */
    .modal { padding: 16px; }
    .modal__panel {
        background: rgba(252, 248, 230, 0.55);
    }
    .modal__panel--degree { grid-template-columns: 1fr; padding: 20px; gap: 16px; }
    .modal__media { padding-right: 0; padding-bottom: 0; }
    .modal__image { aspect-ratio: 4 / 3; max-width: 360px; margin: 0 auto; }
    .modal__heading { font-size: 24px; margin-bottom: 16px; }
    .modal__body { padding: 4px 4px 8px; }
    .modal__body p { font-size: 14px; max-width: 100%; }

    .modal__panel--category { grid-template-columns: 1fr; padding: 28px 22px; gap: 22px; }
    .modal__tag { font-size: 14px; padding: 10px 22px; margin-bottom: 18px; }
    .modal__lead { font-size: 13px; max-width: 100%; }
    .modal__footer-line {         margin: 5px 0 15px    ;padding: 0; font-size: 16px; }

    /* Slider arrows: overlay the panel edges on tablet/mobile so they don't fall off-screen */
    #category-modal { gap: 0; }
    .modal__nav {
        position: absolute;
        top: 50%;
        transform: translateY(-50%);
        width: 42px;
        height: 42px;
        font-size: 24px;
        z-index: 6;
    }
    .modal__nav--prev { left: 10px; }
    .modal__nav--next { right: 10px; }
    .modal__nav:hover { transform: translateY(-50%) scale(1.04); }

    /* FOOTER */
    .footer {
        flex-direction: column;
        align-items: center;
        padding: 40px 20px 24px;
        gap: 28px;
    }
    .footer__group--right { gap: 24px; justify-content: center; }
    .footer__logo-img--eshte { height: 42px; }
    .footer__logo-img--nova  { height: 50px; }
    .footer__logo-img--small { height: 36px; }

    /* HEADER */
    .site-header { top: 20px; left: 20px; gap: 18px; }
    .site-header__logo--eshte { height: 38px; }
    .site-header__logo--nova  { height: 46px; }

    /* CONTACT CTA — tighter spacing on tablet */
    .contact { padding: 60px 20px 70px; }
    .contact__title { font-size: clamp(26px, 5vw, 38px); }
    .contact__intro { font-size: clamp(15px, 2.2vw, 18px); margin-bottom: 32px; }
    .contact-card { padding: 18px 42px; }
    .contact-card__email { font-size: clamp(18px, 3vw, 24px); }
}

/* ---------- Cluster: irregular layered layout up to 1100px ----------
   The default desktop cluster uses fixed pixel widths with % positioning,
   which makes neighbouring bubbles overlap on viewports below ~1100px.
   This block applies an irregular layout in vw (consistent unit for
   sizes AND positions) so the gaps stay predictable from phone to laptop.
   Phone (≤540px) overrides this with its own taller, vertical layout. */
@media (max-width: 1100px) {
    .cluster__bubbles {
        display: block;
        position: relative;
        width: 100%;
        max-width: none;
        height: 53vw;
        max-height: 580px;
        margin: 30px auto 0;
        gap: 0;
        padding: 0;
    }
    .cluster__bubbles .bubble {
        position: absolute !important;
        margin: 0 !important;
        transform: none;
    }
    /* Top row — 4 bubbles, ≥3vw gap horizontally between any pair */
    .bubble--1 { /* FOOD DESIGN — spans 2→22vw */
        width: 20vw !important; height: 20vw !important;
        max-width: 220px; max-height: 220px;
        top: 5vw !important; left: 2vw !important;
    }
    .bubble--3 { /* FOOD BUSINESS — biggest, spans 25→47vw */
        width: 22vw !important; height: 22vw !important;
        max-width: 245px; max-height: 245px;
        top: 0 !important; left: 25vw !important;
    }
    .bubble--4 { /* TECH FOOD — smaller, spans 50→68vw */
        width: 18vw !important; height: 18vw !important;
        max-width: 200px; max-height: 200px;
        top: 7vw !important; left: 50vw !important;
    }
    .bubble--8 { /* FOOD CULTURE — spans 71→92vw */
        width: 21vw !important; height: 21vw !important;
        max-width: 230px; max-height: 230px;
        top: 4vw !important; left: 71vw !important;
    }
    /* Bottom row — 3 bubbles, ≥3vw gap from top row vertically */
    .bubble--5 { /* FUTURE FOOD — spans 11→29vw */
        width: 18vw !important; height: 18vw !important;
        max-width: 200px; max-height: 200px;
        top: 30vw !important; left: 11vw !important;
    }
    .bubble--6 { /* FOOD & DATA — spans 33→53vw */
        width: 20vw !important; height: 20vw !important;
        max-width: 220px; max-height: 220px;
        top: 31vw !important; left: 33vw !important;
    }
    .bubble--7 { /* FOOD INNOVATION — biggest, spans 56→78vw */
        width: 22vw !important; height: 22vw !important;
        max-width: 245px; max-height: 245px;
        top: 28vw !important; left: 56vw !important;
    }
    .bubble:hover { transform: scale(1.04) !important; }
}

/* ---------- Small phone ---------- */
@media (max-width: 540px) {
    /* HERO — sizing inherited from the ≤880px rule (100vh, non-sticky).
       Only padding adjustment for tighter side margins. */
    .hero__sticky { padding: 0 16px; }
    .hero__title-svg {         width: clamp(200px, 67vw, 380px); }

    /* Click hint on phone — pull it closer to the card (less horizontal
       space available). Slightly smaller text + arrow too. */
    .start-card__hint {
        top: -68px;
        right: -8px;
    }
    .start-card__hint-text { font-size: 22px; }
    .start-card__hint-arrow { width: 50px; }
    /* Hero intro animation is inherited from the ≤880px media query
       (transform:none + heroFadeIn keyframe). No overrides needed here. */

    /* MANIFESTO */
    .manifesto__lead { font-size: clamp(18px, 5vw, 26px); margin-bottom: 32px; }
    .manifesto__line { font-size: clamp(20px, 6vw, 30px); }

    /* PILLARS — pills stack vertically */
    .pillars { padding: 60px 16px 40px; }
    .pillars__title { font-size: clamp(22px, 6.4vw, 28px); }
    .pillars__eyebrow { font-size: 14px; margin-bottom: 28px; }
    .pillars__pills { flex-direction: column; align-items: center; gap: 10px; }
    .pillars__pills .pill { width: 100%; max-width: 280px; justify-content: center; padding: 12px 22px; font-size: 15px; }

    /* MOMENTS — 1 column on small phones */
    .moments { padding: 15px 70px 60px; }
    .moments__grid { grid-template-columns: 1fr; max-width: 320px; gap: 18px; }
    .moments__title { font-size: clamp(12px, 2vw, 22px); margin-bottom: 28px; }
    .moment-card__overlay { padding: 24px 20px; gap: 14px; }
    .moment-card__overlay p { font-size: 15px; }
    .moment-card__pill { font-size: 13px; padding: 8px 16px; }
    .moments__intro {
        font-size: clamp(16px, 2.6vw, 38px);
        margin: 0px auto 20px;
    }
    .moment-card {
        box-shadow: 0 5px 2px 0px rgba(60, 40, 0, 0.30);
    }
    /* START */
    .start { padding: 40px 16px 0; gap: 24px; }
    .start__title { font-size: clamp(24px, 6vw, 38px); }
    .start-card { padding: 22px 32px; border-radius: 18px; }
    .start-card__eyebrow {
        font-size: 12px;
    }

.vline {
    width: 1px;

}
    /* STORY / TIMELINE */
    .story { padding: 50px 16px; }
    .story__title { font-size: clamp(22px, 6vw, 26px); }
    .story__intro { margin-bottom: 50px; font-size: 15px; }
    .timeline {
        --tl-circle: 180px;
        --tl-line-x: 14px;
        padding: 24px 0;
    }
    .timeline__item { margin-bottom: 36px; }
    .timeline__caption { font-size: 13px; max-width: 260px; }

    /* CLUSTER */
    .cluster { padding: 50px 16px;position: relative; }
    .cluster__intro { font-size: 20px; max-width: 290px; margin: auto; line-height: 1; }
    .cluster__title { font-size: clamp(20px, 6vw, 26px); }
    .cluster__cta { font-size: 14px; margin-bottom: 40px; margin: 10px 0 0 0; }
    .cluster__cta span {
        font-size: 15px;
        margin: 30px 0 0 0;
        font-weight: 600;
    }

    /* Subtle ripple inside every cluster bubble — a single white ring
       expanding outward from the centre, suggesting the bubble is
       tappable. Stays inside the bubble (overflow:hidden on .bubble
       clips any overshoot, which is fine — looks like the wave hits
       the edge). Per-bubble animation-delay staggers the pulses so
       they don't all fire in unison. */
    .bubble::after {
        content: '';
        position: absolute;
        top: 50%;
        left: 50%;
        width: 70%;
        height: 70%;
        border-radius: 50%;
        border: 2px solid rgba(255, 255, 255, 0.7);
        transform: translate(-50%, -50%) scale(0);
        opacity: 0;
        pointer-events: none;
        z-index: 3;
        animation: bubbleTapRipple 2.4s ease-out infinite;
    }
    .bubble--1::after { animation-delay: 0s;   }
    .bubble--3::after { animation-delay: 0.3s; }
    .bubble--4::after { animation-delay: 0.6s; }
    .bubble--8::after { animation-delay: 0.9s; }
    .bubble--5::after { animation-delay: 1.2s; }
    .bubble--6::after { animation-delay: 1.5s; }
    .bubble--7::after { animation-delay: 1.8s; }

    /* Once any bubble is tapped, fade ALL ripples out and stop the loop
       — the user has discovered the cluster is interactive, no longer
       needs the indicator. */
    .cluster__bubbles.is-tapped .bubble::after {
        animation: none;
        opacity: 0;
        transition: opacity .5s ease-out;
    }
    .cluster__arrow svg {
        width: 100%;
        height: auto;
        display: block;
    }
    /* Irregular, layered cluster matching the Figma phone reference. Bubbles
       have varying sizes and absolute positions so they overlap organically
       (not a gridded 2-col layout). */
    .cluster__bubbles {
        display: block !important;
        position: relative !important;
        width: 100% !important;
        max-width: none !important;
        height: calc(300vw * 0.5);
max-height: unset;
        margin: 60px auto 0 !important;
        gap: 0 !important;
        padding: 0;
    }
    .cluster__bubbles .bubble {
        position: absolute !important;
        margin: 0 !important;
    }
    .bubble--1 { /* FOOD DESIGN — top-left, large */
        width: 42vw !important; height: 42vw !important;
        top: 0 !important; left: 3vw !important;
    }
    .bubble--2 { /* FOOD & HEALTH — top-right, medium */
        width: 34vw !important; height: 34vw !important;
        top: 11vw !important;
        left: 52vw !important;
    }
    .bubble--5 { /* FUTURE FOOD — center, small */
        width: 32vw !important;
        height: 32vw !important;
        top: 41vw !important;
        left: 24vw !important;
    }
    .bubble--6 { /* FOOD & DATA — middle-right, large */
        width: 32vw !important;
        height: 32vw !important;
        top: 15vw !important;
        left: 49vw !important;
    }
    .bubble--3 { /* FOOD BUSINESS — middle-left, large */
        width: 40vw !important;
        height: 40vw !important;
        top: 70vw !important;
        left: 0vw !important;
    }
    .bubble--4 { /* TECH FOOD — middle-right, medium */
        width: 32vw !important;
        height: 32vw !important;
        top: 52vw !important;
        left: 58vw !important;
    }
    .bubble--7 { /* FOOD INNOVATION — bottom-left, large */
         width: 40vw !important;
        height: 40vw !important;
        top: 110vw !important;
        left: 14vw !important;
    }
    .bubble--8 { /* FOOD CULTURE — bottom-right, large */
        width: 32vw !important;
        height: 32vw !important;
        top: 86vw !important;
        left: 48vw !important;
    }
    /* Smaller label for the smallest bubble so it doesn't overflow */
    .bubble--5 .bubble__label { font-size: 11px; }
    .bubble__label {         font-size: 16px;
        font-weight: 600; }

    /* MODALS */
    .modal { padding: 12px; align-items: flex-start; padding-top: 5vh; }
    .modal__panel { border-radius: 22px; max-height: 92vh; }
    .modal__panel--degree { padding: 16px; gap: 12px; }
    .modal__image { aspect-ratio: 4 / 3; max-width: 100%; }
    .modal__heading { font-size: 22px; margin-bottom: 12px; }
    .modal__body { padding: 4px 0; }
    .modal__body p { font-size: 14px; line-height: 1.5; margin-bottom: 14px; }
    .modal__close { top: 10px; right: 12px; }

    /* CONTACT CTA — phone */
    .contact { padding: 0px 20px 0px; }
    .contact__eyebrow { font-size: 12px; margin-bottom: 14px; }
    .contact__title { font-size: clamp(24px, 7.5vw, 32px); margin-bottom: 16px; }
    .contact__intro { font-size: 15px; margin-bottom: 28px; }
    .contact-card { padding: 14px 28px; gap: 3px; }
    .contact-card__label { font-size: 12px; }
    .contact-card__email { font-size: 17px; }

    /* CATEGORY MODAL — fullscreen, no nav arrows, swipe-driven. */
    #category-modal { padding: 0; align-items: stretch; gap: 0; }
    .modal__panel--category {
        max-width: none;
        max-height: none;
        width: 100vw;
        height: 100vh !important;
        border-radius: 0;
        padding: 30px 22px 100px;
        /* Stack vertically — explicit single column + auto rows so children
           never share a row by accident. */
        display: flex;
        flex-direction: column;
        gap: 10px;
transform: unset;
    }
    .modal__panel--category .modal__left,
    .modal__panel--category .modal__right {
        width: 100%;
        flex: 0 0 auto;
    }
    .modal__panel--category .modal__right {
        height: auto !important;   /* override the JS-locked desktop height */
        overflow: visible;
        min-height: 0;
    }
    .modal__panel--category .modal__left { min-height: 0; }
    .modal__nav { display: none; }
    .modal__tag { font-size: 13px; padding: 9px 18px; }

    /* Bottom fade — solid-fading-to-transparent background that hides the
       scrolling panel text behind the pagination + swipe hint. Implemented as
       a pseudo-element on the modal so no extra HTML is needed. */
    #category-modal::after {
        content: '';
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        height: 60px;
        background: linear-gradient(to top,
            rgba(252, 248, 230, 0.98) 0%,
            rgba(252, 248, 230, 0.92) 40%,
            rgba(252, 248, 230, 0) 100%
        );
        backdrop-filter: blur(6px);
        -webkit-backdrop-filter: blur(6px);
        pointer-events: none;
        z-index: 3;
    }

    /* Pagination dots — fixed at bottom of fullscreen panel. */
    .modal__pagination {
        position: fixed;
        left: 0; right: 0;
        bottom: 28px;
        display: flex;
        justify-content: center;
        gap: 8px;
        z-index: 4;
        pointer-events: none;
    }

    /* Swipe hint — visible on mobile, sits above the pagination dots. */
    .modal__swipe-hint {
        display: flex;
        position: fixed;
        bottom: 23px;
        right: 0px;
        left: unset;
        flex-direction: column;
        gap: 0;
    }


    .accordion__title {
        font-size: 14px;
    }

    /* FOOTER */
    .footer { padding: 32px 16px 20px; gap: 22px; }
    .footer__group { gap: 20px; }
    .footer__logo-img--eshte { height: 36px; }
    .footer__logo-img--nova  { height: 44px; }
    .footer__logo-img--small { height: 30px; }

    /* HEADER */
    .site-header { top: 10px; left: 10px; gap: 0;}
    .site-header__logo--nova  { height: 86px;}
    .site-header__logo--eshte {
        height: 60px;
    }
}

/* ---------- Mobile hero intro keyframes ----------
   Used only inside the ≤880px media query above. Title → subtitle → tag
   fade in sequentially, then the hero connector line grows. */
@keyframes heroFadeIn {
    to { opacity: 1; }
}
@keyframes heroLineGrow {
    to { transform: translateX(-50%) scaleY(1); }
}

/* ---------- Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
    .reveal, .vline, .timeline__item, .timeline__track, .snap {
        transition: none !important;
        opacity: 1 !important;
        transform: none !important;
    }
    /* Mobile hero intro: skip the fade sequence entirely. */
    .hero__title, .hero__subtitle, .hero__tag, .hero__line {
        animation: none !important;
        opacity: 1 !important;
    }
    .hero__line {
        transform: translateX(-50%) scaleY(1) !important;
    }
}
