/* =========================================================================
   SweeperX — THE CONTACT SHEET
   A 35mm proof sheet: frames butted in strips, edge-printed codes on the
   rebate, and the editor's grease-pencil marking the keeper before anything
   is cut. Two lights, both real: VIEWING LIGHT (the sheet on the table) and
   SAFELIGHT (the same sheet in the darkroom). The visitor picks.
   ========================================================================= */

@font-face {
  font-family: 'Archivo';
  src: url('/assets/fonts/archivo-var-latin.woff2') format('woff2');
  font-weight: 100 900;
  font-display: swap;
  font-style: normal;
}
@font-face {
  font-family: 'Martian Mono';
  src: url('/assets/fonts/martianmono-var-latin.woff2') format('woff2');
  font-weight: 300 800;
  font-display: swap;
  font-style: normal;
}

/* ============================ the two lights ============================ */

:root {
  color-scheme: light;

  /* VIEWING LIGHT — the proof sheet on the viewing table. */
  --paper:      #E7E4DC;   /* fibre-base stock */
  --paper-2:    #DAD5CA;   /* margin, recessed trays */
  --sheet:      #151310;   /* the photographic black of the strip field */
  --frame:      #241F19;   /* an exposed frame */
  --frame-lit:  #322B22;   /* a frame under the loupe */

  --ink:        #151310;
  --ink-2:      rgba(21, 19, 16, 0.68);
  --ink-3:      rgba(21, 19, 16, 0.52);
  --rule:       rgba(21, 19, 16, 0.16);
  --rule-soft:  rgba(21, 19, 16, 0.09);

  --on-sheet:   #F0EDE5;
  --on-sheet-2: rgba(240, 237, 229, 0.70);
  --sheet-rule: rgba(240, 237, 229, 0.16);

  --wax:        #C7261A;   /* grease pencil, the keeper's mark */
  --wax-ink:    #FFFFFF;
  --edge:       #9A6A16;   /* film edge printing, amber on the rebate */
  --edge-sheet: #E0A537;   /* the same edge printing, read off the black */

  --grain:      0.05;
  --sprocket:   rgba(21, 19, 16, 0.20);

  /* Type */
  --f-sans: 'Archivo', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --f-mono: 'Martian Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  --t-display: clamp(2.5rem, 1.55rem + 4.1vw, 4.5rem);
  --t-title:   clamp(1.8rem, 1.35rem + 1.9vw, 2.625rem);
  --t-heading: clamp(1.35rem, 1.15rem + 0.9vw, 1.8rem);
  --t-lead:    clamp(1.0625rem, 1.0rem + 0.5vw, 1.3125rem);
  --t-body:    1.0625rem;
  --t-small:   0.9375rem;
  --t-edge:    0.6875rem;

  /* Rhythm — 4px base */
  --s-1: 0.25rem; --s-2: 0.5rem;  --s-3: 0.75rem; --s-4: 1rem;
  --s-5: 1.5rem;  --s-6: 2rem;    --s-7: 3rem;    --s-8: 4rem;
  --s-9: clamp(4rem, 2rem + 7vw, 7.5rem);

  --w-prose: 68ch;
  --w-grid:  1180px;
  --gutter:  clamp(1.25rem, 0.75rem + 2vw, 2.5rem);

  --ring: 0 0 0 2px var(--paper), 0 0 0 5px var(--wax);
  --ease: cubic-bezier(.2, .75, .25, 1);
}

/* SAFELIGHT — the darkroom. The sheet is the same object; the room changed. */
@media (prefers-color-scheme: dark) {
  :root:not([data-light="viewing"]) {
    color-scheme: dark;
    --paper:      #100E0C;
    --paper-2:    #191512;
    --sheet:      #080706;
    --frame:      #1A1511;
    --frame-lit:  #2A231B;

    --ink:        #F2EDE3;
    --ink-2:      rgba(242, 237, 227, 0.70);
    --ink-3:      rgba(242, 237, 227, 0.52);
    --rule:       rgba(242, 237, 227, 0.16);
    --rule-soft:  rgba(242, 237, 227, 0.09);

    --on-sheet:   #F2EDE3;
    --on-sheet-2: rgba(242, 237, 227, 0.70);
    --sheet-rule: rgba(242, 237, 227, 0.14);

    --wax:        #FF4634;
    --wax-ink:    #16100E;
    --edge:       #E8A63C;
    --edge-sheet: #E8A63C;

    --grain:      0.07;
    --sprocket:   rgba(242, 237, 227, 0.22);
    --ring: 0 0 0 2px var(--paper), 0 0 0 5px var(--wax);
  }
}

:root[data-light="safelight"] {
  color-scheme: dark;
  --paper:      #100E0C;
  --paper-2:    #191512;
  --sheet:      #080706;
  --frame:      #1A1511;
  --frame-lit:  #2A231B;

  --ink:        #F2EDE3;
  --ink-2:      rgba(242, 237, 227, 0.70);
  --ink-3:      rgba(242, 237, 227, 0.52);
  --rule:       rgba(242, 237, 227, 0.16);
  --rule-soft:  rgba(242, 237, 227, 0.09);

  --on-sheet:   #F2EDE3;
  --on-sheet-2: rgba(242, 237, 227, 0.70);
  --sheet-rule: rgba(242, 237, 227, 0.14);

  --wax:        #FF4634;
  --wax-ink:    #16100E;
  --edge:       #E8A63C;
  --edge-sheet: #E8A63C;

  --grain:      0.07;
  --sprocket:   rgba(242, 237, 227, 0.22);
}

/* ================================ base ================================== */

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--f-sans);
  font-size: var(--t-body);
  font-weight: 420;
  line-height: 1.62;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* The parts we did not draw still carry the sheet. */
::selection { background: var(--wax); color: var(--wax-ink); }
::-webkit-scrollbar { width: 12px; height: 12px; }
::-webkit-scrollbar-track { background: var(--paper-2); }
::-webkit-scrollbar-thumb { background: var(--ink-3); border: 3px solid var(--paper-2); }
::-webkit-scrollbar-thumb:hover { background: var(--ink-2); }
:root { scrollbar-color: var(--ink-3) var(--paper-2); scrollbar-width: thin; }
::marker { color: var(--wax); }

h1, h2, h3, h4 { margin: 0; line-height: 1.04; letter-spacing: -0.035em; text-wrap: balance; font-weight: 800; }
p { margin: 0; }
img, svg { max-width: 100%; }
a { color: inherit; }
b, strong { font-weight: 700; }

:focus-visible { outline: none; box-shadow: var(--ring); border-radius: 2px; }

.wrap { width: 100%; max-width: var(--w-grid); margin-inline: auto; padding-inline: var(--gutter); }
.prose { max-width: var(--w-prose); }

.skip {
  position: absolute; left: var(--gutter); top: -5rem; z-index: 100;
  padding: var(--s-3) var(--s-4);
  background: var(--wax); color: var(--wax-ink); text-decoration: none;
  font: 700 var(--t-small)/1 var(--f-sans);
  transition: top .18s var(--ease);
}
.skip:focus { top: var(--s-4); }

/* Edge printing. Film stock markings: real identifiers and measurements only,
   set on the rebate beside what they identify — never as a label above a heading. */
.edge {
  font-family: var(--f-mono);
  font-size: var(--t-edge);
  font-weight: 500;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--edge);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.on-sheet .edge, .sheet .edge { color: var(--edge-sheet); }

/* Grain. The emulsion, not a texture effect: it lives only on exposed stock. */
.grainy { position: relative; isolation: isolate; }
.grainy::after {
  content: ""; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  opacity: var(--grain);
  /* A file, not a data: URI — `img-src 'self'` covers CSS background images too, and the
     inline version was blocked in production, which left every exposed field with no grain
     at all. Same-origin keeps the zero-third-party-request claim intact. */
  background-image: url("/assets/grain.svg");
}

/* Sprocket rail. The perforation edge is the page's structural line: it runs
   the length of any strip and replaces every border a card would have used. */
.rail, .sec--ruled::before, .proof::before, .proof::after,
.footer::before, .sheet__grid::before, .faq__list::before {
  content: "";
  display: block; height: 14px; flex: none;
  background:
    repeating-linear-gradient(to right,
      transparent 0 7px,
      var(--sprocket) 7px 16px,
      transparent 16px 23px);
}
/* The perforation IS the seam. Spacing only — the hairlines these replace are
   removed at their own declarations below, never re-zeroed from up here. */
.sec--ruled::before { margin-bottom: var(--s-9); }
.sheet__grid::before, .faq__list::before { margin-bottom: var(--s-4); }
.sheet__grid::before { grid-column: 1 / -1; }
.footer::before { margin-bottom: var(--s-7); }

/* ============================ sheet header ============================== */

.nav {
  position: sticky; top: 0; z-index: 50;
  background: var(--paper);
  border-bottom: 1px solid var(--rule);
}
.nav__inner {
  display: flex; align-items: center; gap: var(--s-4);
  min-height: 58px;
}
.nav__brand {
  display: inline-flex; align-items: center; gap: var(--s-3);
  margin-right: auto; text-decoration: none;
  font-weight: 800; font-size: 1.0625rem; letter-spacing: -0.03em;
  flex: 0 0 auto; white-space: nowrap; min-height: 44px;
}
.nav__brand img { width: 26px; height: 26px; display: block; }
.nav__links { display: flex; align-items: center; gap: var(--s-5); }
.nav__links a {
  display: inline-flex; align-items: center; min-height: 44px; white-space: nowrap;
  font-family: var(--f-mono); font-size: var(--t-edge); font-weight: 500;
  letter-spacing: 0.10em; text-transform: uppercase;
  color: var(--ink-2); text-decoration: none;
  border-bottom: 2px solid transparent;
  transition: color .16s var(--ease), border-color .16s var(--ease);
}
.nav__links a:hover { color: var(--ink); border-bottom-color: var(--wax); }
.nav__cta {
  display: inline-flex; align-items: center; min-height: 38px;
  padding: 0 var(--s-4);
  background: var(--wax); color: var(--wax-ink);
  font-weight: 700; font-size: var(--t-small); letter-spacing: -0.015em;
  text-decoration: none; white-space: nowrap;
}
.nav__cta:hover { filter: brightness(1.08); }
@media (max-width: 719px) { .nav__links { display: none; } }

/* The light switch. Named for the two rooms this sheet is read in. */
.lamp {
  display: inline-flex; align-items: stretch;
  border: 1px solid var(--rule); background: var(--paper-2);
  font-family: var(--f-mono); font-size: 0.625rem; letter-spacing: 0.08em;
  text-transform: uppercase; line-height: 1;
}
.lamp button {
  appearance: none; border: 0; background: transparent; cursor: pointer;
  color: var(--ink-3); font: inherit; letter-spacing: inherit;
  padding: 0 var(--s-3); min-height: 44px; min-width: 24px; justify-content: center;
  display: inline-flex; align-items: center; gap: 6px; white-space: nowrap;
  transition: color .16s var(--ease), background .16s var(--ease);
}
.lamp__txt { white-space: nowrap; }
.lamp button::before {
  content: ""; width: 7px; height: 7px; border-radius: 50%;
  background: currentColor; opacity: .35; flex: none;
}
.lamp button[aria-pressed="true"] { color: var(--ink); background: var(--paper); }
.lamp button[aria-pressed="true"]::before { opacity: 1; box-shadow: 0 0 8px currentColor; }
.lamp button:last-child[aria-pressed="true"]::before { color: var(--wax); }
.lamp button:hover { color: var(--ink-2); }

/* Responsive nav, in one place and after every base rule it must beat.
   Scattered earlier in the file, the base declarations simply won. */
@media (max-width: 899px) {
  /* Only the lit room is named; the unlit side collapses to its lamp. */
  .lamp button[aria-pressed="false"] .lamp__txt,
  .lamp button:not([aria-pressed]) .lamp__txt { display: none; }
}
@media (max-width: 639px) {
  .nav__inner { gap: var(--s-3); }
  .lamp__txt { display: none; }
  .lamp button { padding: 0 var(--s-2); }
  /* Two bare lamps name nothing, so the group carries its own legend here. */
  .lamp::before {
    content: "Light"; align-self: center; padding-inline: var(--s-2) 0;
    font-family: var(--f-mono); font-size: 0.5625rem; letter-spacing: 0.10em;
    text-transform: uppercase; color: var(--ink-3); line-height: 1;
  }
}
@media (max-width: 430px) {
  /* The legend earns its width by tightening what surrounds it, never by
     taking the space out of the wordmark. */
  .nav__inner { gap: var(--s-2); }
  .nav__brand { gap: var(--s-2); }
  .nav__cta { padding: 0 10px; font-size: var(--t-small); }
  .lamp button { padding: 0 5px; }
  .lamp::before { padding-inline: 5px 0; }
}
@media (max-width: 359px) {
  /* The wordmark already names the app beside it, so the button says "Get";
     the name stays in the link's accessible name for screen readers. */
  .nav__cta-name {
    position: absolute; width: 1px; height: 1px;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  }
}

/* ================================ hero ================================== */

.hero { padding-block: clamp(2.5rem, 1rem + 5vw, 5rem) 0; }
.hero__grid { display: grid; gap: var(--s-6); }
.hero__grid > * { min-width: 0; }
@media (min-width: 940px) {
  .hero__grid { grid-template-columns: minmax(0, 1.02fr) minmax(0, 0.98fr); gap: var(--s-8); align-items: end; }
}

h1 {
  font-size: var(--t-display);
  font-weight: 850;
  letter-spacing: -0.045em;
  max-width: 16ch;
}
h1 em { font-style: normal; color: var(--wax); }
.hero__sub {
  margin-top: var(--s-5); max-width: 46ch;
  font-size: var(--t-lead); color: var(--ink-2);
}
.hero__actions { margin-top: var(--s-6); display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-4) var(--s-5); }
.hero__price {
  font-family: var(--f-mono); font-size: var(--t-small); font-weight: 600;
  letter-spacing: 0.02em; color: var(--ink); font-variant-numeric: tabular-nums;
}
.hero__price span { color: var(--ink-3); font-weight: 400; }
.hero__qualifier { margin-top: var(--s-4); font-size: var(--t-small); color: var(--ink-3); max-width: 44ch; }

/* App Store badge — Apple's supplied asset, scaled uniformly only. */
.badge { display: inline-block; line-height: 0; transition: transform .2s var(--ease), opacity .2s var(--ease); }
.badge img { height: 48px; width: auto; display: block; }
.badge:hover { transform: translateY(-2px); opacity: .9; }

/* ---------------------------- the contact strip ------------------------- */

.strip {
  background: var(--sheet);
  padding-block: var(--s-2);
  display: flex; flex-direction: column;
}
.strip__frames {
  display: grid;
  grid-template-columns: repeat(var(--cols, 3), minmax(0, 1fr));
  gap: 3px;
  padding: 3px;
}
.frame {
  position: relative;
  aspect-ratio: 3 / 2;
  background: var(--frame);
  overflow: hidden;
  display: grid; place-items: center;
}
.frame__no {
  position: absolute; left: 5px; top: 4px; z-index: 3;
  font-family: var(--f-mono); font-size: 0.5625rem; font-weight: 500;
  letter-spacing: 0.08em; color: var(--edge-sheet); opacity: .85;
  font-variant-numeric: tabular-nums;
}
.frame img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Wax marks. Drawn over the emulsion, never inside it: the mark is the
   editor's decision, and it is reversible until the cut happens. */
.mark { position: absolute; inset: 0; z-index: 4; pointer-events: none; }
.mark path, .mark ellipse, .mark line {
  fill: none; stroke: var(--wax); stroke-width: 5;
  stroke-linecap: round; stroke-linejoin: round;
  opacity: .92;
}
.frame--cut { }
.frame--cut img { opacity: .3; filter: grayscale(1); }
.frame--keep::after {
  content: ""; position: absolute; inset: 0; z-index: 1;
  box-shadow: inset 0 0 0 2px var(--wax);
}

.strip__foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2) var(--s-4);
  padding: var(--s-3) var(--s-3) var(--s-2);
}
.strip__foot .edge { color: var(--edge-sheet); }
/* The caption is printed on the sheet, not on the paper, so it takes the
   on-sheet ink. Dark ink here was invisible in VIEWING LIGHT. */
.strip__caption {
  padding: 0 var(--s-3) var(--s-4);
  font-size: var(--t-small); color: var(--on-sheet-2); max-width: 56ch;
}
.strip__caption b { color: var(--on-sheet); font-weight: 700; }

/* The hero strip animates once: mark, then strike, then the cut frames fade.
   That is the product's whole mechanism, in order, and it is the only
   authored motion on the page. */
.hero .mark path, .hero .mark ellipse, .hero .mark line {
  stroke-dasharray: var(--len, 400);
  stroke-dashoffset: var(--len, 400);
  animation: draw .7s var(--ease) forwards;
  animation-delay: var(--d, .35s);
}
/* Path length and timing per frame. These were `style` attributes until the CSP
   (`style-src 'self'`) blocked them in production, which collapsed the whole sequence into
   six simultaneous marks at the fallback delay. The strip is a fixed six-frame composition,
   so position selectors are exact and the values cannot be blocked.
   The 0.09s stagger runs across all six positions and steps over the keeper's slot, so the
   strike sweeps the strip left to right and visibly passes the frame that was ringed. */
.hero .frame--cut .mark { --len: 150; }
.hero .frame--keep .mark { --len: 300; }
.hero .strip__frames .frame:nth-child(1) .mark { --d: .90s; }
.hero .strip__frames .frame:nth-child(2) .mark { --d: .99s; }
.hero .strip__frames .frame:nth-child(3) .mark { --d: .35s; }
.hero .strip__frames .frame:nth-child(4) .mark { --d: 1.17s; }
.hero .strip__frames .frame:nth-child(5) .mark { --d: 1.26s; }
.hero .strip__frames .frame:nth-child(6) .mark { --d: 1.35s; }
@keyframes draw { to { stroke-dashoffset: 0; } }
.hero .frame--cut img { animation: dim .5s var(--ease) forwards; animation-delay: 1.5s; opacity: 1; filter: none; }
@keyframes dim { to { opacity: .3; filter: grayscale(1); } }

@media (prefers-reduced-motion: reduce) {
  .hero .mark path, .hero .mark ellipse, .hero .mark line { animation: none; stroke-dashoffset: 0; }
  .hero .frame--cut img { animation: none; opacity: .3; filter: grayscale(1); }
}

/* ============================== proof rail ============================== */

.proof { margin-top: var(--s-8); }
.proof ul {
  display: grid; grid-template-columns: repeat(2, 1fr);
  margin: 0; padding: 0; list-style: none;
}
@media (min-width: 720px) { .proof ul { grid-template-columns: repeat(4, 1fr); } }
.proof li {
  padding: var(--s-5) var(--s-4) var(--s-5) 0;
  border-right: 1px solid var(--rule-soft);
  display: flex; flex-direction: column; gap: var(--s-1);
}
.proof li:last-child { border-right: 0; }
@media (max-width: 719px) {
  .proof li:nth-child(2n) { border-right: 0; }
  .proof li:nth-child(-n+2) { border-bottom: 1px solid var(--rule-soft); }
}
.proof b { font-weight: 700; font-size: var(--t-small); letter-spacing: -0.015em; }
.proof span { font-size: var(--t-small); color: var(--ink-3); }

/* =============================== sections =============================== */

.sec { padding-block: var(--s-9); }
.sec--ruled { padding-top: 0; }
.sec__head { max-width: 30ch; }
.sec h2 { font-size: var(--t-title); }
.sec__lede { margin-top: var(--s-5); max-width: 54ch; font-size: var(--t-lead); color: var(--ink-2); }

/* --------------------------- struck lines (§2) -------------------------- */

.struck {
  display: flex; flex-direction: column; gap: var(--s-4);
  font-size: var(--t-title); font-weight: 800; letter-spacing: -0.035em;
  line-height: 1.1; max-width: 20ch;
}
.struck span { position: relative; width: fit-content; color: var(--ink-3); }
.struck span::after {
  content: ""; position: absolute; left: -4px; right: -4px; top: 54%;
  height: 3px; background: var(--wax); transform: scaleX(1); transform-origin: left;
}
.struck span:last-child { color: var(--ink); }
.struck span:last-child::after { display: none; }
@keyframes strike { to { transform: scaleX(1); } }

/* Struck is the default so the lines read correctly with no JS at all. Where light.js ran,
   the pencil is held back until the block is on screen and then draws in the authored
   order — a mark nobody watches being made is not a mark, it is just a line. */
.js .struck span::after { transform: scaleX(0); }
/* Stagger lives here rather than in a `style` attribute, which the CSP blocks. */
.struck span:nth-child(1) { --d: .1s; }
.struck span:nth-child(2) { --d: .35s; }
.js .struck.is-marked span::after {
  animation: strike .5s var(--ease) forwards;
  animation-delay: var(--d, 0s);
}
@media (prefers-reduced-motion: reduce) {
  .js .struck span::after { transform: scaleX(1); }
  .js .struck.is-marked span::after { animation: none; }
}

/* ------------------------------ the sheet ------------------------------- */

.sheet { background: var(--sheet); color: var(--on-sheet); }
.sheet .sec__lede { color: var(--on-sheet-2); }
.sheet h2, .sheet h3 { color: var(--on-sheet); }

.sheet__grid {
  display: grid; gap: 3px; margin-top: var(--s-7);
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
@media (min-width: 700px) { .sheet__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1000px) { .sheet__grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.cell {
  position: relative; background: var(--frame);
  padding: var(--s-5) var(--s-4) var(--s-5);
  min-height: 200px;
  display: flex; flex-direction: column; gap: var(--s-3);
  transition: background .2s var(--ease);
}
.cell:hover { background: var(--frame-lit); }

/* The loupe. A contact sheet has exactly one gesture for "considering this frame" — you put
   the glass on it — and the sheet shipped without any inspect state at all. Crop brackets
   settle onto the frame's corners from just outside it. They are edge amber, not wax:
   hovering is not a decision, and the accent stays rationed to decisions. */
.cell::before, .cell::after {
  content: ""; position: absolute; width: 14px; height: 14px;
  border: 1px solid var(--edge-sheet); opacity: 0; pointer-events: none;
  transition: opacity .18s var(--ease), transform .18s var(--ease);
}
.cell::before { top: 7px; left: 7px; border-right: 0; border-bottom: 0; transform: translate(-3px, -3px); }
.cell::after { bottom: 7px; right: 7px; border-left: 0; border-top: 0; transform: translate(3px, 3px); }
.cell:hover::before, .cell:hover::after,
.cell:focus-within::before, .cell:focus-within::after { opacity: .85; transform: translate(0, 0); }
/* Reduced motion keeps the brackets — they are state, not decoration — and drops the travel. */
@media (prefers-reduced-motion: reduce) {
  .cell::before, .cell::after { transform: none; transition: opacity .18s var(--ease); }
}
.cell__no {
  font-family: var(--f-mono); font-size: 0.5625rem; font-weight: 500;
  letter-spacing: 0.08em; color: var(--edge-sheet); opacity: .8;
  font-variant-numeric: tabular-nums;
}
.cell h3 { font-size: 1.1875rem; font-weight: 750; letter-spacing: -0.025em; margin-top: auto; }
/* A tool with its own page makes the whole frame the target, so the heading stays a heading
   and the hit area is the tile rather than a line of text. */
.cell h3 a { text-decoration: none; }
.cell h3 a::after { content: ""; position: absolute; inset: 0; }
.cell h3 a:hover { color: var(--edge-sheet); }
.cell h3 a:focus-visible { box-shadow: none; }
.cell:has(h3 a:focus-visible) { box-shadow: var(--ring); }
.cell p { font-size: var(--t-small); color: var(--on-sheet-2); }
.cell--wide { grid-column: span 2; }
.cell svg.glyph { width: 30px; height: 30px; color: var(--edge-sheet); stroke-width: 1.4; }

/* ------------------------------ the passes ------------------------------ */

.passes { display: grid; gap: 0; margin-top: var(--s-7); }
@media (min-width: 760px) { .passes { grid-template-columns: repeat(3, 1fr); } }
.pass { padding: var(--s-6) var(--s-5) var(--s-6) 0; position: relative; }
.pass + .pass { padding-left: var(--s-5); }
@media (min-width: 760px) { .pass + .pass { border-left: 1px solid var(--rule-soft); } }
@media (max-width: 759px) { .pass + .pass { border-top: 1px solid var(--rule-soft); padding-left: 0; } }
.pass__mark { height: 44px; margin-bottom: var(--s-4); color: var(--wax); }
.pass h3 { font-size: var(--t-heading); }
.pass p { margin-top: var(--s-3); font-size: var(--t-small); color: var(--ink-2); }

/* ---------------------------- contact print ----------------------------- */

.contact { background: var(--sheet); color: var(--on-sheet); }
.contact h2 { color: var(--on-sheet); max-width: 17ch; }
.contact__body { margin-top: var(--s-5); max-width: 56ch; font-size: var(--t-lead); color: var(--on-sheet-2); }
.contact__body b { color: var(--on-sheet); font-weight: 700; }
.contact__grid { display: grid; gap: var(--s-7); margin-top: var(--s-8); }
@media (min-width: 900px) { .contact__grid { grid-template-columns: minmax(0, 1fr) 250px; gap: var(--s-8); align-items: start; } }

.test { padding: var(--s-6) 0 0; display: grid; gap: var(--s-4); }
.test::before {
  content: ""; display: block; height: 14px; margin-bottom: var(--s-2);
  background: repeating-linear-gradient(to right,
    transparent 0 7px, var(--sprocket) 7px 16px, transparent 16px 23px);
}
.test h3 { font-size: var(--t-heading); }
.test p { font-size: var(--t-small); color: var(--on-sheet-2); }
.test b { color: var(--on-sheet); }
.test__links { display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-5); }
.test__links a {
  display: inline-flex; align-items: center; min-height: 44px;
  color: var(--edge-sheet); font-weight: 600; font-size: var(--t-small);
  text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px;
}
.test__links a:hover { color: var(--wax); }

/* -------------------------- the two strips (§9) ------------------------- */

.arith { margin-top: var(--s-8); display: grid; gap: var(--s-7); }
.arith__row { min-width: 0; }
.arith__row > .edge { display: block; margin-bottom: var(--s-3); }
.arith__label {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s-2) var(--s-4);
  margin-bottom: var(--s-3);
}
.arith__label b { font-size: var(--t-heading); font-weight: 800; letter-spacing: -0.03em; }
.arith__label span { font-size: var(--t-small); color: var(--ink-3); }

/* The subscription strip does not end. It runs off the sheet, and that is the
   argument: 260 exposures where the other roll needed one. */
.roll {
  position: relative; background: var(--sheet);
  padding: 3px; min-width: 0; max-width: 100%;
}
/* The whole roll is printed. Its area against the single frame below is the
   argument, so it may not be clipped or faded out. */
.roll--long {
  display: grid; gap: 4px;
  grid-template-columns: repeat(auto-fill, minmax(28px, 1fr));
}
.roll--long > i { display: block; aspect-ratio: 3 / 2; background: var(--frame); }
.roll__frames { display: flex; gap: 3px; }
.roll__frames > div {
  flex: none; aspect-ratio: 3 / 2; background: var(--frame);
  display: grid; place-items: center;
  font-family: var(--f-mono); font-size: 0.625rem; font-weight: 500;
  color: var(--on-sheet-2); font-variant-numeric: tabular-nums;
}
.roll--one { width: fit-content; max-width: 100%; }
.roll--one { width: fit-content; }
.roll--one .roll__frames > div {
  width: clamp(132px, 15vw, 168px); background: var(--frame-lit); color: var(--on-sheet);
  font-size: var(--t-body); font-weight: 700; box-shadow: inset 0 0 0 2px var(--wax);
}
.arith__total {
  margin-top: var(--s-4); font-family: var(--f-mono); font-size: var(--t-small);
  font-weight: 600; letter-spacing: 0.02em; font-variant-numeric: tabular-nums;
  color: var(--ink-2);
}
.arith__total b { color: var(--ink); }
.arith__total .hot { color: var(--wax); }

.ledger { margin-top: var(--s-8); width: 100%; border-collapse: collapse; }
.ledger th, .ledger td { padding: var(--s-4) 0; border-bottom: 1px solid var(--rule-soft); }
.ledger thead th {
  font-family: var(--f-mono); font-size: var(--t-edge); font-weight: 500;
  letter-spacing: 0.10em; text-transform: uppercase; color: var(--ink-3);
  border-bottom: 1px solid var(--rule); text-align: right; padding-bottom: var(--s-3);
}
.ledger thead th:first-child { text-align: left; }
.ledger tbody th {
  text-align: left; font-size: var(--t-small); font-weight: 400; color: var(--ink-2);
  padding-right: var(--s-5);
}
.ledger td {
  font-family: var(--f-mono); font-size: var(--t-small); font-weight: 500;
  font-variant-numeric: tabular-nums; text-align: right;
  min-width: 7ch; padding-left: var(--s-5);
}
.ledger td:last-child { color: var(--wax); font-weight: 700; }

.free {
  margin-top: var(--s-7); padding: var(--s-6) var(--s-5);
  border: 1px solid var(--rule); background: var(--paper-2);
}
.free h3 { font-size: var(--t-heading); }
.free p { margin-top: var(--s-3); font-size: var(--t-small); color: var(--ink-2); max-width: 62ch; }

/* The full storefront price list — reference data, so it opens on request. */
.prices { margin-top: var(--s-6); border-top: 1px solid var(--rule-soft); }
.prices summary {
  min-height: 48px; display: flex; align-items: center;
  font-family: var(--f-mono); font-size: var(--t-edge); font-weight: 500;
  letter-spacing: 0.10em; text-transform: uppercase; color: var(--ink-3);
  cursor: pointer; list-style: none;
}
.prices summary::-webkit-details-marker { display: none; }
.prices summary::before { content: "+ "; }
.prices[open] summary::before { content: "\2212 "; }
.prices summary:hover { color: var(--wax); }
.prices__note { max-width: 62ch; font-size: var(--t-small); color: var(--ink-2); }
.prices__note b { color: var(--ink); }
.prices .ledger { margin-top: var(--s-5); }
.prices .ledger tbody th { padding-block: var(--s-3); }
/* Reference prices, not the decision — the wax stays spent on the one headline price. */
.prices .ledger td { padding-block: var(--s-3); white-space: nowrap; color: var(--ink); font-weight: 500; }

/* --------------------------------- FAQ ---------------------------------- */

.faq__list { margin-top: var(--s-6); max-width: 74ch; }
.faq details { border-bottom: 1px solid var(--rule-soft); }
.faq summary {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-4);
  min-height: 64px; padding-block: var(--s-4);
  font-size: var(--t-body); font-weight: 650; letter-spacing: -0.02em;
  cursor: pointer; list-style: none;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: ""; flex: none; width: 13px; height: 13px;
  background: var(--ink-3);
  -webkit-mask: linear-gradient(#000 0 0) center/13px 2px no-repeat, linear-gradient(#000 0 0) center/2px 13px no-repeat;
  mask: linear-gradient(#000 0 0) center/13px 2px no-repeat, linear-gradient(#000 0 0) center/2px 13px no-repeat;
  transition: transform .2s var(--ease), background .16s var(--ease);
}
.faq details[open] summary::after {
  transform: rotate(90deg); background: var(--wax);
  -webkit-mask: linear-gradient(#000 0 0) center/13px 2px no-repeat;
  mask: linear-gradient(#000 0 0) center/13px 2px no-repeat;
}
.faq summary:hover { color: var(--wax); }
.faq details p { padding-bottom: var(--s-4); color: var(--ink-2); max-width: 66ch; font-size: var(--t-small); }
.faq details p + p { padding-top: var(--s-3); }
.faq__more { margin-top: var(--s-6); font-size: var(--t-small); color: var(--ink-2); }
.faq__more a { color: var(--wax); text-underline-offset: 3px; }
@media (prefers-reduced-motion: reduce) { .faq summary::after { transition: none; } }

/* ------------------------------ closing bill ---------------------------- */

.close { background: var(--sheet); color: var(--on-sheet); text-align: left; }
.close h2 { color: var(--on-sheet); font-size: var(--t-title); max-width: 18ch; }
.close p { margin-top: var(--s-5); max-width: 50ch; color: var(--on-sheet-2); font-size: var(--t-lead); }
.close .hero__actions { margin-top: var(--s-7); }
.close .hero__price { color: var(--on-sheet); }
.close .hero__price span { color: var(--on-sheet-2); }

/* =============================== footer ================================= */

.footer { padding-block: 0 var(--s-6); }
.footer__top {
  display: flex; flex-wrap: wrap; gap: var(--s-5);
  align-items: center; justify-content: space-between;
  padding-bottom: var(--s-5); border-bottom: 1px solid var(--rule-soft);
}
.footer nav ul { display: flex; flex-wrap: wrap; gap: 0 var(--s-5); margin: 0; padding: 0; list-style: none; }
.footer nav a {
  display: inline-flex; align-items: center; min-height: 44px;
  font-family: var(--f-mono); font-size: var(--t-edge); font-weight: 500;
  letter-spacing: 0.10em; text-transform: uppercase;
  color: var(--ink-2); text-decoration: none;
  border-bottom: 2px solid transparent;
}
.footer nav a:hover { color: var(--ink); border-bottom-color: var(--wax); }
.footer__legal { margin-top: var(--s-5); font-size: var(--t-small); color: var(--ink-3); max-width: 64ch; }
.footer__legal p + p { margin-top: var(--s-2); }
.footer__stamp {
  margin-top: var(--s-5); display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-5);
}

/* ========================== legal & guide pages ========================= */

.legal { padding-block: var(--s-8) var(--s-9); }
.legal__inner > * { max-width: var(--w-prose); }

.legal h1 { font-size: var(--t-title); max-width: 20ch; }
.legal h2 {
  font-size: var(--t-heading); font-weight: 800; letter-spacing: -0.03em;
  margin-top: var(--s-8); padding-top: var(--s-5); border-top: 1px solid var(--rule);
}
.legal h3 { font-size: 1.1875rem; font-weight: 700; letter-spacing: -0.02em; margin-top: var(--s-6); }
.legal h4 { font-size: var(--t-body); font-weight: 700; margin-top: var(--s-5); }

.legal p, .legal ul, .legal ol { margin-top: var(--s-4); }
.legal h1 + p, .legal h2 + p, .legal h3 + p, .legal h4 + p { margin-top: var(--s-3); }
.legal ul, .legal ol { padding-left: var(--s-5); }
.legal li { margin-top: var(--s-2); }
.legal li > ul, .legal li > ol { margin-top: var(--s-2); }
.legal li::marker { color: var(--wax); }

.legal a {
  color: var(--ink); text-decoration: underline;
  text-decoration-color: var(--wax); text-decoration-thickness: 2px; text-underline-offset: 3px;
}
.legal a:hover { color: var(--wax); }

.legal hr { border: 0; border-top: 1px solid var(--rule); margin-block: var(--s-7); }

.legal blockquote {
  margin: var(--s-5) 0; padding: var(--s-5);
  background: var(--paper-2); border-left: 1px solid var(--wax);
}
.legal blockquote > :first-child { margin-top: 0; }

.legal code {
  font-family: var(--f-mono); font-size: 0.82em; padding: 0.12em 0.35em;
  background: var(--paper-2); border: 1px solid var(--rule-soft);
  overflow-wrap: anywhere; /* API names like NSLocationWhenInUseUsageDescription outrun 320px */
}

.legal .tablewrap { overflow-x: auto; margin-top: var(--s-5); }
.legal table { border-collapse: collapse; width: 100%; min-width: 480px; font-size: var(--t-small); }
.legal th, .legal td {
  text-align: left; vertical-align: top;
  padding: var(--s-3); border-bottom: 1px solid var(--rule-soft);
}
.legal th { font-weight: 700; }
.legal thead th { border-bottom: 1px solid var(--rule); }
.legal td { font-variant-numeric: tabular-nums; }

.legal__meta { margin-top: var(--s-4); font-size: var(--t-small); color: var(--ink-2); }
.legal__meta b { color: var(--ink); font-weight: 700; }

.crumbs { margin-bottom: var(--s-5); font-family: var(--f-mono); font-size: var(--t-edge);
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-3); }
.crumbs a { color: var(--ink-2); text-decoration: none;
  display: inline-flex; align-items: center; min-height: 24px; }
.crumbs a:hover { color: var(--wax); }
.crumbs span { margin-inline: var(--s-2); color: var(--ink-3); }

.toc { margin-top: var(--s-6); padding: var(--s-5) 0 0; }
.toc::before {
  content: ""; display: block; height: 14px; margin-bottom: var(--s-4);
  background: repeating-linear-gradient(to right,
    transparent 0 7px, var(--sprocket) 7px 16px, transparent 16px 23px);
}
.toc h2 {
  margin: 0; padding: 0; border: 0;
  font-family: var(--f-mono); font-size: var(--t-edge); font-weight: 500;
  letter-spacing: 0.10em; text-transform: uppercase; color: var(--ink-3);
}
/* Every heading already carries its own number, so the list must not add one. */
.toc ol { margin-top: var(--s-3); padding-left: 0; list-style: none; }
.toc li { margin-top: 0; }
.toc a { color: var(--ink); text-decoration: none;
  display: inline-block; padding-block: 4px; }
.toc a:hover { color: var(--wax); text-decoration: underline; }

.legal h2[id], .legal h3[id] { scroll-margin-top: 78px; }

.guide .device { max-width: 260px; margin: var(--s-6) auto; }
.guide__next { font-size: var(--t-small); }
.guide__next a { color: var(--wax); }

.guidelist { list-style: none; padding: 0; margin-top: var(--s-6); }
.guidelist li { padding: var(--s-5) 0; border-top: 1px solid var(--rule); }
.guidelist li:last-child { border-bottom: 1px solid var(--rule); }
.guidelist h2, .guidelist h3 {
  margin: 0; padding: 0; border: 0;
  font-size: var(--t-heading); font-weight: 800; letter-spacing: -0.03em;
}
.guidelist h2 a, .guidelist h3 a { text-decoration: none; }
.guidelist h2 a:hover, .guidelist h3 a:hover { color: var(--wax); }
.guidelist p { margin-top: var(--s-3); color: var(--ink-2); font-size: var(--t-small); }

/* --------------------------- framed screenshots ------------------------- */

.device { margin: 0; }
.device img, .device video {
  display: block; width: 100%; height: auto;
  background: var(--sheet);
}
.device figcaption {
  margin-top: var(--s-3); font-family: var(--f-mono); font-size: var(--t-edge);
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-3); text-align: center;
}
.contact .device figcaption, .sheet .device figcaption { color: var(--on-sheet-2); }

/* ------------------------------- press kit ------------------------------ */

.legal a.dl {
  display: inline-flex; align-items: center; min-height: 48px;
  padding: 0 var(--s-5);
  background: var(--wax); color: var(--wax-ink);
  font-weight: 700; font-size: var(--t-small); text-decoration: none;
}
.legal a.dl:hover { filter: brightness(1.08); color: var(--wax-ink); }

.assetlist { list-style: none; padding: 0; }
.assetlist li { margin-top: var(--s-2); }
.assetlist a { display: inline-flex; align-items: center; min-height: 44px; }

.shots { display: grid; gap: 3px; margin-top: var(--s-5); grid-template-columns: repeat(2, 1fr); }
@media (min-width: 700px) { .shots { grid-template-columns: repeat(3, 1fr); } }
.legal__inner > .shots { max-width: none; }

/* --------------------------------- 404 ---------------------------------- */

.notfound { padding-block: var(--s-9); }
.notfound h1 { font-size: var(--t-display); max-width: 12ch; }
.notfound p { margin-top: var(--s-5); font-size: var(--t-lead); color: var(--ink-2); max-width: 48ch; }

/* ====================== badge, sheet-aware; frame data ================== */

/* The App Store lockup follows the reading light, not the OS: a manual switch
   means prefers-color-scheme can no longer answer this on its own. */
/* Specificity note: `.badge img` is (0,1,1) and beats a bare `.badge--dk`,
   so every rule in this swap has to carry the element too or it loses. */
.badge { position: relative; }
.badge img.badge--dk { display: none; }
:root[data-light="safelight"] .badge img.badge--lt { display: none; }
:root[data-light="safelight"] .badge img.badge--dk { display: block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-light="viewing"]) .badge img.badge--lt { display: none; }
  :root:not([data-light="viewing"]) .badge img.badge--dk { display: block; }
}
/* On the black sheet the white lockup always wins, whatever the room. */
.sheet .badge img.badge--lt, .contact .badge img.badge--lt, .close .badge img.badge--lt { display: none; }
.sheet .badge img.badge--dk, .contact .badge img.badge--dk, .close .badge img.badge--dk { display: block; }

figure { margin: 0; }

.frame__meta {
  display: grid; gap: 2px; place-items: center;
  font-family: var(--f-mono); font-variant-numeric: tabular-nums;
  text-align: center; padding: var(--s-2); line-height: 1.35;
}
.frame__meta b { font-size: 0.6875rem; font-weight: 600; color: var(--on-sheet); letter-spacing: -0.01em; }
.frame__meta span { font-size: 0.5625rem; font-weight: 400; color: var(--on-sheet-2); letter-spacing: 0.03em; }
.frame--cut .frame__meta { opacity: .42; }
.hero .frame--cut .frame__meta { animation: dimmeta .5s var(--ease) 1.5s forwards; opacity: 1; }
@keyframes dimmeta { to { opacity: .42; } }
@media (prefers-reduced-motion: reduce) {
  .hero .frame--cut .frame__meta { animation: none; opacity: .42; }
}

.strip { align-self: stretch; }
@media (min-width: 940px) { .strip { align-self: end; } }

.ledger caption { text-align: left; padding-bottom: var(--s-4); color: var(--ink-3); }
.sec__note { margin-top: var(--s-4); max-width: 56ch; font-size: var(--t-small); color: var(--ink-3); }


/* Back to top. One frame laid over whatever it passes: emulsion ground, and the light
   switch's hairline so the edge still reads over the black sheet in either room. */
.totop {
  position: fixed; z-index: 40;
  right: var(--gutter); bottom: calc(var(--gutter) + env(safe-area-inset-bottom, 0px));
  display: grid; place-items: center;
  width: 44px; height: 44px; padding: 0;
  appearance: none; cursor: pointer;
  background: var(--frame); color: var(--on-sheet);
  border: 1px solid var(--sheet-rule);
  opacity: 0; visibility: hidden;
  transition: opacity .2s var(--ease), visibility 0s linear .2s, background .16s var(--ease);
}
.totop.is-shown { opacity: 1; visibility: visible; transition-delay: 0s; }
.totop:hover { background: var(--frame-lit); }
@media (prefers-reduced-motion: reduce) { .totop { transition: none; } }
