/* GENERATED FILE — do not edit by hand.
   Source: design/tokens.json
   Regenerate with `node design/generate-tokens.mjs` (or `make tokens`).

   Consumed by the pages the Go backend renders itself — see internal/webstyle.
   The property names match tailwind.css's @theme output on purpose, so markup
   moves between a React component and a server-rendered page unchanged. */

:root {
  color-scheme: light dark;

  --color-bark: #2C1A0E;
  --color-soil: #4A3218;
  --color-leaf: #2E6B34;
  --color-harvest: #7C3D0C;
  --color-sky: #1D6278;
  --color-parchment: #F5F0E8;
  --color-card: #FDFAF4;
  --color-muted: #57412E;

  --font-serif: Georgia, "Times New Roman", Times, serif;

  --text-heading: 22px;
  --text-subheading: 14px;
  --text-body: 14px;
  --text-label: 11px;
  --text-caption: 11px;

  --spacing-unit: 8px;
  --spacing-screen-x: 20px;
  --spacing-card-gap: 16px;
  --spacing-section: 24px;

  --container-page: 480px;
  --height-touch: 44px;

  --gradient-body: linear-gradient(to bottom, #EEF4F8 0%, #F5F0E8 40%, #E6EDE5 100%);
}

@media (prefers-color-scheme: dark) {
  :root {
    --color-bark: #EDE0CE;
    --color-soil: #C4AA8C;
    --color-leaf: #6DB87A;
    --color-harvest: #C77A4E;
    --color-sky: #59ABCC;
    --color-parchment: #131C10;
    --color-card: #1A2516;
    --color-muted: #8A7A6A;

    --gradient-body: linear-gradient(to bottom, #0D1520 0%, #121A0F 40%, #0D1509 100%);
  }
}

/* Page-level defaults for the surfaces the Go backend renders itself.
   Hand-written; the values it reads come from tokens.css, which is generated.

   This is the block that used to live at the top of internal/articles/article.css
   under the comment "Manually kept in sync with tailwind.css" — one copy now,
   in front of every server-rendered page rather than just the article ones. */

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

html {
  overflow-x: hidden;
  overscroll-behavior-x: none;
}

body {
  margin: 0;
  font-family: var(--font-serif);
  font-size: var(--text-body);
  line-height: 1.6;
  color: var(--color-soil);
  /* `fixed` so the sky-to-earth gradient belongs to the window rather than to
     the content — a short page and a long one sit in the same garden. */
  background: var(--gradient-body) fixed;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
  max-width: 100vw;
}

/* Component recipes for server-rendered pages, mirroring the React components
   they have to sit alongside. Hand-written; every value it reads comes from
   tokens.css, which is generated from design/tokens.json.

   Each rule below names the component it mirrors. When one of those changes,
   this changes with it — that pairing is the whole point of the file, and is
   what design-system.md means by a component-level change landing on both
   platforms in the same PR.

   The `ga-` prefix keeps these out of the way of article.css's `.article-*`
   rules, which are appended to this bundle on the article and plant routes. */

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

/* A single centred card on an otherwise empty page — the shape LoginPage.tsx
   and ConsentPage.tsx use (`min-h-screen flex flex-col justify-center items-center`
   around a `max-w-sm`). Padding accounts for the notch on a phone opening this
   inside ASWebAuthenticationSession. */
.ga-center-page {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--spacing-screen-x);
  padding-top: max(var(--spacing-screen-x), env(safe-area-inset-top));
  padding-bottom: max(var(--spacing-screen-x), env(safe-area-inset-bottom));
}

/* --- Surfaces ----------------------------------------------------------- */

/* Card.tsx: `bg-card rounded-md shadow-sm`. One tone, no border — the shadow
   is what lifts it off the gradient. */
.ga-card {
  background: var(--color-card);
  border-radius: 0.375rem;
  box-shadow:
    0 1px 3px 0 rgb(0 0 0 / 0.1),
    0 1px 2px -1px rgb(0 0 0 / 0.1);
  padding: var(--spacing-section);
  width: 100%;
  max-width: 360px;
}

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

/* The heading role: 22px italic bark. Georgia's italic is the app's voice —
   every screen title in the React app is set this way. */
.ga-heading {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--text-heading);
  font-weight: normal;
  line-height: 1.3;
  color: var(--color-bark);
  margin: 0 0 var(--spacing-unit);
}

.ga-body {
  font-size: var(--text-body);
  color: var(--color-soil);
  line-height: 1.5;
  margin: 0 0 var(--spacing-unit);
}

.ga-caption {
  font-size: var(--text-caption);
  color: var(--color-muted);
  line-height: 1.5;
  margin: 0 0 var(--spacing-unit);
}

/* InputField.tsx's label: `text-label uppercase tracking-wide text-soil`. */
.ga-label {
  display: block;
  font-size: var(--text-label);
  text-transform: uppercase;
  letter-spacing: 0.025em;
  color: var(--color-soil);
  margin: var(--spacing-card-gap) 0 4px;
}

/* --- Inputs ------------------------------------------------------------- */

/* InputField.tsx: `w-full px-4 py-3 border border-soil rounded-md font-serif
   text-body bg-card focus:ring-1 focus:ring-leaf`. font-size is bumped to 16px
   from the token's 14px on purpose: mobile Safari zooms the page on focus for
   anything smaller, which on a sign-in page inside ASWebAuthenticationSession
   leaves the gardener mid-form at 1.3× with no way back. */
.ga-input {
  width: 100%;
  padding: 12px 16px;
  border: 1px solid var(--color-soil);
  border-radius: 0.375rem;
  font-family: var(--font-serif);
  font-size: 16px;
  color: var(--color-soil);
  background: var(--color-card);
}

.ga-input:focus {
  outline: none;
  box-shadow: 0 0 0 1px var(--color-leaf);
  border-color: var(--color-leaf);
}

/* The one-time code, presented as one — mirrors InputField.tsx's `variant="code"`
   (`text-heading text-center tracking-[0.4em]`). Both surfaces show a code the
   same way on purpose: a code field that looks like the email field above it is
   what makes people type their address into it, which is the confusion this
   variant exists to remove. The 0.4em indent cancels the trailing letter-space
   so the digits sit optically centred rather than pushed left. */
.ga-input-code {
  font-size: var(--text-heading);
  text-align: center;
  letter-spacing: 0.4em;
  text-indent: 0.4em;
}

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

/* Button.tsx: BUTTON_BASE_CLASS + BUTTON_SIZE_CLASS.md. min-height is the
   44pt touch target (Fitts's Law) — not negotiable on any of these. */
.ga-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: var(--height-touch);
  padding: 12px 24px;
  border: none;
  border-radius: 0.375rem;
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 13px;
  cursor: pointer;
  transition: all 200ms;
}

.ga-btn:hover {
  filter: brightness(0.95);
}

.ga-btn:active {
  filter: brightness(0.9);
}

/* BUTTON_VARIANT_CLASS.primary + BUTTON_GRADIENT_STYLE.primary: dark bark text
   on a light sage gradient, not white-on-forest-green. The color-mix operands
   are tailwind.css's --btn-primary-from/to, inlined here because those two are
   webOnly tokens (design/tokens.json) with no generated counterpart. */
.ga-btn-primary {
  color: var(--color-bark);
  background: linear-gradient(
    to bottom,
    color-mix(in srgb, var(--color-leaf) 35%, white) 0%,
    color-mix(in srgb, var(--color-leaf) 50%, white) 100%
  );
}

@media (prefers-color-scheme: dark) {
  .ga-btn-primary {
    background: linear-gradient(
      to bottom,
      color-mix(in srgb, var(--color-leaf) 45%, var(--color-parchment)) 0%,
      color-mix(in srgb, var(--color-leaf) 60%, var(--color-parchment)) 100%
    );
  }
}

/* BUTTON_VARIANT_CLASS.destructive: harvest outline on a barely-there tint.
   Used for "Deny this connection" — declining is a real, safe choice, so it
   gets a real button rather than the underlined-link treatment it had before. */
.ga-btn-destructive {
  color: var(--color-harvest);
  border: 1px solid var(--color-harvest);
  background: linear-gradient(
    to bottom,
    color-mix(in srgb, var(--color-harvest) 10%, transparent) 0%,
    color-mix(in srgb, var(--color-harvest) 4%, transparent) 100%
  );
}

/* --- Notices ------------------------------------------------------------ */

/* NotificationCard.tsx: a Card with a 4px left rule in the accent colour and
   the message in body type. The rule is what makes a notice read as a notice
   at a glance — same object here as in the app.

   One deviation, and it's forced: NotificationCard is a `card`-toned surface
   sitting on the page gradient, which is what separates it. These notices sit
   *inside* .ga-card, so the same fill would be card-on-card and the rule would
   be doing all the work alone. A few percent of the accent mixed into the card
   tone restores the separation without introducing a second colour — still one
   tone, per design-system.md's card rule. */
.ga-notice {
  border-radius: 0.375rem;
  border-left: 4px solid var(--color-sky);
  background: color-mix(in srgb, var(--color-sky) 7%, var(--color-card));
  padding: 12px;
  font-size: var(--text-body);
  line-height: 1.5;
  color: var(--color-soil);
  margin: 0 0 var(--spacing-card-gap);
}

.ga-notice-warning {
  border-left-color: var(--color-harvest);
  background: color-mix(in srgb, var(--color-harvest) 7%, var(--color-card));
}

.ga-notice-error {
  border-left-color: var(--color-harvest);
  background: color-mix(in srgb, var(--color-harvest) 7%, var(--color-card));
  color: var(--color-harvest);
}

.ga-notice-success {
  border-left-color: var(--color-leaf);
  background: color-mix(in srgb, var(--color-leaf) 7%, var(--color-card));
  color: var(--color-leaf);
}

/* --- Consent checkbox --------------------------------------------------- */

/* LoginPage.tsx's consent row: `accent-leaf` box, caption-sized soil label,
   left-aligned. The whole row is a <label>, so the text is part of the target. */
.ga-consent {
  display: flex;
  align-items: flex-start;
  gap: var(--spacing-unit);
  margin-top: var(--spacing-card-gap);
  font-size: var(--text-caption);
  line-height: 1.5;
  color: var(--color-soil);
  cursor: pointer;
}

.ga-consent input {
  accent-color: var(--color-leaf);
  margin-top: 2px;
  flex-shrink: 0;
  width: 16px;
  height: 16px;
}

/* --- Links -------------------------------------------------------------- */

/* ArticleLink.tsx's text variant: `font-serif italic text-body text-leaf underline`. The
   underline is not decoration here — these sit inside body copy and inside a consent
   checkbox label, where colour alone is not a reliable affordance (and fails WCAG 1.4.1). */
.ga-link {
  font-family: var(--font-serif);
  font-style: italic;
  color: var(--color-leaf);
  text-decoration: underline;
}

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

/* The about/privacy links under the card's content. Separated by a hairline rather than
   whitespace alone so it reads as chrome rather than as one more thing being asked of the
   gardener — this is the last thing on the page and must not compete with the primary
   action above it (Serial Position). */
.ga-footer {
  margin: var(--spacing-section) 0 0;
  padding-top: var(--spacing-unit);
  border-top: 1px solid color-mix(in srgb, var(--color-soil) 15%, transparent);
  text-align: center;
  font-size: var(--text-caption);
  line-height: 1.5;
}

/* Both links plus the separator sit on one line at any width the card allows; the
   separator is muted so the two labels read as the pair they are. */
.ga-footer-sep {
  color: var(--color-muted);
  margin: 0 4px;
}

/* --- Redirect host disclosure ------------------------------------------- */

/* The one line on the authorize page that is a checkable fact rather than
   copy, so it's set in mono to read as data. See clientDisplayHost. */
.ga-host code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--text-caption);
  color: var(--color-bark);
  word-break: break-all;
}

/* Article and plant page rules. The palette, the body gradient, Georgia and
   box-sizing all come from internal/webstyle, which is prepended to this file
   at serve time (see ArticleHandler) — this used to redeclare all of them under
   a "manually kept in sync" comment that nothing enforced. */

.article-container {
  max-width: 640px;
  margin: 0 auto;
  padding: 0 20px 48px;
}

.article-hero {
  width: 100%;
  height: auto;
  display: block;
  border-radius: 4px;
  margin-bottom: 24px;
}

.article-title {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 22px;
  font-weight: normal;
  color: var(--color-bark);
  margin: 0 0 8px;
  line-height: 1.3;
}

.article-summary {
  font-size: 14px;
  color: var(--color-muted);
  margin: 0 0 24px;
  line-height: 1.5;
}

.article-body {
  color: var(--color-soil);
  font-size: 14px;
  line-height: 1.7;
}

.article-body h2 {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 17px;
  font-weight: normal;
  color: var(--color-bark);
  margin: 28px 0 10px;
}

.article-body p {
  margin: 0 0 14px;
}

.article-body img {
  width: 100%;
  height: auto;
  border-radius: 4px;
  margin: 16px 0;
}

.article-body a {
  color: var(--color-leaf);
  text-decoration: underline;
}

.article-body ul,
.article-body ol {
  padding-left: 20px;
  margin: 0 0 14px;
}

.article-body li {
  margin-bottom: 6px;
}

.article-sources {
  margin-top: 40px;
  padding-top: 20px;
  border-top: 1px solid color-mix(in srgb, var(--color-soil) 20%, transparent);
}

.article-sources-heading {
  font-size: 11px;
  font-weight: bold;
  color: var(--color-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin: 0 0 8px;
}

.article-sources-list {
  list-style: none;
  padding: 0;
  margin: 0;
}

.article-sources-list li {
  font-size: 11px;
  color: var(--color-muted);
  margin-bottom: 6px;
}

.article-sources-list a {
  color: var(--color-muted);
  text-decoration: underline;
}

/* The content licence, at the foot of every plant and article page. Muted and the same size
   as the sources it sits under: it is a term of use, not a claim — a reader who wants it will
   look for it, and everybody else should be able to read past it. It carries no top border of
   its own because .article-sources above it already draws one, and two rules a few lines apart
   read as a boundary rather than a footer. */
.article-license {
  margin: 16px 0 0;
  font-size: 11px;
  color: var(--color-muted);
}

.article-license a {
  color: var(--color-muted);
  text-decoration: underline;
}

.article-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin: 40px auto 0;
  padding: 12px 24px;
  min-height: 44px;
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 13px;
  color: var(--color-leaf);
  border: 1px solid var(--color-leaf);
  border-radius: 6px;
  background: linear-gradient(
    to bottom,
    color-mix(in srgb, var(--color-leaf) 10%, transparent) 0%,
    color-mix(in srgb, var(--color-leaf)  4%, transparent) 100%
  );
  text-decoration: none;
  cursor: pointer;
  transition: all 200ms;
}

.article-header {
  padding: 20px 20px 0;
  max-width: 640px;
  margin: 0 auto;
}

.article-cta:hover { filter: brightness(0.95); }
.article-cta:active { filter: brightness(0.90); }

.article-back {
  font-size: 13px;
  color: var(--color-muted);
  text-decoration: none;
}

.article-back:hover {
  color: var(--color-soil);
  text-decoration: underline;
}

