/* adamkofod.com
   Layout: one pinned poster. The name sits on the sea horizon. Scrolling sends a
   swell across it, left to right, carrying dusk behind it; each letter lifts and
   is set back down. Everything that moves returns to level. No scripts. */

/* fonts:self-hosted:start */
@font-face {
  font-family: "Archivo";
  src: url("fonts/archivo-var.woff2") format("woff2");
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-style: normal;
  font-display: block;
}
@font-face {
  font-family: "Fragment Mono";
  src: url("fonts/fragment-mono.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
/* fonts:self-hosted:end */

:root {
  /* colour: all five are taken from the two photographs */
  --ink: #131a26;      /* deep water at morning: the name */
  --silver: #cdd2d8;   /* overcast sky: the ground the page loads on */
  --deep: #1c1a25;     /* water after sunset: the ground the page ends on */
  --foam: #f4efe6;     /* small type over dark water */
  --ember: #f29143;    /* the last light: underlines and focus */

  /* type */
  --display: "Archivo", "Arial Black", "Helvetica Neue", Impact, sans-serif;
  --utility: "Fragment Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  /* geometry: the sea meets the sky 36% of the way down, in every photograph */
  --gutter-l: max(16px, env(safe-area-inset-left, 0px));
  --gutter-r: max(16px, env(safe-area-inset-right, 0px));

  /* how wide the soft edge of the swell front is, as a share of the screen */
  --soft: 22;

  color-scheme: light;
}

/* the swell front: 0% is the left edge of the screen, 100% the right */
@property --front {
  syntax: "<percentage>";
  inherits: true;
  initial-value: -30%;
}

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

body {
  margin: 0;
  background: linear-gradient(var(--silver) 50%, var(--deep) 50%);
  color: var(--ink);
  font-family: var(--utility);
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

::selection { background: var(--ember); color: var(--ink); }

/* ---------- the stage ---------- */
/* Still version (no scroll-linked motion available, or motion turned off):
   two full screens, morning then dusk. The moving version further down pins
   one screen and layers them. */

.stage {
  position: relative;
  height: 200vh;
  height: 200svh;
  overflow: clip;
  isolation: isolate;
  background: var(--silver);
}

.shot, .sky, .glint, .grain {
  position: absolute;
  left: 0;
  right: 0;
}

.shot {
  display: block;
  overflow: hidden;
}
.shot--dawn, .sky { top: 0; height: 50%; }
.shot--dusk { top: 50%; height: 50%; background: var(--deep); }

/* Each photograph is placed so its own horizon lands on the 36% line, then
   sized to cover the screen. --ar is width/height, --hz is how far down the
   photograph its horizon sits, --fx chooses which side to crop from.
   Only the height is set; the browser derives the width from the photograph's
   own proportions, so it can never be stretched or squeezed. */
.shot img {
  --h: max(calc(36% / var(--hz)), calc(64% / (1 - var(--hz))), calc(100vw / var(--ar)));
  position: absolute;
  display: block;
  max-width: none;
  max-height: none;
  height: var(--h);
  width: auto;
  top: calc(36% - var(--h) * var(--hz));
  left: calc(var(--fx, 0.5) * 100%);
  translate: calc(var(--fx, 0.5) * -100%) 0;
  transform-origin: 50% calc(var(--hz) * 100%);
}
.shot--dawn { --ar: calc(3200 / 2134); --hz: 0.3313; }
.shot--dusk { --ar: calc(3000 / 1875); --hz: 0.4457; --fx: 0.1; }

.grain {
  top: 0;
  bottom: 0;
  background: url("img/grain.7783d664.png") 0 0 / 240px 240px;
  mix-blend-mode: overlay;
  opacity: 0.2;
  pointer-events: none;
}

.glint, .cue { display: none; }

/* ---------- the name ---------- */

.sky {
  container-type: size;
  pointer-events: none;
}

.name {
  position: absolute;
  left: var(--gutter-l);
  right: var(--gutter-r);
  bottom: 64cqh;                      /* baseline on the horizon */
  margin: 0;
  color: var(--ink);
  font-family: var(--display);
  font-weight: 900;
  font-stretch: 125%;
  font-size: min(calc(min(95cqw, 100cqw - 32px) / 9.06), 38cqh);
  line-height: 1;
  letter-spacing: 0;
  text-align: center;
  text-transform: uppercase;
  white-space: nowrap;
  text-box: trim-both cap alphabetic; /* the box ends exactly at the baseline */
}
@supports not (text-box: trim-both cap alphabetic) {
  .name { margin-bottom: -0.165em; }
}

.l { display: inline-block; }

/* where each letter stands across the screen, 0 = left edge, 1 = right edge */
.l1 { --x: 0.076; } .l2 { --x: 0.176; } .l3 { --x: 0.276; } .l4 { --x: 0.390; }
.l5 { --x: 0.532; } .l6 { --x: 0.638; } .l7 { --x: 0.734; } .l8 { --x: 0.831; } .l9 { --x: 0.934; }

/* ---------- the close ---------- */

.close {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  gap: 4px 32px;
  padding-block: 120px calc(24px + env(safe-area-inset-bottom, 0px));
  padding-left: max(28px, env(safe-area-inset-left, 0px));
  padding-right: max(28px, env(safe-area-inset-right, 0px));
  /* a little depth under the small type, so it reads over any photograph */
  background: linear-gradient(to top, rgb(14 12 20 / 0.86), rgb(14 12 20 / 0.5) 55%, rgb(14 12 20 / 0));
  color: var(--foam);
  font-family: var(--utility);
  font-size: 1.0625rem;
  line-height: 1.4;
  letter-spacing: 0.02em;
  text-shadow: 0 1px 3px rgb(0 0 0 / 0.55);
}
.close a {
  display: inline-block;
  padding-block: 10px;
  color: inherit;
  text-decoration: underline;
  text-decoration-color: var(--ember);
  text-decoration-thickness: 2px;
  text-underline-offset: 0.4em;
  transition: text-decoration-color 0.2s, text-underline-offset 0.2s;
}
.close a:hover {
  text-decoration-color: var(--foam);
  text-underline-offset: 0.55em;
}
.close a:focus-visible {
  outline: 2px solid var(--ember);
  outline-offset: 4px;
  border-radius: 2px;
}

/* ---------- tall screens: the sailboat photograph, the name stacked in the sky ---------- */

@media (orientation: portrait) {
  :root { --soft: 60; }   /* a narrow screen needs a much softer front */
  .shot--dawn { --fx: 0.44; }
  .shot--dusk { --fx: 0.5; }

  .name {
    top: 9cqh;
    bottom: auto;
    font-size: min(calc((100cqw - 32px) / 4.02), 13.5cqh);
    text-align: left;
    text-box: normal;
  }
  /* both words span the same measure: ADAM set wide, KOFOD drawn in */
  .w {
    display: block;
    text-box: trim-both cap alphabetic;
  }
  .w + .w {
    margin-top: 0.1em;
    font-stretch: 102.3%;
  }
  @supports not (text-box: trim-both cap alphabetic) {
    .name { margin-bottom: 0; }
    .w { line-height: 0.76; }
  }

  .l1 { --x: 0.150; } .l2 { --x: 0.368; } .l3 { --x: 0.587; } .l4 { --x: 0.833; }
  .l5 { --x: 0.137; } .l6 { --x: 0.332; } .l7 { --x: 0.507; } .l8 { --x: 0.683; } .l9 { --x: 0.872; }

  .close { padding-left: max(20px, env(safe-area-inset-left, 0px)); padding-right: max(20px, env(safe-area-inset-right, 0px)); }
}

/* ---------- the moving version ---------- */
/* Scroll position is the only clock. Nothing loops and nothing runs on a timer. */

@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .track {
      height: 300vh;
      height: 300svh;
    }
    .stage {
      position: sticky;
      top: 0;
      height: 100vh;
      height: 100svh;
      animation: pass linear both;
      animation-timeline: scroll(root block);
      animation-range: 0% 80%;
    }
    .shot--dawn, .shot--dusk, .sky { top: 0; height: 100%; }

    /* dusk arrives behind the swell front */
    .shot--dusk {
      -webkit-mask-image: linear-gradient(100deg, #000 calc(var(--front) - var(--soft) * 1%), transparent var(--front));
      mask-image: linear-gradient(100deg, #000 calc(var(--front) - var(--soft) * 1%), transparent var(--front));
    }
    /* the light the front carries */
    .glint {
      display: block;
      top: 0;
      bottom: 0;
      pointer-events: none;
      background: linear-gradient(100deg,
        transparent calc(var(--front) - var(--soft) * 1.5%),
        rgb(255 240 214 / 0.26) calc(var(--front) - var(--soft) * 0.5%),
        transparent calc(var(--front) + 5%));
      mix-blend-mode: soft-light;
    }

    /* the sea comes a little closer the whole way down */
    .shot img {
      animation: approach linear both;
      animation-timeline: scroll(root block);
    }

    /* each letter lifts as the front passes beneath it, then is set back down */
    .l {
      --at: calc((var(--x) * 100 + 2 + var(--soft) / 2) / (110 + var(--soft)) * 80%);
      animation: lift linear both;
      animation-timeline: scroll(root block);
      animation-range: calc(var(--at) - 12%) calc(var(--at) + 12%);
      will-change: transform;
    }

    .close {
      animation: arrive linear both;
      animation-timeline: scroll(root block);
      animation-range: 70% 86%;
    }

    .cue {
      display: block;
      position: absolute;
      left: 50%;
      bottom: calc(24px + env(safe-area-inset-bottom, 0px));
      width: 1px;
      height: 44px;
      margin: 0;
      background: var(--foam);
      animation: leave linear both;
      animation-timeline: scroll(root block);
      animation-range: 0% 4%;
    }
  }
}

@keyframes pass {
  from { --front: -2%; }
  to { --front: calc(108% + var(--soft) * 1%); }
}
@keyframes approach {
  to { transform: scale(1.045); }
}
@keyframes lift {
  0% { transform: none; animation-timing-function: cubic-bezier(0.45, 0, 0.55, 1); }
  50% { transform: translateY(-0.2em) rotate(-1.6deg); animation-timing-function: cubic-bezier(0.45, 0, 0.55, 1); }
  100% { transform: none; }
}
@keyframes arrive {
  from { opacity: 0; transform: translateY(14px); visibility: hidden; }
  to { opacity: 1; transform: none; visibility: visible; }
}
@keyframes leave {
  to { opacity: 0; }
}

/* ---------- the not-found page: one still screen ---------- */

.stage.lost {
  position: relative;
  height: 100vh;
  height: 100svh;
  animation: none;
}
.lost .shot--dusk, .lost .sky { top: 0; height: 100%; }
.lost .shot--dusk { -webkit-mask-image: none; mask-image: none; }
.lost .name { font-size: min(calc(min(95cqw, 100cqw - 32px) / 11.4), 30cqh); }
.lost .close { animation: none; }
@media (orientation: portrait) {
  .lost .name { font-size: min(calc((100cqw - 32px) / 7.1), 13.5cqh); }
  .lost .w + .w { font-stretch: 125%; }
}
