/* Site-wide theme — three pure neon inks on white, maximum brightness.
   The whole site is drawn in exactly three colours — the brightest possible
   neon red ink and lines, neon cobalt for the disc circles (and the text
   inside them), and neon green for the background grid — all sitting on a
   single bright white field. No gradients, no ripples: just a flat field.

   This file owns the shared canvas: the colours, the one typeface, the
   reset and the single base type size and weight. Every page inherits that
   one font, size and weight so type reads in a single voice across the whole
   site; pages add only layout on top, never their own font, size or weight. */

:root {
  /* neon red ink for all type and lines — the brightest possible red */
  --ink: #ff0000;
  /* neon cobalt for the disc circles and the text inside them — the brightest possible blue */
  --circle: #0000ff;
  /* one typeface for the whole site — Satoshi, the geometric face the wordmark
     was already set in, now carried across every surface so the logotype and the
     body type read in a single voice. Loaded as a variable font (Fontshare) so
     the site's single --weight resolves exactly rather than snapping to a step. */
  --font: 'Satoshi', 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
  /* the single type size for the whole site. Every word on every page is set at
     exactly this size — there is no larger or smaller tier anywhere — and it
     scales fluidly with the screen so every page resizes itself to the device.
     The whole site's spacing keys off this size (the rem-based tokens below
     resolve against the root font size, which is set to --type), so growing the
     type here grows the layout in step with it, all in the same proportion. The
     middle term carries the growth (a small fixed base plus a share of the
     viewport width); the floor keeps the type comfortably legible on the
     narrowest phone and the ceiling keeps it quiet and minimal on a wide
     desktop, so it eases smoothly between the two rather than sitting at one
     fixed size. */
  --type: clamp(1.05rem, 0.7rem + 1.35vw, 1.55rem);
  /* the single type weight for the whole site. Every word on every page is set
     at exactly this weight — there is no bold or light tier anywhere. It is the
     weight the disc text reads at, kept light so the type sits quiet and airy on
     a phone and on a wide desktop alike.
     Eased back down a step (560 -> 480) to lighten the whole site's voice — the
     words read thinner and calmer everywhere while staying a single, uniform
     weight across every surface. The lead lines that sit a step bolder than this
     stepped down with it (700 -> 620), so the one-step contrast is unchanged. */
  --weight: 480;
  /* the single softening for every quiet voice on the site. Secondary lines —
     intro copy, legends, the in-disc hints and the stepper captions — are all
     dimmed by exactly this one amount rather than each page picking its own, so
     the contrast between primary and quiet type is identical everywhere. */
  --quiet: 0.8;

  /* One pace and one easing for the move between pages, named once here so every
     part of a navigation — the whole-page dissolve, the corner mark holding its
     place, the disc field gliding from one page's layout to the next — runs at
     exactly the same speed and curve. The span is the same 0.4s as the --swap
     state-change pace below, and the ease-in-out matches the rest of the site's
     motion, so a page change reads in the same voice as everything else. */
  --page-fade: 0.4s;
  --page-ease: ease-in-out;

  /* One pace and easing for every quiet state change inside a page — a disc
     circle swapping colour, a control or caption easing in or out, a wash fading
     up and back. Named once here so the small fades scattered across the app
     all run at exactly the same speed and curve instead of each page picking its
     own near-but-not-equal value (the colour swaps, control fades and washes
     were a spread of 0.35s / 0.45s / 0.5s before this drew them together). It
     sits at the same 0.4s as the page fade above, so a control settling and a
     page turning read at one pace, and the whole site changes state in a single
     voice. */
  --swap: 0.4s;
  --swap-ease: ease;

  /* One pace for every line of text that fades in for the reader to take in — the
     two instruction lines assembling on the bag page, the loading word on the
     home page, the way-out line in the danger zone, and the quiet reveals (the
     "what does my bag say about me" passage and the "left your bag in the car"
     line). Named once here and tuned not to the brisk UI pace above but to the
     beat it takes a reader to actually read a short line, so each line settles in
     just as the eye finishes it rather than snapping in ahead of comprehension.
     It is deliberately slower than the --swap/--page-fade UI pace (0.4s) and
     draws the scattered reveal timings (0.4s here, 0.7s there) onto one value, so
     every line the reader reads arrives at the same, reading-paced beat. */
  --reveal: 0.7s;
  --reveal-ease: ease-in-out;

  /* One pace for immediate press feedback — a stepper button or disc cell
     dipping under a finger. Deliberately quick and tactile, a single short value
     in place of the slightly different press timings the two app pages each
     carried (0.08s / 0.12s), so every press across the site answers in step. */
  --tap: 0.1s;

  /* One fluid spacing scale for the whole site. Every buffer — page gutters,
     the vertical rhythm between blocks, and the headroom that clears the fixed
     corner logo — is drawn from these tokens, so the whitespace stays in the
     same proportion to the type and to the viewport from a narrow phone all the
     way out to a wide desktop. No page invents its own fixed paddings. The
     rungs run small -> grid -> block, each a step of the same fluid family, so
     every gap on every page is one of these three sizes and nothing else. */

  /* side padding on every page */
  --gutter: clamp(1.25rem, 4vw, 2.5rem);
  /* the smallest rung: gaps inside a single component (a disc and its name,
     a stepper's caption and arrows) */
  --gap-sm: clamp(0.6rem, 2vw, 0.9rem);
  /* the middle rung: the gap between discs in every three-by-three grid */
  --gap: clamp(0.9rem, 3vw, 1.6rem);
  /* the largest rung: vertical rhythm between stacked blocks */
  --space: clamp(1.6rem, 4.5vw, 2.6rem);
  /* top headroom: always tall enough to clear the fixed corner logo
     (which itself scales up to ~94px) and the centred back arrow, and to
     keep a clear, even buffer (~1.25–1.7rem at every width) between the bottom
     of the logo and the first element below it, so content never crowds the
     mark. */
  --top-gap: clamp(7.5rem, 18vw, 10.5rem);
  /* matching breathing room at the foot of the page, mirroring the headroom that
     clears the corner logo and back arrow up top, so page content eases into the
     bottom edge fade rather than crowding it. */
  --bottom-gap: clamp(5rem, 11vw, 7.5rem);
}

*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html,
body {
  width: 100%;
  min-height: 100%;
  color: var(--ink);
  font-family: var(--font);
  font-size: var(--type);
  font-weight: var(--weight);
  line-height: 1.4;
  /* keep mobile browsers from inflating our deliberately small type */
  -webkit-text-size-adjust: 100%;
  /* nothing on the site is meant to scroll sideways: every page is a single
     centred column at every width. but a few marks are allowed to spill past
     their own box on purpose — a fast disc's needle breaks past its ring on the
     bag page, the putt figure floats off the left edge on the chat page — and a
     fit-line caught mid-resize can momentarily run long. clip any such sideways
     spill at the viewport edge so it can never raise a stray horizontal
     scrollbar on a narrow phone, while leaving vertical scrolling untouched.
     `clip` is used where supported (it clips without creating a scroll
     container, so the page's normal vertical scroll is unaffected); `hidden` is
     the fallback for older browsers. */
  overflow-x: hidden;
  overflow-x: clip;
}

/* The white field lives on the root element so the body can stay transparent,
   letting the faint tracer canvas (tracers.js) show through behind the type. */
html {
  background: #ffffff;
}

a {
  color: var(--ink);
}

/* Smooth the move between pages. Every page on the site loads this file, so
   opting into cross-document view transitions here makes every navigation —
   the home wordmark into the app, the back chevrons, the crossing into "add
   slots" — flow from one page to the next instead of cutting hard. The browser
   snapshots the old page and the new one and animates between them; nothing is
   added to any page's markup.

   Two things are lifted out of the whole-page dissolve and given their own names
   so they carry through a navigation as single, continuous objects rather than
   each fading out and back in on its own (set in home-logo.js and on each page's
   field):
     • `site-mark`  — the fixed corner logo, identical and in the same spot on
                      every page, so naming it holds it dead still while the rest
                      of the page changes around it.
     • `disc-field` — the central disc-circle cluster shared by the three pages
                      built around it: the home matrix, the app's nine-slot bag
                      and the add-slots rings. Naming it the same on all three
                      lets the field glide and reshape from one layout into the
                      next, tying the three pages' motion together. */
@view-transition {
  navigation: auto;
}

/* Hold the whole navigation — the page dissolve, the mark holding its place and
   the disc field's glide between layouts — to the one shared pace and easing, so
   every part of the swap moves in step and reads in the site's single motion
   voice. The group pseudo carries the position/size glide; the old/new pseudos
   carry the cross-fade. Both draw from the same tokens. */
::view-transition-group(*),
::view-transition-old(*),
::view-transition-new(*) {
  animation-duration: var(--page-fade);
  animation-timing-function: var(--page-ease);
}

/* Honour a reader's request for stillness: skip every part of the transition —
   the dissolve and the named-element glide alike — and let pages swap instantly,
   matching every other animation on the site, which all bail out under the same
   preference. */
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
}

/* A line asked to stay on one line. The fit-text helper (fit-text.js) measures
   each of these and, only when it would otherwise wrap, eases the type down and
   compresses it horizontally until it fits. The nowrap here states that intent
   declaratively so the line never flashes wrapped before the script runs. */
.fit-line {
  white-space: nowrap;
}

/* The shared "back" chevron, centred at the top of every interior page. As a
   navigation control it sits on the same line as the fixed corner logo
   (home-logo.js, ~64–94px tall), so it is sized up from the body type to a
   fluid scale that reads in proportion to that mark rather than as a stray body
   character. Its offset is fluid and tuned to keep it aligned with the logo.
   Trimmed back a step alongside the logo so the top controls sit lighter and
   leave more open field around them. */
.back-arrow {
  position: fixed;
  top: clamp(1rem, 3vw, 1.8rem);
  /* on a notched phone the status-bar / rounded corner eats into the top of the
     viewport, so add the safe-area inset to the offset. the plain clamp above is
     the fallback for browsers that don't understand env(); they simply ignore
     this second declaration. */
  top: calc(clamp(1rem, 3vw, 1.8rem) + env(safe-area-inset-top, 0px));
  left: 50%;
  transform: translateX(-50%);
  color: var(--ink);
  text-decoration: none;
  font-size: clamp(2.2rem, 5vw, 3.2rem);
  line-height: 1;
  padding: 0.4em 0.6em;
  z-index: 10; /* stay above the edge fades, like the fixed corner controls */
}
.back-arrow:hover {
  opacity: 0.7;
}

/* Site-wide edge fade: two fixed white veils, one at the top of the viewport and
   one at the bottom, each a gradient from solid white at the screen edge to fully
   transparent inward. Page content scrolls beneath them, so it dissolves softly
   into the white field as it nears either scrolling edge instead of hitting a
   hard cut — the buffer can never run out, the content just fades away at the
   bottom (and eases in at the top). The veils never take pointer events, and sit
   above the page content but below the fixed corner controls and back arrow
   (z-index 10), so those stay crisp. Their height stays within the page's top and
   bottom buffers so centred pages are untouched. */
body::before,
body::after {
  content: "";
  position: fixed;
  left: 0;
  right: 0;
  z-index: 5;
  pointer-events: none;
}
body::before {
  top: 0;
  height: clamp(3rem, 7vh, 5rem);
  background: linear-gradient(to bottom, #ffffff 0%, rgba(255, 255, 255, 0) 100%);
}
body::after {
  bottom: 0;
  height: clamp(3.5rem, 9vh, 6rem);
  background: linear-gradient(to top, #ffffff 0%, rgba(255, 255, 255, 0) 100%);
}
