/* pad.css — the new DiscordPad homepage.
 *
 * Every number in this file came out of ref/SPEC.md, which came out of
 * tools/ref-capture.mjs reading the live reference pages in a browser. Where a
 * value is not a measurement it says so in a comment. Nothing here was chosen
 * because it looked about right.
 *
 * This file is loaded by index.html (the homepage) and dash.html. src/styles.css, which production
 * uses, is untouched.
 */

/* ═══════════════════════════════════════════════════════════════════ tokens
 *
 * Three widths were measured, so the tokens step at those two breakpoints
 * rather than interpolating. The reference does the same thing: its type
 * scale jumps 72 → 56 → 38, it does not fluidly shrink, and a clamp() here
 * would put the page between two states that the reference never occupies. */
:root {
  /* grid ─ rail is constant, the gutter carries the width change */
  --rail: 1200px;
  --gutter: 120px;

  /* type ─ display is set at or below its own size, body at 1.3 */
  /* Tracking is a fraction of the em on the reference, not a fixed distance:
     -0.03em on display XL at every width, -0.02em on display L at 1440 and
     -0.01em below it. Written in px it happened to be right at 1440 and was
     wrong at the other two. */
  --dxl: 72px;   --dxl-lh: 64.8px;  --dxl-tr: -0.03em;
  --dl:  48px;   --dl-lh:  48px;    --dl-tr:  -0.02em;
  --dm:  28px;   --dm-lh:  28px;    --dm-tr:  -0.01em;
  --bl:  20px;   --bl-lh:  26px;
  --bm:  18px;   --bm-lh:  23px;
  --ui:  16px;   --ui-lh:  19.2px;

  /* chrome */
  --nav-h: 80px;
  --nav-inset: 40px;

  /* containers */
  --card-r: 72px;
  --grid-r: 56px;
  --art-r: 48px;
  --btn-h: 48px;
  --btn-r: 12px;
  --btn-px: 24px;

  /* row */
  --col-text: 579px;
  --col-art: 443px;
  --row-pitch: 120px;
  --band-pad: 200px;
  --hero-pad: 176px;
  --float: 200px;

  /* colour ─ one flat ground, Discord's blurple, across the whole public
     site. There is deliberately no ramp, no radial and no fade to black:
     every band, the closing area and the footer all sit on this exact
     value, the way Discord's own large blue sections do. */
  --hero-top: #5865F2;
  --ground: #5865F2;
  /* Panels that must stay separate from the ground for readability. These
     are the only surfaces allowed to differ from it. */
  --panel-dark: #1b1e3d;
  --panel-deep: #12142c;
  --wordmark: #8890ea;

  --blurple: #5865f2;
  --blurple-lift: #6f7bff;
  --lavender: #e0e3ff;
  --green: #35ed7e;
  --mint: #c8ffef;
  --magenta: #ff4cd2;
  --blush: #f5c9ff;
  --sun-a: #323786;
  --sun-b: #ca707e;
  --sun-c: #dab189;

  --ink: #ffffff;
  --ink-dim: #c9cbe6;
  --ink-mute: #9aa0c4;
  --hair: rgba(255, 255, 255, .14);

  /* Substitutes, chosen by measurement in tools/type-match.mjs against the
     reference's own glyph advances, not by eye. ABC Ginto Discord Nord sets
     "DOWNLOAD DISCORD" at 1339.1 units per 100em with a cap height of 71;
     Roboto Flex at wdth 140 / wght 900 sets it within 0.14% with a cap height
     of 71 exactly, which is why it needs no size or tracking compensation.
     ABC Ginto Discord is matched by Archivo at normal width to within 2.29%,
     and --text-track closes the rest.

     One display instance, pinned. The reference loads exactly one Nord face
     (ABCGintoDiscordNord-Bold), so a single pinned instance mirrors it — and
     the served face is DECLARED at font-stretch 140%, so any other value here
     would fail to match it and silently fall back to the next family. */
  --display: 'Roboto Flex', ui-sans-serif, system-ui, sans-serif;
  --display-wdth: 140%;
  --display-wght: 900;
  --text: Archivo, ui-sans-serif, system-ui, -apple-system, sans-serif;
  --text-track: 0.011em;
}

@media (max-width: 1200px) {
  :root {
    --rail: 864px; --gutter: 80px;
    --dxl: 56px; --dxl-lh: 56px; --dxl-tr: -0.03em;
    --dl: 40px;  --dl-lh: 40px;  --dl-tr: -0.01em;
    --ui-lh: 20.8px;
    --nav-h: 70px; --nav-inset: 32px;
    --card-r: 64px; --art-r: 48px;
    --col-text: 392px; --col-art: 392px;
    --row-pitch: 100px; --band-pad: 146px; --hero-pad: 160px;
    --float: 180px;
  }
}

@media (max-width: 860px) {
  :root {
    --rail: 344px; --gutter: 23px;
    --dxl: 38px; --dxl-lh: 38px; --dxl-tr: -0.03em;
    --dl: 35px;  --dl-lh: 35px;  --dl-tr: -0.01em;
    --dm: 24px;  --dm-lh: 24px;
    --bl: 16px;  --bl-lh: 22px;
    --bm: 16px;  --bm-lh: 22px;
    --ui: 14px;  --ui-lh: 18.2px;
    --nav-h: 64px; --nav-inset: 20px;
    --card-r: 56px; --grid-r: 48px; --art-r: 40px;
    --col-text: 100%; --col-art: 100%;
    --row-pitch: 64px; --band-pad: 100px; --hero-pad: 112px;
    --float: 120px;
  }
}

/* ══════════════════════════════════════════════════════════════════ ground */

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

html {
  background: var(--ground);
  /* On the root, not only on body: a clip on body does not stop a wide child
     from widening the layout viewport on a phone. */
  overflow-x: clip;
}

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--text);
  font-size: var(--bl);
  line-height: var(--bl-lh);
  letter-spacing: var(--text-track);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* The reference never scrolls sideways at any width, and a floating prop
     hanging off the rail would make it. clip rather than hidden, so position:
     sticky inside the page keeps working. */
  overflow-x: clip;
}

img, svg, video { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; }

.rail {
  width: min(var(--rail), 100% - var(--gutter) * 2);
  margin-inline: auto;
}

/* ════════════════════════════════════════════════════════════════════ type
 *
 * Roboto Flex pinned at wdth 140 / wght 900, standing in for ABC Ginto
 * Discord Nord 700. The width axis is the whole match: Ginto Nord is a wide
 * companion cut, not a bold, and at normal width no grotesque comes close. */
.dxl, .dl, .dm {
  font-family: var(--display);
  font-stretch: var(--display-wdth);
  font-weight: var(--display-wght);
  text-transform: uppercase;
  margin: 0;
  text-wrap: balance;
}
.dxl { font-size: var(--dxl); line-height: var(--dxl-lh); letter-spacing: var(--dxl-tr); }
.dl  { font-size: var(--dl);  line-height: var(--dl-lh);  letter-spacing: var(--dl-tr); }
.dm  { font-size: var(--dm);  line-height: var(--dm-lh);  letter-spacing: var(--dm-tr); }

.lede { font-size: var(--bl); line-height: var(--bl-lh); margin: 0; color: var(--ink); }
.copy { font-size: var(--bm); line-height: var(--bm-lh); margin: 0; color: var(--ink-dim); }
/* 1.278, from the gift page's card body at 18 / 23. */
.copy { line-height: var(--bm-lh); }

/* ═════════════════════════════════════════════════════════════════ buttons
 *
 * 48 tall, radius 12, 24 of horizontal padding, label at 16/500. Measured
 * identical on both references at all three widths, so it is not responsive. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: var(--btn-h);
  padding-inline: var(--btn-px);
  border: 0;
  border-radius: var(--btn-r);
  font-family: var(--text);
  font-size: 16px;
  font-weight: 500;
  /* 22px, measured, at every width on both references. */
  line-height: 22px;
  white-space: nowrap;
  cursor: pointer;
  transition: transform .14s ease, background-color .14s ease, opacity .14s ease;
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); }
.btn-white { background: #fff; color: #06070f; }
.btn-white:hover { background: #e8eaff; }
.btn-blurple { background: var(--blurple); color: #fff; }
.btn-blurple:hover { background: var(--blurple-lift); }
.btn-ghost { background: transparent; color: #fff; box-shadow: inset 0 0 0 1px var(--hair); }
.btn-ghost:hover { background: rgba(255, 255, 255, .08); }

.btns { display: flex; flex-wrap: wrap; gap: 16px; }

/* Measured at 390 on the reference: the label drops to 14 while the box keeps
   its 48 and its radius 12. */
@media (max-width: 860px) { .btn { font-size: 14px; } }

/* ═════════════════════════════════════════════════════════════════════ nav
 *
 * Static over the hero and transparent, sitting OUTSIDE the content rail: the
 * reference's nav items run wider than its 1200 rail, which is what keeps the
 * bar from reading as a boxed component. */
.nav {
  /* Fixed rather than absolute, so the bar is reachable from anywhere on the
     page. It sits in exactly the same place at the top of the document, so
     the hero's own spacing is unchanged and nothing shifts. */
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 40;
  height: var(--nav-h);
  display: flex;
  align-items: center;
  gap: 24px;
  padding-inline: var(--nav-inset);
}
.nav-brand {
  display: flex; align-items: center; gap: 10px; margin-right: 12px;
  font-size: var(--ui); line-height: var(--ui-lh);
}
.nav-brand img { width: 26px; height: 26px; object-fit: contain; flex: none; }
.nav-brand b {
  font-family: var(--display);
  font-stretch: var(--display-wdth);
  font-weight: var(--display-wght);
  font-size: 19px;
  letter-spacing: -.02em;
}
.nav-links { display: flex; align-items: center; gap: 4px; }
.nav-links a {
  display: inline-flex;
  align-items: center;
  height: 39px;
  padding-inline: 14px;
  border-radius: 12px;
  font-size: var(--ui);
  line-height: var(--ui-lh);
  font-weight: 500;
  letter-spacing: var(--nav-track, var(--text-track));
  transition: background-color .14s ease;
}
.nav-links a:hover { background: rgba(255, 255, 255, .1); }
.nav-right { margin-left: auto; display: flex; align-items: center; gap: 12px; }
.nav-right .btn {
  height: 39px; border-radius: 16px; padding-inline: 18px;
  /* 19.2, not the 22 every other button uses. Measured on both references. */
  line-height: var(--ui-lh);
}
.nav-signin {
  font-size: var(--ui); font-weight: 500;
  padding-inline: 8px;
}

/* A solid fill, not a blur: once the page scrolls the bar stops being a
   sheet of glass over the artwork and simply becomes opaque. */
.nav.is-stuck { background: #0b0e20; border-bottom: 1px solid var(--hair); }

/* The contract address. Empty until there is one, and it takes no space
   it does not need: the colon alone is the label. */
.nav-ca {
  display: inline-flex; align-items: center; gap: 6px;
  height: 39px; padding-inline: 12px; border-radius: 12px;
  background: rgba(255, 255, 255, .06);
  font-size: 13px; font-weight: 500; letter-spacing: var(--text-track);
  color: rgba(255, 255, 255, .72);
  white-space: nowrap;
}
.nav-ca { border: 0; font: inherit; cursor: pointer; transition: background-color .14s ease; }
.nav-ca:hover:not(:disabled) { background: rgba(255, 255, 255, .12); }
/* No address yet: the label stays, because that is the honest state, but it
   does not pretend to be something you can press. */
.nav-ca:disabled { cursor: default; }
.nav-ca b { font-weight: 500; color: #fff; font-variant-numeric: tabular-nums; }

.nav-x {
  display: inline-flex; align-items: center; justify-content: center;
  width: 39px; height: 39px; border-radius: 12px;
  color: #fff;
  transition: background-color .14s ease;
}
.nav-x:hover { background: rgba(255, 255, 255, .1); }

/* The account button and the one menu that holds signing in and signing
   out. The bar shows a face, never a verb, so its width does not change
   when a session appears. */
.nav-me { position: relative; }
.nav-me-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 39px; height: 39px; padding: 0;
  border: 0; border-radius: 50%; cursor: pointer;
  background: rgba(255, 255, 255, .1);
  color: #fff;
  transition: background-color .14s ease;
}
.nav-me-btn:hover { background: rgba(255, 255, 255, .18); }
.nav-me-av { width: 39px; height: 39px; border-radius: 50%; object-fit: cover; display: block; }
.nav-me-av[hidden], .nav-me-any[hidden] { display: none; }

.nav-menu {
  position: absolute; top: calc(100% + 8px); right: 0;
  min-width: 208px; padding: 6px;
  background: #151833;
  border: 1px solid var(--hair);
  border-radius: 14px;
  display: flex; flex-direction: column; gap: 2px;
  z-index: 50;
}
.nav-menu[hidden] { display: none; }
.nav-menu-head {
  padding: 8px 10px 10px;
  border-bottom: 1px solid var(--hair);
  margin-bottom: 4px;
}
.nav-menu-head[hidden] { display: none; }
.nav-menu-head b { display: block; font-size: 14px; font-weight: 600; }
.nav-menu-head small { display: block; font-size: 12px; color: rgba(255, 255, 255, .6); }
.nav-menu a, .nav-menu button {
  display: block; width: 100%; text-align: left;
  padding: 9px 10px; border: 0; border-radius: 9px;
  background: none; color: #fff; cursor: pointer;
  font: inherit; font-size: 14px; font-weight: 500;
  letter-spacing: var(--text-track);
}
.nav-menu a:hover, .nav-menu button:hover { background: rgba(255, 255, 255, .1); }
.nav-menu button[hidden], .nav-menu a[hidden] { display: none; }
.nav-burger {
  display: none;
  width: 40px; height: 40px;
  align-items: center; justify-content: center;
  background: none; border: 0; border-radius: 12px; cursor: pointer;
}
.nav-burger span { display: block; width: 18px; height: 2px; background: #fff; box-shadow: 0 -6px #fff, 0 6px #fff; }

@media (max-width: 1200px) {
  /* Measured at 1024: 14 / 16 with -0.01em, where 1440 is 16 / 19.2 with none. */
  .nav-links a, .nav-brand { font-size: 14px; line-height: 16px; }
  .nav-links a { --nav-track: -0.01em; }
}

@media (max-width: 1060px) {
  .nav-links { display: none; }
  .nav-burger { display: inline-flex; }
  .nav-signin { display: none; }
  /* The address is long and the bar is short. The account button and the
     link to X stay, because both are one tap and neither is text. */
  .nav-ca { display: none; }
}

/* At 390 the reference's nav is the brand and one rounded-square burger on a
   translucent fill, and nothing else. Keeping the CTA pill there pushed the
   bar 9px past the viewport, which on a phone widens the layout viewport
   rather than clipping. */
@media (max-width: 860px) {
  .nav-right .btn { display: none; }
  .nav-brand b { font-size: 26px; letter-spacing: -.6px; }
  .nav-brand svg { width: 32px; height: 32px; }
  .nav-burger {
    width: 48px; height: 48px;
    background: rgba(255, 255, 255, .13);
  }
  .nav-burger span { width: 20px; box-shadow: 0 -7px #fff, 0 7px #fff; }
}

/* ════════════════════════════════════════════════════════════════════ hero
 *
 * The ground is the section, not a decoration on it: a 3b45a4-to-black ramp
 * about 62% as tall as the hero. Measured at 1440: #3b45a4 at y=0 reaching
 * #000 by y≈900 of a 1347px band. */
.hero {
  position: relative;
  isolation: isolate;
  padding-bottom: 0;
}
/* The hero used to paint its own ramp over the ground. The ground is now
   the same flat blurple everywhere, so the hero simply shows it. */
.hero-inner { padding-top: var(--hero-pad); text-align: center; }
.hero .dxl { max-width: 15ch; margin-inline: auto; }
.hero .lede {
  max-width: 52ch;
  margin: 24px auto 0;
  color: var(--ink);
}
.hero .btns { justify-content: center; margin-top: 32px; }

@media (max-width: 860px) {
  .hero .dxl { max-width: 100%; }
}

/* ═══════════════════════════════════════════════════════ floating 3D props
 *
 * Placed to overlap the rail edge rather than to sit inside it: at 1440 the
 * reference's left prop starts at x=72 where the rail starts at 120. */
.prop {
  position: absolute;
  width: var(--float);
  height: var(--float);
  z-index: 2;
  pointer-events: none;
  object-fit: contain;
  filter: drop-shadow(0 22px 40px rgba(0, 0, 0, .45));
  animation: bob 7s ease-in-out infinite;
}
.prop.is-slow { animation-duration: 9.5s; animation-delay: -2.6s; }
@keyframes bob {
  0%, 100% { transform: translateY(0) rotate(var(--tilt, 0deg)); }
  50% { transform: translateY(-14px) rotate(calc(var(--tilt, 0deg) + 2.5deg)); }
}
@media (prefers-reduced-motion: reduce) {
  .prop { animation: none; transform: rotate(var(--tilt, 0deg)); }
}

/* Placement, per prop, per width. The reference puts its props at the rail's
   edge and lets the viewport crop them; it never puts one over a headline.
   At 1440 its left prop starts at x=72 where the rail starts at 120. */
[data-prop="hero-l"]  { --tilt: -8deg;  left: 3%;    top: 96px; }
[data-prop="hero-r"]  { --tilt: 11deg;  right: 2.5%; top: 31%; }
[data-prop="slab-l"]  { --tilt: -10deg; left: -4%;   top: -16%; }
[data-prop="slab-r"]  { --tilt: 9deg;   right: -4%;  bottom: -18%; }
[data-prop="end-l"]   { --tilt: -14deg; left: 4%;    top: 50%; }
[data-prop="end-r"]   { --tilt: 12deg;  right: 3%;   top: 56%; }

@media (max-width: 1200px) {
  [data-prop="hero-l"] { left: 1%;    top: 88px; }
  [data-prop="hero-r"] { right: 0.5%; top: 30%; }
  [data-prop="end-l"]  { left: 1%; }
  [data-prop="end-r"]  { right: 1%; }
}

/* At 390 the headline is five lines and fills the rail, so nothing can sit
   beside it. The props drop below the buttons and hang off both edges, which
   is where the reference's mobile props are. */
@media (max-width: 860px) {
  /* The hero's two props come out at 390. The reference can keep props in its
     mobile hero because its headline is three lines; ours is five, and with
     two CTAs under it there is no clear space left — every position tried put
     artwork on either the words or the buttons. The slab and the closing band
     keep theirs, so the page still floats objects at this width. */
  [data-prop="hero-l"], [data-prop="hero-r"] { display: none; }
  [data-prop="slab-l"] { left: -10%; top: -11%; }
  [data-prop="slab-r"] { right: -10%; bottom: -12%; }
  [data-prop="end-l"]  { left: -8%;  top: 58%; }
  [data-prop="end-r"]  { right: -8%; top: 64%; }
}

/* ══════════════════════════════════════════════════════════════════ bands */

.band { position: relative; padding-top: var(--band-pad); }
/* 120 between consecutive content bands, 200 only after the ground changes,
   which is the reference's own rhythm. */
.band + .band { padding-top: var(--row-pitch); }
.band-head { text-align: center; }
.band-head .lede { max-width: 56ch; margin: 16px auto 0; color: var(--ink-dim); }

/* ════════════════════════════════════════════════════════ alternating rows
 *
 * 579 of text beside a 443 card with 178 between them, alternating side each
 * time and stacking at 860. */
.row {
  display: grid;
  grid-template-columns: var(--col-text) var(--col-art);
  justify-content: space-between;
  align-items: center;
  gap: 0 calc(var(--rail) - var(--col-text) - var(--col-art));
  margin-top: var(--row-pitch);
}
.row:first-of-type { margin-top: 0; }
@media (min-width: 861px) {
  .row.is-flipped { grid-template-columns: var(--col-art) var(--col-text); }
  .row.is-flipped .row-text { order: 2; }
  .row.is-flipped .card { order: 1; }
}
.row-text .lede { margin-top: 20px; color: var(--ink-dim); max-width: 34ch; }
.row-text .btns { margin-top: 28px; }
.row-note {
  margin-top: 20px;
  font-size: 15px;
  line-height: 21px;
  color: var(--ink-mute);
}

@media (max-width: 1200px) {
  .row { gap: 0 80px; }
}
@media (max-width: 860px) {
  .row { grid-template-columns: 1fr; gap: 32px; text-align: center; }
  .row .card { order: 0; }
  .row .row-text { order: 1; }
  .row-text .lede { margin-inline: auto; }
  .row-text .btns { justify-content: center; }
}

/* ══════════════════════════════════════════════════════════════════ cards
 *
 * The signature container: radius 72 at 1440, a gradient fill, and product UI
 * inset and clipped inside it. The card is the frame and the UI is the
 * subject, which is why the screenshot is never floated on top of it. */
.card {
  position: relative;
  border-radius: var(--card-r);
  overflow: hidden;
  aspect-ratio: 443 / 600;
  display: grid;
  place-items: center;
  isolation: isolate;
}
.card.is-green   { background: linear-gradient(171deg, var(--green), var(--mint)); }
.card.is-blurple { background: linear-gradient(180deg, var(--blurple), var(--lavender)); }
.card.is-magenta { background: linear-gradient(180deg, var(--magenta), var(--blush)); }
.card.is-sun     { background: linear-gradient(180deg, var(--sun-a), var(--sun-b) 72%, var(--sun-c)); }
.card > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.card > .ui { width: 82%; transform: translateZ(0); }

@media (max-width: 860px) { .card { aspect-ratio: 343 / 484; } }

/* ═══════════════════════════════════════════════════════════════ card grid
 *
 * 3 up at 384 with a 24 gap and radius 56, art inset 16 at radius 48. */
.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
  margin-top: 56px;
}
.gcard {
  border-radius: var(--grid-r);
  padding: 16px 16px 32px;
  background: var(--panel-dark);
  box-shadow: inset 0 0 0 1px var(--hair);
}
.gcard-art {
  aspect-ratio: 1;
  border-radius: var(--art-r);
  overflow: hidden;
  background: var(--panel-deep);
  display: grid;
  place-items: center;
}
.gcard-art img { width: 100%; height: 100%; object-fit: cover; }
.gcard .dm { margin-top: 24px; }
.gcard .copy { margin-top: 12px; }

@media (max-width: 1200px) { .grid { grid-template-columns: 1fr; gap: 20px; } }

/* ═════════════════════════════════════════════════════════════ feature slab
 *
 * The gift page's "already have a gift card?" band: one wide rounded
 * container, centred type, a white pill, and 3D props breaking its edges. */
.slab {
  position: relative;
  margin-top: 72px;
  border-radius: var(--card-r);
  /* A panel, not the ground: it has to read as a distinct surface sitting
     on the blue, so it stays dark and flat. */
  background: var(--panel-dark);
  padding: 96px 64px;
  text-align: center;
  overflow: visible;
}
.slab .lede { max-width: 48ch; margin: 18px auto 0; color: var(--ink-dim); }
.slab .btns { justify-content: center; margin-top: 32px; }
@media (max-width: 860px) { .slab { padding: 64px 24px; } }

/* ═════════════════════════════════════════════════════════════ closing band
 *
 * pad-top 160, pad-bottom 288 at 1440, on a ground that has already begun
 * climbing back towards blurple. */
.closing {
  position: relative;
  margin-top: 200px;
  padding-top: 160px;
  padding-bottom: 288px;
  text-align: center;
  isolation: isolate;
}
/* The closing band used to fade from black up to blurple. It is the same
   blurple as everything else now, so it paints nothing of its own. */
.closing .lede { max-width: 52ch; margin: 20px auto 0; }
.closing .btns { justify-content: center; margin-top: 32px; }
@media (max-width: 860px) { .closing { padding-bottom: 180px; margin-top: 120px; } }

/* ═══════════════════════════════════════════════════════════════════ footer
 *
 * Ground keeps climbing to #525ee4, four 200-wide link columns on a 220 pitch
 * starting at x=540, and a wordmark that bleeds off the bottom edge. */
.foot {
  position: relative;
  padding-top: 20px;
  background: var(--ground);
  overflow: hidden;
}
.foot-grid {
  display: grid;
  grid-template-columns: 320px repeat(4, 200px);
  justify-content: space-between;
  gap: 40px 20px;
  padding-top: 80px;
}
.foot-brand b {
  font-family: var(--display);
  font-stretch: var(--display-wdth);
  font-weight: var(--display-wght);
  font-size: 20px;
  letter-spacing: -.02em;
}
.foot-brand p { margin: 16px 0 0; font-size: 14px; line-height: 21px; color: rgba(255, 255, 255, .72); max-width: 30ch; }
.foot-col > summary {
  margin: 0 0 4px;
  font-size: 16px;
  line-height: 20px;
  /* 400, measured. A heavier weight here was the single most visible
     typographic difference in the footer comparison. */
  font-weight: 400;
  color: #fff;
}
.foot-col a {
  display: block;
  padding: 6px 0;
  font-size: 16px;
  line-height: 24px;
  font-weight: 400;
  color: rgba(255, 255, 255, .86);
}
.foot-col a:hover { color: #fff; text-decoration: underline; }
.foot-legal {
  margin-top: 72px;
  padding-top: 20px;
  border-top: 1px solid rgba(255, 255, 255, .22);
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
  font-size: 13px;
  line-height: 20px;
  color: rgba(255, 255, 255, .72);
}

/* The wordmark: full bleed, clipped by the footer's bottom edge. Measured at
   1440 × 332 out of an 816 tall footer, so it is 41% of the footer's height
   and every pixel of the viewport's width. */
.wordmark {
  display: block;
  width: 100%;
  margin-top: 64px;
  margin-bottom: -4.6%;
  font-family: var(--display);
  font-stretch: var(--display-wdth);
  font-weight: var(--display-wght);
  color: var(--wordmark);
  letter-spacing: -.02em;
  line-height: 1.18;
  text-align: center;
  font-size: 15.6vw;
  user-select: none;
}

/* The reference's columns are 200 wide on a 220 pitch at 1440 and 141 on a
   160 pitch at 1024. Ours were 1fr, which came out at 126 and wrapped. */
@media (max-width: 1200px) { .foot-grid { grid-template-columns: 240px repeat(4, 141px); } }

/* Desktop: a <details> is a plain column. The marker and the pointer are
   removed so nothing suggests it can be collapsed at a width where it never
   is. */
.foot-col > summary { list-style: none; cursor: default; }
.foot-col > summary::-webkit-details-marker { display: none; }
.foot-col > summary i { display: none; }

@media (max-width: 860px) {
  .foot-grid { grid-template-columns: 1fr; gap: 0; padding-top: 64px; }
  .foot-brand { margin-bottom: 36px; }
  .foot-col {
    border-top: 1px solid rgba(255, 255, 255, .22);
  }
  .foot-col > summary {
    display: flex; align-items: center; justify-content: space-between;
    padding: 16px 0; cursor: pointer;
    /* 18 / 20 at weight 500 at 390, measured. */
    font-size: 18px; line-height: 20px; font-weight: 500;
  }
  .foot-col > summary i {
    display: block; width: 10px; height: 10px;
    border-right: 2px solid rgba(255, 255, 255, .8);
    border-bottom: 2px solid rgba(255, 255, 255, .8);
    transform: rotate(45deg) translate(-2px, -2px);
    transition: transform .18s ease;
  }
  .foot-col[open] > summary i { transform: rotate(225deg) translate(-2px, -2px); }
  /* 14 / 18 at 390, measured. */
  .foot-col a { padding: 8px 0; font-size: 14px; line-height: 18px; }
  .foot-col > a:last-child { padding-bottom: 18px; }
  .wordmark { font-size: 21vw; margin-bottom: -4%; }
}

/* ═══════════════════════════════════════════════════════════ product UI
 *
 * Real DiscordPad interface, drawn at card scale. These are the actual
 * controls and the actual figures, shrunk to fit a 443px card, not a picture
 * of an interface. */
.ui {
  border-radius: 18px;
  background: #0d1020;
  box-shadow: 0 24px 60px rgba(0, 0, 0, .46), inset 0 0 0 1px rgba(255, 255, 255, .1);
  padding: 16px;
  font-size: 13px;
  line-height: 18px;
  text-align: left;
  color: var(--ink);
}
.ui-bar { display: flex; align-items: center; gap: 6px; margin-bottom: 14px; }
.ui-bar i { width: 8px; height: 8px; border-radius: 50%; background: rgba(255, 255, 255, .2); }
.ui-label {
  font-size: 11px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-mute);
  font-weight: 600;
}
.ui-field {
  margin-top: 8px;
  padding: 10px 12px;
  border-radius: 10px;
  background: #06080f;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .12);
  font-family: ui-monospace, 'SFMono-Regular', Menlo, monospace;
  font-size: 12px;
  color: #dfe2ff;
}
.ui-person { display: flex; align-items: center; gap: 10px; padding: 9px 0; }
.ui-person + .ui-person { border-top: 1px solid rgba(255, 255, 255, .08); }
.ui-av { width: 28px; height: 28px; border-radius: 50%; flex: none; }
.ui-person b { font-weight: 600; }
.ui-person small { display: block; color: var(--ink-mute); font-size: 11px; }
.ui-share { margin-left: auto; font-weight: 600; font-variant-numeric: tabular-nums; }
.ui-total {
  display: flex; justify-content: space-between;
  margin-top: 12px; padding-top: 10px;
  border-top: 1px solid rgba(255, 255, 255, .14);
  font-weight: 600;
}
.ui-amount {
  font-family: var(--display); font-stretch: var(--display-wdth); font-weight: var(--display-wght);
  font-size: 30px; line-height: 1; letter-spacing: -.02em;
  margin: 6px 0 2px;
}
.ui-ok { color: var(--green); }

/* ════════════════════════════════════════════════════════ entrance motion
 *
 * Section entrance, not a scroll film: each band rises once when it reaches
 * the viewport and then stays put. The page is fully usable before any of it
 * has run, because the resting state is the visible one and the class is only
 * added if the observer is available. */
.rise { opacity: 0; transform: translateY(26px); }
.rise.is-in {
  opacity: 1;
  transform: none;
  transition: opacity .62s cubic-bezier(.22, .61, .36, 1), transform .62s cubic-bezier(.22, .61, .36, 1);
}
@media (prefers-reduced-motion: reduce) {
  .rise, .rise.is-in { opacity: 1; transform: none; transition: none; }
}

/* The mock rows show Discord's own default avatars now, so this can be an
   image. Sized explicitly, because an <img> with no box collapses before it
   loads and the row would jump when it arrives. */
img.ui-av { object-fit: cover; flex: none; }
