/* Type. Söhne Buch and Kräftig, self-hosted. font-display: block, so the statement never flashes in a fallback face;
   the files are small and preloaded from index.html. Below them, a metric-matched fallback: Helvetica Neue with
   size-adjust and ascent/descent overrides computed from the two fonts' metrics against the actual copy, so if the
   web fonts ever fail the line breaks, leading, and capsule heights stay where they are. */
@font-face { font-family: "Söhne"; src: url("/fonts/soehne-buch.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: block; }
@font-face { font-family: "Söhne"; src: url("/fonts/soehne-kraftig.woff2") format("woff2"); font-weight: 500; font-style: normal; font-display: block; }
@font-face { font-family: "Söhne Mono"; src: url("/fonts/soehne-mono-buch.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: block; }
@font-face {
  font-family: "Söhne Fallback";
  src: local("Helvetica Neue"), local("HelveticaNeue");
  size-adjust: 98.46%;
  ascent-override: 118.94%;
  descent-override: 42.96%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Söhne Fallback";
  font-weight: 500;
  src: local("Helvetica Neue Medium"), local("HelveticaNeue-Medium");
  size-adjust: 95.89%;
  ascent-override: 122.13%;
  descent-override: 44.12%;
  line-gap-override: 0%;
}

:root {
  color-scheme: light;
  --ink: #000;
  /* The Siri sidebar card is Liquid Glass (glassEffect .regular) over a #F2F2F2 pane. Values below come from the
     app's own layer tree, dumped with lldb in a VM (../siri-card-measurements.md). The pane is the page. */
  --paper: #fafafa;
  --card-ink: #000;
  --card-muted: #808080;
  /* Sized to the window, as on lovefrom.com. Not rounded: a whole-pixel step would make a live resize tick.
     Everything else on the page is a ratio of the heading size, so the whole composition scales together. */
  /* one device pixel, for snapping the capsule's geometry; set per screen density below */
  --dp: 1px;
  /* The page margin is the width of "Yap" in the heading (its ink, Y's left edge to p's right, in Söhne Buch with
     the kerning). The heading is 5% of the viewport width, held under 8% of its height, floored at 28px,
     capped at 120px: 72px at 1440 wide. Inside the margins that breaks the sentence into three balanced lines; the
     space is there, so the type uses it. */
  --margin-em: 1.616; /* "Yap"; "YAP" was 1.842, "yap" 1.555 */
  --h1-size: clamp(28px, min(5vw, 8vh), 120px);
  --margin: calc(var(--h1-size) * var(--margin-em));
  --measure: calc(var(--h1-size) * 700 / 36);
  --h1-lh: calc(var(--h1-size) * 4 / 3);
  --stem: calc(var(--h1-size) * 0.09); /* Söhne Buch's 'l' stem, 90/1000 em; the page's one stroke width */
  /* The pills sit where the heading's next line would, with the capsule's top stroke as that line's first ink: its
     outer edge is on the phantom line's x-height line, so the whitespace above the pills equals the whitespace
     between heading lines measured to the lowercase (a continuous rule reads heavier than a row of cap tops, so the
     x-height is the optical match rather than the cap line). In a line box of height L for Söhne at size F (ascent
     1.171em, descent 0.423em, no line gap) the baseline is L/2 + 0.374 F below the box top and the x-height is
     0.523 F above it, so the x line is L/2 - 0.149 F below the heading's bottom edge. */
  --nav-gap-y: calc(var(--h1-lh) / 2 - 0.149 * var(--h1-size));
  --pill-h: round(max(var(--h1-lh), 44px), var(--dp)); /* one heading line, never under the 44px touch target, snapped to a device pixel so the top and bottom strokes get the same antialiasing */
  --btn-pad-x: 1em; /* the label's own size, resolved on .pill */
  --btn-gap: calc(var(--h1-size) / 3);
}

@media (min-resolution: 1.5dppx) { :root { --dp: 0.5px; } }
@media (min-resolution: 2.5dppx) { :root { --dp: calc(1px / 3); } }

* { box-sizing: border-box; }

html, body { height: 100%; margin: 0; background: var(--paper); }

html {
  /* Typesetting defaults for the whole page.
     kerning and the font's own ligatures and contextual alternates on, explicitly (optimizeLegibility keeps older
     WebKit honest about them); no synthesised bold, italic or small caps, ever; no automatic text inflation on
     phones; greyscale antialiasing on both macOS engines so the stems read at their drawn weight rather than the
     heavier subpixel rendering. Söhne's stylistic sets (ss01 single-storey a, ss02 alternate g) stay off: the
     default forms are the ones Klim set the face's rhythm around. */
  font-family: "Söhne", "Söhne Fallback", "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-kerning: normal;
  font-variant-ligatures: common-ligatures contextual;
  font-feature-settings: "kern", "liga", "calt";
  font-optical-sizing: auto;
  font-synthesis: none;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  hyphens: manual;
  overflow-wrap: normal;
}

body {
  color: var(--ink);
  background: var(--paper);
  display: grid;
  place-items: center;
  padding: var(--margin); /* the width of "YAP" at the current size */
}

main {
  width: 100%;
  max-width: var(--measure);
  text-align: center;
}

/* The statement, centred, balanced. Buch weight, at the fitting Klim
   drew: no tracking anywhere on the page. The full stop hangs outside the measure so the last line's right edge is
   the letters, not the punctuation. Non-breaking spaces in the markup hold the last three words together. */
h1 {
  margin: 0;
  font-size: var(--h1-size);
  line-height: var(--h1-lh);
  font-weight: 400;
  text-wrap: balance;
  hanging-punctuation: first last;
  -webkit-hyphens: none;
  hyphens: none;
}

/* The text of llms.txt, for an AI that opens the page: assistants read the body and nothing else (not meta tags, not
   comments, not text a script adds). It is moved off screen rather than hidden, because display:none, the hidden
   attribute, and aria-hidden each drop it from at least one common text extractor, and a closed <details> drops it
   from readers that render the page. The offset is YAP's address, 4962 El Camino Real, Los Altos (37.3975° N,
   122.1068° W), at 10,000px to the degree, with up as north and left as west. Negative offsets add no scrolling. */
.ai {
  position: absolute;
  top: -373975px;    /* 37.3975° N */
  left: -1221068px;  /* 122.1068° W */
}

nav {
  margin-top: var(--nav-gap-y);
  display: flex;
  justify-content: center;
  gap: var(--btn-gap);
  flex-wrap: wrap;
  font-size: 16px;
}

/* Outline capsule. Stroke matches the display type: Söhne Buch's vertical stem ('l') is 90/1000 em, so at the 60px
   heading it is 5.4px, and the Kräftig labels are sized so their stems match it too (see font-size). Press and
   release are scripted in pill.js, after the (i) button on lovefrom.com: no hover state, a spring to 0.95 on
   pointerdown, back to 1 on release. The glass version is saved in ../liquid-glass-pill.css. */
.pill {
  --stroke: round(var(--stem), var(--dp)); /* the stem, to the nearest device pixel */
  appearance: none;
  box-sizing: border-box;
  margin: 0;
  /* Vertical optical centre for sentence-case labels. Söhne Buch at line-height 1 puts the baseline 0.874em down the
     box (ascent 1171, descent 423, 1000 upm); cap height is 0.718em and x-height 0.523em, so the cap midpoint sits
     0.515em down and the x-height midpoint 0.613em down. The eye reads a mixed-case word somewhere between the two, so
     the target is their mean, 0.564em; a 0.128em bottom pad under align-items:center lifts the box by half that and
     puts it on the capsule's centre line. Descenders are ignored on purpose. */
  /* Tracking solved so the space between letters is the same number of pixels as in the heading. Mean gap between
     adjacent letters (sidebearings plus kerning, over the actual words): heading, Buch at 72px, 0.0811em = 5.84px;
     labels, Kräftig at 54px, 0.0681em = 3.67px. The difference, 2.163px, is 0.03005 of the heading size, so it
     scales with everything else. The right pad gives back the trailing track so the label stays centred. */
  --track: calc(var(--h1-size) * 0.03005);
  letter-spacing: var(--track);
  height: var(--pill-h);
  padding: 0 calc(var(--btn-pad-x) - var(--track)) 0.128em var(--btn-pad-x);
  display: inline-flex;
  align-items: center;
  /* the outline is drawn by ::after, an inset shadow on an overlay: borders snap to whole device pixels, a shadow
     keeps the fractional width the stem has; and as an overlay it stays above the label, so a word rolling out of
     the capsule passes under the line rather than over it */
  border: 0;
  border-radius: 999px;
  /* A true capsule: the ends are semicircles, radius half the height. corner-shape: round is the default and says so
     explicitly; a superellipse here (tried at 1.32, the Siri card's exponent) flattens the ends into a rounded
     rectangle, which is a different object. */
  corner-shape: round;
  color: var(--ink);
  background: none;
  font: inherit;
  /* Size solved so the label's stem equals the heading's: Kräftig's stem is 0.12em, Buch's 0.09em, so the label is
     0.75 of the heading (45px at 60) and both stems, and the outline, are the same width. */
  font-size: calc(var(--h1-size) * 0.75);
  font-weight: 500; /* Söhne Kräftig, the real cut; never synthesised */
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  /* as on lovefrom: default cursor, no tap flash */
  cursor: default;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  /* own compositor layer, so the press scale is done on the rasterised layer and the glyphs are not re-hinted
     every frame (that re-hinting is the sub-pixel crawl). pill.js writes transform inline, so translateZ(0) alone
     would be overwritten; will-change holds the layer. */
  will-change: transform;
  backface-visibility: hidden;
  position: relative; /* pill.js nudges top/left by under a device pixel to snap the box to the pixel grid */
  -webkit-user-select: none;
  user-select: none;
  /* a link is draggable by default; a press that wanders would lift it out as a drag image */
  -webkit-user-drag: none;
  -webkit-touch-callout: none;
}

.pill::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: inset 0 0 0 var(--stroke) var(--ink);
  pointer-events: none;
}
.pill:focus-visible { outline: var(--stem) solid var(--ink); outline-offset: var(--stem); }

/* "Ask an AI" (ask.js): the two labels sit on a drum that ask.js rolls, so one word rolls up and out of focus as the
   other rolls up into place. The capsule's width is locked by ask.js so the roll is the only thing that moves. Perspective sits close, like a fast lens near the subject; ask.js adds the shallow
   depth of field, blurring and fading each face as it leaves the focal plane. */
button.pill {
  justify-content: center;
  overflow: hidden; /* the hard backstop; the visible edge is the painted fade below */
  /* the fade bands: from the capsule's edge (solid paper) to just past the label's line box (clear), top and
     bottom. The label sits 0.064em low for optical centring, and the clear zone reaches 0.12em past the line box
     so descenders stay whole. */
  --fade-top: calc((var(--pill-h) - 1em) / 2 + 0.064em - 0.12em);
  --fade-bottom: calc((var(--pill-h) - 1em) / 2 - 0.064em - 0.12em);
}
/* The receding is painted, not masked: the outline overlay also carries two gradients in the paper colour, solid at
   the capsule's edge and clear at the label, above the words. On an opaque page that is indistinguishable from a
   gradient mask, and unlike a mask it is honoured on every frame of a composited 3D layer in Safari. */
button.pill::after {
  background:
    linear-gradient(to bottom, var(--paper), transparent var(--fade-top)),
    linear-gradient(to top, var(--paper), transparent var(--fade-bottom));
}
/* the lens: holds the perspective. No mask: ask.js fades and blurs each word by its focus, and a gradient mask on a
   composited 3D subtree in Safari is applied in the wrong place while the drum moves, which clipped descenders
   and dropped the arriving word low. */
.lens {
  display: grid;
  perspective: 3em; /* a close lens: the tilt shows as keystone, the near edge of a word wider than the far */
}
/* the drum: both words on a cylinder of radius --r, a quarter turn apart; ask.js sets each word's transform in full */
.flip {
  --r: 0.9em;
  display: grid;
}
.flip .face {
  grid-area: 1 / 1;
  justify-self: center;
  white-space: nowrap;
  backface-visibility: hidden;
  will-change: transform, opacity, filter;
  /* the box reaches past the line box, so descenders are inside it: WebKit clips a filtered 3D layer to its box, and
     at line-height 1 the tail of the p hangs 0.065em below, which cut it off while the word was in motion */
  padding: 0.25em 0.3em;
  margin: -0.25em -0.3em;
}
