/* lucaslockeridge.uk */

/* the blue lives on <html> as well, so short pages (and the landing page,
   whose body is position:fixed) can't leave the canvas showing through */
html {
  background-color: #0848e2;
}

/* IM Fell English — a digitisation of a 17th century type, by Igino Marini.
   SIL Open Font Licence, so it lives here rather than being fetched from
   Google: nothing about the site leaves the site. Two files, 114 KB, and the
   licence sits beside them in assets/fonts/OFL.txt as that licence requires. */
@font-face {
  font-family: "IM Fell English";
  src: url("assets/fonts/imfellenglish-regular.woff2") format("woff2");
  font-weight: normal; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "IM Fell English";
  src: url("assets/fonts/imfellenglish-italic.woff2") format("woff2");
  font-weight: normal; font-style: italic; font-display: swap;
}

body {
  min-height: 100vh;
  margin: 0;
  padding: 80px 6vw 220px 8vw;
  background-color: #0848e2;
  color: #ffffff;
  font-family: "IM Fell English", Palatino, "Palatino Linotype", Georgia, serif;
  font-size: 16px;
  line-height: 1.55;
  position: relative;
  overflow-x: hidden;
}

/* a face, far too big, cropped by the edge of the page.
   sits behind everything and can't be clicked. */
.ghost {
  position: fixed;
  width: 42vw;
  /* no min-width — ghost.js sets extreme sizes and a floor would clamp them */
  filter: invert(1);
  opacity: 0.28;
  pointer-events: none;
  z-index: 0;
}
.ghost.g1 { right: -9vw;  top: 14vh;    transform: rotate(-4deg); }
.ghost.g2 { left: -11vw;  bottom: -8vh; transform: rotate(7deg);  }
.ghost.g3 { right: -13vw; bottom: 6vh;  transform: rotate(3deg);  width: 34vw; }
.ghost.g4 { left:  -7vw;  top: 26vh;    transform: rotate(-11deg); width: 30vw; }
.ghost.g5 { right: -5vw;  bottom: 22vh; transform: rotate(5deg);   width: 46vw; }

/* lifts the content above the ghost. anything that positions itself against
   the viewport carries .overlay so this leaves it alone — listing them by
   name instead kept raising this selector's specificity and silently
   dropping the newest one into normal flow */
body > *:not(.overlay) { position: relative; z-index: 1; }

img { max-width: 100%; height: auto; }

a { color: #ffffff; }
a:hover { text-decoration: none; }

p { margin: 0 0 1.4em; max-width: 34em; }

h2 {
  font-size: 16px;
  font-weight: normal;
  font-style: italic;
  margin: 3.5em 0 1.2em;
}

/* navigation — words at slightly wrong heights, not a row */
nav { margin-bottom: 5em; }
nav a { margin-right: 1.6em; position: relative; display: inline-block; }
nav a:nth-child(2) { top: 15px;  margin-right: 2.6em; }
nav a:nth-child(3) { top: -9px; }
nav a:nth-child(4) { top: 23px;  margin-right: 1.1em; }
nav a:nth-child(5) { top: 3px;   margin-right: 3.2em; }
nav a:nth-child(6) { top: -15px; }
nav a[aria-current="page"] { color: #ffe14f; text-decoration: none; }

/* index */
.top { margin: 0 0 3.5em; }
.top img { width: 380px; max-width: 82vw; }

.stack { margin: 0 0 2.6em; max-width: none; }
.stack a { display: block; width: fit-content; margin-bottom: 0.35em; }
.stack a:nth-child(2) { margin-left: 2.4em; }
.stack a:nth-child(3) { margin-left: 0.7em; }
.stack a:nth-child(4) { margin-left: 3.1em; }

/* releases — wrapping, not a grid */
.covers { margin: 0; padding: 0; list-style: none; max-width: 52em; }
.covers li {
  display: inline-block;
  vertical-align: top;
  width: 150px;
  margin: 0 26px 34px 0;
}
.covers li:nth-child(4n+2) { margin-top: 22px; }
.covers li:nth-child(3n)   { margin-top: 9px; }
.covers img { width: 150px; }
.covers a { display: block; }
.covers .t { display: block; margin-top: 0.4em; }
.covers .c { display: block; color: #bacdff; }

/* gigs */
.gigs { margin: 0; padding: 0; list-style: none; }
.gig { margin-bottom: 3.2em; max-width: 34em; }
.gig .d { display: block; }
.gig .n { display: block; }
.gig .v { display: block; }
.gig .b { display: block; font-style: italic; }
.gig .note { display: block; font-style: italic; }
.gig .poster { display: block; margin-top: 0.9em; }
.gig .poster img { width: 140px; }
.gig:nth-child(3n) { margin-left: 3.5em; }
.gig:nth-child(5n) { margin-left: 1.2em; }

/* photographs — wrapping at uneven sizes */
.shots { margin: 0; padding: 0; list-style: none; max-width: 60em; }
.shots li {
  display: inline-block;
  vertical-align: top;
  margin: 0 22px 26px 0;
}
.shots img { width: 210px; }
.shots li:nth-child(5n+1) img { width: 270px; }
.shots li:nth-child(7n+3) img { width: 170px; }
.shots li:nth-child(4n+2) { margin-bottom: 44px; }

.dim { color: #bacdff; }

@media (max-width: 600px) {
  body { padding: 46px 8vw 120px; }
  nav { margin-bottom: 3.2em; }
  /* the staggered heights collide once the words wrap — flatten them */
  nav a,
  nav a:nth-child(2),
  nav a:nth-child(3),
  nav a:nth-child(4),
  nav a:nth-child(5),
  nav a:nth-child(6) {
    position: static;
    top: auto;
    display: inline-block;
    margin: 0 1.4em 0.4em 0;
  }
  .covers li { width: 130px; margin-right: 18px; }
  .covers img { width: 130px; }
  .shots img,
  .shots li:nth-child(5n+1) img,
  .shots li:nth-child(7n+3) img { width: 100%; }
  .shots li { display: block; margin-right: 0; }
}

/* ---- writing ---- */

.entries { margin: 0; padding: 0; list-style: none; }
.entries li { margin-bottom: 1.8em; }
.entries li:nth-child(2n) { margin-left: 3.4em; }
.entries li:nth-child(3n) { margin-left: 1.2em; }
.entries li:nth-child(5n) { margin-left: 5.1em; }
.entries li:nth-child(7n) { margin-left: 0.4em; }
.entries a { display: block; width: fit-content; }
.entries .when { display: block; color: #bacdff; }

.post { max-width: 34em; }
.post h1 { font-size: 16px; font-weight: normal; margin: 0 0 0.2em; }
.post .when { display: block; color: #bacdff; margin-bottom: 3.2em; }
.post h2 { font-size: 16px; font-weight: normal; font-style: italic; margin: 2.8em 0 1em; }
.post blockquote { margin: 1.8em 0 1.8em 1.6em; font-style: italic; }
.post img { margin: 1.8em 0; }
.post hr { border: 0; border-top: 1px solid #4a7bff; width: 38%; margin: 2.8em 0; }
.post .back { margin-top: 4.5em; }

@media (max-width: 600px) {
  .entries li:nth-child(2n),
  .entries li:nth-child(3n),
  .entries li:nth-child(5n),
  .entries li:nth-child(7n) { margin-left: 0; }
}

/* ---- video ---- */

.films { margin: 0; padding: 0; list-style: none; max-width: 52em; }
.film { margin-bottom: 3.4em; max-width: 480px; }
.film .still { display: block; }
.film img,
.film iframe { display: block; width: 480px; max-width: 100%; height: auto; }
.film iframe { aspect-ratio: 16 / 9; }
.film .t { display: block; margin-top: 0.4em; }
.film .n { display: block; color: #bacdff; }
.film:nth-child(2n) { margin-left: 3.4em; }
.film:nth-child(3n) { margin-left: 1.2em; }

@media (max-width: 600px) {
  .film:nth-child(2n),
  .film:nth-child(3n) { margin-left: 0; }
}


/* ---- the things he's done, on biography ---- */

.intro { margin-bottom: 3.4em; }
.credits { margin: 0; padding: 0; list-style: none; }
.credit { margin-bottom: 2.4em; max-width: 34em; }
.credit .r { display: block; color: #bacdff; }
.credit .w { display: block; }
.credit .note { display: block; font-style: italic; }
.credit:nth-child(3n) { margin-left: 3.5em; }
.credit:nth-child(5n) { margin-left: 1.2em; }

@media (max-width: 600px) {
  .credit:nth-child(3n),
  .credit:nth-child(5n) { margin-left: 0; }
}


/* ---- a release ---- */

.release { max-width: 34em; }
.release h1 { font-size: 16px; font-weight: normal; margin: 0 0 0.2em; }
.release .c { color: #bacdff; margin: 0 0 1.8em; }
.release .art { margin: 0 0 1.4em; }
.release .art img { width: 300px; max-width: 100%; height: auto; }
.release .hear { margin: 0 0 3.4em; }
.release h2 { font-size: 16px; font-weight: normal; font-style: italic; margin: 2.8em 0 1em; }
.release .verse { margin: 0 0 1.7em; }
.release hr { border: 0; border-top: 1px solid #4a7bff; width: 38%; margin: 2.8em 0; }
.release .back { margin-top: 4.5em; }


/* ---- the landing page holds still: no scrolling ---- */

body.landing {
  /* fixed to the viewport, so the document has nothing to scroll at all —
     overflow:hidden on body alone still leaves the html element scrollable */
  position: fixed;
  inset: 0;
  box-sizing: border-box;
  overflow: hidden;
  padding: 5vh 6vw 4vh 8vw;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

/* size the photo off the viewport height so it always fits */
body.landing .top { margin: 0 0 4vh; }
body.landing .box {
  /* size from whichever runs out first, keeping the 3:4 ratio. capped well
     under the page width because a turned box projects ~1.3x its own width */
  /* walls match the photos at 3:4 so nothing is cropped */
  --s: min(40vh, 56vw);
  height: var(--s);
  width: calc(var(--s) * 0.75);
  /* a turned cube reaches ~21% of its width past its own left edge,
     which is more than the page padding allows for on its own */
  margin-left: 4vw;
}
body.landing .stack { margin-bottom: 2vh; }
body.landing p:last-of-type { margin-bottom: 0; }

@media (max-height: 620px) {
  body.landing .box { --s: min(32vh, 56vw); }
  body.landing .stack a { margin-bottom: 0.15em; }
}

/* ---- posters grow on hover ---- */

.gig .poster:hover img,
.gig .poster:focus-visible img {
  /* a real width change, not a transform — this reflows, so the entries
     underneath get pushed down instead of being covered over */
  width: 380px;
}

/* ---- the box you can spin ---- */

.box {
  perspective: 1200px;
  cursor: grab;
  /* stop the browser treating a drag as a scroll or a text selection */
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}

.box-inner {
  position: relative;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
}

.box .face {
  position: absolute;
  inset: 0;
  overflow: hidden;
  /* each side is only visible from outside the box */
  backface-visibility: hidden;
}


.box .face img {
  width: 100%;
  height: 100%;
  object-fit: cover;      /* walls are already 3:4, so nothing is lost */
  display: block;
  pointer-events: none;
}

/* the lid and base are square whatever we do, so the photo is stretched
   to fill rather than cropped or letterboxed */
.box .face.cap { inset: auto 0 auto 0; }
.box .face.cap img { object-fit: fill; }

/* the rare one stretches on any side, so none of it is cropped away */
.box .face.rare img { object-fit: fill; }

/* ---- the name, scattered beside the cube ---- */

body.landing .names {
  /* fixed, not absolute: names.js works in viewport coordinates, and an
     absolute layer sits inside the body's padding box, shifting every
     letter right by 8vw */
  position: fixed;
  inset: 0;
  pointer-events: none;   /* never gets in the way of the cube or the links */
  z-index: 2;
}

body.landing .names span {
  position: absolute;
  white-space: nowrap;
}

/* ---- the thing that happens if you leave it alone ---- */

.haunt {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 3;
}

.haunt-letter {
  position: absolute;
  white-space: pre;
  opacity: 0;
  /* the duration is set per letter in haunt.js so they can differ */
  transition-property: transform, opacity;
  transition-timing-function: cubic-bezier(0.16, 0.6, 0.2, 1);
}

.haunt.going .haunt-letter {
  opacity: 0;
  transition-duration: 600ms;
}

/* the scattered name steps back while the sentence is up */
/* haunt.js drives this fade, timing it to land exactly as the last letter
   of the quote arrives — the duration has to follow the build, which
   changes, so it can't be fixed here */
.names { transition: opacity 90s ease; }

/* ---- someone at the bottom of the page ---- */

.peek {
  /* absolute, not fixed — he belongs to the foot of the document rather
     than riding along with the screen */
  position: absolute;
  right: 3vw;
  bottom: 0;
  width: clamp(90px, 15vw, 190px);
  height: auto;
  z-index: 4;
  pointer-events: none;      /* never in the way of a link */
}
