/*
 * coffeax.com marketing stylesheet.
 *
 * This is the marketing site, not the app. Two things are allowed here that
 * are bugs inside FarmworkX:
 *
 *   The brand faces. EB Garamond and IBM Plex, per docs/17 and the brand
 *   spec. The app uses a system stack because a webfont that fails on rural
 *   data leaves a farm owner staring at nothing. A marketing page can wait.
 *
 *   Layer zero, the brand-only colours. Brand laterite is 5.4:1 and blossom
 *   is 1.6:1, so neither carries body text anywhere. They carry the mark,
 *   fills and dark panels. Body text on this page still runs at 7:1 or
 *   better, measured against its own ground, because the reader is the same
 *   person in the same sunlight.
 *
 * Every value below is a token. CLAUDE.md invariant 12 holds on this side of
 * the wall too. Nothing here loads a tracker: invariant 10 puts the analytics
 * on this hostname and never on the app, and even here it is Cloudflare Web
 * Analytics only, added at deploy and not in this file.
 */

:root {
  /* ---- Layer one: CoffeaX primitives. Copied from the app token file,
         which stays the source of truth. Do not diverge. ---------------- */
  --cx-paper: #FBF8F3;
  --cx-card: #FFFFFF;
  --cx-ink: #1C1917;
  --cx-ink-soft: #57534E;
  /* One step darker, for the sunk ground where --cx-ink-soft only reaches
     6.39:1. Measured against --cx-paper-2, not against paper. */
  --cx-ink-soft-sunk: #4A4642;
  /* Darker again, for the mocked Telegram bubbles, where the outgoing green
     is lighter than paper. 7.2:1 on that green, 8.9:1 on white. */
  --cx-ink-soft-bubble: #46423E;
  --cx-bean: #3E2723;
  --cx-leaf: #245C42;
  --cx-laterite: #8F3316;
  --cx-amber: #92400E;
  --cx-sky: #1E40AF;

  /* ---- Layer zero: brand only. Legal here, a bug in the app. --------- */
  --cx-brand-laterite: #A84A22;
  --cx-brand-compost: #2E241E;
  --cx-brand-blossom: #E6BFC6;
  --cx-brand-leaf-lift: #4E9E6B;
  --cx-brand-clay: #8A6B73;

  /* A second paper, one step down. The brand spec's demo ground. */
  --cx-paper-2: #F1EAE0;

  /* Hairlines and washes, expressed from ink so they stay in the family. */
  --cx-hair: rgba(28, 25, 23, .14);
  --cx-hair-soft: rgba(28, 25, 23, .08);
  --cx-hair-strong: rgba(28, 25, 23, .22);
  --cx-hair-reversed: rgba(251, 248, 243, .18);
  --cx-wash: rgba(28, 25, 23, .05);

  /* Telegram's own colours, used only inside the mocked chat on the
     FarmworkX page. They are not CoffeaX values and nothing else may name
     them: they exist so the mock reads as Telegram at a glance, and so that
     an app component naming one is visibly wrong in review.

     Taken from Telegram's own iOS source, DefaultDayPresentationTheme.swift,
     rather than from a brand palette page: the accent is 0x0088ff, the
     outgoing bubble 0xe1ffc7, the incoming bubble white and the navigation
     bar a light grey with black text.

     The green bubble is genuinely Telegram's and not WhatsApp's. What made
     the first version read as WhatsApp was everything around it: a dark
     header, a green sender name and dark blue keys. Telegram's chrome is
     light grey and its accent is a bright blue, so the green sits in a cool
     frame rather than a warm one. */
  --tg-accent: #0088FF;        /* Links, inline keys, the sender name */
  --tg-wallpaper: #D6E3EC;     /* The chat ground, a cool grey blue */
  --tg-bubble-out: #E1FFC7;    /* Outgoing, Telegram's classic pale green */
  --tg-bubble-in: #FFFFFF;     /* Incoming */
  --tg-bar: #F7F7F7;           /* Navigation bar */
  --tg-bar-text: #000000;
  /* Telegram ships #787878 here and #0088FF for the keys, which measure
     4.1:1 and 3.5:1. This project's floor is 7:1, for a farm owner reading
     a phone in the sun, and a replica is not a reason to drop it. Both are
     darkened until they clear, which keeps the Telegram read: the hue is
     what the eye names, not the exact value. Measured, not judged. */
  --tg-bar-sub: #545454;       /* The member count. 7.1:1 on the bar */
  /* Blue wherever the blue carries text: a sender name, a mention, an inline
     key. Computed against every ground it actually lands on, including the
     key's own 8% blue tint over white, which is the one a white-based sum
     gets wrong. 7.1:1 on the key fill, 7.8:1 on white, 7.2:1 on the green
     outgoing bubble. */
  --tg-accent-text: #00529B;
  --tg-stroke: #C8C7CC;        /* Bubble and bar separators */
  /* Telegram gives each sender in a group its own colour from a small set.
     Two people and a bot need two, so the second is this deeper blue. */
  --tg-name-2: #1E6FB8;

  /* Soil strata. A 4px horizontal grain at 5.5% ink, per the brand spec.
     Under dark panels only. Never under body text, never over a photograph. */
  --cx-grain: repeating-linear-gradient(
    0deg, rgba(28, 25, 23, .055) 0 1px, transparent 1px 4px);

  /* ---- Type. Two faces outside the app, none inside it. ------------- */
  --cx-serif: "EB Garamond", Georgia, "Times New Roman", serif;
  --cx-sans: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", Roboto,
             "Helvetica Neue", Arial, sans-serif;
  --cx-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* The brand scale runs two steps past the app's: 44 and 64 exist for a
     page nobody reads standing in a field. */
  --cx-text-xs: 13px;
  --cx-text-sm: 15px;
  --cx-text-base: 17px;
  --cx-text-lg: 20px;
  --cx-text-xl: 24px;
  --cx-text-2xl: 32px;
  --cx-text-3xl: 44px;
  --cx-text-4xl: 64px;

  --cx-leading-body: 1.5;
  --cx-leading-heading: 1.25;
  --cx-leading-display: 1.03;

  /* ---- Space. The app's seven steps, and nothing between them. ------ */
  --cx-space-1: 4px;
  --cx-space-2: 8px;
  --cx-space-3: 12px;
  --cx-space-4: 16px;
  --cx-space-5: 24px;
  --cx-space-6: 32px;
  --cx-space-7: 48px;
  --cx-space-8: 72px;
  --cx-space-9: 112px;

  --cx-radius-card: 8px;
  --cx-radius-button: 6px;
  --cx-radius-chip: 999px;
  --cx-radius-hair: 2px;

  --cx-tap-min: 48px;
  --cx-tap-gap: 8px;

  --cx-measure: 62ch;
  --cx-wrap: 1080px;

  /* ---- Layer two: page semantics. Named by job. ---------------------- */
  --surface: var(--cx-paper);
  --surface-sunk: var(--cx-paper-2);
  --surface-raised: var(--cx-card);
  --surface-dark: var(--cx-brand-compost);
  --text: var(--cx-ink);
  --text-muted: var(--cx-ink-soft);
  --text-reversed: var(--cx-paper);
  --text-reversed-muted: rgba(251, 248, 243, .72);
  --border: var(--cx-hair);
  --action: var(--cx-bean);
  --action-text: var(--cx-card);
  --link: var(--cx-laterite);
  --accent: var(--cx-brand-laterite);
  --focus-ring: var(--cx-sky);
}

/* ---- Base ---------------------------------------------------------- */

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

html {
  background: var(--surface);
  color: var(--text);
  font-family: var(--cx-sans);
  font-size: var(--cx-text-base);
  line-height: var(--cx-leading-body);
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}

body { margin: 0; overflow-x: hidden; }

h1, h2, h3, h4 {
  font-family: var(--cx-serif);
  font-weight: 400;
  letter-spacing: -.012em;
  line-height: var(--cx-leading-heading);
  margin: 0;
  text-wrap: balance;
}

p { margin: 0 0 1em; max-width: var(--cx-measure); text-wrap: pretty; }

a { color: var(--link); text-underline-offset: .18em; }
a:hover { color: var(--cx-bean); }

img, svg { max-width: 100%; }

:focus { outline: none; }
:focus-visible { outline: 3px solid var(--focus-ring); outline-offset: 2px; }
::selection { background: var(--cx-brand-blossom); color: var(--cx-ink); }

.skip {
  position: absolute; left: -9999px;
  background: var(--action); color: var(--action-text);
  padding: var(--cx-space-3) var(--cx-space-4);
  border-radius: var(--cx-radius-button);
  z-index: 50;
}
.skip:focus { left: var(--cx-space-4); top: var(--cx-space-4); }

/* ---- Layout -------------------------------------------------------- */

.wrap {
  max-width: var(--cx-wrap);
  margin: 0 auto;
  padding-inline: clamp(20px, 5vw, 52px);
}
.wrap-narrow { max-width: 760px; }

.band { padding-block: clamp(56px, 9vw, 112px); }
.band-tight { padding-block: clamp(40px, 6vw, 72px); }
.band-sunk { background: var(--surface-sunk); --text-muted: var(--cx-ink-soft-sunk); }
/* The walk-fact and the demo ground are sunk paper wherever they sit. */
.walk-fact { --text-muted: var(--cx-ink-soft-sunk); }
.band-dark {
  background: var(--surface-dark);
  background-image: var(--cx-grain);
  color: var(--text-reversed);
}
.band-dark h1, .band-dark h2, .band-dark h3 { color: var(--text-reversed); }
.band-dark p { color: var(--text-reversed-muted); }
.band-dark a { color: var(--cx-brand-blossom); }
.band-dark a:hover { color: var(--text-reversed); }
.band-dark .kick { color: var(--text-reversed-muted); }

.rule { height: 1px; border: 0; background: var(--border); margin: 0; }

/* ---- Type helpers -------------------------------------------------- */

.kick {
  font-family: var(--cx-mono);
  font-size: 10px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--text-muted);
  display: block;
  margin-bottom: var(--cx-space-4);
}

.display {
  font-size: clamp(38px, 6.4vw, var(--cx-text-4xl));
  line-height: var(--cx-leading-display);
}
.h2 { font-size: clamp(26px, 3.6vw, var(--cx-text-3xl)); line-height: 1.08; }
.h3 { font-size: var(--cx-text-xl); }

.lede {
  font-family: var(--cx-serif);
  font-size: clamp(20px, 2.4vw, 26px);
  line-height: 1.42;
  max-width: 54ch;
  color: var(--text);
}
.band-dark .lede { color: var(--text-reversed); }

.note { font-size: var(--cx-text-sm); color: var(--text-muted); max-width: 60ch; }
.mono { font-family: var(--cx-mono); font-size: var(--cx-text-xs); }
.sci { font-style: italic; }

/* ---- Buttons ------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--cx-space-2);
  min-height: var(--cx-tap-min);
  padding-inline: var(--cx-space-5);
  border: 1px solid transparent;
  border-radius: var(--cx-radius-button);
  font-family: var(--cx-sans);
  font-size: var(--cx-text-base);
  text-decoration: none;
  cursor: pointer;
  background: transparent;
  color: var(--text);
  transition: background-color .15s ease, border-color .15s ease;
}
.btn-primary { background: var(--action); color: var(--action-text); border-color: var(--action); }
.btn-primary:hover { background: #2C1B18; color: var(--action-text); }
.btn-primary:active { background: #1F110F; }
.btn-secondary { border-color: var(--cx-hair-strong); color: var(--text); }
.btn-secondary:hover { background: var(--cx-wash); color: var(--text); }
.band-dark .btn-secondary { border-color: var(--cx-hair-reversed); color: var(--text-reversed); }
.band-dark .btn-secondary:hover { background: rgba(251, 248, 243, .1); color: var(--text-reversed); }
.band-dark .btn-primary { background: var(--cx-paper); color: var(--cx-brand-compost); border-color: var(--cx-paper); }
.band-dark .btn-primary:hover { background: #FFFFFF; color: var(--cx-brand-compost); }

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--cx-tap-gap) var(--cx-space-3);
  margin-top: var(--cx-space-6);
}

/* ---- The mark ------------------------------------------------------ */

.lockup {
  display: inline-flex;
  align-items: center;
  min-height: var(--cx-tap-min);
  gap: var(--cx-space-3);
  text-decoration: none;
  color: inherit;
  font-family: var(--cx-serif);
  letter-spacing: -.012em;
}
.lockup svg { flex: none; display: block; }
.lockup-name { font-size: var(--cx-text-xl); }
.lockup-parent {
  font-family: var(--cx-mono);
  font-size: 10px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--text-muted);
  display: block;
  margin-bottom: 2px;
}
.band-dark .lockup-parent { color: var(--text-reversed-muted); }

/* ---- Header and footer --------------------------------------------- */

.site-head {
  position: sticky;
  top: 0;
  z-index: 20;
  background: rgba(251, 248, 243, .92);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--border);
}
.site-head .wrap {
  display: flex;
  align-items: center;
  gap: var(--cx-space-4);
  min-height: 68px;
  padding-block: var(--cx-space-2);
}
.site-nav {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: var(--cx-space-2);
}
.site-nav a:not(.btn) {
  display: inline-flex;
  align-items: center;
  min-height: var(--cx-tap-min);
  padding-inline: var(--cx-space-3);
  border-radius: var(--cx-radius-button);
  color: var(--text);
  text-decoration: none;
  font-size: var(--cx-text-sm);
}
.site-nav a:not(.btn):hover { background: var(--cx-wash); }
.site-nav .btn { font-size: var(--cx-text-sm); padding-inline: var(--cx-space-4); }

.site-foot { background: var(--surface-dark); background-image: var(--cx-grain); color: var(--text-reversed); }
.site-foot .wrap { padding-block: clamp(40px, 6vw, 72px); }
.site-foot a { color: var(--cx-brand-blossom); }
.site-foot a:hover { color: var(--text-reversed); }
.foot-grid {
  display: grid;
  gap: var(--cx-space-6);
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
}
.foot-grid h3 {
  font-family: var(--cx-mono);
  font-size: 10px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--text-reversed-muted);
  margin-bottom: var(--cx-space-3);
}
.foot-grid ul { list-style: none; margin: 0; padding: 0; }
.foot-grid li { font-size: var(--cx-text-sm); }
/* 48px tall with 8px between, per docs/17. A footer link is exactly the kind
   a thumb misses on a phone held one handed. */
.foot-grid li a {
  display: flex;
  align-items: center;
  min-height: var(--cx-tap-min);
  margin-bottom: var(--cx-tap-gap);
}
.foot-base {
  margin-top: var(--cx-space-7);
  padding-top: var(--cx-space-5);
  border-top: 1px solid var(--cx-hair-reversed);
  display: flex;
  flex-wrap: wrap;
  gap: var(--cx-space-3) var(--cx-space-5);
  align-items: baseline;
  font-size: var(--cx-text-sm);
  color: var(--text-reversed-muted);
}

/* ---- Cards and grids ----------------------------------------------- */

.grid { display: grid; gap: clamp(16px, 2.4vw, 24px); }
.g2 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.g3 { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }

.card {
  background: var(--surface-raised);
  border-radius: var(--cx-radius-card);
  padding: var(--cx-space-5);
  box-shadow: 0 1px 2px rgba(28, 25, 23, .06), 0 0 0 1px var(--cx-hair-soft);
  display: flex;
  flex-direction: column;
  gap: var(--cx-space-3);
}
.card h3 { font-size: var(--cx-text-lg); }
.card p { margin: 0; font-size: var(--cx-text-sm); color: var(--text-muted); }

.plain { padding-left: var(--cx-space-4); box-shadow: inset 2px 0 0 var(--accent); }
.plain h3 { font-size: var(--cx-text-lg); margin-bottom: var(--cx-space-2); }
.plain p { margin: 0; font-size: var(--cx-text-sm); color: var(--text-muted); }

/* A link inside running text cannot be boxed to 48px without breaking the
   line, so it gets a taller hit area that does not change layout. The height
   is set rather than padded, because padding lands a pixel short once the
   line box rounds. */
.plain p a, .faq .answer a, .note a {
  display: inline-block;
  min-height: var(--cx-tap-min);
  padding-block: var(--cx-space-3);
  margin-block: calc(var(--cx-space-3) * -1);
}
.band-dark .plain { box-shadow: inset 2px 0 0 var(--cx-brand-blossom); }
/* .plain p names --text-muted, which is a dark grey and lands at 1.98:1 on
   the compost ground. Inside a dark band it takes the reversed muted token
   instead, which measures 10.6:1. */
.band-dark .plain p { color: var(--text-reversed-muted); }

/* ---- Status, shared with the app's semantics ------------------------ */

.status {
  display: inline-flex;
  align-items: center;
  gap: var(--cx-space-2);
  padding: var(--cx-space-1) var(--cx-space-3);
  border-radius: var(--cx-radius-chip);
  font-size: var(--cx-text-sm);
  color: var(--cx-card);
  white-space: nowrap;
}
.status .gl { width: 11px; height: 11px; flex: none; background: currentColor; }
.s-overdue { background: var(--cx-laterite); }
.s-overdue .gl { clip-path: polygon(50% 0, 100% 100%, 0 100%); }
.s-soon { background: var(--cx-amber); }
.s-soon .gl { clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%); }
.s-info { background: var(--cx-sky); }
.s-info .gl { border-radius: 50%; }
.s-done { background: var(--cx-leaf); }
.s-done .gl { clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%); }

/* ---- Faq ------------------------------------------------------------ */

.faq { border-top: 1px solid var(--border); max-width: 760px; }
.faq details { border-bottom: 1px solid var(--border); }
.faq summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: var(--cx-space-4);
  min-height: var(--cx-tap-min);
  padding: var(--cx-space-3) 0;
  font-family: var(--cx-serif);
  font-size: var(--cx-text-lg);
  line-height: var(--cx-leading-heading);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "+";
  margin-left: auto;
  font-family: var(--cx-mono);
  font-size: var(--cx-text-lg);
  color: var(--text-muted);
  flex: none;
}
.faq details[open] summary::after { content: "\2212"; }
.faq summary:hover { color: var(--link); }
.faq .answer { padding: 0 0 var(--cx-space-5); }
.faq .answer p { font-size: var(--cx-text-base); color: var(--text-muted); }
.faq .answer p:last-child { margin-bottom: 0; }

/* ---- The dashboard band on /tech/farmworkx, v2 PR 6 ---------------- */

/* Four text tabs on the strong rule, the selected one carrying an inset
   bean underline: a shape, so the state is never colour alone. 48 high. */
.dash-lead { margin-top: var(--cx-space-4); color: var(--text-muted); max-width: var(--cx-measure); text-wrap: pretty; }
.dash { margin-top: var(--cx-space-6); }
.dash-tabs {
  display: flex; flex-wrap: wrap;
  gap: var(--cx-space-1) var(--cx-space-2);
  border-bottom: 1px solid var(--cx-hair-strong);
}
.dash-tab {
  display: inline-flex; align-items: center; gap: var(--cx-space-2);
  min-height: var(--cx-tap-min);
  padding: 0 var(--cx-space-3);
  margin-bottom: -1px;
  border: 0;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: var(--cx-text-base);
  cursor: pointer;
  box-shadow: inset 0 -2px 0 transparent;
}
.dash-tab:hover { background: var(--cx-wash); }
.dash-tab[aria-selected="true"] { box-shadow: inset 0 -2px 0 var(--cx-bean); }
.dash-tab-n { font-family: var(--cx-mono); font-size: var(--cx-text-xs); color: var(--text-muted); }
/* The step's sentence in ink and its rule in the muted ink, side by side
   while there is room. */
.dash-text {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--cx-space-2) var(--cx-space-6);
  margin: var(--cx-space-4) 0 var(--cx-space-5);
}
.dash-text p { margin: 0; max-width: 52ch; text-wrap: pretty; }
.dash-rule { color: var(--text-muted); }
/* The frame: the dashboard at its laptop size, scaled by the script to the
   column. Without the script, or before it has measured, the iframe fills
   the frame at 100% and nothing can be clipped: correctness never depends on
   the transform landing. Only once the script has measured and scaled
   (.is-scaled) is the iframe wider than its frame, by exactly the scale it
   set. Site fix defect 2. */
.dash-frame {
  width: 100%;
  aspect-ratio: 1180 / 760;
  overflow: hidden;
  border-radius: var(--cx-radius-card);
  box-shadow: 0 1px 2px rgba(28, 25, 23, .06), 0 0 0 1px var(--cx-hair-soft);
  background: var(--cx-paper);
}
.dash-frame iframe { display: block; border: 0; width: 100%; height: 100%; transform-origin: 0 0; }
.dash-frame.is-scaled iframe {
  width: var(--dash-w);
  height: var(--dash-h);
  transform: scale(var(--dash-scale));
}
@media (max-width: 719px) { .dash-frame { aspect-ratio: 360 / 720; } }

