/* Sgt. Pepper's Dataworks
   One page. Quiet setting, one psychedelic object.
   Every color and size is a token on :root. */

:root {
  /* Ground is a deep green pulled from the logo's mint family, not a tinted
     black. Ink is the logo's own cream. */
  --ground:    #102b22;
  --ink:       #f4f2e1;
  --ink-quiet: #9bb3a6;
  --mint:      #87cfb1;
  --rule:      rgba(244, 242, 225, 0.2);

  /* Courier Prime, a cleaned-up Courier drawn for screenplays. It reads as a
     typewriter without the costume. Loaded from Google Fonts, since it isn't
     a system face; Courier New is the fallback and ships on both Mac and
     Windows. */
  --face: "Courier Prime", "Courier New", Courier, monospace;

  --mark-size: clamp(3.5rem, 7vw, 5rem);
  --wordmark:  clamp(0.8rem, 2.4vw, 1.0625rem);
  --statement: clamp(1.375rem, 4.4vw, 2.375rem);
  --small:     clamp(0.875rem, 2vw, 0.9375rem);

  --gutter:  clamp(1.5rem, 6vw, 5.5rem);
  --measure: 38ch;

  --type-duration: 1.4s;

  /* How far the sentence and the contacts travel up as they arrive, how long
     they take, and the curve they ride in on.

     The curve is a gentle ease-out, not an expo. An expo curve finishes most
     of its travel in the first fifth of its duration, which reads as the text
     appearing rather than moving. This one spreads the movement out. */
  --rise: 2.5rem;
  --rise-duration: 1.5s;
  --ease-settle: cubic-bezier(0.22, 0.61, 0.36, 1);
}

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

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  min-height: 100svh;
  padding: var(--gutter);
  display: grid;
  align-content: center;
  justify-items: start;
  gap: clamp(1.75rem, 4vw, 2.75rem);

  background: var(--ground);
  color: var(--ink);
  font-family: var(--face);
  font-size: 100%;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

/* The logo. Present, deliberately small. */
.mark {
  display: block;
  width: var(--mark-size);
  height: auto;
}

/* Wordmark. The text is revealed left to right and the caret travels with it.
   Both run on the same clock, so they stay together.

   This is done with clip-path rather than an animated width. An earlier
   version grew the element's width in ch units, which only holds in a
   monospace face and breaks the moment the font changes. clip-path measures
   against the element's own box, so the wordmark survives a font swap. */
.wordmark {
  position: relative;
  margin: 0;
  font-size: var(--wordmark);
  font-weight: 700;
  letter-spacing: 0.22em;
  line-height: 1.2;
  white-space: nowrap;
  color: var(--ink-quiet);
}

.wordmark-text {
  display: inline-block;
  clip-path: inset(0 100% 0 0);
  animation: reveal var(--type-duration) steps(23) 250ms both;
}

.caret {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 2px;
  background: var(--mint);
  animation:
    travel var(--type-duration) steps(23) 250ms both,
    blink  850ms step-end 250ms infinite;
}

/* The sentence is larger than the wordmark on purpose. Anyone arriving here
   already has the name from the email domain; this is the payload. */
.statement {
  margin: 0;
  max-width: var(--measure);
  font-size: var(--statement);
  font-weight: 400;
  line-height: 1.35;
  text-wrap: pretty;
  animation: surface var(--rise-duration) var(--ease-settle) 1.9s both;
}

/* Ruled off from the sentence: this is where the page stops talking and
   starts offering a way to reach him. */
.contact {
  display: flex;
  align-items: center;
  gap: clamp(1.25rem, 3vw, 2rem);
  width: 100%;
  max-width: var(--measure);
  padding-top: clamp(1.25rem, 3vw, 1.75rem);
  border-top: 1px solid var(--rule);
  font-size: var(--small);
  animation: surface var(--rise-duration) var(--ease-settle) 2.6s both;
}

.contact a {
  color: var(--ink);
  text-decoration-color: var(--mint);
  text-underline-offset: 0.35em;
  text-decoration-thickness: 1px;
}

.contact a:hover { color: var(--mint); }

.contact a:focus-visible {
  outline: 2px solid var(--mint);
  outline-offset: 4px;
  border-radius: 2px;
}

.social {
  display: inline-flex;
  line-height: 0;
}

.social svg {
  width: 1.375rem;
  height: 1.375rem;
  fill: var(--ink-quiet);
}

.social:hover svg { fill: var(--mint); }

/* The icon link needs a name for screen readers and for keyboard users
   landing on it, without the word showing. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* steps() needs a literal integer, so the 23 above is the character count of
   SGT. PEPPER'S DATAWORKS. Edit the word and the wordmark together. */
@keyframes reveal {
  to { clip-path: inset(0 0 0 0); }
}

@keyframes travel {
  from { left: 0; }
  to   { left: 100%; }
}

@keyframes blink {
  50% { opacity: 0; }
}

/* Opacity finishes early on purpose. If it ramped across the whole duration,
   the text would still be half transparent while it was doing most of its
   travelling, which reads as appearing rather than moving. */
@keyframes surface {
  from { opacity: 0; transform: translateY(var(--rise)); }
  35%  { opacity: 1; }
  to   { opacity: 1; transform: none; }
}

/* Nothing here depends on motion to be readable. */
@media (prefers-reduced-motion: reduce) {
  .wordmark-text {
    clip-path: none;
    animation: none;
  }

  .caret { display: none; }

  .statement,
  .contact { animation: none; }
}
