/* Mecavoy pre-launch — shared stylesheet.
 *
 * External rather than inline so the CloudFront CSP stays strict.
 *
 * Palette and type are taken from the Mecavoy brand: navy #2E3A7D on warm
 * cream, chunky serif display over a geometric-humanist sans. The page is
 * deliberately single-theme — the identity IS cream, so a dark variant would
 * be a different brand, not the same one after dark. Every colour is painted
 * explicitly so the page holds on any host background.
 *
 * Both faces are self-hosted (see fonts.css). Nothing is fetched from a third
 * party, which is why the CSP has no external origins at all — so the opening
 * sequence below had to be built out of what these two faces and CSS can do,
 * not out of a webfont bought in for the occasion.
 */

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

:root{
  /* ── brand ─────────────────────────────────────────────────────────── */
  --navy:#2E3A7D;
  --navy-deep:#232C60;
  --navy-tint:rgba(46,58,125,.08);

  /* ── warm cream ground ─────────────────────────────────────────────── */
  --ground:#EFE3CF;
  --card:#F5EAD8;
  --raised:#FBF5EA;
  --line:#E3D3B8;
  --line-soft:#EADCC4;

  /* Borders on interactive controls, not decoration. On a cream ground the
     soft --line above is ~1.3:1, and the input's fill is near-identical to the
     card behind it — so the border is the ONLY thing saying "this is a field".
     WCAG 2.2 asks for 3:1 on control boundaries; this is 3.9:1. */
  --control-line:#7C7466;

  /* ── text ── values lifted from the email design, not eyeballed ────── */
  --ink:#201E1D;
  --body:#4A4441;
  --muted:#6D6560;
  --navy-light:#3B4788;   /* eyebrow labels */
  --bullet:#6470AA;       /* list markers */
  --struck:#8F857C;       /* the crossed-out price */

  --ok:#2F7D55;
  --err:#B4352B;

  --display:"Caprasimo",Georgia,"Times New Roman",Times,serif;
  --sans:"Figtree",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;

  --ease:cubic-bezier(.22,.61,.36,1);
  --radius:24px;

  /* ── the opening sequence ──────────────────────────────────────────────
     One timeline, declared once, so the beats can be re-timed without hunting
     through the file. Durations are long on purpose: the mark is meant to
     surface rather than pop, and the rise is weighted — a fast start into a
     long settle, which is what reads as heavy rather than bouncy. */
  --in-mark:1.6s;         /* the mark resolving out of blur              */
  --in-rise:1.35s;        /* mark shrinking while the page opens beneath */
  --in-step:.85s;         /* each line of copy arriving                  */

  --at-rise:1.85s;
  --at-rule:2s;
  --at-tag:2.25s;
  --at-soon:2.55s;
  --at-surprise:2.85s;
  --at-field:3.1s;
  --at-consent:3.28s;
  --at-fine:3.5s;
  --at-foot:3.6s;

  /* How much larger the mark is at rest in the centre of the screen. Scale,
     not width: a transform costs no layout, so the card underneath keeps its
     real size and the composition stays centred on its own without measuring
     anything. */
  --intro-scale:2.3;

  --ease-surface:cubic-bezier(.2,.6,.25,1);   /* out of the blur */
  --ease-rise:cubic-bezier(.22,.68,0,1);      /* the weighted lift */
  --ease-soft:cubic-bezier(.25,.8,.3,1);
}

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

body{
  margin:0;
  min-height:100svh;
  background:var(--ground);
  color:var(--body);
  font-family:var(--sans);
  font-size:16px;
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  display:flex;
  flex-direction:column;
  overflow-x:hidden;
}

/* ── layout ─────────────────────────────────────────────────────────────── */
/* auto margins rather than justify-content:center — when the content is taller
   than the viewport, centring clips the top out of reach; auto margins don't. */
.wrap{
  flex:1 0 auto;
  display:flex;flex-direction:column;align-items:center;
  width:100%;max-width:640px;margin:0 auto;
  padding-block:clamp(28px,6vh,64px);
  padding-left:20px;padding-right:20px;
}

/* The card echoes the email layout, so the page and the messages people get
   afterwards read as one piece rather than two. Its fill arrives with the
   reveal — before that the mark stands alone on the bare cream. */
.card{
  width:100%;
  margin-block:auto;
  padding:clamp(30px,5vw,48px);
  background:var(--card);
  border-radius:var(--radius);
  text-align:center;
}
/* The sequence is scoped to the home page. subscribed.html, unsubscribed.html,
   confirmed.html and oops.html all share this stylesheet, and an unscoped delay
   would leave those pages blank for three seconds for no reason — they are
   landed on, not watched, and oops.html is landed on by somebody who is already
   having a worse time than they expected. */
body.home > .wrap > .card{
  animation:card-fill var(--in-rise) var(--at-rise) var(--ease-rise) both;
}

/* ══ opening sequence ═══════════════════════════════════════════════════════
   Every animation below is ADDITIVE: the resting state is the normal state and
   the keyframes only supply the hidden `from` frame. If animations never run —
   an old browser, a stripped stylesheet, a reader mode — the page renders
   complete and static instead of blank. That is also why nothing here is
   driven by JavaScript: the sequence plays with scripting off.            */

@keyframes card-fill{
  from{background-color:rgba(245,234,216,0)}
  to  {background-color:var(--card)}
}

/* Two animations on one element: `mark-surface` owns the transform until
   `mark-settle` starts at --at-rise, and the later entry in the list wins for
   the properties they share. */
@keyframes mark-surface{
  from{opacity:0;filter:blur(30px);transform:scale(calc(var(--intro-scale) * 1.06))}
  to  {opacity:1;filter:blur(0);   transform:scale(var(--intro-scale))}
}
@keyframes mark-settle{
  from{transform:scale(var(--intro-scale))}
  to  {transform:scale(1)}
}

/* The whole trick of the sequence. The row opens from 0fr, so until it does,
   the card is nothing but the mark and its own padding — which the auto
   margins centre in the viewport. As the row takes its space the card grows
   downward and the mark rises to the top. Nothing is measured or positioned. */
@keyframes open-rows{
  from{grid-template-rows:0fr}
  to  {grid-template-rows:1fr}
}
@keyframes rise{
  from{opacity:0;transform:translateY(20px)}
  to  {opacity:1;transform:none}
}
@keyframes from-right{
  from{opacity:0;transform:translateX(26px)}
  to  {opacity:1;transform:none}
}
@keyframes draw-rule{
  from{transform:scaleX(0)}
  to  {transform:scaleX(1)}
}
@keyframes fade{
  from{opacity:0}
  to  {opacity:1}
}

/* ── brand lockup ───────────────────────────────────────────────────────── */
.brand{display:flex;flex-direction:column;align-items:center}
.brand img{display:block;width:clamp(150px,30vw,186px);height:auto}
body.home .mark{
  transform-origin:50% 50%;
  will-change:transform,filter;
  animation:
    mark-surface var(--in-mark) var(--ease-surface) both,
    mark-settle  var(--in-rise) var(--at-rise) var(--ease-rise) both;
}
/* The logo bitmap includes the descender of the 'y', so its box sits lower
   than the visual baseline. Pull the rule up to compensate. */
.brand .rule{
  display:block;width:52px;height:6px;margin-top:6px;
  background:var(--navy);border-radius:3px;
  transform-origin:50% 50%;
}
body.home .brand .rule{animation:draw-rule .7s var(--at-rule) var(--ease-rise) both}

/* ── the reveal ─────────────────────────────────────────────────────────── */
.reveal{
  display:grid;
  grid-template-rows:1fr;
}
body.home .reveal{animation:open-rows var(--in-rise) var(--at-rise) var(--ease-rise) both}
/* The 0fr row needs a clipping child, and clipping is both-axis in CSS — so
   the box is widened past the card and padded back in, which gives the field
   and the consent line room to travel in from the right without being cut. */
.reveal-clip{
  overflow:hidden;min-height:0;
  margin-inline:-30px;padding-inline:30px;
}

/* ── display type ───────────────────────────────────────────────────────── */
/* Caprasimo ships one weight and is heavy already — asking for 700+ makes the
   browser synthesise a fake bold and the letterforms go muddy. The negative
   tracking is the one liberty taken with it: at display size the default
   fitting opens up, and pulling it back is what makes it read as set rather
   than typed. */
h1,h2{
  font-family:var(--display);
  color:var(--ink);
  font-weight:400;
  line-height:1.15;
  margin:0;
  text-wrap:balance;
}
h2{font-size:clamp(22px,3.4vw,25px);letter-spacing:0}

.tagline{
  margin:30px auto 0;max-width:18ch;
  font-size:clamp(27px,5.6vw,42px);
  line-height:1.1;
  letter-spacing:-.014em;
}
body.home .tagline{animation:rise var(--in-step) var(--at-tag) var(--ease-soft) both}

/* Tracked small caps between hairlines — the quiet counterweight to the serif
   above it. The negative right margin puts the trailing letter-space back, so
   the line is optically centred rather than mathematically centred. */
.soon{
  display:flex;align-items:center;justify-content:center;gap:clamp(10px,3vw,16px);
  margin:20px 0 0;
}
body.home .soon{animation:rise var(--in-step) var(--at-soon) var(--ease-soft) both}
.soon::before,.soon::after{
  content:"";flex:none;height:1px;width:clamp(20px,9vw,54px);
  background:var(--line-soft);
}
.soon span{
  font-size:11.5px;font-weight:800;
  letter-spacing:.3em;margin-right:-.3em;
  text-transform:uppercase;color:var(--navy);
}

.lede{
  margin:16px auto 0;
  font-size:clamp(15px,1.9vw,16.5px);
  color:var(--body);
  text-wrap:pretty;
  max-width:46ch;
}

.eyebrow{
  font-family:var(--sans);
  font-size:12px;font-weight:800;
  letter-spacing:.16em;text-transform:uppercase;
  color:var(--navy-light);
}

/* ── the surprise ───────────────────────────────────────────────────────── */
/* <details> rather than a button: it opens with scripting off, which the CSP
   and the no-JS signup path both already depend on elsewhere. */
.surprise{margin:32px 0 0}
body.home .surprise{animation:rise var(--in-step) var(--at-surprise) var(--ease-soft) both}
.surprise > summary{
  list-style:none;cursor:pointer;
  display:inline-flex;align-items:center;gap:10px;
  padding:13px 22px;
  border:1.5px solid var(--navy);border-radius:999px;
  background:var(--raised);color:var(--navy);
  font-size:14.5px;font-weight:700;letter-spacing:.005em;
  position:relative;overflow:hidden;
  transition:background-color .22s var(--ease),color .22s var(--ease);
}
.surprise > summary::-webkit-details-marker{display:none}
.surprise > summary::marker{content:""}
.surprise > summary:hover{background:var(--navy);color:var(--raised)}
.surprise > summary:focus-visible{outline:2px solid var(--navy);outline-offset:3px}
.surprise .spark,.surprise .chev{display:flex;flex:none}
.surprise .chev{transition:transform .3s var(--ease)}
.surprise[open] > summary .chev{transform:rotate(180deg)}
.surprise[open] > summary{background:var(--navy);color:var(--raised)}

/* A slow pass of light across the pill. Long cycle, short sweep — present
   enough to say "press me", not so present that it nags. */
body.home .surprise > summary::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(105deg,transparent 40%,rgba(255,255,255,.62) 50%,transparent 60%);
  transform:translateX(-130%);
  animation:sheen 5.6s var(--at-surprise) var(--ease-soft) infinite;
}
.surprise[open] > summary::after{animation:none}
@keyframes sheen{
  0%,74%{transform:translateX(-130%)}
  100%  {transform:translateX(130%)}
}

@keyframes offer-open{
  from{opacity:0;transform:translateY(-12px) scale(.985)}
  to  {opacity:1;transform:none}
}

/* ── the Plus offer ──────────────────────────────────────────────────────── */
.offer{
  margin:18px 0 0;padding:26px 24px;
  background:var(--raised);
  border:1px solid var(--line);
  border-radius:20px;
  text-align:center;
}
/* Only when it is actually being opened — on subscribed.html the offer box is
   just part of the page and should not fade itself in. */
.surprise[open] > .offer{animation:offer-open .55s var(--ease-soft) both}
.price{
  display:flex;align-items:baseline;justify-content:center;gap:13px;
  margin:12px 0 0;
  font-family:var(--display);
  line-height:1;
}
.price .was{
  font-family:var(--sans);
  font-size:clamp(24px,4.2vw,30px);font-weight:600;
  color:var(--struck);text-decoration:line-through;
  text-decoration-thickness:2px;
}
.price .now{
  font-size:clamp(46px,9vw,68px);font-weight:400;
  color:var(--navy);letter-spacing:0;
}
.offer p{
  margin:14px auto 0;max-width:40ch;
  font-size:13.5px;line-height:1.55;color:var(--body);
}
.offer strong{font-weight:700;color:var(--ink)}

/* The offer's own terms line. Small, tracked and quiet: it has to be findable
   without competing with the price above it. */
.offer .terms{
  margin:16px auto 0;padding-top:14px;
  border-top:1px solid var(--line);
  font-size:10.5px;font-weight:700;
  letter-spacing:.1em;margin-right:-.1em;
  text-transform:uppercase;
}
/* This sheet has no global `a` rule, so anchors are styled where they appear.
   Without these two the links fall back to browser blue on a cream ground. */
.offer .terms a,.fine a{
  color:var(--muted);text-decoration:underline;text-underline-offset:2px;
  text-decoration-thickness:1px;
}
.offer .terms a:hover,.fine a:hover{color:var(--navy)}
.offer .terms a:focus-visible,.fine a:focus-visible{
  outline:2px solid var(--navy);outline-offset:2px;border-radius:2px;
}

/* ── form ───────────────────────────────────────────────────────────────── */
form{margin:30px 0 0;width:100%}

.field{
  display:flex;gap:7px;
  width:100%;padding:6px;
  background:var(--raised);
  border:1.5px solid var(--control-line);border-radius:13px;
  transition:border-color .18s var(--ease),box-shadow .18s var(--ease);
}
body.home .field{animation:from-right var(--in-step) var(--at-field) var(--ease-rise) both}
.field:focus-within{
  border-color:var(--navy);
  box-shadow:0 0 0 4px var(--navy-tint);
}

input[type=email]{
  flex:1 1 auto;min-width:0;
  padding:12px 14px;
  background:transparent;border:0;outline:none;
  color:var(--ink);font:inherit;font-size:15px;font-weight:500;
  text-align:left;
}
input[type=email]::placeholder{color:var(--muted);font-weight:400}
input[type=email]:focus-visible{outline:none}
input[type=email]:-webkit-autofill{
  -webkit-text-fill-color:var(--ink);
  -webkit-box-shadow:0 0 0 40px var(--raised) inset;
}

button{
  flex:none;
  padding:12px 24px;
  border:0;border-radius:9px;
  background:var(--navy);color:var(--raised);
  font-family:var(--sans);font-size:14.5px;font-weight:700;letter-spacing:.01em;
  cursor:pointer;white-space:nowrap;
  transition:background .16s var(--ease),transform .16s var(--ease),opacity .16s var(--ease);
}
button:hover:not(:disabled){background:var(--navy-deep)}
button:active:not(:disabled){transform:translateY(1px)}
button:disabled{opacity:.55;cursor:default}
button:focus-visible{outline:2px solid var(--navy);outline-offset:3px}

/* ── consent ────────────────────────────────────────────────────────────── */
/* A checkbox, not a radio pair, and never pre-ticked: GDPR requires consent to
   be an unambiguous affirmative action, and a pre-selected control is not one
   (CJEU, Planet49). The wording here is stored verbatim with every record. */
.consent{
  display:flex;align-items:flex-start;gap:11px;
  width:100%;margin:15px 0 0;padding:0 2px;
  cursor:pointer;text-align:left;
  font-size:12.5px;line-height:1.5;color:var(--muted);
}
body.home .consent{animation:from-right var(--in-step) var(--at-consent) var(--ease-rise) both}
.consent input[type=checkbox]{
  appearance:none;-webkit-appearance:none;
  flex:none;width:18px;height:18px;margin:1px 0 0;
  border:1.5px solid var(--control-line);border-radius:5px;
  background:var(--raised);
  cursor:pointer;
  transition:background-color .15s var(--ease),border-color .15s var(--ease);
}
.consent input[type=checkbox]:hover{border-color:var(--navy)}
.consent input[type=checkbox]:checked{
  background-color:var(--navy);
  border-color:var(--navy);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23FBF5EA' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 L9 17 L4 12'/%3E%3C/svg%3E");
  background-size:13px;background-position:center;background-repeat:no-repeat;
}
.consent input[type=checkbox]:focus-visible{outline:2px solid var(--navy);outline-offset:3px}
.consent a{color:var(--navy);text-decoration:underline;text-underline-offset:2px}

/* ── the email and marketing policy ─────────────────────────────────────── */
/* A <details> rather than a link to another page: consent has to be specific
   and informed, and the specifics only count if they are readable at the moment
   of ticking. It needs no JavaScript, which the CSP and the no-JS signup path
   both already depend on. Indented to the consent text, not the checkbox. */
.policy{margin:8px 0 0 29px;text-align:left}
.policy > summary{
  list-style:none;cursor:pointer;display:inline-block;
  font-size:12px;font-weight:700;color:var(--navy);
  text-decoration:underline;text-underline-offset:2px;
}
.policy > summary::-webkit-details-marker{display:none}
.policy > summary::marker{content:""}
.policy > summary:hover{color:var(--navy-deep)}
.policy > summary:focus-visible{outline:2px solid var(--navy);outline-offset:3px;border-radius:3px}
.policy p{
  margin:8px 0 0;max-width:48ch;
  font-size:12px;line-height:1.55;color:var(--muted);
}
.policy[open] > p{animation:offer-open .4s var(--ease-soft) both}
body.home .policy{animation:from-right var(--in-step) var(--at-consent) var(--ease-rise) both}

/* honeypot — off-screen for humans and screen readers, visible to naive bots */
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

/* min-height reserves the line so an incoming message does not shift layout */
.status{
  margin:13px 0 0;min-height:1.35em;
  font-size:13px;font-weight:600;
}
.status[data-state=error]{color:var(--err)}
.status[data-state=ok]{color:var(--ok)}
.status[data-state=busy]{color:var(--muted);font-weight:500}

/* The typo fix, offered inside the status line when the API hands back a
   corrected address. It has to be a button rather than a link — it submits the
   form, it does not navigate — but the page's one `button` rule dresses every
   button as the navy Subscribe control, which at 24px of padding inside a 13px
   line would read as a second primary action competing with the real one. So
   it is walked back to an outlined chip: unmistakably pressable, plainly
   secondary. It carries a whole email address, hence the wrapping rules. */
.status .fix{
  display:inline-block;margin:0 0 0 9px;
  padding:3px 11px;
  border:1.5px solid var(--navy);border-radius:8px;
  background:var(--raised);color:var(--navy);
  font-size:12.5px;font-weight:700;letter-spacing:0;
  white-space:normal;overflow-wrap:anywhere;
  vertical-align:baseline;
}
.status .fix:hover{background:var(--navy);color:var(--raised)}

.fine{
  margin:6px auto 0;max-width:42ch;
  font-size:11.5px;letter-spacing:.01em;color:var(--muted);
}
body.home .fine{animation:fade var(--in-step) var(--at-fine) linear both}

/* A rejected submission should not glow in the brand colour. */
form[data-error] .field{border-color:var(--err)}
form[data-error] .field:focus-within{
  border-color:var(--err);
  box-shadow:0 0 0 4px rgba(180,53,43,.12);
}
form[data-error-consent] .consent input[type=checkbox]{border-color:var(--err)}

/* ── result panels ──────────────────────────────────────────────────────── */
.done{animation:rise .6s var(--ease-soft) both}
.icon{
  width:44px;height:44px;margin:0 auto 20px;
  display:grid;place-items:center;border-radius:50%;
}
.icon--ok{background:rgba(47,125,85,.12);color:var(--ok)}
.icon--mail{background:var(--navy-tint);color:var(--navy)}
.icon--off{background:rgba(110,101,90,.13);color:var(--muted)}

.sub{
  margin:22px auto 0;padding-top:18px;border-top:1px solid var(--line);
  font-size:12.5px;color:var(--muted);max-width:46ch;
}
.sub a{color:var(--navy)}

.addr{
  font-weight:700;color:var(--ink);
  word-break:break-all;
}

.btn-quiet{
  display:inline-block;margin-top:20px;
  font-size:13px;font-weight:600;
  color:var(--navy);text-decoration:none;
}
.btn-quiet:hover{text-decoration:underline;text-underline-offset:3px}
.btn-quiet:focus-visible{outline:2px solid var(--navy);outline-offset:3px;border-radius:3px}

/* ── footer ─────────────────────────────────────────────────────────────── */
footer{
  flex:none;
  padding-block:26px;padding-left:20px;padding-right:20px;
  display:flex;gap:7px 18px;flex-wrap:wrap;
  align-items:center;justify-content:center;
  font-size:12px;color:var(--muted);
}
body.home > footer{animation:fade var(--in-step) var(--at-foot) linear both}
footer a{color:var(--muted);text-decoration:none;border-bottom:1px solid transparent;transition:color .16s,border-color .16s}
footer a:hover{color:var(--navy);border-bottom-color:var(--line)}
footer a:focus-visible{outline:2px solid var(--navy);outline-offset:3px;border-radius:2px}

.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;
}

/* ══ the Plus perks, inside the offer ═══════════════════════════════════════ */
.perks{
  margin:20px 0 0;padding:0;list-style:none;
  display:grid;gap:11px;text-align:left;
}
.perks li{
  display:grid;grid-template-columns:auto 1fr;gap:10px;align-items:start;
  font-size:13.5px;line-height:1.5;color:var(--body);
}
.perks li::before{
  content:"";width:6px;height:6px;margin-top:8px;border-radius:50%;
  background:var(--bullet);
}
.perks b{font-weight:700;color:var(--ink)}

/* ══ the thank-you ═════════════════════════════════════════════════════════
   A postmark, because this is a travel product and the prize is a trip: the
   one moment on the page where a little ceremony is the right answer. It lands
   like a stamp rather than fading in, and everything under it arrives after. */
.thanks{
  width:100%;max-width:min(432px,calc(100vw - 28px));
  padding:0;border:0;background:transparent;color:var(--body);
  overflow:visible;
}
.thanks::backdrop{
  background:rgba(32,30,29,.46);
  backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px);
  animation:fade .45s var(--ease-soft) both;
}
.thanks[open]{animation:thanks-in .62s var(--ease-rise) both}
@keyframes thanks-in{
  from{opacity:0;transform:translateY(22px) scale(.95)}
  to  {opacity:1;transform:none}
}

.thanks-card{
  padding:clamp(28px,6vw,40px) clamp(22px,5vw,36px) clamp(24px,5vw,30px);
  background:var(--card);
  border:1px solid var(--line);
  border-radius:24px;
  text-align:center;
  box-shadow:0 26px 64px -26px rgba(32,30,29,.5);
}

/* The stamp comes down from above its resting size and angle, so the easing
   can overshoot once and settle — the only bounce anywhere on this site, and
   it is here because that is what a stamp does. */
.postmark{display:flex;justify-content:center;color:var(--navy)}
.postmark svg{
  transform:rotate(-7deg);
  animation:stamp-down .6s .3s cubic-bezier(.2,1.42,.45,1) both;
}
@keyframes stamp-down{
  from{opacity:0;transform:rotate(-24deg) scale(1.6)}
  to  {opacity:1;transform:rotate(-7deg) scale(1)}
}
.pm-ring{fill:none;stroke:currentColor;stroke-width:2;stroke-dasharray:3 5.5;opacity:.45}
.pm-inner{fill:none;stroke:currentColor;stroke-width:2.5}
.pm-mark{fill:none;stroke:currentColor;stroke-width:4.5;stroke-linejoin:miter;stroke-linecap:square}
.pm-text,.pm-date{fill:currentColor;font-family:var(--sans);font-weight:800}
.pm-text{font-size:12px;letter-spacing:2.6px}
.pm-date{font-size:9.5px;letter-spacing:1.7px}

.thanks h2{
  margin:16px 0 0;
  font-family:var(--display);font-weight:400;color:var(--ink);
  font-size:clamp(23px,4.6vw,29px);line-height:1.14;letter-spacing:-.014em;
  text-wrap:balance;
}
.thanks-lede{
  margin:13px auto 0;max-width:34ch;
  font-size:14.5px;line-height:1.6;color:var(--body);
}
.thanks-addr{
  font-weight:700;color:var(--navy);
  overflow-wrap:anywhere;
}

/* Dashed, like a tear-off line on a ticket. */
.thanks-list{
  margin:22px 0 0;padding:19px 0 0;list-style:none;
  border-top:1px dashed var(--line);
  display:grid;gap:10px;text-align:left;
}
.thanks-list li{
  display:grid;grid-template-columns:auto 1fr;gap:11px;align-items:start;
  font-size:13.5px;line-height:1.5;color:var(--body);
}
.thanks-list li::before{
  content:"";flex:none;width:16px;height:16px;margin-top:2px;border-radius:50%;
  background:var(--navy) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23FBF5EA' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 L9 17 L4 12'/%3E%3C/svg%3E") center/10px no-repeat;
}

.thanks-close{
  width:100%;margin-top:24px;
  padding:13px 24px;border:0;border-radius:11px;
  background:var(--navy);color:var(--raised);
  font-family:var(--sans);font-size:14.5px;font-weight:700;
  cursor:pointer;
}
.thanks-close:hover{background:var(--navy-deep)}
.thanks-close:focus-visible{outline:2px solid var(--navy);outline-offset:3px}

.thanks-note{
  margin:14px 0 0;
  font-size:11.5px;line-height:1.5;color:var(--muted);
}

/* Everything inside arrives behind the stamp, in reading order. */
.thanks[open] h2          {animation:rise .52s .46s var(--ease-soft) both}
.thanks[open] .thanks-lede{animation:rise .52s .54s var(--ease-soft) both}
.thanks[open] .thanks-list{animation:rise .52s .62s var(--ease-soft) both}
.thanks[open] .thanks-close{animation:rise .52s .7s var(--ease-soft) both}
.thanks[open] .thanks-note{animation:fade .52s .8s linear both}

/* ══ long-form document pages (terms) ══════════════════════════════════════
   A different job to the signup page: read once, carefully, possibly under
   duress. Wider measure, left-aligned, hierarchy that survives skimming. */
.wrap--doc{max-width:760px}
.card--doc{
  text-align:left;
  padding:clamp(28px,5vw,56px);
}
.brand--doc{align-items:flex-start;margin-bottom:34px}
.brand--doc img{width:clamp(132px,22vw,152px)}

.doc-title{
  font-family:var(--display);font-weight:400;color:var(--ink);
  font-size:clamp(30px,5.4vw,42px);line-height:1.08;letter-spacing:-.014em;
  margin:0;
}
.doc-meta{
  margin:12px 0 0;font-size:13.5px;color:var(--muted);
}
.doc-meta a{color:var(--navy)}

.doc h2{
  font-family:var(--display);font-weight:400;color:var(--ink);
  font-size:clamp(21px,3.2vw,26px);line-height:1.2;letter-spacing:-.008em;
  margin:44px 0 0;
}
.doc h3{
  font-family:var(--sans);font-weight:800;color:var(--ink);
  font-size:15px;line-height:1.35;letter-spacing:-.005em;
  margin:26px 0 0;
}
.doc h3.rule-above{
  margin-top:32px;padding-top:26px;border-top:1px solid var(--line);
}
.doc p{margin:10px 0 0;font-size:14.5px;line-height:1.68;color:var(--body);max-width:68ch}
.doc ol,.doc ul{margin:10px 0 0;padding-left:22px;max-width:68ch}
.doc li{margin:7px 0 0;font-size:14.5px;line-height:1.6;color:var(--body)}
.doc b{color:var(--ink);font-weight:700}
.doc code{
  font-family:var(--mono-stack,ui-monospace,SFMono-Regular,Menlo,Consolas,monospace);
  font-size:.9em;background:var(--raised);
  border:1px solid var(--line-soft);border-radius:4px;padding:1px 5px;
}
.doc a{color:var(--navy);text-decoration:underline;text-underline-offset:2px}
.doc a:focus-visible{outline:2px solid var(--navy);outline-offset:2px;border-radius:2px}

/* The plain-English summary. Terms nobody reads protect nobody. */
.tldr{
  margin:30px 0 0;padding:24px 26px;
  background:var(--raised);border:1px solid var(--line);border-radius:18px;
}
.tldr h2{margin:0;font-size:clamp(19px,2.8vw,22px)}
.tldr ul{margin:14px 0 0;padding-left:20px}
.tldr li{font-size:14px}
.tldr-foot{
  margin:16px 0 0;padding-top:14px;border-top:1px solid var(--line);
  font-size:12.5px;color:var(--muted);font-style:italic;
}

/* The two conditions that can cost somebody the prize through inaction. They
   are lifted out of the run of text on purpose. */
.callout{
  margin:12px 0 0;padding:16px 18px;
  background:var(--raised);
  border:1px solid var(--line);border-left:3px solid var(--navy);
  border-radius:4px;
}
.prize-list li{margin-top:10px}

/* An unfilled blank must be impossible to publish by accident, so it shouts on
   the page as well as failing tests/integrity.test.mjs. */
.fill{
  color:var(--err)!important;font-weight:700;
  background:rgba(180,53,43,.09);
  border:1px dashed rgba(180,53,43,.45);border-radius:3px;
  padding:0 5px;white-space:nowrap;
}

.doc-contact{
  margin:40px 0 0;padding-top:22px;border-top:1px solid var(--line);
  font-size:13.5px;color:var(--muted);
}
.doc-contact a{color:var(--navy)}

@media (max-width:540px){
  .fill{white-space:normal}
}

/* ══ /oops.html — which of the four checks refused the address ══════════════
   lambda/api/index.mjs redirects an HTML client to /oops.html#<reason>, and the
   page has to read that fragment and show one of four messages. It cannot use
   script to do it: the CSP is script-src 'self' with no hashes, so an inline
   one would silently not run in production — and more to the point, a page
   whose whole job is to explain a failure is the last page that should depend
   on anything else working. :target is the CSS that reads a fragment, so
   :target is what this is built on.

   Two rules do the whole job. The four blocks are hidden and reveal themselves
   when the fragment names them; the generic block is hidden when any of the
   four has matched, which needs the sibling combinator and therefore needs the
   generic block to come LAST in the markup — `~` only looks forwards. With no
   fragment, or with one we do not recognise, none of the four matches and the
   generic block is simply never hidden. That is the no-fragment default,
   arrived at by doing nothing rather than by a rule of its own.

   The four ids are the Lambda's four reason strings and cannot be renamed on
   one side only. They are also bare ids in a shared stylesheet, which is worth
   knowing: #email in particular is the email input on index.html. Nothing here
   can touch it — the declarations apply to a following .oops-default sibling,
   and that element exists on no other page — but a rule added to these
   selectors later could, so keep new declarations on the .oops- classes. */
.oops{margin:30px 0 0}

.oops > section{
  padding:22px 24px;
  background:var(--raised);
  border:1px solid var(--line);
  border-left:3px solid var(--err);
  border-radius:4px;
}
.doc .oops h2{margin:0;font-size:clamp(19px,2.8vw,23px)}
.doc .oops p{max-width:62ch}

/* The line that says what to do about it, split off from the line that says
   what happened. Somebody who has been refused wants the second one, and on a
   page of four possible explanations it has to be findable without reading. */
.doc .oops-do{
  margin:14px 0 0;padding-top:14px;
  border-top:1px solid var(--line);
  font-weight:600;color:var(--ink);
}

.oops-reason{display:none}
.oops-reason:target{display:block}

/* A fragment does not only select, it scrolls — and left alone the browser puts
   the matched block at the top of the viewport, which on a page this short
   means the visitor arrives below the headline and below "nothing was saved and
   nothing was sent". That is the reassurance, and they should read it before
   the diagnosis. An absurd scroll-margin asks the browser to scroll to a point
   far above the element, which it clamps to the top of the document, so the
   page lands where it would have landed with no fragment at all while the
   fragment goes on doing its real job of choosing the message. */
.oops-reason:target{scroll-margin-top:100vh}
#email:target ~ .oops-default,
#typo:target ~ .oops-default,
#disposable:target ~ .oops-default,
#nomx:target ~ .oops-default{display:none}

/* Why the check happens at all, in the quietest voice on the page. It is the
   answer to "you never used to do this", and it belongs under the fix rather
   than above it. */
.doc .oops-why{
  margin:30px 0 0;padding-top:20px;border-top:1px solid var(--line);
  max-width:66ch;
  font-size:13px;line-height:1.65;color:var(--muted);
}

/* ── skip the sequence ──────────────────────────────────────────────────────
   Anyone who tabs, clicks or types is here to do something, not to watch.
   app.js sets this class on the first such gesture and every beat snaps to its
   resting state. Listed explicitly rather than with a universal selector so
   the sheen, the chevron and the offer's own opening are left alone. */
html.settled .card,
html.settled .mark,
html.settled .brand .rule,
html.settled .reveal,
html.settled .tagline,
html.settled .soon,
html.settled .surprise,
html.settled .field,
html.settled .consent,
html.settled .fine,
html.settled footer{
  animation-duration:1ms!important;
  animation-delay:0s!important;
}

@media (max-width:540px){
  :root{--intro-scale:1.85}
  .field{flex-wrap:wrap;gap:7px}
  input[type=email]{flex:1 0 100%;padding:13px 12px;text-align:center}
  .field > button{flex:1 0 100%;padding:13px 24px}
  .tagline{max-width:14ch}
}

@media (prefers-reduced-motion:reduce){
  /* Delay has to go too. Without it the staggered beats still wait their turn
     and then snap, which is the worst of both. */
  *,*::before,*::after{
    animation-duration:.001ms!important;animation-iteration-count:1!important;
    animation-delay:.001ms!important;
    transition-duration:.001ms!important;transition-delay:0s!important;
  }
}
