/*
  SITE-WIDE STYLES
  ----------------
  Palette, webfont, type scale and the frame navigation. Every page links this.
  Page-specific rules live in their own file (see css/project.css) or in a <style>
  block on the page itself.
*/

  /* 5by7 is a dot-matrix face. It was installed locally on Matt's machine, which
     only works on Matt's machine — this is the subset webfont so visitors get it too.
     Built from 5by7_0.ttf with fontTools, Latin basic only: 19.8 KB. */
  @font-face {
    font-family: "5by7";
    /* relative to THIS FILE (css/), not to the page that links it */
    src: url("../assets/fonts/5by7-regular.woff2") format("woff2");
    font-weight: 400;
    font-style: normal;
    font-display: swap;
  }

  :root {
    --bg: #625d5d;   /* was #454344 until 2026-09-11 — see the palette note in CLAUDE.md */
    --fg: #d6d8d7;
    --muted: #8f9190;
    --link-hover: #fb649d;   /* every clickable bit of text turns this on hover */

    /* One dot of the 5by7 grid is 0.1em, so the face only lands on whole pixels at
       multiples of 10px. Off-multiples go soft, which defeats the point of a
       dot-matrix font. Keep type sizes on this scale. */
    /* One size for all homepage type: nav and the thumbnail hover labels match. */
    --type-nav: 15px;
    --type-label: 15px;

    /* Optical corrections for 5by7, measured from the rendered ink at 20px.
       The line box is NOT the ink: the ink sits 0.05em inside the box top and
       0.25em inside the box bottom (ascent 15 / descent 5 per em, and these are all
       caps so nothing occupies the descent). And letter-spacing leaves a trailing
       space after the last character, making the box wider than the ink. */
    /* Derived by measuring the rendered ink at the size actually in use. These were
       first worked out at 20px (0.05 / 0.25em); at 15px the browser rounds the font's
       ascent and descent to whole pixels and the true values shift slightly. Since the
       whole site is 15px now, these match 15px. Re-measure if the size changes. */
    --ink-above: 0.0333em;  /* 0.5px at 15px — box top to the cap */
    --ink-below: 0.2667em;  /* 4px at 15px — baseline to box bottom */
    /* Half again on the original 14/2.2vw/30. The spiral is sized off the live nav
       boxes, so it shrinks to keep its clearance automatically. */
    --nav-pad: clamp(21px, 3.3vw, 45px);
  }

  * { box-sizing: border-box; }

  html, body {
    margin: 0;
    height: 100%;
    background: var(--bg);
    color: var(--fg);
    font: 400 14px/1.5 "5by7", "Helvetica Neue", Helvetica, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
    /* NO GREY BOX ON TAP.
       iOS and Android paint a translucent dark rectangle over the whole of any
       element you touch. On a nav label that reads as a box drawn round the word; on
       something large — a project card, or a video's play button, which fills its
       entire slot — it flashes a huge dark panel across the page. The site has its
       own press feedback (the text turns pink), so the browser's is just noise. */
    -webkit-tap-highlight-color: transparent;
  }


  /* ---------- Frame navigation ---------- */
  /* Four labels pinned to the edges of the viewport. The side items use
     writing-mode rather than a rotate transform, so letter-spacing tracks along the
     vertical axis properly and the box sizes itself. Mirrored spine convention:
     the left one reads bottom-to-top, the right one top-to-bottom. */

  .frame-nav__item {
    position: fixed;
    z-index: 2000;                 /* above a hovered tile, which lifts to 1000 */
    font-family: "5by7", "Helvetica Neue", Helvetica, Arial, sans-serif;
    font-size: var(--type-nav);
    /* The face has ascender 700 / descender 0 out of 1000, so at line-height 1 the
       browser splits the leftover 6px of a 20px box evenly above and below the ink.
       That is what makes the gap to the edge identical on all four sides — with the
       inherited 1.5 the boxes were 30px and the top/bottom items sat further in
       than the side ones. */
    line-height: 1;
    letter-spacing: 0.34em;
    /* An indent equal to the letter-spacing balances the trailing space, so the ink
       is centred in its own box — in any writing mode, without transform tricks. */
    text-indent: 0.34em;
    text-transform: uppercase;
    text-decoration: none;
    white-space: nowrap;
    color: var(--fg);
    /* Full strength, deliberately. This used to rest at 0.72 opacity as a hover
       affordance, which made the nav read dimmer than the hover labels even though
       both are var(--fg) — the labels are never dimmed. Same colour, same value now.
       The hover cue is a colour change, so it costs nothing in brightness. */
    transition: color 0.2s ease;
  }

  /* Keeps a phrase together on one line. Wrap anything that must never be split —
     a hyphenated word, a name, a measurement — and it moves to the next line whole.
     Use it on phrases, never on a whole heading, or a narrow window gets a line
     that overflows the screen instead of wrapping. */
  .nowrap { white-space: nowrap; }

  /* Removes an element from view but leaves it for screen readers and search
     engines. Used where a heading is structurally needed but not wanted on screen. */
  .visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }

  /* The site-wide rules for clickable text. Any <a> on any page picks these up.
     Thumbnail labels are exempt because .tile__label sets its own colour, which
     is more specific than this.

     The base `a` rule matters: without it, a page that needs its links to sit in
     the page colour has to set `color` on its own `a` selector, and at equal
     specificity a later stylesheet then beats `a:hover` and the hover silently
     stops working. Setting the resting colour here once means no page stylesheet
     needs to touch link colour at all. */
  a { color: inherit; text-decoration: none; }

  /* HOVER IS FOR DEVICES THAT HAVE A POINTER.
     A touchscreen has no hover, so it fakes one: tapping a link leaves it in the
     :hover state until you tap somewhere else. That is why the PROJECTS label stayed
     pink after arriving on a project page — the browser still thought the finger was
     resting on it. `(hover: hover)` limits the rule to devices with a real pointer.
     A phone therefore gets the pink only from :active, below — for the moment of the
     press, which is exactly the feedback that was wanted. */
  @media (hover: hover) {
    a:hover { color: var(--link-hover); }
  }

  a:focus-visible { color: var(--link-hover); }

  /* The press itself, on every device. */
  a:active { color: var(--link-hover); }

  /* PER-LABEL TRACKING
     The four labels have wildly different character counts, so identical tracking
     gives wildly different run lengths and the frame looks lopsided. Each label is
     tracked to even them up. text-indent must always equal letter-spacing on the
     same label, or the ink stops centring — see the optical-corrections note.

     Sides: ABOUT (5 chars) and CONTACT (7) come out EXACTLY equal at 81px.
     Top/bottom: MATT CHING (10) against WORK (4) cannot be equalised — matching
     would need WORK near 0.85em and MATT CHING near 0.11em, which stops being a
     cheat and becomes two different treatments. These close roughly 40% of it. */
  .frame-nav__item--about   { letter-spacing: 0.40em; text-indent: 0.40em; }
  .frame-nav__item--contact { letter-spacing: 0.15em; text-indent: 0.15em; }
  /* PROJECTS is 8 characters against MATT CHING's 10 (and one of those is a space,
     which advances 0.3em rather than 0.6em). Matching their BOX widths exactly took
     0.37em, but that left PROJECTS with letter gaps 54% wider than MATT CHING's, and
     it read as the wider word despite measuring 4px narrower in ink — your eye reads
     the gaps, not the box.
     0.30em splits it: gaps within ~1px of MATT CHING's, box ~10px narrower. Matching
     the texture exactly would need 0.24em, which puts the box 18px off. */
  .frame-nav__item--work    { letter-spacing: 0.30em; text-indent: 0.30em; }

  .frame-nav__item--home    { letter-spacing: 0.24em; text-indent: 0.24em; }

  @media (hover: hover) {
    .frame-nav__item:hover { color: var(--link-hover); text-decoration: none; }
  }

  .frame-nav__item:focus-visible,
  .frame-nav__item:active {
    color: var(--link-hover);
    text-decoration: none;
  }

  /* A BIGGER TARGET THAN THE INK.
     These labels are 15px type — a hit area a few millimetres tall. A near-miss with
     a thumb does not land on nothing, it lands on whatever is behind: on the archive
     that is a project card, so tapping just below CONTACT opened a project instead.
     This invisible pad grows the target well past the recommended 44px without
     moving the label a pixel, and the nav's z-index keeps it above page content. */
  .frame-nav__item::after {
    content: "";
    position: absolute;
    inset: -15px -18px;
  }

  /* Matt Ching sits at the TOP, Work at the bottom. The narrow-screen block
     further down is unaffected — Matt Ching still goes to the top-left corner
     there, which is why the classes stay named for their role, not a position. */
  .frame-nav__item--home {
    top: calc(var(--nav-pad) - var(--ink-above));
    left: 50%;
    transform: translateX(-50%);
  }

  .frame-nav__item--work {
    bottom: calc(var(--nav-pad) - var(--ink-below));
    left: 50%;
    transform: translateX(-50%);
  }

  .frame-nav__item--about {
    /* vertical-rl puts the ascent side at block-start (right); the 180 flip brings
       it back to the left, so this edge carries the small gap. */
    left: calc(var(--nav-pad) - var(--ink-above));
    top: 50%;
    writing-mode: vertical-rl;
    transform: translateY(-50%) rotate(180deg);
  }

  .frame-nav__item--contact {
    right: calc(var(--nav-pad) - var(--ink-above));
    top: 50%;
    writing-mode: vertical-rl;
    transform: translateY(-50%);
  }

  /* On a narrow screen the spiral grows to nearly the full width and would run
     straight into the side items, so all four move to the corners: the midlines are
     left clear and the corners are the furthest points from the centre. */
  @media (max-width: 720px) {
    .frame-nav__item--about,
    .frame-nav__item--contact {
      writing-mode: horizontal-tb;
      transform: none;
      top: auto;
      bottom: var(--nav-pad);
    }
    .frame-nav__item--about   { left: var(--nav-pad); right: auto; }
    .frame-nav__item--contact { right: var(--nav-pad); left: auto; }
    /* now pinned by their bottom edge, so they take the descent-side correction */
    .frame-nav__item--about,
    .frame-nav__item--contact { bottom: calc(var(--nav-pad) - var(--ink-below)); }

    .frame-nav__item--home {
      top: calc(var(--nav-pad) - var(--ink-above));
      bottom: auto;
      left: var(--nav-pad);
      right: auto;
      transform: none;
    }
    .frame-nav__item--work {
      top: calc(var(--nav-pad) - var(--ink-above));
      /* MUST cancel the desktop rule's `bottom`. A fixed element given BOTH top and
         bottom stretches between them: PROJECTS became a 113x775px invisible column
         down the whole right-hand side of the phone. Three bugs came out of that one
         missing line — it sat on top of CONTACT (same z-index, later in the DOM), so
         tapping CONTACT opened a project page; and the spiral measures its clearance
         from the nav's real boxes, so it read a label 8px from the centre and shrank
         itself to the 60px floor, which is why the hero was a tiny knot. */
      bottom: auto;
      left: auto;
      right: var(--nav-pad);
      transform: none;
    }
  }
