﻿/* ═══════════════════════════════════════════════
   DESIGN TOKENS — Warm cream + tomato red
═══════════════════════════════════════════════ */
@font-face{
  font-family:'Nunito';font-style:normal;font-weight:200 1000;font-display:swap;
  src:url('../fonts/Nunito-Variable.ttf') format('truetype');
}
@font-face{
  font-family:'Nunito';font-style:italic;font-weight:200 1000;font-display:swap;
  src:url('../fonts/Nunito-Italic-Variable.ttf') format('truetype');
}
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}
:root{
  /* Warm cream base */
  --cream:#FBF3D9;
  --cream-2:#F5EBC1;
  --cream-3:#EEE0A6;
  --white:#FFFDF5;
  --paper:#FEF9E5;

  /* Deep tomato/burgundy */
  --primary:#B92626;
  --primary-2:#8C1919;
  --primary-3:#5F0F0F;
  --primary-tint:#F8DFD3;
  --primary-glow:rgba(185,38,38,.28);

  /* Warm accent orange */
  --accent:#E8843C;
  --accent-2:#D66A22;

  /* Category colors — warm palette */
  --cat-restaurant:#B92626;
  --cat-street:#E8843C;
  --cat-snack:#D64B7A;
  --cat-cafe:#7A4E2F;

  /* Text */
  --text:#2A1810;
  --text2:#6B4A38;
  --text3:#9C7F6B;
  --line:rgba(42,24,16,.10);
  --line-2:rgba(42,24,16,.16);

  /* Metrics */
  --radius:18px;
  --radius-lg:24px;
  --sheet-radius:28px 28px 0 0;
  --safe-bottom:env(safe-area-inset-bottom,0px);
  --safe-top:env(safe-area-inset-top,0px);
  --tab-h:64px;
  --ribbon-h:var(--safe-top); /* tên biến giữ nguyên (dùng ở .screen/#toast) dù ribbon đã bỏ — khỏi phải sửa mọi nơi dùng */
  --iab-h:48px;

  --font-display:'Nunito',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
  --font-body:'Nunito',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;

  /* Motion — iOS-style easing curves */
  --ease-spring:cubic-bezier(.34,1.56,.64,1);   /* overshoot bounce */
  --ease-out:cubic-bezier(.16,1,.3,1);          /* soft deceleration */
  --ease-ios:cubic-bezier(.32,.72,0,1);         /* snappy iOS default */
  --press:.94;                                   /* tap scale-down */
}
html,body{height:100%;overflow:hidden;background:var(--cream);color:var(--text);font-family:var(--font-body);font-size:15px;line-height:1.5;font-weight:500;-webkit-font-smoothing:antialiased}

/* Icon system — SVG sprite (icons/sprite.svg), referenced via <use>. Sized
   in em so it scales with whatever font-size/line-height context it sits
   in, same as the emoji it replaces; color defaults to currentColor so it
   auto-matches surrounding text (buttons on a solid color background get
   this for free — see js/utils.js icon() for the helper that emits this). */
.icon{display:inline-block;width:1em;height:1em;flex-shrink:0;vertical-align:-.15em;color:currentColor}

/* Desktop / wide screen: center app in a phone-shaped column */
@media (min-width:560px){
  html{background:#2A1810}
  body{
    max-width:440px;margin:0 auto;position:relative;background:var(--cream);
    box-shadow:0 0 40px rgba(0,0,0,.6),0 0 0 1.5px var(--primary-2);
    transform:translateZ(0);
  }
}
button{border:none;background:none;color:inherit;cursor:pointer;font:inherit;font-weight:600}
input,textarea,select{font-family:var(--font-body)}

/* ─── Screens ─── */
/* Screens tràn viền — chạm hẳn cạnh dưới màn hình. Tab bar là pill nổi
   phía trên, không chiếm layout height nữa (trước dùng bottom:var(--tab-h)
   để chừa chỗ; giờ tab bar overlay lên trên nội dung, đúng như prototype). */
.screen{position:fixed;top:var(--ribbon-h);bottom:0;left:0;right:0;display:flex;flex-direction:column;overflow:hidden;background:var(--cream)}
.screen.hidden{display:none}

/* ═══════════════════════════════════════════════
   BOTTOM TAB BAR
═══════════════════════════════════════════════ */
/* Tab bar — floating pill với margin 10px mọi cạnh (đúng prototype:
   position:absolute; left:10px; right:10px; bottom:10px; border-radius:24px).
   Có label bé dưới icon. Check-in là vòng tròn đỏ nhỏ inline với các tab khác.
   Ẩn khi lướt feed xuống, hiện lại khi lướt lên. */
.tabbar{
  position:fixed;left:10px;right:10px;bottom:calc(var(--safe-bottom) + 10px);
  z-index:100;
  background:var(--white);border-top:none;border-radius:28px;
  display:flex;align-items:center;padding:10px 6px;
  box-shadow:0 12px 30px rgba(42,24,16,.24);
  transition:transform .25s ease,opacity .2s ease;
}
.tabbar.scroll-hidden,
/* Same off-screen state, but toggled by CheckinCtrl when the capture-
   preview sheet is open so the send/toggle/caption controls at
   bottom:0 aren't covered by the floating tab bar (2026-09-21). */
.tabbar.checkin-hidden{
  transform:translateY(140%);opacity:0;pointer-events:none;
}
.tab-btn{
  flex:1;padding:5px 0;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;
  color:var(--text3);position:relative;
  transition:color .18s;background:none;border:none;
}
.tab-btn .tab-ico{
  font-size:1.45rem;line-height:1;display:flex;align-items:center;justify-content:center;
  transition:transform .2s cubic-bezier(.34,1.56,.64,1);
}
.tab-btn .tab-lbl{
  font-family:var(--font-body);font-size:.68rem;font-weight:800;letter-spacing:.2px;
  line-height:1;
}
.tab-btn:active .tab-ico{transform:scale(.9)}
.tab-btn.active{color:var(--primary)}
.tab-btn.active .tab-ico{transform:scale(1.1)}
.tab-btn.active::before{display:none}

/* Check-in tab dùng chung style .tab-btn — icon line + label "Check-in",
   không còn tô nền tròn đỏ (per user 2026-09-19). */

/* ═══════════════════════════════════════════════
   TYPOGRAPHY
═══════════════════════════════════════════════ */
.hero-title{
  font-family:var(--font-display);font-weight:900;font-size:2.1rem;line-height:1;
  color:var(--primary);letter-spacing:-1px;user-select:none;
}
.hero-title em{font-style:italic;color:var(--accent);font-weight:900}
/* Easter egg — ẩn mặc định, bấm 5 lần vào tiêu đề mới hiện (xem HomeCtrl._initEasterEgg) */
.hero-tagline{
  font-family:var(--font-display);font-style:italic;font-weight:700;
  font-size:.85rem;color:var(--primary);margin-top:.2rem;
  letter-spacing:.2px;line-height:1;
  display:none;
}
.hero-tagline.show{display:block;animation:tagline-pop .4s var(--ease-spring)}
.hero-tagline em{font-style:italic;color:var(--accent);font-weight:800}
@keyframes tagline-pop{
  from{opacity:0;transform:translateY(-4px) scale(.9)}
  to{opacity:1;transform:none}
}

/* ═══════════════════════════════════════════════
   HOME (Nhóp Nhép tab)
═══════════════════════════════════════════════ */
/* Map tràn viền — homeScreen không còn tự cuộn, mainMapWrap phủ kín,
   brand pill + sheet nổi đè lên trên bằng position:absolute. */
#homeScreen{background:var(--cream)}

/* Brand pill — góc trái map, chỉ chữ "Nhóp Nhép ▾", không emoji không badge */
.brand-float{
  position:absolute;top:calc(var(--safe-top) + .6rem);left:.7rem;z-index:14;
  display:inline-flex;align-items:center;gap:.35rem;
  background:var(--white);border:none;border-radius:24px;
  padding:.6rem 1.05rem .6rem 1.15rem;box-shadow:0 6px 18px rgba(42,24,16,.2);
  font-family:var(--font-display);font-weight:900;font-size:1.05rem;
  color:var(--primary);letter-spacing:-.3px;line-height:1;
}
.brand-float em{font-style:italic;color:var(--accent);font-weight:900}

/* Easter egg tagline — nổi ngay dưới brand pill trên map full-bleed.
   Dùng lại class .hero-tagline (màu/animation) từ bản trước redesign,
   chỉ thêm vị trí absolute cho khớp layout hiện tại. */
#heroTagline{
  position:absolute;top:calc(var(--safe-top) + 3rem);left:.9rem;z-index:14;
  background:var(--white);padding:.3rem .75rem;border-radius:14px;
  box-shadow:0 4px 12px rgba(42,24,16,.18);max-width:220px;
}

/* Dropdown "Tôi muốn ăn" — popover xổ lên NGAY TẠI vị trí #catPillBtn
   (bấm ở đâu, hiện ra ở đó), thay cho panel cũ slide từ cạnh trên màn
   hình xuống (2026-09-19, theo yêu cầu Vinh: "cơ chế như điểm xuất
   phát... hiện ra ngay đó thay vì slide từ trên xuống"). Overlay chỉ để
   bắt tap-ra-ngoài-để-đóng, không tô tối màn hình nữa vì đây là popover
   nhỏ neo theo nút, không phải panel toàn màn hình. left/top hoặc
   left/bottom + transform-origin do HomeCtrl._positionCatDropdown() set
   inline mỗi lần mở, tuỳ còn đủ chỗ phía trên hay phải rơi xuống dưới. */
.cat-dd-overlay{
  position:fixed;top:0;bottom:0;left:0;right:0;z-index:16;
  background:transparent;opacity:0;pointer-events:none;transition:opacity .2s;
}
.cat-dd-overlay.show{opacity:1;pointer-events:auto}
.cat-dd-panel{
  position:fixed;z-index:17;width:min(300px, calc(100vw - 1.6rem));
  background:var(--white);border-radius:var(--radius-lg);
  box-shadow:0 10px 26px rgba(42,24,16,.24);
  padding:.9rem 1rem;
  transform:scale(.85);opacity:0;pointer-events:none;
  transition:transform .22s cubic-bezier(.34,1.56,.64,1),opacity .16s ease;
}
.cat-dd-panel.show{transform:scale(1);opacity:1;pointer-events:auto}
.dd-sec-title{
  font-family:var(--font-display);font-style:italic;font-weight:800;font-size:.75rem;
  color:var(--primary);letter-spacing:1px;text-transform:uppercase;margin-bottom:.5rem;
}

/* Pill bán kính / loại quán — giờ nằm NGAY TRONG khối .loc-row cùng ô
   nhập (xem .loc-row bên dưới), không còn tách riêng 1 dòng phía trên
   label nữa. flex-shrink:0 + white-space:nowrap để input (flex:1) cạnh
   nó không bóp méo/xuống dòng chữ trong pill. */
.radius-pill{
  display:flex;align-items:center;gap:.3rem;background:var(--primary);color:var(--cream);
  border:none;font-family:var(--font-display);font-size:.78rem;font-weight:800;
  padding:.42rem .85rem;border-radius:22px;flex-shrink:0;white-space:nowrap;
}
.radius-pill .chevron{font-size:.65rem;transition:transform .25s}
.radius-pill.open .chevron{transform:rotate(180deg)}

/* Cụm nút nổi — bookmark/thông báo/GPS gộp 1 viên, góc phải trên map */
.map-btn-cluster{
  position:absolute;top:calc(var(--safe-top) + .6rem);right:.7rem;z-index:14;
  display:flex;align-items:center;gap:1px;
  background:var(--white);border-radius:24px;padding:5px;
  box-shadow:0 6px 18px rgba(42,24,16,.2);
}
.cluster-btn{
  width:38px;height:38px;border-radius:50%;background:none;border:none;
  display:flex;align-items:center;justify-content:center;color:var(--text2);font-size:1.1rem;
}
.cluster-btn-gps{color:var(--primary);transition:transform .2s var(--ease-spring)}
.cluster-btn-gps.pulse{transform:scale(1.2)}
.cluster-btn.on{background:var(--primary);color:var(--white)}

/* Manual controls — horizontal dial (2026-09-25 redesign, replaces the
   earlier vertical slider + a separately-floating lock circle, per
   Vinh's reference screenshot of a native camera's brightness dial).
   Sits in its own row directly below .checkin-frame-zone (a real flex
   child of #checkinScreen, not an overlay on the video anymore — see
   .checkin-frame-zone's own comment for why the live-camera layout is
   flex-based). .checkin-exposure and .checkin-lock-btn are independent
   siblings inside this row rather than one nested inside the other:
   CheckinCtrl._setupManualControls() feature-detects each one
   separately (a device can support manual exposure without manual
   focus/exposure LOCK, or vice versa), so each keeps its own .hidden
   toggle; only the row itself needs to hide when NEITHER is supported. */
.checkin-manual-row{
  display:flex;align-items:center;gap:8px;
  padding:8px 18px 0;flex-shrink:0;
}
.checkin-manual-row.hidden{display:none}
.checkin-exposure{
  position:relative; /* containing block for .checkin-exposure-readout below */
  flex:1;min-width:0;height:44px;display:flex;align-items:center;
  background:var(--white);border-radius:22px;padding:0 12px;
  box-shadow:0 6px 18px rgba(42,24,16,.2);
  color:var(--text2);
}
.checkin-exposure.hidden{display:none}
/* Reset + lock: one round-chip family with diary/flip (.checkin-float-btn),
   same white chip + soft shadow, icon ≈45% of the diameter. Reset dims at
   0 ("Tự động") since there is nothing to reset. */
.checkin-cam-btn{
  flex-shrink:0;width:44px;height:44px;border-radius:50%;border:none;
  background:var(--white);color:var(--text2);box-shadow:0 6px 18px rgba(42,24,16,.2);
  display:flex;align-items:center;justify-content:center;
  transition:transform .1s,background-color .15s,color .15s;
}
.checkin-cam-btn .icon{width:20px;height:20px}
.checkin-cam-btn:active{transform:scale(.92)}
.checkin-cam-btn.is-idle{color:var(--text3)}
.checkin-cam-btn.checkin-lock-btn.on{background:var(--primary);color:var(--white)}

/* Ruler (ExposureDial): one tick per notch, taller at whole EVs, darkest
   at 0; ticks between 0 and the thumb are tinted, ticks near the thumb
   grow. Relative drag — touch-action:none keeps the page from scrolling. */
.checkin-dial{--inset:10px;position:relative;flex:1;min-width:0;height:30px;touch-action:none;cursor:ew-resize;border-radius:10px;outline:none}
.checkin-dial:focus-visible{box-shadow:0 0 0 2px var(--primary)}
.checkin-dial-ticks{position:absolute;inset:0;pointer-events:none}
.checkin-dial-tick{
  position:absolute;top:50%;left:calc(var(--inset) + (100% - 2 * var(--inset)) * var(--p));
  width:2px;height:7px;margin-left:-1px;border-radius:1px;background:var(--text3);opacity:.5;
  transform:translateY(-50%) scaleY(var(--s,1));
  transition:transform .16s var(--ease-out),background-color .16s,opacity .16s;
}
.checkin-dial-tick.major{height:12px;background:var(--text2);opacity:.7}
.checkin-dial-tick.zero{height:16px;background:var(--text);opacity:.9}
.checkin-dial-tick.fill{background:var(--primary);opacity:.85}
.checkin-dial-thumb{
  position:absolute;top:50%;left:calc(var(--inset) + (100% - 2 * var(--inset)) * var(--p,.5));
  width:4px;height:24px;margin-left:-2px;border-radius:2px;background:var(--primary);
  transform:translateY(-50%);box-shadow:0 0 0 3px rgba(185,38,38,.14);pointer-events:none;
  transition:left .12s var(--ease-spring),height .15s var(--ease-out);
}
.checkin-dial.dragging .checkin-dial-thumb{height:28px}
.checkin-dial-thumb.bump-l{animation:checkinDialBumpL .22s ease-out}
.checkin-dial-thumb.bump-r{animation:checkinDialBumpR .22s ease-out}
@keyframes checkinDialBumpL{40%{transform:translate(-4px,-50%) scaleY(.86)}}
@keyframes checkinDialBumpR{40%{transform:translate(4px,-50%) scaleY(.86)}}
@media (prefers-reduced-motion:reduce){
  .checkin-dial-tick,.checkin-dial-thumb{transition:none}
  .checkin-dial-thumb.bump-l,.checkin-dial-thumb.bump-r{animation:none}
}

/* Floating "+1.5" / "Tự động" readout above the thumb, set inline via
   ExposureDial._render() as left:<px> relative to .checkin-exposure.
   Visible while dragging + 700ms after. */
.checkin-exposure-readout{
  position:absolute;bottom:calc(100% + 8px);left:0;z-index:2;
  transform:translateX(-50%);
  background:var(--text);color:var(--cream);
  font-size:.72rem;font-weight:800;line-height:1;font-variant-numeric:tabular-nums;
  padding:.3rem .55rem;border-radius:8px;white-space:nowrap;
  opacity:0;pointer-events:none;transition:opacity .2s;
}
.checkin-exposure-readout.show{opacity:1}

#mainMapWrap{
  position:absolute;inset:0;z-index:0;margin:0;border-radius:0;
  border:none;background:var(--cream-2);height:auto;
}
#mainMap{position:absolute;inset:0}
/* Neutral light-gray ground so panning never reveals the app's warm
   cream tone at the edges before tiles finish loading (was
   var(--cream-2), a visibly yellow #F5EBC1, which read as "the whole
   map is tinted yellow"). */
.leaflet-container{background:#F2F1EE;font-family:var(--font-body)!important}
/* Grayscale filter instead of switching tile source — Esri's dedicated
   gray basemap (Light Gray Canvas) only has real detail to z16 and
   blurs badly when upscaled past that, which made deep-zoom street
   alignment (and the location pin sitting on it) look broken. This
   keeps World_Street_Map's full z19 sharpness and just desaturates it
   toward the same light-gray look, only on the tile-image pane so
   pins/markers (a different Leaflet pane) stay their true colors. */
.leaflet-tile-pane{filter:grayscale(1) brightness(1.16) contrast(.9)}

#homeSheet{
  position:absolute;left:0;right:0;bottom:0;z-index:7;
  background:var(--paper);border-top:2px solid var(--text);
  padding:.7rem 1.1rem 1rem;margin-top:0;
  border-radius:var(--radius-lg) var(--radius-lg) 0 0;
  box-shadow:0 -8px 24px rgba(42,24,16,.14);
  max-height:68%;display:flex;flex-direction:column;
  -webkit-mask-image:linear-gradient(to bottom, black 0%, black 90%, rgba(0,0,0,.68) 100%);
  mask-image:linear-gradient(to bottom, black 0%, black 90%, rgba(0,0,0,.68) 100%);
}
.sheet-drag-handle{width:34px;height:4px;background:var(--line-2);border-radius:2px;margin:0 auto .6rem;flex-shrink:0}
.sheet-inner-scroll{flex:1 1 auto;overflow-y:auto;min-height:0;scrollbar-width:none}
/* Home sheet collapse (HomeCtrl._initSheetCollapse): drag it down and only
   the scan button stays, so the map gets nearly the whole screen. The
   form's max-height follows the finger, then snaps; the handle gets a
   finger-sized hit area (the bar itself is 4 px). */
#homeSheet .sheet-drag-handle{position:relative;touch-action:none;cursor:grab;transition:background-color .2s}
#homeSheet .sheet-drag-handle::before{content:'';position:absolute;left:-70px;right:-70px;top:-12px;bottom:-12px}
#homeSheet .sheet-drag-handle:focus-visible{outline:2px solid var(--primary);outline-offset:6px}
#homeSheet .sheet-inner-scroll{overscroll-behavior-y:contain;transition:max-height .34s var(--ease-ios),opacity .24s var(--ease-ios)}
#homeSheet.sheet-dragging .sheet-inner-scroll{transition:none}
#homeSheet.collapsed .sheet-inner-scroll{opacity:0;pointer-events:none}
#homeSheet.collapsed,#homeSheet.collapsed *{touch-action:none}
#homeSheet.collapsed .sheet-drag-handle{background:var(--text3)}
.sheet-inner-scroll::-webkit-scrollbar{display:none}
/* Chừa chỗ cho tab bar pill nổi (54px pill + 10px margin + safe area + hơi thở
   16px) — trước để 14px nên nút Quét ngay bị che. */
.sheet-bg-extend{height:calc(var(--tab-h) + var(--safe-bottom) + 20px);flex-shrink:0}

.row-label{
  font-family:var(--font-display);font-style:italic;font-weight:800;
  font-size:.75rem;color:var(--primary);letter-spacing:1px;text-transform:uppercase;
  margin:.7rem 0 .45rem;display:flex;align-items:center;gap:.4rem;
}
.row-label::before{content:'✦';font-style:normal}
.row-label.mini{font-size:.68rem;margin:.55rem 0 .35rem;letter-spacing:.6px}
.row-label.mini::before{content:'·'}

/* Dish suggestions — collapsed pill row that shows on focus.
   Kept out of the main flow so the home form doesn't feel busy. */
.dish-suggest{
  display:none;flex-wrap:wrap;gap:.35rem;
  margin-top:.4rem;padding:.55rem;
  background:var(--paper);border:1.5px dashed var(--text2);border-radius:12px;
  animation:dish-drop .2s ease-out;
}
.dish-suggest.show{display:flex}
@keyframes dish-drop{ from{opacity:0;transform:translateY(-4px)} to{opacity:1;transform:none} }
.dish-chip{
  padding:.32rem .65rem;font-size:.72rem;font-weight:700;
  border:1.5px solid var(--text);background:var(--white);color:var(--text);
  border-radius:20px;white-space:nowrap;cursor:pointer;
  box-shadow:1.5px 1.5px 0 var(--text);transition:all .12s;
  font-family:var(--font-body);
}
.dish-chip:active{transform:translate(1px,1px);box-shadow:.5px .5px 0 var(--text)}
.dish-chip.active{background:var(--primary);color:var(--cream);border-color:var(--primary-2);box-shadow:1.5px 1.5px 0 var(--primary-2)}

/* Advanced filters toggle */
.advanced-toggle{
  width:100%;margin-top:.85rem;padding:.5rem .85rem;
  background:transparent;border:1.5px dashed var(--text2);border-radius:12px;
  color:var(--text2);font-family:var(--font-display);font-size:.8rem;font-weight:700;
  display:flex;align-items:center;justify-content:space-between;
  transition:all .18s;
}
.advanced-toggle em{font-style:italic;color:var(--primary)}
.advanced-toggle .chevron{transition:transform .25s;color:var(--primary);font-size:.9rem}
.advanced-toggle[aria-expanded="true"]{
  border-color:var(--primary);color:var(--primary);background:var(--primary-tint);
}
.advanced-toggle[aria-expanded="true"] .chevron{transform:rotate(180deg)}
.advanced-body{
  overflow:hidden;max-height:0;
  transition:max-height .32s cubic-bezier(.4,0,.2,1),overflow 0s;
}
/* Once expanded, let chip bounces spill out instead of being clipped.
   overflow flips to visible only AFTER the expand finishes (0s .32s). */
.advanced-body.open{
  max-height:300px;overflow:visible;
  transition:max-height .32s cubic-bezier(.4,0,.2,1),overflow 0s .32s;
}

/* Category chips */
.cat-chips{
  display:flex;gap:.5rem;flex-wrap:nowrap;overflow-x:auto;
  /* Top padding clears both the scale-pop bounce AND the "sắp có" badge
     that overhangs a chip's top (-8px). Left/bottom give bounce room.
     Negative margin keeps the row's outer footprint unchanged. */
  padding:12px 2.2rem 8px 6px;margin:-10px 0 -6px -6px;scrollbar-width:none;
  -webkit-overflow-scrolling:touch;
  /* Right-edge fade — signals "there's more, keep scrolling". Fade drops
     off when .at-end is added by wireScrollMasks in app.js (added
     automatically for any row that fits without scrolling, e.g. Home's
     4-chip #catChips — so widening this never affects a row that isn't
     actually overflowing).
     Widened 12px -> 44px (Vinh flagged 2026-09-11 the 12px version still
     looked broken, not just "clipped": on a 5-chip row like the profile
     filter tabs (#myRFilterChips — 4 categories + "Tất cả"), the peeking
     last chip's visible sliver mostly sat OUTSIDE the narrow fade zone,
     so it rendered at full opacity and then got a hard clip right at the
     scroll boundary — a flat, content-less rounded shape, not a fade.
     44px reaches back far enough that the entire visible peek of a
     cut-off chip sits inside the gradient and actually fades to nothing,
     reading as "scroll for more" instead of a rendering glitch. */
  -webkit-mask-image:linear-gradient(to right, #000 calc(100% - 44px), transparent 100%);
          mask-image:linear-gradient(to right, #000 calc(100% - 44px), transparent 100%);
}
.cat-chips::-webkit-scrollbar{display:none}
.cat-chips.at-end{-webkit-mask-image:none;mask-image:none}
/* #catChips (home "Tôi muốn ăn") is the primary category toggle - all 4
   options must always be plainly visible, never scroll-hidden behind the
   fade. Vinh flagged 2026-09-11 that on narrow phones (375px) the 4 chips
   - worse in EN, where "Street food" is longer than "Vỉa hè" - overflow
   the row width, so the inherited .cat-chips scroll-fade mask kicked in
   and read as a blur/rendering glitch on this all-important control, not
   a "scroll for more" hint. Wrap instead of scroll+fade here so nothing
   on this row is ever hidden or faded, regardless of viewport or locale. */
#catChips{
  flex-wrap:wrap;overflow-x:visible;
  -webkit-mask-image:none;mask-image:none;
  padding-right:6px;
}
.cat-chip{
  display:flex;align-items:center;gap:.3rem;padding:.5rem .85rem;border-radius:24px;
  border:2px solid var(--text);background:var(--white);color:var(--text);
  font-size:.82rem;font-weight:700;white-space:nowrap;flex-shrink:0;
  transition:all .18s cubic-bezier(.34,1.56,.64,1);
  box-shadow:2px 2px 0 var(--text);
}
.cat-chip:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}
.cat-chip.active{background:var(--primary);color:var(--cream);border-color:var(--primary-2);box-shadow:2px 2px 0 var(--primary-2)}
.cat-chip[data-cat="street"].active{background:var(--accent);border-color:var(--accent-2);box-shadow:2px 2px 0 var(--accent-2)}
.cat-chip[data-cat="snack"].active{background:var(--cat-snack);border-color:#A8365F;box-shadow:2px 2px 0 #A8365F}
/* Profile filter tabs (#myRFilterChips) have 1 more chip than Home's
   #catChips ("Tất cả" + 4 categories vs just 4), which was enough extra
   width to overflow and trigger the half-clipped-chip look above. A
   slightly tighter size (scoped to this row only, doesn't touch Home's
   chips) shrinks that overflow so less of the trailing chip needs to
   fade out in the first place. */
#myRFilterChips{gap:.4rem}
#myRFilterChips .cat-chip{padding:.46rem .7rem}
/* Home's #catChips (4 chips, no "Tất cả") — sized to fit all 4 on one
   row with no horizontal scroll on a narrow phone, not just "less
   overflow" like #myRFilterChips above (which still scrolls/fades).
   gap kept generous (not shrunk as far as it could go) — chips packed
   too tight made adjacent ones easy to mis-tap (feedback 2026-09-17). */
#catChips{gap:.55rem;flex-wrap:wrap}
#catChips .cat-chip{padding:.5rem .5rem;font-size:.74rem;gap:.3rem}
/* Home's "Nguồn dữ liệu" (#srcChips) is a primary filter too: all 3 chips
   must stay plainly visible. It overflowed by a few px on ~360-384px
   phones, so the scroll-fade ate "Cộng đồng" and it looked cut off.
   Slightly tighter chips fit one row on those widths; anything narrower
   (or a longer locale) wraps instead of scrolling behind a fade. */
#srcChips{flex-wrap:wrap;overflow-x:visible;-webkit-mask-image:none;mask-image:none;gap:.4rem;padding-right:6px}
#srcChips .cat-chip{padding:.5rem .48rem;font-size:.78rem}
.cat-chip[data-cat="cafe"].active{background:var(--cat-cafe);border-color:#5A3B24;box-shadow:2px 2px 0 #5A3B24}
/* Category icons carry their own category colour, which vanished on the
   same-coloured active chip (pink "Ăn vặt" on pink) — draw them white there. */
.cat-chip[data-cat].active .icon{filter:brightness(0) invert(1)}
/* Community source chip — was flagged "sắp có" until the PocketBase
   backend went live. Now a normal, selectable source. */

/* Radius chips */
.radius-chips{display:flex;gap:.5rem}
.radius-chip{
  flex:1;text-align:center;padding:.55rem 0;border-radius:24px;font-size:.85rem;font-weight:800;
  border:2px solid var(--text);color:var(--text);background:var(--white);
  transition:all .15s;box-shadow:2px 2px 0 var(--text);
}
.radius-chip:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}
.radius-chip.active{background:var(--primary);color:var(--cream);border-color:var(--primary-2);box-shadow:2px 2px 0 var(--primary-2)}

/* Location row + geocode suggestions dropdown.
   .loc-row giờ CHÍNH LÀ khối bo tròn nền cream (input + pill bán kính/loại
   quán nằm phẳng bên trong nó, không lồng khối-trong-khối nữa) — đúng
   pattern ảnh mẫu Vinh gửi 2026-09-19. Trước đây .loc-row chỉ là flex
   container trống, còn input tự có nền trắng/viền/bóng riêng. */
.loc-row-wrap{position:relative;margin-top:.75rem}
.loc-row-wrap .loc-row{margin-top:0}
.loc-row{
  display:flex;align-items:center;gap:.5rem;margin-top:.75rem;
  background:var(--cream);border-radius:20px;padding:.5rem .6rem;
  transition:box-shadow .18s ease;
}
/* Inset, not outset: .sheet-inner-scroll (overflow:auto, no side padding)
   clipped an outer ring at the row's left/right edges. */
.loc-row:focus-within{box-shadow:inset 0 0 0 2px var(--primary-2)}

/* Geocode suggestion dropdown — used on home input, modal address input,
   and friend search. position:fixed, coordinates computed by
   DropdownPosition (utils.js) from the input's live rect — escapes
   whatever scrollable ancestor it's sitting in (homeSheet, modal sheet). */
.geocode-suggest{
  position:fixed;top:var(--go-top,0);left:var(--go-left,0);width:var(--go-width,auto);z-index:9999;
  background:var(--white);border:2px solid var(--text);border-radius:14px;
  box-shadow:4px 4px 0 var(--primary-2);overflow:hidden;
  max-height:var(--go-max-h,280px);overflow-y:auto;display:none;
}
.geocode-suggest.show{display:block;animation:go-in .18s ease}
@keyframes go-in{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}
.go-item{
  padding:.55rem .8rem;cursor:pointer;border-bottom:1.5px dashed var(--line-2);
  font-size:.85rem;color:var(--text);transition:background .12s;
}
.go-item:last-child{border-bottom:none}
.go-item:hover,.go-item.active{background:var(--primary-tint)}
.go-item .go-primary{font-weight:800;font-family:var(--font-display);color:var(--primary);letter-spacing:-.2px}
.go-item .go-sub{font-size:.72rem;color:var(--text2);margin-top:2px;font-weight:500}
.go-loading{padding:.75rem;text-align:center;font-size:.78rem;color:var(--text2);font-style:italic;font-family:var(--font-display)}

/* Follow row — tên (bấm xem profile) + nút Theo dõi/Đang theo dõi riêng */
.go-item.follow-row{display:flex;align-items:center;justify-content:space-between;gap:.5rem;cursor:default}
.follow-name{cursor:pointer;font-weight:700;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.follow-name:hover{color:var(--primary)}
.follow-btn{
  flex-shrink:0;padding:.35rem .7rem;border-radius:20px;font-size:.72rem;font-weight:800;
  border:2px solid var(--text);background:var(--white);color:var(--text);
  box-shadow:2px 2px 0 var(--text);transition:all .12s;white-space:nowrap;
}
.follow-btn:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}
.follow-btn.following{background:var(--primary);color:var(--cream);border-color:var(--primary-2);box-shadow:2px 2px 0 var(--primary-2)}
/* Theo dõi lẫn nhau (mutual) — kiểu TikTok: nhãn "Bạn bè" tách biệt hẳn với
   "Đang theo dõi" 1 chiều, để lộ rõ đây là quan hệ 2 chiều. */
.follow-btn.mutual{background:var(--accent-2);color:var(--white);border-color:var(--text);box-shadow:2px 2px 0 var(--text)}
/* Wrap giữ nút + tag "Đã theo dõi bạn" xếp dọc, canh phải — luôn khai báo
   gap tường minh (bài học từ bug .comm-r-footer: margin-left:auto ăn hết
   chỗ trống, đừng để justify-content 1 mình lo khoảng cách). */
.follow-btn-wrap{display:inline-flex;flex-direction:column;align-items:flex-end;gap:.25rem;flex-shrink:0}
.follows-you-tag{font-size:.62rem;font-weight:700;color:var(--text3);background:var(--cream-2);border-radius:8px;padding:.1rem .45rem;white-space:nowrap}
/* UserQuanModal: Theo dõi + Nhắn tin side by side. */
.userquan-actions{display:inline-flex;align-items:flex-start;gap:.5rem;justify-content:center;flex-wrap:wrap}
.dm-msg-btn{display:inline-flex;align-items:center;gap:.3rem}
.dm-msg-btn .icon{width:.85em;height:.85em}
.go-empty{padding:.75rem;text-align:center;font-size:.78rem;color:var(--text3);font-style:italic}

/* Input giờ chỉ là phần chữ nằm PHẲNG bên trong khối .loc-row — bỏ hết
   nền/viền/bo góc/box-shadow riêng (trước là 1 khối brutalist độc lập)
   để cả .loc-row đọc thành MỘT khối bo tròn liền mạch duy nhất. Focus
   ring chuyển sang .loc-row:focus-within ở trên thay vì border-color. */
.loc-input{
  flex:1;min-width:0;background:transparent;border:none;
  padding:.15rem 0;font-size:.9rem;color:var(--text);outline:none;font-weight:600;
  box-shadow:none;
}
.loc-input::placeholder{color:var(--text3);font-weight:500}
/* Nút phụ trong khối (#gpsBtn ẩn / #dishClearBtn "xoá món") — trước là ô
   vuông brutalist viền dày+đổ bóng, hợp khi đứng riêng NGOÀI khối; giờ
   nằm lọt bên trong khối phẳng nên thu gọn thành icon tròn tối giản. */
.loc-gps-btn{
  flex-shrink:0;width:1.8rem;height:1.8rem;border-radius:50%;
  background:transparent;border:none;box-shadow:none;
  display:flex;align-items:center;justify-content:center;
  font-size:1.05rem;color:var(--text3);transition:background-color .15s,color .15s;
}
.loc-gps-btn:active{background:var(--cream-2)}
.loc-gps-btn.active{background:var(--primary);color:var(--cream)}

/* Scan CTA */
.scan-btn{
  width:100%;margin-top:1rem;padding:1.05rem;border-radius:16px;
  background:var(--primary);color:var(--cream);
  font-family:var(--font-display);font-size:1.15rem;font-weight:900;letter-spacing:.5px;
  border:2px solid var(--text);transition:all .15s;box-shadow:4px 4px 0 var(--text);
  display:flex;align-items:center;justify-content:center;gap:.5rem;
}
.scan-btn:active{transform:translate(2px,2px);box-shadow:2px 2px 0 var(--text)}
.scan-btn:disabled{opacity:.5;pointer-events:none;box-shadow:2px 2px 0 var(--text)}

/* Scan button — loading / scanning state */
.scan-btn.scanning{
  pointer-events:none;
  animation:scan-btn-pulse 1.4s ease-in-out infinite;
  /* keep box-shadow base so pulse layers on top */
}
@keyframes scan-btn-pulse{
  0%,100%{box-shadow:4px 4px 0 var(--text),0 0 0 0 var(--primary-glow,rgba(185,38,38,.0))}
  50%{box-shadow:4px 4px 0 var(--text),0 0 0 9px var(--primary-glow,rgba(185,38,38,.18))}
}
/* Small inline spinner inside the button */
.scan-btn .btn-spinner{
  width:18px;height:18px;flex-shrink:0;
  border:2.5px solid rgba(255,255,255,.35);
  border-top-color:#fff;
  border-radius:50%;
  animation:spin .65s linear infinite;
}

/* GPS pulse marker */
.user-marker-inner{
  width:18px;height:18px;border-radius:50%;background:var(--primary);
  border:3px solid var(--white);box-shadow:0 0 0 0 var(--primary-glow);
  animation:gps-pulse 2s infinite;
}
.user-marker-inner.tracking{background:#2E7D32;box-shadow:0 0 0 0 rgba(46,125,50,.5);animation:gps-pulse-green 1.5s infinite}
@keyframes gps-pulse{
  0%{box-shadow:0 0 0 0 rgba(185,38,38,.6)}
  70%{box-shadow:0 0 0 14px rgba(185,38,38,0)}
  100%{box-shadow:0 0 0 0 rgba(185,38,38,0)}
}
@keyframes gps-pulse-green{
  0%{box-shadow:0 0 0 0 rgba(46,125,50,.55)}
  70%{box-shadow:0 0 0 16px rgba(46,125,50,0)}
  100%{box-shadow:0 0 0 0 rgba(46,125,50,0)}
}

/* GPS button live indicator */
.loc-gps-btn.tracking{background:#2E7D32;color:#fff;border-color:#1B5E20;box-shadow:2px 2px 0 #1B5E20;position:relative}
.loc-gps-btn.tracking::after{
  content:'';position:absolute;top:-3px;right:-3px;width:10px;height:10px;
  background:#4CAF50;border:2px solid var(--white);border-radius:50%;
  animation:blink 1s infinite;
}
@keyframes blink{ 0%,100%{opacity:1} 50%{opacity:.35} }

/* GPS accuracy hint */
.gps-hint{
  font-size:.7rem;font-weight:600;color:var(--text2);margin-top:.35rem;
  padding:.3rem .6rem;background:var(--paper);border-radius:8px;
  border:1.5px dashed var(--text2);display:none;
}
.gps-hint.show{display:block;animation:fade-in .3s ease}
.gps-hint.tracking{border-color:#2E7D32;color:#1B5E20;background:#E8F5E9}
.gps-hint.warn{border-color:var(--primary);color:var(--primary-2);background:var(--primary-tint)}
@keyframes fade-in{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}

/* ═══════════════════════════════════════════════
   RESULTS SCREEN
═══════════════════════════════════════════════ */
#resultsScreen{background:var(--cream)}
.results-topbar{
  flex-shrink:0;display:flex;align-items:center;gap:.6rem;
  padding:.9rem 1.1rem .8rem;background:var(--cream);
  border-bottom:2px solid var(--text);position:relative;z-index:5;
}
.back-btn{
  width:2.4rem;height:2.4rem;border-radius:50%;background:var(--white);
  border:2px solid var(--text);display:flex;align-items:center;justify-content:center;
  font-size:1rem;flex-shrink:0;box-shadow:2px 2px 0 var(--text);transition:all .12s;
}
.back-btn:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}
.results-title{font-family:var(--font-display);font-size:1.15rem;font-weight:900;flex:1;min-width:0;letter-spacing:-.3px;color:var(--text)}
.results-sub{font-size:.72rem;color:var(--text2);font-weight:600;font-family:var(--font-body);margin-top:1px}
.reshuffle-btn{
  padding:.5rem .85rem;border-radius:24px;background:var(--accent);color:var(--white);
  font-family:var(--font-display);font-size:.82rem;font-weight:800;flex-shrink:0;
  border:2px solid var(--text);box-shadow:2px 2px 0 var(--text);transition:all .12s;
  font-style:italic;letter-spacing:.3px;
}
.reshuffle-btn:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}

/* Cat filter tabs */
.cat-tabs{
  flex-shrink:0;display:flex;gap:.4rem;overflow-x:auto;scrollbar-width:none;
  background:var(--cream);padding:.65rem 1.6rem .65rem 1.1rem;
  border-bottom:2px solid var(--text);
  -webkit-overflow-scrolling:touch;
  -webkit-mask-image:linear-gradient(to right, #000 calc(100% - 24px), transparent 100%);
          mask-image:linear-gradient(to right, #000 calc(100% - 24px), transparent 100%);
}
.cat-tabs::-webkit-scrollbar{display:none}
.cat-tabs.at-end{-webkit-mask-image:none;mask-image:none}
.cat-tab{
  padding:.4rem .8rem;font-size:.78rem;font-weight:700;color:var(--text);white-space:nowrap;
  border:2px solid var(--text);border-radius:20px;background:var(--white);
  box-shadow:2px 2px 0 var(--text);transition:all .12s;flex-shrink:0;
}
.cat-tab:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}
.cat-tab.active{background:var(--text);color:var(--cream)}

/* Restaurant grid */
.restaurant-grid{
  flex:1;overflow-y:auto;padding:.8rem 1.1rem;display:grid;
  grid-template-columns:1fr 1fr;gap:.7rem;align-content:start;
  /* Padding cuối = .results-action (~5.5rem) + tab bar pill (--tab-h) +
     safe-area, để card cuối cuộn hết vẫn không bị 2 lớp UI dưới che. */
  padding-bottom:calc(var(--safe-bottom) + var(--tab-h) + 5.5rem);
}
.restaurant-grid::-webkit-scrollbar{display:none}

/* Restaurant card */
.r-card{
  background:var(--white);border-radius:var(--radius);border:2px solid var(--text);
  padding:.75rem;position:relative;overflow:visible;cursor:pointer;
  transition:all .18s;animation:card-in .35s ease both;box-shadow:3px 3px 0 var(--text);
}
.r-card:active{transform:translate(1px,1px);box-shadow:2px 2px 0 var(--text)}
.r-card.selected{background:var(--primary-tint);border-color:var(--primary);box-shadow:3px 3px 0 var(--primary-2)}

/* Tick corner — clickable, independent of card body.
   Empty when unselected (outlined box); filled ✓ when selected. */
.r-check{
  position:absolute;top:-8px;right:-8px;z-index:3;
  width:1.9rem;height:1.9rem;border-radius:50%;
  background:var(--white);color:transparent;
  font-size:.9rem;font-weight:900;line-height:1;
  display:flex;align-items:center;justify-content:center;
  border:2px solid var(--text);box-shadow:2px 2px 0 var(--text);
  cursor:pointer;transition:all .12s;padding:0;
}
.r-check:hover{background:var(--cream-2)}
.r-check:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}
.r-card.selected .r-check{
  background:var(--primary);color:var(--cream);
  box-shadow:2px 2px 0 var(--text);
}
.r-card.user-added::before{
  content:'⭐';position:absolute;top:-6px;left:-6px;
  width:1.4rem;height:1.4rem;border-radius:50%;background:var(--accent);
  display:flex;align-items:center;justify-content:center;font-size:.75rem;
  border:2px solid var(--text);
}
.r-card.osm-added::before{
  content:'🌐';position:absolute;top:-6px;left:-6px;
  width:1.4rem;height:1.4rem;border-radius:50%;background:#4CAF50;
  display:flex;align-items:center;justify-content:center;font-size:.7rem;
  border:2px solid var(--text);
}
.r-card.gemini-added::before{
  content:'✨';position:absolute;top:-6px;left:-6px;
  width:1.4rem;height:1.4rem;border-radius:50%;background:#8B5CF6;
  display:flex;align-items:center;justify-content:center;font-size:.7rem;
  border:2px solid var(--text);color:#fff;
}
.r-card.gemini-added .r-rating{color:#7C3AED;font-weight:800}
.r-ref-note{font-size:.62rem;font-weight:600;font-style:italic;color:var(--text3);opacity:.75}
@keyframes card-in{ from{opacity:0;transform:translateY(12px) scale(.97)} to{opacity:1;transform:none} }

.r-cat-badge{
  display:inline-flex;align-items:center;gap:.25rem;font-family:var(--font-display);
  font-size:.68rem;font-weight:800;font-style:italic;
  padding:.2rem .55rem;border-radius:20px;margin-bottom:.4rem;
  border:1.5px solid var(--text);
}
.r-name{font-family:var(--font-display);font-size:.95rem;font-weight:900;line-height:1.2;margin-bottom:.2rem;color:var(--text);letter-spacing:-.2px}
.r-price{font-size:.72rem;color:var(--primary);font-weight:800;margin-bottom:.35rem}
.r-meta{display:flex;align-items:center;justify-content:space-between;margin-top:.35rem;padding-top:.35rem;border-top:1.5px dashed var(--line-2)}
.r-rating{font-size:.75rem;font-weight:800;color:var(--accent-2)}
.r-dist{font-size:.72rem;color:var(--text3);font-weight:700}
.r-desc{font-size:.72rem;color:var(--text2);line-height:1.4;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;font-weight:500}

/* Hours badge */
.r-hours{
  display:flex;align-items:center;gap:.3rem;margin-top:.3rem;margin-bottom:.2rem;
  font-size:.68rem;font-weight:700;line-height:1.3;
}
.hours-badge{
  display:inline-flex;align-items:center;gap:.2rem;
  padding:.15rem .45rem;border-radius:10px;font-size:.62rem;font-weight:800;
  letter-spacing:.2px;
}
.hours-badge.open{background:#E8F5E9;color:#2E7D32;border:1px solid #A5D6A7}
.hours-badge.closed{background:#FFEBEE;color:#C62828;border:1px solid #EF9A9A}
.hours-badge.unknown{background:var(--paper);color:var(--text3);border:1px solid var(--line-2)}
.hours-detail{color:var(--text3);font-size:.65rem;font-weight:600}

/* Gmaps link */
.r-gmaps-link{
  display:inline-flex;align-items:center;gap:4px;
  font-size:.68rem;font-weight:800;color:#1565c0;text-decoration:none;
  padding:3px 6px;border-radius:8px;background:#E3F2FD;border:1.5px solid #90caf9;
  transition:all .15s;margin-top:6px;
}
.r-gmaps-link:active{background:#BBDEFB;transform:scale(0.95)}

.results-action{
  /* Layout giống #homeSheet: nền kéo xuống tận cạnh dưới màn hình. Nền là
     pseudo-element ::before mờ dần ở đáy (mask gradient), 2 nút thật đứng
     trên nền với opacity 100% (không bị mask fade). Tab bar pill overlay ở
     dưới cùng nhờ z-index. */
  position:absolute;bottom:0;left:0;right:0;z-index:5;
  padding:.75rem 1.1rem calc(var(--safe-bottom) + var(--tab-h) + 16px);
  background:transparent;
}
.results-action::before{
  content:'';position:absolute;inset:0;z-index:-1;
  background:var(--cream);
  -webkit-mask-image:linear-gradient(to bottom, black 0%, black 78%, rgba(0,0,0,.62) 100%);
  mask-image:linear-gradient(to bottom, black 0%, black 78%, rgba(0,0,0,.62) 100%);
}
.action-btn{
  width:100%;padding:1rem;border-radius:16px;
  background:var(--primary);color:var(--cream);
  font-family:var(--font-display);font-size:1.05rem;font-weight:900;letter-spacing:.4px;
  border:2px solid var(--text);box-shadow:4px 4px 0 var(--text);transition:all .12s;
}
.action-btn:active{transform:translate(2px,2px);box-shadow:2px 2px 0 var(--text)}
.action-btn:disabled{opacity:.65;pointer-events:none;box-shadow:2px 2px 0 var(--text)}

/* Group Session — "Tạo phiên chọn quán" secondary button above Lên lịch */
.session-create-btn{
  width:100%;padding:.7rem;border-radius:14px;margin-bottom:.5rem;
  background:var(--white);color:var(--text);font-weight:800;font-size:.85rem;
  border:2px solid var(--text);box-shadow:2px 2px 0 var(--text);transition:all .12s;
}
.session-create-btn:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}
.session-create-btn:disabled{opacity:.65;pointer-events:none;box-shadow:1px 1px 0 var(--text)}

.session-cand-list{display:flex;flex-direction:column;gap:.4rem;max-height:220px;overflow-y:auto}
.session-cand-row{
  display:flex;align-items:center;gap:.5rem;padding:.5rem .7rem;
  border:1.5px solid var(--line-2);border-radius:12px;background:var(--paper);
}
.session-cand-icon{font-size:1rem}
.session-cand-name{font-size:.85rem;font-weight:700;color:var(--text);flex:1;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

.session-invite-row{display:flex;gap:.5rem;margin-bottom:.7rem}
.session-invite-row .form-input{flex:1;font-size:.78rem;color:var(--text2)}
.session-copy-btn{
  flex-shrink:0;width:44px;border-radius:12px;background:var(--primary);
  border:2px solid var(--text);font-size:1.1rem;box-shadow:2px 2px 0 var(--text);
  transition:all .12s;
}
.session-copy-btn:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}

.session-reconnect-banner,.session-expired-banner{
  padding:.5rem .7rem;border-radius:10px;font-size:.78rem;font-weight:700;
  margin-bottom:.6rem;background:#FFEBEE;color:#C62828;border:1px solid #EF9A9A;
}
.session-expired-banner{background:var(--paper);color:var(--text3);border-color:var(--line-2)}

.session-vote-list{display:flex;flex-direction:column;gap:.5rem;max-height:min(45vh,360px);overflow-y:auto;margin-bottom:.7rem}
.session-vote-row{
  display:flex;align-items:center;gap:.6rem;padding:.65rem .8rem;cursor:pointer;
  border:2px solid var(--text);border-radius:14px;background:var(--white);
  box-shadow:2px 2px 0 var(--text);transition:all .12s;
}
.session-vote-row:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}
.session-vote-row.voted{background:var(--primary-tint);border-color:var(--primary)}
.session-vote-row.winner{background:#FFF8E1;border-color:#F9A825;box-shadow:3px 3px 0 #F9A825}
.session-vote-icon{font-size:1.1rem;flex-shrink:0}
.session-vote-name{font-size:.88rem;font-weight:800;color:var(--text);flex:1;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.session-vote-count{font-size:.8rem;font-weight:900;color:var(--accent-2);flex-shrink:0}
.session-vote-check{font-size:.9rem;flex-shrink:0;opacity:0;transition:opacity .12s}
.session-vote-row.voted .session-vote-check{opacity:1}

.session-winner-banner{
  text-align:center;padding:1rem;border-radius:16px;margin-bottom:.7rem;
  background:#FFF8E1;border:2px solid #F9A825;
}
.session-winner-title{font-family:var(--font-display);font-weight:900;font-size:1rem;color:var(--text);margin-bottom:.3rem}
.session-winner-name{font-family:var(--font-display);font-weight:900;font-size:1.2rem;color:var(--primary)}

/* Random pick FAB — round, free-draggable, snaps to a screen corner.
   position:fixed is contained by body's transform:translateZ(0) in the
   desktop phone-frame media query above, so it stays inside the frame
   there too instead of the real browser viewport. */
.rp-fab{
  position:fixed;z-index:60;right:16px;bottom:100px;
  width:54px;height:54px;border-radius:50%;
  background:var(--primary);color:var(--cream);border:2px solid var(--text);
  box-shadow:3px 3px 0 var(--text);display:flex;align-items:center;justify-content:center;
  font-size:1.5rem;line-height:1;cursor:grab;touch-action:none;user-select:none;
  transition:box-shadow .12s,transform .12s,left .25s ease,top .25s ease,right .25s ease,bottom .25s ease;
}
/* Dice icon bigger than the 1em default — this button IS the icon (no
   label text next to it), so it can afford to fill more of the circle
   for a clearer silhouette at a glance. */
.rp-fab .icon{width:1.7em;height:1.7em}
.rp-fab:active{transform:scale(.96)}
.rp-fab.dragging{transition:none;cursor:grabbing;box-shadow:5px 5px 0 var(--text)}
.rp-fab.picking{animation:rp-wiggle .28s ease-in-out infinite}
@keyframes rp-wiggle{0%,100%{transform:rotate(0)}25%{transform:rotate(-10deg)}75%{transform:rotate(10deg)}}

.rp-modal-actions{display:flex;gap:.6rem;margin-top:.4rem}
.rp-btn{
  flex:1;padding:.85rem;border-radius:14px;border:2px solid var(--text);
  font-family:var(--font-display);font-size:.85rem;font-weight:800;font-style:italic;
  box-shadow:2px 2px 0 var(--text);transition:all .12s;
}
.rp-btn:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}
.rp-btn-retry{background:var(--white);color:var(--text)}
.rp-btn-go{background:var(--primary);color:var(--cream)}

.empty-state{
  grid-column:1/-1;display:flex;flex-direction:column;align-items:center;
  justify-content:center;padding:3rem 1rem;gap:.75rem;color:var(--text3);
}
.empty-state .es-icon{font-size:3.5rem}
.empty-state .es-msg{font-family:var(--font-display);font-size:1rem;font-weight:800;text-align:center;color:var(--text2)}
.es-gmaps-btn{
  margin-top:.5rem;display:inline-flex;align-items:center;gap:.4rem;
  padding:.7rem 1.1rem;border-radius:24px;
  background:var(--primary);color:var(--cream);
  border:2px solid var(--primary-2);box-shadow:3px 3px 0 var(--primary-2);
  font-family:var(--font-body);font-weight:800;font-size:.85rem;text-decoration:none;
  transition:transform .26s var(--ease-out),box-shadow .26s var(--ease-out);
}
.es-gmaps-btn:active{transform:translate(2px,2px) scale(.97);box-shadow:1px 1px 0 var(--primary-2)}
.es-gmaps-banner{
  grid-column:1/-1;display:flex;align-items:center;justify-content:center;gap:.4rem;
  margin:0 0 .6rem;padding:.6rem .9rem;border-radius:14px;
  background:var(--primary-tint);border:1.5px dashed var(--primary);
  color:var(--primary);font-weight:800;font-size:.8rem;text-decoration:none;text-align:center;
  transition:transform .22s var(--ease-out),background-color .2s var(--ease-ios);
}
.es-gmaps-banner b{color:var(--primary-2)}
.es-gmaps-banner:active{transform:scale(.97)}
@media (hover:hover) and (pointer:fine){ .es-gmaps-banner:hover{background:var(--primary);color:var(--cream)} .es-gmaps-banner:hover b{color:var(--cream)} }

/* ═══════════════════════════════════════════════
   PLAN SCREEN
═══════════════════════════════════════════════ */
#planScreen{background:var(--cream)}
.plan-topbar{
  flex-shrink:0;display:flex;align-items:center;gap:.6rem;
  padding:.9rem 1.1rem .8rem;background:var(--cream);
  border-bottom:2px solid var(--text);
}
.plan-title{font-family:var(--font-display);font-size:1.2rem;font-weight:900;flex:1;letter-spacing:-.3px;color:var(--primary);font-style:italic}

.plan-summary{
  flex-shrink:0;display:flex;align-items:center;gap:.45rem;overflow-x:auto;
  padding:.7rem 1.1rem;background:var(--paper);border-bottom:2px solid var(--text);
  scrollbar-width:none;-webkit-overflow-scrolling:touch;
  scroll-snap-type:x proximity;
  /* Fade the right edge so the "there's more to scroll" hint is
     visible without stealing focus from the primary content */
  -webkit-mask-image:linear-gradient(to right, #000 calc(100% - 28px), transparent 100%);
          mask-image:linear-gradient(to right, #000 calc(100% - 28px), transparent 100%);
}
.plan-summary::-webkit-scrollbar{display:none}
/* Drop the mask once the user has scrolled to the very end — nothing
   left to hint at, so no need to fade the last chip's border */
.plan-summary.at-end{-webkit-mask-image:none;mask-image:none}
.sum-chip{scroll-snap-align:start}
.sum-chip{
  display:flex;align-items:center;gap:.35rem;padding:.4rem .75rem;
  border-radius:24px;background:var(--white);
  font-size:.76rem;font-weight:800;white-space:nowrap;flex-shrink:0;color:var(--text);
  border:2px solid var(--text);box-shadow:2px 2px 0 var(--text);
}
.sum-chip .sci{font-size:.9rem}

#planMapWrap{
  flex-shrink:0;height:240px;margin:.8rem 1.1rem;border-radius:var(--radius);overflow:hidden;
  border:2px solid var(--text);box-shadow:4px 4px 0 var(--primary-2);position:relative;
}
#planMap{position:absolute;inset:0;background:var(--cream-2)}

/* Plan map overlay controls */
.pmap-controls{
  position:absolute;top:.5rem;right:.5rem;z-index:500;display:flex;flex-direction:column;gap:.3rem;
}
.pmap-btn{
  width:34px;height:34px;border-radius:10px;
  background:var(--white);border:2px solid var(--text);box-shadow:2px 2px 0 var(--text);
  font-size:1.1rem;font-weight:900;display:flex;align-items:center;justify-content:center;
  cursor:pointer;transition:all .1s;color:var(--text);font-family:var(--font-body);
}
.pmap-btn:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}
.pmap-fit{font-size:.75rem;letter-spacing:-.5px}
.pmap-btn.pmap-locate.tracking{background:var(--primary);color:var(--cream);border-color:var(--text)}

/* Fullscreen map — covers everything but the security shield.
   The <body>.map-full companion class slides the tabbar out of view
   so the map really owns the whole viewport. */
#planMapWrap.fullscreen{
  position:fixed;inset:0;z-index:1500;
  margin:0;border-radius:0;border:none;box-shadow:none;
  height:100vh !important;height:100dvh !important;
}
body.map-full .tabbar{transform:translateY(105%)}
#planMapWrap.fullscreen .pmap-controls{
  top:calc(env(safe-area-inset-top, 0px) + .8rem);
  right:.8rem;
}
#planMapWrap.fullscreen .pmap-btn{width:44px;height:44px;font-size:1.25rem}
#planMapWrap.fullscreen .pmap-fit{font-size:.9rem}

/* Cute navigation Start/Navigating button cluster — Google-Maps-inspired,
   only in fullscreen. Positioning (centered, floating above the safe
   area) lives on the WRAPPER now, not .pmap-start-btn itself, so the
   pause button can sit right next to it as one centered unit. */
.pmap-nav-controls{
  display:none;position:absolute;left:50%;
  bottom:calc(env(safe-area-inset-bottom, 0px) + 1.8rem);
  transform:translateX(-50%);
  gap:.6rem;align-items:center;z-index:1510;
}
#planMapWrap.fullscreen .pmap-nav-controls{display:flex}

.pmap-start-btn{
  position:relative;overflow:hidden; /* clips the long-press fill overlay */
  padding:.85rem 1.55rem .85rem 1.1rem;
  display:flex;gap:.55rem;align-items:center;
  background:var(--primary);color:var(--cream);
  border:3px solid var(--text);border-radius:999px;
  box-shadow:3px 4px 0 var(--text);cursor:pointer;
  font-family:var(--font-display);font-weight:900;font-style:italic;
  font-size:1.05rem;letter-spacing:.5px;
  animation:nav-pulse 1.8s ease-in-out infinite;
  -webkit-user-select:none;user-select:none;touch-action:manipulation;
}
.pmap-start-btn:active{
  transform:translate(1px,2px);
  box-shadow:1px 2px 0 var(--text);
}
.pmap-start-btn svg{
  transform:translateY(1px);
  filter:drop-shadow(0 1.5px 0 rgba(0,0,0,.2));
}
.pmap-start-btn:hover{background:var(--primary-2)}
@keyframes nav-pulse{
  0%,100%{box-shadow:3px 4px 0 var(--text), 0 0 0 0 rgba(185,38,38,.55)}
  50%    {box-shadow:3px 4px 0 var(--text), 0 0 0 16px rgba(185,38,38,0)}
}
/* Reduced motion — no pulse, just static */
@media (prefers-reduced-motion: reduce){
  .pmap-start-btn{animation:none}
}

/* "Đang đi" (navigating) state — green, no idle pulse (that was
   specifically a "tap me" affordance; once already moving it'd just be
   visual noise). Reuses the app's existing tracking-green convention
   (.user-marker-inner.tracking / the accuracy circle use the same hue). */
.pmap-start-btn.navigating{
  background:#2E7D32;border-color:#1B5E20;
  box-shadow:3px 4px 0 #1B5E20;animation:none;
}
.pmap-start-btn.navigating:active{box-shadow:1px 2px 0 #1B5E20}
.pmap-start-btn.navigating:hover{background:#256428}

/* "Tạm dừng" (paused) state — same button, amber instead of green so
   it's visually obvious tracking is on hold (tap = resume). One button
   cycles navigating <-> paused; long-press ends the trip from either. */
.pmap-start-btn.paused{
  background:var(--accent-2);border-color:#8a4315;
  box-shadow:3px 4px 0 #8a4315;animation:none;
}
.pmap-start-btn.paused:active{box-shadow:1px 2px 0 #8a4315}
.pmap-start-btn.paused:hover{background:#c05f1e}

/* Long-press-to-end fill — a dark overlay that sweeps left-to-right
   while held, so holding long enough to end the trip is visibly
   confirmed instead of feeling like an accidental tap. --hold-ms is set
   from JS (HOLD_END_MS) so the animation always finishes exactly when
   the timer actually fires. Applies in both active states (navigating
   or paused) — long-press ends the trip from either. */
.pmap-start-btn.navigating::after,
.pmap-start-btn.paused::after{
  content:'';position:absolute;inset:0;background:rgba(0,0,0,.3);
  transform:scaleX(0);transform-origin:left center;pointer-events:none;
}
.pmap-start-btn.navigating.holding::after,
.pmap-start-btn.paused.holding::after{
  animation:hold-fill var(--hold-ms,650ms) linear forwards;
}
@keyframes hold-fill{from{transform:scaleX(0)}to{transform:scaleX(1)}}
@media (prefers-reduced-motion: reduce){
  .pmap-start-btn.navigating.holding::after,
  .pmap-start-btn.paused.holding::after{animation-duration:.01ms}
}

/* Off-route banner — warm amber "heads up", not a scary red error
   (matches the lesson from the duplicate-post confirm box: system
   inferences should read as a helpful nudge, not a bug/alarm). */
.pmap-offroute-banner{
  position:absolute;top:calc(env(safe-area-inset-top, 0px) + .8rem);
  left:50%;transform:translateX(-50%);z-index:1510;
  display:flex;align-items:center;gap:.5rem;
  background:var(--accent);color:var(--text);
  border:2.5px solid var(--text);border-radius:999px;
  padding:.55rem 1.1rem;box-shadow:2px 3px 0 var(--text);
  font-weight:800;font-size:.85rem;white-space:nowrap;
  max-width:calc(100vw - 2rem);
}
.pmap-offroute-icon{animation:offroute-spin 1s linear infinite;display:inline-block}
@keyframes offroute-spin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion: reduce){.pmap-offroute-icon{animation:none}}

/* Timeline scroll — chừa chỗ cho tab bar pill nổi ở đáy, không thì trạm cuối
   lộ trình bị pill che khi cuộn xuống hết. */
.timeline{flex:1;overflow-y:auto;padding:.5rem 1.1rem calc(var(--safe-bottom) + var(--tab-h) + 1rem);scrollbar-width:none}
.timeline::-webkit-scrollbar{display:none}

.tl-item{display:flex;gap:.75rem;margin-bottom:.25rem}
.tl-spine{display:flex;flex-direction:column;align-items:center;flex-shrink:0;width:2.4rem}
.tl-dot{
  width:2.4rem;height:2.4rem;border-radius:50%;display:flex;align-items:center;justify-content:center;
  font-size:1.05rem;border:2px solid var(--text);background:var(--white);flex-shrink:0;
  box-shadow:2px 2px 0 var(--text);
}
.tl-line{flex:1;width:2.5px;background:var(--text);margin:.25rem auto;border-radius:2px}
.tl-content{flex:1;padding-bottom:.8rem;min-width:0}

.tl-travel{
  display:flex;align-items:center;gap:.5rem;padding:.5rem .8rem;
  border-radius:14px;background:var(--paper);border:1.5px dashed var(--text2);
}
.tl-travel-icon{font-size:1.1rem}
.tl-travel-info{flex:1;min-width:0}
.tl-travel-time{font-size:.85rem;font-weight:800;color:var(--text)}
.tl-travel-dist{font-size:.72rem;color:var(--text2);font-weight:600}

.tl-stop{
  background:var(--white);border-radius:var(--radius);border:2px solid var(--text);
  padding:.85rem;box-shadow:3px 3px 0 var(--text);
}
.tl-stop-header{display:flex;align-items:flex-start;gap:.6rem;margin-bottom:.4rem}
.tl-stop-icon{font-size:1.5rem;flex-shrink:0}
.tl-stop-info{flex:1;min-width:0}
.tl-stop-name{font-family:var(--font-display);font-size:1.02rem;font-weight:900;margin-bottom:.15rem;color:var(--text);letter-spacing:-.2px}
.tl-stop-cat{font-size:.72rem;font-weight:700;opacity:.85}
.tl-dwell{display:flex;align-items:center;gap:.5rem;margin-top:.55rem}
.dwell-label{font-size:.75rem;color:var(--text2);font-weight:700}
.dwell-adj{display:flex;align-items:center;gap:.45rem;margin-left:auto;background:var(--paper);padding:.2rem;border-radius:24px;border:1.5px solid var(--text)}
.dwell-num{font-family:var(--font-display);font-size:.9rem;font-weight:900;min-width:2rem;text-align:center;color:var(--primary)}
.dwell-btn{
  width:1.7rem;height:1.7rem;border-radius:50%;background:var(--white);
  font-size:1rem;display:flex;align-items:center;justify-content:center;
  transition:all .12s;font-weight:900;border:1.5px solid var(--text);color:var(--text);
}
.dwell-btn:active{transform:scale(.88);background:var(--primary);color:var(--cream)}

.tl-time{font-size:.75rem;font-weight:800;color:var(--primary);margin-top:.5rem;font-family:var(--font-display);font-style:italic}
.tl-start{font-family:var(--font-display);font-size:.9rem;font-weight:800;color:var(--text2);padding:.4rem 0;font-style:italic}
.tl-hours-warn{
  display:flex;align-items:center;gap:.3rem;margin-top:.4rem;
  padding:.3rem .6rem;border-radius:8px;font-size:.7rem;font-weight:700;
  background:#FFF3E0;color:#E65100;border:1.5px dashed #FFB74D;
}

/* ═══════════════════════════════════════════════
   PERSONAL TAB
═══════════════════════════════════════════════ */
#profileScreen{background:var(--cream);overflow-y:auto}
.profile-scroll{flex:1;overflow-y:auto;scrollbar-width:none;padding-bottom:calc(var(--safe-bottom) + var(--tab-h) + 24px)}
.profile-scroll::-webkit-scrollbar{display:none}

.profile-hero{
  padding:1.2rem 1.1rem 1rem;background:var(--paper);
  border-bottom:2px solid var(--text);position:relative;
}
.profile-avatar-row{display:flex;align-items:center;gap:.9rem}
.avatar{
  width:70px;height:70px;border-radius:50%;background:var(--primary-tint);
  border:2.5px solid var(--text);display:flex;align-items:center;justify-content:center;
  font-size:2.2rem;box-shadow:3px 3px 0 var(--text);flex-shrink:0;cursor:pointer;
  transition:transform .18s;
}
.avatar:active{transform:scale(.94)}
.profile-name-wrap{flex:1;min-width:0}
.profile-name-input{
  font-family:var(--font-display);font-size:1.4rem;font-weight:900;color:var(--primary);
  background:transparent;border:none;outline:none;letter-spacing:-.5px;
  padding:.15rem 0;border-bottom:2.5px dashed transparent;width:100%;
}
.profile-name-input:focus{border-bottom-color:var(--primary)}
.profile-name-display{
  font-family:var(--font-display);font-size:1.4rem;font-weight:900;color:var(--primary);
  letter-spacing:-.5px;padding:.15rem 0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.profile-tagline{font-size:.78rem;color:var(--text2);font-weight:600;margin-top:.15rem}

.avatar-picker{display:flex;flex-wrap:wrap;gap:.5rem}
.avatar-pick-btn{
  width:44px;height:44px;border-radius:50%;background:var(--white);
  border:2px solid var(--text);display:flex;align-items:center;justify-content:center;
  font-size:1.3rem;box-shadow:2px 2px 0 var(--text);transition:all .12s;flex-shrink:0;
}
.avatar-pick-btn:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}
.avatar-pick-btn.active{background:var(--primary-tint);border-color:var(--primary-2);box-shadow:2px 2px 0 var(--primary-2)}

/* Photo avatars (users.avatar). Inline by default — sized like an icon
   so it can sit in running text (dup-check prompt, linked-group author) —
   and filling the circle in every dedicated avatar container. */
.avatar-img{display:inline-block;width:1.15em;height:1.15em;border-radius:50%;object-fit:cover;vertical-align:-.22em;background:var(--cream-2)}
.social-avatar .avatar-img,.post-avatar .avatar-img,.comment-avatar .avatar-img,
.follower-avatar .avatar-img,.dup-check-avatar .avatar-img,.ci-viewer-avatar .avatar-img,
.avatar-row-preview .avatar-img,.avatar-current .avatar-img{display:block;width:100%;height:100%;vertical-align:0}

/* Own profile: the avatar is a button with a small pencil badge. */
.social-avatar.is-editable{position:relative;cursor:pointer;padding:0;font:inherit;font-size:2.3rem;color:inherit}
.social-avatar.is-editable:active{transform:scale(.95)}
.social-avatar.is-editable:focus-visible{outline:2px solid var(--primary);outline-offset:3px}
.social-avatar-edit{
  position:absolute;right:-4px;bottom:-4px;width:30px;height:30px;border-radius:50%;
  background:var(--primary);color:var(--cream);border:2px solid var(--text);
  display:flex;align-items:center;justify-content:center;box-shadow:1.5px 1.5px 0 var(--text);
}
.social-avatar-edit .icon{width:15px;height:15px}
.social-report-link{
  display:inline-flex;align-items:center;gap:.3rem;margin-top:.6rem;padding:.3rem .5rem;
  background:none;border:none;color:var(--text3);font:inherit;font-size:.74rem;font-weight:700;cursor:pointer;
}
.social-report-link .icon{width:14px;height:14px}
.social-report-link[data-state="armed"]{color:var(--primary)}
.social-report-link[data-state="sent"]{color:var(--text3);cursor:default}

/* Account modal row: current avatar + "Đổi avatar" */
.avatar-row{display:flex;align-items:center;gap:.8rem}
.avatar-row .data-btn{flex:0 0 auto}
.avatar-row-preview{
  width:48px;height:48px;border-radius:50%;flex-shrink:0;overflow:hidden;
  background:var(--accent);border:2px solid var(--text);box-shadow:2px 2px 0 var(--text);
  display:flex;align-items:center;justify-content:center;font-size:1.35rem;
}

/* Avatar sheet */
.avatar-current{
  width:96px;height:96px;margin:.2rem auto 1rem;border-radius:50%;overflow:hidden;
  background:var(--accent);border:3px solid var(--text);box-shadow:2.5px 3px 0 var(--text);
  display:flex;align-items:center;justify-content:center;font-size:2.6rem;
}
.avatar-photo-actions{display:flex;gap:.5rem}
.avatar-photo-actions .data-btn{cursor:pointer}
.avatar-photo-actions.is-disabled .data-btn{opacity:.45;cursor:not-allowed}
.visually-hidden{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);border:0;opacity:0}
.avatar-note{font-size:.76rem;color:var(--text2);font-weight:600;text-align:center;margin:.6rem 0 0;line-height:1.4}
.avatar-remove-photo{
  display:block;margin:.7rem auto 0;background:none;border:none;font:inherit;
  font-size:.8rem;font-weight:800;color:var(--primary);text-decoration:underline;cursor:pointer;
}
#avatarChoose .row-label{margin-top:1rem}
#avatarChoose .avatar-picker{justify-content:center}
.avatar-crop-stage{
  position:relative;width:min(100%,260px);aspect-ratio:1/1;margin:.2rem auto 0;overflow:hidden;
  border-radius:18px;background:var(--text);touch-action:none;cursor:grab;user-select:none;-webkit-user-select:none;
}
.avatar-crop-stage:active{cursor:grabbing}
.avatar-crop-stage img{position:absolute;top:0;left:0;max-width:none;transform-origin:0 0;pointer-events:none;-webkit-user-drag:none}
/* Everything outside the circle is dimmed — what's inside is exactly
   what gets saved (the export is square; avatars render as circles). */
.avatar-crop-mask{position:absolute;inset:0;border-radius:50%;box-shadow:0 0 0 999px rgba(42,24,16,.55);border:2px solid var(--cream);pointer-events:none}
.avatar-zoom{display:block;width:min(100%,260px);margin:.9rem auto 0;accent-color:var(--primary);height:28px}
#avatarModal.is-busy .modal-sheet{cursor:progress}

.profile-stats{
  display:grid;grid-template-columns:repeat(4,1fr);gap:.4rem;margin-top:1rem;
}
.stat-card{
  background:var(--white);border:2px solid var(--text);border-radius:14px;
  padding:.55rem .3rem;text-align:center;box-shadow:2px 2px 0 var(--text);
  cursor:pointer;transition:transform .12s,box-shadow .12s;user-select:none;
}
.stat-card:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}
.stat-card:focus-visible{outline:2px solid var(--primary);outline-offset:2px}
.stat-num{font-family:var(--font-display);font-size:1.1rem;font-weight:900;color:var(--primary);line-height:1}
.stat-lbl{font-size:.58rem;color:var(--text2);font-weight:700;margin-top:.2rem;letter-spacing:.2px}

.profile-section{padding:1rem 1.1rem .5rem}
.psec-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:.6rem}
.psec-title{font-family:var(--font-display);font-size:1.15rem;font-weight:900;color:var(--text);letter-spacing:-.3px}
.psec-title em{font-style:italic;color:var(--primary)}

/* Ô tìm kiếm tự ẩn/hiện khi lướt feed.
   KHÔNG animate height/max-height/margin vì bất kỳ dimension transition
   nào cũng trigger layout reflow trên mỗi frame → giật scroll.
   Thay bằng: height snap NGAY (không transition), chỉ opacity fade.
   — Thu gọn: opacity→0 trước, height→0 sau 0.15s (delay trên .collapsed)
   — Mở ra : height→60px ngay, opacity→1 tiếp theo (delay trên base state) */
#communitySearchGroup{
  height:60px;overflow:hidden;
  transition:opacity .15s ease;           /* expand: height snap, opacity fade-in */
}
#communitySearchGroup.scroll-collapsed{
  height:0;opacity:0;margin-bottom:0;
  transition:opacity .15s ease,height 0s linear .15s; /* collapse: fade-out, then snap height */
}
/* .tabbar.scroll-hidden rule sống ở khối tabbar chính phía trên — nơi có cả
   opacity fade + pointer-events + preserve translateX(-50%) của pill nổi. */

/* Cộng đồng — header kiểu IG Reels/Friends THẬT: không có thanh/bar nền
   đặc, chữ nổi trực tiếp lên trên feed (ảnh mẫu Vinh gửi 2026-09-20:
   header IG luôn trong suốt, video/ảnh tràn ngay dưới chữ). Tăng cỡ chữ
   để tạo cảm giác bài viết tràn ra kín màn hình thay vì bị 1 thanh chắn.
   Vì không có nền đặc, độ tương phản dựa vào 2 lớp: (1) gradient mờ
   đậm-trên-nhạt-dưới qua ::before — chỉ để tách vùng chữ/icon khỏi feed
   cho dễ nhìn hơn (Vinh phản hồi 2026-09-20 "cơ chế đúng nhưng hơi khó
   nhìn"), KHÔNG phải nền đặc như bản cũ; (2) tự đổi màu CHỮ theo nội
   dung ngay dưới: mặc định giả định đang đè lên ảnh (post-photo, có thể
   sáng/tối/nhiều màu) nên dùng chữ SÁNG (cream) + text-shadow; khi lướt
   tới đoạn nền trắng/kem thật (post-head/post-body, không ảnh che) thì
   đổi hẳn sang chữ TỐI, gradient giảm bớt (không tắt hẳn — Vinh 2026-09-21
   muốn feed/chức năng LUÔN tách rõ, kể cả trên nền trắng) — xem
   CommunityCtrl._initSubtabContrastObserver().
   Sticky nên luôn hiện khi lướt feed, độc lập với tabbar dưới. Có gạch
   chân dưới tab active (Vinh phản hồi 2026-09-20: cần dấu hiệu rõ đang ở
   màn nào) — dùng currentColor nên tự đổi màu theo state, không cần
   khai riêng cho on-light. */
.comm-subtabs{
  position:sticky;top:0;z-index:5;
  display:flex;align-items:center;gap:.4rem;
  padding:.7rem .5rem;margin-bottom:.4rem;
  background:transparent;
}
.comm-subtabs::before{
  content:'';position:absolute;top:0;left:0;right:0;height:88px;z-index:-1;
  background:linear-gradient(to bottom, rgba(20,10,5,.4) 0%, rgba(20,10,5,.14) 55%, transparent 100%);
  pointer-events:none;transition:opacity .25s ease;
}
/* Vẫn giữ gradient khi ở trạng thái nền trắng (on-light), chỉ giảm bớt —
   tách feed/chức năng phải luôn rõ (Vinh 2026-09-21), không tắt hẳn như
   bản trước (opacity:0), vì lúc đó header lại "trần trụi" trở lại. */
.comm-subtabs.on-light::before{opacity:.4}
.comm-hdr-iconbtn{
  width:34px;height:34px;border-radius:50%;flex-shrink:0;
  background:none;border:none;display:flex;align-items:center;justify-content:center;
  color:var(--cream);filter:drop-shadow(0 1px 3px rgba(20,10,5,.45));
  transition:color .18s,filter .18s,background-color .18s,width .18s,height .18s;
}
.comm-hdr-iconbtn.hidden{display:none}
/* Nút "Đăng quán" — to hơn hẳn + nền đỏ đặc (Vinh 2026-09-21: khó bấm/khó
   thấy vì trước chỉ là icon mảnh trong suốt). Có nền riêng nên không cần
   ăn theo màu chữ sáng/tối của header nữa — luôn rõ bất kể đang đè lên
   ảnh hay đoạn nền trắng. Nút "Đăng nhập" của khách dùng chung kiểu
   (Vinh 2026-09-29): cùng 1 chỗ, đăng nhập xong thành nút Đăng quán. */
#communityAddBtn,#communityGuestSignIn{
  width:42px;height:42px;font-size:1.25rem;
  background:var(--primary);color:var(--cream);
  box-shadow:0 3px 10px rgba(20,10,5,.35);filter:none;
}
#communityAddBtn:active,#communityGuestSignIn:active{background:var(--primary-2)}
.comm-subtabs.on-light #communityAddBtn,
.comm-subtabs.on-light #communityGuestSignIn{color:var(--cream);filter:none}
.comm-hdr-spacer{visibility:hidden;pointer-events:none}
.comm-subtabs-center{flex:1;display:flex;align-items:center;justify-content:center;gap:1.3rem}
.comm-subtab{
  background:none;border:none;font-family:var(--font-display);font-weight:800;
  font-size:1rem;color:rgba(251,243,217,.78);padding:.2rem 0 .4rem;position:relative;
  text-shadow:0 1px 3px rgba(20,10,5,.45);
  transition:color .18s,font-size .15s,text-shadow .18s;
}
.comm-subtab.active{font-size:1.18rem;color:var(--cream)}
.comm-subtab.active::after{
  content:'';position:absolute;bottom:0;left:12%;right:12%;height:2.5px;
  background:currentColor;border-radius:2px;
}
/* Nền trắng/kem thật phía dưới (post-head/post-body, không ảnh che) —
   chữ sáng sẽ chìm nên đổi hẳn sang tối, bỏ shadow + gradient vì không
   cần nữa (nền đã đủ sáng, gradient tối sẽ làm xấu và giảm tương phản). */
.comm-subtabs.on-light .comm-subtab{color:var(--text3);text-shadow:none}
.comm-subtabs.on-light .comm-subtab.active{color:var(--primary)}
.comm-subtabs.on-light .comm-hdr-iconbtn{color:var(--text2);filter:none}

/* Placeholder "tính năng đang cập nhật" — dùng chung cho Check-in & Lộ trình */
.coming-soon-wrap{
  flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;
  text-align:center;gap:.6rem;padding:2.5rem 1.5rem;
}
.coming-soon-ico{
  width:72px;height:72px;border-radius:50%;background:var(--primary-tint);
  color:var(--primary);display:flex;align-items:center;justify-content:center;margin-bottom:.4rem;
}
.coming-soon-title{font-family:var(--font-display);font-size:1.1rem;font-weight:900;color:var(--text)}
.coming-soon-sub{font-size:.85rem;color:var(--text2);max-width:280px;line-height:1.5}
.add-btn{
  display:flex;align-items:center;gap:.3rem;padding:.4rem .75rem;
  background:var(--primary);color:var(--cream);border-radius:20px;
  font-family:var(--font-display);font-size:.78rem;font-weight:800;font-style:italic;
  border:2px solid var(--text);box-shadow:2px 2px 0 var(--text);transition:all .12s;
}
.add-btn:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}

.pref-chips{display:flex;flex-wrap:wrap;gap:.4rem}
.pref-chip{
  padding:.4rem .8rem;border-radius:20px;border:2px solid var(--text);
  background:var(--white);font-size:.78rem;font-weight:700;color:var(--text);
  transition:all .12s;box-shadow:2px 2px 0 var(--text);
}
.pref-chip:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}
.pref-chip.active{background:var(--primary);color:var(--cream);box-shadow:2px 2px 0 var(--primary-2);border-color:var(--primary-2)}

/* Settings modal — section divider + toggle switch + tappable summary row */
.settings-divider{border-top:2px dashed var(--line-2);margin:1.1rem 0}

.switch-row{display:flex;align-items:center;justify-content:space-between;gap:.6rem}
.switch-label{font-size:.8rem;font-weight:700;color:var(--text)}
.switch-hint{font-size:.68rem;color:var(--text3);font-weight:600;margin-top:1px}
.switch{
  width:44px;height:26px;border-radius:14px;background:var(--cream-3);
  border:2px solid var(--text);position:relative;flex-shrink:0;cursor:pointer;
  transition:background .15s;padding:0;
}
.switch-knob{
  width:18px;height:18px;border-radius:50%;background:var(--paper);
  position:absolute;top:1px;left:1px;transition:left .15s;
}
.switch.on{background:var(--primary)}
.switch.on .switch-knob{left:19px}
.switch.disabled{opacity:.55;pointer-events:none}

.settings-row{
  display:flex;align-items:center;justify-content:space-between;gap:.6rem;
  background:var(--white);border:2px solid var(--text);border-radius:14px;
  padding:.65rem .8rem;box-shadow:2px 2px 0 var(--text);cursor:pointer;transition:all .12s;
}
.settings-row:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}
.settings-row-count{font-size:.72rem;font-weight:700;color:var(--text3)}
.settings-row-arrow{color:var(--primary);font-weight:900}

.logout-row{
  text-align:center;padding:.6rem;font-family:var(--font-display);
  font-size:.8rem;font-weight:800;font-style:italic;color:var(--primary);cursor:pointer;
}

.my-r-del{
  width:2rem;height:2rem;border-radius:50%;background:var(--paper);
  border:1.5px solid var(--text2);color:var(--text2);font-size:.9rem;
  display:flex;align-items:center;justify-content:center;flex-shrink:0;
  transition:all .12s;
}
.my-r-del:active{background:var(--primary);color:var(--cream);border-color:var(--primary-2)}

/* Empty state on the profile grid — dropped the dashed box + paper
   background because it felt "disconnected" from the hero above; now
   it's an illustration-style placeholder that flows out of the hero
   directly. CTA button gets the user to the community post form in
   one tap instead of forcing them to hunt for it. */
.empty-my-r{
  padding:2.5rem 1.5rem 3rem;text-align:center;background:transparent;
  border:none;border-radius:0;color:var(--text3);
}
.empty-my-r .em-icon{
  font-size:3rem;margin-bottom:.55rem;line-height:1;
  filter:grayscale(.25) opacity(.75);
}
.empty-my-r .em-msg{
  font-family:var(--font-display);font-size:1.1rem;font-weight:900;
  color:var(--text);font-style:italic;letter-spacing:-.2px;
}
.empty-my-r .em-sub{
  font-size:.8rem;color:var(--text2);margin-top:.4rem;font-weight:500;
  line-height:1.5;max-width:22rem;margin-left:auto;margin-right:auto;
}
.empty-my-r .em-cta{
  display:inline-flex;align-items:center;gap:.4rem;margin-top:1.1rem;
  padding:.65rem 1.3rem;background:var(--primary);color:var(--cream);
  border:2px solid var(--text);border-radius:24px;
  box-shadow:3px 3px 0 var(--text);cursor:pointer;
  font-family:var(--font-display);font-weight:900;font-style:italic;
  font-size:.92rem;letter-spacing:.3px;transition:all .12s;
}
.empty-my-r .em-cta:active{transform:translate(1px,1px);box-shadow:1.5px 1.5px 0 var(--text)}
.empty-my-r .em-auth-row{display:flex;justify-content:center;gap:.6rem;flex-wrap:wrap}
.empty-my-r .em-cta-alt{background:var(--white);color:var(--text)}

/* Data Management */
.data-actions{ display:flex;gap:.5rem;margin-top:.6rem; }
.data-btn{
  flex:1;display:flex;align-items:center;justify-content:center;gap:.3rem;
  padding:.6rem .75rem;border-radius:14px;
  border:2px solid var(--text);background:var(--white);color:var(--text);
  font-size:.78rem;font-weight:700;
  box-shadow:2px 2px 0 var(--text);transition:all .12s;
}
.data-btn:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}
.data-btn.import{background:var(--accent);color:var(--cream);border-color:var(--accent-2);box-shadow:2px 2px 0 var(--accent-2)}
#importFileInput{display:none}

/* ── Gemini AI key section ── */
.ai-status{font-size:.72rem;font-weight:800;letter-spacing:.02em}
.ai-hint{font-size:.76rem;color:var(--text-muted,#8a7f6a);line-height:1.4;margin:.4rem 0 .6rem}
.ai-key-row{display:flex;gap:.4rem;align-items:stretch}
.ai-key-row .form-input{flex:1}
.ai-key-toggle{
  width:44px;flex-shrink:0;border:2px solid var(--text);border-radius:14px;
  background:var(--white);font-size:1rem;box-shadow:2px 2px 0 var(--text);
  cursor:pointer;transition:all .12s;
}
.ai-key-toggle:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}
.ai-key-actions{display:flex;gap:.5rem;margin-top:.5rem}
.ai-getkey{
  display:inline-block;margin-top:.55rem;font-size:.75rem;font-weight:700;
  color:var(--primary);text-decoration:none;border-bottom:1.5px dashed var(--primary);
}

/* ═══════════════════════════════════════════════
   MODAL (Add restaurant)
═══════════════════════════════════════════════ */
.modal-overlay{
  position:fixed;inset:0;z-index:200;background:rgba(42,24,16,.5);
  display:flex;align-items:flex-end;justify-content:center;
  opacity:0;pointer-events:none;transition:opacity .25s;
}
.modal-overlay.show{opacity:1;pointer-events:auto}
.modal-sheet{
  background:var(--paper);width:100%;max-width:520px;
  border-radius:var(--radius-lg) var(--radius-lg) 0 0;
  border-top:2px solid var(--text);
  padding:1rem 1.1rem calc(var(--safe-bottom) + 1rem);
  transform:translateY(100%);transition:transform .3s cubic-bezier(.32,1,.56,1);
  max-height:90vh;overflow-y:auto;scrollbar-width:none;
}
.modal-sheet::-webkit-scrollbar{display:none}
.modal-overlay.show .modal-sheet{transform:translateY(0)}
.modal-handle{width:3rem;height:5px;background:var(--text2);border-radius:3px;margin:0 auto .8rem}
.modal-title{font-family:var(--font-display);font-size:1.5rem;font-weight:900;color:var(--primary);text-align:center;margin-bottom:.3rem;font-style:italic;letter-spacing:-.3px}
.modal-sub{font-size:.78rem;color:var(--text2);text-align:center;margin-bottom:1rem;font-weight:600}

.form-group{margin-bottom:.85rem}
.form-label{
  display:block;font-family:var(--font-display);font-size:.75rem;font-weight:800;
  color:var(--primary);letter-spacing:1px;text-transform:uppercase;margin-bottom:.35rem;
  font-style:italic;
}
.form-input,.form-textarea,.form-select{
  width:100%;background:var(--white);border:2px solid var(--text);border-radius:12px;
  padding:.6rem .85rem;font-size:.9rem;color:var(--text);outline:none;font-weight:600;
  transition:border-color .18s;box-shadow:2px 2px 0 var(--text);
  font-family:var(--font-body);
}
.form-input:focus,.form-textarea:focus,.form-select:focus{border-color:var(--primary);box-shadow:2px 2px 0 var(--primary-2)}
.form-textarea{resize:vertical;min-height:70px}

.cat-picker{display:grid;grid-template-columns:1fr 1fr;gap:.5rem}
.cat-pick-btn{
  padding:.6rem .5rem;border-radius:12px;border:2px solid var(--text);
  background:var(--white);font-size:.8rem;font-weight:700;color:var(--text);
  display:flex;align-items:center;gap:.35rem;transition:all .12s;
  box-shadow:2px 2px 0 var(--text);
}
.cat-pick-btn:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}
.cat-pick-btn.active{color:var(--cream)}
.cat-pick-btn[data-cat="restaurant"].active{background:var(--cat-restaurant);border-color:var(--primary-2);box-shadow:2px 2px 0 var(--primary-2)}
.cat-pick-btn[data-cat="street"].active{background:var(--cat-street);border-color:var(--accent-2);box-shadow:2px 2px 0 var(--accent-2)}
.cat-pick-btn[data-cat="snack"].active{background:var(--cat-snack);border-color:#A8365F;box-shadow:2px 2px 0 #A8365F}
.cat-pick-btn[data-cat="cafe"].active{background:var(--cat-cafe);border-color:#5A3B24;box-shadow:2px 2px 0 #5A3B24}
/* Price picker reuses .cat-pick-btn but keys off data-price, not data-cat */
#cfPricePicker .cat-pick-btn.active{background:var(--accent);border-color:var(--accent-2);box-shadow:2px 2px 0 var(--accent-2)}
/* Visibility picker — same reuse, keys off data-vis */
#cfVisibilityPicker .cat-pick-btn.active{background:var(--text2);border-color:var(--text);box-shadow:2px 2px 0 var(--text)}
/* Language picker (Account modal) — same reuse, keys off data-lang */
#langPicker .cat-pick-btn.active{background:var(--primary);border-color:var(--primary-2);box-shadow:2px 2px 0 var(--primary-2)}

/* Map "chọn vị trí" của modal đăng quán cộng đồng — thêm selector ở đây nếu
   sau này có picker thứ 2 (modal thêm-quán cũ, chỉ lưu local, đã gỡ). */
#communityPickerMap {
  background: #e5e3df url("data:image/svg+xml,%3Csvg width='20' height='20' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M20 0L0 20M0 0L20 20' stroke='%23d3d1cc' stroke-width='1' opacity='0.5'/%3E%3C/svg%3E");
  height:160px;border-radius:14px;overflow:hidden;border:2px solid var(--text);
  box-shadow:2px 2px 0 var(--text);cursor:crosshair;background:var(--cream-2);
}
.picker-hint{
  font-size:.72rem;color:var(--text2);text-align:center;margin-top:.35rem;
  font-weight:600;font-style:italic;
}

/* Tông ấm/thân thiện — CỐ TÌNH không dùng đỏ cảnh báo (--primary-tint) như
   1 bản trước, vì nhìn giống thông báo lỗi hệ thống. Đây là 1 gợi ý xã hội
   vui ("bạn X đã đăng rồi") nên dùng cream + cam, giống hệt tông của
   .linked-group-box bên modal chi tiết cho nhất quán cảm giác 2 chỗ. */
.dup-check-box{
  margin-top:.6rem;padding:.7rem .8rem;border-radius:14px;
  background:var(--cream-2);border:2px solid var(--text);
  box-shadow:2px 2px 0 var(--accent-2);
}
.dup-check-head{display:flex;align-items:center;gap:.55rem}
.dup-check-avatar{
  flex:0 0 auto;width:34px;height:34px;border-radius:50%;background:var(--accent);
  display:flex;align-items:center;justify-content:center;font-size:1.05rem;
  border:1.5px solid var(--text);
}
.dup-check-thumb{
  flex:0 0 auto;width:34px;height:34px;border-radius:50%;background-size:cover;
  background-position:center;border:1.5px solid var(--text);
}
.dup-check-text{font-size:.8rem;color:var(--text);line-height:1.4;font-weight:600}
.dup-check-text b{color:var(--accent-2);font-weight:800}
.dup-check-text.dup-check-confirmed{color:#2e9e5b}
.dup-check-actions{display:flex;gap:.5rem;margin-top:.55rem}
.dup-check-yes,.dup-check-no{
  flex:1;padding:.4rem .5rem;border-radius:10px;border:2px solid var(--text);
  font-size:.74rem;font-weight:800;cursor:pointer;background:var(--white);
}
.dup-check-yes{background:var(--primary);color:var(--cream);border-color:var(--primary-2)}

/* Bản nháp đã khôi phục — cố tình dùng tông xanh "đã giúp bạn giữ lại",
   KHÔNG dùng tông đỏ/cam như .dup-check-box (đó là khung cần người dùng
   quyết định); đây chỉ là thông báo kèm 1 lối thoát để làm lại từ đầu. */
.draft-banner{
  display:flex;align-items:center;gap:.55rem;
  margin:.15rem 0 .9rem;padding:.55rem .7rem;border-radius:14px;
  background:#E4F3E8;border:2px solid var(--text);
  box-shadow:2px 2px 0 #2e9e5b;
}
.draft-banner-text{flex:1;font-size:.78rem;font-weight:700;color:var(--text);line-height:1.35}
.draft-banner-discard{
  flex:0 0 auto;padding:.36rem .62rem;border-radius:10px;
  border:2px solid var(--text);background:var(--white);
  font-size:.72rem;font-weight:800;color:var(--text);cursor:pointer;
  transition:transform .12s;
}
.draft-banner-discard:active{transform:translate(1px,1px)}

.form-actions{display:flex;gap:.5rem;margin-top:1rem}
.btn-cancel{
  flex:1;padding:.8rem;border-radius:14px;background:var(--white);
  border:2px solid var(--text);color:var(--text);font-weight:800;font-size:.9rem;
  box-shadow:2px 2px 0 var(--text);transition:all .12s;
}
.btn-cancel:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}
.btn-save{
  flex:2;padding:.8rem;border-radius:14px;background:var(--primary);color:var(--cream);
  border:2px solid var(--text);font-family:var(--font-display);font-weight:900;font-size:1rem;
  letter-spacing:.3px;box-shadow:3px 3px 0 var(--text);transition:all .12s;
}
.btn-save:active{transform:translate(1.5px,1.5px);box-shadow:1.5px 1.5px 0 var(--text)}

/* Toast */
#toast{
  position:fixed;top:calc(var(--ribbon-h) + .6rem);left:50%;
  transform:translateX(-50%) translateY(-1.2rem);
  background:var(--text);color:var(--cream);
  padding:.6rem 1.15rem;border-radius:24px;font-size:.85rem;font-weight:700;
  box-shadow:0 4px 18px rgba(42,24,16,.28);border:2px solid var(--primary);
  pointer-events:none;z-index:999;opacity:0;
  transition:opacity .22s ease,transform .22s ease;
  white-space:nowrap;max-width:90vw;overflow:hidden;text-overflow:ellipsis;
}
#toast.show{opacity:1;transform:translateX(-50%) translateY(0)}

.scanning-overlay{
  position:absolute;inset:0;z-index:20;display:flex;flex-direction:column;
  align-items:center;justify-content:center;
  background:rgba(251,243,217,.92);backdrop-filter:blur(6px);gap:1rem;
}
.scanning-spinner{
  width:56px;height:56px;border:4px solid var(--primary-tint);
  border-top-color:var(--primary);border-radius:50%;animation:spin .8s linear infinite;
}
@keyframes spin{to{transform:rotate(360deg)}}
.scanning-txt{
  font-family:var(--font-display);font-size:1.1rem;font-weight:800;color:var(--primary);
  font-style:italic;text-align:center;padding:0 1rem;
}
.scanning-sub{
  font-size:.8rem;color:var(--text-muted,#888);letter-spacing:.04em;
  opacity:.8;margin-top:-.25rem;
}

.r-map-marker{
  width:26px;height:26px;border-radius:50%;display:flex;align-items:center;justify-content:center;
  font-size:.85rem;font-weight:900;color:var(--cream);
  border:2px solid var(--text);box-shadow:1.5px 1.5px 0 var(--text);
  font-family:var(--font-display);
}
.leaflet-marker-icon{transition:none!important}

.r-img-wrap {
  width: 100%;
  height: 140px;
  border-bottom: 2px solid var(--text);
  overflow: hidden;
  background: var(--cream-2);
}
.r-img-wrap img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.restaurant-card {
  overflow: hidden; /* Fix corners */
}

/* Full-list modals (my quán / trip history) — bigger height cap so
   the whole scroll area is comfortable, and a body region that scrolls
   inside the sheet instead of pushing the close button off screen. */
.list-sheet{max-height:88vh;max-height:88dvh}
.list-modal-body{
  max-height:60vh;max-height:60dvh;overflow-y:auto;
  padding:.4rem 0 .8rem;margin:.4rem -.15rem 0;
  scrollbar-width:none;-webkit-overflow-scrolling:touch;
}
.list-modal-body::-webkit-scrollbar{display:none}

/* My-quán card grid — same visual language as the results screen,
   without the checkbox (these are already yours, not being picked). */
.list-modal-body .r-grid{
  display:grid;grid-template-columns:1fr 1fr;gap:.55rem;padding:.35rem .15rem;
}
/* NOTE: keep overflow visible so the ⭐/🌐/✨ corner badges on
   .r-card.user-added / .osm-added / .gemini-added aren't clipped.
   The image is instead given its own top-corner radius that lines
   up with the card's outer rounding. */
.list-modal-body .r-img-mini{
  display:block;object-fit:cover;
  height:80px;width:calc(100% + 1.5rem);
  margin:-.75rem -.75rem .55rem;
  border-radius:12px 12px 0 0;
  border-bottom:2px solid var(--text);
}

/* Trip-history stack — each trip is a labeled section, each stop is a
   flat name+address bar (no card decoration, just a strip). */
.trip-item{
  padding:.4rem .15rem;
  border-bottom:2px dashed var(--line);
}
.trip-item:last-child{border-bottom:none}
.trip-date{
  font-family:var(--font-display);font-size:.82rem;font-weight:800;
  color:var(--primary);font-style:italic;letter-spacing:.3px;
  padding:.35rem .55rem;margin-bottom:.4rem;
}
.trip-date-row{display:flex;align-items:center;justify-content:space-between;gap:.5rem}
.trip-date-row .trip-date{padding:.35rem 0 .35rem .55rem;margin-bottom:0;flex:1;min-width:0}
.trip-replay-btn{
  flex-shrink:0;padding:.35rem .7rem;margin:0 .15rem .4rem 0;border-radius:20px;
  font-size:.72rem;font-weight:800;white-space:nowrap;
  border:2px solid var(--text);background:var(--white);color:var(--text);
  box-shadow:2px 2px 0 var(--text);transition:all .12s;
}
.trip-replay-btn:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}
.trip-stop-box{
  display:flex;align-items:center;gap:.55rem;
  padding:.55rem .75rem;margin-bottom:.4rem;
  background:var(--white);border:2px solid var(--text);border-radius:12px;
  box-shadow:2px 2px 0 var(--text);cursor:pointer;
  transition:transform .12s,box-shadow .12s;
}
.trip-stop-box:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}
.trip-stop-box:last-child{margin-bottom:.15rem}
.trip-stop-idx{
  flex-shrink:0;width:1.6rem;height:1.6rem;border-radius:50%;
  background:var(--primary);color:var(--cream);
  display:flex;align-items:center;justify-content:center;
  font-family:var(--font-display);font-weight:900;font-size:.85rem;
  border:1.5px solid var(--text);
}
.trip-stop-info{flex:1;min-width:0}
.trip-stop-name{
  font-family:var(--font-display);font-weight:900;font-size:.9rem;
  color:var(--text);line-height:1.15;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.trip-stop-addr{
  font-size:.7rem;color:var(--text2);font-weight:600;margin-top:.1rem;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}

/* Empty state inside modals */
.list-empty{
  text-align:center;padding:2rem .5rem 1rem;color:var(--text2);
}
.list-empty-icon{font-size:2.4rem;margin-bottom:.4rem}
.list-empty-msg{font-family:var(--font-display);font-weight:800;font-size:1rem;color:var(--text)}
.list-empty-sub{font-size:.8rem;margin-top:.3rem;font-weight:600}

/* Restaurant detail modal — read-only view of a saved quán */
.detail-sheet .r-img-wrap{
  margin:-1rem -1.1rem 1rem;
  border-radius:var(--radius-lg) var(--radius-lg) 0 0;
  border-bottom:2px solid var(--text);
  height:180px;
}
/* Community detail — horizontal scroll strip, up to 4 ảnh/quán */
.detail-photo-strip{
  display:flex;gap:.5rem;overflow-x:auto;margin:-1rem -1.1rem 1rem;padding:0 1.1rem 0;
  scrollbar-width:none;
}
.detail-photo-strip::-webkit-scrollbar{display:none}
.detail-photo-strip img{
  width:220px;height:165px;object-fit:cover;border-radius:14px;
  border:2px solid var(--text);flex-shrink:0;
}
.detail-photo-strip:first-child{margin-top:-1rem}
.detail-cat{
  display:inline-flex;align-items:center;gap:.35rem;
  padding:.3rem .7rem;border-radius:20px;font-size:.75rem;font-weight:800;
  border:2px solid currentColor;margin:0 auto .5rem;
}
.detail-cat-wrap{text-align:center}
.detail-name{
  font-family:var(--font-display);font-size:1.6rem;font-weight:900;
  color:var(--text);text-align:center;line-height:1.15;
  margin:0 0 .6rem;letter-spacing:-.3px;
}
.detail-meta{
  display:flex;gap:.5rem;justify-content:center;flex-wrap:wrap;
  margin-bottom:1rem;
}
.detail-meta span{
  background:var(--cream-2);border:2px solid var(--text);border-radius:20px;
  padding:.35rem .75rem;font-size:.78rem;font-weight:700;color:var(--text);
}
.detail-desc{
  background:var(--cream-2);border:2px solid var(--text);border-radius:14px;
  padding:.8rem .9rem;font-size:.9rem;line-height:1.5;color:var(--text);
  margin-bottom:.4rem;font-weight:500;
}
.detail-address{
  background:var(--paper);border:1.5px dashed var(--text2);border-radius:12px;
  padding:.6rem .8rem;font-size:.82rem;line-height:1.4;color:var(--text);
  font-weight:600;margin:.4rem 0;
}
.detail-coords{
  font-size:.72rem;color:var(--text2);text-align:center;
  margin-top:.5rem;font-weight:600;font-style:italic;
}
.detail-coords.warn{
  color:#B92626;background:#F7D6BB;padding:.5rem;border-radius:10px;
  font-style:normal;font-weight:700;
}
.detail-demo-note{
  font-size:.72rem;line-height:1.4;color:var(--text2);
  opacity:.7;font-style:italic;font-weight:500;
  margin:.35rem 0 .1rem;padding:0 .2rem;
}

/* ═══════════════════════════════════════════════
   iOS-STYLE MOTION POLISH
   Springy easing, tactile scale-press, hover lift.
   Layered on top of the brutalist look — the offset
   shadow presses stay, but now with a soft squish.
═══════════════════════════════════════════════ */

/* Smooth, spring-eased transitions on every interactive control */
.tab-btn,.dish-chip,.cat-chip,.radius-chip,.loc-gps-btn,.scan-btn,
.back-btn,.reshuffle-btn,.cat-tab,.r-card,.r-check,.r-gmaps-link,
.action-btn,.pmap-btn,.dwell-btn,.data-btn,.ai-key-toggle,.pref-chip,
.stat-card,.add-btn,.avatar,.go-item,.cat-pick-btn,.avatar-pick-btn{
  transition:transform .26s var(--ease-out),
             box-shadow .26s var(--ease-out),
             background-color .2s var(--ease-ios),
             color .2s var(--ease-ios),
             border-color .2s var(--ease-ios),
             opacity .2s var(--ease-ios) !important;
  -webkit-user-select:none;user-select:none;touch-action:manipulation;
}

/* Tactile squish on press — combine the brutalist offset with a scale.
   The spring return gives that iOS "pop back" feel. */
.scan-btn:active,.action-btn:active{transform:translate(2px,2px) scale(.97) !important}
.cat-chip:active,.radius-chip:active,.cat-tab:active,.back-btn:active,
.reshuffle-btn:active,.loc-gps-btn:active,.data-btn:active,
.ai-key-toggle:active,.pmap-btn:active,.r-check:active{
  transform:translate(1px,1px) scale(.95) !important;
}
.r-card:active{transform:translate(1px,1px) scale(.985) !important}
.tab-btn:active{transform:scale(.9) !important}
.pref-chip:active,.cat-pick-btn:active,.dish-chip:active,.go-item:active,.avatar-pick-btn:active{transform:scale(.93) !important}
.stat-card:active{transform:scale(.95) !important}
.avatar:active{transform:scale(.9) !important}
.dwell-btn:active{transform:scale(.85) !important}

/* Release spring — when NOT pressed, elements bounce back with overshoot */
.cat-chip,.radius-chip,.cat-tab,.pref-chip,.dish-chip,.stat-card,
.tab-btn,.r-check,.dwell-btn,.avatar,.cat-pick-btn{
  transition-timing-function:var(--ease-spring) !important;
}

/* Chip activation — springy scale pop when toggled on */
@keyframes chip-pop{0%{transform:scale(1)}45%{transform:scale(1.08)}100%{transform:scale(1)}}
.cat-chip.active,.radius-chip.active,.pref-chip.active,
.cat-tab.active,.src-chip.active,.dish-chip.active{
  animation:chip-pop .34s var(--ease-spring);
}

/* Desktop hover lift — only on real pointers (never on touch) */
@media (hover:hover) and (pointer:fine){
  .scan-btn:hover,.action-btn:hover{transform:translateY(-2px)}
  .cat-chip:hover,.radius-chip:hover,.cat-tab:hover,.data-btn:hover,
  .reshuffle-btn:hover,.back-btn:hover,.pref-chip:hover,.stat-card:hover,
  .pmap-btn:hover,.ai-key-toggle:hover,.loc-gps-btn:hover{transform:translateY(-1.5px)}
  .r-card:hover{transform:translateY(-3px);box-shadow:5px 6px 0 var(--text)}
  .tab-btn:hover .tab-ico{transform:scale(1.12)}
  .r-gmaps-link:hover{transform:scale(1.03)}
  .avatar:hover{transform:scale(1.06) rotate(-4deg)}
}

/* Icon micro-motion — checkmark springs in when selected */
@keyframes check-pop{0%{transform:scale(.4);opacity:0}60%{transform:scale(1.15)}100%{transform:scale(1);opacity:1}}
.r-card.selected .r-check{animation:check-pop .32s var(--ease-spring)}

/* GPS button pulse feels alive on press */
.loc-gps-btn:active{transform:scale(.9) !important}

/* Respect reduced-motion preference */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms !important;animation-iteration-count:1 !important;
    transition-duration:.05ms !important}
}

/* ═══════════════════════════════════════════════
   GENERIC UTILITY
═══════════════════════════════════════════════ */
.hidden{display:none !important}

/* ═══════════════════════════════════════════════
   COMMUNITY — auth form, restaurant cards, add-quán modal
═══════════════════════════════════════════════ */
.community-toggle-link{
  display:block;width:100%;text-align:center;margin-top:.6rem;
  font-size:.78rem;font-weight:700;color:var(--primary);
  text-decoration:none;border-bottom:none;background:none;
}
.community-toggle-link:active{opacity:.6}

/* (Guest CTA banner styles removed 2026-09-11 — banners felt too
   intrusive; kept a small "Đăng nhập" .add-btn in the tab header for
   guest sign-up entry instead.) */

/* Restaurant card — like my-r-card but with a taller cover photo + chip rows */
/* Xem ảnh cỡ lớn (chế độ sửa bài). z-index trên cả modal-overlay vì nó
   được mở TỪ trong modal sửa quán. */
.photo-view{
  position:fixed;inset:0;z-index:1200;
  display:flex;align-items:center;justify-content:center;
  background:rgba(24,14,9,.92);padding:1.2rem;
  animation:photo-view-in .18s ease-out;
}
/* BẮT BUỘC: display:flex ở trên đè mất display:none mặc định của thuộc
   tính [hidden]. Thiếu dòng này thì sau khi đóng, overlay vẫn nằm đó
   trong suốt, phủ kín inset:0 ở z-index 1200 và nuốt mọi cú chạm của
   toàn app cho tới khi tải lại trang. */
.photo-view[hidden]{display:none}
.photo-view img{max-width:100%;max-height:100%;border-radius:12px;border:2px solid var(--cream)}
.photo-view-close{
  position:absolute;top:calc(var(--safe-top) + .7rem);right:.9rem;
  width:38px;height:38px;border-radius:50%;cursor:pointer;
  background:var(--cream);color:var(--text);border:2px solid var(--text);
  font-size:1rem;font-weight:800;line-height:1;
}
@keyframes photo-view-in{from{opacity:0}to{opacity:1}}
@media (prefers-reduced-motion:reduce){.photo-view{animation:none}}

/* "N quán mới" — hiện khi poller thấy bài mới LÚC người dùng đang cuộn
   giữa feed.
   Dock cao 0px: pill nằm absolute bên trong nên KHÔNG chiếm chỗ trong
   luồng. Bản đầu để pill sticky thẳng trong luồng thì nó đội list xuống
   ~47px; Chrome/Firefox có scroll anchoring tự bù nên nhìn không thấy,
   nhưng Safari KHÔNG hỗ trợ scroll anchoring → trên iPhone nội dung sẽ
   giật nảy đúng lúc người ta đang đọc. Cao 0 thì không máy nào giật.
   Sticky (không phải fixed) nên pill bám trong vùng feed, không bao giờ
   đè lên #toast ở đỉnh màn hình. */
.new-posts-dock{position:sticky;top:0;height:0;z-index:6;overflow:visible}
.new-posts-pill{
  position:absolute;top:.35rem;left:50%;transform:translateX(-50%);
  padding:.5rem 1rem;border-radius:22px;white-space:nowrap;
  background:var(--primary);color:var(--cream);
  border:2px solid var(--text);box-shadow:2px 2px 0 var(--text);
  font-size:.8rem;font-weight:800;cursor:pointer;
  animation:new-pill-in .26s ease-out;
}
.new-posts-pill:active{transform:translateX(-50%) translate(1px,1px);box-shadow:1px 1px 0 var(--text)}
@keyframes new-pill-in{
  from{opacity:0;transform:translateX(-50%) translateY(-8px)}
  to{opacity:1;transform:translateX(-50%)}
}
@media (prefers-reduced-motion:reduce){.new-posts-pill{animation:none}}

/* padding-bottom = tab-h (56) + bottom margin (14) + safe area + hơi thở
   để post cuối không nằm dưới pill tab bar khi cuộn hết feed. */
.comm-r-list{display:flex;flex-direction:column;gap:.75rem;padding-bottom:calc(var(--safe-bottom) + var(--tab-h) + 24px)}
/* Feed reads as one continuous scroll (posts separated by their own
   border-bottom divider, not a container gap) — the grid-based profile
   views (myRestaurantList/userQuanBody) keep the normal .75rem gap between
   the header block and the grid below it. */
#communityList.comm-r-list{gap:0}
.comm-r-card{
  background:var(--white);border:2px solid var(--text);border-radius:var(--radius);
  box-shadow:3px 3px 0 var(--text);overflow:hidden;
}
.comm-r-cover{
  height:140px;background:var(--cream-2) center/cover no-repeat;
  display:flex;align-items:center;justify-content:center;font-size:2.2rem;
  border-bottom:2px solid var(--text);
}
.comm-r-body{padding:.75rem}
.comm-r-top{display:flex;align-items:flex-start;justify-content:space-between;gap:.5rem}
.comm-r-name{font-family:var(--font-display);font-size:1rem;font-weight:900;color:var(--text);letter-spacing:-.2px;line-height:1.25}
.comm-r-meta{font-size:.72rem;color:var(--text2);font-weight:600;margin-top:.15rem}
.comm-r-desc{font-size:.78rem;color:var(--text3);margin-top:.45rem;line-height:1.45}
.comm-r-chips{display:flex;flex-wrap:wrap;gap:.3rem;margin-top:.55rem}
.comm-r-chip{
  padding:.2rem .55rem;border-radius:20px;font-size:.68rem;font-weight:700;
  background:var(--cream-2);color:var(--text2);border:1.5px solid var(--line-2);
}
.comm-r-chip.hashtag{background:var(--primary-tint);color:var(--primary-2)}
.comm-r-footer{display:flex;align-items:center;justify-content:space-between;gap:.5rem;margin-top:.65rem;padding-top:.6rem;border-top:1.5px dashed var(--line-2)}
.comm-r-author{font-size:.7rem;color:var(--text3);font-weight:600}

/* ── Feed post (Instagram-style, Cộng đồng browse tab) ────────────────── */
/* content-visibility:auto — browser bỏ qua render/paint post nằm ngoài
   viewport, giải quyết jank scroll trên feed dài. contain-intrinsic-size
   ước tính chiều cao để thanh cuộn không nhảy trước khi items render. */
.post-card{
  content-visibility:auto;contain-intrinsic-size:auto 700px;
  border:none;border-radius:0;box-shadow:none;background:var(--white);
  border-bottom:8px solid var(--cream-3);overflow:visible;
}
.post-head{display:flex;align-items:center;gap:.6rem;padding:.7rem .8rem .5rem}
.post-avatar{
  width:38px;height:38px;flex:0 0 auto;border-radius:50%;border:2px solid var(--text);
  background:var(--cream-2);display:flex;align-items:center;justify-content:center;
  font-size:1.2rem;cursor:pointer;
}
.post-head-info{flex:1;min-width:0;text-align:left}
.post-author-name{
  display:block;font-weight:800;font-size:.88rem;color:var(--text);background:none;border:none;
  padding:0;text-align:left;cursor:pointer;
}
.post-meta-line{font-size:.72rem;color:var(--text3);margin-top:.1rem}

/* 4:5 (chuẩn Instagram) — xem ghi chú ở communityCardHtml() trong
   controllers.js. Thumbnail đã crop-fill đúng 4:5 từ server nên
   background-size:cover ở dưới chỉ là fallback an toàn. */
.post-carousel{position:relative;width:100%;aspect-ratio:4/5;background:var(--cream-2)}
/* Chỉ cap chiều cao ở feed (.comm-r-card) — ảnh dọc-dài (9:16) vẫn giữ
   nguyên 4:5 nhưng không được kéo dài quá 60% màn hình khi cuộn feed,
   che hết caption/nút bên dưới. Modal chi tiết (mở riêng để xem) KHÔNG
   bị cap — cố ý, người dùng đã chủ động bấm vào để xem ảnh đầy đủ hơn. */
.comm-r-card .post-carousel{max-height:60vh}
.post-carousel-track{
  display:flex;width:100%;height:100%;overflow-x:auto;scroll-snap-type:x mandatory;
  scrollbar-width:none;
}
.post-carousel-track::-webkit-scrollbar{display:none}
.post-photo{
  flex:0 0 100%;width:100%;height:100%;scroll-snap-align:start;
  background-size:cover;background-position:center;
}
.post-photo-empty{display:flex;align-items:center;justify-content:center;font-size:3rem}
.post-dots{position:absolute;bottom:10px;left:0;right:0;display:flex;justify-content:center;gap:5px}
.post-dot{width:6px;height:6px;border-radius:50%;background:rgba(255,255,255,.55)}
.post-dot.active{background:var(--white)}

.post-body{padding:.6rem .8rem .8rem}
/* Icon row: ❤ 14 · 💬 · ↗ ................ 🔖 (save pushed right, mimic IG) */
.post-actions{display:flex;align-items:center;gap:1rem;margin-bottom:.35rem}
.heart-count{margin-left:-.55rem} /* kéo count sát heart, thoát cái gap chung */
.save-icon-btn{margin-left:auto}
.heart-btn{
  border:none;background:none;padding:0;font-size:1.5rem;line-height:1;cursor:pointer;
  color:var(--text);transition:transform .15s var(--ease-spring);
}
.heart-btn:active{transform:scale(1.3)}
.heart-btn.voted .heart-ico{color:var(--primary)}
.heart-count{font-size:.85rem;font-weight:800;color:var(--text2)}
/* Bình luận/Chia sẻ/Lưu ngay trên card feed — lối tắt, KHÔNG cần mở
   modal chi tiết cho share/save; comment mở modal (cần ô nhập + danh
   sách) nhưng cuộn thẳng tới, không cần user tự cuộn tay. */
.post-action-btn{
  border:none;background:none;padding:0;font-size:1.15rem;line-height:1;
  cursor:pointer;color:var(--text2);transition:transform .12s var(--ease-spring);
}
.post-action-btn:active{transform:scale(1.25)}
/* 🔖 là emoji màu cố định — CSS color không nhuộm lại được, nên dùng
   opacity để phân biệt đã lưu/chưa thay vì đổi màu như heart-ico (♡/♥
   là ký tự outline/filled thường, không phải emoji, nên color áp được). */
.post-action-btn.save-icon-btn{opacity:.5}
.post-action-btn.save-icon-btn.on{opacity:1}
.post-cat-pill{font-size:.68rem;font-weight:800;padding:.25rem .6rem;border-radius:20px;white-space:nowrap}
.post-badge-row{display:flex;justify-content:flex-end;padding:2px 0 6px}
.post-caption{font-size:.85rem;line-height:1.5;color:var(--text)}
.post-caption b{font-weight:900}
.dup-group-hint{font-size:.72rem;color:var(--accent-2);font-weight:700;margin-top:.4rem}

.linked-group-box{margin-top:.7rem;padding:.65rem .7rem;border-radius:12px;background:var(--cream-2);border:1.5px solid var(--line-2)}
.linked-group-title{font-size:.76rem;font-weight:800;color:var(--accent-2);margin-bottom:.5rem}
.linked-group-list{display:flex;gap:.5rem;overflow-x:auto}
.linked-group-item{
  flex:0 0 auto;display:flex;flex-direction:column;align-items:center;gap:.3rem;
  width:64px;background:none;border:none;cursor:pointer;
}
.linked-group-thumb{
  width:52px;height:52px;border-radius:10px;background:var(--cream-3) center/cover no-repeat;
  border:1.5px solid var(--text);display:block;
}
.linked-group-author{font-size:.62rem;color:var(--text2);font-weight:600;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:64px}

/* ── Social profile header + grid (Quán của tôi / UserQuanModal) ────────
   Hero has a warm gradient "cover" background that fades into the
   cream page ground, giving the identity block visual weight without
   feeling detached. Stats sit in a bordered card so they read as one
   unit and anchor the eye between hero and content. */
.social-profile-header{
  padding:1.4rem 1rem 1.5rem;text-align:center;position:relative;
  background:linear-gradient(180deg,
    var(--primary-tint) 0%,
    color-mix(in srgb, var(--primary-tint) 40%, var(--cream)) 60%,
    var(--cream) 100%);
  border-radius:0 0 24px 24px;
  margin:0 -1.1rem .3rem;
}
.social-avatar{
  width:84px;height:84px;margin:0 auto .7rem;border-radius:50%;border:3px solid var(--text);
  background:var(--accent);display:flex;align-items:center;justify-content:center;font-size:2.3rem;
  box-shadow:2.5px 3px 0 var(--text);
}
.social-name{
  font-family:var(--font-display);font-weight:900;font-size:1.2rem;color:var(--text);
  letter-spacing:-.2px;line-height:1.15;
}
.social-tagline{
  font-size:.78rem;color:var(--text2);margin-top:.25rem;font-weight:600;
}
.social-stats{
  display:flex;justify-content:center;margin:1rem auto 0;max-width:320px;
  background:var(--white);border:2px solid var(--text);border-radius:16px;
  box-shadow:2px 2px 0 var(--text);padding:.55rem .3rem;
}
.social-stat{flex:1;padding:0 .5rem}
.social-stat+.social-stat{border-left:1.5px solid var(--line-2)}
.social-stat b{
  display:block;font-family:var(--font-display);font-size:1.2rem;font-weight:900;
  color:var(--primary);line-height:1;
}
/* Direct child only — otherwise the label rule was accidentally hitting
   <span data-star-total> nested inside <b> and painting the star count
   as a small grey uppercase label instead of a big red display number. */
.social-stat > span{
  display:block;font-size:.62rem;color:var(--text2);margin-top:.2rem;
  font-weight:700;text-transform:uppercase;letter-spacing:.4px;
}
/* And the count-badge span inside <b> should keep the parent styling. */
.social-stat b span{
  font:inherit;color:inherit;letter-spacing:normal;text-transform:none;
  display:inline;font-size:inherit;font-weight:inherit;
}
.social-stat[role="button"]{cursor:pointer;border-radius:8px;transition:background .12s}
.social-stat[role="button"]:hover{background:var(--cream-2)}
.social-stat[role="button"]:active{background:var(--cream-3)}

/* Invite-friends card — sits between the profile header and filter tabs.
   Only shown for the logged-in owner's own profile (see ProfileCtrl). */
.invite-card{
  display:flex;align-items:center;justify-content:space-between;gap:.6rem;
  margin-top:.6rem;padding:.65rem .8rem;
  background:var(--cream-2);border:1.5px dashed var(--primary-2);border-radius:14px;
}
.invite-card.hidden{display:none}
.invite-text{font-size:.78rem;color:var(--text);font-weight:600;line-height:1.3}
.invite-text b{color:var(--primary);font-family:var(--font-display);font-size:.9rem}
.invite-btn{
  flex:0 0 auto;padding:.45rem .8rem;border-radius:20px;
  background:var(--primary);color:var(--cream);
  border:2px solid var(--text);box-shadow:2px 2px 0 var(--text);
  font-size:.75rem;font-weight:800;font-family:var(--font-display);
  cursor:pointer;white-space:nowrap;transition:transform .12s,box-shadow .12s;
}
.invite-btn:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}

/* Follower list rows — reuse the friend-chip visual language but as a
   vertical list so it's clearly a tap target per row. */
.follower-row{
  display:flex;align-items:center;gap:.7rem;
  padding:.55rem .5rem;border-radius:12px;cursor:pointer;
  transition:background .12s;
}
.follower-row:hover{background:var(--cream-2)}
.follower-row:active{background:var(--cream-3)}
.follower-row+.follower-row{border-top:1.5px dashed var(--line-2);border-radius:0}
.follower-row .follower-avatar{
  width:38px;height:38px;border-radius:50%;flex-shrink:0;
  background:var(--accent);border:2px solid var(--text);
  display:flex;align-items:center;justify-content:center;font-size:1.1rem;
}
.follower-row .follower-name{
  flex:1;font-family:var(--font-display);font-weight:800;font-size:.95rem;
  color:var(--text);letter-spacing:-.1px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}

.social-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;background:transparent}
.grid-cell{
  aspect-ratio:1/1;background-color:var(--cream-2);background-size:cover;background-position:center;
  display:flex;align-items:center;justify-content:center;font-size:1.6rem;cursor:pointer;
  border:1.5px solid var(--text);border-radius:12px;box-shadow:2px 2px 0 var(--text);
  transition:transform .12s var(--ease-spring),box-shadow .12s;
}
.grid-cell:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}

/* Settings gear — top-right of profile screen, replaces old avatar-tap */
.settings-gear{
  position:absolute;top:calc(env(safe-area-inset-top, 0px) + .6rem);right:.9rem;
  width:2.4rem;height:2.4rem;border-radius:50%;
  background:var(--white);border:2px solid var(--text);box-shadow:2px 2px 0 var(--text);
  display:flex;align-items:center;justify-content:center;font-size:1.15rem;
  cursor:pointer;z-index:6;transition:transform .12s var(--ease-spring),box-shadow .12s;
}
.settings-gear:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}
/* Second gear slot — bookmark 🔖 sits to the LEFT of the settings gear
   with a gap. Same style, different offset. */
.settings-gear.settings-gear-2{right:calc(.9rem + 2.4rem + .5rem)}
/* Slot thứ ba — 🗺️ lộ trình đã lưu, tiếp tục dịch sang trái cùng nhịp. */
.settings-gear.settings-gear-3{right:calc(.9rem + (2.4rem + .5rem) * 2)}

/* Nút 💾 lưu lộ trình trên thanh tiêu đề màn Lịch trình. Đặt sát mép phải,
   đối xứng với nút ← bên trái. */
.plan-save-btn{
  margin-left:auto;flex:0 0 auto;
  display:flex;align-items:center;gap:.3rem;
  padding:.38rem .85rem;border-radius:20px;
  background:var(--primary);color:var(--cream);
  border:2px solid var(--text);box-shadow:2.5px 2.5px 0 var(--text);
  font-size:.8rem;font-weight:800;font-family:var(--font-display);
  cursor:pointer;white-space:nowrap;
  transition:transform .12s,box-shadow .12s;
}
.plan-save-icon{font-size:.95rem;line-height:1}
.plan-save-btn:active{transform:translate(1.5px,1.5px);box-shadow:1px 1px 0 var(--text)}
.plan-save-btn.saved{background:var(--accent)}

/* Trip name dialog — thay window.prompt() */
.trip-name-overlay{
  position:fixed;inset:0;z-index:500;background:rgba(42,24,16,.55);
  display:flex;align-items:center;justify-content:center;padding:1.2rem;
  opacity:0;pointer-events:none;transition:opacity .2s;
}
.trip-name-overlay.show{opacity:1;pointer-events:auto}
.trip-name-card{
  background:var(--white);border:2.5px solid var(--text);border-radius:18px;
  box-shadow:5px 5px 0 var(--text);padding:1.25rem 1.2rem 1rem;
  width:100%;max-width:320px;
  transform:scale(.93);transition:transform .2s cubic-bezier(.32,1,.56,1);
}
.trip-name-overlay.show .trip-name-card{transform:none}
.trip-name-title{
  font-family:var(--font-display);font-size:.95rem;font-weight:900;
  color:var(--text);margin-bottom:.8rem;text-align:center;
}
.trip-name-actions{display:flex;gap:.6rem;margin-top:.85rem}
.trip-name-cancel{
  flex:1;padding:.55rem;border-radius:10px;
  border:2px solid var(--text);background:var(--paper);
  color:var(--text);font-weight:700;font-size:.85rem;font-family:var(--font-body);
  cursor:pointer;transition:background .12s;
}
.trip-name-cancel:active{background:var(--line-2)}
.trip-name-confirm{
  flex:1;padding:.55rem;border-radius:10px;
  border:2px solid var(--text);background:var(--primary);box-shadow:2px 2px 0 var(--text);
  color:var(--cream);font-weight:800;font-size:.85rem;font-family:var(--font-display);
  cursor:pointer;transition:transform .12s,box-shadow .12s;
}
.trip-name-confirm:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}

/* Thẻ 1 lộ trình đã lưu */
.strip-item{
  border:2px solid var(--text);border-radius:14px;background:var(--white);
  box-shadow:2px 2px 0 var(--text);padding:.7rem .8rem;margin-bottom:.7rem;
}
.strip-head{display:flex;align-items:center;gap:.5rem;margin-bottom:.35rem}
.strip-name{flex:1;font-weight:800;font-size:.92rem;color:var(--text);line-height:1.25}
.strip-meta{font-size:.72rem;color:var(--text3);font-weight:600;margin-bottom:.5rem}
.strip-origin{font-size:.74rem;color:var(--text2);font-weight:700;margin-bottom:.5rem}
.strip-stops{display:flex;flex-direction:column;gap:.3rem;margin-bottom:.6rem}
.strip-stop{font-size:.78rem;color:var(--text2);display:flex;gap:.4rem;align-items:baseline}
.strip-stop b{color:var(--primary);font-weight:800;flex:0 0 auto}
.strip-actions{display:flex;gap:.45rem}
.strip-go,.strip-del{
  padding:.42rem .7rem;border-radius:10px;border:2px solid var(--text);
  font-size:.76rem;font-weight:800;cursor:pointer;background:var(--white);color:var(--text);
}
.strip-go{flex:1;background:var(--primary);color:var(--cream);border-color:var(--primary-2)}
.strip-go:active,.strip-del:active{transform:translate(1px,1px)}

/* Quick action bar in detail modals — 2 secondary actions above the
   primary Đóng/Google Maps row. Neutral background, subtle border so
   they don't compete with the primary btn-save color. */
.detail-quick-actions{
  display:flex;gap:.5rem;margin-top:.6rem;
}
.quick-action-btn{
  flex:1;padding:.55rem .5rem;font-size:.78rem;font-weight:700;
  border:1.5px solid var(--text);background:var(--paper);color:var(--text);
  border-radius:12px;box-shadow:2px 2px 0 var(--text);
  cursor:pointer;transition:all .12s;display:inline-flex;
  align-items:center;justify-content:center;gap:.35rem;
  font-family:var(--font-body);
}
.quick-action-btn:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}
.quick-action-btn.on{background:var(--primary);color:var(--cream);border-color:var(--text)}

/* Bình luận trong CommunityDetailModal */
.comment-section{margin-top:.9rem;padding-top:.8rem;border-top:1.5px dashed var(--line-2)}
.comment-section-title{font-family:var(--font-display);font-weight:900;font-size:.88rem;color:var(--text);margin-bottom:.5rem}
.comment-list{display:flex;flex-direction:column;gap:.55rem;margin-bottom:.6rem;max-height:260px;overflow-y:auto}
.comment-loading,.comment-empty{font-size:.8rem;color:var(--text3);text-align:center;padding:.7rem;font-style:italic}
.comment-row{display:flex;align-items:flex-start;gap:.5rem}
.comment-avatar{flex-shrink:0;width:26px;height:26px;border-radius:50%;background:var(--cream-2);
  display:flex;align-items:center;justify-content:center;font-size:.85rem;border:1.5px solid var(--line-2)}
.comment-body{flex:1;min-width:0}
.comment-meta{display:flex;align-items:baseline;gap:.4rem;margin-bottom:.1rem}
.comment-author{font-size:.78rem;font-weight:800;color:var(--text)}
.comment-time{font-size:.68rem;color:var(--text3)}
.comment-text{font-size:.82rem;color:var(--text2);line-height:1.4;word-break:break-word}
.comment-del-btn{flex-shrink:0;width:20px;height:20px;border-radius:50%;background:none;border:none;
  color:var(--text3);font-size:.7rem;cursor:pointer;line-height:1}
.comment-del-btn:active{color:var(--primary)}
.comment-input-row{display:flex;gap:.5rem}
.comment-input{flex:1;padding:.55rem .7rem;border-radius:12px;border:1.5px solid var(--text);
  background:var(--white);font-size:.82rem;color:var(--text);font-family:var(--font-body)}
.comment-send-btn{flex-shrink:0;padding:.55rem 1rem;border-radius:12px;background:var(--primary);
  color:var(--cream);border:1.5px solid var(--text);font-weight:800;font-size:.8rem;
  box-shadow:2px 2px 0 var(--text);transition:all .12s;cursor:pointer}
.comment-send-btn:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}

.empty-comm{
  padding:2rem 1rem;text-align:center;background:var(--paper);
  border:2px dashed var(--text2);border-radius:var(--radius);color:var(--text3);
}
.empty-comm .em-icon{font-size:2.5rem;margin-bottom:.4rem}
.empty-comm .em-msg{font-family:var(--font-display);font-size:.95rem;font-weight:800;color:var(--text2);font-style:italic}
.empty-comm .em-sub{font-size:.75rem;color:var(--text3);margin-top:.3rem;font-weight:500}

/* Tag / hashtag chip input — type + Enter, chips render below */
.chip-tag-list{display:flex;flex-wrap:wrap;gap:.4rem;margin-top:.5rem}
.chip-tag{
  display:flex;align-items:center;gap:.35rem;padding:.3rem .4rem .3rem .65rem;
  border-radius:20px;border:2px solid var(--text);background:var(--white);
  font-size:.75rem;font-weight:700;color:var(--text);box-shadow:2px 2px 0 var(--text);
}
.chip-tag.hashtag{background:var(--primary-tint);color:var(--primary-2)}
.chip-tag-remove{
  width:1.1rem;height:1.1rem;border-radius:50%;background:var(--paper);
  border:1.5px solid var(--text2);color:var(--text2);font-size:.65rem;line-height:1;
  display:flex;align-items:center;justify-content:center;flex-shrink:0;
}
.chip-tag-remove:active{background:var(--primary);color:var(--cream);border-color:var(--primary-2)}

/* Photo picker — up to 4 slots, star = pick thumbnail */
.photo-picker-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:.5rem;margin-top:.5rem}
.photo-slot{
  position:relative;aspect-ratio:1;border-radius:12px;border:2px solid var(--text);
  overflow:hidden;background:var(--white) center/cover no-repeat;
  display:flex;align-items:center;justify-content:center;
  font-size:.7rem;font-weight:700;color:var(--text2);text-align:center;line-height:1.3;
}
.photo-slot-empty{background:var(--paper);border-style:dashed;color:var(--text3)}
.photo-slot-remove{
  position:absolute;top:3px;right:3px;width:1.3rem;height:1.3rem;border-radius:50%;
  background:rgba(42,24,16,.75);color:var(--cream);font-size:.7rem;line-height:1;
  display:flex;align-items:center;justify-content:center;border:1px solid var(--cream);
}
.photo-thumb-star{
  position:absolute;bottom:3px;left:3px;width:1.5rem;height:1.5rem;border-radius:50%;
  background:rgba(42,24,16,.55);color:var(--cream-3);font-size:.85rem;line-height:1;
  display:flex;align-items:center;justify-content:center;border:1px solid rgba(255,255,255,.4);
  transition:all .12s;
}
.photo-thumb-star.active{background:var(--primary);color:#FFD966;border-color:var(--primary-2)}


/* ═══════════════════════════════════════════════
   CHECK-IN TAB — camera-first ("chụp NGAY", real-time capture)
   ───────────────────────────────────────────────
   Live-camera layout rebuilt 2026-09-24 to a Locket-style inset frame
   Vinh signed off on via an interactive demo, replacing the original
   full-bleed-video + reticle + backdrop-blur version: an inset, rounded
   3:4 .checkin-frame with real dark margin around it (var(--text), same
   token the no-permission fallback already used), .brand-float pill
   floating near the top, and diary/shutter/flip as one flex row directly
   under the frame. See the longer comment above .checkin-spacer-top
   further down for the structural reasoning.

   New styles below are ONLY:
     .checkin-frame, .checkin-spacer-*, .checkin-ctrl-row — the live-camera layout
     .checkin-quan-pill/dist  — cosmetic tweaks on top of .brand-float
     .checkin-star-pill       — new: rating row (no existing analog)
     .checkin-preview*        — sheet shown after the shutter fires
     .checkin-share-tog       — new: cream/orange toggle
     .checkin-picker-*        — quán switcher list rows
     .checkin-diary-*         — my check-in history rows

   The shutter itself has a class combo `.rp-fab.checkin-shutter` —
   .rp-fab does 100% of the sizing/border/color/shadow/position math;
   the .checkin-shutter modifier only resizes/repositions it (same red
   fill as every other .rp-fab, e.g. Home's dice button) and swaps the
   inline dice icon (there isn't one — we don't render a child) for
   a nested white "shutter ring" via ::after.

   Every one-off "this is check-in, not the rest of the app" accent
   (a #D64B7A pink, undeclared as a real --checkin token — it only
   ever worked by accident because that hex happens to equal the
   --cat-snack category color) has been retired in favor of the app's
   actual tokens: --primary for actions/selected-state, --accent for a
   secondary highlight (same role it already has for star ratings and
   the share toggle above). Flagged by Vinh (2026-09-24): the pink
   read as a foreign UI, not "same app, different tab".
═══════════════════════════════════════════════ */

/* ── Live camera layout (2026-09-24 rebuild) ──────────────────────────
   Retired the earlier full-bleed-video + reticle + backdrop-blur system
   for a Locket-style layout Vinh signed off on via an interactive demo:
   an inset, rounded 3:4 frame with real margin around it, instead of a
   full-bleed video with a focus box drawn on top. There's no "outside
   the frame" video left to blur — the margin is just solid background —
   so the whole reticle/mask apparatus (and its real-device mask-position
   bug from earlier the same day) is gone, not just patched.

   #checkinScreen is `.screen`'s own flex column (display:flex;
   flex-direction:column is the BASE .screen rule) — .checkin-spacer-top/
   -bottom, .checkin-frame-zone and .checkin-ctrl-row are real flex
   children so the control row always sits directly under the frame
   regardless of the frame's rendered height (width-driven via
   aspect-ratio, so it varies by device) — anchoring the row from a
   fixed screen-bottom offset instead, like the old layout did, would
   overlap the frame on some widths and leave a gap on others. Floating
   chrome that doesn't need to affect that flow (the quán pill, the
   hidden rating pill, capture flash, the preview sheet, sign-in/no-perm
   fallbacks) stays exactly as it was: position:absolute against
   #checkinScreen, unaffected by the flex children around it. */
#checkinScreen{background:var(--text)}

.checkin-spacer-top{flex:4;min-height:0}
.checkin-spacer-bottom{flex:6;min-height:0}

.checkin-frame-zone{flex:0 0 auto;padding:0 18px;min-height:0}
.checkin-frame{
  position:relative;width:100%;aspect-ratio:3/4;
  border-radius:32px;overflow:hidden;
  background:var(--cam-bg,#0e0806);
}
.checkin-video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;transform-origin:50% 50%}
.checkin-frame{touch-action:none}
/* Zoom chips — native-camera style, bottom-centre of the viewfinder. */
.checkin-zoom{position:absolute;left:50%;bottom:12px;transform:translateX(-50%);z-index:3;display:flex;gap:4px;padding:3px;border-radius:22px;background:rgba(20,10,5,.42);-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}
.checkin-zoom.hidden{display:none}
.checkin-zoom-chip{min-width:34px;height:34px;padding:0 6px;border-radius:17px;border:none;background:transparent;color:var(--cream);font-size:11px;font-weight:800;font-variant-numeric:tabular-nums;display:flex;align-items:center;justify-content:center;transition:background-color .15s,color .15s,transform .1s}
.checkin-zoom-chip.on{background:var(--white);color:var(--text);font-size:12px}
.checkin-zoom-chip:active{transform:scale(.92)}
.checkin-video.hidden{display:none}

.checkin-ctrl-row{
  display:flex;align-items:center;justify-content:space-between;
  padding:16px 34px calc(var(--safe-bottom) + 90px);flex-shrink:0;
}

/* Signed-out / no-permission fallbacks — reuse the .coming-soon-wrap
   look already used elsewhere. They live above the (empty) video. */
.checkin-signin,.checkin-noperm{
  position:absolute;inset:0;z-index:6;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  padding:2rem 1.4rem;text-align:center;
  background:linear-gradient(180deg,rgba(20,10,5,.75) 0%,rgba(20,10,5,.92) 100%);
  color:var(--cream);
}
.checkin-signin .coming-soon-title,
.checkin-noperm  .coming-soon-title{color:var(--cream)}
.checkin-signin .coming-soon-sub,
.checkin-noperm  .coming-soon-sub{color:rgba(255,253,245,.75);max-width:32ch}
.checkin-signin.hidden,.checkin-noperm.hidden{display:none}

/* Cosmetic overrides on top of the .brand-float pill for the check-in
   context — same base construction (bg/radius/shadow inherited
   unchanged), but its own top/left instead of .brand-float's
   .6rem/.7rem edge-hugging default: pulled in from the corner per
   Vinh (2026-09-24) so it reads as placed, not stuck to the edge.
   Centered via left:50%+transform (like .rp-fab.checkin-shutter and
   .checkin-star-pill already do), NOT a fixed left px — this pill's
   width is intrinsic (icon + Vietnamese quán name + chevron), so a
   fixed left only happens to look centered for one exact width and
   drifts for any other (caught live on a real phone: with a fixed
   left:83px the actual rendered width wasn't exactly the 224px it was
   measured against, so the margins came out visibly uneven). Percent+
   transform re-centers around whatever width the content actually is,
   every time. max-width caps how wide a long quán name can push it
   before ellipsing — see #checkinQuanName below for why that ellipsis
   needs its own explicit rule: a flex child's default min-width:auto
   lets it shrink-wrap its text across 2 lines INSTEAD of overflowing,
   which is what was actually happening here (not ellipsis at all) —
   caught live once max-width got tight enough to matter; the old very
   generous max-width(100vw-6rem) just never left this dormant bug
   enough room to trigger. */
.checkin-quan-pill{
  top:calc(var(--safe-top) + 24px);left:50%;transform:translateX(-50%);
  max-width:calc(100vw - 166px);z-index:14;
}
.checkin-quan-pill .icon{width:1em;height:1em;color:var(--primary)}
.checkin-quan-pill .chevron{color:var(--text3);font-size:.7rem;margin-left:.1rem}
#checkinQuanName{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
/* Plain muted text, not a colored badge — matches how distance is shown
   everywhere else in the app (.r-dist / .tl-travel-dist), not a one-off
   pill invented just for this pill. */
.checkin-quan-dist{
  color:var(--text3);font-weight:700;font-size:.68rem;
  margin-left:.1rem;
}
.checkin-quan-dist:empty{display:none}

/* Standalone floating icon buttons. Same circular-white-chip visual
   language the app already uses for lone floating buttons (e.g. GPS
   float on Home). Diary/flip are now real flex children of
   .checkin-ctrl-row (2026-09-24 layout rebuild) instead of individually
   absolute-positioned — anchoring each to a fixed screen-bottom offset
   couldn't reliably clear the new width-driven frame height across
   device sizes, and flex placement makes that a non-issue. Lock stays
   absolute since it docks to a specific corner of .checkin-frame. */
.checkin-float-btn{
  z-index:14;border-radius:50%;background:var(--white);
  box-shadow:0 6px 18px rgba(42,24,16,.2);
  display:flex;align-items:center;justify-content:center;color:var(--text2);
  transition:transform .1s;
}
.checkin-float-btn:active{transform:scale(.92)}

.checkin-diary-btn,.checkin-flip-btn{width:54px;height:54px}
.checkin-diary-btn .icon,.checkin-flip-btn .icon{width:24px;height:24px}

/* Docks below .checkin-exposure, same right edge, both relative to
   .checkin-frame now instead of the whole screen (2026-09-24 layout
   rebuild) — the frame's size is width-driven (aspect-ratio:3/4), so a
   screen-relative fixed px offset couldn't reliably land in the same
   spot on every device the way a frame-relative one does. Stack math:
   exposure top:14px + its own ~170px height (12+18+8+120+12 padding/
   icon/gap/slider) + 8px gap ≈ 192px for lock's top. */
.checkin-float-btn.checkin-lock-btn{
  position:absolute;top:192px;right:14px;width:38px;height:38px;
}

/* Star rating pill — floats between the frame edge and the shutter.
   Uses the same sticker construction (2px border + offset shadow) as
   .cat-chip, just laid out horizontally and made bg-white so it reads
   over any camera background. */
.checkin-star-pill{
  position:absolute;left:50%;transform:translateX(-50%);
  /* On a phone with a home indicator, env(safe-area-inset-bottom) is
     ~34px and the floating tab bar pill sits 10px above that, giving
     an effective bottom footprint of ~110px before content clearance.
     Using env() here so this works on both notchless and notched
     phones — the old calc(var(--tab-h) + 90px) evaluated to only 154px
     which put the shutter half-behind the tab bar on iPhones (2026-09-21). */
  bottom:calc(env(safe-area-inset-bottom, 0px) + 190px);z-index:14;
  display:flex;gap:.35rem;padding:.5rem 1rem;
  background:var(--white);border:2px solid var(--text);border-radius:999px;
  box-shadow:2px 2px 0 var(--text);
}
.checkin-star{
  background:none;border:none;padding:0;cursor:pointer;
  color:var(--text3);transition:transform .12s,color .15s;
  display:flex;align-items:center;
}
.checkin-star:active{transform:scale(1.2)}
.checkin-star.on{color:var(--accent-2)}
.checkin-star .icon{width:1.3rem;height:1.3rem}

/* Shutter — .rp-fab does the size/border/shadow math; .checkin-shutter
   only recolors it and, since 2026-09-24, takes it OUT of .rp-fab's
   fixed/floating positioning entirely so it can sit as a normal flex
   child of .checkin-ctrl-row (centered between diary/flip by
   justify-content:space-between there, same as Instagram/Snapchat's
   gallery/shutter/flip row) — the row itself is now what stays clear of
   the tab bar (see .checkin-ctrl-row's bottom padding), not the shutter
   individually. position:relative, NOT static — static would still take
   it out of flow correctly, but it ALSO stops the button being a
   containing block for its own ::after "shutter ring" pseudo-element
   below, which then anchored to some big ancestor instead and rendered
   as a screen-filling blob (caught live while testing this rebuild).
   right:auto;bottom:auto resets .rp-fab's own right:16px;bottom:100px —
   under position:relative (unlike the fixed/static it replaced) those
   inherited offsets don't just get ignored, they shift the button away
   from its normal flex position by that exact amount (caught live: the
   shutter rendered 100px above the row it was actually laid out in). */
.rp-fab.checkin-shutter{
  position:relative;right:auto;bottom:auto;
  width:80px;height:80px;
  background:var(--primary);
  color:var(--cream);
}
.rp-fab.checkin-shutter::after{
  content:'';position:absolute;inset:6px;background:var(--white);
  border-radius:50%;border:2px solid var(--text);
}
.rp-fab.checkin-shutter:active{transform:translate(1px,1px);box-shadow:2px 2px 0 var(--text)}
.rp-fab.checkin-shutter.busy{animation:checkin-shutter-pulse .35s ease}
@keyframes checkin-shutter-pulse{0%,100%{transform:scale(1)}50%{transform:scale(.88)}}

/* Capture flash */
.checkin-flash{position:absolute;inset:0;background:var(--white);opacity:0;pointer-events:none;transition:opacity .15s;z-index:50}
.checkin-flash.on{opacity:.9}

/* ── Live camera: hide the rating pill BEFORE capture — user 2026-09-22
   requested it clean, rating only appears in the preview sheet. Keeps
   the DOM around so _tapShutter's dataset.rating read still works. ── */
#checkinStars{display:none}

/* ── Preview: 3:4 photo card + cream sheet ────────────────────────────
   Two stacked flex rows. Photo card up top with sticker frame (matches
   the post-view artefact 3:4 aesthetic). Cream sheet below with rounded
   top corners like a menu — the app's own visual language. Retake/close
   are the ONLY overlays; every input sits inside the sheet in a proper
   column with real gaps, so nothing overlaps like the pink prototype. */
.checkin-preview{
  position:absolute;inset:0;z-index:70;
  /* Above .rp-fab (z:60 in Home's dice-button base rule) — otherwise
     the shutter button pokes through the preview sheet (2026-09-22
     user bug report). */
  background:var(--cam-bg,#0e0806);
  display:flex;flex-direction:column;
}
.checkin-preview.hidden{display:none}

/* Photo card — 3:4, sticker frame. align-self:center centres horizontally,
   flex-shrink:0 keeps the aspect ratio intact on small phones. */
.checkin-preview-photo-wrap{
  position:relative;align-self:center;flex-shrink:0;
  /* Width also shrinks with screen HEIGHT: the sheet below (swipe card +
     dots + 2 toggles + send ≈ 350px) must always fit without scrolling. */
  width:min(88vw,330px,calc((100vh - 400px - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px)) * .75));
  width:min(88vw,330px,calc((100svh - 400px - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px)) * .75));
  aspect-ratio:3/4;
  margin:calc(env(safe-area-inset-top, 0px) + 18px) 0 0;
  border-radius:22px;
}
.checkin-preview-photo{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  border-radius:22px;
  border:2.5px solid var(--text);
  box-shadow:5px 5px 0 var(--text);
  filter:brightness(.98) saturate(1.05);user-select:none;
}
.checkin-preview-back,.checkin-preview-close{
  position:absolute;top:11px;z-index:5;
  width:38px;height:38px;border-radius:50%;background:var(--white);
  border:2px solid var(--text);box-shadow:2px 2px 0 var(--text);
  display:flex;align-items:center;justify-content:center;color:var(--text);font-weight:900;
  padding:0;cursor:pointer;
}
.checkin-preview-back{left:11px}
.checkin-preview-close{right:11px}
.checkin-preview-back:active,.checkin-preview-close:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}

/* Cream sheet — rounded top corners, sits under the photo. flex:1 lets
   the sheet fill the remaining vertical space cleanly on any device.
   overflow:visible so .checkin-sub-tabs' negative margin can straddle
   the top border (the "handle" effect — the star pill used to do this
   itself before the Locket-style swipeable-subs redesign moved it into
   its own sub-panel). */
.checkin-preview-sheet{
  flex:1;margin:24px 0 0;
  background:var(--cream,#FBF3D9);
  border:2.5px solid var(--text);border-bottom:none;
  border-top-left-radius:28px;border-top-right-radius:28px;
  padding:20px 18px calc(env(safe-area-inset-bottom, 0px) + 18px);
  display:flex;flex-direction:column;gap:10px;
  overflow:visible;
}

/* Locket-style swipeable subs (2026-09-24) — Đánh giá / Địa điểm /
   Nội dung as 3 native-scroll-snap panels instead of one long stacked
   form. Tabs straddle the sheet's top border as the "handle" element
   (same -46px trick the star pill used to do solo), and double as a
   position indicator that syncs FROM scroll position (IntersectionObserver
   in CheckinCtrl._wireSubTabs) as well as a tap-to-jump control INTO it
   (scrollIntoView). Chose native scroll-snap over a hand-rolled
   pointer-driven carousel for the same reason the exposure-slider redo
   kept the native <input type=range>: touch drag, momentum, and
   keyboard/trackpad scrolling all come for free instead of being
   reimplemented and risking drift from how touch scrolling actually
   feels on the device. */
/* 2026-09-25, per Vinh: the three subs are back, but only as ONE
   titled card at a time — no tab chips. Swipe left/right between them
   (native scroll-snap; the neighbour card peeks in at the edge so the
   swipe is discoverable) and the dots below show/jump position. The tab
   chips stay hidden in the DOM only because _wireSubTabs still accepts
   them as position markers. */
.checkin-sub-tabs{
  display:none;gap:6px;justify-content:center;
  position:relative;margin:-46px 0 6px;z-index:2;
}
.checkin-sub-tab{
  padding:.5rem .85rem;background:var(--white);color:var(--text2);
  border:2px solid var(--text);border-radius:999px;box-shadow:2px 2px 0 var(--text);
  font-size:.72rem;font-weight:900;font-family:var(--font-body);
  transition:background .15s,color .15s,transform .1s;
}
.checkin-sub-tab.active{background:var(--primary,#B92626);color:var(--white);border-color:var(--primary-2,#8C1919)}
.checkin-sub-tab:active{transform:translate(1px,1px)}

.checkin-sub-scroll{
  display:flex;gap:10px;overflow-x:auto;scroll-snap-type:x mandatory;
  -webkit-overflow-scrolling:touch;scrollbar-width:none;overscroll-behavior-x:contain;
  margin:0 -18px; /* bleed past the sheet's side padding… */
  padding:4px 28px 6px; /* …then inset so the next card peeks ~18px at the edge */
  scroll-padding:0 28px;
}
.checkin-sub-scroll::-webkit-scrollbar{display:none}
.checkin-sub-panel{flex:0 0 100%;scroll-snap-align:center;display:flex}
.checkin-sub-card{
  flex:1;min-width:0;min-height:84px;display:flex;flex-direction:column;justify-content:center;gap:6px;
  padding:10px 14px 12px;background:var(--white);border:2px solid var(--text);border-radius:20px;
  box-shadow:2px 2px 0 var(--text);cursor:text;transition:border-color .15s;
}
.checkin-sub-card:focus-within{border-color:var(--primary)}
.checkin-sub-label{
  display:flex;align-items:center;gap:6px;
  font-size:.68rem;font-weight:900;font-style:italic;letter-spacing:.8px;text-transform:uppercase;color:var(--primary);
}
.checkin-sub-label .icon{width:14px;height:14px}
.checkin-sub-dots{display:flex;justify-content:center;gap:6px;margin:2px 0 4px}
.checkin-sub-dot{
  position:relative;width:7px;height:7px;padding:0;border:none;border-radius:4px;background:var(--cream-3);
  transition:width .2s var(--ease-out),background-color .2s;
}
.checkin-sub-dot::after{content:'';position:absolute;inset:-10px -6px} /* 27px-tall tap target around a 7px dot */
.checkin-sub-dot.active{width:18px;background:var(--primary)}

/* Star pill inside its sub-panel — reset .checkin-star-pill's absolute
   positioning (which the live-view pill uses); no longer needs its own
   negative-margin "handle" straddle, .checkin-sub-tabs does that now. */
.checkin-preview-stars{
  position:relative;left:auto;right:auto;bottom:auto;transform:none;
  background:none;border:none;box-shadow:none;padding:0;gap:14px;justify-content:flex-start;
}
.checkin-preview-stars .checkin-star .icon{width:1.7rem;height:1.7rem}

/* Address + caption — rounder, more airy padding, same rounded corners
   (20px) so the whole sheet has a consistent radius rhythm. Focus ring
   picks up the primary red (app brand) instead of the old pink. */
/* Address + caption sit flat inside their .checkin-sub-card — the card
   is the box, so the fields themselves carry no border/shadow. */
.checkin-preview-addr,.checkin-preview-cap{
  position:relative;left:auto;right:auto;bottom:auto;width:100%;
  padding:0;background:none;border:none;border-radius:0;box-shadow:none;
  font-size:.95rem;color:var(--text);font-weight:800;
  outline:none;line-height:1.35;
  font-family:var(--font-body);
}
.checkin-preview-cap{
  color:var(--text2);font-style:italic;font-weight:600;font-size:.9rem;resize:none;
}
.checkin-preview-addr::placeholder{color:var(--text3);font-weight:700}
.checkin-preview-cap::placeholder{color:var(--text3);font-style:italic}


/* Share toggle — cream/orange scheme matches the rest of the app.
   Off = white, on = accent orange knob + soft accent tint background. */
.checkin-share-tog{
  position:relative;left:auto;right:auto;bottom:auto;
  display:flex;align-items:center;gap:.65rem;padding:.7rem .9rem;
  background:var(--white);border:2px solid var(--text);border-radius:20px;
  box-shadow:2px 2px 0 var(--text);
  cursor:pointer;user-select:none;transition:background .18s;
}
.checkin-share-tog.on{background:#FFEED9}
.checkin-share-knob{
  width:40px;height:22px;background:var(--cream-3);border:1.5px solid var(--text);
  border-radius:12px;position:relative;flex-shrink:0;transition:background .2s;
}
.checkin-share-knob::after{
  content:'';position:absolute;top:1px;left:1px;
  width:16px;height:16px;background:var(--white);border-radius:50%;transition:transform .2s;
  border:1px solid var(--text);
}
.checkin-share-tog.on .checkin-share-knob{background:var(--accent,#E8843C)}
.checkin-share-tog.on .checkin-share-knob::after{transform:translateX(18px)}
.checkin-share-body{flex:1;font-size:.82rem;color:var(--text);font-weight:900;line-height:1.25}
.checkin-share-body small{display:block;color:var(--text2);font-size:.66rem;margin-top:2px;font-weight:700;font-style:normal}

/* Send CTA — primary red, matches Home's "Random" button + all other
   primary CTAs in the app. Slightly rounder (22px) than .scan-btn's
   default 16px so it sits nicely with the 20px input rows above. */
.scan-btn.checkin-send-btn{
  background:var(--primary,#B92626);color:var(--white);
  margin-top:4px;border-radius:22px;
}
.scan-btn.checkin-send-btn:active{background:var(--primary-2,#8C1919)}

/* ── Quán picker sheet (opens on tap of top pill) ─────────────────────── */
/* Manual address entry — same visual language as .checkin-preview-addr
   (white input, brutalist border+shadow), stacked with a "Dùng địa chỉ
   này" confirm button since there's no separate "submit" affordance
   like a form would have inside this list-sheet. */
.checkin-picker-manual{display:flex;flex-direction:column;gap:.5rem;margin-top:.6rem}
.checkin-picker-manual input{
  width:100%;padding:.7rem 1rem;
  background:var(--white);border:2px solid var(--text);border-radius:16px;
  box-shadow:2px 2px 0 var(--text);
  font-size:.85rem;font-weight:800;color:var(--text);font-family:var(--font-body);
  outline:none;
}
.checkin-picker-manual input::placeholder{color:var(--text3);font-weight:700}
.checkin-picker-manual input:focus{border-color:var(--primary,#B92626)}
.checkin-picker-manual button{
  height:42px;border-radius:14px;background:var(--primary,#B92626);color:var(--white);
  border:2px solid var(--primary-2,#8C1919);box-shadow:2px 2px 0 var(--text);
  font-weight:900;font-size:.85rem;font-family:var(--font-body);
}
.checkin-picker-manual button:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}
.checkin-picker-or{
  text-align:center;font-size:.68rem;font-weight:800;color:var(--text3);
  text-transform:uppercase;letter-spacing:.05em;margin:.9rem 0 .2rem;
}
.checkin-picker-list{
  max-height:52vh;overflow-y:auto;display:flex;flex-direction:column;gap:.5rem;
  padding:.3rem .3rem .6rem;margin:.4rem 0;
}
.checkin-picker-item{
  display:flex;gap:.55rem;padding:.55rem .7rem;background:var(--white);
  border:2px solid var(--text);border-radius:12px;box-shadow:2px 2px 0 var(--text);
  align-items:center;text-align:left;width:100%;cursor:pointer;
  transition:transform .12s;
}
.checkin-picker-item:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}
.checkin-picker-body{flex:1;min-width:0}
.checkin-picker-name{font-weight:900;font-size:.85rem;color:var(--text);line-height:1.15;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.checkin-picker-meta{color:var(--text2);font-size:.65rem;font-weight:700;display:flex;gap:.5rem;margin-top:2px}
/* "Đang chọn" — same selected-state language as .dish-chip.active
   elsewhere (primary-tint fill, primary border/text). */
.checkin-picker-tag{
  font-size:.6rem;font-weight:900;color:var(--primary-2);flex-shrink:0;
  padding:.2rem .45rem;background:var(--primary-tint);
  border:1.5px solid var(--primary);border-radius:6px;
}

/* ── Diary sheet (opens from ↖ cluster) ───────────────────────────────── */
.checkin-diary-list{
  max-height:60vh;overflow-y:auto;display:flex;flex-direction:column;gap:.45rem;
  padding:.3rem .3rem .6rem;margin:.4rem 0;
}
.checkin-diary-row{
  display:flex;gap:.55rem;padding:.5rem;background:var(--white);
  border:1.5px solid var(--text);border-radius:12px;box-shadow:1.5px 1.5px 0 var(--text);
  align-items:center;
}
.checkin-diary-thumb{
  width:44px;height:44px;flex:0 0 44px;border-radius:10px;overflow:hidden;
  border:1.5px solid var(--text);
  display:flex;align-items:center;justify-content:center;
  background:linear-gradient(135deg,var(--cream-3),var(--accent));
  font-size:1.2rem;
}
.checkin-diary-thumb img{width:100%;height:100%;object-fit:cover;display:block}
.checkin-diary-body{flex:1;min-width:0}
.checkin-diary-name{font-weight:900;font-size:.78rem;color:var(--text);line-height:1.15;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.checkin-diary-meta{color:var(--text2);font-size:.62rem;font-weight:700;line-height:1.3;margin-top:2px;display:flex;align-items:center;flex-wrap:wrap;gap:.15rem}
.checkin-diary-meta .icon{margin-right:1px;vertical-align:-.1em}
.checkin-diary-date{color:var(--text-3,#9C7F6B)}
.checkin-diary-tag{
  flex-shrink:0;font-size:.6rem;font-weight:900;
  padding:.15rem .4rem;border:1.5px solid var(--text);border-radius:8px;
  display:inline-flex;align-items:center;gap:.15rem;
}
.checkin-diary-tag.priv{background:var(--paper);color:var(--text2)}
/* Public — same soft accent-orange tint as .checkin-share-tog.on, so
   "shared with everyone" reads as one consistent accent everywhere it
   shows up, not a different color per screen. */
.checkin-diary-tag.pub{background:#FFEED9;color:var(--accent-2);border-color:var(--accent)}

/* ═══════════════════════════════════════════════════════════════════
   CHECK-IN SUBTAB — STORIES BUBBLES + FULLSCREEN VIEWER  (2026-09-22)
   Rewrote the earlier horizontal strip into a dedicated subtab under
   Cộng đồng. Each user with a check-in in the last 24h gets 1 bubble
   (grouped by expand.user.id); tap a bubble → fullscreen viewer with
   auto-advance 5s/post, progress bar segments, tap-left/right nav.
   Feed still client-side filtered to 24h; Diary + trang quán aggregate
   keep everything full-time.
   ═══════════════════════════════════════════════════════════════════ */

/* ─── Bubbles grid (subtab content) ──────────────────────────────── */
.ci-bubbles{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(78px,1fr));
  gap:14px 12px;padding:8px 14px 18px;
}
.ci-bubbles-empty{
  padding:22px 18px;margin:8px 14px 18px;border-radius:16px;
  background:var(--paper);border:2px dashed var(--cream-3);
  display:flex;align-items:center;gap:12px;color:var(--text-2,#6B4A38);
  font-size:.85rem;font-weight:700;line-height:1.4;
}
.ci-bubbles-empty.hidden{display:none}
.ci-bubbles-empty-ico{font-size:1.9rem;flex-shrink:0;filter:drop-shadow(0 1px 2px rgba(0,0,0,.15))}
.ci-bubbles-empty-msg{flex:1}

/* One bubble: circular avatar with gradient ring (unseen) or gray
   ring (all seen). Author name underneath truncates. Count badge
   bottom-right when the user has >1 check-in in the window. */
.ci-bubble{
  display:flex;flex-direction:column;align-items:center;gap:5px;
  cursor:pointer;user-select:none;
}
.ci-bubble-ring{
  position:relative;width:72px;height:72px;border-radius:50%;
  padding:3px;background:conic-gradient(from 210deg,var(--primary,#B92626),var(--accent,#E8843C),var(--primary-3,#5F0F0F),var(--primary,#B92626));
  transition:transform .12s;
}
.ci-bubble:active .ci-bubble-ring{transform:scale(.94)}
.ci-bubble-ring.seen{background:var(--cream-3,#EEE0A6)}
.ci-bubble-inner{
  width:100%;height:100%;border-radius:50%;overflow:hidden;
  background:var(--paper);border:2px solid var(--white,#FFFDF5);
  display:flex;align-items:center;justify-content:center;font-size:1.7rem;
}
.ci-bubble-inner.has-photo{background-size:cover;background-position:center}
/* Small red pulse — user has a check-in <1h old. */
.ci-bubble-fresh{
  position:absolute;top:2px;right:2px;z-index:2;
  width:11px;height:11px;border-radius:50%;
  background:var(--primary,#B92626);border:2px solid var(--white,#FFFDF5);
  animation:ciFreshPulse 1.6s ease-in-out infinite;
}
@keyframes ciFreshPulse{
  0%,100%{box-shadow:0 0 0 0 rgba(185,38,38,.55)}
  50%{box-shadow:0 0 0 5px rgba(185,38,38,0)}
}
.ci-bubble-count{
  position:absolute;bottom:0;right:0;z-index:2;
  min-width:20px;height:20px;padding:0 4px;border-radius:999px;
  background:var(--text);color:var(--white);border:2px solid var(--white,#FFFDF5);
  display:inline-flex;align-items:center;justify-content:center;
  font-size:.62rem;font-weight:900;
}
.ci-bubble-name{
  font-size:.72rem;font-weight:800;color:var(--text);line-height:1.15;
  max-width:82px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:center;
}
/* Bubble skeleton while first fetch loads */
.ci-bubble.skel .ci-bubble-inner{background:linear-gradient(135deg,var(--cream-2),var(--cream-3));animation:ciBubSkel 1.2s infinite alternate}
.ci-bubble.skel .ci-bubble-name{opacity:.4}
@keyframes ciBubSkel{from{opacity:.55}to{opacity:.9}}

/* ─── Fullscreen viewer ──────────────────────────────────────────── */
/* Uses .modal-overlay.show for open/close (same as diary/picker); the
   inner frame is what fills the viewport. Tab bar gets hidden via
   .tabbar.checkin-hidden while viewer is up (see CheckinViewerCtrl).
   Redesigned 2026-09-23: caption + "•••" options menu (owner: Xóa/Ẩn
   khỏi bạn bè/Thống kê; viewer: Báo cáo/Ẩn bài này) + labeled action
   pills replacing the old icon-only circles + inline "Đi tới" chip
   (now one of the action pills instead). Absorbed the old standalone
   CheckinPostViewCtrl modal — that entry point was dead code (nothing
   called .open() any more; Discover/bubbles/calendar all route through
   this viewer), so it was deleted instead of kept in sync by hand. */
#checkinViewer.ci-viewer-ov{background:rgba(0,0,0,.95);z-index:300}
#checkinViewer .ci-viewer-frame{
  position:relative;width:100vw;height:100vh;max-width:520px;
  display:flex;flex-direction:column;
  color:var(--white,#FFFDF5);
  background:transparent;
}

/* Photo cover — fills whole viewport behind everything */
.ci-viewer-photo-wrap{
  position:absolute;inset:0;z-index:1;
  display:flex;align-items:center;justify-content:center;
  background:#000;
}
.ci-viewer-photo{
  width:100%;height:100%;
  background-size:cover;background-position:center;background-repeat:no-repeat;
}
.ci-viewer-photo.empty{
  display:flex;align-items:center;justify-content:center;font-size:6rem;
  filter:drop-shadow(0 4px 12px rgba(0,0,0,.5));
  background:linear-gradient(135deg,#F9A870,#B92626);
}

/* Tap zones — invisible, cover left/right thirds of the photo. Also the
   swipe-detection target (see CheckinViewerCtrl). Keep in front of
   photo but behind header/foot/progress so those stay interactive. */
.ci-viewer-tap{
  position:absolute;top:0;bottom:0;z-index:10;
  background:transparent;border:0;padding:0;cursor:pointer;
  /* The swipe is ours: without this the browser claims a horizontal drag
     (pointercancel, or Chrome's swipe-to-go-back) and the viewer never
     sees the pointerup that decides next/previous. */
  touch-action:none;-webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;
}
.ci-viewer-tap-prev{left:0;width:30%}
.ci-viewer-tap-next{right:0;width:70%}

/* Progress bar segments at the top — 1 segment per post in the group,
   current segment animates fill over 5s via CSS animation. */
.ci-viewer-progress{
  position:absolute;top:calc(env(safe-area-inset-top, 0px) + 10px);
  left:14px;right:14px;z-index:16;
  display:flex;gap:4px;
}
.ci-viewer-progress-seg{
  flex:1;height:3px;border-radius:2px;
  background:rgba(255,255,255,.35);overflow:hidden;
}
.ci-viewer-progress-seg-fill{
  height:100%;width:0;background:var(--white,#FFFDF5);
  transform-origin:left;
}
.ci-viewer-progress-seg.done .ci-viewer-progress-seg-fill{width:100%}
.ci-viewer-progress-seg.active .ci-viewer-progress-seg-fill{
  animation:ciViewerFill 5000ms linear forwards;
}
@keyframes ciViewerFill{from{width:0}to{width:100%}}

/* Header — avatar + name + time on the left, "•••" + close on the right */
.ci-viewer-hd{
  position:absolute;top:calc(env(safe-area-inset-top, 0px) + 26px);
  left:14px;right:14px;z-index:15;
  display:flex;align-items:center;gap:10px;
}
.ci-viewer-avatar{
  width:40px;height:40px;border-radius:50%;
  background:var(--accent,#E8843C);border:2px solid var(--white,#FFFDF5);
  display:flex;align-items:center;justify-content:center;font-size:1.2rem;flex-shrink:0;
  color:var(--text);cursor:pointer;
}
.ci-viewer-avatar .icon{width:1.15rem;height:1.15rem;color:var(--text)}
.ci-viewer-hd-txt{flex:1;min-width:0;line-height:1.2}
.ci-viewer-uname-row{display:flex;align-items:center;gap:5px}
.ci-viewer-username{
  font-size:.98rem;font-weight:900;text-transform:uppercase;letter-spacing:-.01em;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  text-shadow:0 1px 4px rgba(0,0,0,.45);cursor:pointer;
}
.ci-viewer-lock{flex-shrink:0;width:14px;height:14px;opacity:.85}
.ci-viewer-time{font-size:.7rem;font-weight:700;opacity:.9;text-shadow:0 1px 3px rgba(0,0,0,.4)}

.ci-viewer-hd-actions{display:flex;gap:8px;flex-shrink:0}
.ci-viewer-opt-btn,.ci-viewer-close{
  width:36px;height:36px;border-radius:50%;
  background:rgba(0,0,0,.5);color:var(--white,#FFFDF5);
  border:1.5px solid rgba(255,255,255,.35);
  display:flex;align-items:center;justify-content:center;
  padding:0;cursor:pointer;flex-shrink:0;
}
.ci-viewer-opt-btn:active,.ci-viewer-close:active{transform:scale(.92)}
.kebab-dots{display:flex;gap:3px}
.kebab-dots span{width:3.5px;height:3.5px;border-radius:50%;background:var(--white,#FFFDF5)}

/* Bottom bar — caption + location + action pills, over a gradient scrim */
.ci-viewer-foot{
  position:absolute;left:0;right:0;bottom:0;z-index:15;
  padding:18px 14px calc(env(safe-area-inset-bottom, 0px) + 16px);
  background:linear-gradient(to top,rgba(0,0,0,.78) 0%,rgba(0,0,0,.4) 55%,transparent 100%);
  display:flex;flex-direction:column;gap:10px;
}
.ci-viewer-caption{
  font-size:.85rem;font-weight:700;line-height:1.4;color:var(--white,#FFFDF5);
  text-shadow:0 1px 3px rgba(0,0,0,.4);
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}
.ci-viewer-caption.hidden{display:none}
.ci-viewer-counts{
  font-size:.72rem;font-weight:800;color:var(--white,#FFFDF5);opacity:.9;
  text-shadow:0 1px 3px rgba(0,0,0,.4);
  display:flex;align-items:baseline;gap:4px;flex-wrap:wrap;
}
.ci-viewer-counts-sep{opacity:.6}
.ci-viewer-loc{
  display:flex;align-items:center;gap:6px;
  font-size:.8rem;font-weight:800;color:var(--white,#FFFDF5);
}
.ci-viewer-loc .icon{color:var(--accent,#E8843C);width:.9em;height:.9em;flex-shrink:0}
.ci-viewer-loc > span{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}

/* Action pills — owner gets Lưu/Chia sẻ/Đi tới; viewer gets an extra
   Thích at the front. Rendered dynamically per _renderPost() so the
   set always matches record.user === currentUser.id. */
.ci-viewer-actions{display:flex;align-items:center;gap:10px}
.ci-viewer-act{
  flex:1;height:44px;border-radius:14px;min-width:0;
  background:rgba(0,0,0,.5);color:var(--white,#FFFDF5);
  border:1.5px solid rgba(255,255,255,.35);
  display:flex;align-items:center;justify-content:center;gap:6px;
  font-size:.74rem;font-weight:900;font-family:inherit;cursor:pointer;
  transition:transform .1s;
}
.ci-viewer-act .icon{width:1.1rem;height:1.1rem;flex-shrink:0}
.ci-viewer-act span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ci-viewer-act:active{transform:scale(.95)}
.ci-viewer-act.on{background:var(--primary,#B92626);border-color:var(--white,#FFFDF5)}
.ci-viewer-act.direct{background:var(--primary,#B92626);border-color:var(--white,#FFFDF5)}

/* Options popover — mirrors the app's existing anchored .cat-dd-panel
   pattern (light card, scale+opacity transition), just re-themed to sit
   over a dark photo instead of the map. */
.ci-opt-overlay{
  position:absolute;inset:0;z-index:20;background:transparent;
  opacity:0;pointer-events:none;transition:opacity .15s;
}
.ci-opt-overlay.show{opacity:1;pointer-events:auto}
.ci-opt-panel{
  position:absolute;top:calc(env(safe-area-inset-top, 0px) + 72px);right:14px;z-index:21;
  width:210px;background:var(--white,#FFFDF5);border-radius:var(--radius-lg);
  border:2px solid var(--text);box-shadow:0 10px 26px rgba(0,0,0,.4);
  padding:6px;transform-origin:top right;
  transform:scale(.85);opacity:0;pointer-events:none;
  transition:transform .2s cubic-bezier(.34,1.56,.64,1),opacity .15s;
}
.ci-opt-panel.show{transform:scale(1);opacity:1;pointer-events:auto}
.ci-opt-item{
  display:flex;align-items:center;gap:10px;width:100%;
  padding:.6rem .65rem;border-radius:12px;font-size:.82rem;font-weight:800;color:var(--text);
  font-family:inherit;cursor:pointer;transition:background .12s,color .12s;
}
.ci-opt-item:active{background:var(--cream-2)}
.ci-opt-item .icon{width:1.05rem;height:1.05rem;flex-shrink:0}
.ci-opt-item.danger{color:var(--primary)}
.ci-opt-item.danger.confirming{background:var(--primary);color:var(--white,#FFFDF5)}
.ci-opt-sep{height:1px;background:var(--line);margin:4px 4px}

/* Temporary marker for "Đi tới" landing on the Home map */
.leaflet-marker-icon .ci-direct-pin{
  font-size:1.6rem;line-height:1;
  filter:drop-shadow(0 2px 3px rgba(0,0,0,.4));
  animation:ciDirectPinDrop .3s ease-out;
}
@keyframes ciDirectPinDrop{from{transform:translateY(-14px);opacity:0}to{transform:translateY(0);opacity:1}}

/* ── NHẬT KÝ ĂN — "Sổ Dán Món" (NhatKyCtrl) ─────────────────────────────
   Each meal is a photo sticker on a monthly page. Flat stickers, no drop
   shadows: shared vs private reads from a solid vs dashed border. Only the
   opened photo and the streak stamp are tilted — the grid stays straight.
   z-index 150: above the tab bar (100), below .modal-overlay (200) so
   "Xem quán" (CommunityDetailModal) opens on top of the diary. */
.nk{position:fixed;inset:0;z-index:150;user-select:none;-webkit-user-select:none;color:var(--text)}
.nk[hidden],.nk [hidden]{display:none!important}
.nk .icon{display:block;vertical-align:0;width:1em;height:1em}
.nk button:focus-visible,.nk input:focus-visible{outline:2px solid var(--primary);outline-offset:2px}
.nk-backdrop{position:absolute;inset:0;background:rgba(42,24,16,.5);opacity:0;transition:opacity .3s}
.nk.open .nk-backdrop{opacity:1}

/* sticker grammar */
.nk-stk{background:var(--white);border:2px solid var(--text);transition:transform 90ms}
.nk-stk:active{transform:scale(.97)}
.nk-chip{display:inline-flex;align-items:center;justify-content:center;gap:5px;height:36px;padding:0 14px;border-radius:24px;font-size:13px;font-weight:800;white-space:nowrap;flex-shrink:0;background:var(--white);border:2px solid var(--text);transition:transform 90ms,background-color .15s,color .15s}
.nk-chip:active{transform:scale(.97)}
.nk-chip.on{background:var(--primary);color:var(--cream);border-color:var(--primary-2)}
.nk-chip.empty{color:var(--text3)}
.nk-chip.on.empty{color:var(--cream)}
.nk-float{background:var(--white);border:none;box-shadow:0 4px 14px rgba(42,24,16,.18)}
.nk-hit{position:relative}
.nk-hit::after{content:'';position:absolute;inset:-6px}

/* ── Sổ (sheet) ── */
.nk-sheet{position:absolute;left:0;right:0;top:calc(var(--safe-top) + 10px);bottom:0;background:var(--paper);border-radius:24px 24px 0 0;border-top:2px solid var(--text);overflow-y:auto;overscroll-behavior:contain;padding:0 16px calc(var(--safe-bottom) + 24px);scrollbar-width:none;transform:translateY(100%);transition:transform .36s var(--ease-ios),filter .26s}
.nk-sheet::-webkit-scrollbar{display:none}
.nk.open .nk-sheet{transform:none}
.nk.open .nk-sheet.dragging{transition:none}
.nk-sheet.behind{transform:scale(.97)!important;filter:saturate(.9)}
.nk-grab{height:19px;margin:0 -16px;display:flex;justify-content:center;touch-action:none;cursor:grab}
.nk-handle{width:40px;height:5px;border-radius:3px;background:var(--text2);margin-top:8px;opacity:.7}
.nk-head{height:56px;display:flex;align-items:center;justify-content:space-between;gap:8px;position:relative}
.nk-eyebrow{font-style:italic;font-weight:800;font-size:11px;color:var(--primary);letter-spacing:1px;text-transform:uppercase;display:flex;align-items:center;gap:.4rem;line-height:1.3}
.nk-eyebrow::before{content:'✦';font-style:normal}
.nk-titles h2{font-size:24px;font-weight:900;line-height:1.1;letter-spacing:-.4px;margin-top:3px}
.nk-titles h2 em{font-style:italic;color:var(--primary)}
.nk-actions{display:flex;gap:8px}
.nk-circle{width:44px;height:44px;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0}
.nk-circle .icon{width:20px;height:20px}
.nk-search{position:absolute;inset:0;display:flex;align-items:center;gap:8px;opacity:0;pointer-events:none;transition:opacity .16s}
.nk-head.searching .nk-titles,.nk-head.searching .nk-actions{opacity:0;pointer-events:none;transition:opacity .16s}
.nk-head.searching .nk-search{opacity:1;pointer-events:auto}
.nk-search input{flex:1;min-width:0;height:44px;border-radius:14px;padding:0 14px;font-size:15px;font-weight:700;color:var(--text);background:var(--white);border:2px solid var(--text);outline:none;-webkit-appearance:none;appearance:none}
.nk-search input::placeholder{color:var(--text3);font-weight:600}
.nk-search button{height:44px;padding:0 6px;font-weight:800;color:var(--primary)}
.nk-notice{margin-top:10px;display:flex;justify-content:center}
.nk-notice span,.nk-notice button{height:32px;padding:0 12px;border-radius:16px;display:inline-flex;align-items:center;font-size:12px;font-weight:800;color:var(--text2);background:var(--cream-2)}

.nk-memory{margin-top:10px;height:72px;border-radius:18px;padding:0 12px;display:flex;align-items:center;gap:12px;width:100%;text-align:left}
.nk-memory .nk-thumb{width:42px;height:56px;border-radius:6px;border:2px solid var(--text);background-color:var(--cream-2);background-size:cover;background-position:center;flex-shrink:0}
.nk-memory .nk-txt{flex:1;min-width:0;display:flex;flex-direction:column}
.nk-memory .nk-mem-eyebrow{font-size:10px;font-weight:800;font-style:italic;text-transform:uppercase;letter-spacing:.6px;color:var(--accent-2)}
.nk-memory .nk-mem-name{font-size:15px;font-weight:800;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.nk-memory .nk-mem-sub{font-size:12px;font-weight:600;color:var(--text2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.nk-memory .nk-chev{width:20px;height:20px;color:var(--text3)}

.nk-months{display:flex;gap:8px;margin-top:12px;overflow-x:auto;padding:4px 2px 6px;scrollbar-width:none}
.nk-months::-webkit-scrollbar{display:none}

.nk-page-wrap{margin-top:8px;touch-action:pan-y;position:relative}
.nk-page{border-radius:18px;padding:12px 10px 8px;position:relative}
.nk-page.nk-stk:active,.nk-blank.nk-stk:active{transform:none}
.nk-p-head{min-height:52px;padding:0 4px}
.nk-p-head h3{font-size:28px;font-weight:900;line-height:1;letter-spacing:-.6px}
.nk-p-head .nk-meta{font-size:12px;font-weight:700;color:var(--text3);margin-top:4px;min-height:17px}
.nk-stamp{position:absolute;top:-12px;right:-8px;width:76px;height:76px;border-radius:50%;border:2.5px solid var(--primary);box-shadow:inset 0 0 0 2px var(--white),inset 0 0 0 3.5px var(--primary);color:var(--primary);background:rgba(255,253,245,.9);transform:rotate(-12deg);opacity:.92;display:flex;flex-direction:column;align-items:center;justify-content:center;line-height:1;cursor:pointer}
.nk-stamp b{font-size:26px;font-weight:900}
.nk-stamp span{font-size:8.5px;font-weight:900;letter-spacing:.5px;margin-top:2px;text-align:center;max-width:60px}
.nk-stamp.pending{border-style:dashed}
.nk-stamp.pending span{font-size:7.5px;max-width:58px}
.nk-dow{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:5px;height:20px;align-items:center;margin-top:4px}
.nk-dow span{text-align:center;font-size:11px;font-weight:800;color:var(--text3)}
.nk-dow span:last-child{color:var(--primary)}
.nk-grid{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));column-gap:5px;row-gap:8px;margin-top:4px}
.nk-cell{position:relative;aspect-ratio:3/4;border-radius:8px;display:block;width:100%;padding:0;transition:opacity .16s}
.nk-cell.dim{opacity:.25}
/* the page the sticker was stuck on — only visible once it's peeled */
.nk-cell.photo{background:var(--cream-2);border:1.5px dashed var(--line-2)}
.nk-cell .nk-ph{position:absolute;inset:-1.5px;border-radius:8px;overflow:hidden;background:var(--cream-2);border:2px solid var(--text);transition:transform 100ms}
.nk-cell .nk-ph img{display:block;width:100%;height:100%;object-fit:cover}
.nk-cell.private .nk-ph{border:2px dashed var(--text3)}
.nk-cell.nophoto .nk-ph{display:flex;align-items:flex-start;justify-content:center;padding-top:10px;color:var(--text2)}
.nk-cell.nophoto .nk-ph .icon{width:20px;height:20px}
.nk-cell .nk-back{position:absolute;inset:-1.5px;border-radius:8px;background:var(--white);border:2px solid var(--text);transform:translate(3px,-3px)}
.nk-cell.private .nk-back{border-style:dashed;border-color:var(--text3)}
.nk-cell .nk-strip{position:absolute;left:.5px;right:.5px;bottom:.5px;height:14px;border-radius:0 0 6px 6px;background:var(--cat,var(--text2));display:flex;align-items:center;justify-content:space-between;padding:0 4px;color:var(--white);font-size:10px;font-weight:900;line-height:1;z-index:1}
.nk-cell .nk-strip .icon{width:9px;height:9px}
.nk-cell .nk-count{position:absolute;top:-6px;left:-6px;z-index:2;height:16px;padding:0 5px;border-radius:8px;background:var(--white);font-size:10px;font-weight:900;line-height:16px;box-shadow:0 2px 6px rgba(42,24,16,.25)}
.nk-cell.peeled .nk-ph,.nk-cell.peeled .nk-back,.nk-cell.peeled .nk-count{visibility:hidden}
.nk-cell.dropping .nk-ph,.nk-cell.dropping .nk-back,.nk-cell.dropping .nk-count,.nk-cell.dropping .nk-strip{opacity:0}
.nk-cell.today-filled{outline:2px solid var(--primary);outline-offset:2px}
.nk-cell.num{display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;color:var(--text3)}
.nk-cell.future{color:var(--cream-3);cursor:default}
.nk-cell.today{min-width:0;overflow:hidden;border:2px dashed var(--primary);background:var(--primary-tint);color:var(--primary);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px}
.nk-cell.today .icon{width:18px;height:18px}
.nk-cell.today small{font-size:9px;font-weight:800;white-space:nowrap;letter-spacing:-.2px}
.nk-cell.today.pulse{animation:nkTodayPulse .5s ease-in-out 2}
@keyframes nkTodayPulse{50%{transform:scale(1.05)}}
.nk-cell.press .nk-ph{transform:scale(.96)}
.nk-legend{display:flex;justify-content:space-between;margin-top:6px}
.nk-legend button{height:44px;display:flex;align-items:center;gap:5px;font-size:11px;font-weight:700;color:var(--text2);padding:0 4px;transition:opacity .16s}
.nk-legend button i{width:8px;height:8px;border-radius:50%;background:var(--c)}
.nk-legend.filtering button:not(.on){opacity:.4}
.nk-empty-month{font-size:13px;font-style:italic;font-weight:700;color:var(--text3);text-align:center;padding:4px 0 8px}
.nk-blank{margin-top:12px;border-radius:18px;padding:18px 16px;display:flex;flex-direction:column;align-items:center;gap:12px;text-align:center}
.nk-blank p{font-size:14px;font-weight:700;color:var(--text2);line-height:1.4}
.nk-blank button{height:44px;padding:0 18px;border-radius:14px;font-size:14px;font-weight:900;background:var(--primary);color:var(--cream);border:2px solid var(--primary-2)}
.nk-blank button:active{transform:scale(.97)}
.nk-tray-btn{margin-top:14px;width:100%;height:52px;border-radius:16px;font-size:15px;font-weight:900;background:var(--primary);color:var(--cream);border:2px solid var(--primary-2);position:relative;overflow:hidden;isolation:isolate}
.nk-tray-btn:active{transform:scale(.97)}
.nk-tray-btn.locked{background:var(--cream-2);color:var(--text3);border-color:var(--text3)}
.nk-tray-btn .nk-prog{position:absolute;left:0;bottom:0;height:4px;background:var(--accent)}
.nk-tray-btn.locked::after{content:'';position:absolute;left:0;right:0;bottom:0;height:4px;background:var(--cream-3);z-index:-1}

.nk-results{margin-top:12px;display:flex;flex-direction:column;gap:4px}
.nk-results .nk-r-month{font-style:italic;font-weight:800;font-size:10px;color:var(--primary);letter-spacing:.6px;text-transform:uppercase;margin:12px 0 4px;display:flex;gap:.4rem}
.nk-results .nk-r-month::before{content:'·';font-style:normal}
.nk-r-row{height:64px;display:flex;align-items:center;gap:12px;width:100%;text-align:left;padding:0 4px;border-radius:12px}
.nk-r-row:active{background:var(--cream-2)}
.nk-r-row .nk-thumb{width:42px;height:56px;border-radius:6px;border:2px solid var(--text);background-size:cover;background-position:center;flex-shrink:0;background-color:var(--cream-2);display:flex;align-items:center;justify-content:center;color:var(--text2)}
.nk-r-row .nk-thumb .icon{width:18px;height:18px}
.nk-r-row .nk-t{flex:1;min-width:0}
.nk-r-row b{display:block;font-size:15px;font-weight:900;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.nk-r-row small{font-size:12px;font-weight:700;color:var(--text3)}
.nk-r-row i{width:10px;height:10px;border-radius:50%;background:var(--c,var(--text2));flex-shrink:0}
.nk-no-results{padding:40px 12px;text-align:center;font-weight:700;color:var(--text2)}

/* ── Bữa (detail) ── */
.nk-detail{position:absolute;inset:0;z-index:5;pointer-events:none}
.nk-detail.over-mam{z-index:8}
.nk-detail.open{pointer-events:auto}
.nk-scrim{position:absolute;inset:0;background:var(--paper);opacity:0;transition:opacity .26s var(--ease-out)}
.nk-detail.open .nk-scrim{opacity:.97}
.nk-d-top{position:absolute;left:0;right:0;top:calc(var(--safe-top) + 12px);padding:0 16px;display:flex;flex-direction:column;align-items:center;gap:8px;opacity:0;transform:translateY(-8px);transition:opacity .2s,transform .2s}
.nk-detail.open .nk-d-top{opacity:1;transform:none;transition-delay:.16s}
.nk-d-top-row{position:relative;width:100%;display:flex;justify-content:center;align-items:center;height:44px}
.nk-d-date{height:36px;padding:0 16px;border-radius:18px;display:flex;align-items:center;font-size:15px;font-weight:900;font-style:italic}
.nk-d-more{position:absolute;right:0;width:44px;height:44px;border-radius:50%;font-size:18px;font-weight:900;letter-spacing:1px;display:flex;align-items:center;justify-content:center}
.nk-d-meals{height:44px;display:flex;align-items:center;gap:8px;max-width:100%;overflow-x:auto;scrollbar-width:none}
.nk-d-meals::-webkit-scrollbar{display:none}
.nk-d-meals .nk-static{font-size:13px;font-weight:800;color:var(--text2)}
.nk-d-body{position:absolute;left:0;right:0;top:calc(var(--safe-top) + 112px);bottom:calc(var(--safe-bottom) + 80px);overflow-y:auto;overscroll-behavior:contain;scrollbar-width:none;padding-bottom:12px}
.nk-d-body::-webkit-scrollbar{display:none}
.nk-d-stage{min-height:384px;display:flex;justify-content:center;align-items:flex-start;padding-top:4px;touch-action:none;position:relative}
.nk-d-card{position:relative;width:256px}
.nk-detail:not(.open) .nk-d-card{visibility:hidden}
.nk-d-card .nk-behind{position:absolute;inset:0;background:var(--white);border:2px solid var(--text);border-radius:14px;transform:translate(6px,4px) rotate(3deg)}
.nk-d-frame{position:relative;background:var(--white);border:2px solid var(--text);border-radius:14px;padding:8px 8px 0;transform:rotate(var(--tilt,-1.5deg));transition:opacity .14s}
.nk-d-photo{position:relative;width:236px;height:315px;border-radius:8px;overflow:hidden;background-color:var(--cream-2);display:flex;align-items:center;justify-content:center;color:var(--text2)}
.nk-d-photo img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.nk-d-photo img.hi{opacity:0;transition:opacity .16s}
.nk-d-photo img.hi.ready{opacity:1}
.nk-d-photo .icon{width:56px;height:56px}
.nk-d-chin{min-height:40px;padding:6px 4px 8px;font-size:13px;font-weight:700;font-style:italic;color:var(--text2);line-height:1.3;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;cursor:pointer;overflow-wrap:anywhere}
.nk-d-chin.open{-webkit-line-clamp:6}
.nk-d-chin.name{font-style:normal;font-size:14px;font-weight:900;color:var(--text)}
.nk-meal-stk{position:absolute;top:12px;left:-10px;transform:rotate(-6deg);height:30px;padding:0 10px 0 7px;border-radius:15px;display:flex;align-items:center;gap:5px;font-size:12px;font-weight:900;background:var(--white);border:2px solid var(--text)}
.nk-meal-stk .icon{width:16px;height:16px}
.nk-star-stk{position:absolute;top:-10px;right:-10px;width:30px;height:30px;border-radius:50%;background:var(--accent);color:var(--white);border:2px solid var(--text);transform:rotate(14deg);display:flex;align-items:center;justify-content:center}
.nk-star-stk .icon{width:16px;height:16px}
.nk-ticket{margin:12px 16px 0;border-radius:18px;padding:12px 14px;position:relative;opacity:0;transform:translateY(40px);transition:opacity .3s var(--ease-out),transform .3s var(--ease-out)}
.nk-ticket:active{transform:none}
.nk-detail.open .nk-ticket{opacity:1;transform:none;transition-delay:.18s}
.nk-t-a{display:flex;align-items:center;gap:10px;min-height:44px}
.nk-t-a > span:last-child{min-width:0}
.nk-cat-dot{width:36px;height:36px;border-radius:50%;background:var(--white);color:var(--text2);border:2px solid var(--text);box-shadow:inset 0 0 0 3px var(--cat,var(--text3));display:flex;align-items:center;justify-content:center;flex-shrink:0}
.nk-cat-dot .icon{width:18px;height:18px}
.nk-t-a b{display:block;font-size:16px;font-weight:900;line-height:1.2;overflow-wrap:anywhere}
.nk-t-a small{display:block;font-size:12px;font-weight:700;color:var(--text3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.nk-t-b{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-top:6px;min-height:44px}
.nk-stars{display:flex;align-items:center;gap:2px;color:var(--accent);font-size:13px;font-weight:800}
.nk-stars .icon{width:16px;height:16px}
.nk-stars em{font-style:normal;color:var(--text2);margin-left:4px}
.nk-stars.none{color:var(--text3);font-weight:700}
.nk-priv{height:32px;padding:0 10px;border-radius:16px;background:var(--cream-2);display:flex;align-items:center;gap:5px;font-size:11px;font-weight:800;color:var(--text2);flex-shrink:0}
.nk-priv .icon{width:14px;height:14px}
.nk-visits{font-size:12px;font-weight:700;color:var(--text2);margin-top:6px}
.nk-tear{position:relative;margin:12px -14px;border-top:2px dashed var(--line-2)}
.nk-tear::before,.nk-tear::after{content:'';position:absolute;top:-9px;width:16px;height:16px;border-radius:50%;background:var(--paper);border:2px solid var(--text)}
.nk-tear::before{left:-9px;clip-path:inset(0 0 0 50%)}
.nk-tear::after{right:-9px;clip-path:inset(0 50% 0 0)}
.nk-t-btns{display:flex;gap:8px}
.nk-t-btns button{height:44px;border-radius:14px;display:flex;align-items:center;justify-content:center;gap:6px;font-size:13px;font-weight:900;flex:1;min-width:0;padding:0 6px;white-space:nowrap}
.nk-t-btns .nk-go{flex:1.4;background:var(--primary);color:var(--cream);border-color:var(--primary-2)}
.nk-t-btns .nk-go.off{opacity:.5}
.nk-t-btns .icon{width:17px;height:17px}
@media (max-width:380px){
  .nk-t-btns .nk-go{flex:1.15}
  .nk-t-btns button{gap:4px;padding:0 4px}
  .nk-cell.today small{font-size:8px;letter-spacing:-.3px}
}
@media (max-width:340px){
  .nk-t-btns button,.nk-t-btns .nk-go{flex:1 1 auto}
  .nk-stars .icon{width:13px;height:13px}
  .nk-priv{padding:0 8px}
  .nk-cell.today small{display:none}
}
.nk-d-bar{position:absolute;left:12px;right:12px;bottom:calc(var(--safe-bottom) + 12px);display:flex;gap:8px;align-items:center;opacity:0;transform:translateY(80px);transition:opacity .26s,transform .26s var(--ease-out)}
.nk-detail.open .nk-d-bar{opacity:1;transform:none;transition-delay:.22s}
.nk-ruler{flex:1;height:56px;border-radius:16px;position:relative;touch-action:none;cursor:ew-resize}
.nk-ruler:active{transform:none}
.nk-tick{position:absolute;bottom:18px;width:3px;margin-left:-1.5px;border-radius:2px;background:var(--c,var(--line-2))}
.nk-r-lbl{position:absolute;bottom:4px;font-size:9px;font-weight:800;color:var(--text3);transform:translateX(-50%)}
.nk-r-handle{position:absolute;bottom:10px;width:20px;height:20px;margin-left:-10px;border-radius:50%;background:var(--primary);border:2px solid var(--text);transition:left .2s var(--ease-ios);z-index:1}
.nk-ruler.dragging .nk-r-handle{transition:none}
.nk-bubble{position:absolute;bottom:calc(var(--safe-bottom) + 80px);width:56px;height:84px;margin-left:-28px;border-radius:12px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;opacity:0;pointer-events:none;transition:opacity .12s;z-index:6}
.nk-bubble.show{opacity:1}
.nk-bubble i{width:44px;height:58px;border-radius:6px;background-color:var(--cream-2);background-size:cover;background-position:center;border:2px solid var(--text)}
.nk-bubble b{font-size:10px;font-weight:900}
.nk-coach{position:absolute;left:50%;bottom:calc(var(--safe-bottom) + 84px);transform:translateX(-50%);width:max-content;max-width:calc(100% - 32px);padding:7px 14px;border-radius:16px;font-size:12px;font-weight:800;line-height:1.35;text-align:center;z-index:6;opacity:0;pointer-events:none;transition:opacity .2s}
.nk-coach.show{opacity:1}

.nk-peel{position:absolute;z-index:11;background-color:var(--cream-2);background-size:cover;background-position:center;pointer-events:none;border:2px solid var(--text);will-change:left,top,width,height,transform}

.nk-pop{position:absolute;z-index:10;width:250px;border-radius:14px;padding:12px;background:var(--paper);border:2px solid var(--text);display:flex;flex-direction:column;gap:10px}
.nk-pop p{font-size:14px;font-weight:800}
.nk-pop .nk-btns{display:flex;gap:8px}
.nk-pop .nk-btns button{flex:1;height:44px;border-radius:12px;font-weight:900;font-size:13px}
.nk-pop .nk-btns .nk-yes{background:var(--primary);color:var(--cream);border-color:var(--primary-2)}
.nk-menu{position:absolute;z-index:10;right:16px;top:calc(var(--safe-top) + 60px);width:190px;border-radius:14px;padding:6px;background:var(--paper);border:2px solid var(--text)}
.nk-menu p{font-weight:800;font-size:13px;padding:6px 8px}
.nk-menu button{width:100%;height:44px;border-radius:10px;display:flex;align-items:center;gap:10px;padding:0 10px;font-size:14px;font-weight:800;text-align:left}
.nk-menu button:active{background:var(--cream-2)}
.nk-menu button .icon{width:18px;height:18px}
.nk-menu .nk-danger{color:var(--primary)}

/* ── Mâm tháng ── */
.nk-mam{position:absolute;inset:0;z-index:7;background:var(--cream);overflow-y:auto;overscroll-behavior:contain;padding:calc(var(--safe-top) + 12px) 16px calc(var(--safe-bottom) + 20px);opacity:0;pointer-events:none;transition:opacity .2s;scrollbar-width:none}
.nk-mam::-webkit-scrollbar{display:none}
.nk-mam.open{opacity:1;pointer-events:auto}
.nk-mam .nk-eyebrow{margin-top:14px}
.nk-mam h2{font-size:28px;font-weight:900;letter-spacing:-.5px;margin-top:6px;line-height:1.1}
.nk-mam h2 em{font-style:italic;color:var(--primary)}
.nk-poster{margin-top:16px;display:flex;flex-direction:column;align-items:center}
.nk-tray{position:relative;width:260px;height:260px;border-radius:50%;background:var(--cream-3);border:2px solid var(--text)}
.nk-tray::before{content:'';position:absolute;inset:10px;border-radius:50%;border:2px dashed var(--text3)}
.nk-plate{position:absolute;border-radius:50%;background-color:var(--cream-2);background-size:cover;background-position:center;border:2px solid var(--text);padding:0}
.nk-plate.pop-in{animation:nkPlatePop .24s var(--ease-spring) both}
@keyframes nkPlatePop{from{transform:scale(0)}to{transform:scale(1)}}
.nk-chop{position:absolute;right:18px;bottom:-4px;width:3px;height:92px;border-radius:2px;background:var(--text2);transform-origin:bottom center}
.nk-tray-cap{margin-top:12px;font-size:12px;font-style:italic;font-weight:700;color:var(--text2)}
.nk-m-stats{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:16px}
.nk-m-stat{min-height:78px;border-radius:14px;padding:10px 12px;display:flex;flex-direction:column;justify-content:center;min-width:0}
.nk-m-stat:active{transform:none}
.nk-m-stat small{font-size:11px;font-weight:800;color:var(--text3)}
.nk-m-stat b{font-size:15px;font-weight:900;line-height:1.2;margin-top:2px;overflow-wrap:anywhere}
.nk-m-btns{display:flex;gap:8px;margin-top:16px}
.nk-m-btns button{height:48px;border-radius:14px;font-size:14px;font-weight:900;flex:1}
.nk-m-btns .nk-share{flex:1.6;background:var(--primary);color:var(--cream);border-color:var(--primary-2)}

/* ── Ảnh to (lightbox) — paper ground, same sticker frame ── */
.nk-lb{position:absolute;inset:0;z-index:14;background:var(--paper);display:flex;flex-direction:column;opacity:0;pointer-events:none;transition:opacity .2s}
.nk-lb.open{opacity:1;pointer-events:auto}
.nk-lb-top{position:relative;display:flex;align-items:center;justify-content:center;min-height:44px;margin:calc(var(--safe-top) + 12px) 16px 6px}
.nk-lb-top .nk-circle{position:absolute;right:0;top:0}
.nk-lb-stage{flex:1;min-height:0;display:flex;align-items:center;justify-content:center;touch-action:none;overflow:hidden}
.nk-lb-frame{position:relative;border:2px solid var(--text);border-radius:14px;overflow:hidden;background:var(--cream-2);max-width:100%}
.nk-lb-frame img{position:absolute;left:0;top:0;width:100%;height:100%;object-fit:cover;transform-origin:0 0;will-change:transform;user-select:none;-webkit-user-drag:none}
.nk-lb-frame.zoomed{cursor:grab}
.nk-lb-hint{text-align:center;font-size:12px;font-weight:700;color:var(--text3);padding:10px 16px calc(var(--safe-bottom) + 16px)}
.nk-flash{position:absolute;left:50%;top:calc(var(--safe-top) + 64px);transform:translate(-50%,-10px);z-index:12;height:36px;padding:0 14px;border-radius:18px;display:flex;align-items:center;font-size:13px;font-weight:900;white-space:nowrap;opacity:0;transition:opacity .2s,transform .2s;pointer-events:none}
.nk-flash.show{opacity:1;transform:translate(-50%,0)}
.nk-ink{position:absolute;z-index:3;border-radius:50%;border:2px solid var(--primary);pointer-events:none}

@media (prefers-reduced-motion:reduce){
  .nk *,.nk *::before,.nk *::after{transition-duration:.15s!important;animation:none!important}
}

/* ── CHECK-IN DISCOVER (Cộng đồng → Check-in subtab, below friends bubbles) ── */
.ci-disc-divider{height:8px;background:var(--cream-2,#F5EBC1);margin:6px -1.1rem 0}
.ci-disc-section{padding-top:2px}
.ci-disc-hd{padding:12px 0 0}
.ci-disc-title{font-size:.98rem;font-weight:800;color:var(--text);display:flex;align-items:center;gap:6px}
.ci-disc-sub{font-size:.72rem;color:var(--text3);font-weight:600;margin-top:2px}
.ci-disc-chips{display:flex;gap:7px;padding:10px 0 12px;overflow-x:auto}
.ci-disc-chip{
  flex-shrink:0;display:flex;align-items:center;gap:5px;
  padding:.45rem .8rem;border-radius:20px;
  background:var(--paper);border:1.5px solid var(--cream-3,#EEE0A6);
  font-size:.75rem;font-weight:700;color:var(--text2);font-family:inherit;
  cursor:pointer;white-space:nowrap;
}
.ci-disc-chip.on{background:var(--primary);border-color:var(--text);color:var(--white);box-shadow:2px 2px 0 var(--text)}
.ci-disc-empty{text-align:center;padding:1.2rem 1rem;color:var(--text2);font-size:.82rem}
.ci-disc-grid{display:grid;grid-template-columns:1fr 1fr;gap:9px;padding-bottom:6px}
.ci-disc-card{
  position:relative;border-radius:16px;overflow:hidden;
  border:2px solid var(--text);box-shadow:3px 3px 0 var(--text);
  aspect-ratio:3/4.3;display:flex;align-items:flex-end;cursor:pointer;
  transition:transform .1s;
}
.ci-disc-card:active{transform:scale(.96)}
.ci-disc-card-bg{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:2.4rem;background:var(--paper)}
.ci-disc-card-scrim{position:absolute;inset:0;background:linear-gradient(180deg,transparent 40%,rgba(42,24,16,.78) 100%)}
.ci-disc-card-badge{
  position:absolute;top:7px;left:7px;z-index:2;
  display:flex;align-items:center;gap:3px;
  background:rgba(254,249,229,.94);border:1.5px solid var(--text);
  border-radius:10px;padding:3px 7px;font-size:.6rem;font-weight:800;color:var(--text);
}
.ci-disc-card-badge.hot{background:var(--accent);color:var(--white);border-color:var(--text)}
.ci-disc-card-count{
  position:absolute;top:7px;right:7px;z-index:2;
  background:var(--primary);color:var(--white);font-size:.62rem;font-weight:800;
  min-width:18px;height:18px;border-radius:9px;padding:0 4px;
  display:flex;align-items:center;justify-content:center;
  border:1.5px solid var(--text);
}
.ci-disc-card-body{position:relative;z-index:2;padding:8px;width:100%;color:var(--white)}
.ci-disc-card-name{font-size:.75rem;font-weight:800;line-height:1.25;margin-bottom:3px;text-shadow:0 1px 2px rgba(0,0,0,.3)}
.ci-disc-card-meta{font-size:.6rem;font-weight:700;opacity:.92;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ═══════════════════════════════════════════════
   THỐNG KÊ — InsightsSheet (js/insights-sheet.js, 2026-09-26)
   Its own fixed layer: above the check-in viewer (300) and the diary
   (150), below #toast (999). Not a .modal-overlay on purpose (other
   modals hide "the first .modal-overlay.show"). House style only: paper
   sheet, 2px ink borders, hard offset shadows, italic display type.
═══════════════════════════════════════════════ */
.ins-ov{position:fixed;inset:0;z-index:400;display:flex;align-items:flex-end;justify-content:center;pointer-events:none}
/* The author display:flex above beats the UA [hidden] rule — without this the
   closed sheet stays rendered (its shadow, its ✕ in the Tab order, an
   aria-modal dialog in the a11y tree). Same trap as .photo-view[hidden]. */
.ins-ov[hidden]{display:none}
.ins-ov.show{pointer-events:auto}
.ins-backdrop{position:absolute;inset:0;background:rgba(42,24,16,.5);opacity:0;transition:opacity .25s}
.ins-ov.show .ins-backdrop{opacity:1}
.ins-sheet{
  position:relative;width:100%;max-width:520px;max-height:90vh;max-height:90dvh;display:flex;flex-direction:column;
  background:var(--paper);border-top:2px solid var(--text);border-radius:var(--radius-lg) var(--radius-lg) 0 0;
  box-shadow:0 -8px 24px rgba(42,24,16,.18);outline:none;
  transform:translateY(100%);transition:transform .32s var(--ease-ios);
}
.ins-ov.show .ins-sheet{transform:translateY(0)}
.ins-sheet.dragging{transition:none}
.ins-grab{padding:.6rem 0 .1rem;touch-action:none;cursor:grab;flex-shrink:0}
.ins-grab .modal-handle{margin:0 auto}
.ins-top{display:flex;align-items:center;gap:.5rem;padding:.25rem .9rem .55rem;touch-action:none;flex-shrink:0}
.ins-title{flex:1;min-width:0;margin:0;font-size:1.3rem;line-height:1.2;text-wrap:balance}
.ins-title em{color:var(--text)}
.ins-ic{
  width:2.2rem;height:2.2rem;flex-shrink:0;border-radius:50%;
  background:var(--white);border:2px solid var(--text);box-shadow:2px 2px 0 var(--text);
  display:flex;align-items:center;justify-content:center;color:var(--text);
  font-size:1.35rem;font-weight:900;line-height:1;cursor:pointer;
}
.ins-ic .icon{width:1rem;height:1rem}
.ins-ic:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}
.ins-ic.off{visibility:hidden}
.ins-ic:focus-visible,.ins-seg button:focus-visible,.ins-topp:focus-visible,.ins-chart:focus-visible,.ins-retry:focus-visible{outline:2px solid var(--primary);outline-offset:2px}
.ins-body{flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:.1rem 1rem calc(var(--safe-bottom) + 1.2rem);scrollbar-width:none}
.ins-body::-webkit-scrollbar{display:none}

/* Post header: thumbnail + name + date */
.ins-post{display:flex;align-items:center;gap:.7rem;padding:.6rem .7rem;background:var(--white);border:2px solid var(--text);border-radius:14px;box-shadow:2px 2px 0 var(--text)}
.ins-thumb{width:46px;height:46px;flex-shrink:0;border-radius:10px;border:2px solid var(--text);background:var(--cream-2) center/cover no-repeat;display:flex;align-items:center;justify-content:center;color:var(--text2)}
.ins-thumb.empty .icon{width:1.3rem;height:1.3rem}
.ins-post-txt{min-width:0;display:flex;flex-direction:column;line-height:1.25}
.ins-post-txt b{font-family:var(--font-display);font-weight:900;font-size:.98rem;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ins-post-txt span{font-size:.74rem;font-weight:700;color:var(--text3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

.ins-h{font-family:var(--font-display);font-style:italic;font-weight:800;font-size:.72rem;color:var(--primary);letter-spacing:.8px;text-transform:uppercase;margin:1.05rem 0 .5rem}

/* Overview tiles (2×2); the first one is the hero */
.ins-tiles{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:.8rem}
.ins-h + .ins-tiles{margin-top:0}
.ins-tile{min-width:0;min-height:84px;padding:10px 12px;border-radius:14px;background:var(--white);border:2px solid var(--text);box-shadow:2px 2px 0 var(--text);display:flex;flex-direction:column;justify-content:center;gap:1px}
.ins-tile small{font-size:.7rem;font-weight:800;color:var(--text2);line-height:1.2}
.ins-tile b{font-family:var(--font-display);font-size:1.55rem;font-weight:900;color:var(--text);line-height:1.1;font-variant-numeric:tabular-nums;overflow:hidden;text-overflow:ellipsis}
.ins-tile span{font-size:.66rem;font-weight:700;color:var(--text3);line-height:1.2}
.ins-tile.hero{background:var(--primary);border-color:var(--primary-2);box-shadow:2px 2px 0 var(--primary-3)}
.ins-tile.hero small,.ins-tile.hero span{color:var(--cream)}
.ins-tile.hero b{color:var(--white)}
.ins-loading .ins-tile b{color:var(--text3)}
.ins-tile.hero.ins-tile b{color:var(--white)}
.ins-wait{text-align:center;font-size:.78rem;font-weight:700;color:var(--text3);margin:.9rem 0 0}

/* Interactions row */
.ins-acts{display:grid;grid-template-columns:repeat(auto-fit,minmax(58px,1fr));gap:6px}
.ins-act{min-width:0;padding:.55rem .2rem .5rem;border-radius:12px;background:var(--white);border:1.5px solid var(--line-2);display:flex;flex-direction:column;align-items:center;gap:2px;color:var(--primary)}
.ins-act .icon{width:1.05rem;height:1.05rem}
.ins-act b{font-family:var(--font-display);font-weight:900;font-size:1.05rem;color:var(--text);font-variant-numeric:tabular-nums;line-height:1.15}
.ins-act span{font-size:.62rem;font-weight:800;color:var(--text2);text-align:center;line-height:1.15}

.ins-card{padding:.75rem .8rem;border-radius:14px;background:var(--white);border:2px solid var(--text);box-shadow:2px 2px 0 var(--text)}

/* Daily chart */
.ins-chart{display:flex;align-items:flex-end;gap:3px;height:112px;padding-top:16px;touch-action:pan-y;cursor:pointer;outline:none;border-radius:6px}
.ins-chart-card.dense .ins-chart{gap:1.5px}
.ins-col{flex:1 1 0;min-width:0;height:100%;display:flex;align-items:flex-end;justify-content:center;border-radius:5px 5px 0 0}
.ins-bars{position:relative;width:100%;max-width:18px;height:100%;display:flex;align-items:flex-end;justify-content:center;gap:1px}
.ins-bar{position:relative;flex:1;min-width:0;height:calc(var(--h) * 1%);background:var(--primary);border-radius:4px 4px 0 0;transition:height .3s var(--ease-ios),opacity .15s}
.ins-bar.p{background:var(--accent)}
.ins-bar.z{height:3px;background:var(--line-2);border-radius:2px}
.ins-col.pre .ins-bar{height:100%;background:transparent;border:1.5px dashed var(--line-2);border-bottom:0}
.ins-col.today .ins-bar:not(.z):not(.p){background:var(--primary-2)}
.ins-chart.has-sel .ins-col:not(.sel) .ins-bar{opacity:.4}
.ins-col.sel{background:var(--primary-tint)}
/* Value label over the peak day, or over the picked one */
.ins-chart:not(.has-sel) .ins-col.peak .ins-bar:not(.p)::after,
.ins-col.sel .ins-bar:not(.p):not(.z)::after{
  content:attr(data-v);position:absolute;bottom:100%;left:50%;transform:translateX(-50%);margin-bottom:2px;
  font-size:.62rem;font-weight:900;color:var(--text);white-space:nowrap;font-variant-numeric:tabular-nums;
}
.ins-col.pre .ins-bar::after{display:none}
.ins-axis{display:flex;gap:3px;margin-top:4px}
.ins-chart-card.dense .ins-axis{gap:1.5px}
.ins-axis span{flex:1 1 0;min-width:0;text-align:center;font-size:.58rem;font-weight:700;color:var(--text3);line-height:1.15;white-space:nowrap;overflow:visible}
.ins-axis b{display:block;font-weight:800}
.ins-axis span.today{color:var(--primary)}
.ins-cap{margin:.55rem 0 0;font-size:.74rem;font-weight:800;color:var(--text2);text-align:center;min-height:1.1em}
.ins-cleg{display:flex;flex-wrap:wrap;justify-content:center;gap:.4rem .9rem;margin-top:.45rem;font-size:.66rem;font-weight:700;color:var(--text2)}
.ins-cleg span{display:inline-flex;align-items:center;gap:.3rem}
.ins-cleg i{width:10px;height:10px;border-radius:3px;background:var(--primary)}
.ins-cleg i.p{background:var(--accent)}
.ins-cleg i.pre{background:transparent;border:1.5px dashed var(--line-2)}

/* View sources */
.ins-srcs{display:flex;flex-direction:column;gap:.5rem}
.ins-src{display:grid;grid-template-columns:minmax(0,7.5rem) 1fr auto 2.6rem;align-items:center;gap:.5rem}
.ins-src-l{font-size:.74rem;font-weight:800;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ins-src-t{height:9px;border-radius:5px;background:var(--cream-2);overflow:hidden}
.ins-src-t i{display:block;height:100%;border-radius:5px;background:var(--primary)}
.ins-src b{font-size:.78rem;font-weight:900;color:var(--text);font-variant-numeric:tabular-nums;text-align:right}
.ins-src small{font-size:.66rem;font-weight:700;color:var(--text3);text-align:right;font-variant-numeric:tabular-nums}

/* Followers vs others */
.ins-split{display:flex;height:14px;border-radius:7px;overflow:hidden;background:var(--cream-2);border:1.5px solid var(--text)}
.ins-split i{display:block;height:100%}
.ins-split i.f,.ins-leg i.f{background:var(--primary)}
.ins-split i.o,.ins-leg i.o{background:var(--accent)}
.ins-leg{display:flex;flex-direction:column;gap:.35rem;margin-top:.6rem}
.ins-leg span{display:flex;align-items:center;gap:.45rem;font-size:.76rem;font-weight:800;color:var(--text)}
.ins-leg i{width:11px;height:11px;border-radius:3px;flex-shrink:0}
.ins-leg b{margin-left:auto;font-weight:900;font-variant-numeric:tabular-nums}
.ins-leg small{width:2.6rem;text-align:right;font-size:.68rem;font-weight:700;color:var(--text3);font-variant-numeric:tabular-nums}

.ins-foot{margin:1rem .2rem 0;font-size:.68rem;font-weight:600;color:var(--text3);text-align:center;line-height:1.45;text-wrap:balance}
.ins-state{padding:1.6rem 1rem .6rem}
.ins-state .em-icon .icon{width:2.2rem;height:2.2rem;color:var(--text3)}
.ins-retry{flex:none;margin-top:.9rem;padding:.55rem 1.4rem}

/* Account: 7 / 30 days toggle, top posts */
.ins-seg{display:flex;gap:4px;padding:4px;margin-top:.2rem;border-radius:14px;background:var(--cream-2);border:2px solid var(--text)}
.ins-seg button{flex:1;padding:.45rem .5rem;border-radius:10px;background:transparent;border:0;font-family:var(--font-display);font-weight:800;font-size:.82rem;color:var(--text2);cursor:pointer}
.ins-seg button.on{background:var(--primary);color:var(--cream);box-shadow:1.5px 1.5px 0 var(--primary-3)}
.ins-tops{display:flex;flex-direction:column;gap:6px}
.ins-topp{display:flex;align-items:center;gap:.65rem;width:100%;padding:.5rem .6rem;text-align:left;border-radius:14px;background:var(--white);border:2px solid var(--text);box-shadow:2px 2px 0 var(--text);cursor:pointer;color:var(--text)}
.ins-topp:active{transform:translate(1px,1px);box-shadow:1px 1px 0 var(--text)}
.ins-topp .ins-thumb{width:40px;height:40px}
.ins-topp-txt{flex:1;min-width:0;display:flex;flex-direction:column;line-height:1.25}
.ins-topp-txt b{font-weight:900;font-size:.86rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ins-topp-txt span{font-size:.7rem;font-weight:700;color:var(--text3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ins-chev{font-size:1.4rem;font-weight:900;color:var(--text3);line-height:1}
.ins-none{margin:0;padding:.9rem;border-radius:14px;border:1.5px dashed var(--line-2);font-size:.78rem;font-weight:700;color:var(--text3);text-align:center}

/* Profile tab: account insights button — top-LEFT: a 4th slot on the right
   would sit on the centred avatar at phone widths. */
.settings-gear.settings-gear-4{right:auto;left:.9rem}

@media (prefers-reduced-motion: reduce){
  .ins-sheet,.ins-backdrop,.ins-bar{transition:none}
}

/* Game Cơm Tấm Bà Thảo (js/ctbt.js) — nhãn trên viewer, trang quán, banner */
.ci-viewer-game{
  align-self:flex-start;border:1.5px solid rgba(255,214,140,.7);border-radius:999px;
  background:rgba(120,53,15,.72);color:#FFE7B8;font:inherit;font-size:.74rem;font-weight:900;
  padding:6px 12px;cursor:pointer;
}
.ci-viewer-game.hidden{display:none}
.ctbt-quan{margin:.7rem 0 .2rem;display:flex;flex-direction:column;gap:.55rem}
.ctbt-play{
  width:100%;height:44px;border-radius:14px;border:2px solid var(--primary,#C2410C);
  background:linear-gradient(180deg,#FDE68A,#F59E0B);color:#451A03;font:inherit;font-weight:900;font-size:.9rem;cursor:pointer;
}
.ctbt-play:active{transform:scale(.98)}
.ctbt-strip-title{font-size:.8rem;font-weight:900;color:var(--text2)}
.ctbt-strip{display:flex;gap:.5rem;overflow-x:auto;padding-bottom:.2rem;scrollbar-width:none}
.ctbt-strip::-webkit-scrollbar{display:none}
.ctbt-thumb{
  flex:0 0 76px;height:76px;border-radius:14px;border:2px solid var(--line-2,#E8D9C0);
  background:var(--cream-2,#F6EBD9) center/cover no-repeat;cursor:pointer;padding:0;
}
.ctbt-strip-empty{font-size:.78rem;font-weight:700;color:var(--text2);padding:.3rem 0}
/* 2026-10-01: màn "Cho phép liên kết" game ↔ tài khoản (js/ctbt.js _showLinkSheet) */
.ctbt-link-sheet{display:flex;flex-direction:column;gap:.55rem}
.ctbt-link-ico{display:flex;justify-content:center}
.ctbt-link-ico img{width:56px;height:56px;object-fit:contain;image-rendering:pixelated}
.ctbt-link-sheet .modal-sub{margin-bottom:.2rem}
.ctbt-link-list{list-style:none;margin:0 0 .3rem;padding:.6rem .8rem;border-radius:14px;background:var(--cream-2,#F6EBD9);
  display:flex;flex-direction:column;gap:.4rem;font-size:.82rem;font-weight:700;color:var(--text,#2A1810);line-height:1.35}
.ctbt-link-no{border:none;background:transparent;color:var(--text2);font:inherit;font-weight:800;font-size:.82rem;padding:.5rem;cursor:pointer}
.ctbt-link-status{min-height:1.2em;text-align:center;font-size:.78rem;font-weight:800;color:var(--primary,#B92626)}
.ctbt-banner{
  display:flex;align-items:center;gap:.7rem;margin:0 0 .8rem;padding:.7rem .8rem;
  border:2px dashed var(--primary-2,#F59E0B);border-radius:16px;background:#FFF7E6;
}
.ctbt-banner.hidden{display:none}
.ctbt-banner-ico{font-size:1.8rem;line-height:1;display:flex;align-items:center}
.ctbt-banner-ico img{width:40px;height:40px;object-fit:contain;image-rendering:pixelated}
.ctbt-banner-text{flex:1;min-width:0}
.ctbt-banner-title{font-weight:900;font-size:.88rem;color:var(--text,#2A1810)}
.ctbt-banner-sub{font-size:.74rem;font-weight:700;color:var(--text2);line-height:1.35;margin-top:2px}
.ctbt-banner-btn{
  flex-shrink:0;border:none;border-radius:999px;padding:.5rem .9rem;background:var(--primary,#C2410C);
  color:#fff;font:inherit;font-weight:900;font-size:.8rem;cursor:pointer;
}
.scan-notice{
  font-size:.75rem;font-weight:700;color:#92400e;background:#fef3c7;
  padding:.5rem .9rem;line-height:1.4;text-align:center;
}
.feedback-banner{
  display:flex;align-items:center;gap:.7rem;margin:0 0 .8rem;padding:.6rem .8rem;
  border-radius:12px;background:var(--cream-2,#F6EBD9);
}
.feedback-banner-text{flex:1;font-size:.78rem;font-weight:700;color:var(--text2);line-height:1.35}
.feedback-email{font-size:.72rem;font-weight:600;color:var(--text2);opacity:.75}
.feedback-banner-btn{
  flex-shrink:0;border-radius:999px;padding:.4rem .85rem;background:transparent;
  border:2px solid var(--primary,#C2410C);color:var(--primary,#C2410C);
  font:inherit;font-weight:900;font-size:.78rem;text-decoration:none;white-space:nowrap;
}

/* Banner "Mở bằng Safari/Chrome" (InAppBanner, js/app.js) — chỉ trong trình
   duyệt nhúng của app. html.iab-on đẩy --ribbon-h xuống đúng bằng chiều cao
   banner nên mọi .screen và #toast tự nhường chỗ, không che nội dung. */
:root.iab-on{--ribbon-h:calc(var(--safe-top) + var(--iab-h))}
.iab-banner{
  position:fixed;top:0;left:0;right:0;z-index:120;
  height:calc(var(--safe-top) + var(--iab-h));padding:var(--safe-top) .35rem 0 .75rem;
  display:flex;align-items:center;gap:.45rem;
  background:var(--text);color:var(--cream);
}
.iab-text{flex:1;min-width:0;font-size:.74rem;font-weight:700;line-height:1.25}
.iab-btn{
  flex-shrink:0;border:none;border-radius:999px;padding:.42rem .8rem;
  background:var(--primary);color:var(--cream);
  font-family:var(--font-display);font-weight:900;font-size:.76rem;cursor:pointer;
}
.iab-btn:active{background:var(--primary-2)}
.iab-x{
  flex-shrink:0;width:32px;height:32px;border:none;background:none;color:var(--cream);
  display:flex;align-items:center;justify-content:center;opacity:.75;cursor:pointer;
}

/* Bell → unread-DM badge (js/dm.js DmCtrl polls /api/nn — actually
   /api/dm/unread — and toggles .show here). Plain dot, no number: keeps
   the cluster button's fixed size regardless of count. */
#homeBellBtn{position:relative}
.dm-badge{
  position:absolute;top:3px;right:6px;width:9px;height:9px;border-radius:50%;
  background:var(--primary);border:1.5px solid var(--white);display:none;
}
.dm-badge.show{display:block}

/* ═══════════════════════════════════════════════
   NHẮN TIN — DmCtrl (js/dm.js, 2026-09-30)
   Full-screen layer, z-index 260: above .modal-overlay (200 — opened
   from UserQuanModal's "Nhắn tin" button without closing it first would
   otherwise stack wrong) and below the check-in viewer (300, InsightsSheet/
   the comment sheet 400) since nothing there opens DM directly. Same
   .comment-input-row/.comment-input/.comment-send-btn classes as the
   comment sheet for the input row — consistent look, no new CSS needed
   for that part.
═══════════════════════════════════════════════ */
.dm-root{position:fixed;inset:0;z-index:260;display:flex;align-items:flex-end;justify-content:center;pointer-events:none}
.dm-root[hidden]{display:none}
.dm-root.show{pointer-events:auto}
.dm-backdrop{position:absolute;inset:0;background:rgba(42,24,16,.5);opacity:0;transition:opacity .25s}
.dm-root.show .dm-backdrop{opacity:1}
.dm-sheet{
  position:relative;width:100%;max-width:520px;height:88dvh;height:88vh;display:flex;flex-direction:column;
  background:var(--paper);border-top:2px solid var(--text);border-radius:var(--radius-lg) var(--radius-lg) 0 0;
  box-shadow:0 -8px 24px rgba(42,24,16,.18);outline:none;overflow:hidden;
  transform:translateY(100%);transition:transform .32s var(--ease-ios);
}
.dm-root.show .dm-sheet{transform:translateY(0)}
.dm-view{flex:1;min-height:0;display:flex;flex-direction:column}
.dm-view.hidden{display:none}
.dm-hd{
  flex-shrink:0;display:flex;align-items:center;gap:.5rem;
  padding:calc(env(safe-area-inset-top,0px) + .7rem) .9rem .6rem;
  border-bottom:1.5px solid var(--line-2);
}
.dm-hd-title{flex:1;margin:0}
.dm-conv-list{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:.4rem 0 calc(env(safe-area-inset-bottom,0px) + .6rem)}
.dm-conv-row{
  width:100%;display:flex;align-items:center;gap:.7rem;padding:.6rem .9rem;
  background:none;border:none;text-align:left;cursor:pointer;
}
.dm-conv-row:active{background:var(--cream-2)}
.dm-conv-avatar{flex-shrink:0;width:44px;height:44px;border-radius:50%;background:var(--cream-2);display:flex;align-items:center;justify-content:center;font-size:1.3rem;overflow:hidden}
.dm-conv-avatar img{width:100%;height:100%;object-fit:cover}
.dm-conv-body{flex:1;min-width:0}
.dm-conv-name{font-weight:800;font-size:.88rem;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dm-conv-preview{font-size:.76rem;color:var(--text3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dm-conv-row.unread .dm-conv-preview{color:var(--text);font-weight:700}
.dm-conv-meta{flex-shrink:0;display:flex;flex-direction:column;align-items:flex-end;gap:.25rem}
.dm-conv-time{font-size:.66rem;color:var(--text3)}
.dm-conv-dot{width:9px;height:9px;border-radius:50%;background:var(--primary)}
.dm-empty{padding:2.2rem 1.2rem;text-align:center;color:var(--text3);font-size:.85rem;font-style:italic}

.dm-thread-who{flex:1;min-width:0;display:flex;align-items:center;gap:.5rem}
.dm-thread-avatar{flex-shrink:0;width:32px;height:32px;border-radius:50%;background:var(--cream-2);display:flex;align-items:center;justify-content:center;font-size:1rem;overflow:hidden}
.dm-thread-avatar img{width:100%;height:100%;object-fit:cover}
.dm-thread-name{font-weight:800;font-size:.88rem;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dm-msgs{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:.7rem .9rem;display:flex;flex-direction:column;gap:.4rem}
.dm-bubble-row{display:flex}
.dm-bubble-row.mine{justify-content:flex-end}
.dm-bubble{
  max-width:78%;padding:.5rem .75rem;border-radius:16px;font-size:.85rem;line-height:1.4;
  word-break:break-word;background:var(--white);color:var(--text);border:1.5px solid var(--line-2);
}
.dm-bubble-row.mine .dm-bubble{background:var(--primary);color:var(--cream);border-color:var(--primary-2);border-bottom-right-radius:4px}
.dm-bubble-row:not(.mine) .dm-bubble{border-bottom-left-radius:4px}
.dm-bubble-time{font-size:.6rem;opacity:.7;margin-top:.2rem;display:block}
.dm-input-row{flex-shrink:0;padding:.6rem .9rem calc(env(safe-area-inset-bottom,0px) + .6rem);border-top:1.5px solid var(--line-2)}
