/* The homepage of both websites, built by homepage.js. The look of each website sets the fonts of the
   headings and the motion of the buttons. Only transform, opacity and the light of
   the dark area move, and only while the system allows motion. Without motion the opening scene
   shows its last moment, the light of the dark area is in the middle and the chapters of the story
   stand one below the other. */

/* A stage for Shelly and Jack, lit by the light inside it. */
.stage {
  position: relative;
  border: 2px solid var(--stage-outline);
  border-radius: var(--radius);
  background: var(--stage);
}
.light { position: absolute; inset: 0; }
.light-red { background: radial-gradient(circle at 50% 75%, color-mix(in oklab, var(--jack) 32%, transparent), transparent 65%); }
.light-green { background: radial-gradient(circle at 50% 75%, color-mix(in oklab, var(--shelly) 32%, transparent), transparent 65%); }
.light-split {
  background: linear-gradient(90deg, color-mix(in oklab, var(--jack) 26%, transparent), transparent 45% 55%, color-mix(in oklab, var(--shelly) 26%, transparent));
}

/* --- Opening scene --- */

.hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: center;
  gap: 48px;
  padding: 72px 0 56px;
}
.hero-text { display: grid; gap: 20px; justify-items: start; }
.lead { font-size: 18px; color: var(--text-2); }
.hero .trust { font-size: 14px; color: var(--muted); }

/* High enough for the terminal above the shield. The rest of the opening scene counts from
   --scene-start. */
.hero-stage {
  --scene-start: 0.4s;
  height: 340px;
  overflow: hidden;
}
.hero-stage .light-red { opacity: 0; }
.terminal {
  position: absolute;
  top: 16px;
  left: 16px;
  display: grid;
  gap: 4px;
  color: var(--jack);
  font: 11px/1.6 var(--pixel);
  opacity: 0;
}
/* The shield in the middle of the stage, above its bottom edge. */
.shield {
  position: absolute;
  left: calc(50% - 52px);
  bottom: 48px;
  width: 104px;
  height: 128px;
  border: 4px solid var(--shelly);
  border-radius: 50% 50% 45% 45% / 30% 30% 70% 70%;
  box-shadow: 0 0 28px var(--shelly);
}

/* Runs once when the page loads and ends in the look shown without motion. */
@media (prefers-reduced-motion: no-preference) {
  .terminal { animation: shown-then-gone 0.5s calc(var(--scene-start) + 1.3s) both; }
  .terminal span { animation: fade-in 0.15s both; }
  .terminal span:nth-child(1) { animation-delay: calc(var(--scene-start) + 0.1s); }
  .terminal span:nth-child(2) { animation-delay: calc(var(--scene-start) + 0.4s); }
  .shield { animation: shield-up 0.4s calc(var(--scene-start) + 1.15s) ease-out both; }
  .hero-stage .light-red { animation: shown-then-gone 0.6s calc(var(--scene-start) + 1.2s) both; }
  .hero-stage .light-green { animation: fade-in 0.6s calc(var(--scene-start) + 1.2s) both; }
}
@keyframes walk-in { from { transform: translateX(-120%); opacity: 1; } to { opacity: 1; } }
@keyframes shield-up { from { transform: scale(0.4); opacity: 0; } }
@keyframes fade-in { from { opacity: 0; } }
@keyframes shown-then-gone { from { opacity: 1; } }

/* --- Dark area --- */

/* @property lets the sweep keyframes move the light after a touch. The light shows only while a
   mouse is in the area, while the sweep runs or with reduced motion, and its lit part shows the
   striped floor of the stage. Design decision, from the approved design of the fun homepage: the
   radius of the light is about a third of the height of the area. */
@property --light-x { syntax: "<length-percentage>"; inherits: false; initial-value: 50%; }
@property --light-y { syntax: "<length-percentage>"; inherits: false; initial-value: 50%; }
.dark-search {
  --area-height: 340px;
  --light-radius: calc(var(--area-height) * 0.32);
  --light-core: calc(var(--area-height) * 0.2);
  --lit-background:
    radial-gradient(circle var(--light-radius) at var(--light-x) var(--light-y), transparent 0 var(--light-core), var(--darkness) var(--light-radius)),
    repeating-linear-gradient(45deg, var(--stage) 0 12px, color-mix(in oklab, var(--stage) 90%, var(--text)) 12px 24px);
  height: var(--area-height);
  background: var(--darkness);
}
.dark-search.lit,
.dark-search.sweeping { background: var(--lit-background); }

/* While dark-area.js sets cursor-in-dark, the cursor is hidden on the whole page, also over dialogs
   and their backdrop, and the way out is the bottom right corner of the area, in front of the
   traps. The corner is blank and looks like the area around it. Design decision: the corner is a
   square of 64px. */
.dark-way-out {
  display: none;
  position: absolute;
  right: 0;
  bottom: 0;
  z-index: var(--layer-way-out);
  width: 64px;
  height: 64px;
}
:root.cursor-in-dark {
  &, *, *::backdrop { cursor: none; }
  .dark-way-out { display: block; }
}

/* Jack at the bottom left of the window, in front of the page. He walks in from the left edge for
   --walk-rounds rounds of the walk frames, laughs for --laugh-time and walks back out, facing left.
   The visit itself runs one animation for the whole time, whose end dark-area.js waits for. Product
   choice, from the approved design of the fun homepage: two rounds of walking and a laugh of two
   seconds. */
.jack-visit {
  --width: var(--sprite-size);
  --walk-rounds: 2;
  --walk-time: calc(var(--walk-rounds) * var(--walk-frames) * var(--sprite-frame-time));
  --laugh-time: 2s;
  position: fixed;
  left: 0;
  bottom: 0;
  z-index: var(--layer-jack-visit);
  display: grid;
  pointer-events: none;
  animation: visit calc(2 * var(--walk-time) + var(--laugh-time));
}
.jack-visit > * { grid-area: 1 / 1; position: relative; opacity: 0; }
.jack-visit .character { width: var(--width); }
.visit-walk-out .character { scale: -1 1; }
.jack-laughs { top: 12%; left: 62%; }
/* What Jack says is a sentence, so it shows in the sans font: the pixel font is only for short
   labels. */
.jack-laughs, .jack-hint {
  position: absolute;
  inline-size: max-content;
  max-inline-size: 18em;
  padding: 6px 10px;
  border: 2px solid var(--jack);
  background: var(--surface);
  color: var(--text);
  font: 600 14px/1.4 var(--sans);
}

/* Jack at the right edge of the window, in front of the page and facing left, with the hint to his
   left. He moves in until the half of him nearer the page shows, waits and moves out again, for
   --peek-time, which dark-area.js sets and after which it hides the peek. */
.jack-peek {
  position: fixed;
  right: 0;
  top: 40%;
  z-index: var(--layer-jack-visit);
  width: calc(var(--sprite-size) / 2);
  translate: 100% 0;
  pointer-events: none;
}
.jack-peek .character { width: 100%; scale: -1 1; }
.jack-hint { top: 8%; right: 75%; }

/* dark-area.js builds the visit and the peek only while the system allows motion. Design decision,
   from the approved design of the fun homepage: the sweep takes four seconds. */
@media (prefers-reduced-motion: no-preference) {
  .dark-search.lit { --light-x: var(--pointer-x); --light-y: var(--pointer-y); }
  .dark-search.sweeping { animation: sweep 4s ease-in-out; }
  .visit-walk-in { animation: walk-in var(--walk-time) linear; }
  .visit-laugh { animation: shown var(--laugh-time) var(--walk-time); }
  .visit-walk-out { animation: walk-out var(--walk-time) linear calc(var(--walk-time) + var(--laugh-time)); }
  .jack-peek { animation: peek var(--peek-time) ease-in-out; }
}
@media (prefers-reduced-motion: reduce) {
  .dark-search { background: var(--lit-background); }
}
@keyframes sweep {
  from { --light-x: 15%; --light-y: 20%; }
  35% { --light-x: 80%; --light-y: 35%; }
  70% { --light-x: 30%; --light-y: 80%; }
  to { --light-x: 70%; --light-y: 50%; }
}
@keyframes visit { from, to { visibility: visible; } }
@keyframes peek { 15%, 85% { translate: 50% 0; } }
@keyframes shown { from, to { opacity: 1; } }
@keyframes walk-out { from { opacity: 1; } to { transform: translateX(-120%); opacity: 1; } }

/* --- The story --- */

.showcase {
  padding: 24px 0 56px;
  overflow-x: clip;
  scroll-margin-top: var(--header-height);
}
.chapter {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
  align-items: center;
  gap: 48px;
  padding: 32px 0;
}
.chapter-mark { display: none; }
.chapter-copy { display: grid; gap: 12px; justify-items: start; }
.chapter-copy h3 { font: 700 30px/1.2 var(--sans); }
.chapter-copy p { font-size: 18px; color: var(--text-2); }

/* The room on the scene sets the size of the characters: twice --sprite-size on a large scene, that
   size on a medium one and half of it on a small one. */
.scene { height: 380px; container-type: size; }
.cast { --size: calc(var(--sprite-size) / 2); --share: 1; --width: calc(var(--size) * var(--share)); position: relative; }
@container (width >= 340px) and (height >= 300px) {
  .cast { --size: var(--sprite-size); }
}
@container (width >= 512px) and (height >= 640px) {
  .cast { --size: calc(var(--sprite-size) * 2); }
}

/* The characters stand side by side in the middle, smaller when there are two. */
.cast-row {
  position: absolute;
  inset-inline: 0;
  bottom: 14%;
  display: flex;
  justify-content: center;
  align-items: flex-end;
  gap: 24px;
}
.cast-row:has(.cast + .cast) .cast { --share: 0.5; }

.progress { position: absolute; top: 16px; left: 16px; display: flex; gap: 6px; }
.progress span { width: 8px; height: 8px; background: var(--line-strong); }
.progress .current { background: var(--text); }

/* A speech bubble in the pixel look whose tail points up at the scene. What Shelly says is a
   sentence, so it shows in the sans font: the pixel font is only for short labels. */
.speech {
  position: relative;
  margin-top: 12px;
  padding: 10px 12px;
  border: 2px solid var(--shelly);
  background: var(--surface);
  color: var(--text);
  font: 600 15px/1.5 var(--sans);
}
.speech::before {
  content: "";
  position: absolute;
  top: -8px;
  left: 16px;
  width: 10px;
  height: 10px;
  border-top: 2px solid var(--shelly);
  border-left: 2px solid var(--shelly);
  background: var(--surface);
  rotate: 45deg;
}

/* With motion, every scene spans all chapters in the first column and is fixed on screen while the
   texts and their marks scroll past in the second. homepage.js marks the current scene. Design
   decision: each chapter spans one screen height of scrolling, and on a phone 80% of one. */
@media (prefers-reduced-motion: no-preference) {
  .showcase {
    display: grid;
    grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
    column-gap: 48px;
  }
  .chapter { display: contents; }
  .scene {
    grid-column: 1;
    grid-row: 1 / span var(--chapters);
    position: sticky;
    top: calc(var(--header-height) + 24px);
    align-self: start;
    height: calc(100svh - var(--header-height) - 48px);
    opacity: 0;
    transition: opacity 0.5s;
  }
  .scene.current { opacity: 1; }
  .scene .cast-row { transform: translateY(24px); transition: transform 0.6s ease-out; }
  .scene.current .cast-row { transform: none; }
  /* A strip with a rest frame plays its frames once each time its scene becomes the current one,
     200 ms each, the timing that the art came with. */
  .scene.current .character-sprite-once img { animation: sprite-frames calc(var(--frames) * 200ms) steps(var(--frames)); }
  .chapter-text { grid-column: 2; grid-row: var(--chapter); display: grid; }
  .chapter-copy, .chapter-mark { grid-area: 1 / 1; }
  .chapter-copy { position: sticky; top: calc(var(--header-height) + 30svh); align-self: start; }
  .chapter-mark { display: block; height: 100svh; }
}

/* --- Sections of text --- */

.text-section p { max-width: 40em; font-size: 18px; color: var(--text-2); }
.text-items {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
}
.text-items li {
  padding: 16px 20px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--jack);
  border-radius: var(--radius);
  background: var(--surface);
}

.certificate-preview {
  width: min(100%, 420px);
  height: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 8px 24px var(--shadow);
}

/* --- Questions --- */

.faq { max-width: 760px; }
.faq details {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}
.faq summary { padding: 14px 20px; font-weight: 600; cursor: pointer; }
.faq details p { padding: 0 20px 16px; color: var(--text-2); }

/* --- Demo teaser --- */

.teaser { justify-items: center; text-align: center; }
.teaser p { max-width: 36em; color: var(--text-2); }

/* --- Phone --- */

/* With motion the scene is fixed at the top, and the texts scroll below it. */
@media (max-width: 760px) {
  .hero { grid-template-columns: 1fr; gap: 32px; padding-top: 40px; }
  .dark-search { --area-height: 260px; }
  .jack-visit { --width: calc(var(--sprite-size) / 2); }
  .chapter { grid-template-columns: 1fr; gap: 24px; }
  .scene { height: 320px; }
  .text-items { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 760px) and (prefers-reduced-motion: no-preference) {
  .showcase { grid-template-columns: minmax(0, 1fr); }
  .scene { z-index: 1; top: var(--header-height); height: 45svh; }
  .chapter-text { grid-column: 1; }
  .chapter:first-of-type .chapter-text { padding-top: calc(45svh + 24px); }
  .chapter-copy { top: calc(var(--header-height) + 45svh + 24px); }
  .chapter-mark { height: 80svh; }
}
