/* site.css — shared tokens and base styles for latent.actor
   Linked by index.html, apps/index.html, privacy.html.
   The app detail pages under /apps/{stickscore,shrimproll}/ use a
   separate design and deliberately do not link this file. */

:root {
  --bg: #16122e;
  --fg: #f5f5f5;
  --fg-85: rgba(245, 245, 245, 0.85);
  --fg-75: rgba(245, 245, 245, 0.75);
  --fg-70: rgba(245, 245, 245, 0.7);
  --fg-65: rgba(245, 245, 245, 0.65);
  --fg-55: rgba(245, 245, 245, 0.55);

  --font-display: "Workbench", system-ui, sans-serif;
  --font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    Helvetica, Arial, sans-serif;

  --squircle-mask: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%20230.5%20230.5%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M158.2%20230H64.1a320%20320%200%200%201-7-.1c-5%200-10-.5-15-1.3a50.8%2050.8%200%200%201-14.4-4.8%2048.2%2048.2%200%200%201-21-21%2050.9%2050.9%200%200%201-4.8-14.4%20100.7%20100.7%200%200%201-1.3-15v-7l-.1-8.2V64.1a320%20320%200%200%201%20.1-7c0-5%20.5-10%201.3-15a50.7%2050.7%200%200%201%204.8-14.4%2048.2%2048.2%200%200%201%2021-21%2051%2051%200%200%201%2014.4-4.8c5-.8%2010-1.2%2015-1.3a320%20320%200%200%201%207%200l8.2-.1h94.1a320%20320%200%200%201%207%20.1c5%200%2010%20.5%2015%201.3a52%2052%200%200%201%2014.4%204.8%2048.2%2048.2%200%200%201%2021%2021%2050.9%2050.9%200%200%201%204.8%2014.4c.8%205%201.2%2010%201.3%2015a320%20320%200%200%201%20.1%207v102.3l-.1%207c0%205-.5%2010-1.3%2015a50.7%2050.7%200%200%201-4.8%2014.4%2048.2%2048.2%200%200%201-21%2021%2050.8%2050.8%200%200%201-14.4%204.8c-5%20.8-10%201.2-15%201.3a320%20320%200%200%201-7%200l-8.2.1z%22/%3E%3C/svg%3E');
}

html,
body {
  margin: 0;
  /* No rubber-band overscroll. A fixed backdrop is clipped to the viewport,
     so any bounce past the end of the document exposes the root background
     behind it. This was on the original splash and was removed in error when
     the page was made scrollable — `overscroll-behavior` never blocked
     scrolling, only the bounce. */
  overscroll-behavior: none;
}

/* The background lives on <html>, not <body>, and gradient.js animates it
   there. The root element's background is the one that paints the whole
   canvas — behind browser chrome, into safe areas, through overscroll — which
   is exactly the area a fixed element cannot reach. If <body> also carried a
   background it would paint its own box over the document and only the
   unreachable strips would animate, which is backwards. var(--bg) is the
   starting value and the fallback when WebGL is unavailable. */
html {
  background: var(--bg);
}

body {
  color: var(--fg);
  font-family: var(--font-body);
}

/* The backdrop must cover the LARGE viewport, not the small one.
   `height: 100%` on a fixed element resolves against the small viewport —
   the layout with the browser toolbar expanded. On iOS Safari that measured
   796px against a 836px layout viewport, leaving a 40px strip at the bottom
   that fell through to the flat body background once the page could scroll.
   `lvh` is the toolbar-retracted height, so the box stops changing size as
   the toolbar collapses. Width stays `100%` rather than `100vw`, which would
   include the scrollbar on desktop and cause horizontal overflow. */
#gradient {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100vh;
  height: 100lvh;
  z-index: -1;
}

a {
  color: var(--fg-85);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

/* Uppercase, wide-tracked label. The text-indent cancels the trailing
   letter-spacing on the last character so the line centers optically
   rather than sitting a few pixels left. */
.tracked {
  text-transform: uppercase;
  letter-spacing: 0.25em;
  text-indent: 0.25em;
}

/* --- App icon -------------------------------------------------------
   Apple's squircle, from the app promo on nickolas.world. Two states
   share one geometry so a shipped app and an in-progress project sit on
   the same footprint in the grid.
   Shipped:     artwork masked to the path + a hairline border.
   In progress: the same path stroked as a dashed outline, no artwork.
   The border is white here, not the black used on nickolas.world — that
   site has a light background; 10% black is invisible on --bg.        */

.app-icon {
  position: relative;
  width: 170px;
  height: 170px;
  flex-shrink: 0;
}

.app-icon-art {
  width: 100%;
  height: 100%;
  object-fit: contain;
  mask-image: var(--squircle-mask);
  -webkit-mask-image: var(--squircle-mask);
  mask-size: 100% 100%;
  -webkit-mask-size: 100% 100%;
}

.app-icon-border {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.app-icon-border use {
  fill: none;
  stroke: #fff;
  stroke-opacity: 0.15;
  stroke-width: 1.36;
}

/* vector-effect is deliberately not used anywhere here: it is a
   non-inherited property, so setting it on <use> styles the <use>
   element itself rather than the <path> cloned into its shadow tree,
   which makes it inert. Instead .app-icon-border use carries
   stroke-width: 1.36 — at the viewBox-to-pixel scale of this icon
   (230.5 units render at 170px, ~0.74 CSS px per unit), 1.36 * 0.74 ≈
   1px, landing the intended 1px hairline. The pending variant below
   overrides stroke-width and adds the dash pattern in the same user
   units, so `10 8` lands at roughly a 7.4px dash and a 5.9px gap, and
   stroke-width: 2 lands at roughly 1.5px. A dashed line reads lighter
   than a solid one, hence the higher opacity than the shipped border. */
.app-icon--pending use {
  fill: none;
  stroke: #fff;
  stroke-opacity: 0.28;
  stroke-width: 2;
  stroke-dasharray: 10 8;
  stroke-linecap: round;
}
