/* ==========================================================================
   LODESTONE — pre-launch holding page
   Sources: Websites/lodestone-brand-guidelines.pdf, brand-board.png,
            packaging-board.png, lodestone-mark.svg

   The brand's design philosophy is "Quiet Instrument": the aesthetic of the
   calibration laboratory, not the trading-card shop. Vast, even fields of
   near-black; the few elements permitted to exist placed with the finality of
   a fixture bolted to an optical bench. Nothing decorates. Whatever appears,
   measures.

   Four rules are absolute here and are enforced at build time by
   tools/brand-check.py, not merely remembered:
     · no gradients
     · no shadows
     · no blurs
     · Assay Gold (#B8945A) is a physical finish — foil and deboss — and never
       appears on screen
   ========================================================================== */

/* --- Type ---------------------------------------------------------------
   Both families are self-hosted rather than linked from Google's CDN. That
   is what lets the Content-Security-Policy in dist/_headers stay at
   `style-src 'self'; font-src 'self'` with no third-party origins at all,
   and it means the page renders identically with no network beyond this
   folder. Latin subsets only; ~40 KB for the pair.

   Instrument Sans ships as one variable file covering 400–600, so a single
   request serves both the wordmark (400) and any medium weight. Licences
   travel with the files in fonts/OFL-*.txt, as the SIL OFL requires.
   ------------------------------------------------------------------------ */

@font-face {
  font-family: "Instrument Sans";
  src: url("../fonts/instrument-sans-latin-var.woff2") format("woff2");
  font-weight: 400 600;
  font-style: normal;
  font-display: swap;
  /* Present deliberately: with it, a character outside latin falls back to a
     system face. Without it the browser would claim every codepoint for this
     file and render tofu instead. */
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Geist Mono";
  src: url("../fonts/geist-mono-latin-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ==========================================================================
   Tokens
   ========================================================================== */

:root {
  /* --- Palette ----------------------------------------------------------
     Obsidian is the ground state. Cardstock is the specimen. Graphite is
     secondary text and hairlines. Those three are the entire screen palette.

     TRUE NORTH (#D8412F) IS ABSENT FROM THIS FILE ON PURPOSE, and the absence
     is the design. The brand allows exactly one red point per composition —
     "the verified point, the needle's tip" — and on this page that point is
     the north dot inside the mark, which lives in mark.svg. Because the only
     red is inside the mark, the stylesheet has no red in it at all, and a
     second red point cannot be introduced by editing CSS alone.

     Measured against the Obsidian ground (WCAG 2.x relative luminance):
       Cardstock  #F2EFE7  16.96:1
       Ink-2      #9AA0A8   7.39:1
       Graphite   #7A808A   4.90:1  — the floor; AA normal text is 4.5:1
       True North #D8412F   4.38:1  — FAILS AA for text. Graphic use only,
                                      which is all the mark ever makes of it.
     -------------------------------------------------------------------- */
  --obsidian: #0B0D10;
  --cardstock: #F2EFE7;
  --ink-2: #9AA0A8;
  --graphite: #7A808A;

  /* Neutral steps on the Obsidian–Cardstock axis. Never a new hue.
     1.36:1 — deliberately at the edge of perception, matching the register of
     the hairlines and leader lines on the concept boards. Decorative only:
     nothing a reader must perceive is carried by these. */
  --hairline: #23272C;

  /* --- Rhythm -----------------------------------------------------------
     One base unit, 8px. Every vertical measure in the layout is a multiple of
     it, or a clamp between two multiples. The few numbers that are not — an
     underline's 2px offset, the mark-derived ratios — are optical corrections
     rather than rhythm, and each says so where it is used.
     -------------------------------------------------------------------- */
  --u: 8px;

  /* The rendered edge length of the mark's square viewBox. Several other
     measures are derived from it, so it exists as a token rather than as a
     number repeated in three places.

     The ceiling was set by rendering the page at 112 / 152 / 192 / 232px and
     looking at all four. Below ~150px the mark reads as a favicon parked above
     a wordmark and the red north dot disappears entirely; above ~230px it
     stops being the instrument in the field and becomes the field. At 208 the
     mark's artwork is a third of the wordmark's width, the dot registers as
     the one point in the composition, and the lockup still reads as one object
     rather than two stacked ones.

     vmin, not vw: on a short landscape window the constraint is height, and a
     mark scaled off width alone would push the statement off the bottom. The
     96px floor is comfortably above the brand's 24px / 8mm minimum. */
  --mark: clamp(96px, 20vmin, 208px);

  /* Inside the 720-unit viewBox the card is 228.6 wide and 320 tall, so at any
     rendered size the card measures 0.3175 x --mark across and 0.4444 down.
     The rule beneath the wordmark is exactly two card widths — the same
     proportion the rule holds on brand-board.png, arrived at from the mark's
     own construction rather than by eye. */
  --card-w: calc(var(--mark) * 0.3175);
  --rule-w: calc(var(--card-w) * 2);
}

/* ==========================================================================
   Reset — only what this page actually needs
   ========================================================================== */

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

body,
h1,
p,
dl,
dd {
  margin: 0;
}

img,
svg {
  display: block;
  max-width: 100%;
}

/* ==========================================================================
   Page
   ========================================================================== */

html {
  /* Tells the UA to paint scrollbars, form controls and the overscroll gutter
     dark. Without it the overscroll area flashes white on iOS against a page
     that is otherwise entirely Obsidian. */
  color-scheme: dark;
  -webkit-text-size-adjust: 100%;
}

body {
  background: var(--obsidian);
  color: var(--cardstock);
  font-family: "Instrument Sans", -apple-system, BlinkMacSystemFont, "Segoe UI",
    Helvetica, Arial, sans-serif;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* The one thing that must never happen on a composition built out of
     centred axes and tracked capitals. */
  overflow-x: hidden;
}

::selection {
  background: var(--cardstock);
  color: var(--obsidian);
}

/* The sheet: a running head, a plate, a colophon. The proportions are a
   report's, because the brand reads typography the way a report is read.

   100svh rather than 100vh: on mobile Safari, 100vh is the *largest* viewport
   height, so a page sized to it sits partly under the retracted toolbar on
   first paint and the footer is cut off. svh is the smallest, which is the
   one that is always actually visible. */
.sheet {
  min-height: 100svh;
  display: grid;
  grid-template-rows: auto 1fr auto;
  /* Height-aware, not width-aware. The composition is a vertical stack, so the
     dimension that decides whether it fits on one screen is the short one. A
     1366x768 laptop leaves roughly 650px of viewport once browser chrome is
     subtracted, and every vertical measure below is clamped so the whole sheet
     still lands inside that without scrolling. Verified at nine viewports. */
  gap: clamp(calc(var(--u) * 3), 4vh, calc(var(--u) * 5));
  padding-block: clamp(calc(var(--u) * 3), 3.5vh, calc(var(--u) * 6));
  /* max() against the safe-area insets keeps the rails clear of a notch or a
     home indicator in landscape, without letting a device with no inset at all
     fall below the 24px floor. */
  padding-left: max(clamp(calc(var(--u) * 3), 4vw, calc(var(--u) * 6)), env(safe-area-inset-left));
  padding-right: max(clamp(calc(var(--u) * 3), 4vw, calc(var(--u) * 6)), env(safe-area-inset-right));
}

/* ==========================================================================
   Rails — the running head and the colophon

   Small, tracked, monospace, pinned to the margins. This is the grammar of
   both concept boards: the sheet names itself in the top corner and reports
   its data along the bottom, and the whole middle is left alone.
   "A monospace records when measuring."

   Each rail holds a single element, so neither is a flex container — .meta
   below does the only wrapping that happens down here.
   ========================================================================== */

.rail--bottom {
  border-top: 1px solid var(--hairline);
  padding-top: calc(var(--u) * 2.5);
}

.micro {
  font-family: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, Consolas,
    monospace;
  /* 11px. Text is sparse, set small, and always earns its place. */
  font-size: 0.6875rem;
  line-height: 1.45;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--graphite);
}

/* Label/value pairs in the colophon. A description list because that is what
   this is — the same STATUS/VALUE grammar the boards use for their finishes
   and specification rows. */
.meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--u) calc(var(--u) * 3);
}

.meta__pair {
  display: flex;
  gap: calc(var(--u) * 1.5);
}

.meta dt {
  /* The value is the thing being reported; the label only names it. Half a
     step down in luminance separates them without introducing a colour. */
  color: var(--graphite);
}

.meta dd {
  color: var(--ink-2);
}

.link {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid var(--hairline);
  padding-bottom: 2px;
}

.link:hover {
  color: var(--cardstock);
  border-bottom-color: var(--graphite);
}

/* An outline, not a ring — rings are drawn with shadows, and this brand has
   none. Offset so it clears the tracked capitals it surrounds. */
.link:focus-visible {
  outline: 1px solid var(--cardstock);
  outline-offset: 4px;
  border-bottom-color: transparent;
}

/* ==========================================================================
   Plate — the lockup, centred on one axis

   Everything here sits on a single vertical line and nothing sits off it.
   Alignment is the whole design: the plate should read as a plumb line.
   ========================================================================== */

.plate {
  display: grid;
  align-content: center;
  justify-items: center;
  text-align: center;
  /* Optical, not geometric, centring. A block centred by arithmetic reads as
     having sunk. Reserving space at the foot makes the block centre inside
     what is left, which lifts it by half the padding — about 2% of the
     viewport here — and that is where the eye expects the centre to be.

     A padding rather than a transform, so it adds to the sheet's height
     instead of sliding content out of it on a short screen. */
  padding-bottom: clamp(calc(var(--u) * 2), 4vh, calc(var(--u) * 7));
}

.lockup {
  display: grid;
  justify-items: center;
  /* Font-weight 400 on the wordmark, per the guidelines. h1 defaults to bold,
     and a bold LODESTONE is a different mark. */
  font-weight: 400;
}

.lockup__mark {
  width: var(--mark);
  height: var(--mark);
  /* CLEARSPACE MATH. The brand requires >= 0.5 x card height clear on every
     side. Card height is 320/720 of the viewBox, so the requirement is
     0.2222 x --mark. The artwork already carries empty box around it inside
     the SVG — 0.139 x --mark below, 0.164 above, 0.158 either side — so the
     CSS only has to supply the shortfall, which is largest at the bottom:
     0.0832 x --mark, or 17.3px at the 208px ceiling.

     The gap is set to 0.25 x --mark, three times that floor, because the
     clearspace rule is a minimum and the composition wants the air. Being a
     ratio, it holds at every size the clamp produces. */
  margin-bottom: calc(var(--mark) * 0.25);
}

.lockup__word {
  /* Tracking ~ +400 in the guidelines' units, i.e. 0.4em. */
  letter-spacing: 0.4em;
  text-transform: uppercase;
  font-size: clamp(1.5rem, 5.2vw, 2.75rem);
  line-height: 1;
  color: var(--cardstock);

  /* Letter-spacing is applied after the final N as well as between letters, so
     a centred wordmark sits 0.2em to the left of where it looks like it
     should. Making the element shrink-to-fit and then pulling 0.4em off its
     right edge removes that trailing space from layout, which lands the ink —
     not the box — on the page's axis. Sloppy kerning would be a falsified
     reading. */
  display: inline-block;
  margin-right: -0.4em;
}

/* Two card widths, taken from the mark's own construction — not chosen by eye.
   Drawn as a border on the <hr> rather than as a background, so it is one
   hairline at any device pixel ratio instead of a box that can round to two. */
.rule {
  width: var(--rule-w);
  height: 0;
  border: 0;
  border-top: 1px solid var(--graphite);
  margin: clamp(calc(var(--u) * 2), 3vh, calc(var(--u) * 4)) 0;
}

.tagline {
  font-family: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, Consolas,
    monospace;
  font-size: clamp(0.6875rem, 1.6vw, 0.8125rem);
  letter-spacing: 0.34em;
  text-transform: uppercase;
  line-height: 1.4;
  color: var(--ink-2);
  /* Same trailing-space correction as the wordmark, at this tracking. */
  display: inline-block;
  margin-right: -0.34em;
}

/* Four sentences, four lines, one per beat — read as instrument labels rather
   than as prose. Set small and in Graphite so the block reads as a
   specification caption and never as a manifesto. The brand states; the data
   persuades. */
.statement {
  margin-top: clamp(calc(var(--u) * 3), 5vh, calc(var(--u) * 7));
  font-size: clamp(0.875rem, 1.9vw, 1.0625rem);
  /* Loose, because these are four separated readings rather than a paragraph
     and the white space between them is what stops the block reading as verse.
     Tightened on short viewports, where the leading is the cheapest thing to
     give back. */
  line-height: 1.95;
  letter-spacing: 0.005em;
  color: var(--graphite);
  /* The line breaks in the markup are the composition, so this measure is only
     a backstop for the case where a reader's minimum font size overrides the
     clamp. The longest line is 41 characters; at the 14px floor it still
     clears the content width at 320px, verified in the browser rather than
     assumed. */
  max-width: 40ch;
  text-wrap: pretty;
}

/* ==========================================================================
   Short viewports

   The vertical clamps above carry most of this on their own. What they cannot
   quite reach is a 1366x768 laptop, whose viewport is around 650px once
   browser chrome is subtracted: the last few dozen pixels come from here.

   The order is deliberate — leading first, then the optical lift — because
   those are the two things whose loss is least visible. The mark, the wordmark
   and the gaps between the three text blocks are never touched, so the
   composition on a short screen is the same composition, just breathing less.
   With both applied the page fits without scrolling down to 1280x560.
   ========================================================================== */

@media (max-height: 720px) {
  /* Leading first: it is the largest single block of vertical space in the
     plate and the least missed. */
  .statement {
    line-height: 1.7;
  }

  /* The optical lift is a luxury, and on a short screen the alternative to
     giving it up is a scrollbar on a one-screen page. */
  .plate {
    padding-bottom: 0;
  }
}

/* ==========================================================================
   Large displays

   Every clamp above bottoms out at its ceiling somewhere around a 1500px
   viewport, which is correct up to about a 27-inch display and then stops
   being correct: past that the lockup reads as a small object pinned to a very
   large wall rather than as an instrument sitting in a field. One step up for
   the mark and the wordmark together restores the proportion between them —
   the mark's artwork stays at a third of the wordmark's width either way —
   and nothing on a laptop is touched, because the query cannot match there.

   Gated on height as well as width so an ultra-wide but short window, where
   vertical space is the scarce thing, keeps the smaller lockup.
   ========================================================================== */

@media (min-width: 1800px) and (min-height: 1000px) {
  :root {
    --mark: clamp(208px, 20vmin, 288px);
  }

  .lockup__word {
    font-size: clamp(2.75rem, 4vmin, 3.5rem);
  }
}

/* ==========================================================================
   Preferences
   ========================================================================== */

/* Every text pair already clears AA against the Obsidian ground, with Graphite
   at 4.90:1 sitting closest to the 4.5:1 floor. A reader who has asked the OS
   for more contrast gets each tier promoted one step up the same neutral axis —
   no new hue is introduced, so the composition is unchanged and only the
   separation grows. */
@media (prefers-contrast: more) {
  :root {
    --graphite: #9AA0A8; /*  7.39:1 */
    --ink-2: #C8CCD1;    /* 11.35:1 */
    --hairline: #4A4F56;
  }
}

/* Nothing on this page moves — the brand's own words are "a measuring device
   at rest" — so there is no motion to reduce and no prefers-reduced-motion
   block below. The absence is deliberate, not an omission. */

/* A dark-ground page whose background the printer drops prints as Cardstock
   text on white paper: invisible. Asking for the ground to be printed is the
   only correct answer here, because the alternative — inverting for print —
   would turn the one True-North point cyan. */
@media print {
  body {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
}
