/* ---------------------------------------------------------------------------
   components.css — the marketing site's primitive layer.

   The same split the app uses: this file holds things that know nothing about
   the page they are on (a button, an eyebrow, the type scale, the container),
   and landing.css holds the composites that know nothing about each other (the
   nav, the footer, a section).

   Colours come from /styles/brand.css and measurements from /styles/layout.css,
   both overlaid from hosting_shared/. Nothing here spells a colour or a
   container width of its own — test/core/utils/brand_css_parity_test.dart
   fails the build on a raw hex or a local :root anywhere under
   hosting_landing/, which is the rule CLAUDE.md states in prose made into a
   gate.

   Figma file 76n6btvsYu0t6AG5VZ353t. Classes that implement a named Figma
   component carry the node id, per the widget-origin convention.
   --------------------------------------------------------------------------- */

/* ── Page frame ────────────────────────────────────────────────────────────
   The gutter sits on the section and the cap sits on the container, which is
   how the Figma frames are built: a full-bleed section with px-64, holding a
   max-w-1280 column. Writing it the other way round — cap and padding on one
   element — silently narrows the content to 1152 and every measurement in the
   file drifts by 128px. */
.container {
  width: 100%;
  max-width: var(--container-large);
  margin-inline: auto;
}

.section {
  padding-inline: var(--page-padding);
  padding-block: var(--section-pad-lg);
}

.section--tight { padding-block: var(--section-pad-md); }

/* ── Type scale ────────────────────────────────────────────────────────────
   Measured off the marketing frames rather than invented. Each class sets its
   own weight and tracking because brand.css declares a global
   `h1, h2, h3 { font-weight: 800; letter-spacing: -0.2px }` that serves the
   admin dashboard and the legal pages — the marketing headings are Nunito 700
   at no tracking, and a class beats an element selector, so they are overridden
   here rather than by loosening a rule three other surfaces depend on. */
.display,
.h-cta,
.h-showcase,
.h-section,
.h-card,
.h-step,
.h-name,
.h-strip {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: normal;
  color: var(--ink);
  margin: 0;
}

.display    { font-size: 80px; line-height: 88px; }
.h-cta      { font-size: 64px; line-height: 1.2; }
.h-showcase { font-size: 40px; line-height: 1.2; }
.h-section  { font-size: 56px; line-height: 1.1; }
.h-card     { font-size: 32px; line-height: 1.3; }
.h-step     { font-size: 28px; line-height: 1.3; }
.h-name     { font-size: 24px; line-height: 1.5; }
.h-strip    { font-size: 18px; line-height: 1.3; }

.lede {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 22px;
  line-height: 1.5;
  color: var(--muted);
  margin: 0;
}

.body-lg,
.body {
  font-family: var(--font-body);
  font-weight: 400;
  line-height: 1.5;
  color: var(--neutral-mid);
  margin: 0;
}

.body-lg { font-size: var(--text-lg); }
.body    { font-size: var(--text-md); }

/* Figma: Eyebrow — the small uppercase label above a section heading, and the
   footer's link row, which is the same treatment rather than a nav style. */
.eyebrow {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: var(--text-sm);
  line-height: 24px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--neutral-300);
  margin: 0;
}

/* Every display heading on the site carries one of these on the phrase being
   emphasised. Clipping a gradient to text has no fallback worth writing: where
   background-clip:text is unsupported the transparent fill would leave the
   words invisible, so the colour is only dropped inside the @supports. */
.grad-text { color: var(--child-primary); }

@supports (background-clip: text) or (-webkit-background-clip: text) {
  .grad-text {
    background-image: var(--gradient-heading);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }

  /* The hero is the one place the three-stop display gradient belongs: it has
     two 88px lines to run down, which is the height that ramp was drawn for.
     Everywhere else the phrase is a single 42px line and the third stop reads
     as a red edge rather than depth. The contact card's "us" takes it too:
     it is 64px on a dark ground, which is the other place the ramp has enough
     height to read as depth rather than as an edge. */
  .display .grad-text,
  .h-cta .grad-text { background-image: var(--gradient-display); }
}

/* ── Buttons ─────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  height: 40px;
  padding-inline: 14px;
  border: 0;
  border-radius: var(--radius-12);
  font-family: var(--font-body);
  font-weight: 600;
  font-size: var(--text-md);
  line-height: 22px;
  letter-spacing: -0.006em;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: transform 0.15s ease, box-shadow 0.15s ease, filter 0.15s ease;
}

/* Figma: Buttons [1.1] — node 1414:205365 */
.btn--primary {
  background: var(--brand-dark);
  color: var(--card);
}

/* Figma: Buttons [1.1] — node 1491:226174, the contact form's Send. The one
   filled accent on the site that is not the adult indigo: it is the action on
   a card whose heading is already the child gradient, and it is slot 1, so it
   is --child-primary and never a ramp step. Taller than the nav's button
   because the design pads it 14/10 rather than sitting it on a 40px rail. */
.btn--child {
  height: 50px;
  padding-inline: 10px;
  background: var(--child-primary);
  color: var(--card);
}

/* The frames are static, so there is no designed hover. brightness() is used
   rather than a second fill because it gives every variant the same response
   without adding an accent token per button — and a new flat accent is exactly
   what the slot model exists to stop. */
.btn:hover {
  filter: brightness(0.92);
  transform: translateY(-1px);
  box-shadow: var(--shadow-brand);
}

.btn:active {
  filter: brightness(0.88);
  transform: translateY(0);
  box-shadow: none;
}

/* ── Card ──────────────────────────────────────────────────────────────────
   Figma: Card — nodes 1491:225847, 1491:225861, 1491:225892, 1491:225917 and
   the four step cards. One white surface, one hairline, one radius. The
   overflow clip is load-bearing rather than tidy: every card whose artwork
   bleeds relies on it, and so does the media panel whose own corners are
   square. */
.card {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--border-card);
  border-radius: var(--radius-40);
  background: var(--card);
}

.card__body {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 32px;
}

/* A card whose artwork sits below the copy pays its bottom padding in the art
   instead — the illustration is drawn with its own margin. */
.card__body--flush { padding-bottom: 0; }

.card__tagline {
  display: flex;
  align-items: center;
  gap: 12px;
}

.card__text {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* The artwork is exported with its background already flattened onto the
   card's white, because Figma's node render bakes the surface behind it in
   either way — see the Stage 1 note on the logo sphere. It is only correct on
   a white card, which is the only place it is used. */
.card__art {
  display: block;
  width: 100%;
  height: auto;
  margin-top: auto;
}

/* Figma: icon_wrapper — 40x40 holding a 24px glyph. Indigo by default: this is
   the parental-controls voice, which CLAUDE.md keeps at terciary/500 on kid
   surfaces too. The two cards that speak in the child's voice take --child
   instead, and that is a copy decision rather than a viewer-accent one. */
.icon-bubble {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-12);
  background: var(--tertiary-tint);
}

.icon-bubble--child { background: var(--child-surface); }

/* The comparison table draws the same 40x40 bubble as a circle, and adds a
   third fill: --surface for the rows where the answer is "no". The shape
   carries no meaning on its own — the row header and the visually-hidden
   Yes/No are what a screen reader reads — so the colour pair is free to be
   the audience's rather than a semantic red/green. */
.icon-bubble--round { border-radius: var(--radius-full); }
.icon-bubble--muted { background: var(--surface); }

.icon-bubble img {
  display: block;
  width: 24px;
  height: 24px;
}

/* Figma: Buttons [1.1] — node 1414:205005. Label plus a 20px arrow and no
   fill. Taller than the filled button (50 against 40) because it carries the
   arrow, and the design gives it the padding rather than the label. */
.btn--text {
  height: 50px;
  padding-inline: 14px;
  background: transparent;
  color: var(--tertiary-deep);
}

/* The lift and the shadow belong to a filled button; on a transparent one they
   read as a stray rectangle. The arrow moves instead, which is what the label
   is promising. */
.btn--text:hover,
.btn--text:active {
  filter: none;
  transform: none;
  box-shadow: none;
}

.btn__arrow {
  display: block;
  width: 20px;
  height: 20px;
  transition: transform 0.15s ease;
}

.btn--text:hover .btn__arrow { transform: translateX(3px); }

/* Figma: Buttons [1.1] — node 1533:43156. The team cards' LinkedIn pill: a
   white chip on a white card, so the hairline and the x-small shadow are the
   only things separating it from the surface. Its 30px height is 4 + 22 + 4
   rather than a rail, which is why it overrides .btn rather than extending
   it. */
.btn--outline {
  height: 30px;
  gap: 2px;
  padding-inline: 6px;
  border: 1px solid var(--border);
  border-radius: var(--radius-8);
  background: var(--card);
  color: var(--tertiary-deep);
  font-size: var(--text-sm);
  box-shadow: var(--shadow-xs);
}

.btn--outline img {
  display: block;
  width: 20px;
  height: 20px;
}

/* The label sits in its own 4px-padded box in the design, which is what keeps
   the 2px gap from reading as the icon touching the text. */
.btn--outline span { padding-inline: 4px; }

/* Figma: Badges — node 1338:171862. Deliberately an <img> and not a link:
   there is no store listing yet, and a badge that navigates nowhere is worse
   than one that plainly does not invite a tap. The two are different widths
   because the official artwork is — 170 for Apple, 192 for Google — so the
   height is what matches, never the width. */
.store-badge {
  display: block;
  height: 56px;
  width: auto;
}

/* ── Form fields ───────────────────────────────────────────────────────────
   Figma: Text input — node 1491:226167, Text Area — node 1491:226173. Only
   the CTA card uses these, and only on its dark gradient, which is why the
   fill and the border are white at low alpha rather than a surface and a
   hairline: there is no light-background variant to keep them honest against.

   `font: inherit` is doing real work — a bare <input> takes the UA's font at
   13px, so without it the placeholder is a different family and size from the
   label two pixels above it. */
.field {
  width: 100%;
  height: 48px;
  padding: 12px;
  border: 1px solid var(--field-border);
  border-radius: var(--radius-12);
  background: var(--field-fill);
  color: var(--card);
  font: inherit;
  font-family: var(--font-body);
  font-size: var(--text-md);
  line-height: 1.5;
}

.field--area {
  height: 140px;
  /* Vertical only: the field is in a flex column that owns its width, and a
     horizontal drag would push it out of the card. */
  resize: vertical;
}

.field::placeholder { color: var(--field-placeholder); }

/* The dark card is outside the page's light palette, so the shared indigo
   focus ring has almost no contrast against it. White is the only thing on
   this surface that does. */
.field:focus-visible {
  outline: 2px solid var(--card);
  outline-offset: 2px;
}

.field-label {
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--text-md);
  line-height: 1.5;
  color: var(--card);
}

/* ── Rules ───────────────────────────────────────────────────────────────── */
.divider {
  height: 1px;
  border: 0;
  margin: 0;
  background: var(--border-card);
}

/* ── Accessibility ─────────────────────────────────────────────────────────
   The nav is fixed, so an in-page anchor lands under it without a scroll
   margin; :target and scroll-padding are set on the root in landing.css. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip-link {
  position: fixed;
  top: 8px;
  left: 8px;
  z-index: 100;
  padding: 10px 16px;
  border-radius: var(--radius-8);
  background: var(--card);
  color: var(--ink);
  font-family: var(--font-body);
  font-weight: 600;
  font-size: var(--text-sm);
  text-decoration: none;
  box-shadow: var(--shadow-card);
  transform: translateY(-200%);
}

.skip-link:focus-visible { transform: translateY(0); }

:where(a, button, [tabindex]):focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 3px;
  border-radius: var(--radius-8);
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ── The scale's steps ─────────────────────────────────────────────────────
   The full responsive pass is Stage 4. These live here because they are part
   of the type scale rather than part of any one layout, and because a shell
   that renders an 80px heading on a 375px screen is not deployable — which is
   what Stage 1 owes. The two named breakpoints match layout.css's, so the
   gutters and the type step together. */
@media (max-width: 1279px) {
  .display   { font-size: 64px; line-height: 1.1; }
  .h-cta      { font-size: 52px; }
  .h-showcase { font-size: 34px; }
  .h-section  { font-size: 48px; }
  .lede      { font-size: 20px; }
}

@media (max-width: 767px) {
  /* The official artwork is 170 + 192 wide and the pair plus its gap needs
     378px, which overflows a 390px screen before the gutters are paid for.
     The height is the only dimension that is ours to set, and wrap is the
     backstop for the narrower phones below 360. */
  .store-badge { height: 46px; }

  .display   { font-size: 40px; }
  .h-cta      { font-size: 34px; }
  .h-showcase { font-size: 26px; }
  .h-section  { font-size: 32px; }
  .h-card    { font-size: 26px; }
  .h-step    { font-size: 24px; }
  .lede      { font-size: 18px; }
}

/* ── The scale's steps, on height ──────────────────────────────────────────
   The width steps above, turned ninety degrees. The hero is the section that
   needs this first: two columns competing for one window, where the right-hand
   one is a 591px product shot that cannot give much and the left-hand one is
   an 80px heading that can.

   Stepped rather than tapered continuously, which is where this parts company
   with the rhythm tokens in layout.css. A padding is space and reads the same
   at any value; a typeface has drawn weights and fitted curves, and a heading
   at 58.3px is a heading nobody specified. Two steps, both of them a size
   somebody chose.

   Below the fold the reason is different from the hero's and worth saying,
   because it is what the second step is for: nothing down there is being
   fitted into a window, but a 56px section heading in a 720px window is a
   thirteenth of everything visible, and the page reads as though it is
   shouting. Section headings therefore come down with the display, one step
   later than it does.

   Gated from 1024 up for the same reason the rhythm is. Below that the layout
   is one stacked column and the page simply scrolls — there is no fold being
   fitted into, so type shrunk on height there is type shrunk for nothing. */
@media (min-width: 1024px) and (max-height: 860px) {
  .display    { font-size: 64px; line-height: 1.1; }
  .lede       { font-size: 20px; }
  .h-cta      { font-size: 58px; }
  .h-section  { font-size: 50px; }
  .h-showcase { font-size: 36px; }
  .h-card     { font-size: 30px; }
  .h-step     { font-size: 26px; }
}

/* Under ~720 the heading has to come down past the width scale's own step,
   and everything below the fold comes with it. */
@media (min-width: 1024px) and (max-height: 720px) {
  .display    { font-size: 52px; }
  .lede       { font-size: 18px; }
  .h-cta      { font-size: 48px; }
  .h-section  { font-size: 44px; }
  .h-showcase { font-size: 32px; }
  .h-card     { font-size: 28px; }
  .h-step     { font-size: 24px; }
  .h-name     { font-size: 22px; }
}
