/*
 * BabyTales beta landing page.
 *
 * Flattened from the Claude Design export in source/BabytalesLanding.dc.html:
 * the five design-system components it composed (Eyebrow, Heading, Button,
 * FeatureCard, Badge) are written out here as plain classes, so the page needs
 * no React and no runtime. Token values are copied verbatim from the web design
 * system bundle, which derives them from design/tokens.ts, the app's source of
 * truth. Fonts are self-hosted (no Google Fonts request from a visitor's
 * browser); the faces are built from the ones the app bundles, subset to latin.
 *
 * The export drives its modal from React state. Here it is a :target anchor, so
 * the only route to conversion does not depend on JavaScript running.
 */

@font-face {
  font-family: 'Fraunces';
  src: url('assets/fonts/Fraunces-Regular.woff') format('woff');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Fraunces';
  src: url('assets/fonts/Fraunces-Medium.woff') format('woff');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Mukta';
  src: url('assets/fonts/Mukta-Regular.woff') format('woff');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Mukta';
  src: url('assets/fonts/Mukta-SemiBold.woff') format('woff');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

:root {
  /* Backgrounds */
  --bt-bg-primary: #f7f4f2;
  --bt-bg-white: #ffffff;
  --bt-bg-warm-white: #fefbf6;
  --bt-bg-beige: #e9e3dd; /* secondary button fill */

  /* Primary action.
     Darker than design/tokens.ts, which sets #917A74. White on that measures
     4.01:1, under the 4.5:1 the button label needs, and this button carries the
     whole funnel. #7F6A64 is the same warm taupe a step down, already the
     export's hover colour, and reaches 5.06:1. The app's token still has the
     original value, so this is the one place the page and the app differ. */
  --bt-cta-fill: #7f6a64;
  --bt-cta-hover: #6e5b55;
  --bt-cta-text: #ffffff;

  /* Text */
  --bt-text-primary: #282828;
  --bt-text-caption: #6c6c6c;
  --bt-text-secondary: #666666;
  --bt-text-brown: #7a6560;

  /* Inspiration / emotional text roles */
  --bt-text-inspiration-title: #4a3f37;
  --bt-text-inspiration-body: #8a7b6e;

  /* Borders */
  --bt-border-default: #e7e7e7;
  --bt-border-rose: #e8d5cb;

  /* Warm surfaces */
  --bt-surface-clay-badge: #c9a08b;
  --bt-surface-rose-subtle: #f2e8e0;

  /* Spacing */
  --bt-space-xs: 4px;
  --bt-space-sm: 8px;
  --bt-space-md: 12px;
  --bt-space-lg: 16px;
  --bt-space-xl: 20px;
  --bt-space-xxl: 24px;

  /* Radii */
  --bt-radius-card: 16px;
  --bt-radius-input: 12px;
  --bt-radius-pill: 100px;

  /* Type */
  --bt-font-ui: 'Mukta', system-ui, -apple-system, sans-serif;
  --bt-font-emotional: 'Fraunces', Georgia, 'Times New Roman', serif;
  --bt-size-caption: 12px;
  --bt-size-body: 16px;
  --bt-tracking-eyebrow: 1.5px;
}

/* No global border-box reset on purpose: every width and padding below is
   authored against the browser default (content-box), the way the design was
   drawn. Switching the box model shrinks the phone mockups and the sign-up
   card by the width of their padding. */

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--bt-bg-primary);
  color: var(--bt-text-primary);
  font-family: var(--bt-font-ui);
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}

img {
  max-width: 100%;
}

/* The design was drawn and approved at 1.2x. Scaling the whole page keeps the
   proportions of the approved render rather than re-deriving every value. */
.page {
  zoom: 1.2;
  min-height: 100vh;
}

/* ---------- design-system components ---------- */

/* The design system's eyebrow tones, rose #D3B8A7 and taupe #A08C7A, land at
   1.7:1 and 2.9:1 against this background. Both are far under the 4.5:1 that
   12px text needs to stay readable, so every eyebrow uses the warm brown, which
   reaches 5.0:1 on the page and 5.4:1 on white. */
.eyebrow {
  font-family: var(--bt-font-ui);
  font-weight: 600;
  font-size: var(--bt-size-caption);
  letter-spacing: var(--bt-tracking-eyebrow);
  text-transform: uppercase;
  color: var(--bt-text-brown);
  margin: 0;
}

/* ---------- brand header ---------- */

.brand {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.brand__row {
  display: flex;
  align-items: center;
  gap: 9px;
}

.brand__wordmark {
  display: block;
  width: 150px;
  height: auto;
}

/* "Beta" reads as a status marker beside the mark, not a second logo. */
.brand__badge {
  font-family: var(--bt-font-ui);
  font-weight: 600;
  font-size: 11px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--bt-text-brown);
  background: var(--bt-surface-rose-subtle);
  padding: 4px 10px;
  border-radius: var(--bt-radius-pill);
}

/* The single highest-value trust signal on the page: the established printer
   behind it. Small, same weight as an eyebrow, right under the mark. */
.brand__by {
  font-family: var(--bt-font-ui);
  font-weight: 600;
  font-size: 14px;
  color: var(--bt-text-brown);
  margin: 0;
}

.h1,
.h2 {
  font-family: var(--bt-font-emotional);
  font-weight: 400;
  line-height: 1.2;
  color: var(--bt-text-primary);
  margin: 0;
}

.h1 {
  font-size: 32px;
}

.h2 {
  font-size: 24px;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--bt-font-ui);
  font-weight: 600;
  font-size: var(--bt-size-body);
  line-height: 1.1;
  padding: 13px 26px;
  border: none;
  border-radius: var(--bt-radius-pill);
  background: var(--bt-cta-fill);
  color: var(--bt-cta-text);
  text-decoration: none;
  cursor: pointer;
}

.btn:hover,
.modal__cta:hover {
  background: var(--bt-cta-hover);
}

/* A colour shift alone is not a focus indicator. */
.btn:focus-visible,
.modal__cta:focus-visible {
  background: var(--bt-cta-hover);
  outline: 2px solid var(--bt-text-inspiration-title);
  outline-offset: 3px;
}

.modal__close:focus-visible {
  outline: 2px solid var(--bt-text-inspiration-title);
  outline-offset: 3px;
}

/* Secondary action: beige, not the CTA taupe, so the Android path stays clearly
   below the primary iPhone one. Dark label on beige measures 9.8:1. */
.btn--secondary {
  background: var(--bt-bg-beige);
  color: var(--bt-text-inspiration-title);
}

.btn--secondary:hover,
.btn--secondary:focus-visible {
  background: #ded6ce;
}

/* The CTAs that follow body copy sit one step lower than the surrounding
   stack gap. */
.cta--spaced {
  margin-top: var(--bt-space-sm);
}

.icon-knockout {
  fill: var(--bt-bg-warm-white);
}

.feature {
  background: var(--bt-bg-warm-white);
  border: 1px solid var(--bt-border-rose);
  border-radius: var(--bt-radius-card);
  padding: 18px 20px;
}

.feature__icon {
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: var(--bt-surface-rose-subtle);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--bt-cta-fill);
  margin-bottom: 10px;
}

.feature__title {
  font-family: var(--bt-font-emotional);
  font-weight: 400;
  color: var(--bt-text-inspiration-title);
  margin: 0 0 4px;
}

.feature__body {
  font-family: var(--bt-font-ui);
  color: var(--bt-text-inspiration-body);
  margin: 0;
}

/* Both lines in a feature card run at the page's reading size. */
.feature__title,
.feature__body {
  font-size: 17px;
  line-height: 1.6;
}

/* The printed book, shown only in the book card. Fills a narrow (mobile) card,
   but capped so it does not blow up to the full width of the wide desktop card,
   and centred in the card by the auto side margins. 238px is the earlier 340px
   cap reduced by 30%. On mobile the card is narrow enough that width:100% still
   wins, so this only shrinks and centres the desktop render. */
.feature__photo {
  display: block;
  width: 100%;
  max-width: 238px;
  height: auto;
  margin: 14px auto 0;
  border-radius: 12px;
}

.badge-milestone {
  /* Without this the circle is a flex child that shrinks, and the badge
     squashes into an oval as soon as the text beside it wraps. */
  flex: none;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--bt-surface-clay-badge);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--bt-font-emotional);
  font-weight: 500;
  font-size: 26px;
  color: #ffffff;
}

/* ---------- hero ---------- */

.hero {
  padding: clamp(40px, 7vw, 84px) clamp(20px, 5vw, 56px) clamp(48px, 8vw, 96px);
}

/* One column since the hero photograph came out. The copy carries its own
   max-width, so this only centres it on wide screens. */
.hero__inner {
  max-width: 1080px;
  margin: 0 auto;
}

/* Centred, not left-aligned, now that the photograph is gone. Left-aligned it
   left roughly 520px of empty canvas beside it on a desktop window, which reads
   as a missing image rather than a decision. The text inside stays left-aligned;
   only the block is centred. */
.hero__copy {
  display: flex;
  flex-direction: column;
  gap: var(--bt-space-xl);
  max-width: 520px;
  margin: 0 auto;
}

.hero__lead {
  font-family: var(--bt-font-ui);
  font-size: 18px;
  line-height: 1.6;
  color: var(--bt-text-secondary);
  max-width: 480px;
  margin: 0;
}

.hero__text {
  display: flex;
  flex-direction: column;
  gap: var(--bt-space-sm);
}

.hero__actions {
  display: flex;
  flex-direction: column;
  gap: var(--bt-space-md);
  margin-top: var(--bt-space-sm);
}


.caption {
  font-family: var(--bt-font-ui);
  font-size: var(--bt-size-caption);
  line-height: 1.5;
  color: var(--bt-text-caption);
  margin: 0;
}

/* ---------- emotional band ---------- */

.band {
  position: relative;
  width: 100%;
  overflow: hidden;
}

.band__photo {
  display: block;
  width: 100%;
  height: clamp(300px, 46vw, 560px);
  object-fit: cover;
  object-position: center 38%;
}

.band__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, rgba(43, 30, 20, 0) 42%, rgba(43, 30, 20, 0.58) 100%);
}

.band__quote {
  position: absolute;
  left: 0;
  right: 0;
  bottom: clamp(28px, 5vw, 64px);
  display: flex;
  justify-content: center;
  padding: 0 clamp(20px, 5vw, 56px);
}

.band__quote p {
  font-family: var(--bt-font-emotional);
  font-weight: 500;
  font-size: clamp(26px, 4.6vw, 46px);
  line-height: 1.22;
  color: var(--bt-bg-warm-white);
  text-align: center;
  margin: 0;
  max-width: 760px;
  text-shadow: 0 2px 20px rgba(0, 0, 0, 0.38);
}

/* ---------- features ---------- */

.features {
  padding: clamp(48px, 8vw, 88px) clamp(20px, 5vw, 56px);
  background: var(--bt-bg-warm-white);
}

.features__inner {
  max-width: 1080px;
  margin: 0 auto;
  display: flex;
  flex-wrap: wrap;
  gap: clamp(32px, 5vw, 64px);
  align-items: center;
  /* The phones and the feature list only fit side by side above ~1170px.
     Everywhere below that the row wraps, and without this the phones sit hard
     against the left edge with the dead space beside them. */
  justify-content: center;
}

/* One rendered image now, not two screenshots inside CSS-built phone frames.
   The device shells, the tilt, and the shadows are baked into it. It carries no
   alpha: the transparency was composited onto --bt-bg-warm-white, this
   section's background, so the soft shadows fade out invisibly. If that
   background ever changes, the image has to be re-exported with it. */
.phones {
  flex: 0 1 360px;
  display: flex;
  justify-content: center;
}

.phones__image {
  display: block;
  width: 100%;
  height: auto;
}

.features__list {
  flex: 1 1 440px;
  display: flex;
  flex-direction: column;
  gap: var(--bt-space-xl);
}

/* ---------- why join ---------- */

.why {
  padding: clamp(48px, 8vw, 96px) clamp(20px, 5vw, 56px);
}

.why__inner {
  max-width: 1000px;
  margin: 0 auto;
  display: flex;
  flex-wrap: wrap;
  gap: clamp(32px, 5vw, 64px);
  align-items: center;
}

.why__copy {
  flex: 1 1 360px;
  display: flex;
  flex-direction: column;
  gap: var(--bt-space-xl);
}

.why__lead {
  font-family: var(--bt-font-ui);
  font-size: 17px;
  line-height: 1.6;
  color: var(--bt-text-secondary);
  max-width: 560px;
  margin: 0;
}

.why__art {
  flex: 1 1 300px;
  /* Not the export's 260px floor: with the 1.2 zoom that floor is wider than
     the column at a 360px viewport, the most common Android width, and the
     photo spills past the page gutter. The flex basis already carries the
     intent. */
  min-width: 0;
}

.why__art img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--bt-radius-card);
  box-shadow: 0 24px 50px -28px rgba(74, 52, 36, 0.4);
}

/* ---------- sign-up ---------- */

.signup {
  padding: clamp(48px, 8vw, 96px) clamp(20px, 5vw, 56px) clamp(56px, 9vw, 104px);
}

.signup__card {
  max-width: 680px;
  margin: 0 auto;
  background: var(--bt-bg-white);
  border: 1px solid var(--bt-border-default);
  border-radius: var(--bt-radius-card);
  padding: clamp(32px, 5vw, 56px);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--bt-space-lg);
  text-align: center;
}

.signup__lead {
  font-family: var(--bt-font-ui);
  font-size: 17px;
  line-height: 1.6;
  color: var(--bt-text-secondary);
  max-width: 520px;
  margin: 0;
}

.signup__note {
  max-width: 480px;
  margin: var(--bt-space-xs) 0 0;
  line-height: 1.55;
}

/* ---------- android waitlist ---------- */

.android {
  padding: clamp(40px, 7vw, 64px) clamp(20px, 5vw, 56px);
  background: var(--bt-bg-warm-white);
  border-top: 1px solid var(--bt-border-default);
}

.android__inner {
  max-width: 560px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--bt-space-lg);
  text-align: center;
}

.android__lead {
  font-family: var(--bt-font-ui);
  font-size: 17px;
  line-height: 1.6;
  color: var(--bt-text-secondary);
  margin: 0;
}

/* ---------- footer ---------- */

.site-footer {
  padding: clamp(28px, 5vw, 44px) clamp(20px, 5vw, 56px) clamp(40px, 6vw, 64px);
  border-top: 1px solid var(--bt-border-default);
}

.site-footer__inner {
  max-width: 1080px;
  margin: 0 auto;
  display: flex;
  flex-wrap: wrap;
  gap: var(--bt-space-lg) var(--bt-space-xxl);
  align-items: center;
  justify-content: space-between;
}

.site-footer nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--bt-space-xxl);
}

.site-footer a {
  font-family: var(--bt-font-ui);
  font-size: var(--bt-size-caption);
  color: var(--bt-text-caption);
  text-decoration: none;
  /* These are tapped on a phone. The bare text line is about a third of the
     44pt floor, so the padding is the touch target. */
  display: inline-block;
  padding: 11px 4px;
  margin: -11px -4px;
}

.site-footer a:hover {
  color: var(--bt-text-primary);
}

.site-footer a:focus-visible {
  color: var(--bt-text-primary);
  text-decoration: underline;
  outline: 2px solid var(--bt-text-inspiration-title);
  outline-offset: 2px;
}

.site-footer p {
  font-family: var(--bt-font-ui);
  font-size: var(--bt-size-caption);
  color: var(--bt-text-caption);
  margin: 0;
}

/* ---------- the TestFlight hand-off modal ---------- */

/* Driven by :target, not JavaScript. Every CTA is a link to #beta-start, so the
   only route to conversion still works with scripts switched off. The trade-off
   is that Escape does not close it; the backdrop and the close button are the
   two ways out, and both are plain links. */
.modal {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 100;
  align-items: center;
  justify-content: center;
  padding: clamp(16px, 4vw, 40px);
  overflow-y: auto;
  /* Keeps a scroll that reaches the end of the dialog from chaining to the
     page behind, which would move her place on the page while she reads. */
  overscroll-behavior: contain;
}

.modal:target {
  display: flex;
}

.modal__backdrop {
  position: fixed;
  inset: 0;
  background: rgba(43, 30, 20, 0.5);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}

.modal__dialog {
  position: relative;
  /* Scoped, not a global reset: the page is authored against content-box, but
     a content-box max-height would cap the content and let the rendered box be
     max-height plus twice the padding, overflowing every viewport shorter than
     about 1000px. Because .modal centres its child, that overflow splits top
     and bottom and the top half cannot be scrolled back into view. */
  box-sizing: border-box;
  width: 100%;
  max-width: 520px;
  background: var(--bt-bg-white);
  border-radius: var(--bt-radius-card);
  box-shadow: 0 40px 80px -30px rgba(43, 30, 20, 0.5);
  font-family: var(--bt-font-ui);
  /* min() of the two units, not 92vh: on iOS, vh is the toolbars-hidden
     viewport while position: fixed sizes to the visible one, so 92vh alone
     renders a dialog taller than the screen and pushes the close control off
     the top edge, where scrollTop clamps at 0 and it cannot be recovered. */
  max-height: min(92vh, 92dvh);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* The scroll lives here, one level in, so the close control above it is
   positioned against the dialog and does not scroll away with the steps.
   The dialog's padding moved here with it, which keeps the sticky action
   block's negative margins bleeding to the same edge as before. */
.modal__scroll {
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: clamp(24px, 4vw, 40px);
}

.modal__close {
  position: absolute;
  z-index: 2;
  top: 16px;
  right: 16px;
  /* 44px, not the export's 40px. The modal sits outside .page, so the 1.2 zoom
     that lifts the rest of the page over the touch floor does not reach it. */
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--bt-bg-warm-white);
  color: var(--bt-text-caption);
  font-size: 20px;
  line-height: 1;
  text-decoration: none;
  display: flex;
  align-items: center;
  justify-content: center;
}

.modal__close:hover {
  color: var(--bt-text-primary);
}

.modal__body {
  display: flex;
  flex-direction: column;
  gap: var(--bt-space-lg);
}

.modal__intro {
  display: flex;
  flex-direction: column;
  gap: var(--bt-space-sm);
}

.modal__intro-lead {
  font-family: var(--bt-font-ui);
  font-size: 15px;
  line-height: 1.6;
  color: var(--bt-text-secondary);
  margin: 4px 0 0;
}

.modal__steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.modal__step {
  display: flex;
  gap: var(--bt-space-md);
  align-items: flex-start;
  padding: var(--bt-space-md) 0;
  border-bottom: 1px solid var(--bt-border-default);
}

.modal__step:last-child {
  border-bottom: none;
}

.modal__step-text {
  padding-top: 4px;
}

.modal__step-title {
  font-family: var(--bt-font-ui);
  font-weight: 600;
  font-size: 16px;
  line-height: 1.4;
  color: var(--bt-text-primary);
  margin: 0 0 4px;
}

.modal__step-body {
  font-family: var(--bt-font-ui);
  font-size: 15px;
  line-height: 1.6;
  color: var(--bt-text-secondary);
  margin: 0;
}

/* Pinned to the bottom of the dialog rather than sitting at the end of it. The
   three steps make the modal taller than a small phone: on a 375x667 screen
   about a third of it is below the fold, so the button that actually converts
   was 297px down inside a scroll container. The steps scroll under this; the
   button never leaves the screen. The negative margins let the white run to the
   dialog edges so scrolled content cannot show through the padding. */
.modal__actions {
  position: sticky;
  bottom: calc(-1 * clamp(24px, 4vw, 40px));
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--bt-space-sm);
  margin: 0 calc(-1 * clamp(24px, 4vw, 40px)) calc(-1 * clamp(24px, 4vw, 40px));
  padding: var(--bt-space-md) clamp(24px, 4vw, 40px) clamp(24px, 4vw, 40px);
  background: var(--bt-bg-white);
  box-shadow: 0 -12px 16px -12px rgba(43, 30, 20, 0.16);
}


.modal__cta {
  display: block;
  width: 100%;
  text-align: center;
  background: var(--bt-cta-fill);
  color: var(--bt-cta-text);
  font-family: var(--bt-font-ui);
  font-weight: 600;
  font-size: 16px;
  padding: 15px;
  border-radius: var(--bt-radius-pill);
  text-decoration: none;
}

.modal__actions p {
  font-family: var(--bt-font-ui);
  font-size: 14px;
  line-height: 1.5;
  color: var(--bt-text-caption);
  margin: 0;
}

@media (max-width: 640px) {
  .cta {
    display: flex;
    justify-content: center;
  }

  /* Centre the hero note under the centred button. Scoped to mobile: above
     640px the button is left-aligned inside the copy block and the note stays
     left with it, so both alignments always match the button. */
  .hero__note {
    text-align: center;
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
}
