/* ══════════════════════════════════════════════════════════════════════════
   AMCA — Amca Holiday Party
   An invitation in a folder. The landing is the party's name on jet red,
   with one folder's tab standing on the bottom edge: the Internship
   Program's cabinet, down to a single drawer. The invitation is the card in
   it, laid out the way the AUSA invitation's details are, with the reply on
   the card itself. Send folds the card into a paper airplane and throws it
   (fold.js; its scene is styled at the end). The tokens, the type and the
   chips are the brand guidelines' and keep their numbers.

   Laid out on the grid of Figma's Invite v3: 12 columns with 12px gutters
   inside the page's margin (24px), and the card's contents on 12 more
   inside its own (48px); on a phone, 6 of each, inside 16px.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Fonts ─────────────────────────────────────────────────────────────── */
@font-face {
  font-family: "AMCA Reckless";
  src: url("Fonts/AMCAReckless-StandardMLight.woff2") format("woff2");
  font-weight: 300;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("Fonts/JetBrainsMono-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Precept";
  src: url("Fonts/Precept-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Precept";
  src: url("Fonts/Precept-Bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* ── Tokens ────────────────────────────────────────────────────────────── */
:root {
  --white:  #ffffff;
  --black:  #000000;
  --cloud:  #eaeef0;
  --red:    #a3241f;   /* jet red */
  --green:  #255027;   /* the letterform behind the name */
  --paper-back: #f7f7f5;   /* the back of the card, seen as it folds */

  --gutter: 24px;
  --inner:  12px;
  --edge:   calc(2 * var(--gutter));
  --pad:    48px;   /* the card's margin inside its border */
  --col-gap: 12px;  /* Figma: Column gap, between the columns of the page and the card */

  /* The landing as Figma draws it (Invite v4): 1440 by 843, the window
     less the band the tab and the lip of the card stand in (390 by 795 on a
     phone). It is scaled whole to fit the landing and centred in it (on a
     phone, otherwise: see there); --u is one of its pixels, so its pieces
     keep their places on the letterform, and --art-cy is the height in it
     that is put at the landing's middle. (A length in the landing's and the
     letterform's container units: it is only used inside them.) */
  --art-w: 1440;
  --art-h: 843;
  --art-cy: calc(var(--art-h) / 2);
  --u: min(100cqw / var(--art-w), 100cqh / var(--art-h));

  /* The margin round the invitation, all four sides, and the tab's distance
     from the top of the window once it has been pulled up. */
  --m: var(--gutter);

  --serif: "AMCA Reckless", "Times New Roman", serif;
  --mono:  "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  --text:  "Precept", "Helvetica Neue", Arial, sans-serif;

  /* Type: the Internship Program's styles, at 1512 and easing down with the
     window to a floor; the phone block swaps in the Phone/ sizes. */
  --t-heading: clamp(24px, 2.778vw, 42px);    /* Reckless/Heading 42  */
  --t-body:    clamp(14px, 1.058vw, 16px);    /* Precept/Body 16      */
  --t-label:   12px;                           /* Mono/Label 12        */

  --ease: cubic-bezier(.65, 0, .35, 1);

  --btn-h:   33px;
  --field-h: 44px;   /* a text field: a thumb's height */
  --fill:    .3s;    /* red rising up a chip on hover */

  /* The cabinet, as on the Internship Program page. */
  --lip:         14px;                    /* the card showing under the strip, at rest (a phone's: the gutter) */
  --peek:        calc(2 * var(--btn-h));  /* how far the folder lifts under the pointer */
  --peek-time:   .42s;
  --drawer-time: .62s;
}

/* ── The browser's own edges ──────────────────────────────────────────────
   As on the Internship Program page: Safari 26 on a phone colours the band
   behind its status bar and the band around its floating bar from whatever
   fixed or sticky box it finds 4px in from each edge, mid-width (it ignores
   theme-color). Left to itself it finds the landing's red at the top and
   the white card further down. Two fixed boxes, one on each edge and over
   everything, give it black every time. Each keeps its black to a content
   box of no height, so nothing of it is ever painted; Safari reads the
   colour from the style. The page's canvas is black there too, for the
   overscroll (not the staff page's, which keeps its own). */
.edge { display: none; }
@supports (-webkit-touch-callout: none) {
  :root:not(.staff-page) { background: #000; }
  .edge {
    display: block;
    position: fixed;
    left: 0;
    right: 0;
    z-index: 2147483647;
    height: 16px;
    padding-top: 16px;
    background: #000 content-box;
    pointer-events: none;
  }
  .edge--top    { top: -10px; }
  .edge--bottom { bottom: -10px; }
}

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

html {
  scroll-behavior: smooth;
  scrollbar-gutter: stable;
  background: var(--red);
}
/* While the airplane is in the air the page holds still under it. */
html.is-flying { overflow: hidden; }

body {
  margin: 0;
  background: var(--red);
  color: var(--black);
  font-family: var(--text);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img, svg { display: block; }
p, h1, h2, h3, dl, dd { margin: 0; }
a { color: inherit; text-decoration: none; }
button {
  font: inherit;
  color: inherit;
  margin: 0;
  border-radius: 0;
  -webkit-appearance: none;
          appearance: none;
  cursor: pointer;
}
fieldset { margin: 0; padding: 0; border: 0; min-width: 0; }
[hidden] { display: none !important; }

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

::selection { background: var(--red); color: var(--white); }

/* ── Type ──────────────────────────────────────────────────────────────────
   One rule per text style, under its name in the Figma file. Everything
   below this only places type; nothing else sets a size, a leading or a
   tracking. */

/* AMCA Reckless Light 60 and Precept 32 (32 and 22 on a phone): the
   landing's two lines, as Figma's landing sets them (-2% and -3%
   tracking). They are drawn in the landing's SVG, in its pixels, so their
   sizes and every letter's place are there, in index.html; the tracking is
   in the places. */
.landing__type { font-family: var(--text); font-weight: 400; letter-spacing: 0; text-rendering: geometricPrecision; }
.landing__type--name { font-family: var(--serif); font-weight: 300; }

/* Reckless/Heading 42 */
.heading { font: 300 var(--t-heading) / 1 var(--serif); letter-spacing: 0; }

/* Precept/Body 16: the reading copy. A text field never goes under 16px,
   or a phone zooms in on it. */
.invite { font: 400 var(--t-body) / 1.2 var(--text); letter-spacing: 0; }
.field__input { font: 400 16px / 1.2 var(--text); letter-spacing: 0; }

/* Precept/Body Bold 16: the line that leads each fact. */
.fact__lead,
.rsvp__error { font: 700 var(--t-body) / 1.2 var(--text); letter-spacing: 0; }

/* Mono/Label 12 */
.mono {
  font: 400 var(--t-label) / 1.1 var(--mono);
  letter-spacing: 0;
  text-transform: uppercase;
  word-break: break-word;
}

/* The name is never set in capitals, not even inside a mono label. */
.mono .amca { text-transform: none; }

/* Cut to the cap height and the baseline, as every style is in Figma. */
@supports (text-box: trim-both cap alphabetic) {
  .mono,
  .heading,
  .prose p,
  .fact p { text-box: trim-both cap alphabetic; }
}

/* ── Symbols ── the red dot, exactly as tall as the Reckless beside it is
   cut, its top on the top of the name's first line. */
.symbol--red {
  display: block;
  flex: none;
  align-self: start;
  font: 300 var(--t-heading) / 1 var(--serif);
  width: .668em;
  height: .668em;
  width: 1cap;
  height: 1cap;
  border-radius: 50%;
  background: var(--red);
}

/* ── Prose ── paragraphs a blank line apart. */
.prose {
  display: flex;
  flex-direction: column;
  gap: 1.2em;
}

/* ── Chips ─────────────────────────────────────────────────────────────────
   The guidelines' button: a black rule, a mono label, and red rising up it
   from the bottom on hover. Unfilled, it is the card itself. */
.chip {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--inner);
  height: var(--btn-h);
  padding: 0 var(--inner);
  overflow: clip;
  background-color: transparent;
  background-image: linear-gradient(var(--red), var(--red));
  background-repeat: no-repeat;
  background-position: 50% 100%;
  background-size: 100% 0;
  border: 1px solid var(--black);
  color: var(--black);
  white-space: nowrap;
  transition: background-size var(--fill) var(--ease), color var(--fill) var(--ease);
}
@media (hover: hover) and (pointer: fine) {
  .chip:hover { background-size: 100% 100%; color: var(--white); }
}
.chip:focus-visible { outline: 2px solid var(--black); outline-offset: 3px; }

/* The one that sends is in jet red, and raises black. Held down (the copy
   the airplane is folded from) it keeps the black. */
.chip--red {
  background-color: var(--red);
  background-image: linear-gradient(var(--black), var(--black));
  color: var(--white);
}
.chip.is-pressed { background-size: 100% 100%; color: var(--white); }

/* The guidelines' Arrow Regular, in the label's colour. */
.chip__arrow {
  width: 9px;
  height: 9px;
  flex: none;
  background: currentColor;
  -webkit-mask: url("Vectors/arrow.svg") center / contain no-repeat;
          mask: url("Vectors/arrow.svg") center / contain no-repeat;
}

/* ══ The letterform ════════════════════════════════════════════════════
   The Amca "a" in green on the red, where the landing's drawing puts it
   (Figma, Invite v4: 870 wide at 351, 120 in the 1440 by 843 drawing; on a
   phone 358 wide at 16, 265 in 390 by 795), and scaled with it. It stays
   where it is in the window whatever the page does: the invitation slides
   up over it, so once the invitation is pulled up it shows in the margin
   round the card. For the peek it rises with the landing, so the drawing
   holds together. */
.letterform {
  --vh: 100vh;
  --lf-x: 351;
  --lf-y: 120;
  --lf-w: 870;
  position: fixed;
  z-index: 0;
  top: 0;
  left: 0;
  right: 0;
  height: calc(var(--vh) - var(--lip) - var(--btn-h));   /* the landing's */
  container-type: size;
  pointer-events: none;
  transition: transform var(--peek-time) var(--ease);
}
main:has(.landing.is-yielding) .letterform { transform: translateY(calc(-1 * var(--peek))); }
.letterform svg {
  position: absolute;
  left: calc(50% + (var(--lf-x) - var(--art-w) / 2) * var(--u));
  top: calc(50% + (var(--lf-y) - var(--art-cy)) * var(--u));
  width: calc(var(--lf-w) * var(--u));
  height: auto;
  aspect-ratio: 104.464 / 77.386;
  fill: var(--green);
}
@supports (height: 100svh) {
  .letterform { --vh: 100svh; }
}
/* High contrast recolours the name and the red, not a shape behind them. */
@media (forced-colors: active) {
  .letterform { display: none; }
}

/* ══ Landing ═══════════════════════════════════════════════════════════
   Short of the window by exactly the band the tab and the lip of the card
   stand in, so at the top of the page the folder's top edge is the lip's
   height above the bottom edge. In it, Figma's drawing of the landing
   (Invite v4), scaled whole and centred (as --u does for the letterform):
   "You're Invited!" and the party's name set on the slant across the
   letterform, and thin rules beside them. */
.landing {
  position: relative;
  height: calc(100vh - var(--lip) - var(--btn-h));
  height: calc(100svh - var(--lip) - var(--btn-h));
  container-type: size;
  /* The drawing's frame may stand past it (on a phone it is fitted by what
     it draws, not by its frame); what it draws never does. */
  overflow: hidden;
  overflow: clip;
  color: var(--white);
  transition: transform var(--peek-time) var(--ease);
}
/* When the folder peeks, it pushes the landing up with it, as the
   Internship Program's do (and the letterform with it). */
.landing.is-yielding { transform: translateY(calc(-1 * var(--peek))); }
/* The drawing is one SVG in Figma's own pixels (1440 by 843; 390 by 795
   on a phone), scaled and placed as the letterform is (--u, --art-cy). So
   the type and the rules keep exactly the places and the spaces between
   them that they have in Figma, in every browser: each letter is set where
   Figma sets it, on Figma's baseline, and each rule runs between Figma's
   end points, a pixel thick at any size. */
.landing__art {
  position: absolute;
  left: calc(50% - var(--art-w) / 2 * var(--u));
  top: calc(50% - var(--art-cy) * var(--u));
  width: calc(var(--art-w) * var(--u));
  height: calc(var(--art-h) * var(--u));
  overflow: visible;
}
.landing__art--narrow { display: none; }
.landing__art text { fill: var(--white); }
.landing__rule { stroke: var(--white); stroke-width: 1; vector-effect: non-scaling-stroke; transform-box: view-box; }
@media (forced-colors: active) {
  .landing__art text { fill: CanvasText; }
  .landing__rule { stroke: CanvasText; }
}


/* ── The intro (script.js) ── On the red: "You're Invited!" typed in where
   it stands, a letter at a time; then the letterform fading in, green,
   while the rule draws from its right end to its left, which it reaches as
   the H of the party's name is typed (the name begins a little before, so
   that it does); the rest of the name follows, and the folder comes up.
   Until then the page holds still. */
html.is-playing { overflow: hidden; }
.is-playing .letterform svg { opacity: 0; }
/* A rule is drawn by growing it from its right end (its x1, y1: the
   transform-origin beside it in index.html), not with a dash: Safari places
   the dashes of a non-scaling stroke in a scaled drawing at the wrong
   length, so a piece of the rule showed before its turn. */
.is-playing .landing__rule { transform: scale(0); }
.is-playing .landing__k:not(.is-typed) { visibility: hidden; }
.is-playing.is-lighting .letterform svg { animation: fade-in var(--light-time, 1.2s) var(--ease) both; }
.is-playing.is-lighting .landing__rule { animation: draw var(--light-time, 1.2s) var(--ease) both; }
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes draw { from { transform: scale(0); } to { transform: scale(1); } }

/* ══ The folder ════════════════════════════════════════════════════════
   One margin in from each side of the window, and one margin under the
   card, so that pulled up it is framed by the same margin all round. Its
   tab is a strip across the top of the card, the card's whole width. */
.folder {
  position: relative;
  margin: 0 var(--m);
  padding: var(--btn-h) 0 var(--m);
}

/* The name sits on the strip's middle, from the left, and after it what
   came of the reply. Its foot stands on the card's top rule, and a white
   strip under it covers that rule, so the strip and the card read as one
   sheet. */
.folder__tab {
  position: absolute;
  z-index: 1;
  top: 0;
  left: 0;
  right: 0;
  height: var(--btn-h);
  display: flex;
  align-items: center;
  padding: 0 12px;
  text-align: left;
  background: var(--white);
  border: 1px solid var(--black);
  border-bottom: 0;
  color: var(--black);
}
.folder__tab::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  height: 3px;
  background: var(--white);
}
.folder__tab .mono { display: block; flex: 1 1 auto; min-width: 0; }
/* On the red, so the ring is white: black on jet red is under 3:1. */
.folder__tab:focus-visible { outline: 2px solid var(--white); outline-offset: 3px; }

.folder__tab,
.invite {
  transform: translateY(calc(-1 * var(--lift, 0px)));
  transition: transform var(--peek-time) var(--ease);
}

/* At rest the tab and the lip wait on the bottom edge; under the pointer
   the folder lifts a little, as the Internship Program's do. */
.folder.is-peeking { --lift: var(--peek); }
@media (hover: hover) and (pointer: fine) {
  .folder.is-stowed { cursor: pointer; }
}

/* Held under the bottom edge until script.js brings it up, so it is never
   seen in its place first and then taken away. */
.is-intro .folder > * {
  transform: translateY(calc(var(--lip) + var(--btn-h)));
  transition: none;
}
.folder.is-arriving > * {
  animation: drawer-in var(--drawer-time) var(--ease) var(--arrive-delay, 0ms) backwards;
}
@keyframes drawer-in {
  from { transform: translateY(calc(var(--lip) + var(--btn-h))); }
  to   { transform: translateY(0); }
}

/* While its airplane is in the air the folder is not there at all. */
.folder.is-thrown { visibility: hidden; }

/* On the pages a reply sent without the script lands on, the folder is
   only its strip (a link to the invitation) and the lip of the card, on
   the bottom edge. */
.folder--note { padding-bottom: 0; }
.folder__lip {
  height: var(--lip);
  background: var(--white);
  border: 1px solid var(--black);
  border-bottom: 0;
}

/* ══ The invitation ════════════════════════════════════════════════════
   The card: the window's height inside the margin, less the tab, at the
   least, and the window's width inside it, always. Longer than that, it
   runs on and the page scrolls, with the margin still under it. */
.invite {
  min-height: calc(100vh - 2 * var(--m) - var(--btn-h));
  min-height: calc(100dvh - 2 * var(--m) - var(--btn-h));
  display: flex;
  flex-direction: column;
  gap: var(--edge);
  padding: var(--pad);
  background: var(--white);
  border: 1px solid var(--black);
  scroll-margin-top: calc(var(--m) + var(--btn-h));
}

/* On twelve columns 12px apart, inside the card's margin (97px each at
   1440): the dot in the first and the name across the other eleven; under
   the name, the words and the facts, four wide (424px); the reply in the
   last six (642px), so its two-up fields are three columns each. */
.invite__body {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--col-gap);
  row-gap: var(--edge);
  align-items: start;
}
.invite__body > .symbol--red { grid-column: 1; grid-row: 1; }
.invite__title { grid-column: 2 / -1; grid-row: 1; }

.invite__about {
  grid-column: 2 / span 4;
  grid-row: 2;
  display: flex;
  flex-direction: column;
  gap: var(--edge);
}

/* When, where, and what to wear: one line each, ruled off from one another
   like the fields of a record. */
.facts {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  border-bottom: 1px solid var(--black);
}
.fact {
  padding: var(--gutter) 0;
  border-top: 1px solid var(--black);
}
/* The venue's name links to its page (in a new tab, so the invitation
   stays open): underlined, red under the pointer. */
.fact a { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 2px; }
.fact a:focus-visible { outline: 2px solid var(--black); outline-offset: 3px; }
@media (hover: hover) and (pointer: fine) {
  .fact a:hover { color: var(--red); }
}

/* A fact may run on to a line under its lead (the venue's address under
   its name), a line's space below it: cut to their capitals, the lines are
   a line's height less a capital apart. */
@supports (text-box: trim-both cap alphabetic) {
  .fact p + p { margin-top: calc(1.2em - 1cap); }
}

/* ── The reply ── what the guest says, then Send across the column. */
.rsvp {
  grid-column: 7 / -1;
  grid-row: 2;
  display: flex;
  flex-direction: column;
  gap: var(--gutter);
}

.answer {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--inner) var(--col-gap);
  margin-top: calc(var(--inner) - var(--gutter));
}
/* The one picked fills: red for yes, black for no. */
.answer__chip { cursor: pointer; }
.answer__chip:has(input:checked) { background-size: 100% 100%; color: var(--white); }
.answer__chip--no { background-image: linear-gradient(var(--black), var(--black)); }
.answer__chip:has(input:focus-visible) { outline: 2px solid var(--black); outline-offset: 3px; }
.answer.is-invalid .answer__chip { border-color: var(--red); box-shadow: inset 0 0 0 1px var(--red); }

.fields {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--gutter) var(--col-gap);
}
.field {
  display: flex;
  flex-direction: column;
  gap: var(--inner);
  min-width: 0;
}
.field--wide { grid-column: 1 / -1; }
.field__optional { text-transform: none; }
.field__input {
  display: block;
  width: 100%;
  height: var(--field-h);
  margin: 0;
  padding: 0 var(--inner);
  border: 1px solid var(--black);
  border-radius: 0;
  background: var(--white);
  color: var(--black);
  -webkit-appearance: none;
          appearance: none;
}
.field__input--area {
  height: auto;
  min-height: calc(2 * var(--field-h));
  padding: var(--inner);
  resize: vertical;
}
.field__input:focus { outline: 2px solid var(--black); outline-offset: 2px; }
.field.is-invalid .field__input { border-color: var(--red); box-shadow: inset 0 0 0 1px var(--red); }

/* A menu (Figma: Field, Type=Select): a text field's box with the staff
   page's chevron, 10 by 6, one inner padding from its right end, and room
   kept for it. Until a meal is chosen it shows its first line, "Choose a
   meal", in grey; the list itself is always in black. */
.field__input--select {
  padding-right: calc(2 * var(--inner) + 10px);
  background: var(--white) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23000' stroke-width='1.2'/%3E%3C/svg%3E") no-repeat right var(--inner) center;
  text-overflow: ellipsis;
  cursor: pointer;
}
.field__input--select:has(option[value=""]:checked) { color: #6b6f71; }
.field__input--select option { color: var(--black); }

/* The +1 box (Figma: Checkbox): a 20px square with its label 12px to the
   right, centred on it; ticked, it fills jet red with a white tick. The
   whole label is what is pressed, and no wider than its words. */
.check {
  grid-column: 1 / -1;
  justify-self: start;
  display: flex;
  align-items: center;
  gap: 12px;
  cursor: pointer;
}
.check__box {
  flex: none;
  width: 20px;
  height: 20px;
  margin: 0;
  border: 1px solid var(--black);
  border-radius: 0;
  background: var(--white);
  -webkit-appearance: none;
          appearance: none;
  cursor: pointer;
}
.check__box:checked {
  background: var(--red) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 18 18'%3E%3Cpath d='M4.5 9.5l3 3 6-6.5' fill='none' stroke='%23fff' stroke-width='1.5' stroke-linecap='square'/%3E%3C/svg%3E") center / 18px 18px no-repeat;
}
.check__box:focus-visible { outline: 2px solid var(--black); outline-offset: 3px; }

/* The dinner: the meal, the +1 box and the +1's fields. They sit in the
   fields' own grid (their wrappers draw nothing), and are taken away by
   CSS, so the form works the same without the script: all of it once "Will
   not attend" is picked, and the +1's fields while the box is not ticked. */
.dinner,
.dinner__plus { display: contents; }
.rsvp:has(.answer__chip--no input:checked) .dinner,
.dinner:not(:has(.check__box:checked)) .dinner__plus { display: none; }

.rsvp__error { color: var(--red); }

.rsvp__send { width: 100%; }
.rsvp__send[disabled] { cursor: progress; }

/* ── The foot of the card ── one line under a rule, kept to the bottom of
   the card however tall the window makes it, on the body's twelve columns:
   the wordmark from the first, the line and the credit from the seventh
   (where the reply starts), and the flag at the end of the last. The line
   and the credit are spread to the wordmark's height, the line's capitals
   level with its top and the credit's baseline with its foot (Figma). They
   may run on under the flag's columns, short of the flag itself, so the
   line keeps to one line where the window allows. */
.invite__foot {
  margin-top: auto;
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--col-gap);
  align-items: center;
  padding-top: var(--gutter);
  border-top: 1px solid var(--black);
}
.invite__wordmark,
.invite__flag {
  width: auto;
  height: var(--btn-h);
}
.invite__wordmark { grid-column: 1 / span 2; grid-row: 1; }
.invite__flag { grid-column: 12; grid-row: 1; justify-self: end; }
.invite__meta {
  grid-column: 7 / -1;
  grid-row: 1;
  align-self: stretch;
  padding-right: calc(var(--btn-h) * 800 / 421 + var(--col-gap));   /* the flag, and a gap */
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: flex-start;
  gap: 8px;
}

/* ══ Responsive ════════════════════════════════════════════════════════ */

/* Under 1200px three columns are too narrow a menu for the longest meal
   ("Slow-braised beef short ribs"), so the +1's email and meal take the
   reply's width, one under the other. */
@media (max-width: 1200px) {
  .dinner__plus .field { grid-column: 1 / -1; }
}

/* Tablet: the reply goes under the words and the facts, both from the
   name's column to the end, on the same twelve columns. */
@media (max-width: 900px) {
  .invite__about  { grid-column: 2 / -1; }
  .rsvp           { grid-column: 2 / -1; grid-row: 3; }
}

/* ── Phone ── six columns, still 12px apart, inside a 16px margin (44.33px
   each at 390), and the guidelines' phone scale. */
@media (max-width: 620px) {
  :root {
    --gutter: 16px;
    --inner: 8px;
    --pad: var(--gutter);

    --t-heading: 28px;                        /* Phone/Reckless Heading 28 */
    --t-body:    16px;                        /* Phone/Precept Body 16: never under 16 on a phone */
    --lip: var(--gutter);
    --art-w: 390;
    --art-h: 795;
    /* A phone's window is seldom as tall as the drawing, so it is not
       fitted whole: it is as wide as the invitation, the letterform (358
       of its 390) one margin in from each side, or, on a phone too short
       for that, as tall as fits inside the margin; and centred on
       what it draws, from the top of "You're Invited!" (57) to the foot of
       the rule under the name (585), not on its frame. */
    --u: min((100cqw - 2 * var(--gutter)) / 358, (100cqh - 2 * var(--gutter)) / 528);
    --art-cy: 321;
  }

  /* The landing as Figma draws it for a phone: the letterform the width
     inside the margin, the name across it, "You're Invited!" above it to the
     right, each with its rule. */
  .letterform { --lf-x: 16; --lf-y: 265; --lf-w: 358; }
  .landing__art--wide { display: none; }
  .landing__art--narrow { display: block; }

  /* The dot in the first column; the name, and everything under it, in the
     other five. */
  .invite { gap: 32px; }
  .invite__body {
    grid-template-columns: repeat(6, minmax(0, 1fr));
    row-gap: 32px;
  }
  .invite__about { gap: 32px; }

  .fields { grid-template-columns: minmax(0, 1fr); }
  .answer { grid-template-columns: minmax(0, 1fr); }

  /* The wordmark the card's width, and under it the line and the credit in
     the first four of the six columns, with the flag at the end of the
     last two. */
  .invite__foot {
    grid-template-columns: repeat(6, minmax(0, 1fr));
    row-gap: 24px;
  }
  .invite__wordmark { grid-column: 1 / -1; grid-row: 1; width: 100%; height: auto; }
  .invite__meta { grid-column: 1 / -1; grid-row: 2; }
  .invite__flag { grid-column: 5 / -1; grid-row: 2; }
}

/* ══ The paper airplane ════════════════════════════════════════════════
   fold.js builds this over the page when Send is pressed: the card cut
   into the pieces its folds make, each piece a copy of the card clipped to
   its shape and turned in 3D, lit from the upper left; the creases drawn on
   as each fold is made; and the shadow it throws on the page under it. */
.pp-scene {
  position: fixed;
  inset: 0;
  z-index: 50;
  pointer-events: none;
  overflow: hidden;
}
.pp-shadow {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
/* Flat on purpose: the pieces are each seen in perspective (fold.js sets
   it here), and stacked in the order fold.js works out every frame. */
.pp-space {
  position: absolute;
  inset: 0;
}
.pp-facet {
  position: absolute;
  left: 0;
  top: 0;
  transform-origin: 0 0;
  will-change: transform;
  backface-visibility: visible;
}
/* The light on a piece (fold.js sets its colour and strength every frame):
   a sheet of one colour, which costs a phone next to nothing to change. */
.pp-shade {
  position: absolute;
  inset: 0;
  background-color: #000;
  opacity: 0;
  will-change: opacity;
  pointer-events: none;
}
.pp-face {
  position: absolute;
  inset: 0;
  overflow: hidden;
}
.pp-face--back { background: var(--paper-back); visibility: hidden; }
.pp-facet.is-back .pp-face--front { visibility: hidden; }
.pp-facet.is-back .pp-face--back  { visibility: visible; }
.pp-face--front > .invite {
  position: absolute;
  left: 0;
  top: 0;
  margin: 0;
  transform: none;
  transition: none;
  min-height: 0;
}

/* The creases: a soft groove along each fold, on both pieces it parts. They
   come in as their fold is made, and stay. */
.pp-crease {
  position: absolute;
  height: 3px;
  transform-origin: 0 0;
  background: linear-gradient(to bottom, rgba(0, 0, 0, .16), rgba(0, 0, 0, 0));
  opacity: 0;
  transition: opacity .35s linear;
}
.pp-crease.is-on { opacity: 1; }

/* The shadow a flap throws on the paper under it, along its free edges:
   wide and faint while the flap is high, narrowing and deepening as it comes
   down flat (fold.js sets both every frame). Each is a layer of its own: a
   phone has 384 of them, and painted into the pieces they took an iPhone's
   page down early in the throw. */
.pp-contact {
  position: absolute;
  height: 14px;
  transform-origin: 0 0;
  background: linear-gradient(to bottom, rgba(0, 0, 0, .2), rgba(0, 0, 0, .06) 40%, rgba(0, 0, 0, 0));
  opacity: 0;
  will-change: transform, opacity;
}

/* The folder's tab, which stays behind as the card lifts away. */
.pp-tab {
  position: absolute;
  margin: 0;
  transform: none;
  transition: opacity .25s linear, transform .35s var(--ease);
}
.pp-tab.is-gone { opacity: 0; transform: translateY(8px); }

/* ?scrub: the slider for moving through the throw by hand. Not part of the
   invitation. */
.scrubber {
  position: fixed;
  z-index: 60;
  left: var(--m);
  right: var(--m);
  bottom: var(--m);
  display: flex;
  align-items: center;
  gap: var(--gutter);
  padding: var(--inner);
  background: var(--white);
  border: 1px solid var(--black);
}
.scrubber__range { flex: 1 1 auto; min-width: 0; accent-color: var(--red); }
.scrubber__time { flex: none; min-width: 22ch; }
.scrubber__done { flex: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *,
  *::before,
  *::after {
    animation-duration: .01ms !important;
    animation-delay: 0s !important;
    transition-duration: .01ms !important;
  }
}
