/* ShotWork site styles.
 *
 * One stylesheet, plain CSS, no preprocessor. Read top to bottom:
 * tokens, then base elements, then the page furniture, then the
 * components each homepage section uses.
 *
 * FONTS: system stack for now. CLAUDE.md requires any real webfont to be
 * self-hosted with a commercial licence -- that decision is not made yet,
 * so this uses whatever the visitor's OS already has.
 */

/* --- Tokens -------------------------------------------------------
 * Every colour and measurement the site uses is named here. Changing
 * the accent is a one-line edit.
 *
 * These are the brand palette, matching the app's splash screen and the
 * SVGs in static/brand/.
 *
 * One departure: the brand's muted text is #5E6875, which lands at
 * 3.15:1 on this background and fails AA for body text. Every secondary
 * paragraph on the site uses it, so it is lifted to #78828F, which keeps
 * the same character and passes.
 */
:root {
  --bg:      #161818;   /* the brand background */
  --deep:    #0F1111;   /* the darker ground: panels, raised blocks */
  --panel:   #0F1111;
  --line:    #2A2F2F;   /* the hex cell stroke, reused as the site's rules */
  --text:    #94A0B2;   /* slate */
  --muted:   #78828F;   /* lifted from the brand's #5E6875, which fails AA */
  --accent:  #3DF26C;   /* dark grounds only */
  --accent-ink: #06240F; /* text drawn on top of the accent */
  --accent-on-light: #0B8F3E; /* the green for light grounds */

  --wrap:    68rem;     /* maximum content width */
  --radius:  6px;
  --head-height: 60px;

  --font: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: ui-monospace, "Cascadia Mono", "SF Mono", Consolas, monospace;
}

/* --- Base ---------------------------------------------------------- */

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  position: relative;   /* the honeycomb layer anchors to the page */
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 {
  line-height: 1.15;
  letter-spacing: -0.02em;
  margin: 0 0 0.6em;
  font-weight: 600;
  text-wrap: balance;
}

h1 { font-size: clamp(2.1rem, 5vw, 3.2rem); }
h2 { font-size: clamp(1.6rem, 3.2vw, 2.2rem); }
h3 { font-size: 1.25rem; }

p { margin: 0 0 1em; }

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

.muted { color: var(--muted); }
.small { font-size: 0.88rem; }

/* A short paragraph under a heading. Kept narrow so lines stay readable. */
.lede {
  font-size: clamp(1.05rem, 2vw, 1.2rem);
  color: var(--muted);
  max-width: 56ch;
}

/* Horizontal padding + max width. Wraps the content of every section. */
.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 1.5rem;
}

/* Present for screen readers, invisible on screen. Used for the
 * included/not-included words in the comparison table, so the meaning
 * does not rest on a tick mark alone. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Keyboard users can jump straight past the nav. */
.skip { position: absolute; left: -9999px; }

.skip:focus {
  left: 1rem;
  top: 1rem;
  background: var(--accent);
  color: var(--accent-ink);
  padding: 0.5rem 1rem;
  z-index: 10;
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

/* --- Buttons ------------------------------------------------------- */

.btn {
  display: inline-block;
  padding: 0.7rem 1.4rem;
  border-radius: var(--radius);
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: 600;
  font-size: 1rem;
  font-family: inherit;
  text-decoration: none;
  text-align: center;
  border: 1px solid var(--accent);
  cursor: pointer;
}

.btn:hover { filter: brightness(1.08); }

.btn-ghost {
  background: transparent;
  color: var(--text);
  border-color: var(--line);
}

.btn-ghost:hover { border-color: var(--muted); filter: none; }

.btn-small { padding: 0.4rem 0.9rem; font-size: 0.9rem; }

.btn[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
  filter: none;
}

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin: 2rem 0 1rem;
}

/* The hero shows one primary or the other by width, never both: a phone
 * cannot install a desktop app, so it copies the link instead. */
.narrow-only { display: none; }

/* --- Pre-launch banner --------------------------------------------
 * A thin strip above the header while config.PRELAUNCH is True. It
 * scrolls away with the page; the header below it is what stays put.
 */
.prelaunch-banner {
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--accent) 30%, var(--line));
  backdrop-filter: blur(10px);
  color: var(--text);
  font-size: 0.9rem;
  padding: 0.55rem 0;
  text-align: center;
}

/* --- The honeycomb ---------------------------------------------------
 * Drawn by site.js as one SVG of individual hexagons, each with its own
 * opacity. Nothing here fades anything.
 *
 * Three earlier attempts faded a tiled background behind a gradient mask,
 * and all three banded. The reason is that the cell fill is only three
 * colour steps away from the background, so any gradient over it has
 * three visible bands however it is computed. Stepping the gradient per
 * column did not help either: the step edges cut across cells and read as
 * hard stripes.
 *
 * So there is no gradient. Each hexagon is a separate shape and takes a
 * single opacity, worked out from where it sits plus a little noise. The
 * smallest thing that can change brightness is one cell, which is exactly
 * what the pattern is made of, and the noise stops whole columns sharing
 * a value.
 *
 * Without JavaScript there is no pattern at all. It is decoration, and an
 * empty background is a perfectly good fallback.
 */
.page-hex-wrap {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 2600px;
  z-index: -1;
  pointer-events: none;
  overflow: hidden;
}

/* Size comes from the width and height attributes site.js sets, not
 * from here: two sources of truth for the size is one too many. */
.page-hex { display: block; }

/* The one lit cell. Placed by site.js on a real grid centre, and kept
 * clear of the wordmark. Hidden until then, so it never flashes up in the
 * wrong place. */
.page-lit {
  position: absolute;
  width: 56px;
  height: 49.04px;
  background-image: url("brand/hex-lit-cell.svg");
  background-size: 56px 49.04px;
  background-repeat: no-repeat;
  pointer-events: none;
  visibility: hidden;
}

/* --- Header and footer --------------------------------------------- */

.site-head {
  border-bottom: 1px solid var(--line);
  position: sticky;
  top: 0;
  /* See-through, so the honeycomb is visible from the very top of the
   * page. Safe for the brand rule about the wordmark never sitting on the
   * pattern: the pattern's own mask keeps the left 45% clear, and the
   * wordmark is on the left. */
  background: color-mix(in srgb, var(--bg) 72%, transparent);
  backdrop-filter: blur(10px);
  z-index: 5;
}

.head-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: var(--head-height);
}

/* The wordmark is 868 x 100, so a fixed height makes it very wide. It is
 * sized against the screen instead. */
.wordmark {
  display: inline-flex;
  align-items: center;
  flex: none;
  text-decoration: none;
}

.wordmark img { display: block; }

/* The wordmark stays at every width: on a phone it is the only place the
 * name appears, so swapping it for the hexagon would leave the product
 * unnamed. Sized as a share of the screen with a ceiling, so it shrinks
 * rather than overflowing. */
.wordmark .full { width: min(42vw, 190px); height: auto; }
.wordmark .mark { display: none; }

.site-head nav {
  display: flex;
  align-items: center;
  gap: 1.5rem;
}

.site-head nav a {
  text-decoration: none;
  font-size: 0.95rem;
  color: var(--muted);
}

.site-head nav a:hover { color: var(--text); }
.site-head nav a.btn { color: var(--accent-ink); }

.site-foot {
  border-top: 1px solid var(--line);
  margin-top: 4rem;
  padding: 2.5rem 0 2rem;
}

.foot-inner {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem 2.5rem;
  align-items: baseline;
  justify-content: space-between;
}

.foot-links {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
}

.foot-links a {
  color: var(--muted);
  text-decoration: none;
  font-size: 0.92rem;
}

.foot-links a:hover { color: var(--text); }

/* --- Sections ------------------------------------------------------ */

section { padding: 4.5rem 0; }

.section-head { max-width: 56ch; margin-bottom: 2.5rem; }

/* The sticky header would otherwise cover the top of a jumped-to
 * section. */
[id] { scroll-margin-top: calc(var(--head-height) + 1rem); }

.hero { padding: 5rem 0 2rem; }
.hero h1 { max-width: 18ch; }
.hero .lede { max-width: 54ch; }

.hero-media { padding: 1rem 0 2rem; }

/* A single sentence sitting between the hero and the first real
 * section. Deliberately not a row of chips. */
.presets-line {
  padding: 0 0 3.5rem;
  color: var(--muted);
}

.presets-line p { margin: 0; }

/* --- Captures ------------------------------------------------------
 * A still or loop from the app. The border stops a dark screenshot from
 * bleeding into the dark page.
 */
.capture-live {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--panel);
  margin: 0;
}

.capture-live img,
.capture-live video { display: block; width: 100%; height: auto; }

/* --- How it works --------------------------------------------------
 * Three numbered steps. The numbering is real information here: this is
 * a sequence, not a list of features.
 */
.steps-flow {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4rem;
}

.step {
  display: grid;
  grid-template-columns: 1fr 1.25fr;
  gap: 3rem;
  align-items: center;
}

/* Every other step puts the capture on the left, so the page does not
 * read as three identical rows. */
.step:nth-child(even) .step-text { order: 2; }

.step-text { max-width: 48ch; }
.step-text p { margin: 0; color: var(--muted); }

.step-text h3 {
  display: flex;
  align-items: baseline;
  gap: 0.7rem;
  margin-bottom: 0.5em;
}

.step-number {
  font-family: var(--mono);
  font-size: 0.85rem;
  color: var(--accent);
  border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--line));
  border-radius: 50%;
  width: 1.9rem;
  height: 1.9rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
}

/* --- Tables --------------------------------------------------------
 * The comparison and pricing tables are real tables: they are tabular
 * data, and a screen reader should be able to say which column a tick
 * belongs to.
 */
.table-scroll {
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

table {
  width: 100%;
  border-collapse: collapse;
  background: var(--panel);
}

caption { text-align: left; }

th, td {
  text-align: left;
  padding: 0.85rem 1.2rem;
  border-bottom: 1px solid var(--line);
  font-weight: 400;
}

thead th {
  font-weight: 600;
  font-size: 0.85rem;
  letter-spacing: 0.02em;
  color: var(--muted);
  white-space: nowrap;
}

tbody tr:last-child th,
tbody tr:last-child td { border-bottom: 0; }

tbody th { color: var(--text); }

/* The two verdict columns are narrow and centred; the feature name
 * column takes whatever is left. */
.tiers td { text-align: center; width: 8rem; }
.tiers thead th:not(:first-child) { text-align: center; }

.yes { color: var(--accent); font-size: 1.1rem; }
.no { color: var(--muted); }

/* One price, so no price table: the figure, what it entitles, the Buy
 * button, then the plain answer to "why not a subscription". */
.price-block { max-width: 52ch; margin-bottom: 3.5rem; }

.price-figure {
  font-size: 2.8rem;
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1;
  margin-bottom: 0.8rem;
  font-variant-numeric: tabular-nums;
}

.price-block .btn-row { margin: 1.5rem 0 0; }

.why-perpetual {
  margin-top: 3rem;
  padding-top: 2rem;
  border-top: 1px solid var(--line);
  max-width: 52ch;
}

.why-perpetual p { color: var(--muted); margin: 0; }

.founding {
  margin: 1.5rem 0 0;
  color: var(--accent);
}

/* --- What a license adds -------------------------------------------
 * Four items, each a heading and a sentence. Not cards: they are one
 * list of related things, not four separate objects.
 */
.adds {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
  gap: 2rem 2.5rem;
}

.adds h3 { margin-bottom: 0.35em; }
.adds p { margin: 0; color: var(--muted); }

/* A short list of plain facts. Ticked, because each one is something you
 * get, not a bullet in an argument. */
.facts {
  list-style: none;
  margin: 2.5rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  max-width: 60ch;
  color: var(--muted);
}

.facts li { padding-left: 1.5rem; position: relative; }

.facts li::before {
  content: "¹3";
  position: absolute;
  left: 0;
  color: var(--accent);
}

/* --- The two promises ----------------------------------------------
 * Deliberately set apart: they are commitments, not features.
 */
.promises {
  margin-top: 2.5rem;
  border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--line));
  border-radius: var(--radius);
  background: var(--panel);
  padding: 1.75rem 2rem;
  max-width: 60ch;
}

.promises h3 { margin-bottom: 0.7em; }

.promises ul {
  margin: 0;
  padding-left: 1.2rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.promises li { color: var(--text); }

/* A column of running text, kept to a readable measure. */
.prose { max-width: 62ch; }
.prose p:last-child { margin-bottom: 0; }

/* --- Downloads ----------------------------------------------------- */

.downloads {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 1.5rem;
  margin-bottom: 1.5rem;
}

.download {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--panel);
  padding: 1.5rem;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1rem;
}

.download p { margin: 0; }

/* --- Founder line -------------------------------------------------- */

.founder {
  padding: 3rem 0 1rem;
  color: var(--muted);
}

.founder p { margin: 0; max-width: 52ch; }

/* --- Narrow screens ------------------------------------------------
 * The hero swaps its primary button here: below this width the visitor
 * is assumed to be on a phone, where a desktop download is no use.
 */
@media (max-width: 700px) {
  .wide-only { display: none; }
  .narrow-only { display: inline-block; }

  section { padding: 3rem 0; }
  .hero { padding: 2.5rem 0 1.5rem; }
  .presets-line { padding-bottom: 2.5rem; }

  .step { grid-template-columns: 1fr; gap: 1.5rem; }
  /* Stacked, the capture always follows its own text. */
  .step:nth-child(even) .step-text { order: 0; }

  .steps-flow { gap: 3rem; }

  th, td { padding: 0.7rem 0.9rem; }
  .tiers td { width: 5rem; }
}

/* --- Reduced motion ------------------------------------------------
 * Autoplay cannot be stopped from CSS, so site.js pauses the loops. This
 * only removes the smooth-scroll, which is the other moving thing.
 */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}
