/* assets/app.css — the B2C product page.
 *
 * Light throughout. The only dark thing on the page is the phone screenshot itself,
 * which is correct: the app ships two identities (Night Shift amber console, Day Shift
 * cool slate) and the toggle shows both rather than the page describing them. */

.app-hero {
  background: var(--ground); border-bottom: 1px solid var(--line);
  padding: clamp(28px, 3.5vw, 44px) clamp(16px, 5vw, 72px) clamp(24px, 3.5vw, 36px);
}
.app-hero-grid {
  display: grid; grid-template-columns: 1.05fr 0.95fr;
  gap: clamp(32px, 5vw, 64px); align-items: center;
}
.eyebrow {
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 11px; letter-spacing: 2.4px; text-transform: uppercase;
  color: var(--accent); margin-bottom: 16px;
}
.app-hero h1 {
  font-size: clamp(34px, 4.6vw, 58px); line-height: 1.02; letter-spacing: -0.042em;
  font-weight: 700; margin: 0 0 16px; text-wrap: balance;
}
.app-hero .lede {
  font-size: clamp(16px, 1.6vw, 18px); line-height: 1.6; color: var(--ink-2);
  margin: 0 0 24px; max-width: 480px;
}

/* store buttons */
.stores { display: flex; gap: 12px; margin-bottom: 18px; flex-wrap: wrap; }
.store {
  background: var(--ink); color: var(--paper); padding: 11px 20px; border-radius: 8px;
  display: flex; align-items: center; gap: 11px;
}
.store:hover { background: oklch(28% 0.02 265); color: var(--paper); }
/* Android is built but not through Play review, so the badge states that instead of
   linking. It is a <span>, not an <a>: nothing to click, no 404 to land on. */
.store.soon {
  background: transparent; color: var(--ink-2);
  border: 1px dashed var(--line); cursor: default;
}
.store.soon svg { opacity: 0.55; }
.store-sm {
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 8.5px; letter-spacing: 1.2px; text-transform: uppercase; opacity: 0.72;
}
.store-lg { font-size: 15px; font-weight: 600; letter-spacing: -0.02em; margin-top: 1px; }
.stores-note {
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 10.5px; letter-spacing: 1.4px; text-transform: uppercase; color: var(--ink-3);
}

/* phone + toggles */
.shot-col { display: flex; flex-direction: column; align-items: center; gap: 16px; }
.toggles { display: flex; gap: 10px; flex-wrap: wrap; justify-content: center; }
.toggle {
  display: flex; background: var(--paper); border: 1px solid var(--line);
  border-radius: 9px; padding: 3px; gap: 2px;
}
.toggle button {
  display: flex; align-items: center; gap: 7px; padding: 8px 15px; border-radius: 6px;
  border: 0; background: transparent; color: var(--ink-3); cursor: pointer;
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 10px; letter-spacing: 1.3px; text-transform: uppercase; font-weight: 500;
}
.toggle button:hover { color: var(--ink); }
.toggle button.on { background: var(--ink); color: var(--paper); }
.toggle button.on.night { background: var(--night); color: var(--night-ink); }
.dot { width: 8px; height: 8px; border-radius: 2px; display: block; }
.dot-night { background: var(--amber); }
.dot-day { background: var(--accent); }

.phone {
  border: 1px solid var(--line); border-radius: 26px; padding: 8px; background: var(--paper);
  transition: background 0.25s cubic-bezier(0.16, 1, 0.3, 1);
}
.phone.night { background: var(--night-2); border-color: var(--night-line); }
.phone img { width: 216px; height: auto; max-width: 100%; display: block; border-radius: 17px; }
.shot-caption {
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 9.5px; letter-spacing: 1.3px; text-transform: uppercase; color: var(--ink-3);
}

/* Five screens, five dots. They are the only affordance saying the phone is a carousel
   and not a static image, so they carry real hit area under a small painted target. */
.shot-dots { display: flex; gap: 7px; }
.shot-dot {
  width: 18px; height: 18px; padding: 0; border: 0; background: transparent;
  cursor: pointer; display: flex; align-items: center; justify-content: center;
}
.shot-dot::after {
  content: ''; width: 6px; height: 6px; border-radius: 50%;
  background: var(--line);
  transition: background 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}
.shot-dot:hover::after { background: var(--ink-3); }
.shot-dot.on::after { background: var(--accent); }
.shot-dot:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; border-radius: 50%; }

/* A shift with no screenshots yet reads as pending, not broken. */
.toggle button.unavailable { opacity: 0.4; cursor: default; }
.toggle button.unavailable:hover { background: transparent; }

/* The image itself crossfades rather than cutting, but only for people who want motion. */
.phone img { transition: opacity 0.3s cubic-bezier(0.16, 1, 0.3, 1); }
@media (prefers-reduced-motion: reduce) {
  .phone img, .shot-dot::after { transition: none; }
}

/* sections */
.section { padding: clamp(48px, 6vw, 72px) clamp(16px, 5vw, 72px) 0; }
.section:last-of-type { padding-bottom: clamp(48px, 6vw, 76px); }
.section-eyebrow {
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 11px; letter-spacing: 2.2px; text-transform: uppercase;
  color: var(--ink-3); margin-bottom: 30px;
}

.steps { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
.step { padding: 30px clamp(20px, 3vw, 44px) 0 0; border-top: 2px solid var(--ink); }
.step + .step { padding-left: clamp(20px, 3vw, 44px); border-left: 1px solid var(--line); }
.step:last-child { padding-right: 0; }
.step-num {
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 13px; color: var(--ink-3); margin-bottom: 12px;
}
.step h3 { font-size: 22px; font-weight: 600; letter-spacing: -0.024em; margin: 0 0 12px; }
.step p { font-size: 15px; line-height: 1.68; color: var(--ink-2); margin: 0; }

/* what's inside — 2x2 so it reads as a set of surfaces, not a numbered sequence
   like .steps above it. Same type scale and rules, hairline instead of the
   2px cap, so the two sections stay related without competing. */
.features { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0; }
.feature { padding: 26px clamp(20px, 3vw, 44px) 26px 0; border-top: 1px solid var(--line); }
.feature:nth-child(even) { padding-left: clamp(20px, 3vw, 44px); border-left: 1px solid var(--line); }
.feature h3 { font-size: 19px; font-weight: 600; letter-spacing: -0.02em; margin: 0 0 10px; }
.feature p { font-size: 15px; line-height: 1.68; color: var(--ink-2); margin: 0; }

/* reviews */
.reviews { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
.review-card { border: 1px solid var(--line); border-radius: 10px; padding: 30px 32px; }
.review-card.pending { border-style: dashed; display: flex; flex-direction: column; }
.review-head {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 22px; gap: 16px; flex-wrap: wrap;
}
.store-name {
  display: flex; align-items: center; gap: 10px;
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 10.5px; letter-spacing: 1.6px; text-transform: uppercase; color: var(--ink-2);
}
.rating { display: flex; align-items: center; gap: 9px; }
.stars { display: flex; gap: 2px; }
.rating-n { font-size: 14px; font-weight: 600; }
.rating-count { font-size: 13px; color: var(--ink-3); }
.review + .review { border-top: 1px solid var(--line); padding-top: 18px; margin-top: 18px; }
.review h3 { font-size: 15px; font-weight: 600; margin: 0 0 5px; }
.review p { font-size: 14px; line-height: 1.62; color: var(--ink-2); margin: 0; }
.pending-body {
  flex-grow: 1; display: flex; flex-direction: column; justify-content: center;
  align-items: flex-start; gap: 10px;
}
.pending-body h3 { font-size: 19px; font-weight: 600; letter-spacing: -0.02em; margin: 0; }
.pending-body p { font-size: 14px; line-height: 1.62; color: var(--ink-2); margin: 0; max-width: 320px; }

/* stats */
.stats { display: flex; align-items: baseline; gap: clamp(20px, 4vw, 40px); flex-wrap: wrap;
         border-top: 1px solid var(--line); padding-top: 40px; }
.stat-n { font-size: 30px; font-weight: 600; letter-spacing: -0.03em; }
.stat-l {
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 11px; letter-spacing: 1.4px; text-transform: uppercase;
  color: var(--ink-3); margin-left: 6px;
}

/* faq */
.faq { max-width: 760px; }
.faq details { border-bottom: 1px solid var(--line); padding: 18px 0; }
.faq summary {
  font-size: 17px; font-weight: 600; letter-spacing: -0.018em; cursor: pointer;
  list-style: none; display: flex; justify-content: space-between; gap: 16px;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: '+'; color: var(--ink-3); font-weight: 400; }
.faq details[open] summary::after { content: '\2212'; }
.faq details p { font-size: 15px; line-height: 1.7; color: var(--ink-2); margin: 14px 0 0; }

@media (max-width: 900px) {
  .app-hero-grid { grid-template-columns: 1fr; }
  .shot-col { order: -1; }
  .steps { grid-template-columns: 1fr; }
  .step, .step + .step {
    padding: 24px 0 0; border-left: 0; border-top: 2px solid var(--ink); margin-top: 24px;
  }
  .step:first-child { margin-top: 0; }
  .features { grid-template-columns: 1fr; }
  .feature, .feature:nth-child(even) { padding: 22px 0; border-left: 0; }
  .reviews { grid-template-columns: 1fr; }
}

/* ─────────────────────────────────────────────────────────────────────────
   TWO SHIFTS, ONE PAGE.

   The app ships two identities (BrandKit: Night Shift amber console, Day Shift
   cool slate). Rather than describe that, /app BECOMES it: the toggle flips
   [data-shift] on <html> and every token below is redefined. The conveyor and
   the reach map inherit it for free because they were already token-driven.

   Day is the default so /app matches the rest of the site on a cold visit;
   the choice is remembered in localStorage.
   ───────────────────────────────────────────────────────────────────────── */

:root, [data-shift="day"] {
  --mono: 'IBM Plex Mono', ui-monospace, monospace;
  --ink-soft: var(--ink-3);
  --green: oklch(58% 0.15 155);
  /* Day Shift: the brand accent IS blue. */
  --paper:  #f6f7f9;
  --ground: #ffffff;
  --ink:    #26282e;
  --accent: #1d4ed8;
  --accent-hover: #1a44be;
  --amber: var(--accent);
  --page: var(--paper);
  --panel: var(--ground);
  --hairline: var(--line);
}

[data-shift="night"] {
  /* Night Shift matches the app and the live homepage: the app's two surfaces,
     #06050a page and #100d08 panels, sampled from the screenshots. */
  --ground: #06050a;
  --paper:  #06050a;
  --ink:    #f4f1ea;
  --ink-2:  #a8a399;
  --ink-3:  #8a8478;
  --ink-soft: #a8a399;
  --muted:  #8a8478;
  --line:   #1c1a14;
  --line-2: #2a2620;
  --accent: #ffb000;
  --accent-hover: #ffc233;
  --accent-soft: #3a2a08;
  --amber:  #ffb000;
  --amber-warm: #ff7a00;
  --amber-deep: #cc8a00;
  --amber-dim: #7a5a00;
  --green:  #00d27a;
  --page: #06050a;
  --panel: #100d08;
  --hairline: #1c1a14;
  --night: #06050a; --night-2: #100d08; --night-line: #2a2620;
}

[data-shift="night"] body { background: var(--paper); color: var(--ink); }
[data-shift="night"] .app-hero { background: var(--ground); }
[data-shift="night"] .store { background: var(--accent); color: #0c0a07; }
[data-shift="night"] .store-sm { opacity: .8; }
[data-shift="night"] .review-card,
[data-shift="night"] .phone,
[data-shift="night"] .toggle { background: var(--panel); border-color: var(--line); }
[data-shift="night"] .toggle button.on { background: var(--accent); color: #0c0a07; }
[data-shift="night"] .toggle button.on.night { background: var(--accent); color: #0c0a07; }
[data-shift="night"] .step { border-top-color: var(--ink); }
[data-shift="night"] .faq details { border-bottom-color: var(--line); }

/* The page chrome follows the shift too, so the seam never shows -- but the rules for
   that now live in chrome.css, which matches [data-shift="night"] alongside its own
   [data-chrome="night"]. The chrome owns its palette; this file only drives the toggle.
   Keeping a copy here is what let the two drift, so there is deliberately none. */

/* The shift toggle crossfades the whole page via a view transition (app-toggle.js). */
::view-transition-old(root), ::view-transition-new(root) { animation-duration: .35s; animation-timing-function: cubic-bezier(.16,1,.3,1); }
/* First paint only: the inline head script sets this while it corrects the shift from
   localStorage, so a restored choice appears instantly instead of fading in from the
   markup default. Both rAFs later it is gone and the toggle animates normally. */
html.no-anim, html.no-anim * { transition: none !important; animation: none !important; }

/* conveyor sits under the hero */
.belt-wrap { padding: 0 0 clamp(16px, 2.5vw, 28px); background: var(--ground); border-bottom: 1px solid var(--line); }
[data-shift="night"] .belt-wrap { background: var(--ground); }

@media (prefers-reduced-motion: reduce) {
  .track { animation: none !important; }
}

/* ── reach map ───────────────────────────────────────────────────────────
   Static rebuild of the homepage's interactive map. Tokens, so it flips
   with [data-shift] like everything else. */
.reach-wrap {
  padding: clamp(32px, 4vw, 48px) clamp(16px, 5vw, 72px);
  background: var(--ground); border-top: 1px solid var(--line);
}
.reach-inner { max-width: 1180px; margin: 0 auto; }
.reach-title {
  font-size: clamp(28px, 3.6vw, 46px); line-height: 1.08; letter-spacing: -0.035em;
  font-weight: 700; text-align: center; text-wrap: balance; margin: 0 auto 18px; max-width: 22ch;
}
.map-toggle { width: max-content; margin: 0 auto 18px; }
.map-toggle button[aria-pressed="true"] { background: var(--ink); color: var(--paper); }
[data-shift="night"] .map-toggle button[aria-pressed="true"] { background: var(--accent); color: #0c0a07; }
.map-toggle button:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.reach-map { width: 100%; height: auto; display: block; max-width: 880px; margin: 0 auto; }
.reach-map[hidden] { display: none; }
.reach-map .state, .reach-map .land {
  fill: transparent; stroke: var(--line); stroke-width: 1.1; vector-effect: non-scaling-stroke;
}
[data-shift="night"] .reach-map :is(.state, .land) { stroke: #2a2620; }
.reach-map .state[data-b="on"]   { stroke: var(--accent); stroke-opacity: .35; }
.reach-map .state[data-b="warm"] { stroke: var(--accent); stroke-opacity: .6; }
.reach-map .state[data-b="hot"]  { stroke: var(--accent); stroke-opacity: .9; }
.reach-map .core { fill: var(--accent); }
.reach-map .halo { fill: none; stroke: var(--accent); stroke-width: 1.2; opacity: .3; }
.reach-map .lc.hot .halo { opacity: .55; stroke-width: 1.6; }
.reach-map .lead { stroke: var(--ink-3); stroke-width: .7; opacity: .55; }
.reach-map .lbl {
  font-family: 'IBM Plex Mono', ui-monospace, monospace; font-weight: 600; letter-spacing: .05em;
  fill: var(--ink-2); paint-order: stroke fill; stroke: var(--ground); stroke-width: 4px; stroke-linejoin: round;
}
.reach-map .lbl .n { fill: var(--accent); font-weight: 700; }
.reach-map .lbl.hot  { font-size: 16px; font-weight: 700; fill: var(--ink); }
.reach-map .lbl.warm { font-size: 13px; fill: var(--ink); }
.reach-map .lbl.on   { font-size: 10.5px; }
.reach-map .lbl.tiny { font-size: 8.5px; fill: var(--ink-3); font-weight: 500; }
.reach-map .lbl.w { font-size: 22px; font-weight: 700; fill: var(--ink); }
.reach-stats {
  display: flex; gap: clamp(20px, 4vw, 44px); flex-wrap: wrap;
  justify-content: center; margin-top: 26px;
  border-top: 1px solid var(--line); padding-top: 22px;
}
.reach-stats .stat-n { font-size: clamp(20px, 2vw, 26px); font-weight: 600; letter-spacing: -0.028em; }
.reach-stats .stat-l {
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 10.5px; letter-spacing: 1.4px; text-transform: uppercase;
  color: var(--ink-3); margin-left: 7px;
}
.reach-foot { text-align: center; margin: 10px 0 0; font-family: var(--mono, ui-monospace, monospace); font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3, #8a8f98); }
