/* Peter — homepage. Rebuilt 2026-10-19 on tiimoapp.com's structure and
   measurements (1440px reference: 15px base, 1125px column, 4em/2em section
   padding, 16px radii, pill buttons), in Peter's own type and brand blue.
   Every size is in em off the body's font-size, as the reference does, so
   the whole page scales with it: 14px → 15px at 1440 → 16px at 1920. */

:root {
  --ink: #161212;               /* headings */
  --heading: #161613;           /* dark buttons */
  --paragraph: rgba(22, 22, 19, 0.75);
  --muted: rgba(22, 22, 19, 0.5);
  --page: #fcfcfc;             /* Tiimo's page white: the pure-white FAQ box and cards read against it */
  --rule: rgba(22, 22, 19, 0.13);
  --line: #302828;              /* bordered buttons */
  --radius: 16px;

  /* Brand: Peter blue #5F72F6 and tints of it, standing in for the
     reference's lavender family one for one. */
  --brand: #5f72f6;
  --brand-soft: #aab6fb;        /* footer wash   ← #bcaaff */
  --brand-tint: #e8ecfe;        /* reviews body  ← #ece7ff */
  --pill-light: #e3e7fb;        /* light pill    ← #e5e0da */
  --ph: rgba(95, 114, 246, 0.07); /* blank asset slots */
  /* Grain texture laid (soft-light) over every coloured area. */
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");

  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  --sans: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", Arial, sans-serif;
  --ease-io: cubic-bezier(0.645, 0.045, 0.355, 1);
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
section, footer { scroll-margin-top: 1em; }
body {
  margin: 0;
  font-family: var(--sans);
  font-size: 14px;
  line-height: 1.6em;
  color: var(--paragraph);
  background-color: var(--page);
  /* No paper grain: it read as grey (user, 2026-10-19). */
  /* The lavender tint for the problems band eases in slowly (0.5s read as abrupt on pure white, 1.4s as sluggish). */
  transition: background-color 0.9s cubic-bezier(0.45, 0, 0.25, 1);
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}
/* The reference turns the whole page lavender while its reviews are on
   screen; here, a tint of the brand blue. */
body.tinted { background-color: var(--brand-tint); }
@media (min-width: 1440px) { body { font-size: 15px; } }
@media (min-width: 1920px) { body { font-size: 16px; } }

h1, h2, h3, h4 { margin: 0; font-family: var(--serif); font-weight: 400; color: var(--ink); }
h1 { font-size: 4em; line-height: 1.1em; }
h2 { font-size: 3.25em; line-height: 1.13em; }
p { margin: 0; font-size: 1.125em; line-height: 1.6em; }
a { color: inherit; text-decoration: none; }
img { display: block; max-width: 100%; }

.section { position: relative; padding: 4em 2em; }
.content { width: 100%; max-width: 75em; margin: 0 auto; }

/* Blank stand-in for artwork we don't have yet: same box, same radius. */
.ph { background: var(--ph); border-radius: var(--radius); }

/* ---------- reveal on scroll (reference: opacity 0→1, y 15→0, 700ms) ---------- */
.reveal { opacity: 0; transform: translate3d(0, 15px, 0); }
.reveal.in {
  opacity: 1; transform: none;
  transition: opacity 0.7s ease var(--d, 0.1s), transform 0.7s ease var(--d, 0.1s);
}
@media (prefers-reduced-motion: reduce) {
  .reveal, .reveal.in { opacity: 1; transform: none; transition: none; }
  .social-proof-track { animation: none; }
}

/* ---------- buttons (reference: pill, hover scale .98 / .95) ---------- */
.button {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.3em;
  padding: 1em 2.7em; border-radius: 10em;
  background: var(--heading); color: #fff;
  font-family: var(--sans); font-size: 1em; font-weight: 600; line-height: 1.6em;
  border: 2px solid transparent; cursor: pointer;
  transition: box-shadow 0.4s cubic-bezier(0.165, 0.84, 0.44, 1), transform 0.2s var(--ease-io);
}
.button:hover { transform: scale(0.98); }
.button.bordered { background: transparent; color: var(--ink); border-color: var(--line); padding: 1em 1.5em; }
/* Pre-launch download button (see the launch switch in home.js). */
.button.is-soon { opacity: 0.45; cursor: default; pointer-events: none; }
.button.desktop { border-color: #000; padding: 1em 1.5em; }
.button-small {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 8px 16px; border-radius: 10em; font-size: 12px; line-height: 1.2;
  background: var(--heading); color: #fff; cursor: pointer; border: 0; font-family: var(--sans);
  transition: transform 0.2s var(--ease-io);
}
.button-small:hover { transform: scale(0.95); }
.button-small.gray { background: var(--pill-light); color: var(--ink); }
.button-small.bordered { background: transparent; color: var(--ink); border: 2px solid var(--line); padding: 6px 14px; }

/* ---------- top bar (scrolls away) + sticky nav ---------- */
.nav-func { position: relative; height: 40px; opacity: 0; transition: opacity 0.7s ease 0.1s; }
.nav-func.in { opacity: 1; }
.nav-func-bg { position: absolute; inset: 0; background: var(--ink); opacity: 0.05; }
.nav-func-menu {
  position: relative; display: flex; justify-content: flex-end; align-items: center; gap: 28px;
  max-width: 75.5em; height: 40px; margin: 0 auto; padding: 0 16px;
}
.nav-func-link { font-size: 12px; color: #000; cursor: pointer; }

.navbar {
  position: sticky; top: 0; z-index: 500; height: 6em; padding: 0 2em;
  display: flex; align-items: center; justify-content: center;
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1);   /* softer than the reference's 0.2s */
}
/* Reference: scroll down → slide up 110px in 200ms; scroll up → back. */
.navbar.hidden { transform: translate3d(0, -110px, 0); }
.nav-inner { width: 100%; max-width: 75em; display: flex; align-items: center; justify-content: space-between; }
.brand { display: flex; align-items: center; gap: 10px; padding: 0.3em; }
/* The iOS app icon: white square, iOS-style corners (22.5%), and a hairline
   so the white tile still reads against the pale backgrounds. */
.app-icon { border-radius: 22.5%; box-shadow: 0 0 0 1px rgba(22, 22, 19, 0.1), 0 2px 6px rgba(22, 22, 19, 0.08); background: #fff; }
.brand img { width: 36px; height: 36px; }
.brand span { font-family: var(--serif); font-size: 1.9em; line-height: 1; color: var(--ink); transform: translateY(-0.08em); }
.nav-right { display: flex; align-items: center; gap: 1.2em; }
.nav-menu { display: flex; align-items: center; }
.nav-link {
  padding: 0.7em 0.8em; font-size: 1.06em; line-height: 1.3em; color: var(--ink);
  transition: color 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94); cursor: pointer;
  display: inline-flex; align-items: center; gap: 4px; background: none; border: 0; font-family: inherit;
}
.nav-link:hover { color: var(--paragraph); }
.nav-link svg { width: 10px; height: 10px; transition: transform 0.25s ease; }
.nav-button { display: flex; gap: 16px; }

/* Features dropdown */
.dropdown { position: relative; }
.dropdown-list {
  /* Solid white: a see-through panel let the hero headline show through.
     Card down the left, the six features beside it in two columns, read
     top to bottom: Learn, Practice, Ask Peter | Upload, Record, Source Check —
     the app's three tabs, its Add tab's two ways in, and the tap-back-to-
     the-page breadcrumbs. */
  position: absolute; top: calc(100% + 10px); left: 50%; width: 880px;
  transform: translate(-50%, 8px); opacity: 0; pointer-events: none;
  display: grid; grid-template-columns: 300px 1fr 1fr; grid-template-rows: repeat(3, auto); grid-auto-flow: column; gap: 6px; padding: 10px;
  border-radius: 20px; background: #fff;
  box-shadow: 0 30px 60px -20px rgba(22, 22, 19, 0.25), 0 0 0 1px rgba(22, 22, 19, 0.06);
  transition: opacity 0.2s ease, transform 0.2s ease;
}
.dropdown.open .dropdown-list { opacity: 1; pointer-events: auto; transform: translate(-50%, 0); }
.dropdown.open .nav-link svg { transform: rotate(180deg); }
.dd-feature { grid-column: 1; grid-row: 1 / span 3; padding: 28px; border-radius: var(--radius); background: #c9d1fd; position: relative; overflow: hidden; isolation: isolate; color: var(--ink); display: flex; flex-direction: column; gap: 8px; }
.dd-feature::after { content: ""; position: absolute; inset: 0; pointer-events: none; opacity: 0.55; z-index: -1; mix-blend-mode: soft-light; background-image: var(--grain); }
.dd-feature b { font-family: var(--serif); font-weight: 400; font-size: 1.6em; line-height: 1.2; }
.dd-feature span { color: var(--paragraph); }
.dd-feature .button-small { align-self: flex-start; margin-top: auto; background: #fff; color: var(--ink); }
.dd-item { padding: 16px 20px; border-radius: var(--radius); color: var(--paragraph); transition: background 0.2s; cursor: pointer; }
.dd-item:hover { background: rgba(22, 22, 19, 0.04); }
.dd-item b { display: block; color: var(--ink); font-weight: 600; margin-bottom: 2px; }

.menu-button { display: none; width: 44px; height: 44px; border: 0; background: none; padding: 10px; cursor: pointer; }
.menu-button span { display: block; height: 2px; background: var(--ink); margin: 7px 0; transition: transform 0.25s ease; }
.menu-open .menu-button span:first-child { transform: translateY(4.5px) rotate(45deg); }
.menu-open .menu-button span:last-child { transform: translateY(-4.5px) rotate(-45deg); }

/* ---------- hero ---------- */
.gradient-hero {
  /* The long wash behind hero, proof strip and toolkit (reference: 140em). */
  position: absolute; inset: 0 0 auto 0; height: 140em; z-index: -10; pointer-events: none;
  background-image: linear-gradient(148deg, rgba(95, 114, 246, 0.6), transparent 72%);
  /* Fades to TRANSPARENT, not to a solid page colour: a solid end covered
     the paper grain and left a hard white/grey line where the wash stopped. */
  -webkit-mask-image: linear-gradient(180deg, #000 55%, transparent);
          mask-image: linear-gradient(180deg, #000 55%, transparent);
}
/* Grain only where the wash has colour; over the bare page it would grey it. */
.gradient-hero::after { content: ""; position: absolute; inset: 0; pointer-events: none; opacity: 0.55; mix-blend-mode: soft-light; background-image: var(--grain);
  -webkit-mask-image: linear-gradient(148deg, #000 30%, transparent 75%); mask-image: linear-gradient(148deg, #000 30%, transparent 75%); }
.hero {
  position: relative; margin-top: -90px; padding-top: 90px; overflow: hidden;
  background-image: linear-gradient(135deg, #b1bcfc, #ccd3fd 45%), linear-gradient(90deg, #c9d0fd, #e7eafe);
  opacity: 0; transition: opacity 1.2s cubic-bezier(0.445, 0.05, 0.55, 0.95) 0.1s;
}
.hero.in { opacity: 1; }
/* ---------- hero aurora ----------
   A still aurora mesh over the hero gradient, under the content, with a fine
   grain on top: brand blue top-left, a soft violet top-right and a sky blue
   behind the phones. Between the first version (full violet + sky, too
   colourful) and the blues-only one (too flat), then ~10% under that, 2026-10-19. Soft-edged
   radial gradients, no blur filter and no animation. */
.hero { isolation: isolate; }
.aurora { position: absolute; inset: 0; z-index: -1; pointer-events: none; }
.aurora i { position: absolute; display: block; aspect-ratio: 1; border-radius: 50%; }
.aurora .a1 { left: -14%; top: -22%; width: 62%; background: radial-gradient(closest-side, rgba(95, 114, 246, 0.52), rgba(95, 114, 246, 0.2) 55%, transparent); }
.aurora .a2 { right: -16%; top: -10%; width: 52%; background: radial-gradient(closest-side, rgba(150, 132, 249, 0.38), rgba(150, 132, 249, 0.13) 55%, transparent); }
.aurora .a3 { left: 26%; top: 26%; width: 58%; background: radial-gradient(closest-side, rgba(128, 190, 250, 0.32), rgba(128, 190, 250, 0.11) 55%, transparent); }
/* Grain over the colour (soft-light, so it textures without greying). */
.hero::after {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none; opacity: 0.55; mix-blend-mode: soft-light;
  background-image: var(--grain);
}
.hero .section { padding: 4em 2em 0; }
.hero .content { display: flex; flex-direction: column; align-items: center; text-align: center; }
.hero-badge {
  display: inline-flex; align-items: center; gap: 0.4em; height: 39px; margin-bottom: 24px;
  font-family: var(--sans); font-size: 1.9em; font-weight: 500; letter-spacing: -0.015em; color: var(--ink);
}
/* Pill and words are centred together as one line. "New" sits dead centre
   in the pill: a flex box of fixed height, with the text's own line box
   trimmed to its cap height. */
.hero-badge .new-pill {
  display: inline-flex; align-items: center; justify-content: center; height: 1.85em; padding: 0 0.85em;
  border-radius: 999px; background: var(--brand); color: #fff;
  font-size: 0.5em; font-weight: 600; letter-spacing: 0; line-height: 1; text-box: trim-both cap alphabetic;
}
.hero h1 { max-width: 75rem; }
.button-availability { margin-top: 24px; font-size: 0.85rem; text-align: center; color: var(--paragraph); }
/* The hero's App Store button: the page's main call to action, under the availability line
   (where the reference puts its device icons). It pushes the phones, and the hero, down. */
/* The footer's "Download for iOS" pill (.button-small), larger. */
.hero-download { margin-top: 42px; padding: 13px 26px; font-size: 16px; }
/* The button sits a little above the middle of the gap between the availability line and the
   phones, and the phones sit close under it (2026-10-23: midway read as stranded). Gaps are
   measured to the phone bezels, which start 4.17% of the PNG's width down (the rest is its
   shadow margin). */
/* Wider than the 75em column (centred overflow), so the phones read bigger. */
/* Wider than the 75em column (centred overflow), so the phones read bigger.
   The phones sit 96px under the availability line (73 was too tight once the
   device-icons placeholder went) — measured to the phones, not the image: the PNG carries a transparent top margin (3.97% of its width) for the
   shadow, so that much is taken back off the margin. */
.hero-image-wrap { width: min(1260px, calc(100vw - 2em)); flex: none; margin-top: calc(56px - 0.0417 * min(1260px, calc(100vw - 2em))); }
.hero-image {
  /* The five-phone fan (assets/hero.png, 2x). Transparent, so the hero
     gradient shows through; phones run off the bottom like the reference. */
  display: block; width: 100%; height: auto;
}

/* ---------- proof strip (marquee of logo slots, 52s loop) ---------- */
.proof { padding: 4em 0 2em; }
.social-proof-heading { text-align: center; margin: 0 2rem 60px; font-size: 3.5em; line-height: 1.13em; }
.social-proof-banner-wrap {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 128px, #000 calc(100% - 200px), transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 128px, #000 calc(100% - 200px), transparent 100%);
}
.social-proof-track { display: flex; width: max-content; animation: marquee 52s linear infinite; }
/* University wordmarks: --w/--h are design px at a 1440px window (equal
   area per logo), scaled by --u so the strip shrinks with the screen.
   Pure black; marks with shields go black-and-white, since flat black
   turns a shield into a solid blob. */
.social-proof-track { --u: calc(100vw / 1440); align-items: center; height: calc(96 * var(--u)); }
.social-proof-logo { flex: none; width: calc(var(--w) * var(--u)); height: calc(var(--h) * var(--u)); margin: 0 calc(30 * var(--u)); object-fit: contain; filter: brightness(0); }
/* Shield marks: pure black and white, no greys — darken a little, then push
   the contrast so every colour snaps to black and the white details stay white. */
.social-proof-logo.grey { filter: grayscale(1) brightness(0.7) contrast(20); }
/* Official black files (assets/logos): shown exactly as supplied — no filter, which would
   also blacken Harvard's white pages and wreath. */
.social-proof-logo.asis { filter: none; }
/* Harvard: the supplied black shield + the official wordmark (#1e1e1e, from the Wikimedia
   logo file, cropped to the words), laid out in Harvard's own proportions. */
.lockup-harvard { filter: none; display: flex; align-items: center; gap: calc(var(--h) * 0.27 * var(--u)); }
.lockup-harvard img { height: 100%; width: auto; }
.lockup-harvard svg { height: 76%; width: auto; aspect-ratio: 423 / 114; }
/* Wordmarks whose artwork touches the file's edge: drawn inside a slightly larger frame so
   anti-aliasing at the edge can't shave the bottoms of the letters. */
.social-proof-logo.padded svg { display: block; width: 100%; height: 100%; overflow: visible; }
@keyframes marquee { to { transform: translateX(-50%); } }


/* ---------- toolkit carousel ---------- */
.section-content-module { overflow: hidden; padding-top: 6em; }   /* a little more air under the logo strip (was 4em) */
.content-module-heading { max-width: 690px; font-size: 3.4em; line-height: 1.13em; margin-bottom: 1.2em; }
.swiper, .reviews-list-wrap {
  /* Full-bleed: the track runs to both edges of the window, and its first
     card still lines up with the text column. Cards scrolled past the left
     slide out to the screen edge instead of being sliced at the column. */
  --gutter: max(2em, calc((100vw - 75em) / 2));
  margin-left: calc(-1 * var(--gutter)); margin-right: calc(-1 * var(--gutter));
}
.carousel {
  position: relative; display: flex; overflow-x: auto; scroll-snap-type: x mandatory; scroll-behavior: smooth;
  scrollbar-width: none; padding: 0 var(--gutter, 0) 4px;
  scroll-padding: 0 var(--gutter, 0);
}
/* Every card stops in line with the text column's left edge; the last one
   stops with its right edge on the column's right edge, so the row never
   ends hanging off the screen. */
.carousel > :last-child { scroll-snap-align: end; }
.carousel::-webkit-scrollbar { display: none; }
.cm-item { flex: none; width: 353px; margin-right: 31px; display: flex; flex-direction: column; gap: 24px; scroll-snap-align: start; }
.cm-item-top { height: 500px; }
.cm-item-top .ph { width: 100%; height: 100%; }
/* Real card art: drawn on its own white (254), so where a phone's card is
   squarer than the 353 × 500 art, the side bars are the same white. */
.cm-item-top img { display: block; width: 100%; height: 100%; object-fit: contain; border-radius: var(--radius);
  background: #fefefe; box-shadow: 0 0 0 1px rgba(22, 22, 19, 0.06); }
/* Art with a full-bleed background (the subject mesh): fill the card, crop
   the edges on a phone's squarer card instead of adding white bars. */
.cm-item-top img.cover { object-fit: cover; }
.cm-item-text { display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
.cm-item-text h3 { font-size: 1.6em; line-height: 1.25em; }
.cm-item-text .button-small { margin-top: 8px; }
.slider-navigation { display: flex; justify-content: flex-end; gap: 16px; margin-top: 3em; }
.slider-navigation button {
  width: 60px; height: 60px; display: grid; place-items: center;
  border: 0; background: none; color: var(--ink); cursor: pointer; transition: opacity 0.2s, transform 0.2s var(--ease-io);
}
.slider-navigation button:hover { transform: scale(0.92); }
.slider-navigation button:disabled { opacity: 0.25; cursor: default; transform: none; }
.slider-navigation svg { width: 42px; height: 42px; }

/* ---------- media + text rows ---------- */
.media-text-inner { display: grid; grid-template-columns: 1fr 1.1fr; column-gap: 80px; }
.media-text-inner.align-bottom { grid-template-columns: 1.1fr 1fr; align-items: end; }
.media-text-content {
  display: flex; flex-direction: column; justify-content: flex-end; align-items: flex-start; gap: 24px;
  margin: 32px 0 20px;
}
.media-text-headline { font-size: 3.5em; line-height: 1.13em; margin-bottom: 20px; }
.media-text-content p { max-width: 32em; }
.media-text-media-wrap { position: relative; aspect-ratio: 1; border-radius: var(--radius); overflow: hidden; }
.media-text-media-wrap .ph { position: absolute; inset: 0; border-radius: 0; }
.media-text-media-wrap .media-photo { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
/* Upload row: a wheel of subject stickers (after fabric.so's integrations wheel). Sized in
   container units — 1 design px = 100cqw/547 — rather than a scale() transform, so the text and
   stickers render at full resolution. Its centre sits off the box's left edge so only the
   right-hand arc shows.
   ROTATION: two nested layers, each turned by the compositor where the browser can (2026-10-23):
   the wheel by the page's scroll position (a scroll-driven animation), the spin inside it by a
   slow endless turn. Driven from JS instead, the wheel read scrollY a frame or two behind iOS
   Safari's own scrolling and trailed the page; home.js still drives it where scroll-driven
   animations are missing. */
.subject-box { background: #fff; container-type: inline-size; --u: calc(100cqw / 547); --fade: 14%; }
.subject-stage { position: absolute; inset: 0; }
/* The fade at the top and bottom: white gradients laid OVER the wheel. It was a mask on the
   stage, and a mask over a moving layer makes Safari redraw the masked area every frame. */
.subject-stage::before, .subject-stage::after { content: ""; position: absolute; left: 0; right: 0; height: var(--fade); z-index: 1; pointer-events: none; }
.subject-stage::before { top: 0; background: linear-gradient(#fff, rgba(255, 255, 255, 0)); }
.subject-stage::after { bottom: 0; background: linear-gradient(rgba(255, 255, 255, 0), #fff); }
.subject-wheel { position: absolute; left: calc(-180 * var(--u)); top: 50%; width: 0; height: 0; will-change: transform; }
/* A real box around the pivot (the wheel's origin), not 0 × 0: Safari can skip drawing an
   animated layer with no area, and the whole wheel blinked out with it. */
.subject-spin { position: absolute; left: calc(-1000 * var(--u)); top: calc(-1000 * var(--u)); width: calc(2000 * var(--u)); height: calc(2000 * var(--u)); will-change: transform; }
@supports (animation-timeline: scroll()) {
  /* 0.09° per px scrolled: --scroll-max (px, set by home.js) × 0.09deg over the page's scroll. */
  .subject-wheel { animation: wheel-scroll linear both; animation-timeline: scroll(root block); }
  .subject-spin { animation: wheel-idle 32s linear infinite; }
  @media (prefers-reduced-motion: reduce) { .subject-spin { animation: none; } }
}
@keyframes wheel-scroll { from { transform: rotate(0deg); } to { transform: rotate(calc(var(--scroll-max, 0) * 0.09deg)); } }
@keyframes wheel-idle { to { transform: rotate(360deg); } }
.subject-item {
  position: absolute; left: calc(1000 * var(--u)); top: calc(962 * var(--u)); height: calc(76 * var(--u));   /* the spin box's centre */
  display: flex; align-items: center; gap: calc(18 * var(--u)); transform-origin: 0 50%;
  font-size: calc(28 * var(--u)); font-weight: 500; letter-spacing: -0.02em; color: #1d1d1f; white-space: nowrap;
}
.subject-item img { width: calc(64 * var(--u)); height: calc(64 * var(--u)); flex: none; }

/* Name tag on a photo (Made by students row): a small frosted pill, bottom-left */
.photo-caption {
  position: absolute; left: 16px; bottom: 16px; z-index: 3;
  padding: 7px 13px; border-radius: 999px;
  font-size: 14px; line-height: 1; letter-spacing: -0.01em; color: #111;
  background: rgba(255, 255, 255, 0.82);
  -webkit-backdrop-filter: blur(12px) saturate(1.4); backdrop-filter: blur(12px) saturate(1.4);
}
/* Learn path row: one image per path state, all stacked and always fully opaque (so Safari never
   drops a layer it then has to repaint blank). Only the newest state, raised to the top, fades
   in; whatever was showing stays solid underneath — even when several switches overlap. */
.path-steps .media-photo { will-change: opacity; }
.path-steps .media-photo.fade { animation: path-in 0.45s cubic-bezier(0.45, 0, 0.25, 1) both; }
@keyframes path-in { from { opacity: 0; } to { opacity: 1; } }
/* The reference swaps in an animated version of the image on hover (300ms). */
.media-text-media-hover { position: absolute; inset: 0; background: rgba(95, 114, 246, 0.07); opacity: 0; transition: opacity 0.3s cubic-bezier(0.215, 0.61, 0.355, 1); }
/* No hover tint on the row images (user, 2026-10-19). */

/* ---------- "built around real problems" band (reference: reviews) ---------- */
.reviews { overflow: hidden; position: relative; }
/* Grain over the page tint while it is on (fades with it, 0.5s). No
   isolation on .reviews, so soft-light blends with the tinted page. */
.reviews::after { content: ""; position: absolute; inset: 0; pointer-events: none; opacity: 0; z-index: -1; transition: opacity 0.9s cubic-bezier(0.45, 0, 0.25, 1); mix-blend-mode: soft-light; background-image: var(--grain); }
body.tinted .reviews::after { opacity: 0.55; }
/* Fade the grain in and out over the band's top and bottom 160px: the tint covers
   the whole page, so a hard-edged grain box read as faint lines above and below. */
.reviews::after {
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 160px, #000 calc(100% - 160px), transparent);
          mask-image: linear-gradient(180deg, transparent, #000 160px, #000 calc(100% - 160px), transparent);
}
.reviews-top { max-width: 690px; margin-bottom: 56px; }
.reviews-top h2 { font-size: 3.4em; margin-bottom: 20px; }
.reviews-list { align-items: flex-end; }
.review-item {
  flex: none; width: 270px; margin-right: 31px; padding: 32px; border-radius: var(--radius);
  background: #fff; display: flex; flex-direction: column; gap: 21px; scroll-snap-align: start;
}
.review-item-quotation { height: 25px; font-family: var(--serif); font-size: 80px; line-height: 100%; color: #111717; }
/* Five stars in the app's sticker style (from App Store preview 01), between the text and
   the name as on Tiimo's cards, at their size: 102 × 18 px on the same 270 px card. */
.review-item-stars { display: block; width: 103px; height: auto; margin-top: auto; }
.review-item-text { font-family: var(--serif); font-size: 18px; line-height: 26px; color: #111717; }
.review-item-name { font-size: 12.5px; text-transform: uppercase; letter-spacing: 0.02em; color: gray; }
/* Reviewer details under the name: course, then university (with permission). */
.review-item-who { display: flex; flex-direction: column; gap: 3px; }   /* name · course & year · university */
.review-item-course, .review-item-year, .review-item-school { font-size: 12.5px; line-height: 1.35; color: var(--paragraph); }
.review-item-course { color: var(--ink); font-weight: 500; letter-spacing: -0.012em; }   /* lets "BComp Computer Science · Year 4" sit on one line */
.review-item-year { color: var(--ink); font-weight: 500; }
.review-item-course .nowrap { white-space: nowrap; }   /* "· Year 4" moves as one, never splits */
.reviews-bottom { display: flex; justify-content: space-between; align-items: center; margin-top: 80px; }
.reviews-bottom .slider-navigation { margin: 0; }

/* ---------- FAQ ---------- */
/* No overflow:hidden here: Safari leaves the next row's divider painted behind while an answer opens
   inside a rounded clipping box. Nothing pokes past the corners, so the clip isn't needed. */
.faq-group-row-inner { border-radius: var(--radius); background: #fff; }
.faq-item + .faq-item { border-top: 1px solid rgba(22, 22, 19, 0.07); }
/* Rows below an answer that is opening or closing ride on their own layers
   for the length of the animation (home.js adds .shift). Safari repaints
   only what it thinks changed, and with the page's sub-pixel layout it
   missed the strip where a divider USED to be — the grey line that flashed.
   As layers those rows just slide. Never on the growing row itself: its
   layer would be redrawn every frame, which made opening laggy. */
.faq-item.shift { will-change: transform; }
.faq-question {
  width: 100%; display: flex; justify-content: space-between; align-items: flex-start; gap: 20px;
  padding: 28px; border: 0; background: none; text-align: left; cursor: pointer;
  font-family: var(--sans); font-size: 18px; font-weight: 600; line-height: 1.5em; color: #3c3d49;
}
.faq-question svg { flex: none; width: 22px; height: 22px; margin-top: 3px; transition: transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1); }
.faq-item.open .faq-question svg { transform: rotate(180deg); }
.faq-item:not(.open) .faq-question svg { transition: transform 0.3s ease; }
/* Reference: opens over 500ms with a slight overshoot, closes in 300ms. */
.faq-answer { height: 0; overflow: hidden; padding: 0 28px; transition: height 0.5s cubic-bezier(0.34, 1.4, 0.64, 1); }
.faq-item:not(.open) .faq-answer { transition: height 0.3s ease; }
.faq-answer p { margin-bottom: 28px; font-size: 17px; line-height: 1.55em; }

/* ---------- closing CTA ---------- */
.cta { text-align: center; padding-top: 5em; }
.cta h2 { font-size: 5em; line-height: 1.06em; margin-bottom: 0.35em; }
.cta p { max-width: 32em; margin: 0 auto 2.2em; font-size: 1.25em; }
.block-hero-cta { display: flex; flex-direction: column; align-items: center; }
.block-hero-cta .button { min-width: 346px; margin-bottom: 12px; }

/* ---------- footer ---------- */
.section-footer { position: relative; padding: 5.5em 2em 8em; }
.gradient-footer {
  position: absolute; left: 0; right: 0; bottom: 0; height: 190%; z-index: -10;
  background-image: linear-gradient(340deg, var(--brand-soft) 10%, transparent 57%);
  opacity: 0; transition: opacity 1.2s cubic-bezier(0.445, 0.05, 0.55, 0.95) 0.1s;
}
.gradient-footer.in { opacity: 1; }
.gradient-footer::after { content: ""; position: absolute; inset: 0; pointer-events: none; opacity: 0.55; mix-blend-mode: soft-light; background-image: var(--grain);
  -webkit-mask-image: linear-gradient(340deg, #000 25%, transparent 60%); mask-image: linear-gradient(340deg, #000 25%, transparent 60%); }
.footer-art { width: 6em; height: 6em; margin-bottom: 1.4em; }
.footer-art .jitter { width: 100%; height: 100%; display: block; will-change: transform; }   /* angle set by home.js, snapped, never tweened */
.footer-text { display: flex; flex-direction: column; gap: 1em; margin-bottom: 3.5em; }
.footer-text h4 { font-size: 2em; line-height: 1.13em; }
.footer-text p { max-width: 30em; font-size: 1em; }
.footer-content { display: grid; grid-template-columns: repeat(6, 1fr); gap: 30px 7px; }
.footer-menu { display: flex; flex-direction: column; gap: 10px; align-items: flex-start; }
.footer-menu-headline { margin-bottom: 6px; font-size: 1.2em; font-weight: 600; color: var(--ink); }
.footer-link { font-size: 1em; color: var(--paragraph); transition: color 0.2s; cursor: pointer; }
.footer-link:hover { color: var(--ink); }
.footer-down {
  position: absolute; left: 0; right: 0; bottom: 0; display: flex; flex-wrap: wrap; justify-content: space-between; gap: 10px 30px;
  padding: 1em 100px; background: rgba(22, 20, 18, 0.1); font-size: 12px; color: var(--ink);
}
.footer-down nav { display: flex; gap: 22px; }
.footer-down a { text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }

/* ---------- mobile sticky banner (slides up on scroll down) ---------- */
.sticky-banner {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 600; display: none; align-items: center; gap: 12px;
  padding: 12px 16px calc(12px + env(safe-area-inset-bottom)); background: rgba(255, 255, 255, 0.95);
  -webkit-backdrop-filter: blur(20px); backdrop-filter: blur(20px); box-shadow: 0 -1px 0 var(--rule);
  transform: translateY(110%);
  /* HIDDEN, not just slid away, once off screen: iOS Safari fills the area behind its floating
     toolbar with the colour of a fixed bar at the bottom of the page, and a bar merely moved off
     screen left a white strip there after it was closed (2026-10-23). visibility flips after the
     slide out, and before the slide in. */
  visibility: hidden;
  /* Closing: a quick ease-in that ends the moment the bar is off screen, and visibility flips
     on that same frame — an ease-out looked finished long before it was, and the strip lagged. */
  transition: transform 0.32s cubic-bezier(0.55, 0, 0.75, 0.2), visibility 0s linear 0.32s;
}
.sticky-banner.gone { display: none; }
/* See the close handler in home.js. The panel colour lives on ::before so the bar's own
   background (what Safari copies into its toolbar strip) can clear at the tap. */
.sticky-banner { isolation: isolate; }
.sticky-banner::before { content: ""; position: absolute; inset: 0; z-index: -1; background: rgba(255, 255, 255, 0.95); box-shadow: inherit; transition: opacity 0.2s ease-out; }
.sticky-banner > * { transition: opacity 0.2s ease-out; }
.sticky-banner.closing { background: transparent; box-shadow: none; -webkit-backdrop-filter: none; backdrop-filter: none; }
.sticky-banner.closing::before, .sticky-banner.closing > * { opacity: 0; }
.sticky-banner.show { transform: none; visibility: visible; transition: transform 0.5s cubic-bezier(0.215, 0.61, 0.355, 1), visibility 0s; }
/* A round press state of its own instead of Safari's grey tap rectangle, which was not square
   and stayed put while the bar slid away. */
.sticky-banner .close {
  flex: none; display: grid; place-items: center; width: 32px; height: 32px; padding: 0; border: 0; border-radius: 50%;
  background: transparent; font-size: 22px; line-height: 1; color: var(--muted); cursor: pointer;
  -webkit-tap-highlight-color: transparent; transition: background-color 0.15s ease, opacity 0.2s ease-out;
}
.sticky-banner .close:active { background: rgba(22, 22, 19, 0.08); }
.sticky-banner img { width: 44px; height: 44px; }
.sticky-banner .t { flex: 1; font-family: var(--serif); font-size: 15px; line-height: 1.25; color: var(--ink); }
.sticky-banner .t small { display: block; font-family: var(--sans); font-size: 12px; color: var(--muted); }

/* ================= responsive (the reference's breakpoints) ================= */
@media (max-width: 991px) {
  .navbar { height: 8em; padding: 0 1.5em; }
  .nav-right .nav-menu, .nav-right .nav-button { display: none; }
  .menu-button { display: block; }
  .menu-open .nav-right .nav-menu {
    display: flex; flex-direction: column; align-items: stretch; position: absolute; top: 100%; left: 0; right: 0;
    padding: 12px 1.5em 20px; background: var(--page); box-shadow: 0 20px 40px -20px rgba(0, 0, 0, 0.2);
  }
  .menu-open .nav-right .nav-menu .nav-link { font-size: 1.4em; padding: 0.7em 0; justify-content: space-between; width: 100%; }
  .menu-open .dropdown-list { position: static; width: auto; transform: none; grid-template-columns: 1fr; grid-template-rows: none; grid-auto-flow: row; box-shadow: none; background: transparent; padding: 0; display: none; }
  /* transform too: the desktop `.dropdown.open` rule outranks the line above and
     would slide the list half its width off the left edge. */
  .menu-open .dropdown.open .dropdown-list { display: grid; transform: none; }
  .menu-open .dd-feature { display: none; }
  .hero { margin-top: -8em; padding-top: 8em; }
  .media-text-inner, .media-text-inner.align-bottom { display: flex; flex-direction: column-reverse; align-items: stretch; gap: 36px; }
  .media-text-media-wrap { width: 100%; }
  .media-text-inner.media-left { flex-direction: column; }
  .media-text-content { max-width: 80%; margin: 0; }
  .social-proof-track { --u: calc(100vw / 1000); }
  .footer-content { grid-template-columns: repeat(3, 1fr); }
  .footer-content > .spacer { display: none; }
  .footer-down { padding: 1em 2em; }
}
@media (max-width: 767px) {
  h1 { font-size: 3.5em; }
  .navbar { height: 6em; }
  .nav-func { display: none; }
  .hero { margin-top: -6em; padding-top: 6em; }
  .hero-badge { font-size: 1.6em; }
  .section { padding-top: 3.5em; padding-bottom: 3.5em; }
  .media-text-content { max-width: none; }
  .media-text-headline { font-size: 3.2em; }
  .social-proof-heading { font-size: 3.2em; }
  .social-proof-track { --u: calc(100vw / 760); }
  .cta h2 { font-size: 3.6em; }
  .block-hero-cta .button { min-width: 0; width: 100%; }
  .sticky-banner { display: flex; }
  .footer-content { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 479px) {
  h1 { font-size: 3em; }
  .hero-badge { font-size: 1.3em; }
  .section { padding-left: 1.4em; padding-right: 1.4em; }
  .swiper, .reviews-list-wrap { --gutter: 1.4em; }
  .cm-item { width: 82vw; }
  .cm-item-top { height: auto; aspect-ratio: 353 / 500; }   /* the website's card shape, full width */
  .media-text-headline { font-size: 2.7em; }
  .social-proof-heading { font-size: 2.7em; }
  .social-proof-track { --u: calc(100vw / 560); }
  .content-module-heading, .reviews-top h2 { font-size: 2.7em; }
  .cta h2 { font-size: 2.9em; }
  .section-footer { padding-bottom: 12em; }
  .footer-down { padding: 1em 1.4em; }
}

/* ================= phones, matched to the reference at 402px (2026-10-23) =================
   Measured side by side with tiimoapp.com in a 402 × 874 window (iPhone 17 Pro) and in iOS
   Safari. Desktop is untouched; every value below is the reference's own at that width. */
@media (max-width: 767px) {
  /* The bar scrolls away with the page, as the reference's does on phones. Sticky and
     see-through, it hung a blur band over the content, and iOS Safari painted the status-bar
     strip in its (transparent → page white) colour: the white band above the hero. */
  .navbar { position: relative; padding: 0 2em; -webkit-backdrop-filter: none; backdrop-filter: none; }
  .navbar.hidden { transform: none; }
  /* The hero copy starts 26px under the bar, as the reference's does (its section is pulled
     up 30px): the badge at 110px from the top, not 140. Takes the aurora up with it. */
  .hero .section { margin-top: -30px; }
  .brand { padding: 0; gap: 14px; }
  .brand img { width: 42px; height: 42px; }
  .menu-button { width: 44px; height: 34px; padding: 4.5px 6px; }
  /* Buttons: the reference's label line is 15px, so a pill is 47px tall (bordered) and a
     small one 35px — ours were 54 and 30. */
  .button { line-height: 15px; }
  .button-small { line-height: 15px; }
  .button-small.bordered { padding: 8px 16px; }
  /* The download bar: the reference's is a 58px icon, a 17px title and a 44px pill. */
  .sticky-banner { gap: 12px; padding: 14px 16px calc(14px + env(safe-area-inset-bottom)); box-shadow: 0 -1px 0 rgba(22, 22, 19, 0.06); }
  .sticky-banner .close { width: 34px; height: 34px; font-size: 26px; margin-left: -6px; }
  .sticky-banner img { width: 58px; height: 58px; }
  .sticky-banner .t { font-size: 18px; line-height: 1.2; }
  .sticky-banner .t small { margin-top: 3px; font-size: 14px; }
  .sticky-banner .button-small { height: 44px; padding: 0 22px; font-size: 17px; font-weight: 600; background: #333; }
}
@media (max-width: 479px) {
  /* One 28px gutter everywhere (2em), so every picture and card is the same 346px wide. */
  .section { padding-left: 2em; padding-right: 2em; }
  .swiper, .reviews-list-wrap { --gutter: 2em; }
  /* hero */
  .hero h1 { font-size: 3em; }
  .button-availability { font-size: 12px; }
  /* Phones: the button midway, the taller hero (user's pick, 2026-10-23); 15px label. */
  .hero-download { margin-top: 32.5px; padding: 12px 24px; font-size: 15px; }
  .hero-image-wrap { width: 100%; margin-top: calc(37.5px - 0.0417 * (100vw - 4em)); }
  /* logo strip: inside the column, as the reference's, not edge to edge */
  .social-proof-heading { margin: 0 28px 60px; }   /* px: em here would be the heading's own 37.8px */
  .social-proof-banner-wrap {
    margin: 0 2em;
    -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 48px, #000 calc(100% - 48px), transparent 100%);
            mask-image: linear-gradient(90deg, transparent 0, #000 48px, #000 calc(100% - 48px), transparent 100%);
  }
  /* toolkit carousel: one card the full column wide, smaller section heading, 25px arrows */
  .content-module-heading, .reviews-top h2 { font-size: 2em; line-height: 1.06em; }
  .content-module-heading { margin-bottom: 64px; }
  /* Narrower than the column, at the website's card shape, so the next card peeks in. */
  .cm-item { width: 76vw; margin-right: 16px; }
  .cm-item-text h3 { font-size: 1.8em; line-height: 1.18em; }
  .cm-item-text .button-small { margin-top: 16px; }
  .slider-navigation { gap: 8px; margin-top: 44px; }
  .slider-navigation button { width: 44px; height: 44px; }   /* a full tap target */
  .slider-navigation svg { width: 34px; height: 34px; }
  /* The subject wheel ~15% larger on phones, so its arc reaches further across the box, with a
     slimmer fade so more of it shows. */
  .subject-box { --u: calc(100cqw / 475); --fade: 10%; }
  /* reviews: full-width cards, button and arrows on one row */
  .review-item { width: 76vw; margin-right: 16px; }
  /* Both carousels: a middle card stops CENTRED, so the cards either side peek in by the same
     amount; the first still lines up with the column, the last with its right edge. */
  .cm-item, .review-item { scroll-snap-align: center; }
  .carousel > :first-child { scroll-snap-align: start; }
  .reviews-bottom { margin-top: 56px; }
  .reviews-bottom .button { padding: 8px 16px; }
  /* FAQ: 16px questions (80px rows), 15.75px answers */
  .faq-question { font-size: 16px; line-height: 24px; }
  .faq-answer p { font-size: 1.125em; line-height: 1.6em; }
  /* closing CTA */
  .cta h2 { font-size: 2.6em; line-height: 1.1em; margin: 0 10px 0.35em; }
  .cta p { font-size: 1.2em; margin-bottom: 26px; }
  .block-hero-cta .button { width: 288px; }
  .block-hero-cta .button.desktop { background: transparent; color: var(--ink); border-color: var(--line); }
  /* footer: one column, then the legal strip stacked */
  .footer-text p { font-size: 1.125em; line-height: 1.6em; }
  .footer-content { grid-template-columns: 1fr; }
  .section-footer { padding-bottom: 17em; }
  .footer-down { flex-direction: column; align-items: flex-start; gap: 16px; padding: 24px 24px 96px; }
  .footer-down nav { flex-direction: column; gap: 16px; }
}
