/* ============================================================
   Intro page (shared component, window.SBIntro in intro-page.js)

   The first time a browser opens a proposal link (Builder switch
   "Add intro page") it gets this welcome page: their logo x Sendblue,
   "A Sendblue proposal for <business>", and a name box. Enter fades the
   rest of the stage out while the lockup's Sendblue mark holds still,
   then that same mark bounces three times, spins two turns, and grows
   while it spins until the page is solid blue, and the blue fades into
   the proposal underneath.

   Used by the live proposal page (position fixed, full viewport) and by
   the Builder's preview column (.is-embedded fills its frame instead).

   Timeline (play() in intro-page.js uses the same numbers):
     0ms      .is-leaving + .is-hero   stage fades out (.3s) while the hero,
                                       a copy of the lockup's Sendblue mark
                                       that play() lays exactly over it,
                                       takes its place (the lockup's own
                                       mark hides underneath)
     300ms    .is-bounce               mark bounces three times (1.5s)
     1800ms   .is-spin                 two fast turns (1s)
     2800ms   .is-grow                 keeps spinning, grows until blue (1.3s)
     4100ms   .is-fade                 the blue fades into the proposal (.7s)
     4800ms   done
   ============================================================ */

.sb-intro {
    position: fixed;
    inset: 0;
    z-index: 9000;
    background: #fff;
    font-family: 'Montserrat', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    color: #0f172a;
    overflow: hidden;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}
.sb-intro[hidden] { display: none; }
.sb-intro [hidden] { display: none !important; }
/* Scroll lock while the intro is up. overflow: hidden alone is not enough on
   iOS Safari (the document still scrolls with the keyboard open or while the
   toolbars collapse), so the body is pinned too. Safe here because the live
   page only shows the intro on a fresh load at scroll position 0. */
body.sb-intro-open { overflow: hidden; position: fixed; top: 0; left: 0; width: 100%; }

/* Builder preview: fill the preview frame, not the viewport. The frame
   has overflow hidden, and the hero/flood are absolute inside the root,
   so the whole animation stays inside the frame. */
.sb-intro.is-embedded { position: absolute; z-index: 5; }

/* ---- Backdrop: two soft washes of Sendblue blue and a faint dot grid ---- */
.sb-intro-bg {
    position: absolute;
    inset: 0;
    background:
        radial-gradient(62% 58% at 10% 6%, rgba(10,142,255,.14), rgba(10,142,255,0) 72%),
        radial-gradient(56% 52% at 92% 96%, rgba(10,142,255,.10), rgba(10,142,255,0) 72%);
}
.sb-intro-bg::after {
    content: '';
    position: absolute;
    inset: 0;
    background-image: radial-gradient(rgba(15,23,42,.085) 1px, transparent 1.4px);
    background-size: 26px 26px;
    -webkit-mask-image: radial-gradient(ellipse 70% 65% at 50% 50%, #000 20%, transparent 78%);
    mask-image: radial-gradient(ellipse 70% 65% at 50% 50%, #000 20%, transparent 78%);
}

/* ---- Stage: the lockup, the copy, and the name box ---- */
.sb-intro-stage {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    justify-content: safe center;
    gap: 14px;
    padding: 24px;
    text-align: center;
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    transition: opacity .3s ease, transform .3s ease;
}

.sb-intro-lockup {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 22px;
    flex-shrink: 0;
}
.sb-intro-mark {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 84px;
    max-width: 220px;
}
.sb-intro-mark img {
    display: block;
    height: 84px;
    width: auto;
    max-width: 220px;
    object-fit: contain;
}
/* White-ink client logos sit on a navy chip so they stay legible on white. */
.sb-intro-mark-client.is-chip {
    height: auto;
    background: #16233F;
    border-radius: 18px;
    padding: 12px 18px;
    box-shadow: 0 10px 28px rgba(22,35,63,.18);
}
.sb-intro-mark-client.is-chip img { height: 60px; }
.sb-intro-x {
    font-size: 30px;
    font-weight: 700;
    line-height: 1;
    color: #9CA3AF;
}

.sb-intro-eyebrow {
    margin: 10px 0 0;
    font-size: 12px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .12em;
    color: #64748b;
}
.sb-intro-title {
    margin: 0;
    font-size: clamp(30px, 5vw, 52px);
    font-weight: 800;
    letter-spacing: -0.02em;
    line-height: 1.05;
    max-width: min(90vw, 760px);
    word-wrap: break-word;
    overflow-wrap: anywhere;
}
.sb-intro.is-embedded .sb-intro-title { max-width: 100%; }

/* ---- Name form ---- */
.sb-intro-form {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    margin-top: 18px;
    width: min(92vw, 460px);
    flex-shrink: 0;
}
.sb-intro.is-embedded .sb-intro-form { width: min(100%, 460px); }
.sb-intro-field {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    box-sizing: border-box;
    border: 2px solid #e2e8f0;
    border-radius: 999px;
    background: #fff;
    padding: 6px 6px 6px 22px;
    box-shadow: 0 10px 30px rgba(15,23,42,.08);
    transition: border-color .15s ease, box-shadow .15s ease;
}
.sb-intro-field:focus-within {
    border-color: #0a8eff;
    box-shadow: 0 0 0 4px rgba(10,142,255,.18), 0 10px 30px rgba(15,23,42,.08);
}
.sb-intro-input {
    flex: 1;
    min-width: 0;
    border: 0;
    outline: none;
    background: transparent;
    padding: 6px 0;
    font-family: inherit;
    font-size: 17px;
    font-weight: 500;
    color: #0f172a;
}
.sb-intro-input::placeholder { color: #94a3b8; font-weight: 500; }
.sb-intro-go {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
    background: #0a8eff;
    color: #fff;
    border: 0;
    border-radius: 999px;
    padding: 12px 18px;
    font-family: inherit;
    font-weight: 700;
    font-size: 15px;
    line-height: 1;
    cursor: pointer;
    white-space: nowrap;
    transition: background .15s ease, transform .15s ease;
}
.sb-intro-go:hover { background: #0779e0; }
.sb-intro-go:active { transform: scale(.97); }
.sb-intro-go:focus-visible { outline: 2px solid #0a8eff; outline-offset: 2px; }
.sb-intro-enter {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    border-radius: 999px;
    background: rgba(255,255,255,.22);
    font-size: 12px;
    font-weight: 700;
}

/* Empty submit while a name is required: the field shakes and turns red
   for .4s (.is-shake), the note stays up for 2.5s (.is-nudge). */
.sb-intro.is-shake .sb-intro-field {
    animation: sbIntroShake .4s cubic-bezier(.36,.07,.19,.97);
    border-color: #ef4444;
}
.sb-intro.is-shake .sb-intro-field:focus-within {
    border-color: #ef4444;
    box-shadow: 0 0 0 4px rgba(239,68,68,.18), 0 10px 30px rgba(15,23,42,.08);
}
.sb-intro-required-note {
    display: none;
    margin: 0;
    font-size: 13px;
    font-weight: 600;
    color: #dc2626;
}
.sb-intro.is-nudge .sb-intro-required-note { display: block; }
.sb-intro-skip {
    margin-top: 2px;
    padding: 6px 10px;
    background: none;
    border: 0;
    border-radius: 999px;
    font-family: inherit;
    font-size: 13px;
    font-weight: 500;
    color: #64748b;
    cursor: pointer;
}
.sb-intro-skip:hover { text-decoration: underline; color: #334155; }
.sb-intro-skip:focus-visible { outline: 2px solid #0a8eff; outline-offset: 2px; }
.sb-intro.is-required .sb-intro-skip { display: none; }

/* ---- Hero: the Sendblue mark that bounces, spins, and takes over ----
   play() sets left/top/width/height inline so the hero sits exactly over
   the lockup's Sendblue mark (the one the viewer was looking at) and the
   lockup's own copy hides underneath it. The centered 110px values below
   are only the fallback for a mark that could not be measured. No opacity
   transition: the swap has to land in one frame or the mark blinks. */
.sb-intro-hero {
    position: absolute;
    left: 50%;
    top: 50%;
    width: 110px;
    height: 110px;
    margin: -55px 0 0 -55px;
    opacity: 0;
    pointer-events: none;
    will-change: transform;
}
.sb-intro-hero-mark {
    display: block;
    width: 100%;
    height: 100%;
    transform-origin: 50% 50%;
    will-change: transform;
}
/* The shadow follows the hero's size: just under it, a bit narrower. */
.sb-intro-hero-shadow {
    position: absolute;
    left: 50%;
    top: calc(100% + 8px);
    width: 58%;
    height: 10px;
    border-radius: 50%;
    background: radial-gradient(ellipse at center, rgba(30,40,90,1), rgba(30,40,90,0) 70%);
    opacity: .35;
    transform: translateX(-50%) scaleX(1);
    transform-origin: 50% 50%;
    transition: opacity .3s ease;
}

/* ---- Flood: guarantees a solid #0a8eff before the fade ---- */
.sb-intro-flood {
    position: absolute;
    inset: 0;
    background: #0a8eff;
    opacity: 0;
    pointer-events: none;
}

/* ---- Phase classes (set on the root by SBIntro.play) ---- */
.sb-intro.is-playing .sb-intro-stage { pointer-events: none; }
.sb-intro.is-leaving .sb-intro-stage { opacity: 0; transform: scale(.96); }
.sb-intro.is-hero .sb-intro-hero { opacity: 1; }
/* The lockup's own mark steps aside the moment the hero covers it. */
.sb-intro.is-hero .sb-intro-mark-sb img { visibility: hidden; }

/* Bounce: squash and stretch on the mark, the shadow shrinks under each hop.
   The origin sits at the bottom of the mark so a squash stays planted on
   the shadow instead of hovering above it. */
.sb-intro.is-bounce .sb-intro-hero-mark {
    transform-origin: 50% 100%;
    animation: sbIntroBounce 1.5s cubic-bezier(.36,0,.3,1) forwards;
}
.sb-intro.is-bounce .sb-intro-hero-shadow {
    animation: sbIntroBounceShadow 1.5s cubic-bezier(.36,0,.3,1) forwards;
}

/* Spin: two full turns in a second, shadow fades away. */
.sb-intro.is-spin .sb-intro-hero-mark {
    animation: sbIntroSpin 1s cubic-bezier(.55,.05,.25,1) forwards;
}
.sb-intro.is-spin .sb-intro-hero-shadow,
.sb-intro.is-grow .sb-intro-hero-shadow { opacity: 0; }

/* Grow: keeps turning while it accelerates to 90x, the blob's own blue
   becomes the page, and the flood tops it up to a solid #0a8eff. */
.sb-intro.is-grow .sb-intro-hero-mark {
    animation: sbIntroGrow 1.3s cubic-bezier(.6,0,.9,.45) forwards;
}
.sb-intro.is-grow .sb-intro-flood {
    animation: sbIntroFlood 1.3s linear forwards;
}

/* Fade: the whole intro (now solid blue) fades into the proposal. */
.sb-intro.is-fade { transition: opacity .7s ease; opacity: 0; }

/* ---- Keyframes ---- */
/* Three hops of shrinking height (96px, 72px, 48px). Rises ease out so the
   mark hangs at the top, falls ease in so it hits the ground with weight,
   and every landing squashes before the next launch stretches. */
@keyframes sbIntroBounce {
    0%   { transform: translateY(0) scale(1);           animation-timing-function: cubic-bezier(.3,0,.5,1); }
    6%   { transform: translateY(-4px) scale(.94,1.06); animation-timing-function: cubic-bezier(.16,.66,.36,1); }
    20%  { transform: translateY(-96px) scale(1);       animation-timing-function: cubic-bezier(.58,0,.86,.36); }
    34%  { transform: translateY(0) scale(1.12,.88);    animation-timing-function: cubic-bezier(.3,0,.5,1); }
    39%  { transform: translateY(-3px) scale(.97,1.03); animation-timing-function: cubic-bezier(.16,.66,.36,1); }
    52%  { transform: translateY(-72px) scale(1);       animation-timing-function: cubic-bezier(.58,0,.86,.36); }
    66%  { transform: translateY(0) scale(1.1,.9);      animation-timing-function: cubic-bezier(.3,0,.5,1); }
    71%  { transform: translateY(-2px) scale(.98,1.02); animation-timing-function: cubic-bezier(.16,.66,.36,1); }
    84%  { transform: translateY(-48px) scale(1);       animation-timing-function: cubic-bezier(.58,0,.86,.36); }
    96%  { transform: translateY(0) scale(1.08,.92);    animation-timing-function: cubic-bezier(.3,0,.5,1); }
    100% { transform: translateY(0) scale(1); }
}
/* The shadow narrows and lightens at each peak, spreads back on landing. */
@keyframes sbIntroBounceShadow {
    0%   { transform: translateX(-50%) scaleX(1);    opacity: .35; animation-timing-function: cubic-bezier(.3,0,.5,1); }
    6%   { transform: translateX(-50%) scaleX(.96);  opacity: .33; animation-timing-function: cubic-bezier(.16,.66,.36,1); }
    20%  { transform: translateX(-50%) scaleX(.5);   opacity: .12; animation-timing-function: cubic-bezier(.58,0,.86,.36); }
    34%  { transform: translateX(-50%) scaleX(1.06); opacity: .38; animation-timing-function: cubic-bezier(.3,0,.5,1); }
    39%  { transform: translateX(-50%) scaleX(.98);  opacity: .33; animation-timing-function: cubic-bezier(.16,.66,.36,1); }
    52%  { transform: translateX(-50%) scaleX(.58);  opacity: .15; animation-timing-function: cubic-bezier(.58,0,.86,.36); }
    66%  { transform: translateX(-50%) scaleX(1.04); opacity: .37; animation-timing-function: cubic-bezier(.3,0,.5,1); }
    71%  { transform: translateX(-50%) scaleX(.98);  opacity: .33; animation-timing-function: cubic-bezier(.16,.66,.36,1); }
    84%  { transform: translateX(-50%) scaleX(.66);  opacity: .18; animation-timing-function: cubic-bezier(.58,0,.86,.36); }
    96%  { transform: translateX(-50%) scaleX(1.02); opacity: .36; animation-timing-function: cubic-bezier(.3,0,.5,1); }
    100% { transform: translateX(-50%) scaleX(1);    opacity: .35; }
}
@keyframes sbIntroSpin {
    0%   { transform: rotate(0deg) scale(1); }
    100% { transform: rotate(720deg) scale(1); }
}
/* 110px x 90 = 9900px, covers any screen. */
@keyframes sbIntroGrow {
    0%   { transform: rotate(720deg) scale(1); }
    100% { transform: rotate(1440deg) scale(90); }
}
@keyframes sbIntroFlood {
    0%, 55% { opacity: 0; }
    100%    { opacity: 1; }
}
@keyframes sbIntroShake {
    0%, 100% { transform: translateX(0); }
    20%, 60% { transform: translateX(-6px); }
    40%, 80% { transform: translateX(6px); }
}

/* ---- Reduced motion: no bounce, spin, grow, or shake (play() also skips
   those phases and goes straight to the fade). ---- */
@media (prefers-reduced-motion: reduce) {
    .sb-intro.is-bounce .sb-intro-hero-mark,
    .sb-intro.is-bounce .sb-intro-hero-shadow,
    .sb-intro.is-spin .sb-intro-hero-mark,
    .sb-intro.is-grow .sb-intro-hero-mark,
    .sb-intro.is-grow .sb-intro-flood,
    .sb-intro.is-shake .sb-intro-field { animation: none; }
    .sb-intro-stage,
    .sb-intro-hero,
    .sb-intro-hero-shadow { transition: none; }
}

/* ---- Mobile ---- */
@media (max-width: 640px) {
    .sb-intro-lockup { gap: 14px; }
    .sb-intro-mark { height: 60px; max-width: 160px; }
    .sb-intro-mark img { height: 60px; max-width: 160px; }
    .sb-intro-mark-client.is-chip { padding: 9px 13px; border-radius: 14px; }
    .sb-intro-mark-client.is-chip img { height: 42px; }
    .sb-intro-x { font-size: 22px; }
    .sb-intro-form { width: 92vw; }
    .sb-intro-field { padding-left: 18px; }
    .sb-intro-go { padding: 12px 14px; }
}
