* {
  box-sizing: border-box;
}

body {
  margin: 0 auto;
  max-width: 1000px;
  padding: 48px 20px 32px;
  background: #fbf8f1;
  color: #222;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  line-height: 1.4;
}

a {
  color: inherit;
}

a,
button {
  cursor: pointer;
}

/* Tiles and the logo animate their insides on hover. If the mouse hit-tests
   against those moving pieces, Chrome's cursor flickers between the hand and
   the arrow. Making the children invisible to the mouse means the link box
   itself (which never moves) is always what's under the cursor. */
.tile,
.wordmark {
  user-select: none;
  -webkit-user-drag: none;
}

.tile *,
.wordmark * {
  pointer-events: none;
}

/* header */

header h1 {
  margin: 0;
  font-size: 3.2rem;
  font-weight: 800;
  letter-spacing: -0.03em;
}

header h1 a {
  text-decoration: none;
}

/* inline-block so the whole word is one solid hover area, with no gaps
   between letters where the cursor drops back to an arrow */
.wordmark {
  display: inline-block;
}

/* "Liamd8t" - the 8 ball stands in for the o */

.wordmark .ball {
  display: inline-block;
  width: 0.56em;
  height: 0.56em;
  margin: 0 0.035em 0 0.02em;
  vertical-align: -0.01em;
}

.wordmark .t {
  display: inline-block;
  transform-origin: 70% 90%;
}

/* on hover the ball rolls into the t, the t wobbles, the ball bounces back */

.wordmark.bump .ball {
  animation: ball-bump 0.7s;
}

.wordmark.bump .t {
  animation: t-wobble 0.7s;
}

@keyframes ball-bump {
  0% {
    transform: translateX(0) rotate(0);
    animation-timing-function: ease-in;
  }
  30% {
    transform: translateX(0.07em) rotate(28deg);
    animation-timing-function: ease-out;
  }
  55% {
    transform: translateX(-0.04em) rotate(-16deg);
    animation-timing-function: ease-in-out;
  }
  78% {
    transform: translateX(0.012em) rotate(5deg);
  }
  100% {
    transform: translateX(0) rotate(0);
  }
}

@keyframes t-wobble {
  0%,
  28% {
    transform: rotate(0);
  }
  42% {
    transform: rotate(9deg);
  }
  62% {
    transform: rotate(-4deg);
  }
  82% {
    transform: rotate(1.5deg);
  }
  100% {
    transform: rotate(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .wordmark.bump .ball,
  .wordmark.bump .t {
    animation: none;
  }
}

.intro {
  margin: 6px 0 0;
  color: #666;
  font-size: 1.1rem;
}

/* every word in the line under the title does something daft when you point at it */
.word {
  display: inline-block;
  transition: transform 0.35s cubic-bezier(0.2, 0.9, 0.3, 1.4), color 0.2s, letter-spacing 0.35s;
}

.word:hover {
  color: #222;
}

.spin:hover {
  transform: rotate(360deg);
}

.jump:hover {
  transform: translateY(-10px) scale(1.15);
}

.wobble:hover {
  animation: wobble 0.5s ease-in-out;
}

@keyframes wobble {
  20% { transform: rotate(-9deg); }
  40% { transform: rotate(7deg); }
  60% { transform: rotate(-5deg); }
  80% { transform: rotate(3deg); }
  100% { transform: rotate(0); }
}

.squish:hover {
  transform: scale(1.45, 0.65);
}

.flip:hover {
  transform: scaleY(-1);
}

.rainbow:hover {
  animation: rainbow 0.9s linear infinite;
}

@keyframes rainbow {
  0% { color: #e0453a; }
  25% { color: #f5b74a; }
  50% { color: #7ee08a; }
  75% { color: #6fc3df; }
  100% { color: #e0453a; }
}

.stretch:hover {
  letter-spacing: 0.35em;
  transform: translateX(-2px);
}

@media (prefers-reduced-motion: reduce) {
  .word,
  .word:hover {
    animation: none;
    transform: none;
  }
}

/* project grid */

.grid {
  display: grid;
  margin-top: 40px;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 28px 22px;
}

.empty {
  grid-column: 1 / -1;
  margin: 24px 0;
  color: #999;
}

/* project tiles */

.tile {
  position: relative;
  display: block;
  text-decoration: none;
}

.tile-card {
  position: relative;
  isolation: isolate; /* keeps the caption's layering inside this card */
}

.thumb {
  position: relative;
  z-index: 2; /* sits over the caption printed on the page underneath */
  aspect-ratio: 1;
  border-radius: 12px;
  overflow: hidden;
  transition: transform 0.22s cubic-bezier(0.2, 0.8, 0.2, 1);
}

/* The thumbnail floats up off the page, uncovering the text lying under it.
   --caption-height and --float are measured in main.js from the tallest
   description, so nothing ever gets cut off. */
.tile:hover .thumb,
.tile:focus-visible .thumb {
  transform: translateY(calc(-1 * var(--float, 80px))) scale(1.03) rotate(-1.5deg);
}

/* every other card tips the other way, so a row doesn't look uniform */
.tile:nth-child(even):hover .thumb,
.tile:nth-child(even):focus-visible .thumb {
  transform: translateY(calc(-1 * var(--float, 80px))) scale(1.03) rotate(1.5deg);
}

.thumb img {
  display: block;
  width: 100%;
  height: 100%;
}

.tile h3 {
  margin: 10px 0 2px;
  font-size: 1.05rem;
}

.tile p {
  margin: 0;
  color: #777;
  font-size: 0.9rem;
}

/* On computers with a mouse, the name and description are always there,
   lying on the page in the bottom of the card's own space. The thumbnail
   covers them until it floats up. (Phones and tablets can't hover, so they
   just show them under each card as usual.) */
@media (hover: hover) {
  .tile:hover,
  .tile:focus-visible {
    z-index: 3; /* the floating card goes over its neighbours */
  }

  .caption {
    position: absolute;
    /* inside the card's own space, so it never covers the tile below */
    top: calc(100% - var(--caption-height, 68px));
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 1; /* under the thumbnail */
  }

  .caption h3 {
    margin-top: 0;
  }

  .caption p {
    font-size: 0.85rem;
  }
}

/* footer */

footer {
  margin-top: 72px;
  color: #999;
  font-size: 0.9rem;
  text-align: center;
}

@media (max-width: 480px) {
  body {
    padding-top: 32px;
  }

  header h1 {
    font-size: 2.4rem;
  }

  .grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 20px 14px;
  }
}
