/* ==========================================================================
   Tendy 田地故事 — landing page, second trial run (2026-10)
   A layer over the Tendy design tokens (_ds/.../tokens). Mobile-first: the
   base rules are the phone layout, and min-width queries add the rest.

   THE IDEA — 田 as a system. The character 田 is a field drawn as a grid, and
   the page's one photograph is itself a grid of five frames with cream
   gutters. So the page's visual language is plots of land seen from above:
   tiles separated by --plot-gap, furrow textures, colour patches. It appears
   in the hero facts (four plots), the box's compartments, the brand story's
   four problems and the landscape strip that closes the page.

   A VISUAL BUDGET BY JOB, not by count. Each picture answers its own question:
     hero plots — what you get          box figure — what's inside (and the
     delivery map — where                 slot for the client's open-box photo)
     bridge — how it works              the photograph — proof of the work
     24-hour stamp — the damage window  role glyphs — who the boxes go between
     four plots — what we found         name lockup — who we are
     landscape strip — the close
   The four plots, the name lockup and the photograph now share one section,
   OUR STORY (品牌故事 and 產地故事 merged, 2026-10-23).
   The stamp, the role glyphs and the four plots came back from main at the
   client's request (2026-10-23); the stamp is the one that repeats a number
   printed beside it. A new picture replaces one of these or answers a question
   none of them does. None carries invented data. No more than two sections in
   a row go without a picture.

   DARK GREEN marks the places to act: order info, the final call to action and
   the footer. No other section is dark. The one exception is the ticker's thin
   band under the hero, a client's pick (2026-10-23).

   CARRIED OVER from the first-trial editorial.css (removed; see git history): the 2px-radius /
   no-pill / hairline vocabulary, the masthead, mobile menu, ticker, button,
   disclosure, legal, sticky-CTA and footer components, and the contrast
   measurements noted beside them.

   MOTION — five primitives, deliberately capped:
     1. ticker marquee (pausable: hover + explicit button, WCAG 2.2.2)
     2. press / hover micro-interactions (press on every control; hover gated to fine pointers)
     3. disclosure open + close via ::details-content
     4. mobile sticky CTA slide
     5. one-shot scroll reveal on [data-reveal] diagrams — FAILS OPEN (site.js)
   Add a primitive only by removing one. One reduced-motion block, at the end.
   Not counted: the masthead divider fading in over the first 60px of scroll, a
   colour change with nothing moving (gated to no-preference beside .masthead).
   ========================================================================== */

/* ------------------------------------------------------------- Additions */
:root {
  /* Produce accents. Fills and large marks only, never the brand's text colour.
     forest on squash 5.69:1, tomato on ivory 4.81:1. */
  --squash: #E3A93F;
  --squash-tint: #F2DEB0;
  --tomato: #B5472F;
  --leaf-tint: #DCE5CC;
  /* Sampled from the collage's own border (244,241,234), so the photo's gutters
     disappear into the section and its frames sit on the page grid. */
  --collage: #F4F1EA;

  --wrap: 1240px;
  --wrap-wide: 1400px;
  --wrap-read: 820px;
  /* Never narrower than the safe area: viewport-fit=cover lets the page run under
     a landscape phone's notch and rounded corners (5vw is ~42px there, the inset ~47-62px). */
  --gutter: max(clamp(18px, 5vw, 64px), env(safe-area-inset-left, 0px), env(safe-area-inset-right, 0px));
  --plot-gap: clamp(6px, 1vw, 12px);
  --rule-ink: rgba(31, 61, 43, .22);
  --masthead-h: 64px;

  interpolate-size: allow-keywords; /* lets <details> animate 0 -> auto */
}
@media (min-width: 960px) { :root { --masthead-h: 76px; } }

/* ------------------------------------------------------------------ Reset */
*, *::before, *::after { box-sizing: border-box; }
html {
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent; /* the grey tap flash; controls carry their own press state (Touch, below) */
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--masthead-h) + 12px);
  overflow-x: clip; /* clip, not hidden: hidden makes a scroll container and breaks sticky */
}
body {
  margin: 0;
  background: var(--ivory);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: 1.75;
  font-feature-settings: "kern" 1, "liga" 1;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: clip;
}
img, svg { display: block; max-width: 100%; }
img { height: auto; }
a { color: inherit; }
h1, h2, h3, p, figure, blockquote, ul, ol, dl, dd { margin: 0; }
ul, ol { padding: 0; list-style: none; }
::selection { background: var(--leaf-bright); color: var(--pine); }

:focus-visible { outline: 3px solid var(--forest); outline-offset: 3px; border-radius: 1px; }
.section--forest :focus-visible, .final :focus-visible,
.footer :focus-visible, .ticker :focus-visible { outline-color: var(--ivory); }

.skip-link {
  position: absolute; left: 16px; top: -60px; z-index: 100;
  background: var(--forest); color: var(--ivory);
  font-size: var(--fs-sm); font-weight: var(--fw-semibold);
  padding: 12px 18px; text-decoration: none;
}
.skip-link:focus { top: 12px; }

/* Read by screen readers, not shown: a sentence that a drawing on the page
   already says to sighted readers (the brand story's name lockup). */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ------------------------------------------------------------------ Touch
   With the tap flash off, every control answers the press itself: boxed buttons
   scale (.btn:active, below) and everything else dims. iOS only applies :active
   when a touch listener exists, which site.js adds (passive, so it costs no scroll). */
a, button, summary { touch-action: manipulation; } /* no wait for a double-tap zoom before the click */
:where(a, button, summary):not(.btn, .link-arrow) { transition: opacity var(--dur) var(--ease-out); }
:where(a, button, summary):not(.btn, .link-arrow):active { opacity: .6; }
/* Controls, not content: a long press shouldn't select their label or pop the link
   callout. Content links (email, phone, the FAQ answers) stay selectable. */
.btn, button, summary, .masthead__mark, .masthead__nav a, .mnav__panel a {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

/* -------------------------------------------------------------- Structure */
.wrap { width: 100%; max-width: var(--wrap); margin-inline: auto; padding-inline: var(--gutter); }
.wrap--wide { max-width: var(--wrap-wide); }
.wrap--read { max-width: var(--wrap-read); }
section { position: relative; }

.section { padding-block: clamp(72px, 10vw, 136px); }
.section--loud { padding-block: clamp(84px, 12vw, 164px); }
.section--tight { padding-block: clamp(60px, 8vw, 104px); }
.section--paper { background: var(--paper); }
.section--beige { background: var(--beige); }
.section--forest { background: var(--forest); color: var(--on-forest); }

.section-head { max-width: 760px; margin-bottom: clamp(36px, 5vw, 64px); }
.section-head--snug { margin-bottom: 28px; }
.section-head .kicker { margin-bottom: 18px; }
.section-head > p:not(.kicker) { margin-top: 18px; font-size: var(--fs-lg); line-height: 1.8; color: var(--ink); }

/* -------------------------------------------------------------- Type kit */
/* Section labels sit only on the six sections the menu links to, and say the
   menu's own words, so a jump lands on a label that matches the link. 14px with
   light tracking: wide-tracked 12px Chinese was hard to read. */
.kicker {
  display: inline-flex;
  align-items: center;
  gap: .7em;
  font-family: var(--font-body);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  letter-spacing: .04em;
  color: var(--olive-text);
}
.kicker::before { content: ""; width: 26px; height: 1px; background: currentColor; opacity: .8; }
.kicker--light { color: var(--on-forest-soft); }

/* Headline wording: a section people scan for facts gets a noun-phrase label
   with no end punctuation (價格、配送與付款, 從批發市場到農民市集); every other
   headline is a sentence ending in 。 or ？, and questions stay rare (the FAQ's
   還在考慮？ is the only one). Headlines approved by the client 2026-10-23.

   CJK display: keep-all holds phrases together, so lines break only at
   punctuation and at the <wbr>s placed at phrase boundaries in the markup.
   overflow-wrap: anywhere is the emergency exit so nothing can overflow. */
.h2, .hero h1, .final h2 {
  word-break: keep-all;
  overflow-wrap: anywhere;
  text-wrap: balance;
}
.h2 {
  font-family: var(--font-display);
  font-weight: var(--fw-semibold);
  font-variation-settings: var(--fv-head);
  font-size: clamp(28px, 2.6vw + 1rem, 50px);
  line-height: 1.3;
  letter-spacing: .01em;
  color: var(--forest);
}
.section--forest .h2 { color: var(--ivory); }

/* --------------------------------------------------------------- Buttons */
.btn {
  font-family: var(--font-body);
  font-size: var(--fs-ui);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--track-label);
  line-height: 1.3;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .6em;
  min-height: 48px;
  padding: 13px 24px;
  border: 1.5px solid var(--forest);
  border-radius: 2px;
  text-decoration: none;
  cursor: pointer;
  /* Colours ease; the press scale is a response, so it decelerates: --ease-out
     covers 79% of it in the first 40ms, --ease only 18%. */
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
              border-color var(--dur) var(--ease), transform var(--dur) var(--ease-out);
}
.btn svg { width: 1em; height: 1em; flex: none; }
.btn .ico-arrow { transition: transform var(--dur) var(--ease); }
.btn--lg { font-size: var(--fs-body); min-height: 54px; padding: 15px 28px; }
/* Filled buttons are for LINE only: every other link is a .link-arrow. */
.btn--primary { background: var(--forest); color: var(--ivory); }
.btn--on-dark { background: var(--ivory); color: var(--pine); border-color: var(--ivory); }
/* Thumb-width CTAs on phones. */
@media (max-width: 479px) {
  .hero .btn, .info__head .btn, .final .btn, .partner__cta .btn, .origin .btn { width: 100%; }
}
@media (hover: hover) and (pointer: fine) {
  .btn--primary:hover { background: var(--pine); border-color: var(--pine); }
  .btn--on-dark:hover { background: var(--leaf-bright); border-color: var(--leaf-bright); }
  .btn:hover .ico-arrow { transform: translateX(3px); }
  .link-arrow:hover svg { transform: translateX(3px); }
}
.btn:active, .link-arrow:active { transform: scale(.98); }
.btn-row { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 14px; }

.link-arrow {
  position: relative;
  font-weight: var(--fw-semibold);
  font-size: var(--fs-ui);
  letter-spacing: var(--track-label);
  color: var(--forest);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: .5em;
  padding-bottom: 3px;
  border-bottom: 1.5px solid currentColor;
  transition: transform var(--dur) var(--ease-out);
}
/* The system's one hover move, arrow +3px, as on .btn: a transform, not a gap change that relays out the line. */
.link-arrow svg { width: 1em; height: 1em; transition: transform var(--dur) var(--ease); }
.link-arrow--light { color: var(--ivory); border-color: rgba(246, 242, 232, .5); }
/* The underline hugs the text, so the 44px touch target is an invisible layer. */
.link-arrow::after { content: ""; position: absolute; inset: -8px -4px; }

.tag {
  display: inline-block;
  margin: 0 8px 6px 0;
  padding: 4px 10px;
  border: 1.5px solid var(--forest);
  border-radius: 2px;
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  letter-spacing: .04em;
  line-height: 1.4;
  color: var(--forest);
}

/* ==========================================================================
   MASTHEAD
   ========================================================================== */
.masthead {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(246, 242, 232, .9);
  backdrop-filter: saturate(130%) blur(8px);
  -webkit-backdrop-filter: saturate(130%) blur(8px);
  border-bottom: 1px solid var(--line);
}
/* The divider separates nothing at scroll 0; fade it in over the first 60px.
   No scroll-timeline support: the border simply stays on. */
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .masthead { animation: masthead-edge linear both; animation-timeline: scroll(); animation-range: 0 60px; }
    @keyframes masthead-edge { from { border-bottom-color: transparent; } to { border-bottom-color: var(--line); } }
  }
}
.masthead__in { display: flex; align-items: center; gap: 10px; height: var(--masthead-h); }
.masthead__mark { display: inline-flex; flex-shrink: 0; margin-right: auto; }
.masthead__mark img { height: 30px; width: auto; }
.masthead__nav { display: none; }
/* Below 960px the floating bar at the bottom is the LINE button. Showing this
   one too put two identical buttons on screen, 135px of an 844px phone. */
.masthead__cta.btn { display: none; min-height: 44px; padding: 10px 18px; font-size: var(--fs-sm); }
@media (min-width: 960px) {
  .masthead__cta.btn { display: inline-flex; }
  .masthead__in { gap: 28px; }
  .masthead__mark { margin-right: 0; }
  .masthead__mark img { height: 34px; }
  .masthead__nav { display: flex; gap: clamp(18px, 2.2vw, 30px); margin-inline: auto; }
  .masthead__nav a {
    font-size: var(--fs-sm);
    font-weight: var(--fw-medium);
    letter-spacing: .04em;
    color: var(--ink);
    text-decoration: none;
    padding: 4px 0;
    border-bottom: 1.5px solid transparent;
    transition: border-color var(--dur) var(--ease), color var(--dur) var(--ease), opacity var(--dur) var(--ease);
  }
  .masthead__nav a[aria-current="location"] { color: var(--forest); border-color: var(--forest); }
}
/* A touch iPad shows this nav too, and a tapped link would keep the underline. */
@media (hover: hover) and (pointer: fine) {
  .masthead__nav a:hover { color: var(--forest); border-color: var(--forest); }
}

/* Mobile menu — JS-free <details>, below 960px only. */
.mnav { position: relative; flex-shrink: 0; }
@media (min-width: 960px) { .mnav { display: none; } }
.mnav summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 44px;
  padding: 0 12px;
  border: 1.5px solid var(--forest);
  border-radius: 2px;
  /* A visible label: a bare three-line icon is easy to miss on a long page. */
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--track-label);
  color: var(--forest);
}
.mnav summary::-webkit-details-marker { display: none; }
.mnav__icon, .mnav__icon::before, .mnav__icon::after {
  display: block; width: 18px; height: 2px; background: var(--forest); position: relative;
  transition: transform var(--dur) var(--ease);
}
.mnav__icon::before, .mnav__icon::after { content: ""; position: absolute; left: 0; }
.mnav__icon::before { top: -6px; }
.mnav__icon::after { top: 6px; }
.mnav[open] .mnav__icon { background: transparent; }
.mnav[open] .mnav__icon::before { transform: translateY(6px) rotate(45deg); }
.mnav[open] .mnav__icon::after { transform: translateY(-6px) rotate(-45deg); }
.mnav__panel {
  position: absolute;
  top: calc(100% + 12px);
  right: 0;
  min-width: 220px;
  background: var(--ivory);
  border: 1px solid var(--line-strong);
  /* One of two shadows on the page: this panel floats over content it covers. */
  box-shadow: 0 18px 40px rgba(19, 43, 35, .14);
  padding: 8px 0;
  display: flex;
  flex-direction: column;
  /* Six rows are ~350px; a landscape phone shows ~330px under a masthead that
     doesn't scroll away. The panel scrolls inside itself, without chaining to the page. */
  max-height: calc(100vh - var(--masthead-h) - 24px);
  max-height: calc(100dvh - var(--masthead-h) - 24px);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.mnav__panel a {
  font-size: var(--fs-ui);
  font-weight: var(--fw-medium);
  color: var(--ink);
  text-decoration: none;
  padding: 13px 22px;
  border-bottom: 1px solid var(--line);
}
.mnav__panel a:last-child { border-bottom: 0; }
@media (hover: hover) and (pointer: fine) {
  .mnav__panel a:hover { color: var(--forest); background: var(--paper); }
}

/* ==========================================================================
   HERO — the promise, and the box as four plots of land
   ========================================================================== */
.hero { padding-block: clamp(36px, 7vw, 104px) clamp(48px, 7vw, 112px); }
.hero__grid { display: grid; gap: 44px; }
.hero__tag {
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  letter-spacing: .04em;
  color: var(--olive-text);
  margin-bottom: 20px;
}
.hero h1 {
  font-family: var(--font-display);
  font-weight: var(--fw-semibold);
  font-variation-settings: var(--fv-display);
  /* Capped so the 9-character second line fits the copy column at every
     width (column is ~574px at the 1240 wrap: 9 × 62px × 1.01 = 563). */
  font-size: clamp(34px, 3.4vw + .75rem, 62px);
  line-height: 1.24;
  letter-spacing: .01em;
  color: var(--forest);
  margin-bottom: 24px;
}
.hero__sub { font-size: var(--fs-lg); line-height: 1.85; color: var(--ink); max-width: 30em; margin-bottom: 30px; }
.hero__micro { margin-top: 16px; font-size: var(--fs-sm); line-height: 1.65; color: var(--ink-soft); max-width: 30em; }
/* keep-all + the <wbr>s in the markup, as on the headings: the micro line used to
   break inside 要不要 on a phone, and the sub left 植 alone on its last line. */
.hero__sub, .hero__micro { word-break: keep-all; overflow-wrap: anywhere; }

/* 田 — four plots, one fact each, a seal where the paths cross. */
.plate {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--plot-gap);
  aspect-ratio: 1;
  width: 100%;
  max-width: 540px;
  justify-self: center;
  /* The figures scale with the plate, not the viewport: the plate is 340px on a
     phone and 400–540px on desktop, and "NT$649" (~2.65em) must fit one plot. */
  container-type: inline-size;
}
.plot {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: clamp(14px, 2.4vw, 26px);
  padding: clamp(12px, 5.5cqi, 28px);
  overflow: hidden;
  color: var(--forest);
}
/* The furrows, fading out before they reach the type. */
.plot::before {
  content: "";
  position: absolute;
  inset: 0;
  -webkit-mask-image: linear-gradient(to bottom, #000 20%, transparent 72%);
          mask-image: linear-gradient(to bottom, #000 20%, transparent 72%);
}
.plot b, .plot span { position: relative; }
.plot b {
  font-family: var(--font-display);
  font-weight: var(--fw-semibold);
  font-variation-settings: var(--fv-display);
  font-size: 40px;
  font-size: clamp(30px, 13.5cqi, 76px);
  line-height: .95;
  letter-spacing: -.01em;
  font-variant-numeric: lining-nums;
  white-space: nowrap;
}
.plot b small { font-size: .36em; letter-spacing: .02em; margin-inline: .12em; vertical-align: .55em; }
.plot--d b { font-size: 32px; font-size: clamp(26px, 11cqi, 60px); }
.plot span { margin-top: 10px; font-size: var(--fs-sm); font-size: clamp(12px, 3.1cqi, 15px); font-weight: var(--fw-semibold); letter-spacing: .06em; }
/* Each plot's text sits in its OUTER corner, so the seal at the crossing never
   covers it; the furrows fade away from wherever the text is. */
.plot--a, .plot--b { justify-content: flex-start; }
.plot--a::before, .plot--b::before {
  -webkit-mask-image: linear-gradient(to top, #000 20%, transparent 72%);
          mask-image: linear-gradient(to top, #000 20%, transparent 72%);
}
.plot--b, .plot--d { align-items: flex-end; text-align: right; }
.plot--a { background: var(--forest); color: var(--ivory); }
.plot--a::before { background: repeating-linear-gradient(135deg, rgba(246, 242, 232, .12) 0 2px, transparent 2px 13px); }
.plot--b { background: var(--squash); }
.plot--b::before { background: repeating-linear-gradient(0deg, rgba(31, 61, 43, .13) 0 2px, transparent 2px 15px); }
.plot--c { background: var(--leaf-bright); }
.plot--c::before { background: radial-gradient(circle, rgba(31, 61, 43, .22) 2px, transparent 2.6px) 0 0 / 17px 17px; }
.plot--d { background: var(--beige); }
.plot--d::before { background: repeating-linear-gradient(90deg, rgba(166, 125, 74, .3) 0 2px, transparent 2px 14px); }
.plate__seal {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%) rotate(-8deg);
  width: 84px;
  width: clamp(70px, 20cqi, 108px);
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--ivory);
  box-shadow: 0 0 0 var(--plot-gap) var(--ivory);
  border: 1.5px solid var(--forest);
  display: grid;
  place-items: center;
}
.plate__seal::before { content: ""; position: absolute; inset: 5px; border-radius: 50%; border: 1px dashed var(--soil); }
.plate__seal span {
  font-family: var(--font-display);
  font-weight: var(--fw-semibold);
  font-size: clamp(13px, 3.2cqi, 17px);
  line-height: 1.25;
  letter-spacing: .14em;
  text-align: center;
  color: var(--forest);
}
@media (min-width: 900px) {
  .hero__grid { grid-template-columns: minmax(0, 1.12fr) minmax(0, .88fr); align-items: center; gap: clamp(40px, 6vw, 96px); }
  .plate { justify-self: end; }
}

/* ----------------------------------------------------------------- Ticker */
.ticker { position: relative; background: var(--forest); color: var(--on-forest); overflow: hidden; }
.ticker__track { display: flex; width: max-content; animation: ticker 46s linear infinite; }
.ticker__track span {
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  letter-spacing: .14em;
  padding: 15px 30px;
  display: inline-flex;
  align-items: center;
  gap: 30px;
  white-space: nowrap;
}
.ticker__track span::after { content: "✦"; color: var(--squash); font-size: .7em; }
@keyframes ticker { from { transform: translateX(0); } to { transform: translateX(-50%); } }
.ticker[data-paused="true"] .ticker__track { animation-play-state: paused; }
/* Mouse only. On touch, a tap leaves :hover on the ticker, so the play button
   could never restart it. */
@media (hover: hover) and (pointer: fine) {
  .ticker:hover .ticker__track { animation-play-state: paused; }
  .ticker__pause:hover { color: var(--leaf-bright); }
}
.ticker__pause {
  position: absolute; top: 0; bottom: 0; right: 0;
  /* The fill runs to the screen edge; the icon stays inside a landscape safe area. */
  width: calc(46px + env(safe-area-inset-right, 0px));
  display: flex; align-items: center; justify-content: center;
  padding: 0 env(safe-area-inset-right, 0px) 0 0; border: 0;
  border-left: 1px solid var(--on-forest-line);
  background: var(--forest);
  color: var(--on-forest);
  cursor: pointer;
}
.ticker__ico { width: 15px; height: 15px; fill: currentColor; }
.ticker__ico--play { display: none; }
.ticker[data-paused="true"] .ticker__ico--pause { display: none; }
.ticker[data-paused="true"] .ticker__ico--play { display: block; }

/* ==========================================================================
   WHY WE STARTED — the two ends of the gap in words, then the bridge drawn
   ========================================================================== */
.solution__ends { display: grid; gap: 28px; max-width: 1040px; }
.solution__ends p { font-size: var(--fs-lg); line-height: 1.85; color: var(--ink); }
/* Each end's label wears its bank's colour from the bridge below (.bridge__bank),
   so the reader pairs the two paragraphs with the two ends of the drawing. */
.end {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 6px;
  font-family: var(--font-display);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-h5);
  line-height: 1.45;
  color: var(--forest);
}
.end::before { content: ""; flex: none; width: 14px; height: 14px; background: var(--leaf-bright); }
.end--you::before { background: var(--squash); }
@media (min-width: 900px) {
  .solution__ends { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: clamp(32px, 5vw, 72px); }
}

.bridge { position: relative; margin-top: clamp(44px, 6vw, 88px); }
.bridge__arc { display: none; }
.bridge__deck { position: relative; display: grid; }
/* Phone: the deck runs downward, banks at either end. */
.bridge__deck::before {
  content: "";
  position: absolute;
  left: 17px;
  top: 0;
  bottom: 0;
  width: 3px;
  background: var(--forest);
}
/* forest on leaf-bright 5.48:1, on squash 5.69:1. */
.bridge__bank {
  position: relative;
  padding: 16px 18px;
  background: var(--leaf-bright);
  color: var(--forest);
  font-family: var(--font-display);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-h5);
}
.bridge__bank--home { background: var(--squash); }
.bridge__step {
  position: relative;
  padding: 20px 0 20px 50px;
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: 1.55;
  color: var(--ink);
}
.bridge__node {
  position: absolute;
  left: 10px;
  top: 50%;
  width: 17px;
  height: 17px;
  margin-top: -8.5px;
  border-radius: 50%;
  background: var(--ivory);
  border: 3px solid var(--forest);
}
@media (min-width: 900px) {
  .bridge { padding-top: clamp(70px, 9vw, 120px); }
  .bridge__deck { grid-template-columns: 1.15fr 1fr 1fr 1fr 1.15fr; align-items: start; }
  .bridge__deck::before { left: 0; right: 0; top: 0; bottom: auto; width: auto; height: 4px; }
  .bridge__bank { min-height: 96px; display: flex; align-items: flex-end; padding: 18px 20px; font-size: var(--fs-h4); }
  .bridge__step { padding: 28px 14px 0; text-align: center; }
  .bridge__node { left: 50%; top: 2px; margin: -8.5px 0 0 -8.5px; }
  /* The span sits exactly between the banks: 1.15 / 5.3 of the deck each side. */
  .bridge__arc {
    display: block;
    position: absolute;
    left: 21.7%;
    top: 0;
    width: 56.6%; /* explicit: an <svg> with left+right and width:auto falls back to 300px */
    height: clamp(70px, 9vw, 120px);
    overflow: visible;
  }
  .bridge__arc path { fill: none; stroke: var(--forest); stroke-width: 3; vector-effect: non-scaling-stroke; }
  .bridge__arc .bridge__hangers { stroke-width: 1.5; opacity: .45; }
}

/* ==========================================================================
   HOW IT WORKS — a route with four stops
   ========================================================================== */
.route { position: relative; display: grid; --g: clamp(20px, 3vw, 44px); }
.route__step { position: relative; padding: 0 0 34px 66px; }
/* Phone: each stop draws the segment down to the next stop's centre
   (own centre at 18px; the next one sits 18px into the following item). */
.route__step:not(:last-child)::before {
  content: "";
  position: absolute;
  left: 21px;
  top: 18px;
  bottom: -18px;
  width: 2px;
  background: var(--rule-ink);
}
.route__step:last-child { padding-bottom: 0; }
.route__no {
  position: absolute;
  left: 0;
  top: -4px;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--ivory);
  border: 1.5px solid var(--forest);
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: var(--fw-semibold);
  color: var(--forest);
  font-variant-numeric: tabular-nums;
}
.route__step:last-child .route__no { background: var(--squash); border-color: var(--squash); }
.route h3 {
  font-family: var(--font-display);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-h4);
  line-height: 1.4;
  color: var(--forest);
  margin-bottom: 8px;
}
.route p { font-size: var(--fs-ui); line-height: 1.75; color: var(--ink-soft); }
@media (min-width: 900px) {
  .route { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--g); }
  .route__step::before { display: none; }
  .route::before {
    content: "";
    position: absolute;
    background: var(--rule-ink);
    left: 22px;
    right: calc((100% - 3 * var(--g)) / 4 - 22px);
    top: 21px;
    bottom: auto;
    width: auto;
    height: 2px;
  }
  .route__step { padding: 72px 0 0; }
  .route__no { top: 0; }
}

/* ==========================================================================
   WHAT'S IN THE BOX — the box drawn from above, then the four things in it in
   words. Phone: figure, list, note under the heading. From 900px the figure
   takes the left column and the list and note the right; the figure's tag and
   the list's top rule start on one line.
   ========================================================================== */
.box__grid, .box__body { display: grid; gap: clamp(28px, 4vw, 40px); align-content: start; }

/* The box figure (and later the client's open-box photo, see index.html). Capped
   on phones so the list it explains stays close. A container, so the room left
   for the insert card scales with the figure, not with its column. align-self:
   a grid item stretches to the row, and the card, pinned to the figure's bottom
   edge from 600px, would drift away from the box. The top padding leaves room
   for the tag (26px above the rim's inner edge) less the rim, so the tag's top
   is the figure's top. */
.crate {
  --rim: clamp(10px, 1.8vw, 16px);
  position: relative;
  align-self: start;
  width: 100%;
  max-width: 320px;
  padding-top: calc(26px - var(--rim));
  container-type: inline-size;
}
.crate__box {
  position: relative;
  width: 86%;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--plot-gap);
  padding: var(--plot-gap);
  background: var(--kraft);            /* the cardboard dividers */
  border: var(--rim) solid var(--sand); /* the rim */
  box-shadow: inset 0 0 0 1px rgba(107, 79, 52, .35);
}
.crate__tag {
  position: absolute;
  top: -26px;
  left: 14px;
  z-index: 2;
  padding: 4px 10px;
  background: var(--ivory);
  border: 1px solid var(--soil);
  font-size: var(--fs-xs);
  font-weight: var(--fw-bold);
  letter-spacing: .04em;
  color: var(--soil);
}
/* Numbered marker: the figure's pins and the list's numbers. */
.pin, .inbox__no {
  display: inline-grid;
  place-items: center;
  flex: none;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--forest);
  color: var(--ivory);
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  font-weight: var(--fw-bold);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.crate__pin { position: absolute; top: -13px; right: -13px; z-index: 2; box-shadow: 0 0 0 3px var(--ivory); }
/* Eight compartments, eight produce shapes. Abstract on purpose: the real
   contents change weekly and are announced in LINE, so none are named here. */
.cell { position: relative; aspect-ratio: 1; background: var(--beige); }
.cell::before { content: ""; position: absolute; inset: 20%; }
.cell--1::before { background: var(--olive); border-radius: 0 100% 0 100%; transform: rotate(-12deg); }
.cell--2::before { background: var(--tomato); border-radius: 50%; inset: 24%; }
.cell--3::before { background: var(--squash); border-radius: 50%; inset: 16%; }
.cell--4::before { background: var(--leaf-bright); border-radius: 100% 0 100% 0; }
.cell--5::before { background: var(--kraft-deep); border-radius: 999px; inset: 38% 10%; transform: rotate(-35deg); }
.cell--6::before {
  inset: 14%;
  background:
    radial-gradient(circle at 30% 35%, var(--forest) 0 22%, transparent 23%),
    radial-gradient(circle at 68% 32%, var(--olive) 0 24%, transparent 25%),
    radial-gradient(circle at 50% 70%, var(--leaf) 0 26%, transparent 27%);
}
.cell--7::before { background: var(--forest); border-radius: 0 100% 0 100%; transform: rotate(18deg); inset: 18%; }
.cell--8::before { background: var(--leaf); border-radius: 50%; inset: 22%; }

/* Phone: the card lies just below the box, overlapping its rim, so no
   compartment is hidden. From 600px it lies across the box's corner. The tilt
   is the rotate property, not transform: the reveal sets transform: none on
   arrival, which would flatten it. */
.crate__card {
  position: relative;
  margin: -16px 0 0 auto;
  width: 78%;
  padding: 10px 14px;
  background: var(--ivory);
  border: 1px solid var(--line-strong);
  rotate: 2.5deg;
  /* The second (and last) shadow on the page: the card lies on top of the box. */
  box-shadow: 0 16px 30px -14px rgba(19, 43, 35, .35);
}
.card__row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 10px;
  padding: 9px 0;
  border-bottom: 1px dashed var(--line-strong);
}
.card__row:last-child { border-bottom: 0; }
.card__lab { font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: .04em; color: var(--forest); white-space: nowrap; }
.card__lines { height: 15px; background: repeating-linear-gradient(to bottom, var(--line-strong) 0 1.5px, transparent 1.5px 6.5px); }
@media (min-width: 600px) {
  .crate { max-width: 440px; }
  .crate__box { margin-bottom: 22cqi; }
  .crate__card { position: absolute; right: 0; bottom: 0; width: 56%; margin: 0; }
}
@media (min-width: 900px) { .crate { max-width: 560px; } }
.qr { display: grid; grid-template-columns: 1fr 1fr; gap: 3px; width: 34px; height: 34px; }
.qr i { border: 3px solid var(--forest); box-shadow: inset 0 0 0 2px var(--ivory), inset 0 0 0 8px var(--forest); }
.qr i:last-child { border: 0; box-shadow: none; background: repeating-conic-gradient(var(--forest) 0 25%, transparent 0 50%) 0 0 / 5px 5px; }

.inbox { border-top: 1px solid var(--rule-ink); }
.inbox > div { position: relative; padding: 18px 0 18px 44px; border-bottom: 1px solid var(--line); }
.inbox dt {
  font-family: var(--font-display);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-h5);
  line-height: 1.45;
  color: var(--forest);
}
.inbox__no { position: absolute; left: 0; top: 19px; }
.inbox dd { margin-top: 4px; font-size: var(--fs-ui); line-height: 1.75; color: var(--ink-soft); }
/* A note about the whole list, not a fifth item in it: emphasis by weight, not a
   coloured bar or a title, and on a phone extra room above it after the last rule. */
.box-outro { max-width: 34em; font-size: var(--fs-lg); line-height: 1.9; color: var(--ink); }
.box-outro strong { font-weight: var(--fw-semibold); color: var(--forest); }
@media (max-width: 899px) { .box-outro { margin-top: 12px; } }
@media (min-width: 900px) {
  .box__grid { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); column-gap: clamp(48px, 7vw, 112px); }
}

/* ==========================================================================
   ORDER INFO — the carton label
   ========================================================================== */
.info__grid { display: grid; gap: 40px; }
.info__head .btn { margin-top: 30px; }
/* The LINE QR beside the two dark CTAs, from 960px only: a laptop visitor scans
   it with the phone that has LINE. The asset is LINE's own (see index.html). */
.lineqr { display: none; margin: 28px 0 0; }
@media (min-width: 960px) {
  .lineqr:not([hidden]) { display: flex; align-items: center; gap: 16px; }
}
.lineqr img { width: 120px; height: 120px; padding: 8px; background: var(--white); border-radius: 2px; }
.lineqr figcaption { font-size: var(--fs-sm); line-height: 1.6; color: var(--on-forest-soft); }
.label { background: var(--ivory); color: var(--ink); border-radius: 2px; overflow: hidden; }
.label__head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding: 14px 20px;
  background: var(--squash);
  color: var(--forest);
  font-family: var(--font-display);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-h5);
}
.label__head span + span {
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  letter-spacing: .04em;
  padding: 2px 8px;
  border: 1.5px solid var(--forest);
}
.label__rows { padding: 4px 20px 8px; }
.label__row {
  display: grid;
  grid-template-columns: 76px minmax(0, 1fr);
  gap: 14px;
  padding: 16px 0;
  border-bottom: 1px dashed var(--line-strong);
}
.label__row:last-child { border-bottom: 0; }
/* 14px, light tracking: 取消與退款 still fits the 76px phone column (5 × 14.6px). */
.label__row dt {
  padding-top: 1px;
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  letter-spacing: .04em;
  color: var(--olive-text);
}
.label__row dd { font-size: var(--fs-ui); line-height: 1.75; color: var(--ink); }
/* Wrap only at punctuation, so place names never split (基 / 隆市). */
.keep { word-break: keep-all; }
.label__row dd a { color: var(--forest); font-weight: var(--fw-semibold); text-decoration: none; border-bottom: 1px solid var(--line-strong); }
.label__row--price dd { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; }
.label__big {
  font-family: var(--font-display);
  font-weight: var(--fw-semibold);
  font-variation-settings: var(--fv-display);
  font-size: clamp(46px, 6vw, 70px);
  line-height: 1;
  letter-spacing: -.01em;
  color: var(--forest);
  font-variant-numeric: lining-nums;
}
.label__big small { font-size: .38em; vertical-align: .9em; margin-right: .1em; letter-spacing: .02em; }
/* Delivery area: real county boundaries (see the comment in index.html).
   Served (北北基): 臺北 and 基隆 (solid) with 新北 (tint) around them.
   Neighbours are land context only; the inset locates the crop on Taiwan. */
.areamap { display: block; width: 100%; max-width: 320px; height: auto; margin-top: 12px; overflow: hidden; }
.areamap path { stroke-linejoin: round; }
.areamap__nbr { fill: #E9E1D0; stroke: var(--ivory); stroke-width: 1; }
.areamap__ntp { fill: var(--leaf-tint); stroke: var(--olive); stroke-width: 1.2; }
.areamap__tpe { fill: var(--leaf-bright); stroke: var(--forest); stroke-width: 1.2; }
.areamap__kee { fill: var(--leaf-bright); stroke: var(--forest); stroke-width: 1.2; }
/* Same-colour stroke closes the hairline seams between the simplified counties. */
.areamap__island { fill: var(--sage); stroke: var(--sage); stroke-width: .9; }
.areamap__frame { fill: none; stroke: var(--forest); stroke-width: 1; }
/* 11px is the largest 臺北市 that fits wholly inside Taipei's outline (searched with isPointInFill). */
.areamap__lab { font-family: var(--font-body); font-size: 11px; font-weight: 700; fill: var(--forest); }
.areamap__lab--big { font-size: 13px; }
.areamap__lab--kee { font-size: 10px; } /* largest that fits wholly inside Keelung */
.areamap__src { display: block; margin-top: 6px; font-size: var(--fs-xs); line-height: 1.6; color: var(--ink-soft); }
/* Phone: the value column is ~210px, which would set the map's labels at ~10px.
   Let the map (and its credit) run under the label column too. */
@media (max-width: 599px) {
  .areamap, .areamap__src { width: calc(100% + 90px); max-width: none; margin-left: -90px; } /* 76px dt + 14px gap */
}
@media (min-width: 600px) {
  .label__head { padding: 16px 32px; }
  .label__rows { padding: 6px 32px 10px; }
  .label__row { grid-template-columns: 110px minmax(0, 1fr); gap: 20px; }
}
@media (min-width: 900px) {
  .info__grid { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: clamp(40px, 6vw, 96px); align-items: start; }
  .info__head { position: sticky; top: calc(var(--masthead-h) + 40px); }
}

/* ==========================================================================
   THE PHOTOGRAPH — the page's one image, in the middle of OUR STORY (below)
   ========================================================================== */
/* Phone: the collage keeps its height and pans sideways, snapping to each
   column of frames, instead of shrinking to a 200px-tall strip. */
.collage { margin: 0; }
.collage__scroller {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  padding-inline: var(--gutter);
  scrollbar-width: thin;
  scrollbar-color: var(--sage) transparent;
}
.collage__frame {
  --h: clamp(260px, 86vw, 460px);
  position: relative;
  height: var(--h);
  width: calc(var(--h) * 1.8078); /* 3762 / 2081 */
}
.collage__frame picture, .collage__frame img { width: 100%; height: 100%; }
/* Snap points at the left edge of each column of frames, as percentages of the
   cropped image (columns start at 0 / 37.2 / 69.1% across). */
.collage__snap { position: absolute; top: 0; width: 1px; height: 1px; scroll-snap-align: start; scroll-margin-left: var(--gutter); }
.collage__snap--1 { left: 0; }
.collage__snap--2 { left: 37.2%; }
.collage__snap--3 { left: 69.1%; }
.collage__hint { margin-top: 14px; font-size: var(--fs-xs); color: var(--ink-soft); }
.collage__hint::after { content: " →"; }
@media (min-width: 700px) {
  .collage__scroller { overflow: visible; max-width: var(--wrap-wide); margin-inline: auto; }
  .collage__frame { height: auto; width: 100%; aspect-ratio: 3762 / 2081; }
  .collage__hint { display: none; }
}

/* ==========================================================================
   WHY TENDY — three comparisons, side by side from 900px
   ========================================================================== */
.vs { display: grid; border-top: 1px solid var(--rule-ink); }
.vs li { padding: 24px 0; border-bottom: 1px solid var(--line); }
.vs h3 {
  font-family: var(--font-display);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-h4);
  line-height: 1.4;
  color: var(--forest);
}
.vs h3 span { display: block; margin-bottom: 4px; font-family: var(--font-body); font-size: var(--fs-xs); letter-spacing: .04em; color: var(--olive-text); }
.vs p { margin-top: 8px; font-size: var(--fs-lg); line-height: 1.8; color: var(--ink); }
@media (min-width: 900px) {
  .vs { grid-template-columns: repeat(3, minmax(0, 1fr)); column-gap: clamp(28px, 4vw, 56px); }
  .vs li { padding: 30px 0 0; border-bottom: 0; }
}

/* ==========================================================================
   TRUST
   ========================================================================== */
/* The photo section's cream (#F4F1EA) is one step from this ivory, so without a
   line the two sections read as one surface. */
.trust { border-top: 1px solid var(--line); }
.promises { display: grid; border-top: 1px solid var(--rule-ink); }
.promise { padding: 24px 0; border-bottom: 1px solid var(--line); }
.promise h3 {
  font-family: var(--font-display);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-h5);
  line-height: 1.45;
  color: var(--forest);
  margin-bottom: 6px;
}
.promise p { font-size: var(--fs-ui); line-height: 1.75; color: var(--ink-soft); }
/* The damage promise carries the 24-hour stamp: 24 ticks for 24 hours, the
   window to send a photo (client's pick, 2026-10-23). */
.promise--wide { display: flex; gap: 22px; align-items: flex-start; }
.dial {
  position: relative;
  flex: none;
  width: 96px;
  height: 96px;
  border-radius: 50%;
  display: grid;
  place-content: center;
  text-align: center;
  background:
    radial-gradient(closest-side, var(--ivory) 80%, transparent 81%),
    repeating-conic-gradient(var(--tomato) 0 3deg, transparent 3deg 15deg);
}
.dial b { font-family: var(--font-display); font-weight: var(--fw-semibold); font-size: 32px; line-height: 1; color: var(--forest); }
.dial small { font-size: var(--fs-xs); font-weight: var(--fw-semibold); letter-spacing: .04em; color: var(--ink-soft); }
/* The damage promise is the longest; it takes two columns so the grid closes evenly. */
@media (min-width: 600px) {
  .promises { grid-template-columns: 1fr 1fr; column-gap: clamp(28px, 4vw, 56px); }
  .promise--wide { grid-column: span 2; }
}
@media (min-width: 900px) {
  .promises { grid-template-columns: repeat(3, 1fr); }
  .promise { padding: 30px 0; }
}

/* ==========================================================================
   WHO IT'S FOR — paired rows across a spine
   ========================================================================== */
.fit { display: grid; gap: 40px; }
.fit h3 {
  display: flex;
  align-items: center;
  gap: 12px;
  padding-bottom: 14px;
  font-family: var(--font-display);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-h4);
  color: var(--forest);
  border-bottom: 2px solid var(--forest);
}
.fit h3::before {
  content: "＋";
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--leaf-bright);
  color: var(--forest);
  font-family: var(--font-body);
  font-size: 15px;
}
.fit__col--no h3 { color: var(--ink-soft); border-color: var(--rule-ink); }
.fit__col--no h3::before { content: "－"; background: var(--beige); color: var(--soil); }
.fit li {
  display: flex;
  gap: 12px;
  align-items: baseline;
  padding: 16px 0;
  border-bottom: 1px solid var(--line);
  font-size: var(--fs-lg);
  line-height: 1.6;
  color: var(--ink);
}
.fit li::before { content: "＋"; color: var(--olive-text); font-weight: var(--fw-semibold); }
.fit__col--no li { color: var(--ink-soft); }
.fit__col--no li::before { content: "－"; color: var(--ink-soft); }
/* Desktop: subgrid lines each pair up across the centre, so a row reads as
   "this, rather than that". Without subgrid the columns simply don't align. */
@media (min-width: 760px) {
  .fit { grid-template-columns: 1fr 1fr; grid-template-rows: auto repeat(4, auto); gap: 0; }
  .fit__col { display: grid; grid-row: 1 / -1; grid-template-rows: subgrid; }
  .fit__col ul { display: grid; grid-row: 2 / -1; grid-template-rows: subgrid; }
  .fit__col--yes { padding-right: clamp(24px, 4vw, 56px); border-right: 2px solid var(--forest); }
  .fit__col--no { padding-left: clamp(24px, 4vw, 56px); }
}

/* ==========================================================================
   OUR STORY — 品牌故事 and 產地故事 in one section: the name as a lockup beside
   one paragraph, the field record and the photograph, then the timeline. The
   cream is the collage's own, so the photo's gutters vanish.
   ========================================================================== */
.story { background: var(--collage); }
.story__name { display: grid; gap: 28px; margin-bottom: clamp(48px, 7vw, 88px); }
/* tend + 田地 = Tendy. Upright throughout: the italic face is no longer loaded,
   so italic here would be one the browser fakes. */
.name { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 14px 12px; }
.name__part { display: inline-flex; flex-direction: column; }
.name__eq { display: inline-flex; align-items: flex-start; gap: 12px; } /* "= Tendy" wraps as one unit */
.name__word {
  font-family: var(--font-display);
  font-weight: var(--fw-semibold);
  font-variation-settings: var(--fv-display);
  font-size: clamp(38px, 5vw, 76px);
  line-height: 1.05;
  color: var(--forest);
}
.name__word--en { font-variation-settings: var(--fv-em); } /* the softer cut sets the Latin apart */
/* --kraft-deep is 3.29:1 on the collage cream: large display text only, which this is. */
.name__part:first-child .name__word { color: var(--kraft-deep); }
.name__part--result .name__word { padding: .02em .28em .1em; background: var(--forest); color: var(--ivory); }
.name__gloss { max-width: 9em; margin-top: 10px; font-size: var(--fs-xs); font-weight: var(--fw-medium); letter-spacing: .04em; color: var(--ink-soft); }
.name__op { font-family: var(--font-display); font-size: clamp(26px, 3vw, 44px); line-height: 1.5; color: var(--soil); }
.story__words { max-width: 40em; }
.story__words p { font-size: var(--fs-lg); line-height: 1.9; color: var(--ink); }
@media (min-width: 900px) {
  .story__name { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: clamp(40px, 6vw, 96px); align-items: center; }
}

.story__sub {
  display: flex;
  align-items: center;
  gap: 18px;
  margin-bottom: 32px;
  font-family: var(--font-display);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-h3);
  color: var(--forest);
}
.story__sub::after { content: ""; flex: 1; height: 1px; background: var(--rule-ink); }
.tl { position: relative; padding: 0 0 44px 30px; }
.tl::before { content: ""; position: absolute; left: 5px; top: 10px; bottom: -10px; width: 2px; background: var(--rule-ink); }
.tl::after {
  content: "";
  position: absolute;
  left: 0;
  top: 7px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--ivory);
  border: 2px solid var(--forest);
}
.tl--now { padding-bottom: 0; }
.tl--now::before { display: none; }
.tl--now::after { background: var(--squash); border-color: var(--squash); box-shadow: 0 0 0 5px rgba(227, 169, 63, .25); }
.tl__when {
  display: block;
  margin-bottom: 8px;
  font-family: var(--font-display);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-h4);
  line-height: 1.3;
  color: var(--forest);
  font-variant-numeric: lining-nums;
}
.tl__body p { font-size: var(--fs-lg); line-height: 1.9; color: var(--ink); max-width: 40em; }
.tl--now .tl__body p { font-weight: var(--fw-semibold); color: var(--forest); }
/* The founders' question, set apart by size and the display face alone. */
.tl__body .tl__quote {
  margin-top: 18px;
  font-family: var(--font-display);
  font-weight: var(--fw-semibold);
  font-size: clamp(19px, 1.2vw + .7rem, 24px);
  line-height: 1.6;
  color: var(--forest);
}
/* Four problems, four plots: 田 again, 2 × 2 even on a phone (client's pick,
   2026-10-23), with tighter plots there. */
.four { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--plot-gap); margin-top: 22px; max-width: 760px; }
.four li { padding: 14px 14px 16px; font-size: var(--fs-ui); line-height: 1.7; color: var(--ink); }
.four li:nth-child(1) { background: var(--leaf-tint); }
.four li:nth-child(2) { background: var(--beige); }
.four li:nth-child(3) { background: var(--squash-tint); }
.four li:nth-child(4) { background: var(--paper); }
.four__no {
  display: block;
  margin-bottom: 6px;
  font-family: var(--font-display);
  font-variation-settings: var(--fv-display);
  font-size: 26px;
  line-height: 1;
  color: var(--soil);
}
@media (min-width: 600px) {
  .four li { padding: 20px 20px 22px; font-size: var(--fs-body); line-height: 1.75; }
  .four__no { margin-bottom: 8px; font-size: 30px; }
}
@media (min-width: 900px) {
  .tl { display: grid; grid-template-columns: 150px minmax(0, 1fr); column-gap: 64px; padding-left: 0; }
  .tl::before { left: 181px; }
  .tl::after { left: 176px; }
  .tl__when { text-align: right; margin-bottom: 0; }
}

/* The field record (#origin, the old 產地故事 target): the same subhead as
   我們的故事, one line and the two links, then the photograph after the wrap.
   The lockup's bottom margin is the gap above it. From 900px the links sit
   beside the line, on its baseline. */
.origin__body { display: grid; gap: 24px; margin-bottom: clamp(28px, 4vw, 48px); }
.origin__body p { font-size: var(--fs-lg); line-height: 1.85; color: var(--ink); max-width: 34em; }
@media (min-width: 900px) {
  .origin__body { grid-template-columns: minmax(0, 1fr) auto; align-items: end; column-gap: clamp(40px, 6vw, 96px); }
}
/* 我們的故事 opens its own wrap after the photograph, at the lockup's spacing. */
.story__history { margin-top: clamp(48px, 7vw, 88px); }

/* ==========================================================================
   PARTNER PROGRAM — four role cards, each with a glyph of who the boxes travel
   between (client's pick, 2026-10-23). 2 × 2 on phones, one row from 1100px.
   Group orders fold away.
   ========================================================================== */
.roles { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--plot-gap); }
.role { padding: 18px 16px 20px; background: var(--ivory); border-radius: 2px; }
.role__glyph { width: 100%; max-width: 140px; height: auto; margin-bottom: 14px; overflow: visible; }
.role h3 {
  font-family: var(--font-display);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-h5);
  line-height: 1.4;
  color: var(--forest);
  margin-bottom: 6px;
}
.role p { font-size: var(--fs-sm); line-height: 1.7; color: var(--ink); }
.g-you { fill: var(--forest); }
.g-friend { fill: var(--ivory); stroke: var(--forest); stroke-width: 2; }
.g-tendy { fill: var(--squash); stroke: var(--forest); stroke-width: 2; }
.g-link { fill: none; stroke: var(--forest); stroke-width: 1.5; opacity: .5; }
.g-link--dash { stroke-dasharray: 4 4; opacity: .8; }
.g-link--bold { stroke-width: 4; opacity: 1; }
.g-wave { fill: none; stroke: var(--tomato); stroke-width: 2.5; stroke-linecap: round; }
.g-halo { fill: var(--squash); opacity: .5; }
.roles__key { display: flex; flex-wrap: wrap; gap: 8px 20px; margin-top: 16px; font-size: var(--fs-xs); color: var(--ink-soft); }
.roles__key span { display: inline-flex; align-items: center; gap: 7px; }
.roles__key i { width: 12px; height: 12px; }
.k-tendy { background: var(--squash); border: 1.5px solid var(--forest); }
.k-you { background: var(--forest); border-radius: 50%; }
.k-friend { background: var(--ivory); border: 1.5px solid var(--forest); border-radius: 50%; }
@media (min-width: 600px) {
  .roles { gap: 12px; }
  .role { padding: 26px 24px 28px; }
  .role__glyph { margin-bottom: 18px; }
  .role h3 { font-size: var(--fs-h4); }
  .role p { font-size: var(--fs-ui); line-height: 1.75; }
}
@media (min-width: 1100px) { .roles { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.roles__note { margin-top: 18px; font-size: var(--fs-body); color: var(--ink); }

/* 揪團怎麼運作: the shared disclosure (FAQ, below), on its own hairlines. */
.group { margin-top: clamp(28px, 4vw, 40px); border-top: 1px solid var(--rule-ink); border-bottom: 1px solid var(--rule-ink); }
.group__steps { padding-bottom: 20px; max-width: 46em; }
.group__steps li {
  display: grid;
  grid-template-columns: 30px minmax(0, 1fr);
  gap: 4px 14px;
  padding: 12px 0;
}
.group__steps li:first-child { padding-top: 0; }
.group__no {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--squash);
  color: var(--forest);
  font-size: 13px;
  font-weight: var(--fw-bold);
}
.group__steps p { font-size: var(--fs-body); line-height: 1.75; padding-top: 2px; }
.partner__cta { margin-top: clamp(28px, 4vw, 40px); }
.fine { margin-top: 14px; font-size: var(--fs-xs); line-height: 1.7; color: var(--ink-soft); }

/* ==========================================================================
   FAQ + disclosure primitive (shared with the legal blocks and 揪團怎麼運作)
   ========================================================================== */
.faq { display: grid; gap: 24px; }
.faq__head .kicker { margin-bottom: 18px; }
.faq__list { border-top: 1px solid var(--rule-ink); }
.faq details { border-bottom: 1px solid var(--line); }
.faq summary,
.legal__block > summary,
.group > summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 20px;
  padding: 22px 0;
  font-family: var(--font-display);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-h5);
  line-height: 1.5;
  color: var(--forest);
}
.faq summary::-webkit-details-marker,
.legal__block > summary::-webkit-details-marker,
.group > summary::-webkit-details-marker { display: none; }
/* Same curve as the answer opening below it, so the plus and the panel move as one. */
.disclosure__plus { flex: 0 0 auto; width: 16px; height: 16px; position: relative; transition: transform var(--dur-med) var(--ease-out); }
/* --soil, not --kraft: kraft is 2.26–2.45:1 on beige/paper, under 3:1 for UI graphics. */
.disclosure__plus::before, .disclosure__plus::after { content: ""; position: absolute; background: var(--soil); }
.disclosure__plus::before { left: 0; top: 7px; width: 16px; height: 2px; }
.disclosure__plus::after { left: 7px; top: 0; width: 2px; height: 16px; }
.faq details[open] .disclosure__plus,
.legal__block[open] .disclosure__plus,
.group[open] .disclosure__plus { transform: rotate(135deg); }
.faq details::details-content,
.legal__block::details-content,
.group::details-content {
  block-size: 0;
  overflow: hidden;
  transition: block-size var(--dur-med) var(--ease-out), content-visibility var(--dur-med) allow-discrete;
}
.faq details[open]::details-content,
.legal__block[open]::details-content,
.group[open]::details-content { block-size: auto; }
.faq__a { padding: 0 36px 24px 0; font-size: var(--fs-body); line-height: 1.85; color: var(--ink); max-width: 62ch; }
.faq__a b { color: var(--forest); font-weight: var(--fw-semibold); }
.faq__a a { color: var(--forest); font-weight: var(--fw-semibold); text-decoration: none; border-bottom: 1px solid var(--line-strong); }
@media (min-width: 900px) {
  .faq { grid-template-columns: minmax(0, 4fr) minmax(0, 8fr); gap: clamp(32px, 6vw, 96px); }
  .faq__head { position: sticky; top: calc(var(--masthead-h) + 40px); align-self: start; }
}

/* ==========================================================================
   FINAL CTA — and the landscape strip
   ========================================================================== */
.final { position: relative; background: var(--forest); color: var(--on-forest); overflow: hidden; }
.final__in { padding-block: clamp(84px, 12vw, 160px) clamp(56px, 8vw, 104px); }
.final h2 {
  font-family: var(--font-display);
  font-weight: var(--fw-semibold);
  font-variation-settings: var(--fv-display);
  font-size: clamp(32px, 3.8vw + 1rem, 66px);
  line-height: 1.24;
  max-width: 15em;
  color: var(--ivory);
  margin-bottom: 26px;
}
.final__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 20px 24px; }
.patch {
  display: grid;
  grid-template-columns: 1.4fr .8fr 1.1fr .7fr 1.3fr;
  gap: var(--plot-gap);
  height: clamp(72px, 10vw, 140px);
  padding: 0 var(--plot-gap);
}
.patch i:nth-child(n+6) { display: none; }
.patch i:nth-child(1) { background: var(--olive) repeating-linear-gradient(90deg, rgba(246,242,232,.14) 0 2px, transparent 2px 12px); }
.patch i:nth-child(2) { background: var(--squash) repeating-linear-gradient(0deg, rgba(31,61,43,.14) 0 2px, transparent 2px 11px); }
.patch i:nth-child(3) { background: var(--leaf-bright) radial-gradient(circle, rgba(31,61,43,.22) 2px, transparent 2.6px) 0 0 / 15px 15px; }
.patch i:nth-child(4) { background: var(--sand) repeating-linear-gradient(135deg, rgba(107,79,52,.2) 0 2px, transparent 2px 10px); }
.patch i:nth-child(5) { background: var(--leaf) repeating-linear-gradient(45deg, rgba(246,242,232,.14) 0 2px, transparent 2px 13px); }
.patch i:nth-child(6) { background: var(--beige) repeating-linear-gradient(90deg, rgba(107,79,52,.18) 0 2px, transparent 2px 9px); }
.patch i:nth-child(7) { background: var(--tomato); }
.patch i:nth-child(8) { background: var(--sage) repeating-linear-gradient(0deg, rgba(31,61,43,.16) 0 2px, transparent 2px 12px); }
.patch i:nth-child(9) { background: var(--squash-tint) radial-gradient(circle, rgba(107,79,52,.25) 2px, transparent 2.6px) 0 0 / 13px 13px; }
@media (min-width: 760px) {
  .patch { grid-template-columns: 1.4fr .8fr 1.1fr .7fr 1.3fr .9fr .45fr 1.2fr 1fr; }
  .patch i:nth-child(n+6) { display: block; }
}

/* ==========================================================================
   TERMS & PRIVACY
   ========================================================================== */
.legal .section-head > p:not(.kicker) { font-size: var(--fs-ui); color: var(--ink-soft); }
.legal__block { border-top: 1px solid var(--rule-ink); }
.legal__block:last-of-type { border-bottom: 1px solid var(--line); }
.legal__body { padding: 2px 0 28px; }
.legal__p { font-size: var(--fs-sm); color: var(--ink-soft); line-height: 1.85; margin-bottom: 16px; max-width: 62ch; }
.legal__dl > div { display: grid; gap: 2px; padding: 14px 0; border-bottom: 1px solid var(--line); }
.legal__dl > div:last-child { border-bottom: 0; }
.legal__dl dt { font-size: var(--fs-xs); font-weight: var(--fw-semibold); letter-spacing: .04em; color: var(--olive-text); padding-top: 2px; }
.legal__dl dd { font-size: var(--fs-sm); line-height: 1.8; color: var(--ink); }
.legal__dl dd b { color: var(--forest); font-weight: var(--fw-semibold); }
.legal__dl dd a { color: var(--forest); text-decoration: none; border-bottom: 1px solid var(--line-strong); }
@media (min-width: 560px) { .legal__dl > div { grid-template-columns: minmax(96px, 150px) 1fr; gap: 4px 28px; } }

/* ------------------------------------------------------- Mobile sticky CTA */
.stickycta {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 40;
  padding: 10px var(--gutter) calc(10px + env(safe-area-inset-bottom, 0px));
  background: rgba(246, 242, 232, .95);
  backdrop-filter: saturate(130%) blur(8px);
  -webkit-backdrop-filter: saturate(130%) blur(8px);
  border-top: 1px solid var(--line-strong);
  transform: translateY(115%);
  transition: transform var(--dur-med) var(--ease-out);
}
.stickycta.is-visible { transform: none; }
.stickycta .btn { width: 100%; }
@media (min-width: 960px) { .stickycta { display: none; } }

/* ------------------------------------------------------------------ Footer */
.footer { background: var(--pine); color: var(--on-forest-soft); padding-block: clamp(52px, 7vw, 88px) 40px; }
.footer__top {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 30px 20px;
  padding-bottom: 36px;
  border-bottom: 1px solid var(--on-forest-line);
}
.footer__mark { grid-column: 1 / -1; }
.footer__mark img { height: 52px; width: auto; margin-bottom: 20px; }
.footer__mark p { max-width: 34ch; font-size: var(--fs-sm); line-height: 1.8; }
.footer__h { font-size: var(--fs-xs); font-weight: var(--fw-semibold); letter-spacing: .04em; color: var(--on-forest-soft); margin-bottom: 6px; }
/* Each row is ~46px (a 26px link + 2 × 10px; the 14px font keeps the row's line
   box from growing past the link), so the hit areas below meet the 44px touch
   target without overlapping their neighbours. */
.footer ul li { padding-block: 10px; font-size: var(--fs-sm); }
.footer ul li a, .footer__legal-links a {
  position: relative;
  display: inline-block;
  font-size: var(--fs-sm);
  color: var(--on-forest);
  text-decoration: none;
  border-bottom: 1px solid transparent;
}
@media (hover: hover) and (pointer: fine) {
  .footer ul li a:hover, .footer__legal-links a:hover { border-color: var(--on-forest-line); }
}
/* Grow the hit area to 44px without moving the underline. */
.footer ul li a::after, .footer__legal-links a::after { content: ""; position: absolute; inset: -10px -4px; }
.footer__note { margin-top: 26px; max-width: 64ch; font-size: var(--fs-xs); line-height: 1.8; }
.footer__legal { display: flex; flex-direction: column; gap: 14px; padding-top: 22px; font-size: var(--fs-xs); }
.footer__legal-links { display: flex; gap: 22px; flex-wrap: wrap; }
.footer__legal-links a { font-size: var(--fs-xs); line-height: 1.9; }
/* Phone: the two short lists side by side; contact runs full width, the email
   on its own line and the rest in pairs. From 700px: the 2 × 2 grid. */
@media (max-width: 699px) {
  .footer__contact { grid-column: 1 / -1; }
  .footer__contact ul { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: 20px; }
  .footer__contact li:first-child { grid-column: 1 / -1; }
}
@media (min-width: 700px) { .footer__mark { grid-column: auto; } }
@media (min-width: 1000px) {
  .footer__top { grid-template-columns: 1.5fr 1fr 1fr 1.25fr; gap: 40px; }
  .footer__legal { flex-direction: row; justify-content: space-between; align-items: baseline; }
}
/* Room for the floating CTA bar under the last line on phones. */
@media (max-width: 959px) { .footer { padding-bottom: 104px; } }

/* ==========================================================================
   One-shot reveal (motion primitive 4). site.js adds .js-reveal only to
   [data-reveal] blocks that start below the fold, sets --i on each child, and
   adds .is-revealed on first sight — or after a 3s failsafe if the observer
   never reports. With no JS, none of this applies and everything is visible.
   ========================================================================== */
.js-reveal > * { opacity: 0; transform: translateY(14px); }
.js-reveal.is-revealed > * {
  opacity: 1;
  transform: none;
  transition: opacity var(--dur-slow) var(--ease-out) calc(var(--i, 0) * 80ms),
              transform var(--dur-slow) var(--ease-out) calc(var(--i, 0) * 80ms);
}
/* The bridge draws itself left to right (a clip wipe: dash-offset drawing is
   unreliable on a non-scaling stroke) on the in-out curve: a line being drawn,
   not an entrance. On --ease-out it was 85% drawn in 300ms, then crawled. */
.bridge.js-reveal .bridge__arc { clip-path: inset(0 100% 0 0); }
.bridge.js-reveal.is-revealed .bridge__arc { opacity: 1; clip-path: inset(0 0 0 0); transition: clip-path 1.1s var(--ease) .2s; }

/* ==========================================================================
   Reduced motion — the one block
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .ticker__track { animation: none; }
  .ticker__pause { display: none; } /* nothing moves, so nothing to stop */
  .faq details::details-content, .legal__block::details-content, .group::details-content { transition: none; }
  /* The bar fades in place instead of sliding. Hidden while parked, so the
     invisible bar can't catch taps over the content behind it. */
  .stickycta { transform: none; opacity: 0; visibility: hidden; transition: opacity var(--dur) var(--ease), visibility 0s var(--dur); }
  .stickycta.is-visible { opacity: 1; visibility: visible; transition-delay: 0s; }
  /* Belt-and-braces: site.js skips the reveal under this setting, but the OS
     setting can change after the classes were applied. */
  .js-reveal > *, .bridge.js-reveal .bridge__arc {
    opacity: 1 !important; transform: none !important; clip-path: none !important; transition: none !important;
  }
  /* Press feedback is kept: a 2% press scale and a dim are not vestibular motion. */
}
