/* The Useful Company. The look of the apps' welcome and About windows: near-black, a slow mesh of coloured
   light with grain (mesh.js), frosted panels, white type. Two text sizes; everything else is weight and opacity. */

/* Google Sans Flex (SIL Open Font License, fonts/OFL.txt), served from this site so no visitor's browser contacts Google. */
@font-face { font-family: "Google Sans Flex"; font-style: normal; font-weight: 300 700; font-display: swap;
  src: url("/fonts/google-sans-flex-latin-ext.woff2") format("woff2"); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: "Google Sans Flex"; font-style: normal; font-weight: 300 700; font-display: swap;
  src: url("/fonts/google-sans-flex-latin.woff2") format("woff2"); 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; }

:root {
  color-scheme: dark;
  --ink: #0d0b0a;
  --text: #fff;
  --soft: rgba(255, 255, 255, .66);
  --faint: rgba(255, 255, 255, .52);
  --line: rgba(255, 255, 255, .1);
  --title: clamp(34px, 3.4vw, 46px);
  --body: 16px;
  --edge: 32px;
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0; min-height: 100svh; display: flex; flex-direction: column; background: var(--ink); color: var(--text);
  font: 400 var(--body)/1.6 "Google Sans Flex", -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
  font-optical-sizing: auto;
  -webkit-font-smoothing: antialiased; text-wrap: pretty;
}
a { color: inherit; }
a:focus-visible { outline: 2px solid #fff; outline-offset: 4px; }
a:active { opacity: .7; }
/* Increase Contrast: secondary text goes solid. */
@media (prefers-contrast: more) { :root { --soft: #fff; --faint: rgba(255, 255, 255, .85); } }
img { display: block; max-width: 100%; height: auto; }
p { margin: 0; }

h1 { font-size: var(--title); line-height: 1; letter-spacing: -.025em; font-weight: 440; margin: 0; text-wrap: balance; }
h2, h3 { font-size: var(--body); line-height: 1.5; font-weight: 560; margin: 0; }
.soft { color: var(--soft); }
.faint { color: var(--faint); }

.wrap { width: 100%; max-width: 1120px; margin: 0 auto; padding: 0 var(--edge); }

/* Light: a mesh gradient canvas behind the content. The CSS gradient underneath shows until it draws,
   and stays if WebGL isn't available. */
.glow { position: relative; isolation: isolate; overflow: hidden; }
.mesh { position: absolute; inset: 0; z-index: -1; pointer-events: none; }
.mesh canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; opacity: 0; transition: opacity 1.2s ease; }
.mesh.on canvas { opacity: 1; }
.mesh.pyro { background: radial-gradient(90% 70% at 70% 100%, #8a2c12, transparent 70%), #120c0b; }
.mesh.company { background: radial-gradient(70% 70% at 100% 30%, #1d5566, transparent 70%), radial-gradient(70% 60% at 60% 100%, #7a3814, transparent 70%), var(--ink); }
/* The light dims toward the bottom but still ends on a clear edge. A soft shade on the left keeps the words readable. */
.hero .mesh::after { content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    linear-gradient(to bottom, transparent 50%, rgba(13, 11, 10, .95)),
    linear-gradient(100deg, rgba(13, 11, 10, .7) 0%, rgba(13, 11, 10, .35) 35%, transparent 70%); }

/* Frosted panel, as in the About windows: material plus a faint white wash. */
.glass {
  background: rgba(255, 255, 255, .07);
  -webkit-backdrop-filter: blur(30px) saturate(1.6); backdrop-filter: blur(30px) saturate(1.6);
  border: 1px solid var(--line);
  border-radius: 24px;
}

/* Header */
.top { position: absolute; top: 0; left: 0; right: 0; z-index: 2; padding-top: 24px; }
.top .wrap { display: flex; align-items: center; justify-content: space-between; height: 88px; }
.top .logo img { width: 100px; opacity: .92; transition: opacity .15s; }
.top .logo:hover img { opacity: 1; }
.top nav { display: flex; gap: 28px; }
.top nav a { text-decoration: none; color: var(--soft); transition: color .15s; }
.top nav a:hover, .top nav a[aria-current] { color: var(--text); }

/* Hero */
/* Product pages: a hero shorter than the screen, so the first section already shows below it. */
.hero { min-height: min(70vh, 680px); display: flex; align-items: flex-end; padding: 160px 0 80px; }
/* …and lighter than the home page: the shade at the bottom and on the left is gentler. */
.hero:not(.full) .mesh::after {
  background:
    linear-gradient(to bottom, transparent 55%, rgba(13, 11, 10, .6)),
    linear-gradient(100deg, rgba(13, 11, 10, .45) 0%, rgba(13, 11, 10, .2) 35%, transparent 65%);
}
.hero .lede { margin-top: 20px; max-width: 32em; }
.hero .note { margin-top: 28px; }
.icon { width: 96px; height: 96px; margin: 0 0 28px -8px; }

/* Home: a hero the height of the screen, with a small nudge to scroll. */
.hero.full { min-height: 100vh; min-height: 100svh; padding-bottom: 104px; }
/* Headline on the left, the line on the right, sitting on the headline's last baseline. */
.hero.full .wrap { display: flex; align-items: last baseline; justify-content: space-between; gap: 48px; }
.hero.full .lede { margin: 0; text-align: right; max-width: none; white-space: nowrap; }
/* Pyro page: the words on the left, the App Store line on the right, on the lede's last baseline. */
.hero.split .wrap { display: flex; align-items: last baseline; justify-content: space-between; gap: 48px; }
.hero.split .note { margin: 0; text-align: right; white-space: nowrap; }
.hero.split .lede { white-space: nowrap; }
/* Too narrow for both side by side: the App Store line goes under the words. */
@media (max-width: 860px) {
  .hero.split .wrap { display: block; }
  .hero.split .note { margin-top: 28px; text-align: left; }
}
.scroll {
  position: absolute; left: 50%; bottom: 28px; translate: -50% 0;
  display: flex; padding: 10px; color: var(--faint); transition: color .15s;
}
.scroll:hover { color: var(--text); }
@media (prefers-reduced-motion: no-preference) {
  .scroll svg { animation: nudge 2.6s ease-in-out infinite; }
  @keyframes nudge { 0%, 100% { transform: translateY(-2px); } 50% { transform: translateY(3px); } }
}

/* Apps: one card each, the app's own light behind its icon, its words and its window. */
.apps { padding-top: 96px; }
.apps .wrap > h2 { margin-bottom: 20px; }
.appcard {
  display: grid; grid-template-columns: max-content 1fr; gap: 56px; min-height: 480px;
  border-radius: 8px; text-decoration: none; transition: transform .2s ease;
}
.appcard:active { transform: scale(.995); opacity: 1; }
/* A dark shade from the bottom left keeps the card's words readable. mesh.js draws it inside the gradient
   (data-shade) so it has the same grain; this CSS copy only shows until the canvas is up, or without WebGL. */
.appcard .mesh:not(.on)::after { content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(60deg, rgba(13, 11, 10, .85) 0%, rgba(13, 11, 10, .55) 30%, transparent 60%); }
/* Icon at the top of the card, name, line and button at the bottom. */
.appcard .about { display: flex; flex-direction: column; align-items: flex-start; padding: 48px 0 48px 48px; }
.appcard .about .appicon { margin-bottom: auto; }
.appcard .about h3 { margin-top: 32px; }
.appicon { width: 72px; height: 72px; margin: 0 0 20px -6px; }
.appcard h3 + p { margin-top: 2px; line-height: 1.4; white-space: nowrap; }
.more {
  display: inline-block; margin-top: 28px; padding: 9px 18px; border-radius: 999px;
  background: #fff; color: #111; font-weight: 560; transition: background .15s;
}
/* Hovering anywhere on the card: an arrow slides into the pill. */
.more { display: inline-flex; align-items: center; }
.more::after {
  content: "→"; display: inline-block; width: 0; opacity: 0; overflow: hidden; transform: translateX(-6px);
  transition: width .35s cubic-bezier(.2, .7, .2, 1), margin .35s cubic-bezier(.2, .7, .2, 1), opacity .35s, transform .35s cubic-bezier(.2, .7, .2, 1);
}
.appcard:hover .more::after, .appcard:focus-visible .more::after { width: 20px; margin-left: 6px; opacity: 1; transform: none; }
.peek {
  align-self: center; justify-self: center; width: min(78%, 560px); margin: 72px 0;
  /* The capture carries the window's own transparent corners, so the shadow follows them. */
  filter: drop-shadow(0 24px 36px rgba(0, 0, 0, .6));
  transition: transform .6s cubic-bezier(.2, .7, .2, 1);
}
/* On hover the window slides right and the card's edge cuts it off, as if it's heading out. */
.appcard:hover .peek, .appcard:focus-visible .peek { transform: translateX(22%); }

/* Product page sections: a small label, an outcome headline at title size, a line, the facts, a screenshot. */
.feature { padding-top: 160px; }
.kicker { color: #f0a066; font-weight: 560; }
.feature h2, .private h2 { font-size: var(--title); line-height: 1.08; letter-spacing: -.025em; font-weight: 440; margin-top: 6px; text-wrap: balance; }
/* Stacked sections: label and headline, the app in a card of light, then three facts as small cards.
   Copy here is written to fit one line each; keep it that way rather than letting it wrap. */
.stage { margin-top: 64px; padding: 64px; border-radius: 8px; }
/* The video's box has the same shape as the 1760×1000 shots, so this card matches the others exactly;
   the padding inside it shrinks the window itself, and object-fit keeps the video's proportions. */
.stage.solo .shot { display: block; width: 100%; height: auto; aspect-ratio: 1760 / 1000; padding: 7% 0; object-fit: contain; }
/* Safari drops the poster the moment play starts, before the first frame is ready; the same picture behind the
   video fills that gap. The window in the video is opaque, so once frames arrive they cover it exactly. */
.shot.burn { background: url(/pyro/img/burn-poster.png) center / contain no-repeat content-box; }
/* The burn video's play, pause and replay button, in the card's bottom right corner. */
.vidctl { position: absolute; right: 16px; bottom: 16px; width: 44px; height: 44px; border-radius: 50%; border: 0; padding: 0;
  display: grid; place-items: center; color: #fff; cursor: pointer;
  background: rgba(13, 11, 10, .45); -webkit-backdrop-filter: blur(20px); backdrop-filter: blur(20px);
  transition: background-color .2s, transform .15s cubic-bezier(.2, .7, .2, 1); }
@media (hover: hover) { .vidctl:hover { background: rgba(13, 11, 10, .65); } } /* touch screens keep :hover after a tap */
.vidctl:active { transform: scale(.92); background: rgba(13, 11, 10, .75); }
.vidctl:focus-visible { outline: 2px solid #f0a066; outline-offset: 2px; }
.vidctl svg { width: 20px; height: 20px; display: none; fill: currentColor; }
.vidctl .i-replay { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.vidctl[data-state="play"] .i-play, .vidctl[data-state="pause"] .i-pause, .vidctl[data-state="replay"] .i-replay { display: block; }
.points { list-style: none; margin: 16px 0 0; padding: 0; display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
/* Each fact is a small card with no border, just a faint light from the top left: an icon, then the fact on one line. */
.points li { display: flex; align-items: center; gap: 14px; padding: 18px 20px; border-radius: 8px; white-space: nowrap;
  border: 0; background: linear-gradient(135deg, rgba(255, 255, 255, .10), rgba(255, 255, 255, .03)); position: relative; }
/* A soft warm light that follows the pointer across the three cards, so a card brightens as the pointer nears it.
   The page script sets --x and --y on each card; without it nothing shows. */
.points li::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; opacity: 0;
  background: radial-gradient(220px circle at var(--x, 50%) var(--y, 50%), rgba(240, 160, 102, .16), transparent 70%);
  transition: opacity .4s cubic-bezier(.2, .7, .2, 1);
}
.points:hover li::before { opacity: 1; }
.points svg { flex: none; width: 24px; height: 24px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
/* Window captures with their own transparent corners, so the shadow follows the window's shape. */
picture { display: contents; }
picture source { display: none; }
.shot { width: 100%; filter: drop-shadow(0 24px 40px rgba(0, 0, 0, .6)); }

/* The end of a product page: one soft light behind privacy, specs, questions and the footer. It fades in slowly
   from the page colour over the first 700px (eased stops, no visible start) and runs to the bottom. */
.tail { margin-top: 120px; }
.tail .mesh {
  --fade: linear-gradient(to bottom, transparent 0, rgba(0, 0, 0, .04) 70px, rgba(0, 0, 0, .15) 140px, rgba(0, 0, 0, .35) 210px,
    rgba(0, 0, 0, .6) 300px, rgba(0, 0, 0, .82) 420px, #000 700px);
  -webkit-mask-image: var(--fade); mask-image: var(--fade);
}
.tail a { text-decoration-color: rgba(255, 255, 255, .35); text-underline-offset: 3px; }
.tail a:hover { text-decoration-color: #fff; }
.tail footer { padding-top: 120px; }
.tail footer a { text-decoration: none; }

/* Privacy: a headline and three tiles, like Apple's privacy pages. */
.private { padding-top: 220px; }
.private h2 + p { margin-top: 20px; max-width: 34em; }
.tiles { list-style: none; margin: 40px 0 0; padding: 0; display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.tile { border-radius: 12px; padding: 28px; min-height: 220px; display: flex; flex-direction: column; justify-content: space-between; gap: 32px; }
.tile svg { width: 36px; height: 36px; fill: none; stroke: #fff; stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }
.tile h3 + p { margin-top: 2px; }

/* Tech specs: quiet label and value rows. */
.specs { padding-top: 160px; }
.specs dl { margin: 20px 0 0; border-top: 1px solid var(--line); }
.specs dl > div { display: grid; grid-template-columns: 200px 1fr; gap: 24px; padding: 14px 0; border-bottom: 1px solid var(--line); }
.specs dt { font-weight: 560; }
.specs dd { margin: 0; color: var(--soft); }

/* Questions: native disclosure rows. */
.faq { padding-top: 160px; }
.faq h2 { margin-bottom: 20px; }
.faq details { border-bottom: 1px solid var(--line); }
.faq details:first-of-type { border-top: 1px solid var(--line); }
.faq summary { list-style: none; cursor: pointer; padding: 14px 32px 14px 0; position: relative; font-weight: 560; }
.faq summary::-webkit-details-marker { display: none; }
/* A drawn plus, centred on the row's middle; it turns into a cross when open. */
.faq summary::after {
  content: ""; position: absolute; right: 4px; top: 50%; width: 12px; height: 12px; margin-top: -6px; color: var(--soft);
  background: linear-gradient(currentColor, currentColor) center / 100% 1.5px no-repeat,
              linear-gradient(currentColor, currentColor) center / 1.5px 100% no-repeat;
  transition: transform .25s cubic-bezier(.2, .7, .2, 1);
}
/* .shut is set by the page script while an answer slides closed, so the cross turns back as it starts closing. */
.faq details[open]:not(.shut) summary::after { transform: rotate(45deg); }
.faq summary:hover { color: #fff; } .faq summary:hover::after { color: #fff; }
.faq summary:active { opacity: .7; }
.faq details { overflow: hidden; }
.faq details p { padding: 0 32px 18px 0; max-width: 40em; }
.more-help { margin-top: 24px; }

@media (max-width: 900px) {
  .tiles { grid-template-columns: repeat(2, 1fr); }
  .points { grid-template-columns: 1fr; gap: 10px; }
}

/* Text pages: support and privacy */
.doc { padding: 168px 0 0; }
.doc .wrap > * { max-width: 680px; }
.doc h1 { margin-bottom: 24px; }
.doc h2 { margin-top: 40px; margin-bottom: 6px; }
.doc p + p, .doc p + ul, .doc ul + p { margin-top: 12px; }
.doc ul { padding-left: 1.1em; margin: 0; } .doc li { margin-top: 6px; }
.doc p, .doc li { color: var(--soft); }
.doc strong { color: var(--text); font-weight: 560; }
.doc a { text-decoration-color: rgba(255, 255, 255, .35); text-underline-offset: 3px; }
.doc a:hover { text-decoration-color: #fff; }

main { flex: 1; }
footer { padding: 96px 0 48px; color: var(--faint); }
footer .wrap { display: flex; flex-wrap: wrap; gap: 8px 28px; }
footer a { text-decoration: none; color: var(--faint); transition: color .15s; }
footer a:hover { color: var(--text); }
footer .end { margin-left: auto; }

/* Entrance, like the apps' welcome screens: a short rise and fade, staggered. Skipped with Reduce Motion. */
@media (prefers-reduced-motion: reduce) { .mesh canvas { transition: none; } }
@media (prefers-reduced-motion: no-preference) {
  .rise { animation: rise .8s cubic-bezier(.2, .7, .2, 1) both; animation-delay: calc(var(--d, 0) * 90ms); }
  @keyframes rise { from { opacity: 0; transform: translateY(12px); } }
}

@media (max-width: 640px) {
  :root { --edge: 20px; }
  .top { padding-top: 12px; }
  .top .wrap { height: 72px; }
  .top .logo img { width: 84px; }
  .top nav { gap: 20px; }
  .hero { min-height: 0; padding: 136px 0 72px; }
  .icon { width: 80px; height: 80px; margin-left: -6px; }
  .feature { padding-top: 112px; }
  /* On a phone the windows would be too small to read at full width, so the card turns square and the window is
     drawn larger, starting near the left edge and running off the right one (the card clips it). The burn video
     is centred and whole instead: its content sits in the middle and a Cancel button sits at the right edge, so
     any bleed would leave a cut-off button or an off-centre disc. */
  .stage { padding: 0; border-radius: 6px; margin-top: 40px; aspect-ratio: 1; }
  .stage .shot { position: absolute; top: 50%; left: 20px; height: 80%; width: auto; max-width: none; transform: translateY(-50%); }
  .stage.solo .shot { aspect-ratio: 920 / 680; padding: 0; object-fit: contain; width: 92%; height: auto; left: 4%;
    transform: translateY(calc(-50% - 10px)); } /* a little high, so the button below stays clear of the window */
  .vidctl { right: 12px; bottom: 12px; width: 40px; height: 40px; }
  .points { margin-top: 10px; }
  .points li { padding: 16px 18px; }
  .tail { margin-top: 88px; }
  .private { padding-top: 160px; }
  .tiles { grid-template-columns: 1fr; gap: 12px; }
  .tile { min-height: 0; padding: 22px; gap: 24px; }
  .specs, .faq { padding-top: 112px; }
  .specs dl > div { grid-template-columns: 1fr; gap: 2px; }
  .tail footer { padding-top: 88px; }
  .apps { padding-top: 72px; }
  .appcard { grid-template-columns: 1fr; gap: 0; min-height: 0; border-radius: 6px; }
  .appcard .about { padding: 28px 24px 0; }
  .appcard .about h3 { margin-top: 20px; }
  .appicon { width: 64px; height: 64px; }
  .peek { margin: 36px auto 36px; width: 82%; }
  .hero.full { padding-bottom: 88px; }
  .hero.full .wrap { display: block; }
  .hero.full .lede { margin-top: 20px; text-align: left; white-space: normal; }
  .hero.split .lede { white-space: normal; text-wrap: balance; }
  footer .end { margin-left: 0; }
}
