/* Typography — ONE self-hosted face with a voice (v16.4, Nov 3, 2026).
   PLUS JAKARTA SANS everywhere: app UI, body, legal pages and the
   landing's display headlines alike. Floyd's direction for this
   pass — the font must feel cool, fresh, neat and clean, with the
   orange theme's energy — ruled the first two drafts out: Inter
   (the previous face) is impeccably neutral and reads like every
   other SaaS product, and a Fraunces serif pairing tested
   beautifully but warm-editorial, the wrong temperature. Jakarta
   is a modern geometric-humanist sans with soft, rounded
   terminals: sunny and friendly at display sizes, crisp and calm
   in UI text, and unmistakably a consumer brand rather than a
   template. It won a rendered comparison against Manrope, Outfit,
   Sora and Nunito (QA: ~/workspace/qa/trocaly-v16.4/font-compare/).
   One variable file (SIL Open Font License, latin subset, 27 KB —
   LIGHTER than the ~97 KB of Inter statics it replaces) carries
   wght 200–800, fingerprinted ?v=29 for the immutable year cache,
   no external request at runtime; the OS stack stays as the
   fallback while it loads (font-display: swap). legal.css declares
   the same face for the legal pages. */
@font-face{font-family:'Plus Jakarta Sans';font-style:normal;font-weight:200 800;font-display:swap;src:url('/fonts/jakarta-var-latin.woff2?v=29') format('woff2')}
:root{
  /* v16.3 orange re-theme (Floyd's ruling, Nov 3, 2026): one
     unified orange system sampled from the official icon
     (#FF8A1E -> #F04E23 -> #E63329). --flame/--ember/--rust are
     the bright GRAPHICS stops (wallet card, avatar initials);
     every TEXT colour below them is darkened into the AA range
     and verified numerically: --give/--want #BC3A10 = 5.60:1 on
     white, --deep #9A3412 = 7.31:1, --ink #33231B = 15.03:1,
     --muted #6E5B4C = 6.43:1. "I Give" green and "I Want" blue
     are retired — --give and --want now hold the same ember. */
  --flame:#F06400; --ember:#F04E23; --rust:#E63329; --deep:#9A3412;
  --give:#BC3A10; --want:#BC3A10; --ink:#33231B; --muted:#6E5B4C;
  --line:#EDDCD0; --bg:#FFFFFF; --soft:#FDF3EC;
  /* Gradient TEXT stops: the ember range #C2410C -> #B02A1B,
     every stop >= 4.5:1 on white (5.18 / 5.52 / 6.58). */
  --grad-text:linear-gradient(90deg,#C2410C,#BE3A12,#B02A1B);
}
/* Type system (v16.4): one family, two registers — DISPLAY:
   Plus Jakarta Sans 800 with tightened tracking (-.015em hero,
   -.01em titles) for the hero headline and landing section
   titles; UI: h1 24/700 · h2 18/700 · body 15/400 · meta 13/400 ·
   price 16/800. Weight 800 is reserved for the wordmark, display
   headlines, prices and the wallet balance. Credits, prices and
   counts set in tabular numerals so columns of figures always
   line up. Radius scale: 10 fields · 12 buttons/rows · 14
   cards/tiles · 18–22 display cards · 999 pills. Shadows are one
   warm family (rgba of the #46230A ink-brown at .06/.10/.16/.25). */
*{box-sizing:border-box}
html{color:var(--ink)}
body{margin:0;font-family:'Plus Jakarta Sans',-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;color:var(--ink);background:var(--bg);line-height:1.5;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-webkit-tap-highlight-color:rgba(240,78,35,.14)}
/* Form controls do not inherit the body face in every browser —
   without this, buttons and inputs quietly render in a second,
   unchosen font. One typeface everywhere (audit, Nov 3). Weight
   and leading need the same rescue: the footer's Help button sat
   at 400/normal among 600/1.5 links until Floyd caught it
   (Nov 5, 2026). */
button,input,select,textarea{font-family:inherit}
button{font-weight:inherit;line-height:inherit}
/* V16.3.2 link-colour fix (Floyd, live report — blue words in the
   app): the v16.3 palette sweep checked hexes, but no rule ever
   coloured a bare <a>, so any anchor without a themed class (the
   in-app Help view's mailto links were the visible case) fell
   back to the browser's default link blue. The fix is the class
   of defect, not the instance: EVERY anchor now takes the unified
   action ember (--give: 5.60:1 on white, 5.12:1 on --soft,
   5.14:1 on the note tint), and hover/active deepen to --deep
   (7.31:1) with an underline. Scoped overrides keep links on the
   dark surfaces in the cream accent already verified >= 4.53:1
   on every hero stop (the wallet card keeps its own white), and
   an anchor wearing .btn keeps the button's text colour (the
   .btn.white/.ghost/.outline variants still win on specificity). */
a{color:var(--give)}
a:hover,a:active{color:var(--deep);text-decoration:underline}
.hero-deep a,.mission-vision a,.example-card a{color:#FFE3C2}
.hero-deep a:hover,.mission-vision a:hover{color:#fff}
.example-card a:hover{color:var(--deep)}
.wallet-card a{color:#fff}
a.btn,a.btn:hover,a.btn:active{color:#fff}
/* V8: the bar is position:fixed, not sticky — sticky failed in
   Floyd's in-app webview (the bar scrolled away with the page and
   the nav ended up rendered at the page's bottom area). Fixed is
   honoured in every scroll context. #topbar-spacer below reserves
   the bar's height in normal flow; app.js (syncTopbar) keeps the
   spacer — and the --topbar-h variable — equal to the bar's real
   measured height. The CSS default for both is 73px, the exact
   header-only height of the logged-out bar the page markup starts
   in (nav hidden): header padding 24 + brand block 48 + border 1.
   Logged in, the nav adds 45px (44px buttons + border) = 118px. */
.topbar{position:fixed;top:0;left:0;right:0;background:#fff;z-index:6}
#topbar-spacer{height:73px}
header{display:flex;justify-content:space-between;align-items:center;gap:12px;padding:12px 16px;border-bottom:1px solid var(--line);background:#fff}
.brand{display:flex;align-items:center;gap:10px;cursor:pointer;flex:none}
.brand-icon{width:40px;height:40px;border-radius:10px}
.brand-name{font-weight:800;font-size:20px;background:var(--grad-text);-webkit-background-clip:text;background-clip:text;color:transparent;white-space:nowrap}
.brand-tag{color:var(--deep);font-size:12px;font-weight:600;letter-spacing:.4px;white-space:nowrap}
.top-links{display:flex;align-items:center;gap:10px;font-size:14px;flex-wrap:nowrap}
.linklike{background:none;border:none;color:var(--want);font-size:15px;cursor:pointer;padding:4px}
.top-links .linklike{min-height:44px;display:inline-flex;align-items:center;padding:6px 8px;white-space:nowrap}
main{max-width:860px;margin:0 auto;padding:16px}
main:has(> #view-explore:not(.hidden)){max-width:1200px}
/* While the landing is the visible view, <main> goes full width
   so the gradient hero is truly full-bleed; the content below
   it re-centres itself in .landing-wrap. Same :has pattern as the
   Explore rule above; the moment any other view shows, the
   standard width returns. */
main:has(> #view-landing:not(.hidden)){max-width:none;padding:0 0 16px}
h1{font-size:28px;font-weight:700;margin:8px 0 10px;letter-spacing:-.01em;line-height:1.25}
h2{font-size:20px;margin:22px 0 8px;letter-spacing:-.01em;line-height:1.3}
h3{margin:14px 0 4px;font-size:16px}
.muted{color:var(--muted)} .small{font-size:13px}
.hidden{display:none!important}
.card{border:1px solid var(--line);border-radius:14px;padding:16px;background:#fff;margin:10px 0}
label{display:block;margin:10px 0;font-size:14px;font-weight:600}
input,select,textarea{width:100%;margin-top:4px;padding:10px;border:1px solid var(--line);border-radius:10px;font-size:15px;font-weight:400;background:#fff}
.btn{border:none;border-radius:12px;padding:11px 18px;font-size:15px;font-weight:700;color:#fff;cursor:pointer;white-space:nowrap}
.btn.green{background:var(--give)} .btn.blue{background:var(--want)}
.btn.ghost{background:var(--soft);color:var(--ink);border:1px solid var(--line)}
.btn.small{padding:7px 12px;font-size:13px;border-radius:9px}
.btn.danger{background:#B3261E}
/* v17: report/error actions are NOT brand actions — a plain
   neutral outline, never the brand gradient or the danger red. */
.btn.neutral{background:#fff;color:var(--ink);border:1px solid var(--line)}
.btn.google{background:#fff;color:var(--ink);border:1px solid var(--line);width:100%;display:flex;align-items:center;justify-content:center;gap:10px}
.btn.google .g-mark{width:20px;height:20px;flex:none;display:block}
.or-row{display:flex;align-items:center;gap:10px;color:var(--muted);font-size:12px;margin:12px 0 2px}
.or-row::before,.or-row::after{content:'';flex:1;border-top:1px solid var(--line)}
.btn.big{flex:1;padding:16px;font-size:18px}
/* Homepage design — the landing keeps the saturated full-bleed
   gradient hero structure (numbered GIVE/EARN/GET step cards, the
   bike example on a deep card, a gradient Join free), recoloured
   in v16.3 to the orange family of the official icon. Palette:
   hero #A84E00 -> #BC3A10 -> #B23414 -> #A8231A (the icon stops
   darkened; white text >= 5.26:1 on every stop), example card
   deep ember-brown #46200A -> #57260B, warm cream accents
   #FFE3C2 (on dark only, >= 4.53:1 on every hero stop), step
   titles in the AA ember range. */
.hero-deep{background:linear-gradient(122deg,#A84E00 0%,#BC3A10 32%,#B23414 63%,#A8231A 100%);color:#fff;text-align:center}
.hero-deep-in{max-width:880px;margin:0 auto;padding:48px 20px 52px}
.hero-chip{display:inline-block;font-weight:800;letter-spacing:2.5px;text-transform:uppercase;font-size:13px;color:#FFE3C2;border:1.5px solid rgba(255,255,255,.55);border-radius:999px;padding:6px 16px;margin:0 0 22px}
.hero-headline{font-size:clamp(40px,7vw,64px);line-height:1.1;font-weight:800;margin:0 0 16px;letter-spacing:-.015em;color:#fff;text-wrap:balance}
.hero-sub{font-size:clamp(18px,2.6vw,22px);font-weight:600;margin:0 auto 28px;max-width:620px}
.hero-actions-deep{display:flex;gap:12px;justify-content:center;flex-wrap:wrap}
.hero-actions-deep .btn{min-width:200px}
.btn.white{background:#fff;color:#9A3412;box-shadow:0 8px 22px rgba(60,25,5,.28)}
.btn.outline{background:transparent;color:#fff;border:2px solid rgba(255,255,255,.85)}
.btn.solid{background:linear-gradient(90deg,#C2410C,#A8231A);color:#fff;box-shadow:0 8px 20px rgba(168,60,10,.25)}
.fee-line{font-size:13.5px;margin:14px 0 0;color:#fff;opacity:.96}
.fee-line-light{color:var(--muted);opacity:1}
/* v16.6 (balance plan): Log in demoted to a text link under the
   hero's ONE solid action. The line sits in the cream accent
   (#FFE3C2, >= 4.53:1 on every hero stop); the link itself is
   white, underlined — the .linklike ember would fail AA on the
   gradient, and this class overrides it by source order. */
.hero-login-line{margin:16px 0 0;font-size:15px;font-weight:600;color:#FFE3C2}
.hero-login-link{color:#fff;font-size:15px;font-weight:700;text-decoration:underline;text-underline-offset:3px;min-height:44px;display:inline-flex;align-items:center;padding:6px 4px}
.hero-login-link:hover{color:#fff}
.hero-mission-deep{margin:22px 0 0;font-weight:700;font-size:15px;color:#FFE3C2}
.landing-wrap{max-width:860px;margin:0 auto;padding:0 16px}
.steps-wrap{padding:40px 0 4px}
.steps-title{font-size:clamp(27px,4vw,36px);font-weight:800;margin:0 0 6px;color:#3D2314;text-align:center;letter-spacing:-.01em;text-wrap:balance}
.steps-lede{text-align:center;color:var(--muted);font-size:19px;font-weight:500;margin:0 auto 24px;max-width:560px}
.step-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}
.step{border:1px solid var(--line);border-radius:18px;padding:24px 20px;background:#fff;box-shadow:0 4px 14px rgba(70,35,10,.06)}
.step-num{width:52px;height:52px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:24px;font-weight:800;color:#fff;margin-bottom:14px}
.step-1 .step-num{background:linear-gradient(135deg,#C2410C,#9E4A00)}
.step-2 .step-num{background:linear-gradient(135deg,#C33C14,#A83A0A)}
.step-3 .step-num{background:linear-gradient(135deg,#B02A1B,#8F2B12)}
.step h3{font-size:25px;font-weight:800;margin:0 0 6px;letter-spacing:.5px}
.step-1 h3{color:#B23A08}.step-2 h3{color:#A83A0A}.step-3 h3{color:#9E2B1E}
.step p{margin:0;font-size:16.5px}
@media (max-width:700px){.step-grid{grid-template-columns:1fr}}
/* v16.5: homepage cartoon block — the example card's radius and
   warm shadow language; the play badge is the unified ember with
   a white triangle, deepening on hover/focus like every action. */
.video-block{position:relative;max-width:720px;margin:0 auto 26px;border-radius:20px;overflow:hidden;background:#2B1912;box-shadow:0 12px 30px rgba(70,35,10,.16)}
.video-block video{display:block;width:100%;aspect-ratio:16/9}
.video-play{position:absolute;inset:0;width:100%;height:100%;background:none;border:none;padding:0;cursor:pointer;display:flex;align-items:center;justify-content:center}
.video-play-badge{width:78px;height:78px;border-radius:50%;background:var(--give);display:flex;align-items:center;justify-content:center;box-shadow:0 10px 24px rgba(50,25,10,.35);transition:transform .15s ease,background .15s ease}
.video-play-tri{width:0;height:0;margin-left:6px;border-left:27px solid #fff;border-top:17px solid transparent;border-bottom:17px solid transparent}
.video-play:hover .video-play-badge,.video-play:focus-visible .video-play-badge{background:var(--deep);transform:scale(1.05)}
/* v18.8.5: the four-video homepage tour (Floyd's order, Nov 4) —
   all four how-to videos live on the homepage in one numbered
   row of open players (posters only until Play). Help carries a
   single video ("If something goes wrong") and each app view
   carries its own.
   v18.8.6 (geometry correction): the four masters are PORTRAIT
   9:16, so ≥900px keeps the one row of four, while <900px the
   tour becomes a horizontal snap carousel (one row, next tile
   peeking) instead of the 2×2 grid / stacked wall. The singles
   are sized by height — see the .guide component below. */
.tour-wrap{padding:40px 0 4px}
.tour-title{font-size:clamp(24px,3.4vw,30px);font-weight:800;margin:0 0 6px;color:#3D2314;text-align:center;letter-spacing:-.01em;text-wrap:balance}
.tour-sub{text-align:center;color:var(--muted);font-size:16.5px;margin:0 auto 24px}
.tour-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:16px}
.tour-video{background:#fff;border:1px solid var(--line);border-radius:18px;padding:16px 8px;box-shadow:0 4px 14px rgba(70,35,10,.06);display:flex;flex-direction:column;align-items:center;text-align:center;min-width:0}
.tour-chip{width:40px;height:40px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:19px;font-weight:800;color:#fff;margin-bottom:12px;flex:none}
.tour-video:nth-child(1) .tour-chip{background:linear-gradient(135deg,#C2410C,#9E4A00)}
.tour-video:nth-child(2) .tour-chip{background:linear-gradient(135deg,#C33C14,#A83A0A)}
.tour-video:nth-child(3) .tour-chip{background:linear-gradient(135deg,#B02A1B,#8F2B12)}
.tour-video:nth-child(4) .tour-chip{background:linear-gradient(135deg,#9E2B1E,#7E1F0E)}
.tour-video .qa-video{margin:0 0 12px}
.tour-frame{position:relative;width:100%}
.tour-video-title{font-size:14px;font-weight:700;line-height:1.3;margin:0 0 4px}
.tour-video-cap{font-size:13.5px;color:var(--muted);margin:0}
@media (max-width:899px){
  .tour-grid{display:flex;overflow-x:auto;scroll-snap-type:x mandatory;scroll-padding-inline:16px;gap:12px;padding:4px 2px 12px}
  .tour-video{flex:0 0 min(74vw,300px);scroll-snap-align:start}
}
.example-card{margin:28px 0 6px;background:var(--soft);border:1px solid var(--line);border-radius:20px;padding:30px 28px;color:var(--ink);text-align:center}
.example-kicker{font-size:13px;font-weight:800;letter-spacing:2px;text-transform:uppercase;color:var(--muted);margin:0 0 10px}
.example-big{font-size:clamp(21px,3.4vw,27px);font-weight:700;line-height:1.45;margin:0}
.credits-hl{color:var(--give);font-weight:800}
/* v16.5: the skills block — a light warm panel in the step-card
   language (soft tint, hairline, 22px radius) so the gradient
   Mission & Vision panel after it keeps its weight. The closing
   line takes the .trustline emphasis treatment in deep ember. */
.skills-block{margin:40px 0 4px;background:var(--soft);border:1px solid var(--line);border-radius:22px;padding:34px 28px;text-align:center}
.skills-title{font-size:clamp(27px,4vw,36px);font-weight:800;margin:0 0 14px;color:#3D2314;letter-spacing:-.01em;text-wrap:balance}
.skills-text{font-size:17px;line-height:1.65;max-width:640px;margin:0 auto}
.skills-close{margin:20px 0 0;font-size:clamp(18px,2.8vw,21px);font-weight:800;color:var(--deep);line-height:1.5}
@media (max-width:700px){.skills-block{padding:28px 20px}}
.mission-vision{margin:28px 0 24px;padding:34px 28px;border-radius:22px;background:linear-gradient(130deg,#A84E00 0%,#BC3A10 38%,#B23414 70%,#A8231A 100%);color:#fff;box-shadow:0 12px 30px rgba(70,35,10,.16)}
.mission-vision-title{font-size:clamp(27px,4vw,36px);font-weight:800;line-height:1.15;margin:0 0 22px;color:#fff;text-align:center;letter-spacing:-.01em;text-wrap:balance}
.mission-vision-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:16px}
.mission-vision-card{background:rgba(59,24,6,.42);border:1px solid rgba(255,255,255,.38);border-radius:18px;padding:24px}
.mission-vision-label{font-size:13px;font-weight:800;letter-spacing:2px;text-transform:uppercase;color:#FFE3C2;margin:0 0 10px}
.mission-vision-text{font-size:17px;line-height:1.6;margin:0}
@media (max-width:700px){.mission-vision{padding:28px 20px}.mission-vision-grid{grid-template-columns:1fr}}
.trustline{text-align:center;font-size:clamp(18px,2.8vw,21px);font-weight:700;color:#3D2314;max-width:640px;margin:32px auto 20px;line-height:1.5}
/* v18.9 (photo-fee release): the homepage fee line — the same
   centred trust register as .trustline, one step quieter:
   smaller, muted, no emphasis. It informs; it never sells. */
.fee-note-line{text-align:center;font-size:15.5px;font-weight:600;color:var(--muted);max-width:640px;margin:0 auto 24px;line-height:1.55}
.cta-row{text-align:center;padding-bottom:6px}
.cta-row .btn{min-width:220px}
/* v16.6 (balance plan): the closing band — the page's bookend.
   A hairline, the mission line in the steps-title register, one
   solid Join free, and a quiet Explore text link. It is the only
   place after the hero where a solid action appears on the
   landing (the guardrail: one primary per view, bookended). */
.closing-band{margin:40px auto 8px;padding:36px 20px 10px;border-top:1px solid var(--line);text-align:center}
.closing-line{font-size:clamp(22px,3.4vw,30px);font-weight:800;color:#3D2314;margin:0 0 18px;letter-spacing:-.01em}
.closing-band .btn{min-width:220px}
.closing-explore{margin:12px 0 0}
.closing-link{color:var(--give);font-size:15px;font-weight:600;min-height:44px;display:inline-flex;align-items:center;padding:10px 12px}
.closing-link:hover{color:var(--deep);text-decoration:underline}
.back-row{margin:0 0 4px}
.tabs{display:flex;gap:8px;margin-bottom:8px}
.tab{flex:1;padding:9px;border-radius:9px;border:1px solid var(--line);background:var(--soft);cursor:pointer;font-weight:600;white-space:nowrap}
.tab.active{background:var(--deep);color:#fff;border-color:var(--deep)}
.note{border-radius:10px;padding:10px 12px;background:#FDE8DC;border:1px solid #F2C4B0;font-size:14px;white-space:pre-line;position:relative}
/* v18.31 clean-up controls: the notice dismiss × sits at the
   card's top-right (routine notices only — protected ones
   carry the .note-tag instead), and the conversation item
   wrapper holds the row + its Archive action. */
.note-x{position:absolute;top:2px;right:4px;width:32px;height:32px;border:0;background:transparent;color:var(--muted);font-size:19px;line-height:1;cursor:pointer;border-radius:8px}
.note-x:hover{color:var(--ink)}
.note:has(.note-x),.note:has(.note-tag){padding-right:38px}
.note-tag{margin-left:8px;vertical-align:1px}
.conv-item{margin:8px 0}
.conv-item .conv-row{margin:0}
.conv-actions{text-align:right;margin-top:2px}
/* v18.31: the push on/off switch (Profile notifications card).
   A real checkbox under a pill track — state is the checkbox's
   own state, never a label that can drift from the truth. */
.push-row{display:flex;align-items:center;justify-content:space-between;gap:12px}
.push-label{font-weight:600;font-size:15px}
.switch{position:relative;display:inline-block;width:52px;height:30px;flex:none}
.switch input{position:absolute;opacity:0;width:0;height:0}
.switch-ui{position:absolute;inset:0;border-radius:999px;background:#D8C3B4;cursor:pointer;transition:background-color .15s ease}
.switch-ui:before{content:"";position:absolute;width:24px;height:24px;border-radius:50%;background:#fff;top:3px;left:3px;box-shadow:0 1px 3px rgba(0,0,0,.25);transition:transform .15s ease}
.switch input:checked + .switch-ui{background:var(--deep)}
.switch input:checked + .switch-ui:before{transform:translateX(22px)}
.switch input:disabled + .switch-ui{opacity:.55;cursor:not-allowed}
.switch input:focus-visible + .switch-ui{outline:2px solid var(--deep);outline-offset:2px}
/* v14.5: the unverified-member banner sits at the top of <main> in
   every logged-in view; the CASL consent checkbox must not inherit
   the full-width text-input rule; the Turnstile slot reserves its
   space only when a widget is actually rendered into it. */
.verify-banner{margin:4px 0 10px}
.check-label{display:flex;gap:8px;align-items:flex-start;font-weight:400;margin:12px 0}
.check-label input[type="checkbox"]{width:auto;margin:3px 0 0;flex:none}
.turnstile-slot{margin:10px 0}
.turnstile-slot:empty{margin:0}
/* v18 (posting safety): the Give/edit rules box — the short
   never-list in plain words plus the one confirmation checkbox
   that enables the Post/Save button; the chosen reason in the
   listing-report sheet; the credits line in the chat view. */
.rules-box{border:1px solid var(--line);background:var(--soft);border-radius:10px;padding:10px 12px;margin:14px 0 12px}
.rules-box p{margin:0}
.rules-box .check-label{margin:8px 0 0}
#sheet [data-reason].selected,#sheet [data-cat].selected,#sheet [data-reqkind].selected{background:var(--deep);color:#fff;border-color:var(--deep)}
.thread-note{margin:2px 0 10px}
.search-row{display:flex;flex-direction:column;gap:8px}
/* v16.6 (balance plan): the guest bar — one slim soft-tint strip
   at the top of Explore for signed-out visitors, with a text
   link, never a solid button (Explore's only action weight stays
   with search + the listing tiles). */
.guest-bar{display:flex;align-items:center;gap:4px;background:var(--soft);border:1px solid var(--line);border-radius:10px;padding:6px 12px;font-size:14px;margin-bottom:10px}
.guest-bar .linklike{color:var(--give);font-weight:700;min-height:44px;display:inline-flex;align-items:center;padding:6px 4px}
#view-explore .search-row{position:sticky;top:var(--topbar-h,118px);background:#fff;z-index:4;padding:10px 0 8px}
.chips{display:flex;gap:8px}
.chip{border:1px solid var(--line);background:#fff;border-radius:999px;padding:8px 16px;cursor:pointer;font-size:14px;display:inline-flex;align-items:center;min-height:44px;white-space:nowrap}
.chip.active{background:var(--deep);color:#fff;border-color:var(--deep)}
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:14px;margin-top:14px}
.tile{border:1px solid var(--line);border-radius:14px;overflow:hidden;cursor:pointer;background:#fff}
.tile-img{aspect-ratio:4/3;background:var(--soft);display:flex;align-items:center;justify-content:center;overflow:hidden}
.tile-img img{width:100%;height:100%;object-fit:cover}
.tile-img.noimg{flex-direction:column;gap:2px;color:var(--give)}
.tile-img.noimg .ph-letter{font-size:30px;font-weight:700;line-height:1.1}
.tile-img.noimg .ph-cat{font-size:12px;font-weight:600;letter-spacing:.6px;text-transform:uppercase;color:var(--muted)}
.tile-body{padding:12px}
.tile-title{font-weight:700;margin-bottom:2px;letter-spacing:-.01em}
.tile-meta{font-size:13px;color:var(--muted)}
.tile-trust{font-size:13px;color:var(--deep);margin-top:2px}
.trust-line{margin:6px 0}
.price{font-weight:800;color:var(--deep);font-size:16px}
/* Figures line up in columns (v16.4): credits, prices, counts and
   the exchange log never jitter as digits change width. */
.price,.wallet-balance,.count-badge,table.log,.tile-trust,.fee-line{font-variant-numeric:tabular-nums}
.row{border:1px solid var(--line);border-radius:12px;padding:12px;margin:8px 0;background:#fff}
.row.clickable{cursor:pointer}
.row-head{display:flex;justify-content:space-between;gap:10px;align-items:baseline}
.row-actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}
/* v18.18: End membership sits in its own zone, below a divider. */
.owner-end-zone{border-top:1px solid var(--line);margin-top:14px;padding-top:12px}
.badge{display:inline-block;font-size:12px;font-weight:700;padding:2px 8px;border-radius:999px;background:var(--soft);color:var(--deep)}
.badge.warn{background:#FFF4E0;color:#8A5A00}
.badge.bad{background:#FDECEA;color:#B3261E}
.wallet-card{border-radius:16px;padding:20px;color:#fff;background:linear-gradient(120deg,var(--flame),var(--ember),var(--rust))}
.wallet-balance{font-size:34px;font-weight:800}
.wallet-sub{opacity:.92;font-size:14px;margin-top:4px;white-space:pre-line}
.msg{border-top:1px solid var(--line);padding:8px 0;font-size:14px}
.msg b{color:var(--deep)}
footer{text-align:center;color:var(--deep);font-weight:600;padding:18px 10px 8px}
footer a{color:var(--want);text-decoration:none}
footer a:hover{text-decoration:underline}
footer .legal-links{font-size:14px;margin-top:2px}
footer .legal-links a{display:inline-block;padding:13px 8px;min-height:44px;white-space:nowrap}
/* v18.17: each footer separator rides in a nowrap unit with the
   link AFTER it, so a wrap can never strand a "·" at a line end. */
.fl-u{white-space:nowrap}
.trust-strip{display:flex;flex-wrap:wrap;gap:10px 22px;justify-content:center;border-top:1px solid var(--line);border-bottom:1px solid var(--line);padding:12px 8px;margin:16px 0 8px;font-size:14px;font-weight:600;color:var(--deep)}
.proof-line{text-align:center;font-weight:700;color:var(--deep);margin:6px 0 2px}
.empty-state{margin-top:14px}
:focus-visible{outline:3px solid var(--want);outline-offset:2px;border-radius:4px}
/* v16.6 (balance plan): the five destinations in #bottom-nav are
   the whole signed-in map, at both widths — desktop shows them
   in the bar's middle cell; on mobile the bar never renders and
   the 5-tab bar is the only navigation. (The v10–v16.5 dropdown
   panel and its account rows are gone: Saved and Log out live in
   the Profile now.) */
#bottom-nav{display:flex;background:#fff;border-bottom:1px solid var(--line)}
#bottom-nav button{flex:1;background:none;border:none;padding:13px 2px;min-height:44px;font-size:13px;font-weight:600;color:var(--muted);cursor:pointer;white-space:nowrap}
#bottom-nav button.active{color:var(--deep)}
/* V10: at >=900px the fixed bar becomes ONE row — brand left, nav
   centred, account actions right — instead of header stacked over
   nav (118px tall logged in). Under 900px the bar is one row too
   (header only — see the max-width:899px block below). The
   <header> becomes display:contents so its two children (.brand,
   .top-links) join the bar's grid directly, and the bar takes
   over the header's padding and bottom hairline. syncTopbar()
   measures the bar's offsetHeight, so the spacer and --topbar-h
   follow automatically. Logged out, the middle grid cell simply
   sits empty (v16.6 removed the landing anchor links that used
   to fill it): the bar reads brand + three text actions. */
@media (min-width:900px){
  .topbar{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:16px;padding:12px 16px;border-bottom:1px solid var(--line)}
  .topbar header{display:contents}
  .topbar .brand{grid-column:1;grid-row:1;justify-self:start}
  .topbar .top-links{grid-column:3;grid-row:1;justify-self:end}
  /* grid-row:1 is load-bearing: the nav comes after .top-links
     in DOM order, and grid auto-placement would push it to row 2
     (the V10 QA caught exactly that). */
  #bottom-nav{grid-column:2;grid-row:1;justify-self:center;border-bottom:none}
  #bottom-nav button{flex:none;padding:13px 14px}
}
/* V10 (Floyd's one-bar rule) — v16.6 form: under 900px the bar is
   ONE row (logo left, actions right) and there is NO second nav
   system in it: #bottom-nav never renders here (display:none
   beats even the removal of .hidden at login — the 5-tab bar at
   the bottom of the screen is the only signed-in navigation, and
   Saved + Log out live in the Profile). The v10–v16.5 ☰ dropdown
   panel is removed outright: no absolute panel, no menu-open
   state, no account rows. */
@media (max-width:899px){
  /* One row has to fit ~358px: the brand keeps its icon + name
     (the tagline lives in the hero), the "Hi, name" greeting goes
     (Log out already says you're in), and the gaps/padding slim
     down. Measured result: a ~73px bar at 360–390px. */
  .brand{flex:none}
  .brand-tag{display:none}
  #whoami{display:none}
  header{gap:8px}
  .top-links{gap:6px}
  .top-links .linklike{padding:6px 5px}
  #bottom-nav{display:none}
  /* While logged in — app.js unhides #nav-logout then — the
     header's own Log out control leaves the bar, so the narrow
     bar keeps only its quiet links; Log out's home is the
     Profile (v16.6; it was the dropdown panel's row before).
     The :has keys on the same .hidden class app.js toggles, so
     the rule follows login state with no extra wiring; logged
     out it fails and Log in / Join free stay in the bar as the
     entry points. */
  .topbar:has(#nav-logout:not(.hidden)) #nav-logout{display:none}
}
/* v16.6 NO-WRAP band (Floyd's phone catch, Nov 3: on his phone,
   in an in-app browser, the header's "Log in" and "Join free"
   wrapped onto two lines — "Log / in", "Join / free"). The law
   from here on: every header item and every button label stays
   on ONE line at every width (white-space:nowrap rides the base
   rules above). At <=480px the brand drops to icon-only — the
   standard professional pattern, Floyd pre-approved — and the
   link padding/gaps tighten one step, so the widest guest
   header (auth view: brand + Explore · Help · Log in ·
   Join free) fits 320px with room to spare. Measured, not
   eyeballed: ~/workspace/qa/trocaly-v16.6/headers.mjs asserts
   scrollWidth <= clientWidth per element at 320–430px. The
   icon stays 40px — the brand tap target does not shrink. */
@media (max-width:480px){
  .brand-name,.brand-tag{display:none}
  header{padding:12px;gap:8px}
  .top-links{gap:4px}
  .top-links .linklike{padding:6px 4px}
}
/* Signed-in desktop guard band: at 900–1080px the five-item nav,
   a long "Hi, name" greeting and the account links together can
   crowd the one-row bar; the nav's side padding tightens one
   step there so nothing wraps or clips (nowrap is already law). */
@media (min-width:900px) and (max-width:1080px){
  #bottom-nav button{padding:13px 9px}
  .top-links{gap:6px}
}
#whoami{white-space:nowrap}
/* Anchor targets must land below the fixed bar, not behind it. */
#how-it-works,#what-can-be-exchanged,#mission-vision,#fees{scroll-margin-top:calc(var(--topbar-h,73px) + 16px)}
#toast{position:fixed;left:50%;transform:translateX(-50%);bottom:24px;background:var(--ink);color:#fff;padding:11px 16px;border-radius:10px;font-size:14px;z-index:20;max-width:88vw;text-align:center}
#sheet{position:fixed;inset:0;background:rgba(50,25,10,.45);z-index:15;display:flex;align-items:flex-end;justify-content:center}
.sheet-card{background:#fff;width:100%;max-width:640px;max-height:88vh;overflow:auto;border-radius:18px 18px 0 0;padding:18px}
.sheet-img{aspect-ratio:16/9;border-radius:12px;background:var(--soft);display:flex;align-items:center;justify-content:center;overflow:hidden}
.sheet-img.noimg{flex-direction:column;gap:2px;color:var(--give)}
.sheet-img.noimg .ph-letter{font-size:40px;font-weight:700;line-height:1.1}
.sheet-img.noimg .ph-cat{font-size:12px;font-weight:600;letter-spacing:.6px;text-transform:uppercase;color:var(--muted)}
.sheet-img img{width:100%;height:100%;object-fit:cover}
.inline{display:flex;gap:8px} .inline input{flex:1}
/* Listing photos: the file inputs are never painted — display:none
   is the only reliable hide. (V7 used a 1px/opacity rule; iOS still
   painted the native "Choose File / no file selected" control at
   the page bottom — Floyd's screenshot, V8.) Activation does not
   need the input visible: the Give form's control is a <label
   for>, and the listings' Add/Change photo buttons call .click()
   from inside real tap handlers — both fire a display:none input
   in every modern browser, proven by the V8 device-matrix smoke
   (~/workspace/qa/trocaly-v8-matrix.mjs), which instruments click
   listeners on both inputs and clicks the styled controls. */
.file-hidden{display:none}
.photo-field{margin:2px 0 4px}
.photo-add{display:flex;align-items:center;gap:14px;margin:0;border:2px dashed var(--line);border-radius:14px;padding:14px;background:var(--soft);color:var(--deep);font-size:16px;cursor:pointer;min-height:44px}
.photo-add img{width:64px;height:64px;border-radius:10px;object-fit:cover;flex:none}
.photo-add:active{background:#FBE7D7}
/* v18.9: the Give form's chosen-photo previews (up to 10). */
.photo-thumbs{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}
.photo-thumbs img{width:64px;height:64px;border-radius:10px;object-fit:cover;border:1px solid var(--line)}
/* v18.9: the listing-sheet gallery — arrows ride the photo's
   edges (44px targets), thumbs below mark the current one. */
.gal-wrap{position:relative}
.gal-arrow{position:absolute;top:50%;transform:translateY(-50%);width:44px;height:44px;border-radius:50%;border:1px solid var(--line);background:rgba(255,255,255,.94);color:var(--ink);font-size:24px;line-height:1;display:flex;align-items:center;justify-content:center;cursor:pointer;padding:0}
.gal-prev{left:10px}
.gal-next{right:10px}
.gal-thumbs{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}
.gal-thumb{padding:0;border:2px solid transparent;border-radius:10px;background:none;cursor:pointer;line-height:0}
.gal-thumb img{width:56px;height:56px;object-fit:cover;border-radius:8px}
.gal-thumb.active{border-color:var(--give)}
/* v18.11: the full-photo viewer — tapping a listing photo or a
   message photo opens it whole: contain fit, never cropped, on a
   dark full-screen backdrop. Arrows/swipe move between photos. */
#gal-main{cursor:zoom-in}
.msg-img{cursor:zoom-in}
.pv{position:fixed;inset:0;background:rgba(20,10,5,.95);z-index:30;display:flex;align-items:center;justify-content:center}
.pv.hidden{display:none}
.pv img{max-width:100%;max-height:100%;object-fit:contain}
.pv-btn{position:absolute;width:44px;height:44px;border-radius:50%;border:1px solid rgba(255,255,255,.35);background:rgba(0,0,0,.45);color:#fff;font-size:22px;line-height:1;display:flex;align-items:center;justify-content:center;cursor:pointer;padding:0}
.pv-close{top:14px;right:14px;font-size:17px}
.pv-prev{left:10px;top:50%;transform:translateY(-50%)}
.pv-next{right:10px;top:50%;transform:translateY(-50%)}
.pv-count{position:absolute;bottom:16px;left:50%;transform:translateX(-50%);color:#fff;background:rgba(0,0,0,.45);border:1px solid rgba(255,255,255,.35);border-radius:999px;padding:3px 12px;font-size:13px;font-weight:600}
/* v18.9: the photo manager sheet (Your listings -> Photos). */
.pm-grid{display:flex;flex-wrap:wrap;gap:12px;margin:6px 0 4px}
.pm-item{width:104px}
.pm-item img{width:104px;height:78px;object-fit:cover;border-radius:10px;border:1px solid var(--line);display:block}
.pm-tag{font-size:12px;font-weight:700;color:var(--deep);margin:4px 0 2px}
.pm-actions{display:flex;flex-direction:column;gap:6px;align-items:flex-start}
table.log{width:100%;border-collapse:collapse;font-size:13px}
table.log td,table.log th{border-bottom:1px solid var(--line);padding:6px 4px;text-align:left;vertical-align:top}
/* v14 (§G): avatars — the member's photo, or their initial on the
   brand gradient (the bright flame->rust stops live here and on
   the wallet card; .avatar-initial is a graphic, not text on white).
   Circles at three sizes: sm rides inline in trust lines and rows,
   the default sits in member lines, lg heads the profile. */
.avatar{width:36px;height:36px;border-radius:50%;object-fit:cover;vertical-align:middle;flex:none}
.avatar-sm{width:22px;height:22px;font-size:12px}
.avatar-lg{width:84px;height:84px;font-size:34px}
.avatar-initial{display:inline-flex;align-items:center;justify-content:center;background:linear-gradient(120deg,var(--flame),var(--ember),var(--rust));color:#fff;font-weight:700}
.tile-trust{display:flex;align-items:center;gap:6px}
.member-line{display:flex;align-items:center;gap:10px;margin:10px 0}
.member-line .linklike{padding:0;font-size:14px}
.profile-head{display:flex;gap:16px;align-items:flex-start}
.profile-head .avatar-lg{flex:none}

/* v15 — chat, favourites, in-app sheets.
   The unread count rides the Messages nav item in the same pill
   language as .badge; the heart is a real 44px button (top-right
   of the tile, clear of the tile's own tap); chat bubbles split
   mine/theirs by alignment + the brand action ember; and the
   sheet dialogs reuse #sheet's card with full-width actions, so
   every former native dialog looks like the rest of the app. */
.count-badge{display:inline-block;min-width:20px;text-align:center;font-size:11px;font-weight:700;line-height:1;padding:3px 6px;border-radius:999px;background:#B3261E;color:#fff;vertical-align:2px}
.tile{position:relative}
.fav-btn{position:absolute;top:8px;right:8px;width:44px;height:44px;border-radius:50%;border:1px solid var(--line);background:rgba(255,255,255,.96);color:var(--muted);font-size:19px;line-height:1;display:flex;align-items:center;justify-content:center;cursor:pointer;z-index:2;padding:0}
.fav-btn::before{content:'♡'}
.fav-btn.active{background:var(--give);border-color:var(--give);color:#fff}
.fav-btn.active::before{content:'♥'}
.fav-btn:active{transform:scale(.94)}
.sheet-title-row{display:flex;align-items:flex-start;gap:10px}
.sheet-title-row h2{flex:1;margin-top:2px}
.fav-btn.sheet-fav{position:static;flex:none}
.conv-row{display:flex;gap:12px;align-items:flex-start;width:100%;text-align:left;background:#fff;border:1px solid var(--line);border-radius:12px;padding:12px;margin:8px 0;cursor:pointer;font-size:15px;color:var(--ink)}
.conv-row .conv-main{flex:1;min-width:0}
.conv-row .conv-top{display:flex;justify-content:space-between;gap:10px;align-items:baseline}
.conv-row .conv-preview{display:block;color:var(--muted);font-size:13.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:2px}
.conv-row .conv-listing{display:block;font-size:13px;color:var(--deep);font-weight:600}
.conv-row time{font-size:12px;color:var(--muted);flex:none}
.conv-row .count-badge{flex:none;margin-top:2px}
.thread-head .th-top{display:flex;gap:12px;align-items:center}
.thread-head .th-main{flex:1;min-width:0;overflow-wrap:anywhere}
.thread-head .th-actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px}
.thread-head .th-actions .btn{min-height:40px}
.thread-msgs{display:flex;flex-direction:column;gap:8px;margin:14px 0}
.bubble{max-width:78%;padding:9px 12px;border-radius:14px;font-size:15px;overflow-wrap:anywhere}
.bubble.mine{align-self:flex-end;background:var(--want);color:#fff;border-bottom-right-radius:4px}
.bubble.theirs{align-self:flex-start;background:var(--soft);border:1px solid var(--line);border-bottom-left-radius:4px}
.bubble .b-time{display:block;font-size:11px;opacity:.75;margin-top:3px}
/* v18.32 support chat: the disclosure card sits before the first
   message; the crisis line is a real visible card (in the support
   view and wherever a crisis card renders in a thread); system
   notes centre quietly; support-side bubbles carry a small
   "Trocaly Support" label so no message ever looks like it came
   from a named person. */
.support-head{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap}
.support-head h1{margin:0}
.support-disclosure{border:1px solid var(--line);background:var(--soft);border-radius:10px;padding:9px 12px;margin:12px 0 8px}
#view-support .crisis-line,.support-crisis{border:1px solid #F0B8AC;background:#FDECEA;color:#8A2A1E;border-radius:10px;padding:9px 12px;font-weight:600;margin:8px 0}
.support-system{text-align:center;color:var(--muted);font-size:13px;margin:6px auto;max-width:92%}
.support-who{display:block;font-size:11px;font-weight:700;opacity:.75;margin-bottom:2px}
.support-deflect-item{padding:8px 0;border-top:1px solid var(--line)}
.support-deflect-item:first-child{border-top:0;padding-top:2px}
.support-card{margin-bottom:14px}
/* Help card email option (Nov 6): chat stays the one solid
   primary button; email is a quiet secondary target — full
   address visible (copyable), at least 44px tall. */
.support-email{display:inline-flex;align-items:center;min-height:44px;margin-top:10px;padding:10px 14px;border:1px solid var(--line);border-radius:12px;background:var(--soft);color:var(--ink);font:inherit;font-weight:700;font-size:15px;text-decoration:none;cursor:pointer}
.thread-input{position:sticky;bottom:10px;background:#fff;padding:6px 0}
.thread-input input{margin-top:0}
.thread-input .btn{min-height:44px;flex:none}
.sheet-actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:16px}
.sheet-actions .btn{flex:1 1 132px;min-height:44px}
.sheet-card textarea{resize:vertical}
.sheet-note{margin-top:10px}

/* ---------- v16: bottom tab bar, Explore filters, feedback, notices ---------- */
#tabbar{display:none}
#tabbar button{flex:1;background:none;border:none;min-height:56px;padding:8px 2px;font-size:12px;font-weight:600;color:var(--muted);cursor:pointer;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;white-space:nowrap}
#tabbar button.active{color:var(--deep);background:var(--soft)}
#tabbar .count-badge{margin:0}
@media (max-width:899px){
  /* The bar exists only for a signed-in member (body.in-app is
     set at boot, removed at logout): fixed to the bottom, always
     visible with labels, clear of the home indicator. Content
     gets matching bottom room on <main> (never on body — the
     topbar spacer math up top must stay undisturbed). */
  body.in-app #tabbar{display:flex;position:fixed;left:0;right:0;bottom:0;z-index:7;background:#fff;border-top:1px solid var(--line);padding-bottom:env(safe-area-inset-bottom)}
  body.in-app main{padding-bottom:84px}
  /* iPhone homepage scroll fix (Nov 6): the landing rule
     (main:has(> #view-landing…), specificity 1,1,1) defeats the
     84px above (0,1,2) with its padding:0 0 16px shorthand, so
     the landing's last link sat partly behind the tab bar.
     This scoped rule (1,1,2) restores the full clearance on
     the landing only, plus the home-indicator inset. */
  body.in-app main:has(> #view-landing:not(.hidden)){padding-bottom:calc(84px + env(safe-area-inset-bottom))}
  body.in-app #toast{bottom:92px}
  body.in-app .thread-input{bottom:80px}
}
.filter-row{display:flex;flex-wrap:wrap;gap:8px;align-items:center;justify-content:space-between}
.cat-chips{flex:1 1 240px;flex-wrap:nowrap;overflow-x:auto;padding-bottom:2px;scrollbar-width:none}
.cat-chips::-webkit-scrollbar{display:none}
.cat-chips .chip{flex:none;min-height:38px;padding:6px 12px;font-size:13px}
.sort-label{display:inline-flex;align-items:center;gap:6px;font-size:13px;color:var(--muted);font-weight:600}
.sort-label select{min-height:38px;border:1px solid var(--line);border-radius:8px;background:#fff;font-size:13px;padding:4px 6px;color:var(--ink)}
.feedback-row{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-top:10px;font-size:14px;font-weight:600}.note.unseen{border-color:var(--ember);box-shadow:inset 3px 0 0 var(--ember)}
/* v18.28 profile group: ONE card of full-width rows at the
   bottom of your own Profile — Notices (collapsible), Saved
   listings, Help, Log out, Delete my account. Hairline
   dividers between rows instead of separate cards, so the
   whole section reads as one tidy list. Dividers are
   border-TOPs (every row but the first), so a hidden row
   (Delete, when deletion is not open) never leaves a stray
   line behind. */
.profile-group{padding:0;overflow:hidden}
.pg-row{display:flex;align-items:center;gap:8px;width:100%;min-height:52px;padding:12px 16px;background:#fff;border:0;border-top:1px solid var(--line);font-size:16px;font-weight:700;color:var(--ink);cursor:pointer;text-align:left}
.pg-row:first-child{border-top:0}
.pg-row:active{background:var(--soft)}
.pg-row-label{flex:1}
.pg-row .badge{flex:none}
.pg-chev{flex:none;color:var(--muted);font-size:13px;transition:transform .15s ease}
.pg-row.open .pg-chev{transform:rotate(180deg)}
.pg-danger{color:#B3261E}
#profile-notices-area{padding:12px 16px;border-top:1px solid var(--line)}
.start-line{color:var(--deep)}
.trust-strip span::before{content:"\2713  ";color:var(--give);font-weight:800}
/* v16.6: the footer's Help button (a <button>, unlike its <a>
   siblings) gets the SAME 44px touch box the anchors have had
   since v16 — the unified footer row is one row at one height. */
.foot-link{font-size:inherit;display:inline-flex;align-items:center;min-height:44px;padding:13px 8px}

/* ---------- v16.4 polish pass ----------
   BROWSER-CHROME STATES. The v16.4 computed-colour audit scanned
   every visible element on 30 surfaces and found the palette
   itself clean — the remaining browser defaults live where an
   element scan cannot see: the states the UA paints for itself.
   Each one is tokenized to the theme here.
   - Text selection: Chrome/Safari paint their own blue highlight
     when no ::selection rule exists. Now a warm amber tint with
     ink text (readable on white and on the dark surfaces alike).
   - Placeholder: the UA's neutral grey becomes a warm taupe
     derived from --muted (#9A7B5F, ~3.9:1 — deliberately
     secondary, like all placeholder text). v18.17 (panel fix
     batch): darkened to #8D7057 (4.58:1 measured) — the examples
     inside fields carry real guidance (the credits example
     teaches the pricing model), so they now clear the 4.5:1
     floor for text.
   - Caret + checkbox/radio accent: the ember, not UA blue.
   - Autofill: Chrome's pale yellow-blue wash is replaced with
     the field's own white, ink text, ember caret.
   - Focus in fields: border deepens to the ember and a soft
     ember halo appears (the :focus-visible outline below stays
     for links/buttons; fields trade it for the halo so the two
     never stack).
   - Scrollbars: a thin warm thumb everywhere (Firefox via
     scrollbar-color, WebKit via the pseudo-elements); the
     category-chip rail keeps its hidden bar.
   - Disabled buttons finally LOOK disabled (before v16.4 a
     disabled .btn computed opacity 1 / cursor pointer —
     indistinguishable from a live one). */
::selection{background:#FAD9AE;color:var(--ink)}
::placeholder{color:#8D7057;opacity:1}
input,select,textarea{caret-color:var(--give)}
input[type="checkbox"],input[type="radio"]{accent-color:var(--give)}
input:-webkit-autofill{-webkit-text-fill-color:var(--ink);-webkit-box-shadow:0 0 0 100px #fff inset;caret-color:var(--give)}
input:focus,select:focus,textarea:focus{border-color:var(--give)}
input:focus-visible,select:focus-visible,textarea:focus-visible{outline:none;box-shadow:0 0 0 3px rgba(188,58,16,.16)}
html{scrollbar-color:#E3C3AB transparent;scrollbar-width:thin}
::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-thumb{background:#E3C3AB;border-radius:8px;border:2px solid #fff}
::-webkit-scrollbar-track{background:transparent}
.btn:disabled{opacity:.55;cursor:not-allowed}
button:disabled{cursor:not-allowed}

/* MOTION + MICRO-INTERACTIONS. Everything here is a 120–180ms
   ease on colour/transform only — feedback, never decoration —
   and the whole system collapses to instant under
   prefers-reduced-motion. Anchor jumps glide (the scroll-margin
   rules above keep targets clear of the fixed bar); the sheet
   rises 12px as it opens; listing tiles lift 2px under a real
   pointer. The toast gains the same warm shadow as the sheets
   so floating surfaces share one depth language. */
@media (prefers-reduced-motion: no-preference){
  html{scroll-behavior:smooth}
}
.btn,.chip,.tab,.fav-btn,#tabbar button{transition:background-color .15s ease,color .15s ease,border-color .15s ease,transform .12s ease}
.btn:active{transform:translateY(1px)}
.btn:disabled:active{transform:none}
.tile{transition:transform .18s ease,box-shadow .18s ease}
@media (hover:hover) and (pointer:fine){
  .tile:hover{transform:translateY(-2px);box-shadow:0 10px 24px rgba(70,35,10,.10)}
  .chip:hover{border-color:#D9BBA3}
}
#toast{box-shadow:0 10px 30px rgba(50,25,10,.25)}
@keyframes sheet-up{from{transform:translateY(12px)}to{transform:translateY(0)}}
#sheet .sheet-card{animation:sheet-up .22s ease}
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{transition-duration:.01ms!important;animation-duration:.01ms!important;scroll-behavior:auto!important}
}

/* v17: Help Q&A (the knowledge base in public/help.js — the same
   rules live in legal.css for the public /help page). Rows are
   real buttons, at least 44px tall, nothing expanded by default;
   the search filters as you type. */
.qa-search{margin:14px 0 6px}
.qa-search-label{display:block;font-weight:700;margin-bottom:6px}
.qa-search-input{font-size:16px;padding:12px}
.qa-count{color:var(--muted);font-size:13px;margin:6px 0 0}
.qa-cat{margin:24px 0 0}
/* v18.8.6: twin of the legal.css rule — in-app Help has the
   guide directly above the answers; the first category starts
   flush so the guide's 16px bottom margin sets the gap. */
#help-qa>.qa-cat:first-child{margin-top:8px}
.qa-cat>h2{font-size:19px;margin:0 0 4px}
.qa-item{border-top:1px solid var(--line)}
.qa-item h3{margin:0;font-size:16px}
.qa-q{display:flex;width:100%;align-items:center;justify-content:space-between;gap:12px;background:none;border:none;padding:12px 2px;min-height:44px;font:inherit;font-weight:600;color:var(--ink);text-align:left;cursor:pointer}
.qa-q::after{content:'+';font-size:20px;font-weight:400;color:var(--muted);flex:none}
.qa-q[aria-expanded="true"]::after{content:'\2013'}
.qa-a p{margin:0 0 14px;line-height:1.6}
.qa-video{display:block;width:100%;aspect-ratio:9/16;border-radius:16px;background:#1c1c1e;margin-top:10px}
.help-video{margin:0 0 16px}
.help-video .help-video-title{font-size:18px;margin:0 0 6px}
.help-video .qa-video{margin-top:0}
.help-video-cap{font-size:13.5px;color:var(--muted);margin:8px 0 0}
/* v18.8.6: the guide component — one shared shape for every
   single (Help + I Give + Exchanges + Messages). The masters
   are portrait 9:16, so the player is sized by HEIGHT, not
   width: height:min(50vh,500px) keeps a phone at ≤50vh and a
   desktop at ≤ min(52vh,500px), width follows at height × 9/16
   (~281px max), every pixel showing the video — no crop, no
   letterbox. Centred in a ≤400px block; the ember play badge
   is the cartoon's .video-play overlay at guide size, and
   help.js dismisses it on tap (or on play) and starts the
   video — the only tap is Play, nothing is ever hidden. */
.help-video.guide{max-width:400px;margin:0 auto 16px;text-align:center}
.help-video.guide .help-video-title{margin:0 0 10px}
.guide-frame{position:relative;width:max-content;max-width:100%;margin:0 auto}
.guide-frame .qa-video{width:auto;height:min(50vh,500px);max-width:100%;margin:0;border-radius:20px;box-shadow:0 12px 30px rgba(70,35,10,.16)}
.guide-badge{width:64px;height:64px}
.guide-badge .video-play-tri{border-left-width:22px;border-top-width:14px;border-bottom-width:14px;margin-left:5px}
@media (max-width:679px){
  .guide-badge{width:56px;height:56px}
  .guide-badge .video-play-tri{border-left-width:19px;border-top-width:12px;border-bottom-width:12px;margin-left:4px}
}
/* Guide band — Option B (Floyd, Nov 6): the SINGLE guide on
   I Give / Exchanges / Messages moves into a full-width Deep
   Energy band: gradient + soft circles, the whole uncropped
   player, its title + watch line, and 3 numbered steps in
   white. Scoped to guides that contain a .guide-band, so the
   Help view's guide (no band) keeps the plain component above,
   and the homepage tour strip is untouched. Stacked under
   700px (video centred, steps under it); at 700px+ the video
   sits left and title/steps right, with the text column
   spread over the video's full height (title at the top,
   steps distributed) so the band carries no dead orange
   under the steps. */
.help-video.guide:has(.guide-band){max-width:none;text-align:left}
.guide-band{position:relative;overflow:hidden;border-radius:24px;color:#fff;background:linear-gradient(120deg,#F06400 0%,#F04E23 52%,#E63329 100%);box-shadow:0 12px 30px rgba(70,35,10,.16);padding:22px 20px 24px;text-align:left}
.gb-circle{position:absolute;border-radius:50%;background:rgba(255,255,255,.13);pointer-events:none}
.gb-c1{width:230px;height:230px;top:-110px;right:-60px}
.gb-c2{width:150px;height:150px;bottom:-80px;left:-40px;background:rgba(255,255,255,.10)}
.gb-c3{width:90px;height:90px;top:38%;right:6%;background:rgba(255,255,255,.08)}
.guide-band-inner{position:relative;display:flex;flex-direction:column;align-items:center;gap:16px}
.guide-band-text{text-align:center;max-width:560px}
.help-video.guide .guide-band .help-video-title{font-size:24px;font-weight:800;margin:0 0 4px;letter-spacing:-.01em;color:#fff}
.guide-watch{margin:0;color:#FFE9DC;font-size:14px;font-weight:600}
.guide-band .guide-frame .qa-video{height:380px;box-shadow:0 14px 34px rgba(90,25,0,.35)}
.guide-steps{list-style:none;margin:2px 0 0;padding:0;display:flex;flex-direction:column;gap:12px;text-align:left;width:100%;max-width:520px}
.guide-steps li{display:flex;gap:12px;align-items:flex-start;font-size:15.5px;line-height:1.45;color:#FFF6F0}
.guide-step-num{flex:none;width:28px;height:28px;border-radius:50%;background:#fff;color:#C2410C;font-weight:800;font-size:15px;display:flex;align-items:center;justify-content:center;margin-top:1px}
@media (min-width:700px){
  .guide-band{padding:30px 34px}
  .guide-band-inner{display:grid;grid-template-columns:auto 1fr;grid-template-rows:auto 1fr;column-gap:34px;row-gap:14px;align-items:start}
  .guide-band .guide-frame{grid-column:1;grid-row:1 / span 2;align-self:center;margin:0}
  .guide-band .guide-frame .qa-video{height:400px}
  .guide-band-text{text-align:left;max-width:none;grid-column:2;grid-row:1;align-self:end}
  .help-video.guide .guide-band .help-video-title{font-size:28px}
  .guide-steps{max-width:none;margin-top:0;grid-column:2;grid-row:2;align-self:stretch;display:flex;flex-direction:column;justify-content:space-evenly;gap:12px}
  .guide-steps li{font-size:16.5px}
}
.qa-empty{margin:18px 0}
.qa-contact{margin:22px 0 6px}

#what-can-be-exchanged p{max-width:620px}
.btn.green:hover,.btn.blue:hover{background:var(--deep)}
.btn.solid:hover{background:linear-gradient(90deg,#A83A0A,#8F1F16)}
.btn.ghost:hover{border-color:#D9BBA3}
.linklike:hover{color:var(--deep);text-decoration:underline}
.chip:hover{border-color:#D9BBA3}
#nav-join.btn{padding:9px 16px;font-size:14.5px;min-height:40px}
body.in-app footer{padding-bottom:calc(84px + env(safe-area-inset-bottom))}
@media (min-width:900px){
  .steps-wrap{padding-top:56px}
  .tour-wrap{padding-top:56px}
  .skills-block{margin-top:56px}
  .closing-band{margin-top:56px}
}

/* v18.9 location: Explore place controls + the aggregated map */
.place-row{display:flex;flex-wrap:wrap;gap:10px 14px;align-items:center;margin:10px 0 4px}
.dist-chips{display:flex;flex-wrap:wrap;gap:6px}
.place-pick{display:inline-flex;align-items:center;gap:8px;font-weight:600;font-size:14.5px;position:relative}
.place-pick input{border:1px solid var(--line);border-radius:10px;padding:8px 10px;font-size:14.5px;min-width:170px;background:#fff}
/* Button-walk fix (Nov 5, 2026): the app's own place suggestions
   (a native <datalist> renders nothing on iOS/webviews). */
.place-suggest{position:absolute;top:calc(100% + 4px);left:0;right:0;z-index:30;background:#fff;border:1px solid var(--line);border-radius:12px;box-shadow:0 10px 26px rgba(70,35,10,.16);padding:4px;display:flex;flex-direction:column}
.place-option{appearance:none;border:0;background:none;text-align:left;font:inherit;font-weight:600;padding:9px 10px;border-radius:8px;cursor:pointer;color:inherit}
.place-option:hover,.place-option:active{background:var(--soft)}
.online-toggle{font-size:14.5px;font-weight:600}
.explore-map{height:300px;border:1px solid var(--line);border-radius:16px;margin:10px 0 4px;z-index:0}
.explore-map .leaflet-container{font:inherit;border-radius:16px}
.map-count{background:var(--give);color:#fff;border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:800;box-shadow:0 2px 8px rgba(70,35,10,.25)}
.tile .tile-place{color:var(--muted);font-weight:600}
.tile .tile-dist{color:var(--deep);font-weight:700}
.online-chip{display:inline-block;background:#E4F2E9;color:#14532D;border-radius:999px;padding:1px 8px;font-size:12px;font-weight:700;margin-left:6px;vertical-align:1px}
/* v18.9 chat photos */
.msg-imgs{display:flex;flex-wrap:wrap;gap:6px;margin:4px 0}
.msg-img{width:104px;height:104px;object-fit:cover;border-radius:10px;border:1px solid var(--line);background:var(--soft)}
.msg .msg-imgs .msg-img{width:120px;height:120px}
.chat-photo-note{font-size:13px;color:var(--muted)}
.thread-photo-btn{flex:none}
/* v18.27 pending-photo previews in the chat composers: the
   member sees the actual picked photos before sending. */
.pending-thumbs{display:flex;flex-wrap:wrap;gap:6px;margin:6px 0}
.pending-thumb{position:relative;flex:none;width:56px;height:56px}
.pending-thumb img{width:56px;height:56px;object-fit:cover;border-radius:10px;border:1px solid var(--line);background:var(--soft);display:block}
.pending-thumb-x{position:absolute;top:-6px;right:-6px;width:20px;height:20px;border-radius:50%;border:1px solid var(--line);background:#fff;color:var(--ink);font-size:14px;line-height:1;padding:0;cursor:pointer;display:flex;align-items:center;justify-content:center}
/* v18.9 attestation card */
.attest-card{border:1px solid #F2C4B0;background:#FDE8DC;border-radius:14px;padding:14px 16px;margin:0 0 14px}
.attest-card h2{margin:0 0 6px;font-size:17px}
.attest-card .check-label{margin:6px 0}
/* v18.9 Help two-cell (the ONE guide, at widths that fit it) */
.guide-two-cell{display:block}
.help-side{max-width:400px;margin:0 auto;text-align:left}
.help-side-label{font-size:12.5px;font-weight:800;letter-spacing:1.2px;text-transform:uppercase;color:var(--muted);margin:0 0 6px}
.help-side-cap{font-size:15.5px;margin:0 0 12px}
.help-side-links{display:flex;flex-direction:column;align-items:flex-start;gap:8px;margin:0 0 12px}
.help-side-links .linklike{padding:0;text-align:left;font-size:15px}
.help-side-all{font-weight:700;font-size:15px}
@media (min-width:768px){
  .guide-two-cell{display:grid;grid-template-columns:auto 1fr;gap:28px;align-items:start;max-width:1060px;margin:0 auto}
  .guide-two-cell .help-video.guide{margin:0}
  .guide-two-cell .help-side{max-width:none;margin:6px 0 0}
}

/* ---------- v18.30: the neatness sweep (Nov 6, 2026) ----------
   Layout/spacing/duplication only — no behaviour changes.
   Panel-reviewed clean-up list, approved by Floyd. */
/* 1: tab-bar badges leave the label flow — tucked at the tab's
   top-right corner, so all five labels share one baseline and
   one height whether or not a badge is showing. */
#tabbar button{position:relative}
#tabbar .count-badge{position:absolute;top:5px;right:8px}
/* 2: the full footer is a public-page element — on signed-in
   phone app screens (the tab-bar shell, <900px) it does not
   render at all. Desktop and guests keep it.
   Landing exemption (iPhone homepage scroll fix, Nov 6): the
   homepage stays visitable while signed in and its footer
   ("Nothing wasted. Everything used fully." + the legal
   links) is part of it, so the footer renders while — and
   only while — the landing view is the visible view. Other
   in-app views keep it hidden. The :has() rule carries an ID
   in its argument, so it beats the hide rule above it. */
@media (max-width:899px){
  body.in-app footer{display:none}
  body.in-app:has(main > #view-landing:not(.hidden)) footer{display:block}
}
/* 3: the collapsed Explore filters block. */
#more-filters{margin-top:2px}
#more-filters .filter-row{margin-top:8px}
/* 5: a no-photo tile/sheet placeholder is a compact strip, not
   a panel — the title and price lead. */
.tile-img.noimg{aspect-ratio:auto;height:72px;flex-direction:row;gap:8px}
.tile-img.noimg .ph-letter{font-size:22px}
.sheet-img.noimg{aspect-ratio:auto;height:104px;flex-direction:row;gap:10px}
.sheet-img.noimg .ph-letter{font-size:30px}
/* 6: tiles anchor clear of the sticky search bar, and the bar
   carries a hairline so content passing under it reads clean. */
.tile{scroll-margin-top:calc(var(--topbar-h,118px) + 76px)}
#view-explore .search-row{border-bottom:1px solid var(--line)}
/* 7: the post form's rules read as short lines (same words);
   the disabled Post it keeps most of the primary colour, so it
   no longer reads as washed out next to the other actions. */
.rules-list{margin:6px 0 0;padding-left:18px;line-height:1.45}
.rules-list li{margin:1px 0}
#post-listing-btn:disabled{opacity:.78}
/* 10: exchange action rows wrap evenly (equal-width buttons),
   and a price never splits across lines. */
#exchanges .row-actions .btn{flex:1 1 148px}
.price{white-space:nowrap}
.row-head .price{flex:none}
/* 11: thread bubbles — the time gets real bottom room (it was
   half-clipped), and a photo fills its bubble instead of
   sitting small with empty space beside it. */
.thread-msgs{padding-bottom:12px}
.bubble{padding:10px 12px 11px}
.bubble .b-time{line-height:1.35}
.bubble .msg-img{flex:1 1 96px;width:auto;height:auto;aspect-ratio:1/1;max-width:232px}
/* 12: Messages guide video — the native control bar overlaid the
   poster's burned-in bottom caption. Handled in help.js instead of
   a letterbox band (padding could not lift the contain-fitted poster
   off the content-box bottom, so it kept the icons on the caption):
   guide videos carry no controls until the first play, so pre-play
   the poster shows with only the app's own play badge; the badge is
   the play affordance and controls arrive with playback. Outer
   size/position unchanged. */
/* 17: the listing sheet's closing row — Report and Close share
   one equal-width row. */
.sheet-end-actions .btn{flex:1 1 0}
/* 20: the delete sheet — the same consequence words, set
   tighter, so the confirm fields and buttons are on screen. */
.sheet-card.delete-sheet{max-height:94vh;padding-top:14px}
.delete-lines{margin:0 0 10px;padding-left:18px;line-height:1.42;font-size:13.5px}
.delete-lines li{margin:0 0 3px}
.delete-sheet label{margin:6px 0}
.delete-sheet h2{margin-bottom:6px}
/* 21: stacked sheet actions (report reasons, report kinds,
   member-report categories) are compact rows — the flex basis
   that made them tall empty boxes is gone, so every reason
   fits on one screen. */
.sheet-actions.stack{flex-direction:column;align-items:stretch}
.sheet-actions.stack .btn{flex:0 0 auto;min-height:44px}
/* 22: the photo manager — one photo shows large, not a
   thumbnail in a mostly-empty sheet. */
.pm-item{width:min(216px,100%)}
.pm-item img{width:100%;height:auto;aspect-ratio:4/3}

/* Release B: "I'm looking for…" request cards in Explore and
   the meeting card in exchanges. Both reuse the card/row
   language; nothing new to learn. */
.req-entry p{margin:0 0 10px}
.req-card{display:flex;gap:12px;align-items:flex-start}
.req-card .req-img{width:72px;height:72px;object-fit:cover;border-radius:10px;flex:0 0 auto}
.req-card .req-main{flex:1;min-width:0}
.req-card .req-text{font-weight:600;overflow-wrap:anywhere}
.req-card .req-meta{margin-top:2px}
.req-card .row-actions{margin-top:8px}
.meet-card{border:1px solid var(--line);border-left:4px solid var(--want);border-radius:12px;padding:10px 12px;margin:8px 0;background:var(--soft)}
.meet-card .meet-line{margin:0 0 2px}
.meet-card p{margin:2px 0}
.meet-card.replaced{opacity:.6;border-left-color:var(--line)}
.msg .meet-card{margin:0}

/* Clarity pass (Nov 6, 2026): Explore section headings + request
 * card badges. The badge is outline-style (never a filled pill) so
 * it cannot be mistaken for a credit/price badge on a listing. */
.explore-heading{font-size:20px;margin:20px 0 10px}
.req-strip-title{font-size:17px;margin:16px 0 8px}
.req-entry{border-style:dashed}
.req-badges{display:flex;gap:6px;flex-wrap:wrap;align-items:center;margin-bottom:4px}
.req-badge{font-size:11px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--ember);border:1.5px solid var(--ember);border-radius:999px;padding:2px 8px;line-height:1.5}
.req-kind{font-size:11px;font-weight:600;border-radius:999px;padding:3px 8px;background:#F1F1F4;color:#444;line-height:1.5}
.req-card .req-text{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}
.req-kind-chips{margin:6px 0 10px}
#req-text{width:100%}
