/* KRAFTful — kraftful.me
 *
 * Tokens are lifted from design/brandfiles/KRAFTful-colour-spec.md verbatim.
 * The spec's one rule governs the whole page: colour means something or it is
 * not there. Amber is brand and nothing else; green and red are reserved for
 * compliance and verdict and therefore appear NOWHERE on this page, because
 * a marketing page has no targets to hit. Decorative green would make the
 * product lie before the reader reaches a real chart.
 */

:root {
  /* surfaces */
  --surface-page: #0B0B0D;
  --surface-card-top: #1B1B23;
  --surface-card-bot: #121218;
  --surface-inset: #14141A;
  --hairline: #24242E;

  /* text */
  --text-primary: #F4F4F8;
  --text-secondary: #C8C8D4;
  --text-tertiary: #7A7A88;
  --text-quaternary: #5C5C68;

  /* brand */
  --accent: #D9962B;
  --accent-on-light: #A86F14;

  /* the inverted band */
  --bone: #F4F4F8;
  --bone-dim: #E4E4EA;

  --page-max: 1180px;
  --gutter: clamp(20px, 5vw, 56px);
  --section-y: clamp(72px, 11vw, 152px);

  --ui: -apple-system, "SF Pro Text", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--surface-page);
  color: var(--text-primary);
  font: 400 17px/1.6 var(--ui);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
img, video { display: block; max-width: 100%; }
a { color: inherit; }

.wrap { max-width: var(--page-max); margin: 0 auto; padding: 0 var(--gutter); }

/* ── eyebrow ───────────────────────────────────────────────────────────────
   The app's own provenance vocabulary, borrowed. In the product these pills
   name where a number came from; here they name what a section is about, so
   the page and the screenshots read as one object. */
.eyebrow {
  font: 600 11px/1 var(--mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-tertiary);
  margin: 0 0 18px;
}
.eyebrow--accent { color: var(--accent); }

h1, h2, h3 { margin: 0; font-weight: 700; letter-spacing: -0.022em; line-height: 1.08; }
h1 { font-size: clamp(34px, 5.6vw, 66px); }
h2 { font-size: clamp(27px, 3.6vw, 43px); }
h3 { font-size: clamp(19px, 1.7vw, 22px); letter-spacing: -0.012em; }
p { margin: 0 0 1em; color: var(--text-secondary); }
p.lead { font-size: clamp(18px, 1.9vw, 21px); max-width: 34em; }
.dim { color: var(--text-tertiary); }
.small { font-size: 15px; }

/* ── masthead ─────────────────────────────────────────────────────────────*/
.masthead {
  position: absolute; inset: 0 0 auto; z-index: 5;
  display: flex; align-items: center; justify-content: space-between;
  gap: 20px; padding: 26px var(--gutter);
  max-width: var(--page-max); margin: 0 auto;
}
.masthead__lockup { height: 26px; width: auto; }
.masthead__nav { display: flex; align-items: center; gap: 8px; }
.masthead__link {
  font-size: 14.5px; color: var(--text-secondary); text-decoration: none;
  padding: 9px 15px; border-radius: 999px; border: 1px solid transparent;
  transition: color .18s, border-color .18s, background .18s;
}
.masthead__link:hover { color: var(--text-primary); border-color: var(--hairline); }
.masthead__link--edge { border-color: var(--hairline); background: rgba(255,255,255,.03); }
@media (max-width: 620px) { .masthead__link--hide { display: none; } }

/* ── hero ─────────────────────────────────────────────────────────────────
   The A1 loop, measured: average frame luminance 1.79-1.84% and the
   upper-left two-thirds at p99.9 = 2.80% against a 21.59% mid-grey ceiling,
   on every sampled frame. The copy sits in that region, which is why it holds
   13:1 contrast without a scrim doing the work. */
.hero { position: relative; min-height: min(94vh, 860px); display: flex; align-items: flex-end; overflow: hidden; }
.hero__media { position: absolute; inset: 0; }
.hero__media img, .hero__media video { width: 100%; height: 100%; object-fit: cover; }
/* A floor gradient only — the frame is already dark enough overhead. */
.hero__floor {
  position: absolute; inset: auto 0 0; height: 46%;
  background: linear-gradient(180deg, transparent, rgba(11,11,13,.86) 62%, var(--surface-page));
}
/* ⚠️ NO max-width ON NARROW SCREENS. A 20ch cap here read fine on a desktop
   mock and wrecked the phone: the headline broke to four lines and the eyebrow
   split "ALWAYS / ON" across two. The column IS the constraint below 780px;
   the cap only earns its keep once there is a scene to keep clear of. */
/* ⚠️ padding-BOTTOM, not the padding shorthand. `.hero__body` also carries
   `.wrap`, and a shorthand here resets .wrap's horizontal gutter to zero —
   which put the headline and both buttons flush against the left edge of the
   phone while the masthead above them stayed correctly inset. */
.hero__body { position: relative; padding-bottom: clamp(56px, 9vw, 104px); }
.hero h1 { margin-bottom: 20px; }
.hero .eyebrow { white-space: nowrap; }
@media (max-width: 400px) { .hero .eyebrow { letter-spacing: .1em; font-size: 10px; } }
@media (min-width: 780px) { .hero__body { max-width: 60%; } .hero p { max-width: 30ch; } }

/* ── buttons ──────────────────────────────────────────────────────────────*/
.cta { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; margin-top: 30px; }
.btn {
  display: inline-flex; align-items: center; gap: 9px;
  font: 600 15.5px/1 var(--ui); text-decoration: none;
  padding: 15px 24px; border-radius: 999px; border: 1px solid transparent;
  transition: transform .16s, background .16s, border-color .16s;
}
.btn:active { transform: translateY(1px); }
.btn--primary { background: var(--text-primary); color: #0B0B0D; }
.btn--primary:hover { background: #fff; }
.btn--ghost { border-color: var(--hairline); color: var(--text-primary); background: rgba(255,255,255,.03); }
.btn--ghost:hover { border-color: #37374A; }
.btn--ink { background: #0B0B0D; color: var(--bone); }
.btn--ink:hover { background: #17171d; }

/* ── sections ─────────────────────────────────────────────────────────────*/
section { padding: var(--section-y) 0; }
.rule { border: 0; border-top: 1px solid var(--hairline); margin: 0; }

.split { display: grid; gap: clamp(32px, 5vw, 72px); align-items: center; }
@media (min-width: 900px) { .split { grid-template-columns: 1fr 1fr; } .split--wide { grid-template-columns: 1fr 1.25fr; } }

/* ── cards ────────────────────────────────────────────────────────────────
   The spec's gradient, not a flat fill: "flat cards read as unfinished
   rather than austere". */
.card {
  background: linear-gradient(180deg, var(--surface-card-top), var(--surface-card-bot));
  border: 1px solid var(--hairline);
  border-radius: 18px;
  padding: clamp(22px, 2.6vw, 30px);
}
.grid { display: grid; gap: 16px; }
@media (min-width: 720px) { .grid--3 { grid-template-columns: repeat(3, 1fr); } .grid--2 { grid-template-columns: repeat(2, 1fr); } }
.card h3 { margin-bottom: 9px; }
.card p:last-child { margin-bottom: 0; }

/* ── product UI, floating (the Steep mechanic) ───────────────────────────*/
.shots { display: flex; gap: clamp(14px, 2vw, 26px); align-items: flex-end; }
.shot {
  border-radius: 26px; overflow: hidden; flex: 1 1 0; min-width: 0;
  border: 1px solid var(--hairline);
  box-shadow: 0 34px 70px -22px rgba(0,0,0,.92), 0 8px 22px -10px rgba(0,0,0,.7);
}
.shot img { width: 100%; height: auto; }
.shot--raise { transform: translateY(clamp(-40px, -3.4vw, -14px)); }
@media (max-width: 720px) { .shots { overflow-x: auto; padding-bottom: 8px; -webkit-overflow-scrolling: touch; }
  .shot { flex: 0 0 62%; } .shot--raise { transform: none; } }

.frame {
  border-radius: 14px; overflow: hidden; border: 1px solid var(--hairline);
  box-shadow: 0 34px 70px -26px rgba(0,0,0,.9);
}
.frame img { width: 100%; height: auto; }

/* ── platform strip ──────────────────────────────────────────────────────*/
.platform { display: grid; gap: 14px; }
@media (min-width: 760px) { .platform { grid-template-columns: 1fr 1fr; } }
.plat {
  display: flex; gap: 16px; align-items: flex-start;
  padding: clamp(20px, 2.3vw, 26px);
  border: 1px solid var(--hairline); border-radius: 16px;
  background: linear-gradient(180deg, var(--surface-card-top), var(--surface-card-bot));
}
.plat--soon { background: none; border-style: dashed; }
.plat__glyph { flex: 0 0 auto; width: 26px; height: 26px; color: var(--text-tertiary); }
.plat--now .plat__glyph { color: var(--text-primary); }
.plat__t { font-weight: 650; margin-bottom: 5px; }

/* ── the inverted coach band ─────────────────────────────────────────────
   The page's one light section. The brand spec makes coach ink-on-bone and
   calls the inversion an identity device, not a theme. Measured at 91.75%
   average luminance with the left half at 98.89%, which is where the copy
   goes. */
.band { position: relative; background: var(--bone); color: #0B0B0D; overflow: hidden; }
.band__media { position: absolute; inset: 0; }
.band__media img { width: 100%; height: 100%; object-fit: cover; }
.band__media::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(90deg, var(--bone) 34%, rgba(244,244,248,.55) 62%, transparent);
}
.band__body { position: relative; max-width: 46ch; }
.band h2, .band h3 { color: #0B0B0D; }
.band p { color: #3A3A46; }
.band .eyebrow { color: var(--accent-on-light); }
.band__lockup { height: 25px; width: auto; margin-bottom: 22px; }
.band .card { background: #fff; border-color: #E2E2E9; }

/* ── pricing ─────────────────────────────────────────────────────────────*/
.price { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; margin: 6px 0 4px; }
.price__free { font-size: clamp(38px, 4.6vw, 54px); font-weight: 800; letter-spacing: -0.03em; line-height: 1; }
.price__then { font-size: 17px; color: var(--text-secondary); }
.price__amt { color: var(--text-primary); font-weight: 650; }
.price__note { font-size: 14.5px; color: var(--text-tertiary); margin-top: 14px; }
.ticks { list-style: none; margin: 20px 0 0; padding: 0; display: grid; gap: 11px; }
.ticks li { display: flex; gap: 11px; align-items: flex-start; color: var(--text-secondary); font-size: 15.5px; }
.ticks svg { flex: 0 0 auto; margin-top: 3px; color: var(--accent); }

/* ── footer ──────────────────────────────────────────────────────────────*/
.foot { padding: 46px 0 60px; color: var(--text-quaternary); font-size: 14px; }
.foot__row { display: flex; flex-wrap: wrap; gap: 14px 26px; align-items: center; justify-content: space-between; }
.foot a { color: var(--text-tertiary); text-decoration: none; }
.foot a:hover { color: var(--text-secondary); }

/* ── grain ───────────────────────────────────────────────────────────────
   feTurbulence rather than a generated plate. The generated one was measured
   and rejected: its top-vs-bottom edge differed by 158 against a 28.6
   baseline, so it carried a gradient and could never tile. fractalNoise with
   stitchTiles repeats seamlessly by construction. */
.grain::after {
  content: ''; position: absolute; inset: 0; pointer-events: none; z-index: 2;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='g'><feTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='1' stitchTiles='stitch'/><feColorMatrix type='saturate' values='0'/></filter><rect width='200' height='200' filter='url(%23g)'/></svg>");
  opacity: .03; mix-blend-mode: overlay;
}
.hero .grain::after, .hero::after { mix-blend-mode: screen; opacity: .022; }

/* ── arrivals ────────────────────────────────────────────────────────────
   Deliberately NOT IntersectionObserver: its callbacks are delivered on the
   frame loop, so in a throttled or background tab nothing fires and content
   stays at opacity 0 permanently. Content must not be able to disappear.
   Same reasoning as landing/assets/js/rail.js. */
.rise { opacity: 0; transform: translateY(16px); transition: opacity .5s ease, transform .5s ease; }
.rise.is-in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .rise { opacity: 1; transform: none; transition: none; }
  .shot--raise { transform: none; }
  * { animation: none !important; scroll-behavior: auto !important; }
}
