/* Layout and structure. Every colour, size and position comes from config.js
   (through settings.css) — change values there, not here. */

/* --- Fonts (§6, self-hosted) ----------------------------------------------
   The @font-face rules are generated by build.js into settings.css, because
   the font files are cut down and renamed when the site is built. */

/* --- Hidden heading -------------------------------------------------------
   Each page's title as a heading for screen readers and search engines; not
   shown on screen (§16). */

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

/* --- Page colours ---------------------------------------------------------- */

.page--main {
  --top-block-colour: var(--main-top-block-colour);
  --band-colour: var(--main-band-colour);
  --bottom-block-colour: var(--main-bottom-block-colour);
  --band-text-colour: var(--main-band-text-colour);
  --top-button-colour: var(--main-input-button-colour);
  --vertical-name-colour: var(--main-vertical-name-colour);
  --vertical-info-colour: var(--main-vertical-info-colour);
  --copyright-colour: var(--main-copyright-colour);
}

.page--design {
  --top-block-colour: var(--design-top-block-colour);
  --band-colour: var(--design-band-colour);
  --bottom-block-colour: var(--design-bottom-block-colour);
  --band-text-colour: var(--design-band-text-colour);
  --top-button-colour: var(--design-output-button-colour);
  --vertical-name-colour: var(--design-vertical-name-colour);
  --vertical-info-colour: var(--design-vertical-info-colour);
  --copyright-colour: var(--design-copyright-colour);
}

.page--about {
  --top-block-colour: var(--about-top-block-colour);
  --band-colour: var(--about-band-colour);
  --bottom-block-colour: var(--about-bottom-block-colour);
  --band-text-colour: var(--about-band-text-colour);
  --top-button-colour: var(--about-back-button-colour);
  --copyright-colour: var(--about-copyright-colour);
}

/* --- Base ------------------------------------------------------------------ */

html {
  /* The loop keeps the scroll position itself; the browser must not shift it
     when photos above the screen change size. */
  overflow-anchor: none;
  background: var(--bottom-block-colour);
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
}

a {
  color: inherit;
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
}

svg {
  display: block;
}

/*
  Converting mockup measurements (whole screen) into page positions.

  The page starts below the status bar, so anything measured from the top of
  the screen moves up by --status-bar-height.

  Anything measured from the bottom is placed from the bottom of the *smallest*
  Safari viewport (100svh — bars fully showing), so it does not move when
  Safari's bar shrinks while scrolling; --safari-bottom-bar-height is the part
  of the screen below that. The bottom colour block paints on downwards past
  the screen edge, under Safari's bar (§3).
*/
:root {
  --page-bottom: 100vh;
  --screen-bottom-on-page: calc(var(--page-bottom) + var(--safari-bottom-bar-height));
  --band-top: calc(
    var(--screen-bottom-on-page) - var(--reference-screen-height)
    + var(--top-block-height) + var(--photo-window-height)
  );
}

@supports (height: 100svh) {
  :root {
    /* --min-viewport-height comes from viewport.js: Safari's 100svh is
       sometimes too small (iOS 26), so the larger of the two is used. */
    --page-bottom: max(100svh, var(--min-viewport-height, 0px));
  }
}

/* One screen pixel, whatever the screen's density (§8, §11). */
:root {
  --hairline: 1px;
}

@media (min-resolution: 2dppx) {
  :root { --hairline: 0.5px; }
}

@media (min-resolution: 3dppx) {
  :root { --hairline: 0.3333px; }
}

/* --- Photo strip ----------------------------------------------------------- */

.strip {
  background: var(--photo-placeholder-colour);
}

.photo {
  position: relative;
  margin: 0;
  /* A shared link like #008 lands with the photo just under the top block. */
  scroll-margin-top: max(0px, calc(var(--top-block-height) - var(--status-bar-height)));
}

.photo picture,
.photo img {
  display: block;
  width: 100%;
  height: auto;
  background: var(--photo-placeholder-colour);
  /* No "Save to Photos" menu on long press, no selecting or dragging. */
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-user-drag: none;
}

.photo__code {
  position: absolute;
  left: var(--code-number-left);
  bottom: var(--code-number-bottom);
  font-family: var(--code-number-font), "Arial Narrow", sans-serif;
  font-weight: 700;
  font-size: var(--code-number-font-size);
  letter-spacing: var(--code-number-tracking);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--code-number-light);
  pointer-events: none;
}

/* Over very white photos (decided per photo when the site is built, §14). */
.photo--code-dark .photo__code {
  color: var(--code-number-dark);
}

/* --- Fixed colour blocks and band ----------------------------------------- */

.block,
.band {
  position: fixed;
  left: 0;
  right: 0;
  z-index: 10;
}

.block--top {
  top: 0;
  height: max(0px, calc(var(--top-block-height) - var(--status-bar-height)));
  background: var(--top-block-colour);
}

.block--top::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 100%;
  height: var(--block-bleed);
  background: inherit;
}

.band {
  top: var(--band-top);
  height: var(--band-height);
  overflow: hidden;
  background: var(--band-colour);
  color: var(--band-text-colour);
}

.block--bottom {
  top: calc(var(--band-top) + var(--band-height));
  height: calc(var(--bottom-block-height) + var(--block-bleed));
  background: var(--bottom-block-colour);
}

.band__track {
  display: flex;
  align-items: center;
  height: 100%;
  white-space: pre;
  will-change: transform;
}

.band__run,
.band__item {
  display: flex;
  flex: none;
  align-items: center;
  height: 100%;
}

/* Photography page band layers (band.js). */
.band__layer {
  position: absolute;
  inset: 0;
  overflow: hidden;
}

/* Once band.js is running, each photo's stretch of band is placed exactly. */
.band--live .band__track {
  position: relative;
  display: block;
}

.band--live .band__item {
  position: absolute;
  top: 0;
  overflow: hidden;
}

/* While the speed cap is on: a solid row of triangles. */
.band__triangle-row {
  display: flex;
  align-items: center;
  gap: var(--triangle-gap);
  height: 100%;
  will-change: transform;
}

.band__triangle-row svg {
  flex: none;
  width: var(--triangle-width);
  height: var(--triangle-height);
}

/* After scrolling up: triangles point right until scrolling down again
   (photography page, hard cut). */
.band--reversed .triangles svg,
.band--reversed .band__triangle-row svg {
  transform: scaleX(-1);
}

.band__text {
  margin: 0 var(--triangle-text-gap);
  font-family: var(--band-font), sans-serif;
  font-size: var(--band-font-size);
  letter-spacing: var(--band-tracking);
  line-height: 1;
}

.triangles {
  display: flex;
  flex: none;
  gap: var(--triangle-gap);
}

.triangles svg {
  width: var(--triangle-width);
  height: var(--triangle-height);
}

/* --- Arrow (one SVG, turned per button in CSS — §7) ------------------------ */

.arrow {
  display: block;
  flex: none;
  width: var(--arrow-width);
  height: var(--arrow-height);
}

.arrow svg {
  width: 100%;
  height: 100%;
}

/* --- Buttons: shared ------------------------------------------------------- */

.top-button,
.about-button {
  position: fixed;
  z-index: 20;
  font-family: var(--button-font), Arial, sans-serif;
  font-weight: 700;
  font-size: var(--button-font-size);
  letter-spacing: var(--button-tracking);
  line-height: 1;
}

/* Invisible padding so the tappable area is at least 44 × 44 px (§7). */
.top-button::after,
.about-button::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: max(100%, var(--tap-target-min));
  height: max(100%, var(--tap-target-min));
  transform: translate(-50%, -50%);
}

/* --- INPUT / OUTPUT / BACK ------------------------------------------------- */

/* Positions in CLAUDE.md measure to the top of the capital letters (checked
   against the mockup), so the word is trimmed to its cap height and aligned to
   the top of the button, level with the top of the arrow. */
.top-button__word,
.about-button__word {
  text-box: trim-both cap alphabetic;
}

.top-button {
  left: var(--top-button-left);
  top: calc(var(--top-button-top) - var(--status-bar-height));
  height: var(--top-button-height);
  color: var(--top-button-colour);
}

/* The arrow and the word together — the button's visual bounds, which the
   selection frame hugs (§11). */
.button-visual {
  display: flex;
  align-items: flex-start;
  width: max-content;
}

.top-button .button-visual {
  gap: var(--top-button-arrow-gap);
}

.top-button--back .button-visual {
  gap: var(--back-button-arrow-gap);
}

.about-button .button-visual {
  gap: var(--about-arrow-gap);
}

/* Selection frame: one screen pixel, hugging the visual bounds, no gap.
   Mouse: while hovering. Touch: while the finger is held on that button
   (buttons.js adds .is-pressed). Photos never get a frame (§11). */
.is-pressed > .button-visual,
.is-pressed > * > .button-visual {
  box-shadow: inset 0 0 0 var(--hairline) var(--selection-frame-colour);
}

@media (hover: hover) {
  .top-button:hover > .button-visual,
  .about-button:hover .button-visual {
    box-shadow: inset 0 0 0 var(--hairline) var(--selection-frame-colour);
  }
}

/* INPUT's arrow points right (as drawn); OUTPUT's points left (§7). */
.top-button--output .arrow {
  transform: scaleX(-1);
}

/* --- ABOUT (rotated anticlockwise, arrow at the bottom pointing down) ------ */

.about-button {
  left: var(--about-button-left);
  top: calc(var(--about-button-top) - var(--status-bar-height));
  width: var(--about-button-width);
  height: var(--about-button-height);
  color: var(--about-button-colour);
  transition: color var(--about-button-fade) linear;
}

/* Chosen per photo by aboutbutton.js (§14). */
.about-button--light { color: var(--about-button-light); }
.about-button--dark { color: var(--about-button-dark); }

/* Laid out as a normal row — [← ABOUT] — then turned 90° anticlockwise about
   its top-left corner, so the left-pointing arrow ends up at the bottom,
   pointing down, and the word reads upwards. */
.about-button__inner {
  position: absolute;
  left: 0;
  top: 100%;
  width: var(--about-button-height);
  height: var(--about-button-width);
  display: flex;
  align-items: flex-start;
  padding-left: var(--about-arrow-inset);
  box-sizing: border-box;
  transform-origin: 0 0;
  transform: rotate(-90deg);
}

.about-button .arrow {
  transform: scaleX(-1);
}

/* --- Vertical name and Info (over the photos, §7, §14) --------------------- */

.vertical-name,
.vertical-info {
  position: fixed;
  z-index: 5;
  pointer-events: none;
  mix-blend-mode: var(--vertical-text-blend-mode);
  transform: translateY(-100%);
}

.vertical-name {
  right: var(--vertical-name-right);
  top: calc(var(--screen-bottom-on-page) - var(--vertical-name-from-bottom));
  width: var(--vertical-name-width);
  color: var(--vertical-name-colour);
}

.vertical-name svg {
  width: 100%;
  height: auto;
}

/* Rotated 90° clockwise: first line on the right, text reading downwards,
   lines aligned to the bottom (right-aligned before rotation). */
.vertical-info {
  right: var(--vertical-info-right);
  top: calc(var(--screen-bottom-on-page) - var(--vertical-info-from-bottom));
  writing-mode: vertical-rl;
  text-align: end;
  white-space: pre;
  font-family: var(--info-font), sans-serif;
  font-weight: 400;
  font-size: var(--info-font-size);
  letter-spacing: var(--info-tracking);
  line-height: var(--info-line-height);
  color: var(--vertical-info-colour);
  user-select: none;
  -webkit-user-select: none;
}

/* --- BACK (About page) ---------------------------------------------------- */

/* Arrow points left; the word is mirrored left-to-right (Illustrator's
   Reflect → Vertical axis) but the arrow is not. The mirrored word's trailing
   letter-spacing would land beside the arrow, so it is taken back out, letting
   the arrow touch the K (§7). */
.top-button--back .arrow {
  transform: scaleX(-1);
}

.top-button--back .top-button__word {
  transform: scaleX(-1);
  margin-left: calc(var(--button-tracking) * -1);
}

/* --- About page ------------------------------------------------------------ */

.page--about,
.page--about body {
  overflow: hidden;
  height: 100%;
}

/* Spans the window between the top block and the band. The artwork itself is
   scaled to that height and centred; the space beside it is filled (§15). */
.about-background {
  background: var(--about-background-surround);
  position: fixed;
  left: 0;
  right: 0;
  top: max(0px, calc(var(--top-block-height) - var(--status-bar-height)));
  height: calc(var(--band-top) - max(0px, calc(var(--top-block-height) - var(--status-bar-height))));
}

.about-background svg {
  width: 100%;
  height: 100%;
}

.about-background__fill {
  fill: var(--about-background-fill);
}

/* Outlines exactly one screen pixel thick on any phone (§8). */
.about-background__line {
  fill: none;
  stroke: var(--about-background-line);
  stroke-width: 1px;
  vector-effect: non-scaling-stroke;
}

@media (min-resolution: 2dppx) {
  .about-background__line { stroke-width: 0.5px; }
}

@media (min-resolution: 3dppx) {
  .about-background__line { stroke-width: 0.3333px; }
}

.about-intro,
.about-contact {
  position: fixed;
  z-index: 5;
  margin: 0;
  font-family: var(--button-font), Arial, sans-serif;
  font-weight: 700;
  font-style: normal;
  color: var(--about-text-colour);
  /* Positions are measured to the top of the capitals and to the baseline. */
  text-box: trim-both cap alphabetic;
}

.about-intro {
  left: var(--about-intro-left);
  right: var(--about-intro-left);
  top: calc(var(--about-intro-top) - var(--status-bar-height));
  font-size: calc(var(--about-intro-font-size) * var(--about-text-scale));
  line-height: calc(var(--about-intro-line-height) * var(--about-text-scale));
  letter-spacing: var(--about-intro-tracking);
  text-align: left;
}

.about-contact {
  right: var(--about-contact-right);
  top: calc(var(--screen-bottom-on-page) - var(--about-contact-from-bottom));
  transform: translateY(-100%);
  font-size: calc(var(--about-contact-font-size) * var(--about-text-scale));
  line-height: calc(var(--about-contact-line-height) * var(--about-text-scale));
  letter-spacing: var(--about-contact-tracking);
  text-align: right;
  white-space: pre;
}

.about-contact a {
  -webkit-touch-callout: default;
}

/* About band: the text carries its own " | " separators and trailing space. */
.band__text--about {
  margin: 0 0 0 var(--triangle-text-gap);
}

/* --- Copyright line (all pages) -------------------------------------------- */

/* Deliberately tiny, centred. Placed by the bottom of its letters (including
   descenders) a fixed distance above the screen bottom, so changing the size
   makes it grow upwards. */
.copyright {
  position: fixed;
  z-index: 15;
  left: 0;
  right: 0;
  top: calc(var(--screen-bottom-on-page) - var(--copyright-from-screen-bottom));
  transform: translateY(-100%);
  margin: 0;
  text-align: center;
  font-family: var(--copyright-font), Arial, sans-serif;
  font-weight: 700;
  font-size: var(--copyright-font-size);
  letter-spacing: var(--copyright-tracking);
  line-height: 1;
  color: var(--copyright-colour);
  text-box: trim-both cap text;
}

/* --- Debug readout (only with ?debug in the address) ----------------------- */

.debug {
  position: fixed;
  z-index: 100;
  right: 8px;
  top: 8px;
  padding: 6px 8px;
  font: 11px/1.4 ui-monospace, Menlo, monospace;
  color: #fff;
  background: rgba(0, 0, 0, 0.75);
  white-space: pre;
  pointer-events: none;
}
