/* ==========================================================================
   Lachlan Rouse - single page
   Layout is: fixed water photo background, with one centred column on top
   holding the name and a headed group of rows per section. Everything in
   the column is aligned to its left edge, so there is one line running
   down the page rather than two.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Type. Both faces are self-hosted, so the page works with no network and
   still opens straight from Finder. They are Instrument Serif and Instrument
   Sans, drawn by the same foundry, under the SIL Open Font License; the
   licence sits next to them in fonts/.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: "Instrument Serif";
  src: url("fonts/instrument-serif-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Instrument Sans";
  src: url("fonts/instrument-sans-var.woff2") format("woff2");
  font-weight: 400 600;
  font-style: normal;
  font-display: swap;
}

:root {
  /* Warm off-whites, not blue-whites. The only light in the photo is the
     low sun on the water, which is copper; cool text over it reads pasted
     on. These are near enough to white that contrast is unaffected. */
  --ink:          #f6f2ec;
  --ink-soft:     rgba(246, 242, 236, 0.70);
  --ink-faint:    rgba(246, 242, 236, 0.48);
  --deep:         #232428;   /* the photo's average colour, measured */

  /* The highlight that sweeps a row under the pointer. With no borders,
     rules or arrows on the page, this is the only thing that responds,
     so it has to be readable without becoming a button. */
  --wash:         rgba(246, 242, 236, 0.09);

  --column:       32rem;   /* width of the link column */
  --ease:         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: 100vh;
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: clamp(1.5rem, 6vw, 3rem) 1.25rem;
  padding-top: max(clamp(1.5rem, 6vw, 3rem), env(safe-area-inset-top));
  padding-bottom: max(clamp(1.5rem, 6vw, 3rem), env(safe-area-inset-bottom));

  font-family: "Instrument Sans", ui-sans-serif, system-ui, -apple-system,
               "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  color: var(--ink);
  background: var(--deep);        /* shows for the instant before the photo paints */
  overflow-x: hidden;
}

/* --------------------------------------------------------------------------
   Background: the water
   -------------------------------------------------------------------------- */

.backdrop {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  /* One still photo, sized to cover whatever shape the window is. The colour
     underneath it matches the photo's average, so the moment before it paints
     is a shade of the same thing rather than a flash of something else. */
  background: var(--deep) url("media/water.jpg") center / cover no-repeat;
}

/* Darkens the corners so the centre column is the brightest part of the page.
   Kept light on purpose: it is here to shape attention, not to rescue
   contrast. Measured against the patch of water the column actually sits on,
   the ink runs from about 4.3:1 at the single brightest pixel to 6.8:1 at the
   99th percentile and 14:1 at the median, with the text-shadow on every
   element lifting the worst of those further. So: comfortably AA, not AAA.
   If you swap the photo for a brighter one, raise these opacities.
   The greys are neutral to match the water, which is a near-neutral slate
   rather than the blue it first reads as. */
.backdrop__wash {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(115% 80% at 50% 34%,
      rgba(14, 15, 18, 0.00) 0%,
      rgba(13, 14, 17, 0.12) 52%,
      rgba(10, 11, 14, 0.34) 100%),
    linear-gradient(180deg,
      rgba(12, 13, 16, 0.20) 0%,
      rgba(12, 13, 16, 0.02) 40%,
      rgba(9, 10, 13, 0.28) 100%);
}

/* --------------------------------------------------------------------------
   The centre column
   -------------------------------------------------------------------------- */

.stage {
  position: relative;
  z-index: 1;

  width: 100%;
  max-width: var(--column);
  display: flex;
  flex-direction: column;
  gap: clamp(1.4rem, 4vw, 1.85rem);
}

.intro__name {
  margin: 0;
  font-family: "Instrument Serif", ui-serif, Georgia, serif;
  font-size: clamp(2.75rem, 11.5vw, 4.5rem);
  font-weight: 400;
  /* Instrument Serif is a narrow face, so the name is set larger than the
     rest of the page would suggest and given room rather than tracked in.
     Nothing negative here: at this size the letters need the air. */
  letter-spacing: 0.005em;
  line-height: 1.02;
  text-shadow: 0 2px 30px rgba(8, 6, 5, 0.5);
}

.intro__tagline {
  margin: 0.8rem 0 0;
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-faint);
  text-shadow: 0 1px 12px rgba(8, 6, 5, 0.6);
}

.intro__bio {
  margin: 0.4rem 0 0;
  font-size: 1rem;
  font-weight: 400;
  color: var(--ink-soft);
  text-shadow: 0 1px 12px rgba(8, 6, 5, 0.6);
}

/* --------------------------------------------------------------------------
   A headed group: a quiet label with rows, or a note, underneath it
   -------------------------------------------------------------------------- */

.group {
  display: flex;
  flex-direction: column;
}

/* Same treatment as the line under the name, one size down, so the two read
   as the same kind of quiet label rather than competing. */
.group__label {
  margin: 0 0 0.55rem;
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-faint);
  text-shadow: 0 1px 12px rgba(8, 6, 5, 0.6);
}

/* For a group with something to say but nothing to click yet. Set at the
   same size and rhythm as a row so it belongs to the same family, but one
   step down in brightness so it never looks like a link that isn't working. */
.group__note {
  margin: 0;
  padding: 0.5rem 0;
  font-size: 1rem;
  color: var(--ink-soft);
  text-shadow: 0 1px 12px rgba(8, 6, 5, 0.6);
}

/* --------------------------------------------------------------------------
   The list of links

   No boxes, borders or rules. A row is just its label, and the photo shows
   through the whole column. What marks a row as a link is that it is a
   domain name, brighter than the label above it, and that it lights up
   under the pointer.
   -------------------------------------------------------------------------- */

.links {
  display: flex;
  flex-direction: column;
}

.link {
  position: relative;
  display: block;
  width: 100%;

  /* reset, because this is both <a> and <button> */
  appearance: none;
  border: 0;
  background: none;
  font: inherit;
  color: var(--ink);
  text-decoration: none;
  cursor: pointer;

  padding: 0.5rem 0;
  text-align: left;
}

/* The highlight sits behind the label and runs a little wider than the
   column on both sides, so it reads as a sweep across the row rather than
   a button lighting up. */
.link::before {
  content: "";
  position: absolute;
  inset: 0 -0.8rem;
  border-radius: 8px;
  background: transparent;
  transition: background 0.28s var(--ease);
}

.link__label {
  position: relative;
  font-size: 1rem;
  letter-spacing: 0.01em;
  text-shadow: 0 1px 12px rgba(8, 6, 5, 0.55);
}

@media (hover: hover) {
  .link:hover::before { background: var(--wash); }
}

.link:active::before { background: var(--wash); }

/* This matters more than it used to. With the arrows and rules gone, the
   focus ring is the only affordance a keyboard visitor gets. */
.link:focus-visible {
  outline: 2px solid rgba(255, 255, 255, 0.92);
  outline-offset: 3px;
  border-radius: 3px;
}

/* Fade the column in on load, one row after another. */
.intro,
.group__label,
.group__note,
.link {
  animation: rise 0.75s var(--ease) both;
}
.intro { animation-delay: 0.05s; }

/* The rows are numbered within their own group, so the second group's label
   and note carry their own delays to keep one cascade running down the page
   rather than two starting over. */
.group:nth-of-type(1) .group__label { animation-delay: 0.14s; }
.link:nth-child(1) { animation-delay: 0.20s; }
.link:nth-child(2) { animation-delay: 0.26s; }
.link:nth-child(3) { animation-delay: 0.32s; }
.link:nth-child(4) { animation-delay: 0.38s; }
.link:nth-child(5) { animation-delay: 0.44s; }
.link:nth-child(6) { animation-delay: 0.50s; }

.group:nth-of-type(2) .group__label { animation-delay: 0.46s; }
.group:nth-of-type(2) .group__note  { animation-delay: 0.52s; }

@keyframes rise {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* --------------------------------------------------------------------------
   Utility
   -------------------------------------------------------------------------- */

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   Anyone who has asked for less movement. The background is a still photo for
   everyone now, so all that is left to settle is the way the page arrives.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .intro,
  .group__label,
  .group__note,
  .link {
    animation: none !important;
    transition: none !important;
  }
  .link::before { transition: none !important; }
}
