/* ============================================================
   Orrery — hero section

   The plate is a sunrise seen from a ridge above a cloud sea,
   with a cratered moon to the left, a second small moon, and a
   ringed giant filling the top right. It is symmetrical, bright
   and centre-weighted — the hardest kind of frame to set type
   on. Measured over the whole loop, as the contrast a #FFF6EC
   ink keeps against the brightest frame of each cell:

     the sun, the spires, the cloud sea      1.0-2.5:1
     dark ink, anywhere                      up to 5.1:1 at best
     the top band, left of the giant         8.2-13.7:1
     the rock in the bottom-left corner      5.7-16.7:1

   So: the ink is warm white, dark ink is never used, and the
   copy stands on the rock in the bottom-left corner — the one
   surface in the frame that stays dark under a rising sun. The
   rock is a wedge that widens as it falls, which is why the
   headline's second line is the longer one: the block is cut to
   the shape of the ledge it sits on, not to a column.

   That corner is also why the plate is anchored left bottom.
   Cover trims a 16:9 plate off the flanks or the top depending
   on the window, and only a bottom anchor keeps the ledge on
   screen at every shape.

   Phones get an upright plate of the same scene, composed for
   the frame rather than cropped out of the wide one. Its rock
   is narrower — see the upright block near the foot of this
   file — so the headline sets in three lines there.

   There is no navigation. A row of links across the top would
   run onto the giant's lit limb (1.2:1 at x 0.78-0.87), and a
   button standing in for them needed a ground of its own to
   read there. So the top bar carries the wordmark and nothing
   else, and the frame stays open.

   Fraunces sets the headline — an optical serif with the ball
   terminals and the slight wonk of an old almanac title page,
   which is the book this product replaces. Archivo sets the
   rest: the plain grotesque of a table of figures.
   ============================================================ */

:root {
  --void:  #090810;   /* the rock in the corner: the page's own ground */
  --ink:   #FFF6EC;   /* the sun's core, warmed: type */
  --ember: #F77F2D;   /* the lit edge of the cloud sea: mark, focus ring */
  --ash:   rgba(255, 246, 236, .76);   /* the lede, on the rock */

  --display: "Fraunces", "Iowan Old Style", Georgia, serif;
  --util:    "Archivo", ui-sans-serif, "Helvetica Neue", Arial, sans-serif;

  --gutter: clamp(1.25rem, 3vw, 2.75rem);
  --ease:   cubic-bezier(.22, .61, .36, 1);

  /* The ledge, in CSS pixels, derived from the plate rather than the screen.
     The rock holds x 0.00-0.19 and y 0.75-1.00 of the plate, and cover renders
     the plate at max(vw/1920, vh/1080) — so those two fractions come out as the
     expressions below. Size the type off vh alone and a 16:9 window, which
     crops nothing and so shows the ledge at its smallest, walks the headline
     off the rock and onto the cloud. */
  --ledge-w: max(19vw, 33.78vh);
  --ledge-h: max(14.06vw, 25vh);
  /* everything in the block that is not the two headline lines — the lede, the
     button, the gaps between them and the gutter under the last of them. The
     headline gets the rest of the ledge and no more. */
  --below: 137px;
}

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

html, body { margin: 0; }

body {
  background: var(--void);
  color: var(--ink);
  font-family: var(--util);
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; text-decoration: none; }

:focus-visible { outline: 2px solid var(--ember); outline-offset: 4px; }

/* ---------- stage ---------- */

.hero {
  position: relative;
  min-height: 100svh;
  overflow: hidden;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto 1fr;
  padding: 0 var(--gutter) clamp(1.25rem, 3vh, 2.25rem);
}

.hero__media { position: absolute; inset: 0; }

.hero__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* the copy stands on the rock in the bottom-left corner, so that corner is
     the one part of the plate that must survive every crop */
  object-position: left bottom;
  display: block;
}

/* ---------- top bar ---------- */

.topbar {
  grid-column: 1 / -1;
  grid-row: 1;
  position: relative;
  z-index: 3;
  display: flex;
  align-items: center;
  padding-block: clamp(.9rem, 2.4vh, 1.6rem);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: .7rem;
  font-family: var(--display);
  font-variation-settings: "opsz" 40, "SOFT" 0, "WONK" 1;
  font-weight: 500;
  font-size: clamp(1.3rem, 1.6vw, 1.55rem);
  letter-spacing: .005em;
}

.brand__word { white-space: nowrap; }

/* ---------- the mark ----------
   An orrery: one orbit seen at an angle, its star, and the two moons the
   product exists to keep track of. It is the only ornament on the page. */

.mark { width: 30px; height: 30px; flex: none; }

.mark__orbit {
  fill: none;
  stroke: var(--ember);
  stroke-width: 1.1;
}

.mark__star { fill: var(--ink); }

.mark__moon {
  fill: var(--ink);
  /* a gap in the ground colour, so a moon reads as passing in front of the
     orbit rather than sitting on the line */
  stroke: var(--void);
  stroke-width: 1.7;
  paint-order: stroke;
  /* the same ellipse as the orbit, written as a path so the moons can ride it */
  offset-path: path("M 2.8,15 A 12.2,5.4 0 1 1 27.2,15 A 12.2,5.4 0 1 1 2.8,15");
  offset-rotate: 0deg;
  offset-distance: var(--at);
}
.mark__moon--near { --at: 38%; }
.mark__moon--far  { --at: 88%; fill: var(--ember); }

/* A window wider than 2:1 crops enough off the plate's top that, with the
   bottom anchored, the top bar slides down off the night sky and onto the lit
   haze — 2.1:1 at 844x390, against 4.9:1 at 2:1 exactly. Past that line the
   wordmark takes a ground, in the page's own colour and sized to the words.
   Everywhere else the sky behind it is already dark and the brand is plain
   type on the footage. */

@media (min-aspect-ratio: 2 / 1) {
  .brand {
    margin-left: -.55rem;
    padding: .3rem .55rem;
    background: var(--void);
  }
}

/* ---------- copy, on the ledge ---------- */

.hero__copy {
  grid-column: 1;
  grid-row: 2;
  position: relative;
  z-index: 2;
  justify-self: start;
  /* the rock is the floor of the frame, so the block sits on the floor */
  align-self: end;
  max-width: calc(var(--ledge-w) - var(--gutter));
}

.title {
  margin: 0;
  font-family: var(--display);
  font-variation-settings: "opsz" 144, "SOFT" 0, "WONK" 0;
  font-weight: 400;
  /* "Two tide tables." measures 6.77em in this face, so dividing the ledge by
     6.85 makes the headline as large as the rock will carry and never a
     character wider. Every step-down below is the same sum, re-floored. */
  font-size: clamp(1.15rem,
                   min(calc((var(--ledge-w) - var(--gutter)) / 6.85),
                       calc((var(--ledge-h) - var(--below)) / 2.08)),
                   3.4rem);
  line-height: 1.04;
  letter-spacing: -.012em;
}

.title__line { display: block; }
/* the second line is the long one, matching the ledge as it widens downward */
.title__line--wonk { font-variation-settings: "opsz" 144, "SOFT" 0, "WONK" 1; }

.lede {
  margin: .85rem 0 0;
  font-size: .76rem;
  line-height: 1.6;
  letter-spacing: .005em;
  color: var(--ash);
}

.btn {
  display: inline-flex;
  align-items: center;
  min-height: 42px;
  margin-top: 1.1rem;
  padding: .6rem 1.4rem;
  /* opaque, so it stands on its own ground rather than on a scrim over the
     footage; the plate keeps its contrast everywhere around it */
  background: var(--ink);
  color: var(--void);
  /* and a hairline in the page's own ground, so the button's edge still reads
     if a bright frame ever comes up behind it. No scrim either way. */
  box-shadow: 0 0 0 1px var(--void);
  font-size: .78rem;
  letter-spacing: .04em;
  text-transform: uppercase;
  /* the label is the action's name and it never breaks: a narrow ledge should
     push the button past its edge, not split "Start a world" */
  white-space: nowrap;
  transition: background .3s var(--ease), color .3s var(--ease);
}
.btn:hover, .btn:focus-visible { background: var(--ember); color: var(--void); }

/* ---------- the page arriving ----------
   One sequence, once. The moons swing into place as the mark draws, which is
   the only motion on the page that is not the plate's own. */

@media (prefers-reduced-motion: no-preference) {
  .brand, .title__line, .lede, .btn {
    animation: rise .9s var(--ease) both;
  }
  .title__line:nth-child(1) { animation-delay: .18s; }
  .title__line:nth-child(2) { animation-delay: .27s; }
  .lede        { animation-delay: .42s; }
  .btn         { animation-delay: .52s; }

  .mark__orbit { animation: draw 1.1s var(--ease) both; }
  .mark__moon  { animation: swing 1.4s var(--ease) both .1s; }
  .mark__moon--far { animation-duration: 1.8s; }
}

@keyframes rise {
  from { opacity: 0; transform: translateY(.6rem); }
  to   { opacity: 1; transform: none; }
}

@keyframes draw {
  from { stroke-dasharray: 58; stroke-dashoffset: 58; }
  to   { stroke-dasharray: 58; stroke-dashoffset: 0; }
}

@keyframes swing {
  from { offset-distance: calc(var(--at) - 34%); opacity: 0; }
  60%  { opacity: 1; }
  to   { offset-distance: var(--at); opacity: 1; }
}

/* ============================================================
   Narrow. Same composition — the copy still stands on the rock
   — but the top bar tightens and the type steps down with the
   ledge. Anything held upright also swaps to the upright plate.
   ============================================================ */

@media (max-width: 900px), (max-height: 560px) {
  .topbar   { padding-block: clamp(.7rem, 2vh, 1.2rem); }
  .lede     { font-size: .74rem; color: var(--ink); }
  .btn      { margin-top: .9rem; min-height: 40px; }
}

/* ---------- held upright ----------
   Upright is its own plate, 404x720, composed for the frame rather than cut
   out of the wide one: the sun still between the spires, the ringed giant's
   arc across the top right, a crescent and two moons in the sky, and the same
   rock along the bottom. The rock is narrower here than in the wide frame —
   a lit valley runs down the middle of it — so the ledge is x 0.00-0.37 and
   y 0.79-1.00, where the worst cell over the loop is 5.9:1. Cover renders
   this plate at max(vw/404, vh/720), which turns those two fractions into the
   expressions below.

   At that measure the headline sets its own break: the first line fills the
   ledge and the second wraps, so the block is three lines rather than two and
   the type stays large enough to read. So the sum divides by the first line,
   5.35em, and the height budget by three lines rather than two. The lede goes
   — there is no room for it above the cloud. */

@media (max-width: 900px) and (orientation: portrait) {
  :root {
    --ledge-w: max(37vw, 20.76vh);
    --ledge-h: max(37.43vw, 21vh);
    --below:   62px;          /* no lede here: the button, its gap and the gutter */
  }

  .lede  { display: none; }
  .btn   { margin-top: .65rem; min-height: 36px; }
  .title {
    font-size: clamp(1.05rem,
                     min(calc((var(--ledge-w) - var(--gutter)) / 5.35),
                         calc((var(--ledge-h) - var(--below)) / 3.12)),
                     3.4rem);
  }
}

/* The same trade on the upright plate. A phone is the plate's own shape, near
   enough, and the top bar sits on night sky at 7.9:1 or better. Squarer than
   about 0.61 the crop comes off the top, the bar lands on the crescent and the
   cratered moon (1.4:1), and the wordmark takes its ground. */

@media (max-width: 900px) and (orientation: portrait) and (min-aspect-ratio: 61 / 100) {
  .brand {
    margin-left: -.55rem;
    padding: .3rem .55rem;
    background: var(--void);
  }
}

/* ---------- held sideways ----------
   No height to spend, and the ledge is at its narrowest — 19vw of a short
   window. The lede has nowhere to set at that measure, so the headline and the
   button carry the page and the whole block tightens onto the floor. */

@media (orientation: landscape) and (max-height: 560px) {
  .hero    { padding-bottom: clamp(.75rem, 3vh, 1.25rem); }
  .topbar  { padding-block: clamp(.45rem, 2vh, .9rem); }
  .lede    { display: none; }
  .btn     { margin-top: .8rem; min-height: 36px; padding: .5rem 1.15rem; }
  .mark    { width: 26px; height: 26px; }
}

/* A landscape phone is the worst case in the whole set: the ledge is 19% of a
   window that is already short, which leaves about 110px of rock at 568x320.
   So the gutter gives back what it can and the headline's floor comes down to
   match — small, but still standing on the rock rather than hanging off it. */

@media (orientation: landscape) and (max-width: 700px) {
  :root   { --gutter: clamp(.9rem, 2.4vw, 1.5rem); }
  .btn    { min-height: 34px; padding: .45rem .95rem; font-size: .7rem; }
  .brand  { font-size: 1.15rem; }
  .mark   { width: 22px; height: 22px; }
}

/* Stacked, the block is taller than the ledge on a landscape phone and the
   headline's first line ends up on the haze above the rock (2.8:1 at 568x320).
   Laid in a row along the floor it is only two lines tall, which the ledge
   carries at every one of these shapes — and the button, being opaque, can
   stand on the wider part of the rock to the right of it. */

@media (orientation: landscape) and (max-height: 430px) {
  :root { --below: 14px; }    /* the headline is the whole block: only the gutter */

  .hero__copy {
    display: flex;
    align-items: flex-end;
    gap: .9rem;
    max-width: none;
  }
  .title {
    max-width: calc(var(--ledge-w) - var(--gutter));
    font-size: clamp(.85rem,
                     min(calc((var(--ledge-w) - var(--gutter)) / 6.85),
                         calc((var(--ledge-h) - var(--below)) / 2.08)),
                     1.5rem);
  }
  .btn   { margin-top: 0; flex: none; }
}
