/* ===========================================================================
   BadgeBox landing — motion layer.
   It adds to landing.css, it does not replace it: every effect lives behind a
   class on <html> (mo-hero, mo-reveal, ...) and without that class the page
   stays exactly as it is today. It is there to turn one effect on and off at a
   time and judge it, but it is also how it goes to production: the classes
   that pass the test are kept and the others are thrown away.

   One rule: motion explains, it does not decorate. One distance, one easing,
   three durations.
   =========================================================================== */

:root {
    --mo-rise:  14px;                            /* the only distance travelled */
    --mo-fast:  120ms;                           /* states and hover          */
    --mo-base:  240ms;                           /* swaps, pills, crossfade   */
    --mo-enter: 480ms;                           /* entrances in viewport     */
    --mo-step:   60ms;                           /* stagger step              */
    --mo-ease:       cubic-bezier(.2, .8, .2, 1);   /* decelerates, no bounce */
    --mo-ease-enter: cubic-bezier(.16, 1, .3, 1);
}

/* --- safety contract --------------------------------------------------------
   Nothing disappears if the JavaScript does not arrive: the hidden state exists
   only under html.js, which a synchronous script in <head> sets before the
   first paint. Without JS the page is complete and still. */


/* ===========================================================================
   1 · THE PRIMITIVE — a single entrance, reused everywhere
   =========================================================================== */

html.js.mo-reveal .reveal > * {
    opacity: 0;
    transform: translateY(var(--mo-rise));
    transition: opacity var(--mo-enter) var(--mo-ease-enter),
                transform var(--mo-enter) var(--mo-ease-enter);
    transition-delay: calc(var(--i, 0) * var(--mo-step));
}
html.js.mo-reveal .reveal.is-in > * { opacity: 1; transform: none; }

/* Skipped by an anchor: it is already behind you, so it just gets in place. */
html.js .is-instant, html.js .is-instant > *,
html.js .is-instant *::before, html.js .is-instant *::after,
html.js .is-instant::before, html.js .is-instant::after {
    transition: none !important;
    animation: none !important;
}

/* The figures with the screenshot enter as a single block and from a touch
   lower: they are the heavy object of the row, not a line of text. */
html.js.mo-reveal .reveal--solo {
    opacity: 0;
    transform: translateY(20px) scale(.985);
    transition: opacity var(--mo-enter) var(--mo-ease-enter),
                transform 620ms var(--mo-ease-enter);
}
html.js.mo-reveal .reveal--solo.is-in { opacity: 1; transform: none; }

/* The line that closes every block is the page's promise: its blue rule
   draws itself instead of already being there. It is the only flourish I
   allow myself, and it recurs eight times, so it becomes a signature, not a whim. */
html.js.mo-reveal .blk__k { border-top-color: transparent; position: relative; }
html.js.mo-reveal .blk__k::before {
    content: ""; position: absolute; left: 0; right: 0; top: -2px; height: 2px;
    background: var(--lp-accent);
    transform: scaleX(0); transform-origin: left;
    transition: transform 420ms var(--mo-ease) 300ms;
}
html.js.mo-reveal .reveal.is-in .blk__k::before,
html.js.mo-reveal .blk__k.is-in::before { transform: none; }


/* ===========================================================================
   2 · THE HERO — entrance choreography and the rotating word
   =========================================================================== */

html.js.mo-hero .hero__text > *,
html.js.mo-hero .hero__proof-l,
html.js.mo-hero .hero__mock,
html.js.mo-hero .hero__stage { opacity: 0; }

html.js.mo-hero.is-ready .hero__text > * {
    animation: mo-rise-in 560ms var(--mo-ease-enter) both;
    animation-delay: calc(var(--i, 0) * var(--mo-step));
}
/* The social proof label is no longer a child of .hero__text — it sits in
   the band that spans the two columns — so its delay is written here
   instead of coming from motion.js's --i: it falls between the last line
   of the claim (240ms) and the first logo (600ms). */
html.js.mo-hero.is-ready .hero__proof-l {
    animation: mo-rise-in 560ms var(--mo-ease-enter) 520ms both;
}
html.js.mo-hero.is-ready .hero__mock,
html.js.mo-hero.is-ready .hero__stage {
    animation: mo-stage-in 720ms var(--mo-ease-enter) 260ms both;
}
@keyframes mo-rise-in  { from { opacity: 0; transform: translateY(var(--mo-rise)); } to { opacity: 1; transform: none; } }
@keyframes mo-stage-in { from { opacity: 0; transform: translateY(28px); }          to { opacity: 1; transform: none; } }

/* --- the rotating word -----------------------------------------------------
   Two behaviours on the same DOM, so they can really be compared:
   · off  = today's (crossfade, box as wide as the longest word, the gap
            after «gli scontrini»);
   · on   = vertical reel, the box narrows to the current word and a 3px
            blue rule underlines it, following its width.
   The two measures --mo-rot-h and --mo-rot-drop are the only ones to adjust
   if the font changes: the first is the height of the little window, the
   second realigns it on the title's baseline. */
.mo-rot { display: inline-block; position: relative; }
.mo-rot__w { color: var(--bbx-blue-300); }

/* Without JavaScript the first word stays, in normal flow: the little window
   and the rule are built by motion.js, and if it does not arrive the title
   must still read — «Smetti di rincorrere le timbrature», whole. Everything
   that hides or moves therefore sits under html.js and not one level up. */
html:not(.js) .mo-rot__w:not(.is-on) { display: none; }

html.js .mo-rot {
    --mo-rot-h: 1.16em;
    --mo-rot-drop: -.09em;
    vertical-align: bottom;
    height: var(--mo-rot-h);
    margin-bottom: var(--mo-rot-drop);
    width: var(--mo-w, auto);
}
html.js .mo-rot__clip { display: block; position: relative; height: 100%; overflow: hidden; }
html.js .mo-rot__w {
    position: absolute; left: 0; top: 0;
    line-height: var(--mo-rot-h);
    white-space: nowrap;
    opacity: 0;
}
html.js .mo-rot__w.is-on { opacity: 1; }
html.js .mo-rot__rule {
    position: absolute; left: 0; bottom: -.06em; height: 3px;
    background: var(--lp-accent); border-radius: 2px;
    width: var(--mo-w, 0); opacity: 0;
}

/* off — today's crossfade, box still */
html.js:not(.mo-hero) .mo-rot__w {
    transform: translateY(.3em);
    transition: opacity .45s ease, transform .45s ease;
}
html.js:not(.mo-hero) .mo-rot__w.is-on  { opacity: 1; transform: none; }
html.js:not(.mo-hero) .mo-rot__w.is-out { opacity: 0; transform: translateY(-.3em); }

/* on — the reel, the breathing box, the rule that follows */
html.js.mo-hero .mo-rot { transition: width 460ms var(--mo-ease); }
html.js.mo-hero .mo-rot__rule {
    opacity: 1;
    transition: width 460ms var(--mo-ease);
}
html.js.mo-hero .mo-rot__w { transform: translateY(102%); }
html.js.mo-hero .mo-rot__w.is-on {
    opacity: 1; transform: none;
    transition: transform 520ms var(--mo-ease-enter), opacity 160ms linear;
}
html.js.mo-hero .mo-rot__w.is-out {
    opacity: 0; transform: translateY(-102%);
    transition: transform 520ms var(--mo-ease-enter), opacity 260ms linear 160ms;
}

/* the customer logos arrive after the rest, one after another */
html.js.mo-hero.is-ready .hero__proof li {
    animation: mo-rise-in 460ms var(--mo-ease-enter) both;
    animation-delay: calc(600ms + var(--i, 0) * 70ms);
}


/* ===========================================================================
   3 · THE HEADER — materializes, tells you where you are, and measures the way
   =========================================================================== */

/* Above the fold it is dark blue on dark blue: a border that separates nothing.
   Above the fold the header therefore stays opaque and borderless — sewn to the
   hero, which is exactly the same #002952 — and shows up as an object of its own
   only afterwards, with a veil, a border and a touch less height.

   WARNING: «transparent» does NOT go here. The header is sticky in flow, not
   overlaid on the hero: it sits above it, not on top of it. Making it
   transparent uncovers the body's white and the white logo disappears. */
html.js.mo-header .hd {
    background: var(--lp-dark); backdrop-filter: none;
    border-bottom-color: transparent;
    transition: background-color var(--mo-base) var(--mo-ease),
                border-color var(--mo-base) var(--mo-ease);
}
html.js.mo-header .hd.is-stuck {
    background: rgba(0, 41, 82, .92); backdrop-filter: blur(10px);
    border-bottom-color: rgba(255, 255, 255, .12);
}
html.js.mo-header .hd__bar { transition: padding var(--mo-base) var(--mo-ease); }
html.js.mo-header .hd.is-stuck .hd__bar { padding-top: 9px; padding-bottom: 9px; }

/* The indicator that slides from one link to the next. It stays within the
   nav's height: .hd__nav has overflow:hidden and anything sticking out would be clipped. */
html.js.mo-header .hd__nav { position: relative; }
.mo-navdot {
    position: absolute; left: 0; bottom: 0; height: 2px;
    background: #fff; border-radius: 2px;
    width: var(--w, 0); transform: translateX(var(--x, 0));
    opacity: 0; pointer-events: none;
}
html.js.mo-header .hd__nav.is-spy .mo-navdot {
    opacity: 1;
    transition: transform 320ms var(--mo-ease), width 320ms var(--mo-ease), opacity var(--mo-base);
}
html.js.mo-header .hd__nav a { transition: color var(--mo-fast) ease; }
html.js.mo-header .hd__nav a.is-here { color: #fff; }

/* The progress bar: where the browser can animate on scroll it does not
   cost a line of JavaScript. Elsewhere the fallback in motion.js moves it. */
html.js.mo-header .hd::after {
    content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 2px;
    background: var(--lp-accent);
    transform: scaleX(var(--mo-progress, 0)); transform-origin: left;
}
@supports (animation-timeline: scroll()) {
    html.js.mo-header .hd::after {
        animation: mo-progress linear both;
        animation-timeline: scroll(root block);
    }
}
@keyframes mo-progress { from { transform: scaleX(0); } to { transform: scaleX(1); } }


/* ===========================================================================
   4 · THE ITEMS THAT CHASE YOU — they arrive one at a time
   =========================================================================== */

html.js.mo-items .items li {
    border-left-color: transparent; position: relative;
    opacity: 0; transform: translateX(-10px);
    transition: opacity 420ms var(--mo-ease-enter),
                transform 420ms var(--mo-ease-enter);
    transition-delay: calc(var(--i, 0) * 180ms);
}
html.js.mo-items .items li::before {
    content: ""; position: absolute; left: -3px; top: 0; bottom: 0; width: 3px;
    background: var(--bbx-gray-200);
    transform: scaleY(0); transform-origin: top;
    transition: transform 320ms var(--mo-ease);
    transition-delay: calc(var(--i, 0) * 180ms);
}
html.js.mo-items .sec--dark .items li::before { background: rgba(255, 255, 255, .3); }
html.js.mo-items .items.is-in li { opacity: 1; transform: none; }
html.js.mo-items .items.is-in li::before { transform: none; }


/* ===========================================================================
   5 · THE THREE STEPS — the line draws itself, the number lights up as it passes
   =========================================================================== */

html.js.mo-steps .steps li:not(:last-child)::after {
    content: ""; position: absolute; left: 12px; top: 26px; bottom: -12px; width: 2px;
    background: var(--lp-accent-tint);
    transform: scaleY(0); transform-origin: top;
    transition: transform 380ms var(--mo-ease);
    transition-delay: calc(var(--i, 0) * 260ms + 200ms);
}
html.js.mo-steps .steps.is-in li::after { transform: none; }

/* It lights up and goes out: the drawing stays as before, but the pulse has
   crossed the three steps. A request on the move. */
html.js.mo-steps .steps.is-in li::before {
    animation: mo-step 760ms var(--mo-ease) both;
    animation-delay: calc(var(--i, 0) * 260ms);
}
@keyframes mo-step {
      0% { background: var(--lp-accent-tint); color: var(--lp-accent-press); transform: scale(1); }
     35% { background: var(--lp-accent);      color: #fff;                   transform: scale(1.14); }
    100% { background: var(--lp-accent-tint); color: var(--lp-accent-press); transform: scale(1); }
}


/* ===========================================================================
   6 · WHERE YOU CLOCK IN FROM — the same entrance, four doors
   The clock-in arrives on one device at a time: the shell rises by four
   pixels and the border turns blue while the time appears. At the end, the
   line that says where they all end up.
   =========================================================================== */

html.js.mo-devices .dv__scr, html.js.mo-devices .dv__station, html.js.mo-devices .dv__out { opacity: 0; }
html.js.mo-devices .dv.is-in .dv__scr {
    animation: mo-rise-in 400ms var(--mo-ease) both;
    animation-delay: calc(420ms + var(--i, 0) * 520ms);
}
/* The pill already has a transform of its own — it is what centres it. mo-rise-in
   ends with «transform: none» and would wipe it out, throwing it half
   outside the column: its transforms have to be combined by hand. */
html.js.mo-devices .dv.is-in .dv__station {
    animation: mo-dv-pill 400ms var(--mo-ease) both;
    animation-delay: calc(420ms + var(--i, 0) * 520ms);
}
@keyframes mo-dv-pill {
    from { opacity: 0; transform: translate(-50%, var(--mo-rise)); }
    to   { opacity: 1; transform: translate(-50%, 0); }
}
html.js.mo-devices .dv.is-in .dv__d {
    animation: mo-dv 900ms var(--mo-ease) both;
    animation-delay: calc(300ms + var(--i, 0) * 520ms);
}
@keyframes mo-dv {
      0% { border-color: var(--bbx-gray-200); transform: translateY(0); }
     35% { border-color: var(--lp-accent);    transform: translateY(-4px); }
    100% { border-color: var(--bbx-gray-200); transform: translateY(0); }
}
/* Safety net. Here the final state comes from an animation, not from a
   transition: is-instant turns it off with animation:none and without this line
   the skipped block would stay at zero opacity forever. Where the final state is
   already written in a rule — the primitive, the items, the steps — it is not needed. */
html.js.mo-devices .dv.is-instant .dv__scr,
html.js.mo-devices .dv.is-instant .dv__station,
html.js.mo-devices .dv.is-instant .dv__out { opacity: 1; }

html.js.mo-devices .dv.is-in .dv__out {
    animation: mo-rise-in 460ms var(--mo-ease-enter) 2600ms both;
}


/* ===========================================================================
   7 · PRICING — a control that behaves like a control
   =========================================================================== */

html.js.mo-pricing .pr__switch { position: relative; }
html.js.mo-pricing .pr__switch button { position: relative; z-index: 1; }
html.js.mo-pricing .pr__switch button.is-on { background: transparent; }
.mo-thumb {
    position: absolute; top: 4px; bottom: 4px; left: 0;
    background: var(--lp-page); border-radius: var(--lp-radius-control);
    width: var(--w, 0); transform: translateX(var(--x, 0));
    opacity: 0; pointer-events: none;
}
html.js.mo-pricing .pr__switch.is-ready .mo-thumb {
    opacity: 1;
    transition: transform var(--mo-base) var(--mo-ease), width var(--mo-base) var(--mo-ease);
}

/* The price changed with an abrupt text swap: it looked like a bug.
   The entrance is caught with a MutationObserver, without touching
   landing.js — when the effect is off, it goes back to how it was. */
html.js.mo-pricing .pr__amount.is-new,
html.js.mo-pricing .pr__total.is-new { animation: mo-price var(--mo-base) var(--mo-ease); }
@keyframes mo-price { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

html.js.mo-pricing .pr__save.is-hit { animation: mo-hit 620ms var(--mo-ease); }
@keyframes mo-hit { 0%, 100% { transform: scale(1); } 35% { transform: scale(1.18); } }

html.js.mo-pricing .pr {
    transition: transform var(--mo-fast) var(--mo-ease), box-shadow var(--mo-fast) var(--mo-ease);
}
html.js.mo-pricing .pr:hover { transform: translateY(-2px); box-shadow: var(--bbx-shadow-md); }


/* ===========================================================================
   8 · THE SCREENSHOTS — they settle instead of already being still
   Scroll-driven animation: where the browser cannot do it nothing
   happens, and there is not a single scroll listener to pay for.
   =========================================================================== */

@supports (animation-timeline: view()) {
    html.js.mo-shot .shot img {
        animation: mo-settle linear both;
        animation-timeline: view();
        animation-range: entry 0% entry 90%;
    }
    @keyframes mo-settle { from { transform: scale(1.045); } to { transform: none; } }

    /* Hero: moving away, screenshot and photo separate slightly. It must
       feel like depth, not be recognisable as parallax. */
    html.js.mo-shot .hero__shot {
        animation: mo-drift linear both;
        animation-timeline: view();
        animation-range: exit 0% exit 100%;
    }
    @keyframes mo-drift { from { transform: translateY(0); } to { transform: translateY(-34px); } }
}

html.js.mo-shot .below__photos picture { overflow: hidden; border-radius: 14px; }
html.js.mo-shot .below__photos img { transition: transform 600ms var(--mo-ease); }
html.js.mo-shot .below__photos picture:hover img { transform: scale(1.035); }


/* ===========================================================================
   9 · NAVIGATION ON THE PHONE
   Below 720px .hd__nav is display:none today: half the audience, says the
   brief, has no way to move around a page of nineteen blocks.
   It is not an effect, it is a gap — but opening it is motion, so it lives here.
   =========================================================================== */

.mo-burger {
    display: none; align-items: center; justify-content: center;
    width: 34px; height: 32px; padding: 0;
    background: transparent; border: 1px solid rgba(255, 255, 255, .3);
    border-radius: var(--lp-radius-control); color: #fff;
}
.mo-burger span {
    display: block; position: relative; width: 16px; height: 2px;
    background: #fff; border-radius: 2px;
    transition: transform var(--mo-base) var(--mo-ease), background-color var(--mo-fast);
}
.mo-burger span::before, .mo-burger span::after {
    content: ""; position: absolute; left: 0; width: 16px; height: 2px;
    background: #fff; border-radius: 2px;
    transition: transform var(--mo-base) var(--mo-ease);
}
.mo-burger span::before { top: -5px; }
.mo-burger span::after  { top: 5px; }
.mo-burger[aria-expanded="true"] span { background: transparent; }
.mo-burger[aria-expanded="true"] span::before { transform: translateY(5px) rotate(45deg); }
.mo-burger[aria-expanded="true"] span::after  { transform: translateY(-5px) rotate(-45deg); }

.mo-sheet {
    position: absolute; left: 0; right: 0; top: 100%;
    background: var(--lp-dark); border-bottom: 1px solid rgba(255, 255, 255, .12);
    opacity: 0; visibility: hidden; transform: translateY(-10px);
    transition: opacity var(--mo-base) var(--mo-ease),
                transform var(--mo-base) var(--mo-ease),
                visibility var(--mo-base);
}
.mo-sheet.is-open { opacity: 1; visibility: visible; transform: none; }
.mo-sheet a {
    display: block; padding: 13px 20px; color: #fff; font-size: 16px; font-weight: 600;
    border-top: 1px solid rgba(255, 255, 255, .08);
    opacity: 0; transform: translateY(6px);
    transition: opacity 280ms var(--mo-ease), transform 280ms var(--mo-ease);
    transition-delay: calc(var(--i, 0) * 40ms);
}
.mo-sheet.is-open a { opacity: 1; transform: none; }

@media (max-width: 720px) {
    html.js.mo-nav .mo-burger { display: inline-flex; }
}
@media (min-width: 721px) {
    .mo-sheet { display: none; }
}


/* ===========================================================================
   10 · WHO ASKED FOR LESS MOTION
   The generic rule in landing.css squashes the durations, but that is not
   enough: what starts from opacity:0 must really become visible, not in .01ms.
   =========================================================================== */

@media (prefers-reduced-motion: reduce) {
    html.js .reveal > *, html.js .reveal--solo,
    html.js .items li, html.js .items li::before,
    html.js .steps li::after,
    html.js .hero__text > *, html.js .hero__stage, html.js .hero__proof li,
    html.js .hero__mock, html.js .hero__proof-l,
    html.js .mo-sheet a, html.js .shot img, html.js .hero__shot,
    html.js .dv__scr, html.js .dv__station, html.js .dv__out, html.js .dv__d,
    html.js .blk__k::before {
        opacity: 1 !important;
        transform: none !important;
        clip-path: none !important;
        animation: none !important;
    }
    html.js .mo-rot__w { transition: none !important; }
    html.js .mo-rot__w:not(.is-on) { opacity: 0 !important; }
}
