/* Birthday Sky — what the sky has done on one calendar day.
 *
 * REFERENT: a screen-printed planetarium poster, roughly 1960s. Flat spot
 * inks on uncoated stock, concentric arcs, geometric starbursts, hairline
 * rules, condensed display lettering over a plain humanist body face.
 *
 * WHY THIS ONE, AND WHY NOT A NIGHT SKY. The obvious move for a page about
 * eclipses and shooting stars is a dark field with stars on it. That is
 * already the Halloween candy site's art direction, hex for hex — #1b0f2b,
 * chunky rounded display type, saturated brights on cream — and building it
 * again would make two of the four tools on this shelf look like one site
 * with two skins. §12 of the playbook exists because of exactly that class of
 * mistake.
 *
 * The way out is that this page is a printed artefact ABOUT the sky rather
 * than a picture of it. A poster can be light, and nothing else on the shelf
 * is: the other three are near-black, DOS blue and indigo night. Being the
 * only bright page in the portfolio is worth more than being the fourth dark
 * one.
 *
 * THE PALETTE IS MEASURED, NOT CHOSEN BY EYE. The last site shipped an
 * invented colour that failed contrast (#7878c0, about 3.3:1) and had to have
 * it removed. Every value below carries its ratio against the paper, computed
 * rather than guessed, and the note says what the colour is allowed to do:
 *
 *   ink       #1f3a5f   10.01   body text
 *   slate     #5b6b7f    4.75   secondary text
 *   peacock-t #12626e    6.11   text
 *   coral-t   #b8401f    4.83   text, and a fill with paper text on it
 *   coral     #e0603c    3.10   shapes and headline-sized type only
 *   peacock   #1a7f8e    4.10   shapes and headline-sized type only
 *   mustard   #d9a520    1.96   FILL ONLY, never text — ink on it is 5.11
 *
 * Mustard is the trap. It is the colour the poster wants most and it cannot
 * carry a single word on this paper. It rules, it fills, it underlines; it
 * never says anything.
 *
 * NO GRADIENTS, NO SHADOWS, NO BLUR. A two-colour press could not make one,
 * and the moment one appears the sheet stops reading as printed and starts
 * reading as a web page with a beige background. Depth comes from overlap and
 * from flat offset, the way it did on the press.
 *
 * NO IMAGE FILES. Every arc, burst and rule below is CSS. The page downloads
 * two fonts and a JSON file and nothing else.
 *
 * NO DARK MODE, deliberately. A poster is a printed object; a "dark variant"
 * of one is not a thing that exists. Inverting it would cost the single
 * property that keeps this page distinct from the rest of the shelf.
 */

:root {
  /* Stock */
  --paper:      #f4efe4;
  --paper-2:    #ece5d6;   /* panel tint, one step down */
  --paper-3:    #e2d9c6;   /* table stripe */

  /* Inks that may carry text */
  --ink:        #1f3a5f;   /* 10.01 */
  --slate:      #5b6b7f;   /*  4.75 */
  --peacock-t:  #12626e;   /*  6.11 */
  --coral-t:    #b8401f;   /*  4.83, and paper sits on it at 4.83 */

  /* Inks for shapes and display sizes only */
  --coral:      #e0603c;   /*  3.10 */
  --peacock:    #1a7f8e;   /*  4.10 */

  /* Fill only. Never text. Ink on it is 5.11. */
  --mustard:    #d9a520;

  --rule:       rgba(31, 58, 95, 0.22);
  --rule-hard:  rgba(31, 58, 95, 0.45);

  --display: "Space Grotesk", "Helvetica Neue", Arial, sans-serif;
  --body:    "Work Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;

  --sheet: 54rem;
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body.poster {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--body);
  font-size: 1.0625rem;
  line-height: 1.6;
  /* The press furniture is positioned against the page, so the page has to be
     the containing block and has to clip it. Without the clip the top-right
     burst puts a horizontal scrollbar on narrow screens. */
  position: relative;
  overflow-x: hidden;
}

/* --------------------------------------------------------------------
   Press furniture. Two shapes, both flat, both CSS.
   -------------------------------------------------------------------- */

.press { position: absolute; inset: 0; pointer-events: none; overflow: hidden; }

/* Concentric arcs, top left. Drawn as three rings with transparent fills so
   the paper shows through — a screen print puts ink down or it does not, it
   has no half measures.

   Opacity is on the element rather than in the colours because `opacity`
   applies to the pseudo-elements too, which is the trick that keeps all three
   rings at one strength. The first value was 0.16 and rendered as three pale
   smudges — noticeably fainter than the same artwork on the share card, which
   is the comparison that showed it up. A printed ring is either there or it
   is not. */
.arcs {
  position: absolute;
  top: -11rem; left: -9rem;
  width: 26rem; height: 26rem;
  border-radius: 50%;
  border: 1.5rem solid var(--peacock);
  opacity: 0.32;
}
.arcs::before, .arcs::after {
  content: "";
  position: absolute;
  border-radius: 50%;
  border: 1.5rem solid var(--coral);
}
.arcs::before { inset: 2.5rem; border-color: var(--coral); }
.arcs::after  { inset: 6rem;   border-color: var(--mustard); }

/* Starburst, top right: eight spokes from one point, made with repeating
   conic stripes and clipped to a circle. One element, no image. */
.burst {
  position: absolute;
  top: -6rem; right: -7rem;
  width: 22rem; height: 22rem;
  border-radius: 50%;
  background: repeating-conic-gradient(
    var(--mustard) 0deg 7deg, transparent 7deg 45deg);
  opacity: 0.35;
}

/* --------------------------------------------------------------------
   The three things that move.
   --------------------------------------------------------------------
   Rules this had to obey, from the top of this file: no gradients, no
   shadows, no blur. That rules out the obvious glowing meteor with a soft
   tail, and it turns out not to matter, because the press has its own way of
   doing all three.

   NOTHING FADES. A streak is off-canvas at the start and end of its cycle and
   crosses in between; `.press` clips it, so it enters and leaves without an
   opacity keyframe anywhere. The eclipsing moon is paper-coloured, which makes
   it invisible against the sheet and visible only where it covers the sun --
   which is both what a two-colour print would have to do and what an eclipse
   actually looks like.

   Everything animates transform only, so none of it costs a layout.
   -------------------------------------------------------------------- */

/* The sun, concentric with the burst's rays. */
.solar {
  position: absolute;
  top: 5rem; right: 4rem;
  width: 0; height: 0;
}
.solar i {
  position: absolute;
  width: 7rem; height: 7rem;
  margin: -3.5rem 0 0 -3.5rem;
  border-radius: 50%;
}
.sun { background: var(--mustard); opacity: 0.45; }
.moon {
  background: var(--paper);
  animation: transit 38s linear infinite;
}
@keyframes transit {
  /* Off one side, across, off the other. Totality is simply the moment the
     two discs line up; there is no keyframe for it. */
  0%   { transform: translateX(-13rem); }
  100% { transform: translateX(13rem); }
}

/* The moon, in the left margin, with the earth's shadow crossing it.
   Sat at left:-2.5rem in the first version, which sliced it against the
   viewport edge and read as a smudge rather than a moon. It now sits wholly
   inside the gutter, which is 14rem wide at the widths that have one. */
.lunar {
  position: absolute;
  top: 27rem; left: 1.5rem;
  width: 6rem; height: 6rem;
  border-radius: 50%;
  background: var(--paper-3);
  /* The umbra is a disc, and it is only allowed to exist on the moon. */
  overflow: hidden;
}
.umbra {
  position: absolute;
  top: -1rem; left: 0;
  width: 8rem; height: 8rem;
  border-radius: 50%;
  background: var(--coral);
  opacity: 0.6;
  animation: umbra 52s linear infinite;
}
@keyframes umbra {
  0%   { transform: translateX(-10rem); }
  100% { transform: translateX(10rem); }
}

/* Streaks. A triangle, not a line: wide at the head, to a point at the tail,
   which is the shape a print would cut rather than a gradient it cannot.

   WHERE THEY ARE ALLOWED TO GO. The first version sent them diagonally across
   the whole sheet and one of them drew a coral line straight through the word
   "birthday" in the headline. A page's own furniture must not cross its type.
   They now run in the top-right corner, right of where the headline ends and
   above where the first panel starts, which is the only large clear area on
   the sheet -- and it is where the sun already is, so they read as belonging
   to it. */
.meteor {
  position: absolute;
  top: 0; left: 0;
  width: 8rem; height: 0.45rem;
  background: var(--coral);
  clip-path: polygon(100% 0, 100% 100%, 0 50%);
  opacity: 0.5;
}
/* dx 28rem, dy 19.6rem is atan(19.6/28) = 35 degrees, so the streak moves
   along its own axis instead of sliding sideways. */
/* The first paths ran from -12rem to +7.6rem of y, which meant four fifths of
   every flight happened above the top edge and the streak only appeared as it
   was already leaving. These cross the clear upper right in view: y from below
   the top edge down to about 12rem, x staying right of where the tagline
   ends. */
@keyframes shoot {
  0%   { transform: translate(44rem, -8rem) rotate(35deg); }
  6%   { transform: translate(72rem, 11.6rem) rotate(35deg); }
  100% { transform: translate(72rem, 11.6rem) rotate(35deg); }
}
@keyframes shoot-2 {
  0%   { transform: translate(48rem, -10rem) rotate(35deg); }
  5%   { transform: translate(74rem, 8.2rem) rotate(35deg); }
  100% { transform: translate(74rem, 8.2rem) rotate(35deg); }
}
@keyframes shoot-3 {
  0%   { transform: translate(41rem, -6rem) rotate(35deg); }
  7%   { transform: translate(71rem, 15rem) rotate(35deg); }
  100% { transform: translate(71rem, 15rem) rotate(35deg); }
}
.meteor-1 { animation: shoot 17s linear infinite; }
.meteor-2 { width: 5.5rem; background: var(--peacock); animation: shoot-2 23s linear infinite 6s; }
.meteor-3 { width: 10rem; background: var(--mustard); opacity: 0.65; animation: shoot-3 31s linear infinite 13s; }

@media (max-width: 40rem) {
  /* On a phone the furniture is competing with the only column there is. */
  .arcs  { top: -13rem; left: -12rem; width: 18rem; height: 18rem; }
  .burst { top: -8rem; right: -9rem; width: 15rem; height: 15rem; }
  .solar { top: 3.5rem; right: 2.5rem; }
  .solar i { width: 5rem; height: 5rem; margin: -2.5rem 0 0 -2.5rem; }
  /* There is no gutter to put it in. */
  .lunar { display: none; }
  /* And no clear corner either: at 24rem wide the whole sheet is the column.
     The streaks run above the kicker and off the top-right, a short path that
     never reaches the type. */
  .meteor { width: 5rem; }
  @keyframes shoot {
    0%   { transform: translate(4rem, -9rem) rotate(35deg); }
    6%   { transform: translate(26rem, 6rem) rotate(35deg); }
    100% { transform: translate(26rem, 6rem) rotate(35deg); }
  }
  @keyframes shoot-2 {
    0%   { transform: translate(1rem, -11rem) rotate(35deg); }
    5%   { transform: translate(23rem, 4rem) rotate(35deg); }
    100% { transform: translate(23rem, 4rem) rotate(35deg); }
  }
  @keyframes shoot-3 {
    0%   { transform: translate(6rem, -10rem) rotate(35deg); }
    7%   { transform: translate(28rem, 5rem) rotate(35deg); }
    100% { transform: translate(28rem, 5rem) rotate(35deg); }
  }
}

/* --------------------------------------------------------------------
   Sheet
   -------------------------------------------------------------------- */

.wrap {
  position: relative;
  max-width: var(--sheet);
  margin: 0 auto;
  padding: 3.5rem 1rem 4rem;
}

.sheet-head { margin-bottom: 2.5rem; }

.path {
  font-family: var(--display);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--slate);
  margin: 0 0 1.25rem;
}

h1 {
  font-family: var(--display);
  font-weight: 700;
  /* Condensed by hand: the face is not a condensed cut, and squeezing the
     tracking is what mid-century poster lettering actually did. */
  letter-spacing: -0.02em;
  line-height: 0.95;
  font-size: clamp(2.5rem, 9vw, 4.75rem);
  margin: 0 0 1rem;
  text-wrap: balance;
}
h1 em { font-style: normal; color: var(--coral-t); }

.tagline {
  font-size: 1.15rem;
  color: var(--slate);
  margin: 0;
  max-width: 34rem;
  text-wrap: pretty;
}

/* --------------------------------------------------------------------
   Panels. A panel is a tinted block with a ruled cap carrying its name —
   the way a poster labels a region of itself.
   -------------------------------------------------------------------- */

.panel {
  background: var(--paper-2);
  border: 2px solid var(--ink);
  margin: 0 0 1.75rem;
}

.panel-rule {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 1rem;
  background: var(--ink);
}
.panel-rule span {
  font-family: var(--display);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--paper);
}
/* The rule runs out to the edge of the cap, which is what makes it read as a
   printed label rather than a heading with a background. */
.panel-rule::after {
  content: "";
  flex: 1;
  height: 2px;
  background: var(--mustard);
}

.panel-body { padding: 1.5rem 1rem; }
@media (min-width: 40rem) { .panel-body { padding: 1.75rem 1.5rem; } }

.panel-intro { margin: 0 0 1.25rem; color: var(--slate); max-width: 40rem; }

.panel h2 {
  font-family: var(--display);
  font-size: 1.6rem;
  letter-spacing: -0.01em;
  margin: 0 0 0.5rem;
}

/* --------------------------------------------------------------------
   The picker
   -------------------------------------------------------------------- */

.panel-pick { background: var(--paper); }

.pickrow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem;
  margin: 0 0 0.85rem;
}

.pick-label {
  font-family: var(--display);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--slate);
}

.field {
  font-family: var(--display);
  font-size: 1.05rem;
  font-weight: 500;
  color: var(--ink);
  background: var(--paper);
  border: 2px solid var(--ink);
  border-radius: 0;
  padding: 0.5rem 0.65rem;
  min-height: 2.75rem;
}
.field:focus-visible { outline: 3px solid var(--coral); outline-offset: 2px; }

.press-btn {
  font-family: var(--display);
  font-size: 0.85rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--paper);
  background: var(--coral-t);
  border: 2px solid var(--ink);
  border-radius: 0;
  padding: 0.7rem 1.2rem;
  min-height: 2.75rem;
  cursor: pointer;
  /* Flat offset, not a shadow: the second colour is printed beside the first,
     slightly out of register. Pressing closes the gap. */
  box-shadow: 4px 4px 0 var(--ink);
  transition: transform 0.06s linear, box-shadow 0.06s linear;
}
.press-btn:hover { background: #a33418; }
.press-btn:active { transform: translate(4px, 4px); box-shadow: 0 0 0 var(--ink); }
.press-btn:focus-visible { outline: 3px solid var(--peacock); outline-offset: 3px; }
.press-btn.ghost { background: transparent; color: var(--ink); }
.press-btn.ghost:hover { background: var(--mustard); }

.hint { font-size: 0.9rem; color: var(--slate); margin: 0; }

/* --------------------------------------------------------------------
   The headline — the one loud thing on the sheet
   -------------------------------------------------------------------- */

.headline {
  border: 2px solid var(--ink);
  background: var(--mustard);   /* fill only; the text on it is ink at 5.11 */
  padding: 1.75rem 1.25rem;
  margin: 0 0 1.75rem;
}

.headline-date {
  font-family: var(--display);
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  margin: 0 0 0.6rem;
  color: var(--ink);
}

.headline-say {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.5rem, 5.5vw, 2.4rem);
  line-height: 1.12;
  letter-spacing: -0.015em;
  margin: 0;
  color: var(--ink);
  text-wrap: balance;
}

/* --------------------------------------------------------------------
   Stacked findings
   -------------------------------------------------------------------- */

.stack { list-style: none; margin: 0; padding: 0; }

.stack li {
  display: grid;
  grid-template-columns: 4.5rem 1fr;
  gap: 0 1rem;
  align-items: baseline;
  padding: 0.85rem 0;
  border-top: 1px solid var(--rule);
}
.stack li:first-child { border-top: 2px solid var(--ink); }
.stack li:last-child { border-bottom: 1px solid var(--rule); }

.stack .yr {
  font-family: var(--display);
  font-weight: 700;
  font-size: 1.25rem;
  color: var(--peacock-t);
  font-variant-numeric: tabular-nums;
}
.stack .what { margin: 0; }
.stack .sub {
  grid-column: 2;
  margin: 0.2rem 0 0;
  font-size: 0.92rem;
  color: var(--slate);
}

/* The one row that is not celebrated. Chelyabinsk hurt about 1,500 people and
   it is also the biggest entry in the catalogue, so it cannot be dropped and
   must not be cheered. It gets a quiet coral edge and plain wording. */
.stack li.sober { border-left: 4px solid var(--coral-t); padding-left: 0.85rem; }
.stack li.sober .yr { color: var(--coral-t); }

.nextline {
  margin: 1.25rem 0 0;
  padding-top: 1rem;
  border-top: 2px solid var(--ink);
  font-size: 0.98rem;
}
.nextline b { font-family: var(--display); color: var(--peacock-t); }

/* The shower panel is the warm one: it is the only layer a visitor can act
   on, so it gets the peacock fill and a little more air. */
.panel-shower .panel-body { background: var(--paper-2); }
/* Several majors can fall inside the same ten days, so items need a seam. */
.shower-item + .shower-item {
  margin-top: 1.25rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--rule);
}

.shower-name {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.25rem, 4vw, 1.8rem);
  margin: 0 0 0.4rem;
  color: var(--peacock-t);
}
.shower-when { margin: 0 0 0.75rem; }
.shower-parent { margin: 0; color: var(--slate); font-size: 0.95rem; }

/* The offset on .press-btn is drawn 4px below the button's own box, so a
   margin equal to the gap everything else uses still let the shadow sit on
   the next panel's cap. Measured at 0px of clearance before this was added. */
.actions { margin: 1.5rem 0 1.75rem; }
.feedback {
  margin: 0.75rem 0 0;
  font-family: var(--display);
  font-size: 0.85rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--peacock-t);
}

/* --------------------------------------------------------------------
   The 366-row almanac
   -------------------------------------------------------------------- */

.table-group {
  font-family: var(--display);
  font-size: 1.1rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin: 2rem 0 0.5rem;
  padding-bottom: 0.35rem;
  border-bottom: 3px solid var(--mustard);
}
.table-group:first-of-type { margin-top: 0.5rem; }

.value-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.95rem;
  margin: 0 0 0.5rem;
}
.value-table th, .value-table td {
  text-align: start;
  padding: 0.4rem 0.5rem;
  border-bottom: 1px solid var(--rule);
  vertical-align: baseline;
}
.value-table thead th {
  font-family: var(--display);
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--slate);
  border-bottom: 2px solid var(--ink);
}
.value-table tbody tr:nth-child(even) { background: var(--paper-3); }
.value-table .col-day {
  font-family: var(--display);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  width: 3rem;
}
.value-table .col-year {
  font-variant-numeric: tabular-nums;
  color: var(--peacock-t);
  width: 5rem;
}
.value-table .col-detail { color: var(--slate); }

.table-foot { margin: 1.25rem 0 0; font-size: 0.9rem; color: var(--slate); }

/* --------------------------------------------------------------------
   Article
   -------------------------------------------------------------------- */

.deep-item { border-top: 1px solid var(--rule); }
.deep-item:last-of-type { border-bottom: 1px solid var(--rule); }
.deep-item summary {
  font-family: var(--display);
  font-weight: 500;
  font-size: 1.05rem;
  padding: 0.9rem 0;
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
}
.deep-item summary::-webkit-details-marker { display: none; }
.deep-item summary::before {
  content: "+";
  font-weight: 700;
  color: var(--coral-t);
  font-size: 1.2rem;
  line-height: 1;
}
.deep-item[open] summary::before { content: "\2212"; }
.deep-item summary:focus-visible { outline: 3px solid var(--coral); outline-offset: 2px; }
.deep-body { padding: 0 0 1rem 1.5rem; max-width: 38rem; }
.deep-body p { margin: 0 0 0.9rem; }
.deep-body a { color: var(--peacock-t); }

/* --------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------- */

footer {
  margin-top: 3rem;
  padding-top: 1.5rem;
  border-top: 3px solid var(--ink);
  font-size: 0.9rem;
  color: var(--slate);
}

/* Required by NASA's terms for the eclipse catalogues, so it is styled to be
   read rather than tucked away. */
.credit {
  margin: 0 0 1.25rem;
  padding: 0.75rem 1rem;
  border-inline-start: 4px solid var(--mustard);
  background: var(--paper-2);
  color: var(--ink);
  font-size: 0.88rem;
}

.foot-nav { display: flex; flex-wrap: wrap; gap: 1.25rem; margin-bottom: 1rem; }
footer a { color: var(--peacock-t); }
.fine-print { font-size: 0.82rem; }

.hidden { display: none !important; }

@media (prefers-reduced-motion: reduce) {
  /* The furniture stays; it just stops. The moon parks clear of the sun and
     the umbra clear of the moon, so a still page shows the sky rather than a
     permanent eclipse, and the streaks sit off-canvas where the clip hides
     them. Nothing here carries meaning, so nothing is lost by holding still. */
  * { transition: none !important; }
  .moon, .umbra, .meteor { animation: none !important; }
  .moon { transform: translateX(13rem); }
  .umbra { transform: translateX(-10rem); }
  .meteor { transform: translate(44rem, -8rem) rotate(35deg); }
}

/* The link out to the whole-year page, where the 366-row table went. Sized
   like a panel so it reads as a place to go rather than as a footnote. */
.seealso {
  margin: 0 0 1.75rem;
  padding: 1rem 1.25rem;
  border: 2px solid var(--ink);
  background: var(--paper-2);
}
.seealso a {
  font-family: var(--display);
  font-weight: 700;
  font-size: 1.05rem;
  color: var(--peacock-t);
  text-decoration: none;
}
.seealso a:hover { text-decoration: underline; }
.seealso a:focus-visible { outline: 3px solid var(--coral); outline-offset: 3px; }

/* Back to the tool, from the whole-year page. */
.backlink { margin: 0 0 1.5rem; }
.backlink a { color: var(--peacock-t); font-weight: 600; }
