/* Forager Research Outpost — the hub.
   Plain CSS. No build step, no imports, no external fonts.

   Palette and the two contrast rules come from DESIGN_BRIEF.md:
   - On the cream, an accent may carry a mark, a border, or a plate — never body text.
     Card text is always ink, uniformly, so the five cards read as a set.
   - On the dark band, a light-mode accent never survives: SkillFlamingo's #b0305f
     measures 2.18 there and ExperimentOwl's #71468c 1.88, so neither is used on it.
     An app's wordmark rung is not used here either — SkillFlamingo's #c97191 is
     2.97 on the cream, under the non-text floor.                                  */

:root {
  --cream:  #f4f1e8;   /* card / canvas                                */
  --ink:    #26221e;   /* body text — 13.98 on cream                   */
  --muted:  #6b7063;   /* secondary text. The brief pins #6f7467, but that
                          is 4.25 on cream — under AA for body copy. This is
                          Lab dE 1.61 from it (below a just-noticeable
                          difference) and measures 4.51.                 */
  --forest: #4f6f52;   /* the wilderness surround                      */
  --deep:   #26322b;   /* the dark band                                */
  --forest-rule: #5c815f; /* #4f6f52 is only 2.37 on the dark band. Lifted to
                          3.03, the same move the brief makes for an app
                          accent that is too dark for the band.          */

  --edge:   #e2ddcd;   /* cream, one step down — hairlines on the sheet */
  --sheet-max: 74.4rem;   /* was 62rem — widened 20% */
}

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

html { -webkit-text-size-adjust: 100%; }

/* Small screens run one column, so every block stands at full height at once and
   the fold fills fast. Scaling the ROOT is the one lever that reaches the whole
   page: near enough everything here is sized in rem, so a single value moves
   type, margins and padding together and every proportion survives intact.

   Media-query `rem` resolves against the INITIAL root size rather than this one,
   so no breakpoint in this file shifts underneath the change.

   93.75% and not lower: it puts the smallest body copy on the page -- the hero
   attribution and the mission paragraphs, both 0.875rem -- at 13.1px. Another
   step down would take them under 13, which is where secondary text on a phone
   starts costing more in readability than it returns in fold space. */
@media (max-width: 34rem) {
  html { font-size: 93.75%; }
}

body {
  margin: 0;
  /* The wilderness surround. Both forest values from the brief, blended.
     Visible as the flanks beside the cream sheet on wide viewports. */
  background: var(--deep) linear-gradient(180deg,
      var(--deep) 0%, var(--forest) 55%, var(--deep) 100%) fixed;
  color: var(--ink);
  /* Column so the footer's dark band can fill a tall window. Without it the
     surround gradient shows as a bare green field below the footer. */
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  font: 400 clamp(1rem, 0.96rem + 0.2vw, 1.0625rem)/1.6
        -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

img { max-width: 100%; height: auto; }

/* ── hero ─────────────────────────────────────────────────────────────────── */

/* The painting, unobscured. No scrim, no band, nothing set over it — which is
   also why the old scrim contrast maths is gone: there is no longer any text on
   the art to clear. Roughly the top third of the viewport, capped so
   it does not swallow a short window or balloon on a tall one. */
.hero {
  position: relative;
  overflow: hidden;
  flex: 0 0 auto;
  height: clamp(13rem, 34vh, 27rem);
  background:
    url("assets/hero/outpost-hero.jpg") center 46% / cover no-repeat,
    var(--deep);
}

@media (max-width: 700px) {
  .hero { background-image: url("assets/hero/outpost-hero@900.jpg"); }
}

/* A faint 135-degree sheen crossing the painting every few seconds. Cream-tinted
   rather than white, so it reads as lamplight moving over the canopy instead of
   as glare. It travels right to left. The band is oversized and starts well off
   to one side; the keyframes spend most of the cycle parked there, so the sweep
   is an occasional event rather than continuous motion. Purely decorative — the global reduced-motion
   rule stops it, and parked off-screen it simply never appears. */
.hero::after {
  content: "";
  position: absolute;
  inset: -40%;
  pointer-events: none;
  background: linear-gradient(135deg,
      rgba(244, 241, 232, 0) 44%,
      rgba(244, 241, 232, 0.0035) 48%,
      rgba(244, 241, 232, 0.009) 50%,
      rgba(244, 241, 232, 0.0035) 52%,
      rgba(244, 241, 232, 0) 56%);
  transform: translateX(85%);
  animation: hero-sheen 10s linear infinite;
}

@keyframes hero-sheen {
  0%   { transform: translateX(85%); }
  45%  { transform: translateX(-85%); }
  100% { transform: translateX(-85%); }
}

/* ── the cream sheet: the lit interior you step into ──────────────────────── */

.sheet {
  max-width: var(--sheet-max);
  margin: 0 auto;
  /* top reduced 30%: 2.25/5vw/3.5 -> 1.575/3.5vw/2.45. Sides and bottom unchanged. */
  padding: clamp(1.575rem, 3.5vw, 2.45rem) clamp(1.25rem, 4vw, 3rem) clamp(2.5rem, 6vw, 4rem);
  background: var(--cream);
  /* Square, and no shadow: the sheet's top edge is meant to meet the painting
     as one straight line, and a soft shadow would blur exactly that join. */
  border-radius: 0;
  flex: 0 0 auto;
  width: 100%;
}

/* The wide short hero. The mark and the title share a row; the tagline and the
   blurb sit under BOTH of them at the container's full width, rather than being
   indented into the title's column. */
.sheet-hero {
  margin-bottom: clamp(2rem, 4vw, 3rem);
  padding-bottom: clamp(1.5rem, 3vw, 2rem);
  border-bottom: 1px solid var(--edge);
}

.sheet-hero__row {
  display: flex;
  /* baseline, not flex-end: an img's baseline IS its bottom edge, and this PNG
     has only 1px of transparent margin under the treehouse's grass. So the
     treehouse stands exactly on the title's baseline — the same ground line —
     where flex-end would drop it by the font's descender instead. */
  align-items: baseline;
  /* halved: 1/3vw/1.75 -> 0.5/1.5vw/0.875 */
  gap: clamp(0.5rem, 1.5vw, 0.875rem);
}

.sheet-hero__mark {
  --mark-size: clamp(3.25rem, 7vw, 4.5rem);
  flex: none;
  width: var(--mark-size);
  height: auto;
  /* Optical, not geometric. The image's bottom edge already lands exactly on
     the text baseline — measured, gap 0.00px — but the grass mound tapers to a
     point over its last 13 rows, so its last opaque pixel is not where the eye
     reads the ground. The mound is widest at 95% of the image height and is
     down to three-quarter width by 97%; nudging down 4% seats it on the line
     the letters sit on instead of leaving it hovering above them.

     A transform rather than a negative margin: flex synthesises a replaced
     element's baseline from its BORDER box, so margin-bottom moves nothing
     here. Verified — the margin version measured a 0.00px shift. */
  transform: translateY(calc(var(--mark-size) * 0.04));
}

.sheet-hero__title {
  margin: 0;
  color: var(--ink);
  font-family: Georgia, "Iowan Old Style", "Times New Roman", serif;
  font-weight: 400;
  font-size: clamp(1.5rem, 1.1rem + 1.9vw, 2.5rem);
  line-height: 1.15;
  letter-spacing: -0.01em;
  text-wrap: balance;
}

/* The app half of the wordmark. #4f6f52 measures 4.99 on the cream, so it
   clears normal-text contrast and does not depend on the title being large —
   which matters, because the title's floor is 1.5rem, exactly the large-text
   boundary. */
.sheet-hero__app {
  color: var(--forest);
}

/* The tagline, set under the whole mark-and-title row and starting at the
   header's own left edge -- so it reads as a tagline on the lockup as a unit,
   not as a caption hanging off the title. Small caps so it reads as a mark's
   tagline and not as a first sentence, and muted so it sits beneath the
   wordmark instead of competing with it.

   all-small-caps, not small-caps: the latter leaves the initial "F" at full cap
   height, which reads as a sentence that happens to be styled oddly. Letter-
   spaced because small caps set at normal tracking close up and turn into a
   grey bar at this size. */
.sheet-hero__lede {
  /* Tight to the title on purpose: the mark, the wordmark and this line are one
     lockup, and the spacing has to say so. The gap below (see the attribution's
     margin) is deliberately several times larger -- that ratio is what makes the
     three read as a badge with text under it rather than as three stacked
     lines. */
  margin: 0.15rem 0 0;
  color: var(--muted);
  font-size: 0.875rem;
  font-variant-caps: all-small-caps;
  font-weight: 600;
  letter-spacing: 0.075em;
  line-height: 1.35;
}

/* The attribution. Small and muted so it reads as a credit line under the
   statement, not as a second claim competing with it. */
.sheet-hero__blurb {
  margin: 1.375rem 0 0;
  color: var(--muted);
  font-size: 0.9375rem;
  line-height: 1.55;
}

@media (max-width: 34rem) {
  /* All four of these sit at their clamp FLOOR by 375px, so the clamps have
     nothing left to give and the values have to come down explicitly. */
  .sheet { padding-top: 1.225rem; }   /* 1.75rem x 0.7, in step with the base */
  .sheet-hero { margin-bottom: 1.5rem; padding-bottom: 1.25rem; }
  .mission { margin-bottom: 1.75rem; }
  .mission__points { gap: 1.125rem; }

  .sheet-hero__row { gap: 0.4375rem; }   /* halved, in step with the base */
  .sheet-hero__mark { --mark-size: 2.75rem; }
  /* Small caps in a ~275px column: tighter tracking and a step down in size buy
     back a whole line without the tagline losing its register. */
  .sheet-hero__lede { font-size: 0.8125rem; letter-spacing: 0.045em; }
}

/* Both uses of this are followed by an intro paragraph, so the heading sits
   tight to its own text and the paragraph carries the gap down to the content. */
.sheet__heading {
  margin: 0 0 0.85rem;
  color: var(--muted);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.sheet__intro {
  margin: 0 0 1.75rem;
  max-width: 46rem;
  color: var(--muted);
  font-size: 0.9375rem;
  line-height: 1.55;
}

/* ── mission ──────────────────────────────────────────────────────────────── */

.mission {
  margin-bottom: clamp(2rem, 4vw, 3rem);
}

/* Serif and ink, matching the title rather than the hero's muted paragraphs.
   It is the one sentence on the page making an argument, so it gets the
   page's only other piece of display type. */
.mission__lead {
  margin: 0 0 1.75rem;
  max-width: 46rem;
  color: var(--ink);
  font-family: Georgia, "Iowan Old Style", "Times New Roman", serif;
  font-size: clamp(1.0625rem, 0.95rem + 0.5vw, 1.25rem);
  line-height: 1.5;
  text-wrap: pretty;
}

/* Three across, stepping straight to one. They do not pass through two: three
   items in two columns strand the last one under a gap, which reads as an
   omission rather than as a set. */
.mission__points {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.25rem, 3vw, 2rem);
  margin: 0;
  padding: 0;
  list-style: none;
}

@media (max-width: 44rem) {
  .mission__points { grid-template-columns: 1fr; gap: 1.5rem; }
}

/* A short rule over each point, echoing the accent plate on the cards below but
   in the hub's own forest — this section is the hub speaking, not any one app.
   2px against the card's 3px: these are text, not objects. #4f6f52 measures
   4.99 on the cream, well clear of the 3:1 floor for a non-text element. */
.mission__point {
  padding-top: 0.875rem;
  border-top: 2px solid var(--forest);
}

.mission__point > :is(h1, h2, h3, h4) {
  margin: 0 0 0.4rem;
  color: var(--ink);
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1.3;
}

.mission__point p {
  margin: 0;
  color: var(--muted);
  font-size: 0.875rem;
  line-height: 1.55;
}

/* ── cards ────────────────────────────────────────────────────────────────── */

/* Count-agnostic on purpose. A fixed 2x2 does not extend to five, so this is a
   wrapping flex row with a centred last row: 4 lands as 3 + 1 and 5 as 3 + 2,
   and each reads as deliberate rather than as a hole in a grid. With the fifth
   card in, the short row holds exactly the two that are not live yet. */
.cards {
  --gap: 1.125rem;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--gap);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* The basis is computed from the ROW width, not the card's own content, so a
   short last row keeps the same card size as a full one instead of stretching
   to cover the gap. flex-grow stays 0 for the same reason. */
.card {
  position: relative;
  flex: 0 1 calc((100% - 2 * var(--gap)) / 3);
  display: flex;
  flex-direction: column;
  padding: 1.5rem 1.5rem 1.375rem;
  background: var(--cream);
  border: 1px solid var(--edge);
  border-top: 3px solid var(--accent);      /* the accent as a plate */
  border-radius: 10px;
  box-shadow: 0 1px 2px rgba(38, 34, 30, 0.06);
}

/* Columns step 3 -> 2 -> 1. The basis is the row width divided by the column
   count, so cards stay the same size whether their row is full or short. */
@media (max-width: 56rem) {
  .card { flex-basis: calc((100% - var(--gap)) / 2); }
}

@media (max-width: 34rem) {
  .card { flex-basis: 100%; }
}

/* Head row: the name upper-left, the mark upper-right, and the tagline below
   spanning the full card width. align-items: flex-start keeps the name's cap
   height and the mark's top edge on the same line rather than centring them. */
.card__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.75rem;
  /* Fixed height so the taglines line up across a row even though the mark
     boxes differ — see --mark-h below. */
  min-height: 3.25rem;
  margin-bottom: 0.5rem;
}

/* The mark: the app's own silhouette, in the app's accent.
   The brief's rule is that an accent may carry the mark, the border, or a plate,
   never body text — this is the mark, so the accent belongs here and the card
   text stays ink.

   The height is per-card (`--mark-h`, set inline) and the width is free. One
   shared height does not work, because each viewBox has to span that animal's
   whole animation, and animals differ in how much of their own box they fill
   at rest: the gopher's upright pose is 91% of its box, the jay's perch only
   62% of an arc that has to reach its climb-away. At one box height that put
   the gopher and mouse at ~40px against the fox and jay at ~28px. Each height
   here is derived so every animal RENDERS at 34px at rest.

   align-self: flex-end stands them all on one baseline, since each animal sits
   at the bottom of its own viewBox. */
.mark {
  flex: none;
  align-self: flex-end;
  height: var(--mark-h, 2.75rem);
  width: auto;
  fill: var(--accent);
}

/* All eight poses stay in the svg; exactly one is shown. The hover loop that
   used to cycle them was removed -- the cards display the still mark only.
   The other seven paths are kept deliberately: they are the traced sheet as it
   came out of the tracer, and re-enabling the loop later is per-card keyframes
   plus these same paths, not another trace. */
.mark__pose { opacity: 0; }
.mark__pose--rest { opacity: 1; }

.card__name {
  margin: 0;
  color: var(--ink);                        /* ink, never the accent */
  font-family: Georgia, "Iowan Old Style", "Times New Roman", serif;
  font-weight: 400;
  font-size: 1.4375rem;
  letter-spacing: -0.005em;
}

/* The card's headline, above its body copy. Deliberately NOT .sheet__heading —
   that is the uppercase section label ("THE APPS"), and it rendered these
   sentence-case lines as 12px caps. Deliberately not a heading element either:
   the card's own <h3> name is its heading, and a second one inside the card
   either inverts the outline (an <h2> under an <h3>) or adds an outline entry
   per card for no navigational gain.

   Ink against the body's muted grey, so the pair reads headline-then-detail at
   a glance. Same size as the body with weight doing the separating — a larger
   size here would start competing with the serif card name above it. */
.card__tagline {
  margin: 0 0 0.5rem;
  color: var(--ink);
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1.35;
}

.card__what {
  margin: 0 0 1.25rem;
  color: var(--muted);
  font-size: 0.9375rem;
  line-height: 1.5;
}

.card__link {
  margin: auto 0 0;
  padding-top: 0.9375rem;
  border-top: 1px solid var(--edge);
  color: var(--ink);                        /* ink, not the accent */
  font-size: 0.875rem;
  text-decoration: none;
  overflow-wrap: anywhere;
}

.card__link[href] { text-decoration: underline; text-decoration-color: var(--accent);
                    text-underline-offset: 3px; text-decoration-thickness: 2px; }

.card__link[href]:hover { text-decoration-thickness: 3px; }

.card__link:focus-visible,
.card:focus-within { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 4px; }

/* Revealed only when an app confirms a live session — never to say "signed
   out", which the hub cannot know when a request simply fails.

   Absolutely positioned on purpose. It arrives after paint, so anything in flow
   would reflow the card under whoever is already reading it; the foot row is
   too tight to hold it besides, since the subdomain link and this pill together
   overrun a 3-column card and would wrap the link. Straddling the top accent
   rule puts it where the card's own state already reads.

   Same pill language as the SOON tag: accent border, ink text — the accent
   carries a border here, never the words. */
.card__status {
  position: absolute;
  top: 0;
  right: 1.25rem;
  transform: translateY(-50%);
  padding: 0.125rem 0.5rem;
  background: var(--cream);
  border: 1px solid var(--accent);
  border-radius: 999px;
  color: var(--ink);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* FieldMouse — no deploy infrastructure yet. Present, but not a live link.
   The mark is NOT dimmed to signal that. Fading it to 0.7 measured 2.91 on the
   cream, under the brief's 3:1 non-text floor, and even 0.72 only reaches 3.02.
   The "SOON" tag says it in words instead, and the four marks stay one set. */
.card__link--none { display: flex; align-items: center; gap: 0.625rem; color: var(--muted); }

/* ExperimentOwl carries no mark yet, so its head row has one child. min-height
   on .card__head already holds the row open, which is what keeps its tagline on
   the same line as FieldMouse's beside it — nothing further is needed here. */

.tag {
  padding: 0.125rem 0.5rem;
  border: 1px solid var(--accent);          /* the accent as a border */
  border-radius: 999px;
  color: var(--ink);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* ── secondary pages: terms, privacy, contact ─────────────────────────────── */

/* No hero on these. They are not the front door, and 363 KB of painting to
   read a policy is a poor trade. The sheet grows instead of the footer here —
   the index wants the dark band filling a tall window, but on a short document
   that same rule leaves most of the screen as empty footer. */
.page-doc .sheet   { flex: 1 0 auto; }
.page-doc .footer  { flex: 0 0 auto; }

.sheet--doc { padding-top: clamp(1.75rem, 4vw, 2.75rem); }

.doc-home {
  display: inline-flex;
  align-items: baseline;
  gap: 0.55rem;
  margin-bottom: clamp(1.5rem, 4vw, 2.25rem);
  color: var(--ink);
  font-family: Georgia, "Iowan Old Style", "Times New Roman", serif;
  font-size: 1.0625rem;
  text-decoration: none;
}

/* Same 4% optical seat as the hero mark, for the same reason. */
.doc-home img { width: 1.75rem; height: auto; transform: translateY(calc(1.75rem * 0.04)); }
.doc-home__app { color: var(--forest); }
.doc-home:hover span { text-decoration: underline; text-underline-offset: 3px; }
.doc-home:focus-visible { outline: 2px solid var(--forest); outline-offset: 3px; border-radius: 3px; }

.doc { max-width: 60ch; }

.doc h1 {
  margin: 0 0 1.5rem;
  color: var(--ink);
  font-family: Georgia, "Iowan Old Style", "Times New Roman", serif;
  font-weight: 400;
  font-size: clamp(1.75rem, 1.3rem + 2vw, 2.5rem);
  line-height: 1.15;
  letter-spacing: -0.01em;
}

.doc h2 {
  margin: 2rem 0 0.5rem;
  color: var(--ink);
  font-family: Georgia, "Iowan Old Style", "Times New Roman", serif;
  font-weight: 400;
  font-size: 1.25rem;
}

.doc p { margin: 0 0 0.85rem; color: var(--muted); }
.doc a { color: var(--ink); text-decoration-color: var(--forest); text-underline-offset: 3px; }
.doc code {
  padding: 0.1em 0.35em;
  background: var(--edge);
  border-radius: 3px;
  font-size: 0.9em;
}

/* The unwritten-content notice. Deliberately conspicuous: this text must not be
   mistaken for a policy, so it gets the accent bar and ink rather than muted. */
.doc-note {
  margin: 0 0 1.75rem;
  padding: 0.9rem 1.1rem;
  border-left: 3px solid var(--forest);
  background: var(--edge);
  border-radius: 0 6px 6px 0;
  color: var(--ink) !important;
  font-size: 0.9375rem;
  line-height: 1.55;
}

.doc-todo {
  color: var(--ink) !important;
  font-style: italic;
}

/* ── footer ───────────────────────────────────────────────────────────────── */

.footer {
  max-width: var(--sheet-max);
  margin: 0 auto;
  padding: 2rem clamp(1.25rem, 4vw, 3rem) 3.5rem;
  background: var(--deep);
  border-top: 3px solid var(--forest-rule);
  text-align: center;
  flex: 1 0 auto;
  width: 100%;
  /* Centres the two lines when the band grows to fill a tall window.
     At the band's natural height this changes nothing. */
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.footer__line  { margin: 0; color: var(--cream); font-family: Georgia, serif; font-size: 1.0625rem; }
.footer__copy  { margin: 0.6rem 0 0; color: #9fa79a; font-size: 0.8125rem; }

/* Cream at 11.82 on the dark band, so the links are readable text rather than
   the dimmed grey the notes use. The rule under them is the affordance — the
   link text is the same cream as the wordmark line above it, so the underline
   is the only thing marking these as links, which puts it under 1.4.11's 3:1
   floor for non-text. At 0.35 it measured 2.81; 0.5 measures 4.20. It
   brightens rather than appearing on hover, so nothing shifts. */
.footer__links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.35rem 1.25rem;
  margin: 0.75rem 0 0;
}

.footer__links a {
  color: var(--cream);
  font-size: 0.875rem;
  text-decoration: none;
  border-bottom: 1px solid rgba(244, 241, 232, 0.5);
}

.footer__links a:hover { border-bottom-color: var(--cream); }

.footer__links a:focus-visible {
  outline: 2px solid var(--forest-rule);
  outline-offset: 3px;
  border-radius: 2px;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; }
}
