/* The sponsor wall, at the foot of the home page above the footer. Loaded
   after styles.css and desktop.css. The
   Supporters live on a Mac: the brand wallpaper with its menu bar, and the
   people as icons. Without script, on touch screens and on narrow windows it is
   Launchpad: a calm grid on the dimmed wallpaper that names everyone under
   their tile. With a mouse or trackpad it is the Dock (sponsors.ts adds
   .is-live): each shelf stands on a glass Dock that spreads as the tiles swell
   under the pointer or keyboard focus, and the one you are on shows its name in
   a tooltip above it. */

.wall {
  margin-top: calc(32 * var(--u));
}
.wall-head {
  display: grid;
  justify-items: center;
  gap: calc(4 * var(--u));
  margin-bottom: calc(20 * var(--u));
  text-align: center;
}
.wall-count {
  display: inline-flex;
  align-items: center;
  gap: calc(10 * var(--u));
  margin: 0;
  padding: calc(9 * var(--u)) calc(16 * var(--u));
  border-radius: 999px;
  background: rgb(24 33 38 / 0.05);
  color: var(--ink);
  font-size: calc(13 * var(--u));
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
/* A live dot: the wall is updated as Supporters join. */
.wall-count::before {
  content: "";
  flex: none;
  width: calc(8 * var(--u));
  height: calc(8 * var(--u));
  border-radius: 50%;
  background: linear-gradient(135deg, #3a86ff, #8a3dff);
  box-shadow: 0 0 0 calc(3 * var(--u)) rgb(58 134 255 / 0.16);
}
/* Shown while the live Dock holds keyboard focus; its words also describe
   each tile to screen readers (aria-describedby, set by sponsors.ts). */
.wall-keys {
  display: none;
  margin: 0;
  color: var(--muted);
  font-size: calc(12 * var(--u));
  line-height: 1.6;
  opacity: 0;
  transition: opacity 160ms ease;
}
.wall:has(.dock.is-live) .wall-keys {
  display: block;
}
.wall:has(.dock.is-live:focus-within) .wall-keys {
  opacity: 1;
}
/* On the home page the wall stands between the FAQ and the launch bookend,
   with no rule of its own, and the launch follows it without its own top
   margin: the launch's padding and glow are the air between them. Its head
   is the launch heading's two lines, one step smaller. */
.sponsors {
  margin-top: calc(128 * var(--u));
}
.sponsors + .launch {
  margin-top: 0;
}
.sponsors-intro {
  text-align: center;
}
.sponsors-intro h2 {
  font-size: clamp(38 * var(--u), 4vw, 56 * var(--u));
  font-weight: 700;
  letter-spacing: -0.035em;
  line-height: 1.06;
}
.sponsors-sub {
  display: block;
  color: var(--soft);
}
/* The thanks ends in a heart instead of a full stop, in the app icon's
   gradient (the count's dot wears it too). The first time the wall comes
   into view (sponsors.ts adds .is-thanked) it beats once, lub-dub, and a
   ring of the same light spreads from it. */
.thanks-heart {
  position: relative;
  display: inline-block;
  width: 0.6em;
  height: 0.6em;
  margin-left: 0.08em;
  vertical-align: baseline;
}
.thanks-heart svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
  transform-origin: 50% 60%;
}
.thanks-heart::after {
  content: "";
  position: absolute;
  inset: -20%;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgb(58 134 255 / 0.35), rgb(138 61 255 / 0));
  opacity: 0;
  pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
  .sponsors.is-thanked .thanks-heart svg {
    animation: thanks-beat 1100ms 200ms both;
  }
  .sponsors.is-thanked .thanks-heart::after {
    animation: thanks-ring 1100ms 200ms cubic-bezier(0.19, 1, 0.22, 1) both;
  }
}
@keyframes thanks-beat {
  0% {
    transform: scale(1);
    animation-timing-function: cubic-bezier(0.3, 0, 0.2, 1);
  }
  14% {
    transform: scale(1.24);
    animation-timing-function: cubic-bezier(0.4, 0, 0.6, 1);
  }
  30% {
    transform: scale(0.96);
    animation-timing-function: cubic-bezier(0.3, 0, 0.2, 1);
  }
  44% {
    transform: scale(1.14);
    animation-timing-function: cubic-bezier(0.19, 1, 0.22, 1);
  }
  100% {
    transform: scale(1);
  }
}
@keyframes thanks-ring {
  0% {
    transform: scale(0.6);
    opacity: 0;
  }
  14% {
    opacity: 1;
  }
  100% {
    transform: scale(2.6);
    opacity: 0;
  }
}
.sponsors-intro p {
  max-width: 52ch;
  margin: calc(14 * var(--u)) auto 0;
  color: var(--muted);
  font-size: calc(15 * var(--u));
  line-height: 1.7;
}
:is(.sponsors-intro h2, .wall-empty .dock-name):lang(zh) {
  letter-spacing: 0;
}
.sponsors-intro h2:lang(zh) {
  line-height: 1.2;
}

@media (max-width: 760px) {
  .wall:has(.dock.is-live) .wall-keys {
    display: none;
  }
}

/* The screen. The Dock sits at its foot, as on a Mac; a short wall leaves
   the wallpaper above it. */
.wall-desktop {
  --accent: #dbe7ff;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: calc(500 * var(--u));
}
/* Launchpad dims and softens the wallpaper, so the names read on every fold. */
.wall-desktop::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: rgb(8 10 40 / 0.5);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  transition: opacity 300ms ease;
}
.wall-desktop:has(.dock.is-live)::before {
  opacity: 0;
}

.dock-frame {
  position: relative;
  padding: calc(96 * var(--u)) calc(40 * var(--u)) calc(44 * var(--u));
}

/* Launchpad: every tile named beneath it, in white. */
.dock {
  --tile: calc(64 * var(--u));
  --air: calc(10 * var(--u));
  --cell: calc(116 * var(--u));
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(var(--cell), 1fr));
  row-gap: calc(36 * var(--u));
  margin: 0;
  padding: 0;
  list-style: none;
}
.dock-item {
  position: relative;
  display: grid;
  align-content: start;
  justify-items: center;
  min-width: 0;
}
.dock .portrait {
  --size: var(--tile);
  box-shadow: 0 calc(6 * var(--u)) calc(16 * var(--u)) calc(-6 * var(--u)) rgb(2 3 20 / 0.6);
}
.dock .portrait::after {
  border-color: rgb(255 255 255 / 0.14);
}
/* Your own tile carries the Dock's running-app dot. */
.dock-item.is-you::after {
  content: "";
  position: absolute;
  top: calc(var(--tile) + var(--air) / 2 - 2 * var(--u));
  left: calc(50% - 2 * var(--u));
  width: calc(4 * var(--u));
  height: calc(4 * var(--u));
  border-radius: 50%;
  background: rgb(255 255 255 / 0.9);
  transform: translateX(var(--shift, 0px));
  transition: transform 260ms var(--ease);
}
.dock-label {
  display: grid;
  justify-items: center;
  gap: calc(2 * var(--u));
  min-width: 0;
  max-width: 100%;
  margin: calc(var(--air) + 6 * var(--u)) 0 0;
  padding-inline: calc(8 * var(--u));
  text-align: center;
}
.dock-name {
  display: -webkit-box;
  overflow: hidden;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  color: #fff;
  font-size: calc(13 * var(--u));
  font-weight: 600;
  line-height: 1.4;
  overflow-wrap: anywhere;
  text-shadow: 0 1px 3px rgb(2 3 20 / 0.55);
}
.dock-since {
  color: rgb(255 255 255 / 0.78);
  font-size: calc(12 * var(--u));
  line-height: 1.5;
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 3px rgb(2 3 20 / 0.55);
}
.dock-you {
  color: #fff;
  font-weight: 600;
}
/* In the grid the month is enough, and "You" takes its own line above it; the
   words stay for screen readers. */
.dock:not(.is-live) .dock-since-word {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.dock:not(.is-live) .dock-you {
  display: block;
}
.dock:not(.is-live) .dock-you-sep {
  display: none;
}

/* The live Dock: centred shelves with room above to swell into and room at the
   ends to spread. sponsors.ts evens the shelves out (--shelf tiles each), sets
   --scale and --shift on each item of the shelf under the pointer, and lays a
   glass shelf (.dock-shelf) under each row that it widens with the swell. */
.dock.is-live {
  --gap: calc(14 * var(--u));
  --end: calc(var(--tile) * 0.82);
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: calc(120 * var(--u)) var(--gap);
  max-width: calc(var(--shelf, 999) * (var(--tile) + var(--gap)) - var(--gap) + 2 * var(--end));
  margin-inline: auto;
  padding: calc(8 * var(--u)) var(--end) 0;
}
.dock.is-live .dock-item {
  width: var(--tile);
  outline: none;
}
.dock.is-live .portrait {
  transform: translateX(var(--shift, 0px)) scale(var(--scale, 1));
  transform-origin: 50% 100%;
  transition: transform 260ms var(--ease);
}
.dock.is-live.is-tracking .portrait,
.dock.is-live.is-tracking .dock-item.is-you::after,
.dock.is-live.is-tracking ~ .dock-shelf {
  transition-duration: 90ms;
  transition-timing-function: linear;
}
/* The tooltip: one at a time, above the tile you are on, as the Dock names an
   app. */
.dock.is-live .dock-label {
  position: absolute;
  bottom: calc(var(--tile) * var(--scale, 1) + 14 * var(--u));
  left: 50%;
  z-index: 2;
  width: max-content;
  max-width: min(24em, 86vw);
  margin: 0;
  padding: calc(8 * var(--u)) calc(14 * var(--u)) calc(9 * var(--u));
  border-radius: calc(12 * var(--u));
  background: rgb(248 250 255 / 0.88);
  box-shadow:
    inset 0 0 0 1px rgb(255 255 255 / 0.6),
    0 calc(10 * var(--u)) calc(30 * var(--u)) calc(-10 * var(--u)) rgb(2 3 20 / 0.6);
  -webkit-backdrop-filter: blur(20px) saturate(1.6);
  backdrop-filter: blur(20px) saturate(1.6);
  opacity: 0;
  pointer-events: none;
  transform: translate(calc(-50% + var(--shift, 0px) + var(--nudge, 0px)), 6px);
  transition:
    opacity 140ms ease,
    bottom 260ms var(--ease),
    transform 320ms var(--ease);
}
.dock.is-live .dock-item.is-active .dock-label {
  opacity: 1;
  transform: translate(calc(-50% + var(--shift, 0px) + var(--nudge, 0px)), 0);
}
.dock.is-live .dock-name {
  display: block;
  overflow: visible;
  color: var(--ink);
  font-size: calc(15 * var(--u));
  line-height: 1.3;
  text-shadow: none;
}
.dock.is-live .dock-since,
.dock.is-live .dock-you {
  color: var(--muted);
  text-shadow: none;
}
.dock.is-live .dock-you {
  color: var(--ink);
}
.dock.is-live .dock-item:focus-visible .portrait {
  outline: 2px solid var(--accent);
  outline-offset: 4px;
}

/* A glass shelf under each row of the live Dock. sponsors.ts places it from
   the unswollen layout (--x, --y, --w) and widens it to the swollen tiles at
   either end (--grow-l, --grow-r). */
.dock-shelf {
  position: absolute;
  top: var(--y);
  left: calc(var(--x) + var(--grow-l, 0px));
  width: calc(var(--w) - var(--grow-l, 0px) + var(--grow-r, 0px));
  height: calc(var(--tile-h) + 18 * var(--u));
  border-radius: calc(22 * var(--u));
  background: rgb(255 255 255 / 0.16);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.42),
    inset 0 0 0 1px rgb(255 255 255 / 0.2),
    0 calc(12 * var(--u)) calc(32 * var(--u)) calc(-12 * var(--u)) rgb(2 3 20 / 0.5);
  -webkit-backdrop-filter: blur(24px) saturate(1.8);
  backdrop-filter: blur(24px) saturate(1.8);
  pointer-events: none;
  transition:
    left 260ms var(--ease),
    width 260ms var(--ease);
}

/* No one listed yet: an empty Dock holding one open slot. */
.wall-empty {
  --tile: calc(64 * var(--u));
  display: grid;
  justify-items: center;
  text-align: center;
}
.wall-empty .desk-dock {
  padding: calc(8 * var(--u));
}
.wall-empty-slot {
  --size: var(--tile);
  border: 1px dashed rgb(255 255 255 / 0.55);
  background: rgb(255 255 255 / 0.06);
}
.wall-empty-slot::after {
  display: none;
}
.wall-empty-slot svg {
  width: calc(22 * var(--u));
  height: calc(22 * var(--u));
  fill: none;
  stroke: #fff;
  stroke-width: 1.6;
  stroke-linecap: round;
}
.wall-empty .dock-label {
  margin-top: calc(20 * var(--u));
}
.wall-empty .dock-name {
  font-family: var(--display);
  font-size: calc(22 * var(--u));
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: -0.02em;
}

/* The launch's own keys (.hero-button), so the page closes on one set. */
.wall-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: calc(12 * var(--u));
  margin-top: calc(32 * var(--u));
}
.wall-actions .hero-button {
  flex: 0 1 auto;
}
.wall-actions .wall-ink {
  color: #fff;
  background-color: var(--ink);
}
.wall-actions .hero-button svg {
  transition: transform 220ms var(--ease);
}
@media (prefers-reduced-motion: no-preference) {
  .wall-actions .hero-button:hover svg {
    transform: translateX(3px);
  }
}

@media (max-width: 760px) {
  .wall {
    margin-top: 28px;
  }
  .wall-desktop {
    min-height: 420px;
    border-radius: 18px;
  }
  .dock-frame {
    padding: 72px 16px 32px;
  }
  .dock {
    --cell: 100px;
  }
  .dock.is-live {
    --tile: 56px;
    --gap: 12px;
    row-gap: 108px;
  }
  .wall-actions {
    margin-top: 28px;
  }
  .sponsors {
    margin-top: 88px;
  }
  .wall-desktop .desk-menus span {
    display: none;
  }
}
@media (max-width: 540px) {
  .dock {
    --tile: 56px;
    --cell: 88px;
    row-gap: 28px;
  }
  .dock-frame {
    padding: 64px 8px 28px;
  }
}
@media (prefers-reduced-motion: reduce) {
  .dock.is-live .portrait,
  .dock-item.is-you::after,
  .dock-shelf {
    transition: none;
  }
  .dock.is-live .dock-label,
  .dock.is-live .dock-item.is-active .dock-label {
    transform: translateX(calc(-50% + var(--nudge, 0px)));
    transition: opacity 140ms ease;
  }
}
@media (forced-colors: active) {
  .dock-item.is-you::after {
    background: CanvasText;
    forced-color-adjust: none;
  }
  .dock-shelf,
  .dock.is-live .dock-label {
    border: 1px solid CanvasText;
  }
}
