/* Color tokens — see DESIGN.md §2. Tokens only; no raw hex in component CSS.
   (The out-of-scope palettes of DESIGN.md §5a — semantic danger/success/warning,
   vendored Leaflet, content gradients — deliberately keep their literals.) */
:root{
  /* The ONE icon that must live in CSS: the #nav-av image-branch fallback
     mask (see the block by #nav-av below). Generated from
     vendor/lucide/icons/user.svg — stroke colour is irrelevant, a mask reads
     alpha only. */
  --ico-user:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M19%2021v-2a4%204%200%200%200-4-4H9a4%204%200%200%200-4%204v2%22%20%2F%3E%20%3Ccircle%20cx%3D%2212%22%20cy%3D%227%22%20r%3D%224%22%20%2F%3E%3C%2Fsvg%3E");
  /* Brand */
  --farrow-teal:#00A99D;        /* primary brand color; chrome fills only */
  --farrow-teal-deep:#00786F;   /* teal for TEXT/links/icons on light backgrounds (AA-safe) */
  --farrow-teal-tint:#D7F0EE;   /* pale teal; subtle highlights, selected rows */
  /* Neutrals */
  --surface-page:#FAFAF8;       /* app/page background */
  --surface-card:#FFFFFF;       /* cards, sheets, nav bar background */
  --border-hairline:#E4E2DC;    /* card borders, dividers */
  --text-primary:#2C2C2A;       /* body text */
  --text-secondary:#888780;     /* metadata, captions, inactive tabs */
  --on-teal:#FFFFFF;            /* text/icons placed on --farrow-teal */
  /* Semantic alert. §7 bans new accent colors without a Ben + Alto ruling —
     this is the ratified exception (Ben, 2026-07-25, notifications batch): an
     unread badge cannot carry brand teal on the teal header (§2 teal-on-teal)
     and no existing token reads as "unread". Standard alert red, scoped to
     status badges only — never a surface, never text, and explicitly NOT a
     new brand color. It exists as a token so component CSS stays hex-free. */
  --badge-alert:#E5484D;        /* unread/attention dot */
  /* Dark neutrals — landing hero ONLY (DESIGN.md §2). Not for app screens. */
  --surface-dark:#15171C;       /* hero background (replaces navy #0b1020) */
  --surface-dark-2:#1D2026;     /* hero secondary panels (replaces #0f1530) */
  --on-dark:#FFFFFF;            /* headline text/logo on dark */
  --on-dark-secondary:#C9CBCF;  /* supporting text on dark */
  /* Legacy vars, repointed at the tokens above (DESIGN.md §5b). --bg, --bg2,
     --brand2, --accent and --grad are deleted. */
  --ink:var(--text-primary); --paper:var(--surface-card);
  --muted:var(--text-secondary); --line:var(--border-hairline);
  --brand:var(--farrow-teal);
  --shadow:0 18px 50px -20px rgba(0,0,0,.35);
  --r:18px;
}
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}

/* ---- Icons (DESIGN.md §4a) ----------------------------------------------
   Lucide, inline SVG, emitted by icon() in icons.js. Everything here is
   geometry and alignment ONLY: every icon carries stroke="currentColor" and no
   fill of its own, so colour comes from whatever the button or label already
   inherits. The existing token rules keep driving it unchanged — .tab.active's
   --farrow-teal-deep, .tab's --muted, .app-top .icon-btn's --on-teal — and this
   batch introduces no colour token of any kind.
   Size comes from the width/height attributes icon() writes (16/20/24); the few
   display contexts that want a different box override it below, next to the
   rule that already owned that box. */
.ico{display:inline-block;vertical-align:-.18em;flex:none}
/* Flex/centred containers: the baseline nudge above is wrong inside them. */
.tab .ico,.icon-btn .ico,.eng-btn .ico,.dact .ico,.gate-logo .ico,.ce,.tp-check .ico,
.cat-opt .ico,.rk-thumb .ico,.dthumb .ico,.dt-emoji .ico,.pin .ico{vertical-align:middle}
/* Display contexts that were sized by font-size when they held a glyph. */
.gate-logo .ico{width:34px;height:34px}
.globe .ico{width:100%;height:100%;display:block}
.feat-ico .ico{width:30px;height:30px}
.rk-thumb .ico,.dthumb .ico,.dt-emoji .ico{width:22px;height:22px}
.pin .ico{width:15px;height:15px}
.cat-opt .ce .ico{width:20px;height:20px}
.dt-trip .ico{width:34px;height:34px}
.tp-cover .ico{width:22px;height:22px}
/* Keyboard focus: a visible ring on every control — the app had no
   :focus-visible styles at all, so tabbing was invisible. Mouse/touch focus
   (:focus without :focus-visible) stays ringless, as before. */
button:focus-visible,a:focus-visible,input:focus-visible,textarea:focus-visible,
select:focus-visible,[role=button]:focus-visible,[tabindex]:focus-visible{
  outline:2px solid var(--farrow-teal-deep);outline-offset:2px}
/* On teal/photo/dark surfaces a deep-teal ring vanishes — DESIGN.md §3 gives
   indicator rings --on-teal there. */
.app-top :focus-visible,.trip-hero :focus-visible,.hero :focus-visible,
.foot :focus-visible,.bcard :focus-visible{outline-color:var(--on-teal)}
body{
  font-family:system-ui,sans-serif;
  color:var(--ink); background:var(--surface-page); line-height:1.5; -webkit-font-smoothing:antialiased;
}
h1,h2,h3{font-family:system-ui,sans-serif; line-height:1.05; letter-spacing:-.01em}
a{color:inherit;text-decoration:none}
.muted{color:var(--muted)}
.grad-text{background:var(--farrow-teal);-webkit-background-clip:text;background-clip:text;color:transparent}

/* ---------- buttons ---------- */
.btn-primary{
  background:var(--farrow-teal-deep); color:var(--on-teal); border:0; padding:13px 22px; border-radius:999px;
  font-weight:700; font-size:15px; cursor:pointer;
  transition:transform .15s, box-shadow .15s;
}
.btn-primary:hover:not(:disabled){transform:translateY(-2px)}
/* In-flight / not-yet-valid states must LOOK inert (double-submit guards,
   wizard Next/Generate): same geometry, muted, no hover lift. */
.btn-primary:disabled{opacity:.55;cursor:default}
.btn-ghost.dark:disabled{opacity:.55;cursor:default}
.btn-ghost{
  background:rgba(255,255,255,.08); color:inherit; border:1px solid rgba(255,255,255,.18);
  padding:11px 18px; border-radius:999px; font-weight:600; font-size:14px; cursor:pointer; transition:.15s;
}
.btn-ghost:hover{background:rgba(255,255,255,.16)}

/* ---------- hero ---------- */
.hero{
  background:radial-gradient(1200px 600px at 80% -10%,var(--surface-dark-2) 0%,transparent 55%),
             radial-gradient(900px 500px at 0% 20%,var(--surface-dark-2) 0%,transparent 50%),
             linear-gradient(160deg,var(--surface-dark),var(--surface-dark-2));
  color:var(--on-dark); padding-bottom:90px; overflow:hidden; position:relative;
}
.nav{max-width:1160px;margin:0 auto;display:flex;align-items:center;justify-content:space-between;padding:22px 24px}
.brand{display:flex;align-items:center;gap:9px;font-weight:800;font-size:20px;letter-spacing:-.02em}
.logo{font-size:22px;color:var(--farrow-teal-deep)}
/* the mark sits on the dark hero + footer; on light chrome it stays deep teal */
.hero .logo,.foot .logo{color:var(--on-dark)}
/* Brand wordmark artwork (DESIGN.md §5) on the dark hero, the dark footer and
   the teal app header — one image, no text span, since the §5 fidelity gate
   failed for live text. Height-driven with width:auto so the PNG is never
   stretched (§5 bans that outright); flex:none stops the flex parents
   shrinking it below that.
   39px is a floor, not a taste call: the 1292x559 asset renders 90.13px wide
   there, clearing §5's 90px minimum wordmark width (38.94px is the exact
   break-even). Sizing it instead to the height the old glyph+text lockup
   occupied (30px landing / 27px app) gives 69.3px / 62.4px — under that
   minimum, and visibly SMALLER than the brand reads today, because this asset
   packs the whole word into the height the glyph alone used to fill. */
.logo-img{height:39px;width:auto;display:block;flex:none}
.nav-links{display:flex;align-items:center;gap:26px;font-size:14px;font-weight:600;color:var(--on-dark-secondary)}
.nav-links a:hover{color:var(--on-dark)}
.hero-inner{max-width:1160px;margin:0 auto;padding:40px 24px 0;display:grid;grid-template-columns:1.05fr .95fr;gap:40px;align-items:center}
.pill{display:inline-block;background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.14);color:var(--on-dark-secondary);padding:7px 15px;border-radius:999px;font-size:13px;font-weight:600;margin-bottom:22px}
.hero h1{font-size:clamp(38px,5.2vw,64px);font-weight:700}
.lede{margin:22px 0 28px;font-size:18px;color:var(--on-dark-secondary);max-width:520px}
.hero-cta{display:flex;gap:14px;flex-wrap:wrap}
.hero-stats{display:flex;gap:34px;margin-top:40px}
.hero-stats div{display:flex;flex-direction:column}
.hero-stats b{font-size:30px;font-family:system-ui,sans-serif}
.hero-stats span{font-size:13px;color:var(--on-dark-secondary)}

.hero-art{position:relative;height:420px}
.globe{position:absolute;inset:0;margin:auto;width:300px;height:300px;font-size:300px;line-height:300px;text-align:center;
  filter:drop-shadow(0 30px 60px rgba(0,0,0,.45));animation:spin 40s linear infinite;opacity:.95}
@keyframes spin{to{transform:rotate(360deg)}}
/* (The .float-card / .fc-img / .c1-.c3 / @keyframes bob block was removed —
   dead since the honesty pass took out the mock live-journey inbox.) */

/* ---------- features ---------- */
.features{max-width:1160px;margin:0 auto;padding:90px 24px}
.sec-head{text-align:center;max-width:680px;margin:0 auto 50px}
.sec-head h2{font-size:clamp(28px,3.4vw,42px)}
.sec-head p{color:var(--muted);font-size:18px;margin-top:12px}
.feat-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:20px}
.feat{background:var(--paper);border:1px solid var(--line);border-radius:var(--r);padding:26px;transition:.2s}
.feat:hover{transform:translateY(-4px);box-shadow:var(--shadow)}
.feat-ico{font-size:30px;margin-bottom:14px}
.feat h3{font-size:19px;margin-bottom:8px}
.feat p{font-size:14.5px;color:var(--muted)}

/* ---------- app device ---------- */
.app-wrap{background:var(--surface-page);padding:30px 24px 90px}
.device{
  max-width:1080px;margin:0 auto;background:var(--paper);border-radius:26px;overflow:hidden;
  box-shadow:0 40px 90px -30px rgba(0,0,0,.45);border:1px solid var(--line);display:flex;flex-direction:column;height:760px;
}
/* The app header is a brand field: DESIGN.md §3 puts the top bar in a raw
   --farrow-teal fill with a white logo, and §2 reserves the raw fill for
   exactly this (brand fields: header, splash, empty states). */
/* Three-region grid (Ben-ruled 2026-07-25, header v2): bell slot | logo | +.
   `1fr auto 1fr` is what centres the logo OPTICALLY — the side columns are
   equal by construction, so the brand sits dead-centre however wide the two
   clusters grow. The old flex + space-between could only centre it when the
   two sides happened to be the same width; a single unread badge on the bell
   would have pulled it off. Children are placed by ORDER, so the markup order
   in app.html (.app-lead, .app-brand, .app-actions) IS the visual order, and
   there must be exactly THREE direct children — a fourth lands in an unplaced
   fourth column and un-centres the logo. */
/* Vertical padding is 10px, not 16px, purely to hold this bar at its
   established height: tallest-child + 2*padding + 1px border. The tallest
   child is the 40px .icon-btn compose + — NOT the 39px wordmark — so the bar
   measures 40 + 20 + 1 = 61px, and 44 + 20 + 1 = 65px under
   @media(pointer:coarse) where .icon-btn grows to 44px. (The previous
   "39 + 20 + 1 = 60" arithmetic here counted only the logo and was already
   stale before this batch; corrected 2026-07-25.) The grid swap changes no
   child's height, so the measurement is unchanged by it. Anything added to
   .app-lead taller than 40px resizes the bar — the bell batch especially. */
.app-top{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;padding:10px 22px;border-bottom:1px solid var(--line);background:var(--farrow-teal)}
.app-brand{display:flex;align-items:center;gap:8px;font-weight:800;font-size:18px}
/* Layout only. The font-size/weight/colour this rule used to carry described a
   text label that no longer exists: signed IN the slot is empty (header v2),
   and signed OUT its single .chip-signout child brings its own type tokens. */
.app-profile{display:flex;align-items:center}
/* Left header region — the notifications bell lands HERE (top-left, Ben-ruled
   2026-07-25), and now does: #notif-bell is its only child.
   Breadcrumb carried over from the deleted presence-dot rule: the bare global
   `.dot` was renamed `.chip-presence` on 2026-07-25 precisely so the bell could
   own an unread-badge class without colliding with it. The bell's badge is
   `.bell-dot`, so neither name is contested.
   The white-on-teal note that used to sit here is discharged: the treatment
   below was generalised from `.app-top .compose-btn` to `.app-top .icon-btn`
   as instructed, so the bell inherits it rather than rendering as the default
   --farrow-teal-deep-on-teal pill that §7 bans. */
.app-lead{display:flex;align-items:center;gap:10px;justify-self:start}
/* Right-hand header cluster (Ben-ruled 2026-07-25). Everything riding the
   right side — the compose +, and the signed-out Sign in slot — is a child of
   .app-actions, never a direct child of .app-top (see the three-child grid
   contract above). */
.app-actions{display:flex;align-items:center;gap:10px;justify-self:end}
/* Icon buttons on the teal bar. DESIGN.md §3 allows white icons on the header
   and §7 reserves --on-teal for exactly this; the default .icon-btn treatment
   (--farrow-teal-deep glyph on a --surface-card pill) would be teal-on-teal
   here, so both the fill and the border are dropped rather than recolored.
   Generalised from `.app-top .compose-btn` to `.app-top .icon-btn` in the
   notifications batch (2026-07-25), per the instruction the .app-lead comment
   above carried: the bell needs the identical treatment, and scoping this to
   the button class rather than naming each one means the next header icon
   gets it for free. */
.app-top .icon-btn{background:transparent;border-color:transparent;color:var(--on-teal)}
.app-top .icon-btn:hover{background:rgba(255,255,255,.16);border-color:transparent}
/* Notifications bell. Sized by .icon-btn (40px / 44px coarse) so the frozen
   bar height is untouched; `position:relative` only anchors the badge. The
   font-size no longer drives the mark (it is an SVG at a fixed 20px now) but
   is kept so the button box is unchanged. */
.bell-btn{position:relative;font-size:17px;line-height:1}
/* Unread badge. Absolutely positioned and pointer-transparent, so it adds no
   layout box and can never grow .app-lead past the bell's own 40px — the
   height constraint the grid comment above calls out. The ring matches the
   bar so the dot reads as a badge rather than a speck of noise. */
.bell-dot{position:absolute;top:6px;right:6px;width:9px;height:9px;border-radius:50%;
  background:var(--badge-alert);box-shadow:0 0 0 2px var(--farrow-teal);pointer-events:none}
/* This codebase scopes .hidden PER COMPONENT — there is no global rule (see
   the S3.1 note at #mc-pane-*). Without this line renderNotifDot() would
   toggle a class that styles nothing and the dot would show permanently. */
.bell-dot.hidden{display:none}
@media(pointer:coarse){.bell-dot{top:8px;right:8px}}
/* Still live, and now the ONLY thing #app-profile ever renders: as of header v2
   (2026-07-25) the signed-IN header slot is empty — the presence dot is gone
   and the avatar moved to the bottom-nav Profile tab — while the signed-OUT
   branch still writes a .chip-signout "Sign in" button into #app-profile,
   which is inside .app-top (api.js). Kept per Ben's ruling 2026-07-25 despite
   the /app auth redirect making it unreachable in practice.
   Sign OUT left this bar on 2026-07-25, but this rule did not go with it. Was
   border-color:var(--brand) — teal on teal, so the border vanished on hover
   instead of highlighting. The hover text colour is left alone:
   --farrow-teal-deep on the white pill. */
.app-top .chip-signout:hover{border-color:var(--on-teal)}

.screens{flex:1;overflow:hidden;position:relative}
.screen{position:absolute;inset:0;overflow-y:auto;padding:24px 26px;overscroll-behavior:contain}
.screen.hidden{display:none}

.map-head,.feed-head{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:16px;flex-wrap:wrap}
.map-head h2,.feed-head h2{font-size:26px}
.beta{font-family:system-ui,sans-serif;font-size:11px;font-weight:700;background:var(--farrow-teal-deep);color:var(--on-teal);padding:3px 9px;border-radius:999px;vertical-align:middle;margin-left:6px}
#map{height:min(40vh,320px);border-radius:16px;border:1px solid var(--line);z-index:0}

/* cooperative map gestures (see makeMapCooperative in app.js) */
@media (hover:hover){
  .coop:not(.coop-on):hover::after{content:'Click to interact with the map';position:absolute;top:10px;left:50%;transform:translateX(-50%);font-family:system-ui,sans-serif;font-size:12px;font-weight:600;background:rgba(0,0,0,.72);color:var(--on-teal);padding:6px 13px;border-radius:999px;z-index:800;pointer-events:none;white-space:nowrap}
}
.coop-hint{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-family:system-ui,sans-serif;font-size:14px;font-weight:700;background:rgba(0,0,0,.35);color:var(--on-teal);z-index:800;pointer-events:none;opacity:0;transition:opacity .25s}
.coop-hint-on .coop-hint{opacity:1}
.chips,.log-filters{display:flex;gap:8px;flex-wrap:wrap}
.chip{font-size:13px;font-weight:600;border:1px solid var(--line);background:var(--surface-card);padding:7px 13px;border-radius:999px;cursor:pointer;display:flex;align-items:center;gap:6px;transition:.15s}
.chip.active{background:var(--ink);color:var(--on-teal);border-color:var(--ink)}
.chip .sw{width:10px;height:10px;border-radius:3px}

/* map popups */
.leaflet-popup-content{margin:10px 12px;font-family:system-ui,sans-serif}
.pop b{font-size:14px} .pop .pc{font-size:12px;color:var(--text-secondary)} .pop .pr{font-weight:700;color:var(--farrow-teal-deep)}
.pin-hit{width:40px;height:40px;display:flex;align-items:flex-end;justify-content:center}
.pin{display:flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50% 50% 50% 2px;transform:rotate(45deg);box-shadow:0 6px 14px -4px rgba(0,0,0,.5);border:1.5px solid var(--surface-card)}
.pin span{transform:rotate(-45deg);font-size:10px}

/* avatars + save button (shared by feed, search, profiles) */
.av{width:38px;height:38px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:18px;color:var(--on-teal);flex:none}
/* Initials fallback for the empty-avatar branch (DESIGN.md §9 item 1). Opt-in:
   only avHTML() callers that pass initials emit this class, so every other
   avatar surface keeps the compass on its hashed background. Overrides .av's
   --on-teal, which would be white-on-tint and fail contrast.
   §2 is what sets the SIZE here: --farrow-teal-deep on --farrow-teal-tint
   measures 4.49:1, which §2 (Ben-ruled 2026-07-21) limits to icons and large
   text — so the initials must stay at DESIGN.md's >=18px large-text threshold.
   .av's own 18px is deliberately inherited rather than restated; the moment
   card's 48px circle takes 19px. Do not shrink either below 18px without
   changing the colour pair, which is a §2/§9 decision, not a CSS tweak. */
.av-initials{background:var(--farrow-teal-tint);color:var(--farrow-teal-deep);font-weight:600;letter-spacing:.02em}
.mc-av.av-initials{font-size:19px}
.save-btn{margin-left:auto;border:1px solid var(--line);background:var(--surface-card);padding:8px 15px;border-radius:999px;font-weight:600;font-size:13px;cursor:pointer;transition:.15s}
.save-btn.saved{background:var(--ink);color:var(--on-teal);border-color:var(--ink)}

/* bucket */
#bucket{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.bcard{position:relative;border-radius:16px;overflow:hidden;height:170px;display:flex;align-items:flex-end;padding:16px;color:var(--on-teal);cursor:pointer;box-shadow:0 10px 24px -14px rgba(0,0,0,.4);transition:.15s}
.bcard:hover{transform:translateY(-3px)}
.bcard::after{content:"";position:absolute;inset:0;background:linear-gradient(transparent,rgba(0,0,0,.6))}
.bcard .bc-inner{position:relative;z-index:1}
.bcard .btag{font-size:11px;font-weight:700;background:rgba(255,255,255,.25);padding:3px 9px;border-radius:999px;backdrop-filter:blur(4px)}
.bcard h4{font-size:20px;font-family:system-ui,sans-serif;margin:8px 0 2px}
.bcard small{font-size:12px;opacity:.85}
.bemoji{position:absolute;top:12px;right:14px;font-size:30px;z-index:1}

/* inbox / auto-log */

/* planner */
.planner-controls{display:flex;gap:12px;flex-wrap:wrap;align-items:flex-end;background:var(--surface-card);border:1px solid var(--line);border-radius:16px;padding:16px;margin-bottom:18px}
.ctl{display:flex;flex-direction:column;gap:5px}
.ctl label{font-size:12px;font-weight:700;color:var(--muted)}
.ctl select{border:1px solid var(--line);border-radius:10px;padding:10px 12px;font-family:inherit;font-size:14px;font-weight:600;background:var(--surface-card);cursor:pointer;min-width:130px}
.plan-out:empty{display:none}
.plan-intro{background:var(--farrow-teal-tint);border:1px solid var(--border-hairline);border-radius:14px;padding:16px 18px;margin-bottom:16px;font-size:14.5px}
.plan-intro b{color:var(--text-primary)}
.day{background:var(--surface-card);border:1px solid var(--line);border-radius:14px;padding:14px 16px;margin-bottom:12px;display:flex;gap:14px}
.day .dnum{width:44px;height:44px;border-radius:11px;background:var(--farrow-teal-deep);color:var(--on-teal);font-weight:800;display:flex;align-items:center;justify-content:center;flex:none;font-size:13px;text-align:center;line-height:1.1}
.day .ditems{font-size:14px}
.day .dtitle{font-weight:700;margin-bottom:4px}
.day .ditem{color:var(--text-primary);font-size:13.5px;margin:2px 0;display:flex;gap:7px}
.thinking{display:flex;align-items:center;gap:12px;color:var(--muted);font-size:15px;padding:30px}
/* planner v2: wide rows, option chips, concept cards, detail view */
.ctl-wide{flex:1 1 100%}
.opt-hint{font-weight:500;color:var(--text-secondary);font-size:11px;margin-left:4px}
.opt-chips{display:flex;flex-wrap:wrap;gap:7px}
.pchip{background:var(--surface-page);border:1px solid var(--line);border-radius:999px;padding:7px 13px;font-size:13px;font-weight:600;cursor:pointer;font-family:inherit;color:var(--text-primary);transition:.12s}
.pchip.active{background:var(--ink);color:var(--on-teal);border-color:var(--ink)}
.pchip:disabled{opacity:.4;cursor:default}
.wiz-city-input{width:100%;box-sizing:border-box;border:1px solid var(--line);border-radius:11px;padding:10px 13px;font-family:inherit;font-size:14.5px;margin:10px 0 8px}
.wiz-city-input:disabled{opacity:.4}
.plan-go{flex-direction:row;align-items:center;gap:12px}
.plan-err{color:#dc2626;font-size:13px;font-weight:600}
/* Error card: neutral surface so the semantic danger-red (§5a) reads at AA. */
.plan-errcard{background:var(--surface-card);border:1px solid var(--border-hairline);border-radius:14px;padding:15px 18px;margin-bottom:16px}
/* Teaching empty state for the idle Plan pane (renderPlanEmpty). */
.plan-guide{list-style:none;display:flex;flex-direction:column;gap:15px;margin-top:6px}
.pg-step{display:flex;gap:14px;align-items:flex-start}
.pg-num{flex:none;width:30px;height:30px;border-radius:50%;background:var(--farrow-teal-tint);color:var(--text-primary);font-weight:600;font-size:14px;display:flex;align-items:center;justify-content:center}
.pg-step>div{padding-top:2px}
.pg-step b{display:block;font-size:15px;font-weight:600;margin-bottom:2px}
.pg-step span{display:block;color:var(--text-secondary);font-size:13.5px;line-height:1.45}
.concept-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:12px;margin-bottom:6px}
.concept-card{text-align:left;background:var(--surface-card);border:1px solid var(--line);border-radius:16px;padding:16px;cursor:pointer;font-family:inherit;display:flex;flex-direction:column;gap:8px;transition:.15s}
.concept-card:hover{border-color:var(--brand);box-shadow:0 10px 30px -18px rgba(0,0,0,.5)}
.cc-title{font-family:system-ui,sans-serif;font-size:19px}
.cc-highlights .ditem{color:var(--text-primary);font-size:13px;margin:2px 0}
.cc-summary{font-size:13.5px;color:var(--text-primary)}
.cc-open{margin-top:auto;color:var(--farrow-teal-deep);font-weight:700;font-size:13.5px}
/* draft trips (saved from the planner) */
.trip-draft-banner{background:#fff7ed;border:1px solid #fdba74;border-radius:14px;padding:14px 16px;margin-bottom:14px;font-size:13.5px;color:#7c2d12;display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.trip-draft-banner .complete-btn{margin-left:auto;padding:9px 16px;font-size:13.5px}
.plan-ref{background:var(--surface-card);border:1px solid var(--line);border-radius:14px;padding:14px 16px;margin-bottom:14px}
.plan-ref .pr-head{font-size:12px;font-weight:700;color:var(--muted);margin-bottom:6px}
.plan-ref .pr-name{font-family:system-ui,sans-serif;font-size:17px}
/* pre-cap rows can store long text: clamp the summary to two lines … */
.plan-ref .pr-pitch{font-size:13.5px;color:var(--text-primary);margin:4px 0 6px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.plan-ref .pr-chips{margin-top:4px}
/* … and ellipsize each highlight chip (.chip base look, non-interactive) */
.plan-ref .pr-chip{cursor:default;display:inline-block;max-width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.plan-ref .pr-expand{margin-top:10px;border:1px solid var(--farrow-teal-deep);background:var(--surface-card);color:var(--farrow-teal-deep);font-family:system-ui,sans-serif;font-weight:700;font-size:12px;padding:5px 12px;border-radius:999px;cursor:pointer;transition:.15s}
.plan-ref .pr-expand:hover{background:var(--farrow-teal-deep);color:var(--on-teal)}
.plan-ref .pr-itin{margin-top:10px;font-size:13px}
.plan-ref .pr-day{margin-top:8px}
.plan-ref .pr-daylabel{font-weight:700}
.jrn-back{background:none;border:0;color:var(--muted);font-weight:700;font-size:13.5px;cursor:pointer;padding:0 0 10px;font-family:inherit}
.jrn-back:hover{color:var(--ink)}
.plan-note{background:var(--surface-card);border:1px solid var(--line);border-radius:14px;padding:14px 16px;margin-bottom:12px;font-size:13.5px;color:var(--text-primary)}
.plan-note b{color:var(--ink)}
.spin{width:20px;height:20px;border:3px solid var(--line);border-top-color:var(--brand);border-radius:50%;animation:sp .7s linear infinite}
@keyframes sp{to{transform:rotate(360deg)}}

/* modals */
.modal-bg{
  position:fixed;inset:0;z-index:2000;background:rgba(0,0,0,.55);backdrop-filter:blur(4px);
  display:none;align-items:center;justify-content:center;padding:20px;
}
.modal-bg.open{display:flex}
.modal{background:var(--surface-card);border-radius:22px;width:100%;max-width:460px;max-height:90vh;overflow:hidden;display:flex;flex-direction:column;box-shadow:0 40px 90px -20px rgba(0,0,0,.5);animation:pop .2s ease}
@keyframes pop{from{transform:translateY(14px) scale(.97);opacity:0}to{transform:none;opacity:1}}
.modal-head{display:flex;align-items:center;justify-content:space-between;padding:18px 22px;border-bottom:1px solid var(--line)}
.modal-head h3{font-size:22px}
.x{border:0;background:var(--surface-page);width:32px;height:32px;border-radius:50%;cursor:pointer;font-size:14px;color:var(--text-secondary);transition:.12s}
.x:hover{background:var(--border-hairline);color:var(--text-primary)}
/* overscroll-behavior:contain everywhere a sheet scrolls: hitting the end of
   a modal list used to chain the scroll into the screen behind it (jank). */
.modal-body{padding:20px 22px;overflow-y:auto;overscroll-behavior:contain}
/* min-width:0 — grid/flex children default to min-width:auto, which let the
   City/Country pair push the modal wider than a phone screen. */
.fld{display:flex;flex-direction:column;gap:6px;margin-bottom:14px;min-width:0}
.fld>span{font-size:13px;font-weight:700;color:var(--text-primary)}
.fld>span em,.fld>span b{font-weight:700}.fld>span em{color:var(--muted);font-style:normal;font-weight:500}
.fld>span b{color:var(--farrow-teal-deep)}
.fld input,.fld textarea{border:1px solid var(--line);border-radius:11px;padding:11px 13px;font-family:inherit;font-size:14.5px;resize:none;min-width:0;max-width:100%}
.fld input:focus,.fld textarea:focus{border-color:var(--brand)}
/* Suppress the outline for MOUSE focus only — keyboard focus keeps the global
   :focus-visible ring (was: a blanket outline:none that hid it from tabbing). */
.fld input:focus:not(:focus-visible),.fld textarea:focus:not(:focus-visible){outline:none}
/* The "Which day?" <select> was raw/native — no border, and it triggered iOS
   focus-zoom. Match the .fld inputs (native chevron kept; 16px on mobile below). */
.fld select{width:100%;border:1px solid var(--line);border-radius:11px;padding:11px 13px;font-family:inherit;font-size:14.5px;background:var(--surface-card);color:var(--text-primary);cursor:pointer;max-width:100%}
.fld select:focus{border-color:var(--brand)}
.fld select:focus:not(:focus-visible){outline:none}
.fld-row{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.fld-label{font-size:13px;font-weight:700;color:var(--text-primary);display:block;margin-bottom:8px}
.cat-pick{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin-bottom:16px}
.cat-opt{border:1px solid var(--line);background:var(--surface-card);border-radius:12px;padding:10px 6px;cursor:pointer;text-align:center;font-size:12px;font-weight:600;color:var(--text-secondary);transition:.12s}
.cat-opt .ce{font-size:20px;display:block;margin-bottom:3px}
.cat-opt.sel{color:var(--on-teal);border-color:transparent}
input[type=range]{accent-color:var(--brand);height:6px}
.loc-row{display:flex;align-items:center;gap:12px;margin:4px 0 18px;flex-wrap:wrap}
.btn-find{border:1px solid var(--farrow-teal-deep);color:var(--farrow-teal-deep);background:var(--surface-card);font-weight:700;font-size:13.5px;padding:10px 15px;border-radius:11px;cursor:pointer;white-space:nowrap}
.btn-find:hover{background:var(--farrow-teal-tint);color:var(--text-primary)}
.loc-hint{font-size:12.5px;color:var(--muted);flex:1;min-width:140px}
.loc-hint.ok{color:#16a34a;font-weight:600}
.loc-hint.err{color:#dc2626;font-weight:600}
/* wrap on narrow screens — three footer buttons were squeezing into
   three-line pills at phone width */
.modal-foot{display:flex;gap:10px;justify-content:flex-end;border-top:1px solid var(--line);padding-top:16px;flex-wrap:wrap}
.btn-ghost.dark{background:var(--surface-page);color:var(--text-primary);border:1px solid var(--line)}
.btn-ghost.dark:hover:not(:disabled){background:var(--border-hairline)}

/* delete account (danger zone of Edit profile) */
.da-open{display:block;margin:14px auto 0;border:0;background:none;color:#dc2626;font-size:13px;font-weight:600;cursor:pointer;padding:4px 8px}
.da-open:hover{text-decoration:underline}
.da-warn{font-size:13.5px;line-height:1.5;color:#7f1d1d;background:#fef2f2;border:1px solid #fecaca;border-radius:11px;padding:12px 14px;margin:0 0 16px}
.btn-danger{background:#dc2626;color:#fff;border:0;padding:13px 22px;border-radius:999px;font-weight:700;font-size:15px;cursor:pointer;box-shadow:0 10px 24px -8px rgba(220,38,38,.6);transition:transform .15s,box-shadow .15s,opacity .15s}
.btn-danger:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 16px 30px -8px rgba(220,38,38,.7)}
.btn-danger:disabled{opacity:.45;cursor:default;box-shadow:none}

/* tabbar */
/* safe-area: keep the tab bar clear of the iPhone home indicator */
.tabbar{display:flex;border-top:1px solid var(--line);background:var(--surface-card);padding-bottom:env(safe-area-inset-bottom,0)}
.tab{flex:1;border:0;background:none;padding:11px 4px 13px;display:flex;flex-direction:column;align-items:center;gap:3px;font-family:inherit;font-size:11px;font-weight:600;color:var(--muted);cursor:pointer;transition:.15s;border-top:2px solid transparent;margin-top:-1px}
.tab span{font-size:19px;display:flex;align-items:center;justify-content:center;height:20px}
.tab.active{color:var(--farrow-teal-deep);border-top-color:var(--farrow-teal)}

/* sub-navs inside the Journey + Profile tabs */
.subnav{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:18px}
/* profile-pane tabs (Rankings/Trips/Map): underline-style text tabs.
   Kept separate from .chip (filter pills) and .subnav (shared with Journey). */
.ptab{border:0;background:none;padding:8px 2px 10px;font-family:inherit;font-size:14px;font-weight:600;color:var(--muted);cursor:pointer;transition:.15s;border-bottom:2px solid transparent}
.ptab.active{color:var(--ink);border-bottom-color:var(--ink)}
.pane.hidden{display:none}
.sect-head{margin-top:28px}

/* ---------- Phase 2: Instagram-style feed ---------- */
.icon-btn{border:1px solid var(--line);background:var(--surface-card);width:40px;height:40px;border-radius:50%;font-size:16px;cursor:pointer;transition:.15s;flex:none}
.icon-btn:hover{border-color:var(--brand)}
.fs-bar{display:flex;gap:10px;align-items:center;margin-bottom:10px}
.fs-bar input{flex:1;border:1px solid var(--line);border-radius:999px;padding:11px 18px;font-family:inherit;font-size:14.5px}
.fs-bar input:focus{border-color:var(--brand)}
.fs-bar input:focus:not(:focus-visible){outline:none}
.fs-bar .x{flex:none}

.pcard{background:var(--surface-card);border:1px solid var(--line);border-radius:18px;overflow:hidden;margin-bottom:18px;box-shadow:0 8px 24px -16px rgba(0,0,0,.3)}
.pauthor{display:flex;align-items:center;gap:10px;padding:12px 16px}
.pauthor .av{width:36px;height:36px;font-size:17px}
.pwho{display:flex;flex-direction:column;line-height:1.25}
.pwho b{font-size:14px}
.pwho span{font-size:12px;color:var(--muted)}
/* share cards: entry slideshow + context + caption.
   Instagram-ish proportions: capped card width, square media. */
.sharecard{max-width:440px;margin-left:auto;margin-right:auto}
.pcarousel{position:relative}
.ptrack{display:flex;overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:none;overscroll-behavior-x:contain}
.ptrack::-webkit-scrollbar{display:none}
.pslide{flex:0 0 100%;scroll-snap-align:center;aspect-ratio:1/1;background:var(--surface-page);position:relative}
.pslide img{width:100%;height:100%;object-fit:cover;display:block}
.pdots{position:absolute;bottom:10px;left:0;right:0;display:flex;gap:5px;justify-content:center;pointer-events:none}
.pdots span{width:7px;height:7px;border-radius:999px;background:rgba(255,255,255,.5);box-shadow:0 1px 2px rgba(0,0,0,.35);transition:width .2s ease,background-color .2s ease;pointer-events:auto;cursor:pointer}
/* mouse access: hover-revealed step arrows (same dark-scrim chrome as
   .trip-share/.bremove); touch keeps swipe only */
.car-arrow{display:none;position:absolute;top:50%;transform:translateY(-50%);width:34px;height:34px;border-radius:50%;border:0;background:rgba(0,0,0,.35);color:var(--on-teal);font-size:20px;line-height:1;cursor:pointer;z-index:4;align-items:center;justify-content:center;backdrop-filter:blur(2px)}
.car-arrow:hover{background:rgba(0,0,0,.55)}
.car-prev{left:10px}
.car-next{right:10px}
@media (hover:hover) and (pointer:fine){
  .pcarousel:hover .car-arrow,.pcarousel:focus-within .car-arrow{display:flex}
}
.pdots span.on{background:var(--surface-card);width:14px}
.sl-grad{display:flex;align-items:center;justify-content:center}
.sl-ic{font-size:56px;filter:drop-shadow(0 6px 14px rgba(0,0,0,.35))}
.sl-cap{position:absolute;left:0;right:0;bottom:0;display:flex;align-items:flex-end;justify-content:space-between;gap:10px;padding:30px 14px 12px;background:linear-gradient(transparent,rgba(0,0,0,.6));color:var(--on-teal);font-size:13.5px;font-weight:700}
.sl-cap span{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sl-cap em{font-style:normal;font-weight:600;opacity:.85}
.sl-cap b{flex:none;font-size:13px}
/* no-media fallback slide: name + rating + trip/location on the category gradient */
.sl-fb{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:7px;height:100%;padding:0 24px;color:var(--on-teal);text-align:center;filter:drop-shadow(0 2px 8px rgba(0,0,0,.35))}
.sl-fb b{font-family:system-ui,sans-serif;font-size:22px;font-weight:600;line-height:1.15}
.sl-fb b em{font-style:normal;font-family:system-ui,sans-serif;font-size:15px;font-weight:600;opacity:.85;white-space:nowrap}
.sl-fb .sl-fb-r{font-size:15px;font-weight:800}
.sl-fb small{font-size:13px;font-weight:600;opacity:.85}
.share-head{display:flex;align-items:baseline;justify-content:space-between;gap:10px;padding:13px 16px 0;cursor:pointer}
.share-head b{font-family:system-ui,sans-serif;font-size:17.5px;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.share-head span{font-size:12.5px;color:var(--muted);font-weight:600;flex:none}
.share-cap{font-size:14px;color:var(--text-primary);line-height:1.5;padding:7px 16px 0}
.tripfoot{display:flex;align-items:center;gap:10px;padding:12px 16px}
.share-foot{justify-content:flex-end}
.tf-view{border:0;background:var(--farrow-teal-deep);color:var(--on-teal);font-weight:700;font-size:13px;padding:9px 15px;border-radius:999px;cursor:pointer;white-space:nowrap;flex:none}
.tripfoot .save-btn{margin-left:0;flex:none}

/* ---- moment feed card (DESIGN.md §9) ------------------------------------
   A single-place card, NOT a slideshow: headline + score, then the place's
   photo and note. Everything below is scoped under .momentcard so the trip and
   day carousels above keep their presentation exactly as they are.
   Per §9 Exclusions every weight is set explicitly — the UA <b>/<strong>
   default is 700 and §4 allows 400/500/600 only — and every colour is a token. */
.momentcard{padding-bottom:2px}
.mc-top{display:flex;align-items:flex-start;gap:12px;padding:14px 16px 0}
.mc-id{display:flex;align-items:flex-start;gap:12px;min-width:0;flex:1;cursor:pointer}
/* §9 item 1: 48px, moment-card only. The shared .av base (and .pauthor .av,
   which still owns the 36px carousel-card avatar) is deliberately untouched. */
.mc-av{width:48px;height:48px;font-size:22px}
.mc-lines{display:flex;flex-direction:column;gap:3px;min-width:0}
/* §9 item 2: "[Name] rated [Place]" — name and place 600, the verb 400. */
.mc-head{font-size:15px;line-height:1.35;color:var(--text-primary);font-weight:400}
.mc-name,.mc-place{font-weight:600}
.mc-verb{font-weight:400}
/* §9 item 3: category icon + location, secondary. */
.mc-meta{display:flex;align-items:center;gap:6px;font-size:13px;font-weight:400;color:var(--text-secondary);min-width:0}
.mc-loc{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* §9 item 4: neutral score badge — ring + card background, NO value-based
   colour tiers (that would be a new accent decision under §1/§7). */
.mc-score{flex:none;display:flex;align-items:center;justify-content:center;width:44px;height:44px;border-radius:50%;border:1px solid var(--border-hairline);background:var(--surface-card);color:var(--text-primary);font-size:15px;font-weight:600;font-variant-numeric:tabular-nums}
/* §9 item 5: one image, square, and NO overlay — the name and rating that the
   carousel prints over the photo (.sl-cap) live in the headline and badge here,
   so nothing sits on top of the user's photo (§3). */
.mc-photo{margin-top:12px;aspect-ratio:1/1;background:var(--surface-page)}
.mc-photo img{width:100%;height:100%;object-fit:cover;display:block}
/* §9 item 6: posts.note, clamped to 3 lines, "See more" expands in place.
   The share-time caption is not rendered on moment cards (ruled, A10). */
.mc-note{padding:12px 16px 0}
.mc-note-body{font-size:14px;font-weight:400;line-height:1.5;color:var(--text-primary);display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden}
.mc-note-open .mc-note-body{display:block;-webkit-line-clamp:none;overflow:visible}
.mc-note-label{font-weight:600}
.mc-more{margin-top:2px;border:0;background:none;padding:0;font-family:inherit;font-size:14px;font-weight:500;color:var(--farrow-teal-deep);cursor:pointer}
.mc-more[hidden]{display:none}
/* §9 items 7-8: the existing engagement bar (data-eng targeting preserved),
   then the timestamp as its own element. .eng-btn already inherits
   --text-primary at rest; the active like takes teal here per §3. */
.mc-foot{justify-content:flex-start;padding-top:10px}
.momentcard .eng-n{font-weight:600}
.momentcard .eng-btn.liked{color:var(--farrow-teal-deep)}
.mc-time{margin-left:auto;flex:none;font-size:12.5px;font-weight:400;color:var(--text-secondary)}
/* likes + comments (per individual post): bar under the media on feed cards,
   compact row on trip-detail entries */
.ptrack{touch-action:manipulation} /* no double-tap zoom, keeps swipe/pan */
.pactions{display:flex;align-items:center;gap:4px}
.pengage{margin-right:auto} /* bottom-left of the card foot; Save/View stay right */
.pengage .pactions .eng-n:last-child{margin-right:0}
.dinfo .pactions{padding:8px 0 0}
.eng-btn{border:0;background:none;font-size:20px;line-height:1;cursor:pointer;padding:2px 4px;transition:transform .12s}
.eng-btn:active{transform:scale(1.25)}
.eng-btn.liked{animation:heartpop .25s ease}
@keyframes heartpop{40%{transform:scale(1.35)}}
.eng-n{font-size:13.5px;font-weight:700;color:var(--text-primary);margin-right:12px;cursor:pointer;min-width:12px}
.heart-burst{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:74px;pointer-events:none;z-index:5;filter:drop-shadow(0 8px 18px rgba(0,0,0,.35));animation:burst .65s ease forwards}
@keyframes burst{0%{transform:scale(.3);opacity:0}25%{transform:scale(1.15);opacity:1}70%{transform:scale(1);opacity:1}100%{transform:scale(.9);opacity:0}}

/* transient notice (uxNotice): failures with no inline slot — likes etc. */
.ux-notice{position:absolute;left:50%;transform:translateX(-50%);bottom:calc(76px + env(safe-area-inset-bottom,0px));background:var(--surface-card);border:1px solid var(--line);color:var(--text-primary);font-size:13px;font-weight:600;padding:9px 16px;border-radius:999px;box-shadow:var(--shadow);z-index:3000;opacity:0;transition:opacity .2s;pointer-events:auto;max-width:80%;text-align:center}
.ux-notice.show{opacity:1}
/* Honor the OS "reduce motion" setting everywhere — not just the uxNotice pill.
   The spinning globe, floating cards' bob, loading spinners, modal pop-in, heart
   burst, hover lifts and smooth scroll all stop. Loading spinners settle to a
   static ring (still a clear "busy" cue) instead of rotating. No JS depends on
   transitionend/animationend, so nulling them is behaviourally safe. */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
    scroll-behavior:auto !important;
  }
}

/* comment sheet */
.comment-modal{max-height:72vh;min-height:340px}
.cmt-list{flex:1;overflow-y:auto;padding:14px 20px;overscroll-behavior:contain}
.cmt{display:flex;gap:10px;align-items:flex-start;margin-bottom:14px}
.cmt.pending{opacity:.55}
.cmt-av{width:32px;height:32px;font-size:15px}
.cmt-body{flex:1;min-width:0}
.cmt-who{font-size:12px;color:var(--muted);cursor:pointer}
.cmt-who b{color:var(--ink);font-size:13px}
.cmt-body p{font-size:14px;line-height:1.45;color:var(--text-primary);margin-top:2px;overflow-wrap:break-word}
.cmt-del{border:0;background:none;color:var(--text-secondary);font-size:13px;cursor:pointer;padding:4px;flex:none}
.cmt-del:hover{color:#dc2626}
.cmt-err{padding:0 20px}
.cmt-err:empty{display:none}
.cmt-bar{display:flex;gap:10px;padding:12px 16px;border-top:1px solid var(--line)}
.cmt-bar input{flex:1;border:1px solid var(--line);border-radius:999px;padding:11px 16px;font-family:inherit;font-size:14.5px}
.cmt-bar input:focus{border-color:var(--brand)}
.cmt-bar input:focus:not(:focus-visible){outline:none}
.cmt-post{border:0;background:var(--farrow-teal-deep);color:var(--on-teal);font-weight:700;font-size:13.5px;padding:0 18px;border-radius:999px;cursor:pointer}

.cmt-avlink{flex:none;cursor:pointer}

/* user-list sheet (followers / following / likers) */
.ulist-modal{max-height:72vh;min-height:340px}
.ulist-list{flex:1;overflow-y:auto;padding:14px 20px;overscroll-behavior:contain}
.ulist-list .thinking{padding:10px 0}
.plink{cursor:pointer}
.plink:hover b,.plink:hover{text-decoration:underline}

/* ---------- notifications panel (2026-07-25) ---------- */
/* Same sheet geometry as the user-list sheet above — this is a list in a
   modal, and it should not invent a second shape for that. */
.notif-modal{max-height:72vh;min-height:340px}
.notif-list{flex:1;overflow-y:auto;padding:8px 12px 14px;overscroll-behavior:contain}
.notif-row{display:flex;align-items:center;gap:12px;width:100%;text-align:left;
  padding:11px 10px;border:0;border-radius:12px;background:transparent;cursor:pointer;
  font:inherit;color:var(--text-primary);transition:.15s}
.notif-row:hover{background:var(--surface-page)}
/* Unread rows: a teal wash plus the alert dot. The wash carries the state on
   its own (colour is not the only signal) and --farrow-teal-tint is already
   the token for a highlighted row, so nothing new is introduced here. */
.notif-row.unread{background:var(--farrow-teal-tint)}
.notif-row.unread:hover{background:var(--farrow-teal-tint);filter:brightness(.97)}
.notif-av{flex:none}
/* Actionable row (pending follow request, ruling 7). It reuses .freq-yes /
   .freq-no verbatim — those rules never depended on a .freq parent — and
   needs nothing but a shrink guard, since .notif-text already absorbs the
   free space the same way .freq-who did. */
.notif-row.notif-act>.freq-yes,.notif-row.notif-act>.freq-no{flex:none}
.notif-text{flex:1;min-width:0;font-size:14px;line-height:1.4}
.notif-text b{font-weight:700}
.notif-when{display:block;font-size:12px;color:var(--text-secondary);margin-top:2px}
/* Mirrors .bell-dot, minus the header ring: on a light row the badge needs no
   halo to separate it from the background. */
.notif-unread-dot{flex:none;width:8px;height:8px;border-radius:50%;background:var(--badge-alert)}

.feed-more{display:block;margin:2px auto 22px;border:1px solid var(--line);background:var(--surface-card);color:var(--farrow-teal-deep);font-weight:700;font-size:13px;padding:10px 24px;border-radius:999px;cursor:pointer;transition:.15s}
.feed-more:hover{border-color:var(--brand);background:var(--farrow-teal-tint);color:var(--text-primary)}
.feed-more:disabled{opacity:.6;cursor:default}

/* ---------- Phase 3: profiles ---------- */
#profile-head{margin-bottom:4px}
.prof-top{display:flex;align-items:center;gap:16px}
.prof-av{width:72px;height:72px;font-size:34px;flex:none}
.prof-names{flex:1;min-width:0}
.prof-names h2{font-size:24px}
.prof-names span{font-size:13px;color:var(--muted);font-weight:600}
.prof-follow{font-size:13px;color:var(--text-primary);margin-top:5px}
.prof-follow b{font-family:system-ui,sans-serif;font-size:14px}
.prof-bio{font-size:14px;color:var(--text-primary);margin-top:10px}
.prof-stats-sect{margin:18px 0 20px}
.prof-stats-head{font-size:16px;margin-bottom:10px}
.prof-stats{display:flex;gap:22px;align-items:center;flex-wrap:wrap}
.pstat{display:flex;flex-direction:column;align-items:center;gap:6px;line-height:1.2}
.pstat b{display:flex;align-items:center;justify-content:center;width:64px;height:64px;border-radius:50%;border:2px solid var(--ink);font-family:system-ui,sans-serif;font-size:20px}
.pstat span{font-size:11px;color:var(--muted);font-weight:700;text-transform:uppercase;letter-spacing:.04em}
#profile-private.hidden,#profile-body.hidden{display:none}
.prof-top .follow-btn{font-size:13px;padding:10px 18px;flex:none}

/* image avatars (uploaded) vs emoji avatars */
.avimg{overflow:hidden}
.avimg img{width:100%;height:100%;object-fit:cover;display:block}
/* .chip-av / .chip-av-emoji were the HEADER profile chip's circle until header
   v2 (2026-07-25) emptied that slot. They are kept and REUSED as-is for their
   new home: the bottom-nav Profile tab's icon (#nav-av below, api.js
   renderNavAvatar). The 22px base size is the old header size — the nav
   overrides it to 19px/17px on id specificity rather than changing it here,
   so nothing else that may adopt these classes inherits a nav-sized circle. */
.chip-av{display:inline-block;width:22px;height:22px;border-radius:50%;overflow:hidden;vertical-align:-6px}
.chip-av img{width:100%;height:100%;object-fit:cover;display:block}
/* Emoji fallback (no uploaded avatar). Shares .chip-av so the chip is one
   consistent circle either way — before 2026-07-25 this branch was a bare text
   node and rendered as a loose glyph next to the name. It needs its own field
   because there is no image to fill the circle: --surface-card matches the
   avatar placeholders elsewhere and keeps the emoji legible on teal. */
.chip-av-emoji{display:inline-flex;align-items:center;justify-content:center;background:var(--surface-card);font-size:13px;line-height:1}

/* ---- Profile-tab avatar (header v2, Ben-ruled 2026-07-25) ----
   The user's avatar rides the bottom-nav Profile tab icon. #nav-av is the tab's
   original <span> and shares the fixed `.tab span` icon box (20px, 18px under
   560px) with its four siblings, so the 11px label underneath does not shift on
   the Profile tab alone — the property the old shared glyph metrics gave for
   free. Only the circle INSIDE it is given fixed dimensions; sizes are on id
   specificity so `.tab span` cannot drive them. */
#nav-av .chip-av{width:19px;height:19px;vertical-align:middle}
#nav-av .chip-av-emoji{font-size:13px}
/* Fallback-on-failure (MANDATORY — Ben-ruled 2026-07-25). hydrateImages()
   REMOVES the <img> outright when the authenticated avatar fetch fails, which
   would otherwise leave an empty circle on the tab for the rest of the session.
   The default `user` icon sits UNDERNEATH as a ::before and the image merely
   covers it, so a removed <img> degrades to the default icon instead of a blank.
   Scoped :not(.chip-av-emoji) on purpose — the emoji branch draws the USER'S
   OWN avatar (R1) and must not have an icon rendered behind it.

   The icon arrives as a MASK, not a background image: masking lets
   `background-color:currentColor` colour it, so this fallback still inherits
   its colour from the tab exactly as the old glyph did and DESIGN.md §4a's
   "no hardcoded colours in SVG" holds. A background-image data-URI would have
   had to bake a hex value in. CSS cannot call icon(), so this is the one place
   icon geometry is restated outside icons.js — the render suite pins the two
   copies together (xss-render: "css user mask matches the icons.js path"). */
#nav-av .chip-av:not(.chip-av-emoji){position:relative}
#nav-av .chip-av:not(.chip-av-emoji)::before{content:'';position:absolute;inset:0;background-color:currentColor;-webkit-mask:var(--ico-user) center/13px no-repeat;mask:var(--ico-user) center/13px no-repeat}
#nav-av .chip-av img{position:relative}
/* The emoji branch is user data and keeps font metrics; only the no-avatar
   fallback inside it is an icon, sized to the glyph it replaced. */
#nav-av .chip-av-emoji .ico{width:13px;height:13px}
/* Mirrors the 560px tab-icon step-down at the foot of the media-query block. */
@media(max-width:560px){
  #nav-av .chip-av{width:17px;height:17px}
  #nav-av .chip-av-emoji{font-size:12px}
  #nav-av .chip-av-emoji .ico{width:12px;height:12px}
  #nav-av .chip-av:not(.chip-av-emoji)::before{-webkit-mask-size:12px;mask-size:12px}
}
.pauthor{cursor:pointer}
.freq{cursor:pointer}
.th-owner{text-decoration:underline;cursor:pointer}

/* rankings */
#ranks-chips{margin-bottom:14px}
.rk-row{display:flex;align-items:center;gap:12px;background:var(--surface-card);border:1px solid var(--line);border-radius:14px;padding:10px 14px;margin-bottom:9px}
.rk-n{font-family:system-ui,sans-serif;font-weight:700;font-size:16px;color:var(--muted);width:22px;text-align:center;flex:none}
.rk-thumb{width:46px;height:46px;border-radius:11px;flex:none;display:flex;align-items:center;justify-content:center;font-size:20px;overflow:hidden}
.rk-thumb img{width:100%;height:100%;object-fit:cover;display:block}
.rk-info{flex:1;min-width:0;line-height:1.3}
.rk-info b{font-size:14.5px;display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rk-info small{font-size:12px;color:var(--muted)}
.rk-rate{font-weight:800;color:var(--farrow-teal-deep);flex:none}

/* edit profile */
.ep-av-row{display:flex;align-items:center;gap:16px;margin-bottom:16px}
.ep-toggle{display:flex;align-items:center;gap:14px;border:1px solid var(--line);border-radius:14px;padding:13px 15px;cursor:pointer;margin-bottom:14px}
.ep-toggle>div{flex:1}
.ep-toggle b{font-size:14px;display:block}
.ep-toggle small{font-size:12px;color:var(--muted)}
/* Visually hidden, NOT display:none — the checkbox must stay keyboard-
   focusable (Tab + Space) with a visible ring on the switch. */
.ep-toggle{position:relative}
.ep-toggle input{position:absolute;opacity:0;width:1px;height:1px;pointer-events:none}
.ep-toggle input:focus-visible + .switch{outline:2px solid var(--farrow-teal-deep);outline-offset:2px}
.switch{width:44px;height:26px;border-radius:999px;background:var(--border-hairline);position:relative;flex:none;transition:.2s}
.switch::after{content:"";position:absolute;top:3px;left:3px;width:20px;height:20px;border-radius:50%;background:var(--surface-card);box-shadow:0 2px 5px rgba(0,0,0,.25);transition:.2s}
.ep-toggle input:checked + .switch{background:var(--brand)}
.ep-toggle input:checked + .switch::after{left:21px}

/* journal (drafts + sharing) */
#journal-trips{display:grid;grid-template-columns:1fr 1fr;gap:18px}
.draft-pill{position:absolute;top:10px;right:10px;background:var(--surface-card);color:#b45309;font-size:11px;font-weight:800;padding:3px 9px;border-radius:999px;box-shadow:0 4px 12px -4px rgba(0,0,0,.35);z-index:1}
.draft-badge{font-size:10.5px;font-weight:800;color:#b45309;background:#fef3c7;border:1px solid #fcd34d;padding:2px 8px;border-radius:6px;display:inline-block;margin-bottom:5px;margin-left:5px}
.droute{font-size:13px;font-weight:700;color:var(--text-secondary);margin-top:2px;letter-spacing:.3px}
.trip-share{border:0;background:rgba(0,0,0,.3);color:var(--on-teal);font-size:12px;font-weight:700;padding:7px 12px;border-radius:999px;cursor:pointer;backdrop-filter:blur(4px);z-index:1}
.trip-share:hover:not(:disabled){background:rgba(0,0,0,.55)}
.trip-share:disabled{opacity:.45;cursor:default}
.share-sub{margin:-4px 0 12px}
.share-list{background:var(--surface-page);border:1px solid var(--line);border-radius:12px;padding:11px 14px;font-size:13px;margin-bottom:14px}
.share-list b{display:block;margin-bottom:6px;font-size:12.5px}
.share-list.muted{color:var(--muted);font-style:italic}
.share-item{padding:2px 0}

/* trips list */
.trips-head{align-items:center}
.new-trip-btn{border:0;background:var(--farrow-teal-deep);color:var(--on-teal);font-weight:700;font-size:14px;padding:11px 18px;border-radius:999px;cursor:pointer;transition:transform .15s;white-space:nowrap}
.new-trip-btn:hover{transform:translateY(-2px)}
#trips-list{display:grid;grid-template-columns:1fr 1fr;gap:18px}
.tcard{background:var(--surface-card);border:1px solid var(--line);border-radius:18px;overflow:hidden;cursor:pointer;box-shadow:0 8px 24px -16px rgba(0,0,0,.3);transition:.15s}
.tcard:hover{transform:translateY(-4px);box-shadow:var(--shadow)}
.tcover{height:120px;display:flex;align-items:center;justify-content:center;position:relative}
.temoji{font-size:46px;filter:drop-shadow(0 4px 10px rgba(0,0,0,.3))}
.tbody{padding:15px 17px}
.tbody h3{font-size:21px;margin-bottom:4px}
.tmeta{font-size:12.5px;color:var(--muted);font-weight:600}
.tsum{font-size:13.5px;color:var(--text-primary);margin:7px 0 9px}
.tstats{font-size:12.5px;color:var(--farrow-teal-deep);font-weight:700}

/* trip detail (popup modal) */
.trip-view-modal{max-width:540px;width:100%;max-height:88vh;overflow-y:auto;padding:22px;overscroll-behavior:contain}
#add-modal{z-index:2100}
.back{border:0;background:var(--surface-page);color:var(--text-primary);font-weight:700;font-size:13.5px;padding:9px 15px;border-radius:999px;cursor:pointer;margin-bottom:16px}
.back:hover{background:var(--border-hairline)}
.trip-hero{border-radius:20px;padding:22px;color:var(--on-teal);display:flex;align-items:center;gap:18px;margin-bottom:16px;position:relative;overflow:hidden;box-shadow:0 14px 34px -16px rgba(0,0,0,.4)}
.trip-hero::after{content:"";position:absolute;inset:0;background:linear-gradient(120deg,rgba(0,0,0,.15),rgba(0,0,0,.4));pointer-events:none}
.th-emoji{font-size:54px;position:relative;z-index:1;filter:drop-shadow(0 4px 10px rgba(0,0,0,.35))}
.th-text{position:relative;z-index:1}
.th-text h2{font-size:30px}
.th-meta{font-size:14px;opacity:.95;font-weight:600;margin-top:3px}
.th-stats{font-size:13px;opacity:.9;margin-top:8px}
/* Owner hero only (friend hero never gets .has-actions): stack the old
   emoji+text row above a normal-flow action bar. */
.trip-hero.has-actions{flex-direction:column;align-items:stretch;gap:14px}
.th-main{display:flex;align-items:center;gap:18px}
.th-actions{display:flex;flex-wrap:wrap;gap:8px;position:relative;z-index:1}
.th-actions button{min-width:34px;min-height:34px;padding:0;font-size:16px;display:inline-flex;align-items:center;justify-content:center}
@media (pointer:coarse){
  .th-actions button{min-width:44px;min-height:44px}
}

/* ---------- touch targets (pointer:coarse only — desktop keeps its density).
   The audit measured the small controls at 21–32px; the floor here follows the
   ~44px guideline the .th-actions rule above already established. ---------- */
@media (pointer:coarse){
  .x{width:44px;height:44px;font-size:16px}
  .icon-btn{width:44px;height:44px}
  .dact{width:40px;height:40px;font-size:14px}
  .dactions{gap:8px}
  .dentry .dinfo{padding-right:48px} /* room for the wider action column */
  .bremove{width:40px;height:40px;font-size:14px}
  .cmt-del{padding:12px 14px}
  .eng-btn{padding:9px 10px}
  .eng-n{padding:9px 4px}
  .chip,.pchip{padding:11px 16px;min-height:44px}
  .ptab{padding:11px 4px 13px}
  .follow-btn,.freq-yes{padding:11px 17px}
  .freq-no{padding:11px 14px}
  .save-btn{padding:11px 17px}
  .chip-signout{padding:8px 13px}
  /* Guarantee the 44px floor independent of font-size — padding alone left the
     follow / accept / decline / save / sign-out pills at ~34-38px. */
  .follow-btn,.freq-yes,.freq-no,.save-btn,.chip-signout{
    min-height:44px;display:inline-flex;align-items:center;justify-content:center}
  .da-open{padding:12px 14px}
  .jrn-back{padding:10px 8px 12px}
  .pr-expand{padding:9px 15px}
  .prof-follow .plink{display:inline-block;padding:6px 2px}
  input[type=range]{height:32px} /* 6px track was nearly ungrabbable on touch */
  /* Landing nav + hero secondary CTAs to the 44px floor. */
  .btn-nav,.hero-cta .btn-ghost{min-height:44px;display:inline-flex;align-items:center;justify-content:center}
}

/* ---------- iOS focus-zoom guard: Safari zooms the whole layout when a
   focused input's font-size is under 16px. Touch devices only — desktop
   keeps the 14.5px design size. ---------- */
@media (pointer:coarse){
  .fld input,.fld textarea,.fld select,.fs-bar input,.cmt-bar input,.wiz-city-input,.ctl select{font-size:16px}
}
.trip-filters{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:20px}

/* timeline */
.timeline{position:relative}
.dayrow{display:flex;gap:14px}
.daymark{display:flex;flex-direction:column;align-items:center;flex:none;width:34px}
.daynum{width:34px;height:34px;border-radius:50%;background:var(--farrow-teal-deep);color:var(--on-teal);font-weight:800;font-size:14px;display:flex;align-items:center;justify-content:center;flex:none}
.dayline{flex:1;width:2px;background:var(--line);margin:4px 0}
.dayrow:last-child .dayline{display:none}
.daybody{flex:1;padding-bottom:22px}
.dayhead{font-family:system-ui,sans-serif;font-size:17px;font-weight:600;margin:5px 0 12px;padding-top:4px}
.dentry{display:flex;gap:12px;background:var(--surface-card);border:1px solid var(--line);border-radius:14px;padding:11px 13px;margin-bottom:10px;box-shadow:0 6px 18px -16px rgba(0,0,0,.3)}
.dthumb{width:46px;height:46px;border-radius:11px;flex:none;display:flex;align-items:center;justify-content:center;font-size:22px}
.dinfo{flex:1;min-width:0}
.dtag{font-size:10.5px;font-weight:700;color:var(--on-teal);padding:2px 8px;border-radius:6px;display:inline-block;margin-bottom:5px}
.dname{font-size:15px;font-weight:700}
.drate{color:var(--farrow-teal-deep);font-size:13px;font-weight:700;margin-left:4px}
.dnote{font-size:13px;color:var(--text-secondary);margin-top:2px}
.dempty{font-size:14px;color:var(--text-secondary);text-align:center;padding:22px 16px;line-height:1.5}
.day-add{border:1px dashed var(--border-hairline);background:var(--surface-page);color:var(--farrow-teal-deep);font-weight:700;font-size:13px;padding:9px 14px;border-radius:11px;cursor:pointer;width:100%;transition:.15s}
.day-add:hover{background:var(--farrow-teal-tint);border-color:var(--brand);color:var(--text-primary)}

/* add-place trip pill + cover picker + planner badges */
.trip-pill{display:inline-block;background:var(--surface-page);border-radius:999px;padding:7px 14px;font-size:13px;color:var(--text-primary);margin-bottom:14px}
.trip-pill b{color:var(--ink)}
/* Batch A: openAdd swaps the modal between trip mode (trip pill + day <select>)
   and moment mode (plain date field). Per the per-component .hidden convention
   documented at .bell-dot and #mc-pane-*, EACH toggled element needs its own
   rule — a bare .hidden styles nothing in this codebase, so without this line
   both modes would render stacked. */
#add-trip-pill.hidden,#f-day-fld.hidden,#f-date-fld.hidden{display:none}
/* Same convention, same omission: app.html ships #f-route-fld with .hidden and
   renderCatPick() toggles it on chosenCat!=='flight', but the backing rule was
   never written — so Route rendered on EVERY category. Harmless-looking, but
   savePost() nulls route unless the category is flight, so anything typed there
   on a hotel/food entry was silently dropped on save. Kept as its own rule
   rather than folded into the line above: the two are toggled by different
   code paths (openAdd vs renderCatPick) and each has its own render pin. */
#f-route-fld.hidden{display:none}
.cover-pick{display:grid;grid-template-columns:repeat(6,1fr);gap:8px;margin-bottom:14px}
.cover-opt{height:46px;border-radius:11px;display:flex;align-items:center;justify-content:center;font-size:22px;cursor:pointer;border:2px solid transparent;opacity:.7;transition:.12s}
.cover-opt.sel{opacity:1;border-color:var(--ink);transform:scale(1.05)}
/* "live AI" status pill. The leading ● is a CSS dot, not an icon (Ben left the
   choice open): it is a status indicator rather than a symbol, Lucide's `circle`
   is a stroked ring at 2px and would read as an outline instead of a filled
   dot, and currentColor already carries the pill's semantic green. Same shape
   as .ph-dot / .bell-dot, which are dots for the same reason. */
.ai-live{font-size:11px;font-weight:700;color:#16a34a;background:#dcfce7;padding:3px 10px;border-radius:999px;margin-left:8px;vertical-align:middle}
.ai-live::before{content:'';display:inline-block;width:6px;height:6px;border-radius:50%;background:currentColor;margin-right:5px;vertical-align:.1em}
.ai-sample{font-size:11px;font-weight:600;color:#9a6b00;background:#fef3c7;padding:3px 10px;border-radius:999px;margin-left:8px;vertical-align:middle}

/* long user text: wrap or ellipsize instead of overflowing rows and cards */
.share-cap,.dname,.dnote,.droute,.prof-bio,.prof-names h2,.tbody h3,.bcard h4,.gate-card p{overflow-wrap:break-word}
.pwho{min-width:0}
.pwho b,.pwho span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.freq-who{min-width:0}
.freq-who b,.freq-who small{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* footer */
.foot{background:var(--ink);color:var(--on-dark-secondary);text-align:center;padding:46px 24px}
.foot .brand{justify-content:center;color:var(--on-dark);margin-bottom:8px}
.foot p{font-size:14px;color:var(--on-dark-secondary)}
/* Attribution links were the same grey as the surrounding text — undistinguishable
   from prose. Brighten + underline so they read as links (AA on the --ink footer). */
.attribution a{color:var(--on-dark);text-decoration:underline}

@media(max-width:880px){
  .hero-inner{grid-template-columns:1fr} .hero-art{display:none}
  .feat-grid{grid-template-columns:1fr 1fr}
  .nav-links>a{display:none}
  #trips-list,#journal-trips,#bucket{grid-template-columns:1fr}
  .device{height:680px}
}
@media(max-width:560px){
  .feat-grid{grid-template-columns:1fr}
  .tab span{font-size:17px;height:18px} .tab{font-size:10px}
}

/* ============ JOURNEY ============ */
/* plan → journey bridge button */
.jrn-cta{width:100%;margin-top:12px;background:var(--surface-card);border:1px dashed var(--farrow-teal-deep);color:var(--farrow-teal-deep);font-weight:700;font-size:14px;padding:12px;border-radius:13px;cursor:pointer;transition:.15s}
.jrn-cta:hover{background:var(--farrow-teal-tint);color:var(--text-primary)}

/* ---------- auth gate + API-era additions (Phase 4) ---------- */
.device{position:relative}
.auth-gate{position:absolute;inset:0;z-index:500;background:rgba(250,250,248,.92);backdrop-filter:blur(6px);display:flex;align-items:center;justify-content:center;padding:24px}
.auth-gate.hidden{display:none}
.gate-card{background:var(--surface-card);border:1px solid var(--line);border-radius:22px;padding:34px 38px;max-width:400px;width:100%;text-align:center;box-shadow:0 30px 70px -30px rgba(0,0,0,.35)}
.gate-logo{font-size:34px;color:var(--farrow-teal-deep);margin-bottom:6px}
.gate-card h3{font-size:24px;font-family:system-ui,sans-serif;margin-bottom:6px}
.gate-card p{font-size:14px;color:var(--muted);margin-bottom:18px}
.gate-card .fld{text-align:left;margin-bottom:12px}
.gate-card .btn-primary{width:100%;margin-top:6px}
.chip-signout{border:1px solid var(--line);background:var(--surface-card);border-radius:999px;font-size:12px;font-weight:700;padding:4px 10px;cursor:pointer;color:var(--text-primary)}
.chip-signout:hover{border-color:var(--brand);color:var(--farrow-teal-deep)}
.bremove{position:absolute;top:10px;left:12px;z-index:2;border:0;border-radius:50%;width:26px;height:26px;background:rgba(0,0,0,.35);color:var(--on-teal);font-size:12px;cursor:pointer;backdrop-filter:blur(4px)}
.bremove:hover{background:rgba(0,0,0,.6)}
.pin-results{display:flex;flex-direction:column;gap:8px;margin-top:4px}
.pin-opt{display:flex;flex-direction:column;align-items:flex-start;gap:2px;text-align:left;border:1px solid var(--line);background:var(--surface-page);border-radius:12px;padding:10px 14px;cursor:pointer;font-size:14px;transition:.15s}
.pin-opt:hover{border-color:var(--brand);background:var(--farrow-teal-tint)}
.pin-opt small{color:var(--muted);font-size:12px}

/* ---------- Phase 5: friends, photos, edit/delete ---------- */
.freq{display:flex;align-items:center;gap:10px;border:1px solid var(--line);background:var(--surface-page);border-radius:12px;padding:9px 12px;margin-bottom:8px}
.freq .av{width:34px;height:34px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:17px;flex:none}
.freq-who{flex:1;display:flex;flex-direction:column;line-height:1.25}
.freq-who small{color:var(--muted);font-size:12px}
.freq-yes,.follow-btn{border:0;background:var(--farrow-teal-deep);color:var(--on-teal);font-weight:700;font-size:12px;padding:7px 13px;border-radius:999px;cursor:pointer}
.freq-yes:disabled,.freq-no:disabled,.follow-btn:disabled,.save-btn:disabled{opacity:.55;cursor:default}
.follow-btn.on{background:var(--border-hairline);color:var(--text-primary)}
.freq-no{border:1px solid var(--line);background:var(--surface-card);color:var(--text-secondary);font-size:12px;padding:7px 10px;border-radius:999px;cursor:pointer}

/* ---------- Phase 4: Discover (search + popular grid) ---------- */
.disc-bar{margin-bottom:16px;position:relative}
/* Leading search glyph + type=search semantics (was a plain text pill with no
   search affordance). Native clear decorations hidden — we render our own ✕. */
.fs-ico{position:absolute;left:17px;top:50%;transform:translateY(-50%);font-size:15px;line-height:1;pointer-events:none;opacity:.6;z-index:1}
.disc-bar input{padding-left:44px}
.disc-bar input::-webkit-search-cancel-button,.disc-bar input::-webkit-search-decoration{-webkit-appearance:none;appearance:none}
.disc-results.hidden,#disc-popular.hidden,#disc-clear.hidden{display:none}
.disc-sect{margin-bottom:20px}
.disc-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(148px,1fr));gap:12px;margin-top:8px}
.disc-tile{cursor:pointer;border-radius:14px;overflow:hidden;transition:transform .12s}
.disc-tile:hover{transform:translateY(-2px)}
.dt-media{position:relative;aspect-ratio:1/1;border-radius:14px;overflow:hidden;background:var(--surface-page);display:flex;align-items:center;justify-content:center}
.dt-media img{width:100%;height:100%;object-fit:cover;display:block}
.dt-emoji{width:100%;height:100%;display:flex;align-items:center;justify-content:center;font-size:40px}
.dt-media.dt-trip{font-size:40px;background:var(--farrow-teal)}
.dt-likes{position:absolute;left:8px;bottom:8px;background:rgba(0,0,0,.55);color:var(--on-teal);font-size:12px;font-weight:700;padding:3px 8px;border-radius:999px;backdrop-filter:blur(2px)}
.dt-cap{padding:7px 2px 2px;line-height:1.25}
.dt-cap b{display:block;font-size:13.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dt-cap small{color:var(--muted);font-size:12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block}
/* Skeleton loaders — hold the layout at final shape (spinners stay only where
   the shape is unknown, e.g. the auth gate). Pulse stops under reduced-motion. */
.skel{background:var(--border-hairline);border-radius:8px;overflow:hidden;animation:skelpulse 1.3s ease-in-out infinite}
@keyframes skelpulse{0%,100%{opacity:.9}50%{opacity:.5}}
.dt-media.skel{border-radius:14px}
.sk-line{display:block;height:11px;border-radius:6px;margin-top:7px}
.sk-line.w60{width:60%}
.dphotos{display:flex;gap:6px;margin-top:8px;align-items:center;flex-wrap:wrap}
.dphoto{width:58px;height:58px;object-fit:cover;border-radius:9px;border:1px solid var(--line)}
.dphoto-add{width:58px;height:58px;border:1px dashed var(--border-hairline);background:var(--surface-page);border-radius:9px;font-size:14px;cursor:pointer;color:var(--muted)}
.dphoto-add:hover{border-color:var(--brand);color:var(--farrow-teal-deep)}
.dentry{position:relative}
.dactions{display:flex;flex-direction:column;gap:6px;transition:.15s;position:absolute;top:10px;right:10px}
/* hide-until-hover only where hover exists; on touch the buttons stay visible */
@media (hover:hover) and (pointer:fine){
  .dactions{opacity:0}
  .dentry:hover .dactions{opacity:1}
}
.dact{border:1px solid var(--line);background:var(--surface-card);border-radius:8px;width:26px;height:26px;font-size:12px;cursor:pointer;color:var(--text-secondary)}
.dact:hover{border-color:var(--brand);color:var(--farrow-teal-deep)}
/* entry already shared (S3): ✓ state — still tappable, re-share confirms */
.dact-shared{color:#16a34a;border-color:#86efac;background:#f0fdf4}
.dact-shared:hover{border-color:#16a34a;color:#15803d}

/* ---------- S3: compose "+" + chooser + trip picker ---------- */
.compose-btn{font-size:22px;color:var(--farrow-teal-deep);line-height:1}
.compose-btn:hover{background:var(--farrow-teal-tint)}
.profile-compose{display:block;margin-left:auto;margin-bottom:10px}
/* Own-profile action row: sign out (left) + compose (right), right-aligned as
   a group. Sign out moved here on 2026-07-25 when the header chip went
   icon-only — this is the app's only sign-out entry point. .profile-compose
   keeps margin-left:auto to hold the + at the right edge, but its own
   margin-bottom is dropped so it doesn't stack with the row's. */
.prof-actions{display:flex;align-items:center;gap:10px;margin-bottom:10px}
.prof-actions .profile-compose{margin-bottom:0}
.compose-opt{display:flex;flex-direction:column;align-items:flex-start;gap:3px;text-align:left;width:100%;border:1px solid var(--line);background:var(--surface-page);border-radius:14px;padding:14px 16px;cursor:pointer;font-family:inherit;font-size:15px;transition:.15s;margin-bottom:10px}
.compose-opt:hover{border-color:var(--brand);background:var(--farrow-teal-tint)}
.compose-opt b{font-size:16px}
.compose-opt small{color:var(--muted);font-size:12.5px}
.tp-row{cursor:pointer;transition:.15s}
.tp-row:hover{border-color:var(--brand)}
.tp-cover{width:40px;height:40px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-size:20px;flex:none}
.tp-sel{border-color:var(--brand);background:var(--farrow-teal-tint)}
.tp-check{color:var(--farrow-teal-deep);font-weight:800;font-size:15px}
.tp-new .tp-cover{background:var(--farrow-teal-tint);color:var(--farrow-teal-deep);font-weight:800}
/* S3.1 fix: mcShowStep toggles .hidden on the three panes but no rule backed
   it (this codebase scopes .hidden per component — there is no global rule),
   so all three compose panes rendered stacked. Pre-existing in S3. */
#mc-pane-place.hidden,#mc-pane-trip.hidden,#mc-pane-caption.hidden{display:none}
.mc-photo{width:auto;padding:0 10px;font-size:12px;white-space:nowrap}
.trip-hero{position:relative}
.trip-del{border:0;background:rgba(0,0,0,.3);color:var(--on-teal);font-size:12px;font-weight:700;padding:7px 12px;border-radius:999px;cursor:pointer;backdrop-filter:blur(4px)}
.trip-del:hover{background:rgba(220,38,38,.75)}
.trip-edit{border:0;background:rgba(0,0,0,.3);color:var(--on-teal);font-size:12px;font-weight:700;padding:7px 12px;border-radius:999px;cursor:pointer;backdrop-filter:blur(4px);z-index:1}
.trip-edit:hover{background:rgba(0,0,0,.55)}

/* ---------- landing: nav auth buttons ---------- */
#nav-auth{display:flex;gap:10px;align-items:center}
.btn-nav{padding:9px 16px;font-size:13.5px;display:inline-block}
a.btn-nav{line-height:1}

/* ---------- landing: static screenshot frames (swap .shot-ph for real <img class="shot-img">) ---------- */
.shots{background:var(--surface-page);padding:90px 24px}
.shots-row{display:grid;grid-template-columns:repeat(4,1fr);gap:24px;max-width:1160px;margin:0 auto}
.shot{display:flex;flex-direction:column;gap:14px}
.shot-screen{aspect-ratio:9/17;border-radius:28px;border:7px solid var(--surface-dark);background:var(--surface-card);overflow:hidden;position:relative;box-shadow:0 30px 60px -25px rgba(0,0,0,.45)}
.shot-img{width:100%;height:100%;object-fit:cover;display:block}
.shot-ph{position:absolute;inset:0;display:flex;flex-direction:column}
.ph-top{height:36px;flex:none;display:flex;align-items:center;gap:6px;padding:0 13px;font-weight:800;font-size:12px;border-bottom:1px solid var(--line)}
.ph-dot{width:7px;height:7px;border-radius:50%;background:#22c55e;margin-left:auto;box-shadow:0 0 0 3px rgba(34,197,94,.18)}
.ph-body{flex:1;padding:11px;display:flex;flex-direction:column;gap:9px;min-height:0;justify-content:space-between}
.ph-line{height:8px;border-radius:99px;background:var(--border-hairline);flex:none}
.ph-line.w40{width:40%}.ph-line.w50{width:50%}.ph-line.w60{width:60%}.ph-line.w70{width:70%}.ph-line.w80{width:80%}.ph-line.w90{width:90%}
.ph-map{flex:1;border-radius:12px;position:relative;border:1px solid var(--line)}
.ph-map span{position:absolute;font-size:15px;filter:drop-shadow(0 2px 3px rgba(0,0,0,.25))}
.ph-chiprow{display:flex;gap:6px;flex:none}
.ph-chiprow i{font-style:normal;font-size:9.5px;font-weight:700;border:1px solid var(--line);border-radius:999px;padding:4px 8px;color:var(--text-secondary);background:var(--surface-card)}
.ph-card{border:1px solid var(--line);border-radius:12px;padding:8px;display:flex;flex-direction:column;gap:7px;background:var(--surface-card)}
.ph-cover{height:56px;border-radius:9px;display:flex;align-items:center;justify-content:center;font-size:24px;flex:none}
.ph-cover.tall{height:72px}
.ph-day{display:flex;gap:8px;align-items:center}
.ph-day em{font-style:normal;width:24px;height:24px;flex:none;border-radius:50%;background:var(--farrow-teal-deep);color:var(--on-teal);font-weight:800;font-size:10px;display:flex;align-items:center;justify-content:center}
.ph-day.sq em{border-radius:7px;width:28px}
.ph-day>div{flex:1;display:flex;flex-direction:column;gap:5px}
.ph-intro{border:1px solid #e3e6ff;background:linear-gradient(135deg,#eef0ff,#fdf0f6);border-radius:10px;padding:9px;display:flex;flex-direction:column;gap:6px}
.ph-book{background:var(--ink);color:var(--on-teal);font-size:10.5px;font-weight:700;text-align:center;border-radius:999px;padding:8px}
.shot figcaption{text-align:center}
.shot figcaption b{font-family:system-ui,sans-serif;font-size:17px;display:block}
.shot figcaption span{font-size:13px;color:var(--muted)}
@media(max-width:880px){.shots-row{grid-template-columns:1fr 1fr}}
@media(max-width:560px){.shots-row{grid-template-columns:1fr;max-width:280px}}

/* ---------- /app: full-page app shell ---------- */
.app-page{background:var(--surface-page)}
.app-page .app-wrap{min-height:100vh;padding:24px;display:flex}
/* 100dvh where supported: iOS Safari's dynamic bottom bar makes 100vh taller
   than the visible viewport, which clipped the tab bar behind it. */
.app-page .device{width:100%;max-width:1200px;height:calc(100vh - 48px);height:calc(100dvh - 48px);min-height:560px;margin:auto}
/* On the teal header the wordmark label goes white. .app-brand is 18px/800
   (see above), which is exactly §2's ">= 18px bold" threshold, so --on-teal
   at 2.93:1 is permitted here — the same allowance the logo and icons get.
   Nothing smaller in this bar may take it. */
.app-page .app-brand{color:var(--on-teal)}

/* "← Back to site": the web-only way out of /app, pinned top-left OUTSIDE the
   app container. .app-page .app-wrap is min-height:100vh, so an in-flow link
   would either add page scroll or sit below the fold — hence position:fixed.
   z-index clears the device frame; it sits in the .app-wrap's 24px gutter.
   The header logo's href="/" is an independent second way back. */
.back-to-site{position:fixed;top:10px;left:14px;z-index:10;font-size:12px;font-weight:700;color:var(--muted);text-decoration:none;padding:6px 8px;border-radius:8px}
.back-to-site:hover{color:var(--farrow-teal-deep);background:var(--surface-card)}
@media(pointer:coarse){.back-to-site{min-height:44px;display:inline-flex;align-items:center;padding:6px 10px}}
/* Native kill-switch convention (established 2026-07-25). The Capacitor build
   sets `is-native` on <body> and every web-only affordance marked .native-hide
   disappears — one flag, one rule. Add .native-hide to future web-only chrome
   rather than inventing a second mechanism. */
body.is-native .native-hide{display:none}
