/* Little Me — the app's own design language, on the web.
   Tokens are lifted from LittleMe/DesignSystem/MemoryCameraTheme.swift so the site and the app
   cannot drift into two different products: same ink, same paper, same drape, same handwriting. */

/* The app's own five faces, three of which are bundled OFL files we already ship in the binary:
   Lora Medium Italic is the wordmark, Newsreader Medium is every headline, Caveat is the
   signature. Body text and machine labels are SF Pro and SF Mono, which the system provides.
   Headings were coming out in SF Pro before this — a sans where the app sets a serif, which is
   exactly the "doesn't look like the app" you notice without being able to name. */
@font-face {
  font-family: "Lora";
  src: url("assets/lora-italic.ttf") format("truetype");
  font-weight: 500; font-style: italic; font-display: swap;
}
@font-face {
  font-family: "Newsreader";
  src: url("assets/newsreader.ttf") format("truetype");
  font-weight: 500; font-display: swap;
}
@font-face {
  font-family: "Caveat";
  src: url("assets/caveat.ttf") format("truetype");
  font-weight: 500;
  font-display: swap;                  /* the page reads before the signature arrives */
}

:root {
  color-scheme: light;
  --ink: #24242a;
  --on-ink: #f4f4f6;
  --muted: rgba(36, 36, 42, .72);
  --faint: rgba(36, 36, 42, .45);
  --hair: rgba(36, 36, 42, .12);
  --card: rgba(255, 255, 255, .55);
  --paper: #ffffff;
  --drape-deep: #b4b8c4;               /* CurtainStyle.studio */
  --drape-lit: #edeef3;
  --glow: #f8faff;
  --measure: 68ch;
  --page: 1100px;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, system-ui, sans-serif;
  --display: "Newsreader", ui-serif, Georgia, serif;
  --brand: "Lora", ui-serif, Georgia, serif;
}


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

/* The width/height attributes on every <img> are there so the browser reserves the right box before
   the file arrives — but the HTML spec maps them to presentational hints on the CSS width and
   height properties. Overriding width without height lets the intrinsic height win, which is how a
   square polaroid came out four times taller than it was wide. */
img { max-width: 100%; height: auto; display: block; }

/* The drape is `position: fixed`, so it covers the VISUAL viewport and nothing else — not the
   rubber-band overscroll at either end, and not the strip iOS exposes as its chrome slides away.
   Those fell through to the body's flat `--drape-lit` and read as the background dropping out.
   The fix is that the fold pattern is a 90deg repeating gradient: constant in Y, so painting the
   same stack on the root matches the drape at any scroll offset. Only the warm highlight and the
   vignette stay up in .drape, and both are too soft to see a seam in.
   `overflow-x: clip` (not hidden) contains the 100vw marquee where a classic scrollbar takes real
   width, without making the root a scroll container and breaking the sticky header. */
html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  overflow-x: clip;
  background:
    repeating-linear-gradient(90deg,
      rgba(180, 184, 196, .55) 0px,
      rgba(237, 238, 243, .55) 34px,
      rgba(180, 184, 196, .55) 78px,
      rgba(196, 200, 210, .35) 96px,
      rgba(180, 184, 196, .55) 118px),
    var(--drape-lit);
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
  /* Killing the animation would leave the strip frozen mid-slide and the hero blank, so both fall
     back to something usable: a strip you scroll yourself, and the first print, held. */
  .marquee { overflow-x: auto; -webkit-mask-image: none; mask-image: none; }
  .track { animation: none; }
  .frames img { animation: none; }
  .frames img:first-child { opacity: 1; }
}

body {
  margin: 0;
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.6;
  color: var(--ink);
  /* Transparent, so the root's copy of the fold pattern shows through. A background here is opaque
     over the root's for the whole document height, which is what left the overscroll flat. */
  background: transparent;
  -webkit-font-smoothing: antialiased;
}

/* The drape. The app draws it as layered sines in a Canvas; here it is three gradients, which
   costs nothing to download and reads the same at a glance. A 4.6 MB PNG of the real thing was
   the alternative. */
.drape {
  position: fixed;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(60% 45% at 58% 22%, rgba(255, 233, 201, .30), transparent 70%),
    linear-gradient(to bottom, rgba(248, 250, 255, .32), transparent 55%),
    /* Broad, low-contrast folds. The first attempt used a 26px period at full deep-to-lit range and
       read as corrugated metal rather than fabric; the app's own drape is mostly wide and quiet with
       a few crease harmonics. */
    repeating-linear-gradient(90deg,
      rgba(180, 184, 196, .55) 0px,
      rgba(237, 238, 243, .55) 34px,
      rgba(180, 184, 196, .55) 78px,
      rgba(196, 200, 210, .35) 96px,
      rgba(180, 184, 196, .55) 118px),
    var(--drape-lit);
}
.drape::after {                         /* the edge vignette */
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, rgba(0,0,0,.10), transparent 12%, transparent 88%, rgba(0,0,0,.10));
}

/* ---- type ------------------------------------------------------------------------------- */

h1, h2, h3 {
  font-family: var(--display);
  font-weight: 500;                    /* Newsreader Medium, as the app sets it */
  line-height: 1.14;
  letter-spacing: -0.015em;
  margin: 0 0 .5em;
}
h1 { font-size: clamp(2.6rem, 6.2vw, 4.2rem); }
h2 { font-size: clamp(1.7rem, 3.4vw, 2.4rem); }
h3 { font-size: 1.2rem; letter-spacing: -0.005em; }
p  { margin: 0 0 1em; }
a  { color: var(--ink); text-underline-offset: .18em; text-decoration-thickness: 1px; }
a:hover { text-decoration-thickness: 2px; }

.kicker {                                /* the app's "machine label" voice */
  font-family: var(--mono);
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--faint);
  margin: 0 0 1.2em;
}
.lede { font-size: clamp(1.05rem, 2vw, 1.25rem); color: var(--muted); max-width: var(--measure); }
.hand { font-family: "Caveat", cursive; font-weight: 500; }

/* No page here carries a style="" attribute, and none may: the CSP in _headers sets
   style-src 'self' with no 'unsafe-inline', so production silently dropped every one of them
   while they worked over a local file server. The closing paragraph lost its auto margins, the
   footer nav lost its flex row, and all eight hero frames lost their --i and animated as one.
   These are the rules those attributes used to carry. */
.section-lede { margin-bottom: 2.6rem; }
.looks-note    { margin-top: 2rem; }
.more-link     { margin-top: 2rem; }

/* A heading sitting directly on a row of cards reads as a label for the first card rather than
   for the group. Where a paragraph intervenes it already has the room. */
h2 + .steps, h2 + .looks { margin-top: 2.2rem; }

/* ---- layout ----------------------------------------------------------------------------- */

/* The insets are 0 in portrait, so this changes nothing on the common case; it keeps text off the
   notch when a phone is turned sideways, which `viewport-fit=cover` otherwise allows. */
.wrap {
  width: min(100% - 2.5rem - env(safe-area-inset-left) - env(safe-area-inset-right), var(--page));
  margin-inline: auto;
}
section { padding: clamp(2.6rem, 6vw, 5rem) 0; }
.center { text-align: center; }
.center .lede, .center .kicker { margin-inline: auto; }

/* The app's chrome is clear glass and mono capitals — IconPill, the GET chip, SEE THE OTHERS.
   A row of plain sans links over the drape read like a template; this is the same material and the
   same voice, floating over the fabric rather than sitting on it. */
header.site {
  position: sticky;
  top: .75rem;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: .75rem;
  /* Symmetric. It was 1.1rem on the left for the wordmark and 0.6 on the right, which the
     language picker's own padding hid on the landing page — but privacy and support have no
     picker, so their last nav link sat right against the edge. */
  padding: .5rem 1.15rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, .62);
  border: 1px solid rgba(255, 255, 255, .75);
  box-shadow: 0 1px 0 rgba(255,255,255,.6) inset, 0 8px 24px rgba(36, 36, 42, .10);
  backdrop-filter: saturate(140%) blur(14px);
  -webkit-backdrop-filter: saturate(140%) blur(14px);
}
.mark { display: inline-flex; align-items: center; gap: .55rem; color: var(--ink); text-decoration: none; }
/* Lora Medium Italic — the app's wordmark, the same face on the same two words. */
.mark strong { font-family: var(--brand); font-style: italic; font-weight: 500; font-size: 1.12rem; letter-spacing: 0; }
.mark img { height: 26px; width: auto; }
footer.site .mark img { height: 24px; }
header.site nav { display: flex; gap: 1.5rem; }
header.site nav a {
  text-decoration: none;
  color: var(--faint);
  font-family: var(--mono);
  font-size: .66rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  transition: color .16s ease;
}
header.site nav a:hover { color: var(--ink); }
/* Four links plus the wordmark do not fit ~350px of usable width. How it works and Examples are
   scroll shortcuts on a page you can thumb through in a second; Privacy and Support are the two
   the App Store requires to be findable, so those are the two that stay.
   Named one by one, not by `[href^="#"]`: Privacy on this page IS an in-page anchor, so that
   selector hid it too and left mobile with a single link where the comment promised two. */
@media (max-width: 620px) {
  header.site { padding: .55rem .9rem; }
  header.site nav a[href="#how"], header.site nav a[href="#gallery"] { display: none; }
  header.site nav { gap: 1.1rem; }
}

/* ---- the polaroid ------------------------------------------------------------------------ */

/* Same proportions as the print: 6% border on three sides, a 22% chin that IS the bottom margin.
   See PolaroidGeometry in LittleMeAPI — change one, change both. */
/* The border is on the PHOTO, not the card. A percentage padding on the card resolves against its
   containing block, not itself — so the same 6% became 18px inside a grid column and 66px inside a
   centred 300px card, and the closing polaroid came out with a stamp-sized picture in a wide mat.
   Margins on the photo resolve against the figure's own width, which is the thing we mean. */
.polaroid {
  background: var(--paper);
  padding: 0;
  border-radius: 4px;
  box-shadow: 0 2px 3px rgba(0,0,0,.10), 0 16px 26px rgba(0,0,0,.20);
  display: block;
  width: 100%;
}
.polaroid img { width: 88%; height: auto; margin: 6% 6% 0; aspect-ratio: 1; object-fit: cover; border-radius: 2px; }
.polaroid figcaption {
  font-family: "Caveat", cursive;
  /* Container-relative, like the chin above it. A vw-based clamp sized the signature against the
     WINDOW while the paper it sits on is sized by its column, so the big hero print got the small
     end of the clamp and the little marquee prints got the large end — backwards, and worst on a
     phone, where the hero fills the screen and the caption was still on its 1.1rem floor.
     0.44 × 0.22 = 0.0968: `PolaroidGeometry.captionOfChin` times the chin, the app's own number. */
  font-size: 9.68cqw;
  color: rgba(36, 36, 42, .62);
  text-align: center;
  /* The print's chin is 0.25 × the photo's side, and the photo is 0.88 of the card. */
  height: 22cqw;
  display: grid;
  place-items: center;
  /* One line, like the print: the chin is a fixed 22cqw, so a caption that wrapped would push its
     second line off the paper. `PolaroidComposer` shrinks instead; CSS cannot, so the captions on
     this page are chosen to fit and this keeps a longer one from breaking the card silently. */
  white-space: nowrap;
}
.polaroid { container-type: inline-size; }
.tilt-l { transform: rotate(-2deg); }
.tilt-r { transform: rotate(1.5deg); }

/* ---- hero ------------------------------------------------------------------------------- */

.hero { display: grid; gap: clamp(2rem, 5vw, 4rem); align-items: center; }
@media (min-width: 860px) { .hero { grid-template-columns: 1.05fr .95fr; } }
.hero .polaroid { max-width: 420px; margin-inline: auto; }
/* The shared .5em is a paragraph gap; under a 67px display face it measures 34px and the lede
   stops reading as the headline's own second breath. Scaled to the title, not to the body. */
.hero h1 { margin-bottom: .28em; }

.cta { display: flex; flex-wrap: wrap; gap: .8rem; align-items: center; margin-top: 1.8rem; }
.btn {
  display: inline-flex; align-items: center; gap: .5rem;
  background: var(--ink); color: var(--on-ink);
  padding: .85rem 1.5rem; border-radius: 999px;
  font-weight: 600; font-size: .98rem; text-decoration: none;
  box-shadow: 0 6px 16px rgba(0,0,0,.22);
}
.btn:hover { background: #35353d; }
.btn[aria-disabled="true"] { background: rgba(36,36,42,.16); color: rgba(36,36,42,.62); box-shadow: none; cursor: default; }
/* The app's own facts, in the app's machine-label voice — the same row Ago carries under its
   badge. They replace a "iPhone · iOS 26" line that told a visitor nothing they had not worked out
   from the App Store button directly above it. */
.hero-meta { display: flex; flex-direction: column; gap: .45rem; margin-top: 1.6rem; }
.hero-meta span {
  display: inline-flex; align-items: center; gap: .45rem;
  font-family: var(--mono); font-size: .64rem; font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase; color: var(--faint);
}
.hero-meta svg { width: 13px; height: 13px; }

.closing { text-align: center; }
.closing .polaroid { max-width: 268px; margin: 0 auto 2rem; }
.closing .lede { margin: 0 auto 1.8rem; }
.closing .app-store { margin-top: .4rem; }
.closing .fineprint {
  max-width: 58ch; margin: 1.5rem auto 0;
  font-size: .92rem; color: var(--muted);
}

/* ---- steps ------------------------------------------------------------------------------ */

.steps { display: grid; gap: 1.6rem; counter-reset: step; }
@media (min-width: 760px) { .steps { grid-template-columns: repeat(3, 1fr); gap: 2.2rem; } }
.step { background: var(--card); border: 1px solid var(--hair); border-radius: 18px; padding: 1.6rem; backdrop-filter: blur(6px); }
.step::before {
  counter-increment: step; content: counter(step, decimal-leading-zero);
  font-family: var(--mono); font-size: .72rem; letter-spacing: .18em;
  color: var(--faint); display: block; margin-bottom: .9rem;
}
.step p { margin: 0; color: var(--muted); font-size: .96rem; }

/* ---- gallery ---------------------------------------------------------------------------- */

/* The home screen's carousel, on the web. Full-bleed so the prints run off both edges the way
   they do in the app, and printed twice so the wrap has no seam.

   It does NOT pause on hover. That seemed considerate and was not: the strip is full-bleed and
   tall, so a cursor left anywhere near the middle of the window while reading stopped it dead —
   which reads as the animation stuttering rather than as a feature. It runs, always. */
.marquee {
  width: 100vw;
  margin-left: calc(50% - 50vw);
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
}
.track {
  display: flex;
  /* The floor was 1.2rem, which on a phone put a 19px trough between 200px prints — the strip read
     as separated cards rather than as one shelf of photographs. The ceiling is unchanged. */
  gap: clamp(.75rem, 2.4vw, 2rem);
  width: max-content;
  padding: clamp(1rem, 2vw, 1.4rem) 0 clamp(1.5rem, 3vw, 2.2rem);
  animation: marquee 64s linear infinite;
}
.track .polaroid { width: clamp(200px, 21vw, 250px); flex: none; }
.track .polaroid:nth-child(3n)   { transform: rotate(1.4deg); }
.track .polaroid:nth-child(3n+1) { transform: rotate(-1.6deg); }
@keyframes marquee { to { transform: translate3d(-50%, 0, 0); } }

/* ---- the hero print, changing its mind ----------------------------------------------------- */

.frames { position: relative; aspect-ratio: 1; }
.frames img {
  position: absolute; inset: 0; margin: 0;
  width: 100%; height: 100%;
  opacity: 0;                              /* the base state, so nothing stacks before its turn */
  animation: cycle 32s ease-in-out infinite;
  animation-delay: calc(var(--i) * 4s);
}
/* The turn each frame waits for. This was a style="--i:N" on every <img> until the CSP ate it and
   left all eight sharing a 0s delay, which is one image with seven invisible ones behind it. */
.frames img:nth-child(1) { --i: 0 }
.frames img:nth-child(2) { --i: 1 }
.frames img:nth-child(3) { --i: 2 }
.frames img:nth-child(4) { --i: 3 }
.frames img:nth-child(5) { --i: 4 }
.frames img:nth-child(6) { --i: 5 }
.frames img:nth-child(7) { --i: 6 }
.frames img:nth-child(8) { --i: 7 }
@keyframes cycle {
  0%    { opacity: 0 }
  2.2%  { opacity: 1 }
  12.5% { opacity: 1 }
  14.7% { opacity: 0 }
  100%  { opacity: 0 }
}
.hero-cycle .frames { margin: 6% 6% 0; width: 88%; border-radius: 2px; overflow: hidden; }

/* ---- looks ------------------------------------------------------------------------------ */

.looks { display: grid; gap: 2rem; }
@media (min-width: 760px) { .looks { grid-template-columns: 1fr 1fr; } }
/* The files are 4:3, and at full column width that made these the tallest images on the page —
   534×401 on a desktop, taller than the hero print, and two of them stacked on a phone. Cropped
   to 3:2 they are a band the eye passes over instead of two portraits it has to scroll past.
   `object-fit: cover` keeps the centre, which is where both faces are. */
.look img {
  width: 100%; display: block;
  aspect-ratio: 3 / 2; object-fit: cover;
  border-radius: 14px; box-shadow: 0 10px 24px rgba(0,0,0,.16);
}
.look h3 { margin: 1rem 0 .3rem; }
.look p { color: var(--muted); font-size: .96rem; margin: 0; }

/* ---- promises --------------------------------------------------------------------------- */

.promises { display: grid; gap: 1.2rem; }
@media (min-width: 760px) { .promises { grid-template-columns: repeat(2, 1fr); gap: 1.4rem 2.4rem; } }
.promise { display: flex; gap: .85rem; align-items: flex-start; }
.promise svg { flex: none; width: 20px; height: 20px; margin-top: .22rem; color: var(--faint); }
.promise p { margin: 0; font-size: .97rem; color: var(--muted); }
.promise strong { color: var(--ink); font-weight: 620; }

/* ---- prose (privacy, support) ------------------------------------------------------------ */

.prose { max-width: var(--measure); }
/* A policy page is not the landing page: the h1 is a document title, not a headline. */
.prose h1 { font-size: clamp(2rem, 4.5vw, 2.8rem); }
.prose h2 { margin-top: 2.4em; font-size: 1.35rem; }
.prose h2:first-of-type { margin-top: 1em; }
.prose ul { padding-left: 1.15em; margin: 0 0 1em; }
.prose li { margin-bottom: .45em; }
.prose .updated { font-family: var(--mono); font-size: .72rem; letter-spacing: .14em; text-transform: uppercase; color: var(--faint); }
.prose table { border-collapse: collapse; width: 100%; margin: 0 0 1.5em; font-size: .93rem; }
.prose th, .prose td { text-align: left; padding: .6rem .8rem; border-bottom: 1px solid var(--hair); vertical-align: top; }
.prose th { font-family: var(--mono); font-size: .68rem; letter-spacing: .12em; text-transform: uppercase; color: var(--faint); font-weight: 600; }
.prose .table-scroll { overflow-x: auto; }

/* ---- footer ----------------------------------------------------------------------------- */

footer.site { border-top: 1px solid var(--hair); padding: 2.4rem 0 3.4rem; margin-top: 2rem; }
footer.site .row { display: flex; flex-wrap: wrap; gap: 1rem 1.6rem; align-items: center; justify-content: space-between; }
footer.site nav { display: flex; gap: 1.4rem; flex-wrap: wrap; }
footer.site a { color: var(--muted); text-decoration: none; font-size: .92rem; }
footer.site a:hover { color: var(--ink); text-decoration: underline; }
footer.site .fine { font-size: .82rem; color: var(--faint); margin: 1.2rem 0 0; }


/* ---- header controls: language + theme, the same pair the other sites carry ---------------- */

/* Only the language picker lives here. There is no theme switch: the app has no
   selectable dark mode — its darkroom is a state the create flow passes through, not a
   preference — and a control on the site with nothing behind it in the product is chrome. */
.controls { display: flex; align-items: center; gap: .6rem; }
.lang-select {
  font-family: var(--mono); font-size: .66rem; font-weight: 600; letter-spacing: .12em;
  color: var(--faint);
  background: rgba(255, 255, 255, .7); border: 1px solid rgba(36, 36, 42, .10);
  border-radius: 999px; padding: .4rem .55rem; cursor: pointer; line-height: 1.3;
  transition: color .16s ease, border-color .16s ease;
}
.lang-select:hover { border-color: var(--ink); color: var(--ink); }

/* ---- App Store badge ----------------------------------------------------------------------- */

/* Apple's own artwork, the same file and the same treatment as the PetCard site — the badge is
   Apple's to draw, and a hand-built lookalike is both off-guideline and visibly not it. */
.app-store { display: inline-flex; text-decoration: none; border-radius: 10px; transition: transform .18s cubic-bezier(.2,.8,.2,1); }
.app-store img { height: 52px; width: auto; display: block; }
@media (hover: hover) { .app-store:hover { transform: translate3d(0,-2px,0); } }
.app-store:active { transform: translate3d(0,0,0) scale(.99); }

