/* site.css - the shared chrome. Generated by
   tools/publish_redesign.py. Do not hand edit: the next publish
   overwrites it. */

.bar { background: var(--ink); color: var(--ink-invert); font-size: var(--step-small); text-align: center; padding: 10px 16px; }
.bar a { color: var(--accent); }

.nav { position: sticky; top: 0; z-index: 40; background: color-mix(in srgb, var(--bg) 88%, transparent); backdrop-filter: blur(12px); border-bottom: 1px solid var(--line-soft); }
.nav__in { display: flex; align-items: center; gap: var(--gap-l); height: 72px; }
/* nowrap because at 390px it broke to "NORED / FARMS" over two lines and pushed
   the header out of shape. Seen on the phone render, not in the markup. */
.nav__logo { font-weight: var(--w-medium); letter-spacing: var(--track-tight); font-size: 1.125rem; text-decoration: none; white-space: nowrap; }
.nav__links { display: flex; gap: var(--gap-m); margin-left: auto; }
.nav__links a { text-decoration: none; font-size: 0.9375rem; padding: 6px 0; border-bottom: 1px solid transparent; }
.nav__links a:hover, .nav__links a.on { border-bottom-color: var(--ink); }
.nav__act { display: flex; gap: var(--gap-s); align-items: center; margin-left: var(--gap-l); }
.nav__burger { display: none; margin-left: auto; background: none; border: 0; padding: 10px; cursor: pointer; }
.nav__burger span { display: block; width: 22px; height: 2px; background: var(--ink); margin: 4px 0; }
.nav__close, .nav__links-search, .nav__links-cta { display: none; }

/* THE DIMMED OVERLAY behind the side panel. Sits outside the media query
   because it is harmless at rest on desktop (opacity 0, visibility hidden,
   so it never paints or blocks a click) and JS only ever adds
   nav__overlay--active after the burger has been used, which only happens
   on a narrow screen. */
.nav__overlay { position: fixed; inset: 0; background: rgba(0,0,0,.45); opacity: 0; visibility: hidden; transition: opacity .3s ease, visibility .3s ease; z-index: 99; }
.nav__overlay--active { opacity: 1; visibility: visible; }

@media (max-width: 860px) {
  .nav__burger { display: block; }
  .nav__act { margin-left: auto; }
  .nav__act .chip { display: none; }
  /* THE HEADER RAN OFF THE RIGHT OF EVERY PHONE SCREEN, and the cause was the
     GAP and not the contents. Measured on the rendered page at 375px, which is
     the only place it is visible: the three showing items are 125 + 102 + 42 =
     269px and the content box is 327px, so they fit with room to spare. Two
     gaps of var(--gap-l), 48px each, add 96px, and 269 + 96 = 365 against 327.
     The burger ended at x=389 on a 375px screen and the whole page could be
     dragged sideways, on every page that has a nav.
     A desktop gap was simply never reduced for a phone. */
  .nav__in { gap: var(--gap-s); }

  /* THE SIDE-PANEL SLIDE MENU, per seed-design-reference.md's "Side Menu /
     Navigation": a full-height panel off-canvas at rest, sliding to
     translateX(0) when nav__links--open is toggled, over the dimmed overlay
     above. This replaces the old strip that dropped down under the bar.
     Always rendered (never display:none) so the transform can animate; at
     rest it sits fully outside the viewport, which is what keeps it out of
     the way and out of the tab order in practice. */
  .nav__links {
    display: flex; flex-direction: column; align-items: stretch; gap: 0;
    position: fixed; top: 0; left: 0; width: 86%; max-width: 360px; height: 100vh;
    box-sizing: border-box; overflow-y: auto; background: var(--bg);
    padding: 84px var(--gap-l) var(--gap-l); z-index: 100;
    transform: translateX(-100%);
    transition: transform .32s cubic-bezier(.4,0,.2,1);
  }
  .nav__links--open { transform: translateX(0); }
  .nav__links a { padding: 14px 0; border-bottom: 1px solid var(--line-soft); font-size: 1.0625rem; }
  .nav__close { display: block; position: absolute; top: 14px; right: 16px; width: 40px; height: 40px; background: none; border: 0; font-size: 30px; line-height: 1; color: var(--ink); cursor: pointer; }
  .nav__links-search, .nav__links-cta { display: flex; margin-top: var(--gap-m); border-bottom: 0; }
  .nav__links-cta { justify-content: center; width: 100%; }
}
@media (prefers-reduced-motion: reduce) {
  .nav__links, .nav__overlay { transition: none; }
}

/* SCROLL REVEAL. REVEAL_JS below adds/removes these two classes; the CSS only
   ever needs to know the two states. Skipped entirely for
   prefers-reduced-motion because REVEAL_JS itself declines to run and never
   adds .reveal in the first place, but this still needs its own guard in case
   a page ever gets the class some other way. */
@media (prefers-reduced-motion: no-preference) {
  .reveal { opacity: 0; transform: translateY(22px); transition: opacity .55s cubic-bezier(.4,0,.2,1), transform .55s cubic-bezier(.4,0,.2,1); }
  .reveal--in { opacity: 1; transform: translateY(0); }
}

/* HERO: the photograph as taken. Nothing is laid over it, per
   .claude/rules/nothing-covers-a-picture.md. The heading sits in a band
   underneath, which is the rule's own instruction: move the text, never dim
   the picture. */
.hero { position: relative; min-height: 62vh; border-radius: 0 0 var(--radius-pill) var(--radius-pill); overflow: hidden; }
.hero img { display: block; width: 100%; height: 62vh; object-fit: cover; object-position: 72% center; }
.hero__band { background: var(--ink); color: var(--ink-invert); }
.hero__band .shell { padding-block: var(--gap-l); }
/* .hero__band, NOT .hero. The text lives in its own band under the photograph
   now, so every ".hero h1" and ".hero .lede" rule silently matched nothing and
   the lede fell back to the muted body colour: grey-green type on dark green,
   which rendered as disabled text rather than as a sentence. Caught by looking
   at the page, not by any checker. */
.hero__band h1 { max-width: 22ch; }
.hero__band .lede { max-width: 56ch; color: rgba(255,255,255,.92); margin-top: var(--gap-m); font-size: 1.0625rem; }
.hero__cta { display: flex; gap: var(--gap-s); margin-top: var(--gap-l); flex-wrap: wrap; }

.band-lemongrass { background: var(--lime-100); }
.band-yellow     { background: var(--white-100); }
.band-foam       { background: var(--bg-alt); }
.band-lemongrass, .band-yellow, .band-foam { border-radius: var(--radius-pill); }

.trust { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--gap-m); padding: var(--gap-l); }
.trust__n { font-size: clamp(2rem,3vw,2.75rem); font-weight: var(--w-light); letter-spacing: var(--track-tighter); line-height: 1; }
.trust__l { font-size: var(--step-small); color: var(--ink-muted); margin-top: 10px; }
/* The cells are LINKS now, so these read "> * + *" rather than "> div + div".
   Each number was a claim with no way to check it: "Tested" said independent
   third party lab testing and went nowhere. Every cell now goes to the page
   that backs it up, which is what demonstrating experience means rather than
   asserting it (the-site-is-the-ranch-not-chris.md). */
.trust > * + * { border-left: 1px solid var(--line); padding-left: var(--gap-m); }
.trust > a { display: block; text-decoration: none; color: inherit; border-radius: var(--radius-s); transition: opacity .15s; }
.trust > a:hover .trust__n { text-decoration: underline; text-underline-offset: 4px; }
.trust > a:hover { opacity: .82; }
@media (max-width: 780px) { .trust { grid-template-columns: repeat(2,1fr); } .trust > * + * { border-left: 0; padding-left: 0; } }

.head { display: flex; align-items: end; justify-content: space-between; gap: var(--gap-m); margin-bottom: var(--gap-l); }

.prod__name { margin-top: var(--gap-s); font-size: 1.0625rem; font-weight: var(--w-medium); }
.prod__desc { color: var(--ink-muted); font-size: 0.9375rem; margin-top: 6px; }
.prod__foot { display: flex; align-items: center; justify-content: space-between; margin-top: auto; padding-top: var(--gap-s); gap: var(--gap-s); }
.prod__price { font-variant-numeric: tabular-nums; }
.prod__badge { position: absolute; top: 12px; left: 12px; }
.prod { position: relative; display: flex; flex-direction: column; height: 100%; }
.grid { align-items: stretch; }

.filters { display: flex; gap: var(--gap-xs); flex-wrap: wrap; margin-bottom: var(--gap-l); }
.filters a.chip { text-decoration: none; }
.search { display: flex; align-items: center; gap: 10px; border: 1px solid var(--line); border-radius: var(--radius-pill); padding: 12px 20px; width: min(420px, 100%); background: var(--bg); }
.search input { border: 0; outline: 0; background: transparent; font: inherit; width: 100%; color: var(--ink); }
.art__cat { font-size: var(--step-small); color: var(--ink-muted); }
.art__title { font-size: 1.0625rem; font-weight: var(--w-normal); margin-top: 6px; letter-spacing: var(--track-tight); }
.art__meta { font-size: var(--step-small); color: var(--ink-muted); margin-top: var(--gap-xs); }
/* A product card is a flex COLUMN so margin-top:auto can push the price and the
   button to the same line across a row whose descriptions wrap to different
   heights. Making the whole card a link and then setting display:block on it
   destroyed that column, and the three footers went ragged again. So the block
   rule takes everything EXCEPT a product card. */
a.card { text-decoration: none; color: inherit; }
a.card:not(.prod) { display: block; }

/* FOUR rungs, because the site sells four tiers. The mockup had three. */
.ladder { display: grid; grid-template-columns: repeat(4,1fr); gap: var(--gap-m); }
@media (max-width: 1100px) { .ladder { grid-template-columns: repeat(2,1fr); } }
@media (max-width: 640px)  { .ladder { grid-template-columns: 1fr; } }
.rung { border: 1px solid var(--line); border-radius: var(--radius); padding: var(--gap-m); display: flex; flex-direction: column; gap: var(--gap-s); }
.rung--now { border-color: var(--ink); }
.rung__dots { display: flex; gap: 4px; }
.dot { width: 7px; height: 7px; border-radius: 50%; background: var(--line); }
.dot--on { background: var(--ink); }
.rung ul { margin: 0; padding-left: 1.1em; color: var(--ink-muted); font-size: 0.9375rem; }
.rung li { margin-bottom: 5px; }
.rung__price { margin-top: auto; font-size: 1.25rem; font-weight: var(--w-light); letter-spacing: var(--track-tight); }

.mail { display: grid; grid-template-columns: 1.1fr 1fr; gap: var(--gap-l); align-items: center; }
@media (max-width: 860px) { .mail { grid-template-columns: 1fr; } }
.mail__form { display: flex; gap: var(--gap-s); margin-top: var(--gap-m); flex-wrap: wrap; }
.mail__form input { flex: 1 1 200px; border: 1px solid var(--line); border-radius: var(--radius-pill); padding: 14px 22px; font: inherit; outline: 0; background: var(--bg); color: var(--ink); }

.foot { background: var(--ink); color: var(--ink-invert); border-radius: var(--radius-pill) var(--radius-pill) 0 0; }
/* minmax(0, ...) on every track, NOT plain 1fr. A grid track defaults to
   min-width:auto, so it cannot shrink below its content's minimum: adding the
   signup input to the first cell forced that column to 240px and pushed the
   whole footer past a 375px phone, which made the page scroll sideways. Caught
   by measuring the rendered page at 375px, not by reading the CSS. */
.foot__grid { display: grid; grid-template-columns: 1.4fr repeat(3, minmax(0, 1fr)); gap: var(--gap-l); padding-block: var(--gap-xl) var(--gap-l); }
@media (max-width: 860px) {
  .foot__grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  /* The brand cell carries the signup, so it gets the full width on a phone
     rather than asking for an email address in a 240px column. */
  .foot__grid > :first-child { grid-column: 1 / -1; }
}
.foot h4 { font-size: var(--step-small); text-transform: uppercase; letter-spacing: 0.08em; color: var(--green-300); margin: 0 0 var(--gap-s); font-weight: var(--w-medium); }
.foot a { display: block; text-decoration: none; color: rgba(255,255,255,.85); font-size: 0.9375rem; padding: 5px 0; }
.foot a:hover { color: var(--accent); }
.foot__base { border-top: 1px solid rgba(255,255,255,.14); padding-block: var(--gap-m); display: flex; justify-content: space-between; gap: var(--gap-s); font-size: var(--step-small); color: var(--green-300); flex-wrap: wrap; }

/* The footer signup. Every page that renders a footer asks for the email;
   the homepage passes signup=None because it has its own section already. */
.foot__signup { margin-top: var(--gap-m); }
.foot__signup p { color: var(--green-300); font-size: 0.9375rem; margin: 0 0 var(--gap-s); max-width: 34ch; }
.foot__signup-row { display: flex; gap: var(--gap-s); flex-wrap: wrap; }
.foot__signup-row input { flex: 1 1 190px; min-width: 0; border: 1px solid rgba(255,255,255,.22); border-radius: var(--radius-pill); padding: 12px 20px; font: inherit; font-size: 0.9375rem; outline: 0; background: rgba(255,255,255,.06); color: var(--ink-invert); }
.foot__signup-row input::placeholder { color: rgba(255,255,255,.5); }
.foot__signup-row input:focus { border-color: var(--accent); }
/* .foot a is display:block, so the button needs its own box or it fills the row. */
.foot__signup-row button { flex: 0 0 auto; cursor: pointer; }
/* .btn--primary paints itself var(--ink), which is the FOOTER'S OWN BACKGROUND,
   so on a dark footer the button rendered dark green on dark green and read as
   plain indented text rather than a button. Caught by screenshotting the live
   page and looking at it, not by any check: every computed value was "correct"
   in isolation. The accent is the one colour on the site that carries on dark. */
.foot__signup-row .btn--primary { background: var(--accent); color: var(--ink); }
.foot__signup-row .btn--primary:hover { background: var(--ink-invert); }

/* A photograph given room. No caption on it, no scrim, no gradient. */
.band-photo { display: block; }
.band-photo img { display: block; width: 100%; height: clamp(280px, 46vh, 520px); object-fit: cover; }
