/* Google Fonts are loaded via <link> tags in <head> (preconnect + stylesheet),
   not @import here — an @import inside a stylesheet forces the browser to
   fetch and parse this whole file first before it even discovers the font
   stylesheet, adding a serial round-trip before fonts start downloading.
   <link> tags in the HTML are discovered immediately by the preload scanner,
   in parallel with everything else. See index.html / privacy.html <head>. */

:root{

    --yellow:#FBB320;
    --yellow-soft:#FFF3D6;
    --orange:#F5941F;
    --navy:#14324D;
    --navy-deep:#0E2438;
    --cream:#FFFBF3;
    --ink:#14324D;
    --ink-soft:#5F6B75;

    --container:1120px;
    --radius-lg:28px;
    --radius-md:20px;

    --shadow-soft:0 20px 60px rgba(20,50,77,.10);
    --shadow-strong:0 30px 80px rgba(20,50,77,.18);

}

*{
    margin:0;
    padding:0;
    box-sizing:border-box;
}

html{
    scroll-behavior:smooth;
}

/* Scroll-jacked "step" sections and their snap-to-place behaviour are a
   desktop-only affair — on touch/mobile they fight the browser's own
   momentum scrolling, so those sections fall back to a simple auto-cycling
   carousel instead (see the mobile rules further down + script.js). */
@media (min-width:961px){

    html{
        scroll-snap-type:y proximity;
    }

    .hero{
        scroll-snap-align:start;
    }

}

body{

    font-family:'Inter',sans-serif;
    color:var(--ink);
    background:#ffffff;
    overflow-x:hidden;
    -webkit-font-smoothing:antialiased;

}

/* ---------- CUSTOM CURSOR ---------- */
/* Native CSS cursor can't play a Lottie animation, so instead we hide the
   system cursor and follow the pointer with an animated element. The
   cursor:none rule only kicks in once the animation has actually loaded
   (html.custom-cursor-ready), so nobody ends up with no cursor at all if
   the animation fails to load for any reason. */

.cursor-lottie{

    position:fixed;
    top:0;
    left:0;

    width:44px;
    height:44px;

    pointer-events:none;
    z-index:99999;

    transform:translate3d(-50%,-50%,0);

    opacity:0;

    transition:opacity .25s ease;

}

.cursor-lottie.active{

    opacity:1;

}

@media (hover:hover) and (pointer:fine){

    html.custom-cursor-ready,
    html.custom-cursor-ready body,
    html.custom-cursor-ready *{

        cursor:none !important;

    }

}

/* ---------- GRAIN ---------- */

.grain{

    position:fixed;
    inset:0;
    z-index:9999;

    opacity:.035;
    mix-blend-mode:overlay;

    pointer-events:none;

    background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");

}

/* ---------- PRELOADER ---------- */
/* Full-screen splash shown until the hero background image has loaded (see
   script.js — it also enforces a minimum display time so the Lottie loop
   never gets cut off mid-animation). Sits above .grain (9999) so it fully
   masks the page, but below the custom cursor (99999) so the animated
   cursor still shows on top of it, matching the site's z-index scale. */

.preloader{

    position:fixed;
    inset:0;
    z-index:20000;

    display:flex;
    align-items:center;
    justify-content:center;

    background:var(--navy);

    transition:opacity .5s ease, visibility .5s ease;

}

.preloader.is-hidden{

    opacity:0;
    visibility:hidden;
    pointer-events:none;

}

.preloader-anim{

    width:400px;
    height:400px;

}

@media (max-width:640px){

    .preloader-anim{

        width:280px;
        height:280px;

    }

}

/* Locks scroll while the preloader is up — set as a class on <body> in the
   raw HTML (not added via JS) so scroll is blocked from the very first
   paint, not just once script.js runs. Removed by script.js once ready. */
body.is-preloading{

    overflow:hidden;

}

img{
    max-width:100%;
    display:block;
}

/* ---------- SCROLLBAR ---------- */

html{

    scrollbar-width:thin;
    scrollbar-color:rgba(20,50,77,.25) transparent;

}

::-webkit-scrollbar{

    width:6px;
    height:6px;

}

::-webkit-scrollbar-track{

    background:transparent;

}

::-webkit-scrollbar-thumb{

    background-color:rgba(20,50,77,.25);
    border-radius:999px;

}

::-webkit-scrollbar-thumb:hover{

    background-color:rgba(20,50,77,.45);

}

a{
    color:inherit;
}

.eyebrow{

    text-transform:uppercase;
    letter-spacing:.14em;
    font-size:.78rem;
    font-weight:700;
    color:var(--orange);
    margin-bottom:14px;

}

/* ---------- HERO ---------- */

.hero{

    position:relative;
    overflow:hidden;

    padding:96px 24px 110px;

    text-align:center;

}

.hero::before{

    content:"";

    position:absolute;
    inset:0;

    background-image:url("assets/background-web.png");
    background-size:cover;
    background-position:center;
    background-repeat:no-repeat;

    animation:heroBreathe 12s ease-in-out infinite;
    will-change:transform;

    z-index:0;

}

@keyframes heroBreathe{

    0%, 100%{ transform:scale(1.2); }
    50%{ transform:scale(1); }

}

.hero-content-wrap{

    position:relative;
    z-index:1;

    max-width:640px;
    margin:0 auto;

}

.hero-content{

    position:relative;

    transition:opacity .65s ease;

}

.hero-content-alt{

    position:absolute;
    inset:0;

    display:flex;
    align-items:center;
    justify-content:center;

    opacity:0;
    pointer-events:none;

    transition:opacity .65s ease;

}

.hero-alt-title{

    font-size:2.6rem;
    font-weight:800;
    line-height:1.15;
    color:var(--navy);
    letter-spacing:-.02em;

}

/* Mobile only — 30% smaller than the desktop size (2.6rem) */
@media (max-width:960px){

    .hero-alt-title{

        font-size:1.82rem;

    }

}

.hero-wave{

    position:absolute;
    left:0;
    right:0;
    bottom:-1px;

    line-height:0;
    z-index:2;

    pointer-events:none;

}

.hero-wave svg{

    width:100%;
    height:70px;
    display:block;

}

@media (max-width:640px){

    .hero-wave svg{

        height:40px;

    }

}

h1{

    margin-bottom:22px;

}

.brand-logo{

    height:288px;
    width:auto;

    margin:0 auto;

    transition:transform .3s ease;

}

.brand-logo:hover{

    animation:logoPulse 1.1s ease-in-out infinite;

}

@keyframes logoPulse{

    0%, 100%{ transform:scale(1); }
    50%{ transform:scale(1.07); }

}

.tagline{

    font-family:'Quicksand',sans-serif;
    font-size:1.41rem;
    font-weight:700;
    color:#01505A;

    margin-bottom:16px;

}

.description{

    max-width:460px;
    margin:0 auto 34px;

    font-size:1.05rem;
    line-height:1.75;
    color:rgba(20,50,77,.72);

}

.store-badges{

    display:flex;
    align-items:center;
    justify-content:center;
    gap:16px;

    margin-bottom:80px;

}

.store-badge{

    display:inline-block;

    transition:transform .25s ease, filter .25s ease;

}

.store-badge img{

    height:48px;
    width:auto;

}

.store-badge:hover{

    transform:translateY(-2px);

}

/* ---------- SHOWCASE ---------- */

.showcase{

    padding:40px 24px 100px;

    text-align:center;

    background:#ffffff;

}

.showcase .eyebrow{

    text-align:center;
    font-size:1.87rem;
    letter-spacing:.04em;
    margin-bottom:24px;

}

.showcase-grid{

    max-width:var(--container);
    margin:36px auto 0;

    display:flex;
    align-items:center;
    justify-content:center;

    flex-wrap:nowrap;

}

.showcase-card{

    width:286px;
    border-radius:var(--radius-md);
    box-shadow:var(--shadow-soft);

    cursor:zoom-in;

    opacity:0;

    margin:0 -22px;

    transition:transform .6s cubic-bezier(.25,.9,.35,1), box-shadow .35s ease, opacity .6s ease;

}

.card-a{ transform:rotate(-4deg) scale(.7); z-index:1; }
.card-b{ transform:rotate(2deg) translateY(-14px) scale(.7); z-index:2; }
.card-c{ transform:rotate(-2deg) scale(.7); z-index:3; }
.card-d{ transform:rotate(3deg) translateY(-10px) scale(.7); z-index:2; }
.card-e{ transform:rotate(-3deg) scale(.7); z-index:1; }

.showcase-grid.in-view .card-a{ opacity:1; transform:rotate(-4deg) scale(1); transition-delay:0s; }
.showcase-grid.in-view .card-b{ opacity:1; transform:rotate(2deg) translateY(-14px) scale(1); transition-delay:.15s; }
.showcase-grid.in-view .card-c{ opacity:1; transform:rotate(-2deg) scale(1); transition-delay:.3s; }
.showcase-grid.in-view .card-d{ opacity:1; transform:rotate(3deg) translateY(-10px) scale(1); transition-delay:.45s; }
.showcase-grid.in-view .card-e{ opacity:1; transform:rotate(-3deg) scale(1); transition-delay:.6s; }

.showcase-card:hover,
.showcase-grid.in-view .card-a:hover,
.showcase-grid.in-view .card-b:hover,
.showcase-grid.in-view .card-c:hover,
.showcase-grid.in-view .card-d:hover,
.showcase-grid.in-view .card-e:hover{

    transform:rotate(0) translateY(-8px) scale(1.03);
    box-shadow:var(--shadow-strong);
    transition-delay:0s;

}

/* ---------- CARDS STACK ---------- */
/* Mobile: a simple auto-playing carousel — only the "current" card shows,
   tap or swipe right to jump ahead yourself.
   Desktop (961px+): full-screen pinned scrollytelling, current card slides
   away on scroll to reveal the next one stacked underneath. */

.cards-stack{

    position:relative;

    padding:50px 24px 70px;

    background:#ffffff;
    text-align:center;

}

.cards-stack-sticky{

    position:relative;

    max-width:380px;
    margin:0 auto;

    aspect-ratio:3 / 4;

    border-radius:var(--radius-lg);
    box-shadow:var(--shadow-soft);
    overflow:hidden;

    cursor:pointer;

}

.stack-card{

    position:absolute;
    inset:0;

    width:100%;
    height:100%;

    opacity:0;

    transition:opacity .6s ease;

}

.stack-card.current{

    opacity:1;

}

.stack-card picture,
.stack-card img{

    width:100%;
    height:100%;

    object-fit:cover;
    display:block;

}

/* Mobile: no card styling at all — each slide is just a full-width image
   filling the section, no rounded corners, no shadow, no card frame. */
@media (max-width:960px){

    .cards-stack{

        padding:0;

    }

    .cards-stack-sticky{

        max-width:none;
        margin:0;

        aspect-ratio:4 / 5;

        border-radius:0;
        box-shadow:none;

    }

}

@media (min-width:961px){

    .cards-stack{

        height:100vh;
        padding:0;

        background:#ffffff;

        scroll-snap-align:start;

    }

    .cards-stack-sticky{

        max-width:none;

        height:100%;

        aspect-ratio:auto;
        border-radius:0;
        box-shadow:none;

        cursor:default;

    }

    .stack-card{

        transform:translateX(0);
        opacity:1;

        transition:transform 1s cubic-bezier(.4,0,.2,1), opacity .65s ease;

    }

    /* These screenshots don't have enough native resolution to be
       force-cropped/upscaled to fill the full viewport height without
       looking soft. Show them at full width and their own natural
       height instead — no crop, no upscale beyond their real size.
       Anchored to the top, so if a screenshot is shorter than the
       viewport, the leftover space just sits empty below it. */
    .stack-card picture,
    .stack-card img{

        width:100%;
        height:auto;

    }

    .stack-card.exited{

        transform:translateX(100%);
        opacity:0;

    }

    .stack-card[data-index="0"]{ z-index:3; }
    .stack-card[data-index="1"]{ z-index:2; }
    .stack-card[data-index="2"]{ z-index:1; }

}

/* ---------- STORY ---------- */

.story{

    background:var(--cream);

    padding:90px 24px;

    display:grid;
    grid-template-columns:1fr 1fr;
    align-items:center;
    gap:60px;

    max-width:var(--container);
    margin:0 auto;

    border-radius:var(--radius-lg);

}

.story + .story{

    margin-top:32px;

}

.story-reverse .story-visual img{

    width:40%;
    margin:0 auto;

}

.story-reverse .story-text{

    padding-left:14%;

}

.story-visual img{

    width:100%;
    height:auto;

    animation:floaty 4.5s ease-in-out infinite;

}

@keyframes floaty{

    0%, 100%{ transform:translateY(0); }
    50%{ transform:translateY(-14px); }

}

.story-text{

    max-width:420px;

}

.story-text h2{

    font-size:2rem;
    font-weight:800;
    color:var(--navy);
    line-height:1.2;

    margin-bottom:18px;

}

.story-text p{

    font-size:1.05rem;
    line-height:1.75;
    color:var(--ink-soft);

}

/* ---------- MAP STORY ---------- */
/* Mobile: a normal section, image with the 3 bubbles auto-cycling on top.
   Desktop (961px+): full-screen pinned scrollytelling, stepped by scroll. */

.map-story{

    position:relative;

    padding:70px 24px;

    text-align:center;

    background:#ffffff;

}

.map-story-sticky{

    position:relative;

    max-width:640px;
    margin:0 auto;

}

.map-story-sticky picture,
.map-story-img{

    width:100%;
    height:auto;
    display:block;

    border-radius:var(--radius-lg);
    box-shadow:var(--shadow-soft);

}

.speech-bubble{

    display:flex;

    position:absolute;

    align-items:flex-start;
    gap:10px;

    max-width:230px;

    background:#ffffff;

    padding:12px 16px;
    border-radius:16px;

    box-shadow:0 12px 34px rgba(20,50,77,.22);

    text-align:left;

    opacity:0;
    transform:translateY(8px);

    transition:opacity .5s ease, transform .5s ease;

}

.speech-bubble.visible{

    opacity:1;
    transform:translateY(0);

}

/* Mobile: skip per-bubble positioning (data-x/data-y, set on desktop only
   via JS) — there's too little room to place each one differently, so
   every bubble shares this one fixed spot above the map. */
@media (max-width:960px){

    .speech-bubble{

        left:50% !important;
        top:-14px !important;

        transform:translate(-50%, 8px);

    }

    .speech-bubble.visible{

        transform:translate(-50%, 0);

    }

}

.bubble-avatar{

    flex:0 0 auto;

    width:34px;
    height:34px;

    border-radius:50%;

    display:flex;
    align-items:center;
    justify-content:center;

    font-family:'Quicksand',sans-serif;
    font-weight:700;
    font-size:.85rem;
    color:#ffffff;

}

.bubble-name{

    font-family:'Quicksand',sans-serif;
    font-weight:700;
    font-size:.82rem;
    color:var(--navy);

    margin-bottom:2px;

}

.bubble-text{

    font-size:.88rem;
    font-weight:600;
    line-height:1.45;
    color:var(--ink-soft);

}

.speech-bubble::after{

    content:"";

    position:absolute;
    bottom:-9px;
    left:28px;

    width:0;
    height:0;

    border:9px solid transparent;
    border-top-color:#ffffff;
    border-bottom:0;

}

@media (min-width:961px){

    .map-story{

        height:100vh;
        padding:0;

        scroll-snap-align:start;
        scroll-snap-stop:always;

    }

    .map-story-sticky{

        max-width:none;
        margin:0;

        height:100%;

        overflow:hidden;

        display:flex;
        align-items:center;
        justify-content:center;

    }

    .map-story-sticky picture,
    .map-story-img{

        width:100%;
        height:100%;
        object-fit:contain;

        border-radius:0;
        box-shadow:none;

    }

    .speech-bubble{

        max-width:260px;
        transition:opacity .65s ease, transform .65s ease;

    }

}

/* ---------- SUPPORT ---------- */

.support{

    max-width:560px;
    margin:0 auto;

    padding:100px 24px;

    text-align:center;

}

.support h2{

    font-size:1.7rem;
    font-weight:800;
    margin-bottom:12px;

}

.support p{

    color:var(--ink-soft);
    margin-bottom:18px;
    line-height:1.6;

}

.support a{

    color:var(--orange);
    text-decoration:none;
    font-weight:700;
    font-size:1.08rem;

}

.support a:hover{

    text-decoration:underline;

}

/* ---------- LANGUAGE SWITCH ---------- */

.lang-switch{

    position:fixed;
    top:24px;
    right:28px;
    z-index:70;

    display:flex;
    align-items:center;
    gap:2px;

    background:rgba(255,255,255,.85);
    backdrop-filter:blur(6px);
    -webkit-backdrop-filter:blur(6px);

    border:1px solid rgba(20,50,77,.08);
    border-radius:999px;
    padding:4px;

    box-shadow:var(--shadow-soft);

    /* Steps back while the page is moving and returns once it settles
       (class toggled in script.js). The two directions are deliberately
       not symmetric: leaving is brisk, coming back is slower and lands
       with a hint of give, which reads as weight rather than as a bounce.
       Scaled from the top-right corner so it tucks towards the edge of the
       screen instead of drifting inwards. */
    transform-origin:top right;
    transform:scale(1);

    transition:transform .45s cubic-bezier(.34,1.4,.5,1), opacity .45s ease;

}

.lang-switch.is-scrolling{

    transform:scale(.82);
    opacity:.85;

    transition:transform .6s ease-out, opacity .6s ease-out;

}

@media (prefers-reduced-motion:reduce){

    .lang-switch,
    .lang-switch.is-scrolling{

        transform:scale(1);
        opacity:1;

        transition:none;

    }

}

.lang-btn{

    appearance:none;
    border:none;
    background:transparent;
    cursor:pointer;

    font-family:'Quicksand',sans-serif;
    font-weight:700;
    font-size:.74rem;
    letter-spacing:.03em;
    color:rgba(20,50,77,.5);

    padding:6px 13px;
    border-radius:999px;

    transition:background .25s ease, color .25s ease;

}

.lang-btn:hover{

    color:var(--navy);

}

.lang-btn.active{

    background:var(--orange);
    color:#ffffff;

}

@media (max-width:640px){

    .lang-switch{

        top:14px;
        right:14px;

    }

    .lang-btn{

        font-size:.68rem;
        padding:5px 11px;

    }

}

/* ---------- DOT NAV ---------- */

.dot-nav{

    position:fixed;
    right:28px;
    top:50%;
    transform:translateY(-50%);
    z-index:60;

    display:flex;
    flex-direction:column;
    align-items:center;
    gap:18px;

}

.dot-nav-track{

    position:absolute;
    top:10px;
    bottom:10px;
    left:50%;
    transform:translateX(-50%);

    width:2px;

    background-image:repeating-linear-gradient(
        to bottom,
        rgba(20,50,77,.3) 0,
        rgba(20,50,77,.3) 3px,
        transparent 3px,
        transparent 9px
    );

    z-index:0;

}

.dot-nav-progress{

    position:absolute;
    top:0;
    left:0;
    width:100%;
    height:0%;

    background:var(--orange);

    /* arrives with a small snap rather than easing flatly into place */
    transition:height .45s cubic-bezier(.2,.9,.25,1.05);

}

/* Short bright segment that runs down the track to the dot just reached.
   Created from script.js, so the markup stays clean. */
.dot-nav-spark{

    position:absolute;
    left:50%;
    top:0;

    width:6px;
    height:18px;
    margin-left:-3px;
    margin-top:-9px;

    border-radius:3px;

    background:linear-gradient(
        to bottom,
        rgba(251,179,32,0) 0%,
        rgba(255,214,130,.95) 45%,
        rgba(251,179,32,0) 100%
    );

    opacity:0;
    pointer-events:none;

    z-index:2;

}

.dot-nav .dot{

    position:relative;
    z-index:1;

    width:20px;
    height:20px;

    display:flex;
    align-items:center;
    justify-content:center;

}

.dot-nav .dot span{

    display:block;

    width:10px;
    height:10px;

    border-radius:50%;
    background:rgba(20,50,77,.2);

    transition:background .3s ease, transform .3s ease, width .3s ease, height .3s ease, border-radius .3s ease;

}

.dot-nav .dot:hover span{

    background:rgba(20,50,77,.45);
    transform:scale(1.2);

}

.dot-nav .dot.visited span{

    background:var(--orange);

}

.dot-nav .dot.active span{

    width:20px;
    height:20px;

    border-radius:0;
    background:url("assets/moral-compass.png") center / contain no-repeat;

    transform:none;

}

.dot-nav .dot::after{

    content:attr(data-label);

    position:absolute;
    right:22px;
    top:50%;
    transform:translateY(-50%);

    white-space:nowrap;

    background:var(--navy-deep);
    color:#fff;

    font-size:.72rem;
    font-weight:600;

    padding:6px 12px;
    border-radius:8px;

    opacity:0;
    visibility:hidden;

    transition:opacity .2s ease;

    pointer-events:none;

}

.dot-nav .dot:hover::after{

    opacity:1;
    visibility:visible;

}

@media (max-width:960px){

    .dot-nav{

        right:14px;
        gap:14px;

    }

    .dot-nav .dot span{

        width:8px;
        height:8px;

    }

    .dot-nav .dot.active span{

        width:16px;
        height:16px;

    }

    /* Tooltips rely on :hover, which sticks after a tap on touch
       devices — hide them below desktop and rely on the dots alone */
    .dot-nav .dot::after{

        display:none;

    }

}

@media (max-width:640px){

    .dot-nav{

        right:10px;
        gap:12px;

    }

}

/* ---------- LIGHTBOX ---------- */

.lightbox{

    position:fixed;
    inset:0;
    z-index:999;

    display:flex;
    align-items:center;
    justify-content:center;

    padding:32px;

    background:rgba(14,36,56,.92);

    opacity:0;
    visibility:hidden;

    cursor:zoom-out;

    transition:opacity .3s ease, visibility .3s ease;

}

.lightbox.active{

    opacity:1;
    visibility:visible;

}

.lightbox-img{

    max-width:min(92vw, 900px);
    max-height:90vh;
    width:auto;

    border-radius:16px;
    box-shadow:0 30px 90px rgba(0,0,0,.45);

    transform:scale(.9);
    transition:transform .3s ease;

}

.lightbox.active .lightbox-img{

    transform:scale(1);

}

/* ---------- CAT MASCOT ---------- */
/* A little surprise: peeks in from the left edge once the user scrolls
   past the full-screen card-stack section, stays ~8s, then fades away
   (see script.js). Now shown on both desktop and mobile — same
   center-left position on both, only the size (and the matching
   margin-left) changes at the 960px breakpoint.

   DESKTOP RULE BELOW — confirmed perfect as-is, do not touch (Roman,
   19/07/2026): width 150px, margin-left:-18px.

   The source GIF is 144px wide; the ledge the cat is gripping sits about
   17px into the frame (measured), with a faint rendering seam right at
   its own left border before that. At the desktop display width (150px,
   factor ~1.04x) that scales to ~18px — margin-left:-18px shifts the
   frame so the ledge lines up with the real viewport edge and pushes the
   seam off-screen. The mobile override further down re-derives the same
   ratio at a smaller size.

   BUG FIX (31/07/2026): the gif now loads lazily (JS sets "src" from
   "data-src" only when the reveal triggers — see script.js), instead of
   being present in the HTML from the start. Before this element had a
   real image loaded, it had no intrinsic size, so "height:auto" briefly
   resolved to ~0 — then jumped to its real ~256px-tall box the instant the
   gif's dimensions became known. Because centering here is done with
   "transform:translateY(-50%)", which is computed off the element's OWN
   height, that box-size jump visibly shifted the cat on screen (reported
   as a mobile-only "jump" while scrolling — mobile is where the reveal
   more often lands mid-load on a slower connection). aspect-ratio reserves
   the correct height from the very first paint, before the image data
   ever arrives, so there is nothing left to snap into place later. */
.cat-peek{

    position:fixed;
    left:0;

    /* "50%" of a fixed element resolves against the viewport, and on mobile
       the viewport itself grows and shrinks as the browser's address bar
       collapses and reappears during scrolling — so the cat kept drifting
       up and down instead of sitting still. "svh" is the *small* viewport
       height: a value fixed at the address-bar-visible size that never
       changes mid-scroll, which pins the cat in place. The percentage is
       kept first as a fallback for browsers without svh. */
    top:50%;
    top:50svh;

    width:150px;
    height:auto;
    aspect-ratio:144/256;

    margin-left:-18px;

    z-index:40;

    opacity:0;
    pointer-events:none;

    transform:translateY(-50%) translateX(-24px);

    transition:opacity .9s ease, transform .9s cubic-bezier(.22,1,.36,1);

}

.cat-peek.is-visible{

    opacity:1;
    transform:translateY(-50%) translateX(0);

}

/* Mobile: same center-left spot, just smaller — 90px (factor ~0.625x of
   the 144px source), so the same ledge offset scales to margin-left:-11px
   (17 * 0.625 ≈ 11) to keep the paw right on the real screen edge.
   (Tried 180px on 19/07/2026 — reverted: the 144px-wide source gets too
   grainy/pixelated scaled up that far on mobile.) */
@media (max-width:960px){

    .cat-peek{

        width:90px;
        margin-left:-11px;

    }

}

/* ---------- FOOTER ---------- */

footer{

    background:var(--navy-deep);
    color:rgba(255,255,255,.7);

    text-align:center;

    padding:48px 24px;

}

.footer-logo{

    height:28px;
    width:auto;

    margin:0 auto 14px;

    opacity:.95;

}

footer p{

    font-size:.9rem;
    font-weight:500;

}

.footer-links{

    display:flex;
    align-items:center;
    justify-content:center;
    flex-wrap:wrap;
    gap:20px;

    margin-top:16px;

}

.footer-links a{

    font-size:.85rem;
    font-weight:600;
    color:rgba(255,255,255,.7);
    text-decoration:none;

    transition:color .2s ease;

}

.footer-links a:hover{

    color:#ffffff;

}

/* ---------- PRIVACY PAGE ---------- */

/* Full-page fixed backdrop. Being position:fixed it never scrolls, which
   is what creates the parallax read against the text scrolling over it
   (see script.js). NOTE: a positioned element (even with no z-index set)
   always paints above static in-flow content, regardless of DOM order —
   z-index:-1 is required here so it actually sits behind <main>/<footer>
   instead of covering them. */
.privacy-bg{

    position:fixed;
    inset:0;
    z-index:-1;

    background-image:url("assets/background-web.png");
    background-size:cover;
    background-position:center;
    background-repeat:no-repeat;

    animation:heroBreathe 20s ease-in-out infinite;
    will-change:transform;

}

@media (prefers-reduced-motion:reduce){

    .privacy-bg{
        animation:none;
    }

}

.privacy-hero{

    padding:100px 24px 52px;

    text-align:center;

}

.privacy-hero-content{

    max-width:640px;
    margin:0 auto;

}

.privacy-logo{

    height:72px;
    width:auto;

    margin:0 auto 24px;

}

.privacy-hero h1{

    font-size:2.3rem;
    font-weight:800;
    color:var(--navy);
    letter-spacing:-.02em;

    margin-bottom:10px;

    text-shadow:0 2px 28px rgba(255,255,255,.4);

}

.privacy-version{

    font-size:.85rem;
    font-weight:600;
    color:rgba(20,50,77,.72);

}

/* No card, no background box — the text floats directly over the fixed
   image. Legibility comes from full-opacity ink + a soft white glow
   (text-shadow) instead of an opaque panel. */

.policy-wrap{

    padding:8px 24px 160px;

}

.policy{

    max-width:660px;
    margin:0 auto;

}

.policy .back-link{

    display:inline-block;

    margin-bottom:40px;

    font-size:.9rem;
    font-weight:700;
    color:#01505A;
    text-decoration:none;

    text-shadow:0 1px 1px rgba(255,255,255,.7), 0 0 18px rgba(255,255,255,.45);

}

.policy .back-link:hover{

    text-decoration:underline;

}

/* Each h2 + its paragraphs/list is one "flying" block, animated
   individually as it enters the viewport (see script.js). Resting state
   (no-JS fallback) is fully visible, static — the fly-in is a progressive
   enhancement, never a requirement to read the text. */
.policy-block{

    margin-bottom:40px;

}

.policy-block:last-child{

    margin-bottom:0;

}

.policy h2{

    font-size:1.3rem;
    font-weight:800;
    color:var(--navy);
    letter-spacing:-.01em;

    margin-bottom:14px;

    text-shadow:0 1px 2px rgba(255,255,255,.8), 0 0 24px rgba(255,255,255,.55);

}

.policy p{

    font-size:1.03rem;
    line-height:1.8;
    color:var(--navy);

    margin-bottom:14px;

    text-shadow:0 1px 1px rgba(255,255,255,.65), 0 0 16px rgba(255,255,255,.4);

}

.policy ul{

    margin:0 0 14px 20px;

    color:var(--navy);
    line-height:1.8;

}

.policy li{

    margin-bottom:8px;

    text-shadow:0 1px 1px rgba(255,255,255,.65), 0 0 16px rgba(255,255,255,.4);

}

.policy a{

    color:#01505A;
    font-weight:700;
    text-decoration:underline;

}

/* ---------- RESPONSIVE ---------- */

@media (max-width:860px){

    .story{

        grid-template-columns:1fr;
        text-align:center;
        gap:36px;
        padding:64px 24px;
        border-radius:0;

    }

    .story-text{

        max-width:460px;
        margin:0 auto;

    }

    .story-reverse .story-text{

        padding-left:0;

    }

    .story-reverse .story-visual{

        order:-1;

    }

}

@media (max-width:640px){

    .hero{

        padding:64px 18px 72px;

    }

    .brand-logo{

        height:216px;

    }

    .store-badges{

        flex-direction:column;
        gap:12px;

    }

    .store-badge img{

        height:38px;

    }

    .showcase .eyebrow{

        font-size:1.28rem;
        margin-bottom:18px;

    }

    .tagline{

        font-size:1.08rem;

    }

    .description{

        font-size:1rem;

    }

    .showcase{

        padding:24px 18px 72px;

    }

    .showcase-grid{

        display:grid;
        grid-template-columns:repeat(6, 1fr);
        justify-items:center;
        align-items:center;

        padding:10px 6px 20px;
        row-gap:24px;

    }

    .showcase-card{

        width:120px;
        margin:0;

        box-shadow:0 8px 24px rgba(20,50,77,.10);

    }

    /* Row 1: 3 cards across all 6 columns, each spanning 2 */
    .card-a{ grid-column:1 / 3; grid-row:1; }
    .card-b{ grid-column:3 / 5; grid-row:1; }
    .card-c{ grid-column:5 / 7; grid-row:1; }

    /* Row 2: 2 cards, centered across the same 6 columns */
    .card-d{ grid-column:2 / 4; grid-row:2; }
    .card-e{ grid-column:4 / 6; grid-row:2; }

    .story h2{

        font-size:1.6rem;

    }

    .support{

        padding:72px 24px;

    }

}

/* ---------- EXPERIMENT: VIDEO CARD FULL SCREEN (test) ---------- */

/* The video stack replaces the 3-image .cards-stack section, but only on
   the Italian site — the video graphics only exist in Italian. EN/DE keep
   the original image stack, so exactly one of the two is ever displayed. */
.video-stack{

    display:none;

    position:relative;

    padding:50px 0 70px;

    background:#ffffff;

}

/* Desktop only: the video graphics are landscape 16:9, so on phones the
   original portrait image stack is kept in every language. German is not
   listed because no German overlay artwork exists yet — it keeps the
   image stack everywhere. */
@media (min-width:961px){

    html[lang="en"] .video-stack,
    html[lang="it"] .video-stack{ display:block; }

    html[lang="en"] .cards-stack,
    html[lang="it"] .cards-stack{ display:none; }

}

.video-card{

    position:relative;

    width:100%;

    /* same aspect as card_full_screen (1717 x 916) so the overlay
       graphic sits exactly where it did in the flat image */
    aspect-ratio:1717 / 916;

    overflow:hidden;

    background:#000;

    cursor:pointer;

    -webkit-tap-highlight-color:transparent;

}

.video-card:focus-visible{

    outline:3px solid var(--orange, #f5a623);
    outline-offset:-3px;

}

/* Each slide = one background video + its overlay graphic.
   Slides are stacked; only the active one is visible. */
.video-slide{

    position:absolute;
    inset:0;

    opacity:0;
    visibility:hidden;

    transition:opacity var(--slide-fade, .7s) ease,
               visibility 0s linear var(--slide-fade, .7s);

    will-change:opacity;

}

.video-slide.is-active{

    opacity:1;
    visibility:visible;

    transition:opacity var(--slide-fade, .7s) ease,
               visibility 0s linear 0s;

}

.video-card-bg{

    position:absolute;
    inset:0;

    width:100%;
    height:100%;

    object-fit:cover;
    display:block;

}

.video-card-overlay{

    position:absolute;
    inset:0;

    width:100%;
    height:100%;

    /* contain (not cover) so overlays whose aspect ratio differs from the
       card are scaled down and centred instead of being cropped */
    object-fit:contain;
    display:block;

    /* The source graphics are ~1700px wide but the card is full-bleed, so on
       a wide screen they were being upscaled and looked soft. Drawing them
       at 80% keeps them nearer their native size — smaller on screen, but
       noticeably sharper. Scaling is centred, so the composition holds. */
    transform:translateY(var(--overlay-lift, 0)) scale(var(--overlay-scale, .8));

    /* Only the transform is transitioned here. The opacity is rewritten on
       every frame by the rAF loop in script.js (it is driven by the video's
       playhead), so a CSS opacity transition would fight it — the Immersion
       fade is eased in JS instead, on the same multiplier the old hover
       dimming used. */
    transition:transform .45s cubic-bezier(.16, 1, .3, 1);

    opacity:0;
    will-change:opacity, transform;

    pointer-events:none;

}

/* ---------- IMMERSION MODE ---------- */

/* Lets the active clip be watched without its overlay graphic. The state is
   per-slide (the class lives on .video-slide, not on .video-card), so the
   other two slides are untouched and keep their own graphic. */

/* As the graphic dissolves it also drifts up and grows a hair, so the exit
   reads as a deliberate move rather than as an image that failed to load. */
.video-slide.is-immersive .video-card-overlay{

    --overlay-lift:-14px;
    --overlay-scale:.84;

}

/* Bottom-left stack: hint on top, control underneath. The wrapper is
   click-through so the rest of the card keeps its "click to skip" behaviour;
   only the control itself takes the pointer. */
.immersion-ui{

    position:absolute;

    left:clamp(18px, 3vw, 44px);
    bottom:clamp(16px, 2.6vw, 38px);

    z-index:2;

    display:flex;
    flex-direction:column;
    align-items:flex-start;
    gap:10px;

    pointer-events:none;

}

/* Typographic, not a button: same uppercase / wide-tracking treatment as
   .eyebrow, in white because it sits over video. */
.immersion-toggle{

    position:relative;

    display:inline-grid;      /* both labels share one cell, so the control
                                 never changes size when the text swaps */

    appearance:none;
    -webkit-appearance:none;
    background:none;
    border:0;
    padding:0;

    font-family:inherit;
    font-size:.72rem;
    font-weight:700;
    letter-spacing:.16em;
    text-transform:uppercase;

    color:rgba(255, 255, 255, .78);
    text-shadow:0 1px 12px rgba(0, 0, 0, .55);

    cursor:pointer;
    pointer-events:auto;

    transition:opacity .4s ease, color .3s ease;

}

.immersion-toggle:hover{ color:#ffffff; }

.immersion-toggle:focus-visible{

    outline:2px solid var(--yellow, #FBB320);
    outline-offset:6px;

}

/* Hairline that draws itself in on hover — the only "affordance" the
   control gets, instead of a background or a border. */
.immersion-toggle::after{

    content:"";

    position:absolute;
    left:0;
    right:.16em;   /* compensates the trailing letter-spacing */
    bottom:-6px;

    height:1px;

    background:currentColor;

    transform:scaleX(0);
    transform-origin:left center;

    transition:transform .4s cubic-bezier(.16, 1, .3, 1);

}

.immersion-toggle:hover::after,
.immersion-toggle:focus-visible::after{ transform:scaleX(1); }

.immersion-label{

    grid-area:1 / 1;

    transition:opacity .3s ease;

}

/* Normal state: ENTER visible, EXIT parked. Immersion flips the pair. */
.label-exit{ opacity:0; }

.video-slide.is-immersive .label-enter{ opacity:0; }
.video-slide.is-immersive .label-exit{ opacity:1; }

/* In Immersion the control gets out of the way with the graphic... */
.video-slide.is-immersive .immersion-toggle{

    opacity:0;
    pointer-events:none;

}

/* ...and comes back as EXIT when the pointer approaches the bottom-left
   corner (the .show-exit class is set from script.js), or whenever it is
   focused with the keyboard. */
.video-slide.is-immersive.show-exit .immersion-toggle,
.video-slide.is-immersive .immersion-toggle:focus-visible{

    opacity:1;
    pointer-events:auto;

}

/* One-shot hint on entering the mode, so it is obvious this is a state the
   user switched on and knows how to leave. Fades itself out after a moment. */
.immersion-hint{

    margin:0;

    font-size:.68rem;
    font-weight:500;
    letter-spacing:.06em;

    color:rgba(255, 255, 255, .72);
    text-shadow:0 1px 12px rgba(0, 0, 0, .55);

    opacity:0;
    transform:translateY(4px);

    transition:opacity .45s ease, transform .45s ease;

}

.video-slide.show-hint .immersion-hint{

    opacity:1;
    transform:translateY(0);

}

/* Only one of the two hint wordings is ever shown, picked by pointer type
   rather than by screen width — a touch laptop gets the tap wording. */
.hint-touch{ display:none; }

@media (hover:none){

    .hint-hover{ display:none; }
    .hint-touch{ display:inline; }

    /* No hover to reveal EXIT with, so it simply stays on screen, quietly. */
    .video-slide.is-immersive .immersion-toggle{

        opacity:.62;
        pointer-events:auto;

    }

}


/* Desktop: the section IS the viewport — exactly 100vw x 100vh on every
   screen, same as the .cards-stack section it replaces.

   Previously the card kept its own 1717/916 ratio at 100% width, which
   meant its height was decided by the width of the screen and almost never
   matched the height of the screen:
     - on wide/short screens (ultrawide, 16:9 laptops) the card came out
       TALLER than the viewport, so the section grew past 100vh; with
       scroll-snap-align:start the top was pinned to the top of the screen
       and the bottom was simply cut off — which is why the IMMERSION
       control (bottom-left corner) sometimes disappeared, and why the
       graphic looked pushed down, with more empty space above it than
       below;
     - on taller screens the card was shorter than the viewport and floated
       in the middle of a white band.

   Now the card fills the viewport and the video fills the card with
   object-fit:cover — the same thing Elementor's "Cover" background does:
   the clip is scaled proportionally until it covers the whole frame and
   whatever sticks out is cropped. No stretching, no squashing, no upscaling
   beyond the natural scale-to-fill, so the quality is untouched.

   The overlay artwork keeps object-fit:contain, so it is never cropped and
   never distorted: it is scaled to fit inside the frame and centred, which
   also means the space above and below it is now always identical. */
@media (min-width:961px){

    html[lang="en"] .video-stack,
    html[lang="it"] .video-stack{

        display:block;

        height:100vh;
        min-height:0;
        padding:0;

        overflow:hidden;

        /* no longer visible behind the card, but keeps the section from
           flashing white while the first frame is still decoding */
        background:#000;

        scroll-snap-align:start;

    }

    .video-stack .video-card{

        margin:0;

        width:100%;
        height:100%;

        /* the ratio is what forced the card off-screen — on desktop the
           viewport decides the size, not the artwork */
        aspect-ratio:auto;

    }

}

@media (prefers-reduced-motion:reduce){

    .video-card-overlay{ opacity:1 !important; }

    /* Immersion is a user-requested state, not decoration, so it still
       works here — it just happens instantly instead of dissolving. */
    .video-slide.is-immersive .video-card-overlay{ opacity:0 !important; }

    .video-card-overlay,
    .immersion-toggle,
    .immersion-toggle::after,
    .immersion-label,
    .immersion-hint{ transition:none; }

}
