/* The ad-matched landing card: the layer over the app's first screen for a visitor who clicked an ad. services/bff/src/landing.ts
   renders the markup into the two shell documents, apps/host/src/landing-theme-client.ts runs it; the build copies this file to
   /landing/landing.css. Host-owned: the vendored apps are not touched, and none of their rules reach it (every selector starts
   at .sbw-landing, which nothing else uses).

   Look plan. Surface: mobile web + landing page. Exemplar, re-used from private-ops reddit-ads-chat-direct/creative/new-images.md
   (Mobbin Google AI composer, Neo AI Assistant, Mindtrip "Start a chat" cards): the outcome artwork large, over one line of
   label; the Mobbin MCP was not re-opened.
   - Palette, five named values per scheme, all from the boot palette (apps/host/src/boot-palette.json) except the hairline:
       dark phone    canvas #000000   ink #ececec   muted #b3b3b3   hairline #2a2a2a
       dark desktop  canvas #0d0d0d   ink #e6e8ee   muted #b0b4bf   hairline #2a2a2a
       light         canvas #faf8f3   ink #141310   muted #5f5b52   hairline #e3dfd6
     The hairline is the app's own (vendor/superbot-mobile src/design-system/themes.ts, Dark #2a2a2a, Light #e3dfd6). The scheme is
     the one the page already resolved: <html data-scheme> when the page states it (src/scheme-prepaint.ts for the phone,
     the desktop renderer's scheme-boot.js), else the browser's prefers-color-scheme; every ground that is not light (dark, ash,
     night) takes the dark set, as the boot-failure panel does (build.mjs bootPanelCss). No second mechanism.
   - Accent: exactly one, Superbot blue #2b6bff (a row's `accent` may replace it), on the Continue pill and nowhere else.
   - Type: one family, the boot page's "SF Pro Rounded", ui-rounded, system-ui (no font file ships). The headline is 28/36 at
     weight 600 with negative tracking; the sub and the button are 16/24 at 400 and 500; nothing else is set.
   - Radius: exactly two. 16px the media frame, 9999px the Continue pill.
   - The one bold thing: the ad's own media, as large as the screen allows (phone: the width minus the 24px gutters, at most 46svh
     tall; desktop: the right column, at most 70vh tall), object-fit contain, never cropped.
   - Motion: one entrance, the layer's opacity 0 to 1 in 200ms, guarded below. No resting shadow, no gradient, no glow, no card in a card.

   Every number is a design-tokens value (~/.cosmos/skills/design-tokens/dist/tokens.css): spacing 4, 8, 12, 16, 24, 32, 48, 64;
   radius-16 and radius-full; text-headline-medium 28/36 and text-title-medium 16/24; duration-200; ease-standard-decelerate; state
   layers hover 0.08 and press 0.10 (as brightness 1.08 and 0.9). The 840px breakpoint is the Material 3 "expanded" window class
   (design-system.mdc, Layout vocabulary); 46svh, 36svh and 70vh are the media's share of the screen, ratios not tokens. */

.sbw-landing {
  --lp-accent: #2b6bff;
  --lp-accent-ink: #ffffff;
  --lp-bg: #faf8f3;
  --lp-fg: #141310;
  --lp-muted: #5f5b52;
  --lp-line: #e3dfd6;
  position: fixed;
  inset: 0;
  /* Under the edge bands (build.mjs edgeBandCss, 2147483647), over everything else. */
  z-index: 2147483646;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: max(24px, env(safe-area-inset-top, 0px)) max(24px, env(safe-area-inset-right, 0px)) 0 max(24px, env(safe-area-inset-left, 0px));
  padding-left: max(24px, env(safe-area-inset-left, 0px));
  padding-right: max(24px, env(safe-area-inset-right, 0px));
  background-color: var(--lp-bg);
  color: var(--lp-fg);
  font-family: "SF Pro Rounded", ui-rounded, system-ui, sans-serif;
  font-size: 16px;
  line-height: 24px;
  font-weight: 400;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

@media (prefers-color-scheme: dark) {
  html:not([data-scheme]) .sbw-landing {
    --lp-bg: #000000;
    --lp-fg: #ececec;
    --lp-muted: #b3b3b3;
    --lp-line: #2a2a2a;
  }
  html:not([data-scheme]) .sbw-landing[data-shell='desktop'] {
    --lp-bg: #0d0d0d;
    --lp-fg: #e6e8ee;
    --lp-muted: #b0b4bf;
  }
}

html[data-scheme]:not([data-scheme='light']) .sbw-landing {
  --lp-bg: #000000;
  --lp-fg: #ececec;
  --lp-muted: #b3b3b3;
  --lp-line: #2a2a2a;
}

html[data-scheme]:not([data-scheme='light']) .sbw-landing[data-shell='desktop'] {
  --lp-bg: #0d0d0d;
  --lp-fg: #e6e8ee;
  --lp-muted: #b0b4bf;
}

/* A reload of a landing the visitor already took (the head script saw the app's own route in the address) never shows it. */
html[data-sbw-landing-skip] .sbw-landing {
  display: none;
}

/* The legal footer (landing/legal.css, services/bff/src/landing.ts injectLegal) is fixed to the bottom of the viewport while the head
   script states html[data-sbw-legal]: the layer then ends above it, so the footer is under the layer's Continue and never over it, and
   the bottom safe area, which the footer owns, is not counted twice in the Continue bar below. */
html[data-sbw-legal] .sbw-landing {
  bottom: var(--sbw-legal-h, 0px);
}

html[data-sbw-legal] .sbw-landing-bar {
  padding-bottom: 16px;
}

/* While a field has the phone's keyboard the footer steps aside (legal.css), and the layer takes the bottom back. */
html[data-sbw-legal][data-sbw-vv-follow] .sbw-landing {
  bottom: 0;
}

.sbw-landing-media {
  flex: none;
  box-sizing: border-box;
  max-width: 100%;
  /* The media and the words sit as one group in the space above the action: the free height is shared above and below it. */
  margin: auto 0 0;
  border: 1px solid var(--lp-line);
  border-radius: 16px;
  overflow: hidden;
  line-height: 0;
}

.sbw-landing-media img,
.sbw-landing-media video {
  display: block;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 46vh;
  max-height: 46svh;
  object-fit: contain;
}

/* A video row's description for a screen reader: a video has no alt, and its poster is not read. */
.sbw-landing-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  white-space: nowrap;
  clip-path: inset(50%);
}

.sbw-landing-copy {
  flex: none;
  box-sizing: border-box;
  width: 100%;
  max-width: 560px;
  margin: 0 0 auto;
  text-align: center;
}

.sbw-landing-copy h1 {
  margin: 0;
  font-size: 28px;
  line-height: 36px;
  font-weight: 600;
  letter-spacing: -0.67px;
  text-wrap: balance;
}

.sbw-landing-sub {
  max-width: 60ch;
  margin: 8px auto 0;
  color: var(--lp-muted);
  text-wrap: pretty;
}

/* The pinned action: at the bottom of the screen, or of the content when it is longer than the screen (the layer scrolls). */
.sbw-landing-bar {
  flex: none;
  box-sizing: border-box;
  position: sticky;
  bottom: 0;
  width: 100%;
  max-width: 560px;
  margin: 0;
  padding-top: 12px;
  padding-bottom: max(16px, env(safe-area-inset-bottom, 0px));
  background-color: var(--lp-bg);
}

/* With no script the button could not do anything: the head script states html[data-sbw-landing] and brings it. */
.sbw-landing-go {
  display: none;
  box-sizing: border-box;
  width: 100%;
  min-height: 48px;
  margin: 0;
  padding: 0 32px;
  border: 0;
  border-radius: 9999px;
  background-color: var(--lp-accent);
  color: var(--lp-accent-ink);
  font: inherit;
  font-weight: 500;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  -webkit-appearance: none;
  appearance: none;
}

html[data-sbw-landing] .sbw-landing-go {
  display: block;
}

.sbw-landing-go:focus-visible {
  outline: 2px solid var(--lp-fg);
  outline-offset: 2px;
}

@media (hover: hover) {
  .sbw-landing-go:hover {
    filter: brightness(1.08);
  }
}

.sbw-landing-go:active,
.sbw-landing-go[aria-busy='true'] {
  filter: brightness(0.9);
}

.sbw-landing-go[aria-busy='true'] {
  cursor: progress;
}

/* A short phone (320 x 568, a landscape phone): the media gives way before the copy and the button do. */
@media (max-height: 640px) {
  .sbw-landing-media img,
  .sbw-landing-media video {
    max-height: 36vh;
    max-height: 36svh;
  }
}

/* A window of the Material 3 expanded class: two columns, the words and the button on the left, the media on the right. */
@media (min-width: 840px) {
  .sbw-landing {
    display: grid;
    grid-template-columns: minmax(0, 480px) minmax(0, 640px);
    grid-template-rows: 1fr auto auto 1fr;
    grid-template-areas:
      '. media'
      'copy media'
      'bar media'
      '. media';
    justify-content: center;
    align-items: center;
    gap: 0 64px;
    padding: 48px;
  }
  .sbw-landing-media {
    grid-area: media;
    justify-self: center;
    margin: 0;
  }
  .sbw-landing-media img,
  .sbw-landing-media video {
    max-height: 70vh;
  }
  .sbw-landing-copy {
    grid-area: copy;
    max-width: none;
    margin: 0;
    align-self: end;
    text-align: left;
  }
  .sbw-landing-sub {
    margin-left: 0;
    margin-right: 0;
  }
  .sbw-landing-bar {
    grid-area: bar;
    position: static;
    align-self: start;
    max-width: none;
    padding-top: 24px;
    padding-bottom: 0;
    background-color: transparent;
  }
  html[data-sbw-landing] .sbw-landing-go {
    width: fit-content;
    min-width: 192px;
  }
}

/* The one entrance, and the layer's dead-man timer: 47s after it first paints, whatever script did or did not do, the layer hides
   itself (the head script drops it at 45s; this is the backstop when it never ran). Both live inside the motion guards: the timer
   moves no pixels, so it is declared for both branches. */
@keyframes sbw-lp-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes sbw-lp-expire {
  to {
    visibility: hidden;
    pointer-events: none;
  }
}

@media (prefers-reduced-motion: no-preference) {
  .sbw-landing {
    animation: sbw-lp-in 200ms cubic-bezier(0, 0, 0, 1) both, sbw-lp-expire 1ms linear 47s forwards;
  }
}

@media (prefers-reduced-motion: reduce) {
  .sbw-landing {
    animation: sbw-lp-expire 1ms linear 47s forwards;
  }
}
