/* ─────────────────────────────────────────────────────────────────────────────
   Contact landing page.
   Palette and shape mirror the application design tokens
   (frontend/projects/offer-engine-app/src/styles/tokens.scss) so the page reads
   as the same product. System fonts only: the page makes no network request
   beyond its own three files, which is the difference between loading and not
   loading on congested conference Wi-Fi.
   ───────────────────────────────────────────────────────────────────────────── */

:root {
  --bg:        #F3F7FB;
  --surface:   #FFFFFF;
  --border:    #E1E9F2;
  --border-s:  #C6D4E3;

  --txt-1: #1C2B3A;
  --txt-2: #4D6175;
  --txt-3: #8DA2B5;

  --primary:   #4A86C8;
  --primary-d: #3972B5;
  --navy:      #2D5F9E;

  --brand-teal: #00B87A;

  /* Brand panel, deepened well past the app's --navy so the white-and-green
     lockup carries. The app UI itself stays on the token palette; this is a
     marketing surface, and the token set has no shade dark enough for a logo
     to sit on. Both stops are the same steel-blue hue as --navy, just darker,
     so the page still reads as the same family.
     Deliberately not dark green: the mark's own green would lose contrast
     against it, which is the opposite of the point. */
  --panel-1: #0D2338;
  --panel-2: #1E4A78;

  --success:   #0FA974;
  --warning:   #E8A317;
  --warning-l: #FEF7E5;
  --danger:    #E84040;

  --radius:    10px;
  --radius-lg: 14px;

  --shadow-l: 0 12px 40px rgba(28, 43, 58, .15), 0 4px 12px rgba(28, 43, 58, .06);

  --tr: .18s cubic-bezier(.4, 0, .2, 1);

  --font: system-ui, -apple-system, 'Segoe UI', sans-serif;
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--font);
  color: var(--txt-1);
  background: var(--bg);
  line-height: 1.5;
  /* 16px floor on inputs stops iOS Safari zooming in on focus, which on a
     phone at a stand looks like the page breaking. */
  font-size: 16px;
}

/* ── Shell ─────────────────────────────────────────────────────────────── */

.shell {
  display: grid;
  grid-template-columns: 1fr;
  min-height: 100vh;
  /* Fall back gracefully: dvh accounts for mobile browser chrome. */
  min-height: 100dvh;
}

@media (min-width: 900px) {
  .shell { grid-template-columns: 1.05fr 1fr; }
}

/* ── Brand panel ───────────────────────────────────────────────────────── */

.brand {
  position: relative;
  overflow: hidden;
  color: #fff;
  /* Three layers, back to front:
       1. navy base, the panel's identity
       2. a deep wash of the brand green bleeding in from the bottom-right, low
          enough that it reads as a tint on the navy rather than a green panel
       3. a soft highlight at the top-left so the surface is not flat
     The green is the brand green rather than a generic dark green, so the tint
     belongs to the same family as the mark sitting on top of it. */
  background:
    radial-gradient(85% 65% at 100% 100%, rgba(4, 215, 128, .16) 0%, rgba(4, 215, 128, 0) 58%),
    radial-gradient(120% 90% at 12% 8%, rgba(255,255,255,.10) 0%, rgba(255,255,255,0) 60%),
    linear-gradient(150deg, var(--panel-1) 0%, var(--panel-2) 100%);
  padding: 40px 28px 44px;
  display: flex;
  align-items: center;
}

@media (min-width: 900px) {
  .brand { padding: 72px 64px; }
}

.brand-inner {
  position: relative;
  z-index: 1;
  max-width: 30rem;
  margin-inline: auto;
  width: 100%;
}

/* The lockup is a wide 94x22, so it needs more width than a square mark would
   to carry the same presence. */
.logo {
  display: block;
  width: 148px;
  height: auto;
  margin-bottom: 26px;
}

@media (min-width: 900px) {
  .logo { width: 170px; margin-bottom: 32px; }
}

.eyebrow {
  margin: 0 0 14px;
  font-size: .75rem;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: rgba(255,255,255,.72);
}

h1 {
  margin: 0 0 16px;
  font-size: clamp(1.75rem, 5.2vw, 2.75rem);
  font-weight: 700;
  letter-spacing: -.025em;
  line-height: 1.12;
  text-wrap: balance;
}

.lede {
  margin: 0;
  font-size: 1.0625rem;
  color: rgba(255,255,255,.88);
  max-width: 26rem;
}

.reassure {
  margin: 26px 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 9px;
}

.reassure li {
  position: relative;
  padding-left: 24px;
  font-size: .9375rem;
  color: rgba(255,255,255,.82);
}

/* Teal check drawn in CSS, so the list costs nothing to load. */
.reassure li::before {
  content: '';
  position: absolute;
  left: 2px; top: .45em;
  width: 9px; height: 5px;
  border-left: 2px solid var(--brand-teal);
  border-bottom: 2px solid var(--brand-teal);
  transform: rotate(-45deg);
}

/* Hidden on small screens: it would push the form below the fold, and getting
   to the form without scrolling is the whole point on a phone. */
.arc { display: none; }

@media (min-width: 900px) {
  /* Bleeds off the right edge on purpose, but sits clear of the bottom one so
     both endpoint dots stay on the panel and the arc reads as drawn rather
     than cropped. */
  .arc {
    display: block;
    position: absolute;
    right: -40px; bottom: 8px;
    width: 400px;
    color: rgba(255,255,255,.28);
    pointer-events: none;
  }
}

/* ── Form panel ────────────────────────────────────────────────────────── */

.panel {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 28px 20px 44px;
}

@media (min-width: 900px) {
  .panel { padding: 48px 56px; }
}

.card {
  position: relative;
  width: 100%;
  max-width: 26rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-l);
  padding: 28px 24px 24px;
}

@media (min-width: 900px) {
  .card { padding: 32px 30px 28px; }
}

.card-title {
  margin: 0 0 20px;
  font-size: 1.125rem;
  font-weight: 700;
  letter-spacing: -.015em;
}

/* ── Fields ────────────────────────────────────────────────────────────── */

.field { margin-bottom: 15px; }

label {
  display: block;
  margin-bottom: 6px;
  font-size: .8125rem;
  font-weight: 600;
  color: var(--txt-2);
}

.opt {
  font-weight: 500;
  color: var(--txt-3);
  text-transform: lowercase;
}

input, textarea {
  width: 100%;
  font: inherit;
  font-size: 1rem;
  color: var(--txt-1);
  background: var(--surface);
  border: 1px solid var(--border-s);
  border-radius: var(--radius);
  padding: 11px 13px;
  transition: border-color var(--tr), box-shadow var(--tr);
}

textarea { resize: vertical; min-height: 76px; }

input::placeholder, textarea::placeholder { color: var(--txt-3); }

input:focus-visible, textarea:focus-visible {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(74, 134, 200, .22);
}

input[aria-invalid='true'], textarea[aria-invalid='true'] {
  border-color: var(--danger);
}

.err {
  margin: 6px 0 0;
  font-size: .8125rem;
  color: var(--danger);
}

/* Honeypot: off-screen rather than display:none, because some bots skip
   fields that are not rendered at all. */
.hp {
  position: absolute;
  left: -9999px;
  width: 1px; height: 1px;
  overflow: hidden;
}

/* ── Submit ────────────────────────────────────────────────────────────── */

.submit {
  position: relative;
  width: 100%;
  margin-top: 6px;
  /* 48px keeps the target comfortable for a thumb. */
  min-height: 48px;
  font: inherit;
  font-size: 1rem;
  font-weight: 600;
  color: #fff;
  background: var(--primary);
  border: 0;
  border-radius: var(--radius);
  cursor: pointer;
  transition: background var(--tr), transform var(--tr);
}

.submit:hover  { background: var(--primary-d); }
.submit:active { transform: translateY(1px); }

.submit:focus-visible {
  outline: 2px solid var(--primary-d);
  outline-offset: 2px;
}

.submit[disabled] { opacity: .72; cursor: default; }
.submit[disabled]:active { transform: none; }

.spinner {
  display: none;
  position: absolute;
  top: 50%; left: 50%;
  width: 17px; height: 17px;
  margin: -9px 0 0 -9px;
  border: 2px solid rgba(255,255,255,.4);
  border-top-color: #fff;
  border-radius: 50%;
  animation: spin .7s linear infinite;
}

.submit.busy .submit-label { visibility: hidden; }
.submit.busy .spinner      { display: block; }

@keyframes spin { to { transform: rotate(360deg); } }

.fineprint {
  margin: 4px 0 14px;
  font-size: .75rem;
  color: var(--txt-3);
  text-align: center;
}

/* ── Done state ────────────────────────────────────────────────────────── */

.done { text-align: center; padding: 12px 0 6px; }

.tick {
  width: 52px; height: 52px;
  margin: 0 auto 18px;
  display: grid;
  place-items: center;
  color: var(--success);
  background: #EDFBF5;
  border: 1px solid rgba(15, 169, 116, .35);
  border-radius: 50%;
}

.tick svg { width: 26px; height: 26px; }

.done h2 {
  margin: 0 0 8px;
  font-size: 1.25rem;
  font-weight: 700;
  letter-spacing: -.015em;
}

.done p {
  margin: 0;
  font-size: .9375rem;
  color: var(--txt-2);
}

/* Queued-offline variant: same layout, amber instead of green, so the
   difference is visible without a second block of markup. */
.done.queued .tick {
  color: var(--warning);
  background: var(--warning-l);
  border-color: rgba(232, 163, 23, .35);
}

.again {
  margin-top: 22px;
  font: inherit;
  font-size: .875rem;
  font-weight: 600;
  color: var(--primary-d);
  background: none;
  border: 0;
  padding: 8px 4px;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.again:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
  border-radius: 4px;
}

/* ── Status line ───────────────────────────────────────────────────────── */

.status {
  margin: 14px 0 0;
  font-size: .8125rem;
  text-align: center;
  color: var(--danger);
  min-height: 1.2em;
}

/* Deliberately NOT display:none when empty. This is the only channel for the
   429 and "cannot save locally" messages, and a live region that is display:none
   at the moment it updates is announced unreliably or not at all. The reserved
   min-height above keeps the empty state from shifting the layout anyway. */

/* ── Motion ────────────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  /* The spinner is the only signal that a submission is in flight, so keep it
     turning, just slowly enough not to trigger motion sensitivity. */
  .spinner { animation-duration: 1.6s !important; animation-iteration-count: infinite !important; }
}
