/* Hermes Mobile - design system (Phase 6, P0).
   Dark-only by design ("Dark. Professional. Quiet." per spec) - reuses
   the exact real Hermes desktop tokens (--olive/--success/--danger/
   --sidebar-bg families in desktop_app/frontend/style.css) rather than
   inventing a second palette. */

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body { height: 100%; overflow-x: hidden; }
body {
  margin: 0;
  background: #09090B;
  color: #F5F5F7;
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto, sans-serif;
  -webkit-font-smoothing: antialiased;
  overscroll-behavior-y: none;
}
button, input { font-family: inherit; }
img { max-width: 100%; display: block; }

.btn-primary, .btn-secondary {
  min-height: 44px;
  border-radius: 12px;
  font-size: 15px;
  font-weight: 650;
  border: none;
  cursor: pointer;
  padding: 0 18px;
  /* Shared component fix (item 6): neither rule ever set a display
     mode, so a <button> got whatever the browser's default internal
     text alignment happened to be, and an <a> (e.g. "Open Etsy
     Draft", display:inline by default) ignored min-height/centering
     entirely - text sat top-left instead of centered. Flex-centering
     here fixes every real button AND link using these classes at
     once, not just one call site. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  text-align: center;
  text-decoration: none;
  box-sizing: border-box;
}
.btn-primary { background: #3B82F6; color: #fff; }
.btn-primary:active { background: #2563EB; }
.btn-primary:disabled { opacity: 0.6; }
.btn-primary.is-success { background: #3DDC84; color: #062012; opacity: 1; }
.btn-secondary { background: rgba(255,255,255,0.06); color: #F5F5F7; border: 1px solid rgba(255,255,255,0.10); }
.btn-secondary:disabled { opacity: 0.45; }

/* ---------------- LOGIN ---------------- */
.login-screen {
  min-height: 100vh;
  /* Item 13: 100dvh tracks Safari's real, current visual viewport as
     its address bar/toolbar shows or hides, instead of 100vh's fixed
     (historically largest-viewport) value that can leave content
     clipped or a gap at the bottom as the toolbar animates. Declared
     after the 100vh fallback (never replacing it) for browsers/
     WebViews that don't support dvh yet. */
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 32px 24px calc(32px + env(safe-area-inset-bottom));
  text-align: center;
}
.login-mark { margin-bottom: 18px; }
.login-mark img { border-radius: 16px; }
.login-title { font-size: 22px; font-weight: 700; margin: 0 0 6px; letter-spacing: -0.01em; }
.login-sub { font-size: 14px; color: #9A9AA4; margin: 0 0 28px; max-width: 280px; }
.login-form { width: 100%; max-width: 320px; display: flex; flex-direction: column; gap: 12px; }
.login-input {
  min-height: 48px;
  border-radius: 12px;
  border: 1px solid rgba(255,255,255,0.12);
  background: rgba(255,255,255,0.05);
  color: #F5F5F7;
  font-size: 16px;
  padding: 0 14px;
  text-align: center;
  letter-spacing: 0.02em;
}
.login-input:focus { outline: none; border-color: #3B82F6; }
.login-submit { width: 100%; }
.login-error { color: #FF5E5E; font-size: 13px; margin: 0; }
.login-hint { font-size: 11.5px; color: #6E6E78; max-width: 300px; margin-top: 28px; line-height: 1.5; }

/* ---------------- APP SHELL ---------------- */
.app { min-height: 100vh; min-height: 100dvh; display: flex; flex-direction: column; }
.app-header {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: calc(14px + env(safe-area-inset-top)) 20px 14px;
  background: rgba(9,9,11,0.86);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border-bottom: 1px solid rgba(255,255,255,0.06);
}
.app-header-title { font-size: 14px; font-weight: 750; letter-spacing: 0.08em; color: #F5F5F7; }
.avatar-btn {
  width: 32px; height: 32px; border-radius: 999px;
  background: rgba(255,255,255,0.08); border: 1px solid rgba(255,255,255,0.12);
  color: #F5F5F7; font-size: 11px; font-weight: 700; letter-spacing: 0.02em;
  display: flex; align-items: center; justify-content: center; cursor: pointer;
}

.app-main {
  flex: 1;
  padding: 20px 18px calc(96px + env(safe-area-inset-bottom));
  max-width: 560px;
  width: 100%;
  margin: 0 auto;
}
.view { display: none; }
.view.is-active { display: block; }

.section-block { margin-bottom: 32px; }
.section-label { font-size: 11.5px; font-weight: 750; letter-spacing: 0.09em; color: #7A7A84; }
.section-label-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 4px; }
.section-count {
  font-size: 11.5px; font-weight: 750; color: #F5F5F7;
  background: rgba(255,255,255,0.08); border-radius: 999px; min-width: 20px; height: 20px;
  display: flex; align-items: center; justify-content: center; padding: 0 6px;
}

/* ---------------- TODAY ---------------- */
.today-content { margin-top: 10px; }
.today-revenue { font-size: 40px; font-weight: 750; letter-spacing: -0.02em; line-height: 1.05; }
.today-revenue-label { font-size: 12.5px; color: #9A9AA4; margin-top: 2px; }
.today-secondary-row {
  display: flex; align-items: center; gap: 16px;
  margin-top: 14px; font-size: 14px; font-weight: 600; color: #D8D8DE;
}
.today-favorites { color: #3DDC84; }
.today-skeleton, .needs-you-skeleton, .activity-skeleton {
  height: 54px; border-radius: 12px; margin-top: 10px;
  background: linear-gradient(90deg, rgba(255,255,255,0.04) 25%, rgba(255,255,255,0.08) 37%, rgba(255,255,255,0.04) 63%);
  background-size: 400% 100%;
  animation: hermesShimmer 1.4s ease infinite;
}
@keyframes hermesShimmer { 0% { background-position: 100% 0; } 100% { background-position: 0 0; } }
.updated-pill { font-size: 11.5px; color: #6E6E78; margin-top: 10px; }

/* ---------------- NEEDS YOU ---------------- */
.needs-you-list { display: flex; flex-direction: column; gap: 8px; margin-top: 10px; }
.needs-you-card {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 14px;
  border-radius: 14px;
  background: rgba(255,255,255,0.035);
  border: 1px solid rgba(255,255,255,0.07);
  min-height: 44px;
  cursor: pointer;
}
.needs-you-card:active { background: rgba(255,255,255,0.06); }
.needs-you-thumb {
  width: 44px; height: 44px; border-radius: 10px; object-fit: cover; flex-shrink: 0;
  background: rgba(255,255,255,0.06);
}
.needs-you-body { flex: 1; min-width: 0; }
.needs-you-name { font-size: 14px; font-weight: 700; letter-spacing: 0.01em; text-transform: uppercase; }
.needs-you-status { font-size: 12.5px; color: #9A9AA4; margin-top: 1px; }
.needs-you-action { font-size: 12.5px; font-weight: 700; color: #3B82F6; display: flex; align-items: center; gap: 4px; flex-shrink: 0; }

/* ---------------- ACTIVITY ---------------- */
.activity-list { display: flex; flex-direction: column; gap: 14px; margin-top: 10px; }
.activity-row { display: flex; align-items: center; gap: 10px; min-height: 44px; }
.activity-dot { width: 7px; height: 7px; border-radius: 999px; flex-shrink: 0; }
.activity-dot.is-success { background: #3DDC84; }
.activity-dot.is-active { background: #3B82F6; animation: processingPulse 1.1s ease-in-out infinite; }
.activity-dot.is-error { background: #FF5E5E; }
.activity-body { flex: 1; min-width: 0; }
.activity-name { font-size: 13.5px; font-weight: 650; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.activity-detail { font-size: 12px; color: #9A9AA4; margin-top: 1px; }
.activity-progress-track { height: 4px; border-radius: 999px; background: rgba(255,255,255,0.08); margin-top: 6px; overflow: hidden; }
.activity-progress-fill { height: 100%; background: #3B82F6; border-radius: 999px; transition: width 0.2s ease; }
.activity-time { font-size: 11.5px; color: #6E6E78; flex-shrink: 0; }

.empty-hint { font-size: 13px; color: #6E6E78; margin-top: 10px; }
.analytics-error-state { text-align: center; padding: 40px 20px; }
.analytics-error-state .empty-hint { margin-bottom: 14px; }
.analytics-error-state .btn-secondary { display: inline-flex; min-width: 120px; }

/* ---------------- COMING SOON STUBS ---------------- */
.coming-soon-card {
  margin-top: 12px;
  padding: 28px 20px;
  border-radius: 16px;
  border: 1px dashed rgba(255,255,255,0.14);
  text-align: center;
}
.coming-soon-icon {
  width: 40px; height: 40px; border-radius: 999px;
  background: rgba(59,130,246,0.15); color: #3B82F6;
  display: flex; align-items: center; justify-content: center;
  font-size: 20px; font-weight: 700; margin: 0 auto 12px;
}
.coming-soon-title { font-size: 15px; font-weight: 700; margin: 0 0 6px; }
.coming-soon-body { font-size: 13px; color: #9A9AA4; line-height: 1.5; margin: 0; }

/* ---------------- BOTTOM NAV ----------------
   A real 5-column grid spanning the full viewport width - not flex,
   deliberately: with flex, an unlabeled center item can end up visually
   off-center relative to its four labeled siblings once font-rendering
   width differs. A 5-column grid guarantees column 3 (Create) sits at
   EXACTLY 50% of the viewport, regardless of label text width. */
.bottom-nav {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 30;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  background: rgba(9,9,11,0.92);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border-top: 1px solid rgba(255,255,255,0.07);
  padding-bottom: env(safe-area-inset-bottom);
}
.nav-item {
  min-height: 56px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  background: none; border: none; color: #7A7A84; cursor: pointer;
}
.nav-item.is-active { color: #F5F5F7; }
.nav-icon { width: 22px; height: 22px; }
.nav-icon svg { width: 100%; height: 100%; }
.nav-label { font-size: 10.5px; font-weight: 650; letter-spacing: 0.01em; }
.nav-item-create { position: relative; }
.nav-item-create .nav-icon-create {
  width: 44px; height: 44px; border-radius: 999px;
  background: #3B82F6; color: #fff;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 4px 14px rgba(59,130,246,0.45);
}
.nav-item-create .nav-icon-create svg { width: 20px; height: 20px; }
.nav-item-create.is-active .nav-icon-create,
.nav-item-create .nav-icon-create { color: #fff; }

/* ---------------- BOTTOM SHEETS ---------------- */
.sheet-overlay {
  position: fixed; inset: 0; z-index: 50;
  background: rgba(0,0,0,0.55);
  display: flex; align-items: flex-end;
}
.sheet {
  width: 100%;
  background: #111113;
  border-top-left-radius: 20px;
  border-top-right-radius: 20px;
  border: 1px solid rgba(255,255,255,0.08);
  border-bottom: none;
  padding: 10px 20px calc(24px + env(safe-area-inset-bottom));
  max-height: 80vh;
  overflow-y: auto;
}
.sheet-handle { width: 36px; height: 4px; border-radius: 999px; background: rgba(255,255,255,0.18); margin: 4px auto 18px; }

.detail-header { display: flex; align-items: center; gap: 12px; margin-bottom: 18px; }
.detail-thumb { width: 56px; height: 56px; border-radius: 12px; object-fit: cover; background: rgba(255,255,255,0.06); }
.detail-name { font-size: 16px; font-weight: 750; text-transform: uppercase; letter-spacing: 0.01em; }
.detail-status { font-size: 13px; color: #9A9AA4; margin-top: 2px; }
.detail-action-btn { width: 100%; margin-top: 4px; }

.profile-sheet-content { display: flex; flex-direction: column; gap: 12px; }
.profile-row { display: flex; align-items: center; justify-content: space-between; padding: 6px 2px 14px; border-bottom: 1px solid rgba(255,255,255,0.07); }
.profile-label { font-size: 13px; color: #9A9AA4; }
.profile-value { font-size: 13px; font-weight: 650; }
.profile-settings-btn, .profile-disconnect-btn { width: 100%; }
.profile-disconnect-btn { color: #FF5E5E; }

.back-btn {
  background: none; border: none; color: #9A9AA4; font-size: 14px; font-weight: 650;
  padding: 4px 0 16px; cursor: pointer; min-height: 32px;
}

/* ---------------- CHIPS (filters / ranges) ---------------- */
.chip-row { display: flex; gap: 8px; margin-bottom: 20px; overflow-x: auto; -ms-overflow-style: none; scrollbar-width: none; }
.chip-row::-webkit-scrollbar { display: none; }
.chip {
  flex-shrink: 0;
  min-height: 34px;
  padding: 0 16px;
  border-radius: 999px;
  border: 1px solid rgba(255,255,255,0.12);
  background: rgba(255,255,255,0.04);
  color: #9A9AA4;
  font-size: 13px; font-weight: 650;
  cursor: pointer;
}
.chip.is-active { background: #3B82F6; border-color: #3B82F6; color: #fff; }

/* ---------------- LISTING ROWS (shared: Listings, Top Posters) ---------------- */
.listings-search-row { margin-bottom: 14px; }
.listings-search {
  width: 100%; min-height: 42px; border-radius: 12px;
  border: 1px solid rgba(255,255,255,0.1); background: rgba(255,255,255,0.04);
  color: #F5F5F7; font-size: 15px; padding: 0 14px;
}
.listings-search:focus { outline: none; border-color: #3B82F6; }
.listings-list, .top-posters-list { display: flex; flex-direction: column; gap: 6px; }
.listing-row, .top-poster-row {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 4px; min-height: 44px; cursor: pointer;
  border-bottom: 1px solid rgba(255,255,255,0.06);
}
.listing-row:active, .top-poster-row:active { background: rgba(255,255,255,0.03); }
.listing-thumb {
  width: 44px; height: 44px; border-radius: 10px; object-fit: cover; flex-shrink: 0;
  background: rgba(255,255,255,0.06);
}
.listing-row-body { flex: 1; min-width: 0; }
.listing-row-name { font-size: 14px; font-weight: 650; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.listing-row-sub { font-size: 12px; color: #9A9AA4; margin-top: 1px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.listing-status-pill {
  font-size: 10.5px; font-weight: 750; letter-spacing: 0.04em;
  padding: 3px 8px; border-radius: 999px; flex-shrink: 0; white-space: nowrap;
}
.is-status-active { background: rgba(61,220,132,0.14); color: #3DDC84; }
.is-status-draft { background: rgba(255,255,255,0.08); color: #D8D8DE; }
.is-status-needs { background: rgba(59,130,246,0.16); color: #3B82F6; }
.is-status-unlinked { background: rgba(255,255,255,0.06); color: #7A7A84; }
.listing-chevron { color: #4A4A52; font-size: 18px; flex-shrink: 0; }
.top-poster-revenue { font-size: 14px; font-weight: 750; flex-shrink: 0; white-space: nowrap; }

/* ---------------- LISTING EDITOR ---------------- */
.editor-header { display: flex; align-items: center; gap: 12px; margin-bottom: 24px; }
.editor-header-thumb { width: 52px; height: 52px; border-radius: 12px; object-fit: cover; background: rgba(255,255,255,0.06); flex-shrink: 0; }
.editor-header-body { flex: 1; min-width: 0; }
.editor-header-name { font-size: 16px; font-weight: 750; text-transform: uppercase; letter-spacing: 0.01em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.editor-header-status { font-size: 12.5px; color: #9A9AA4; margin-top: 2px; }

.editor-section { border-bottom: 1px solid rgba(255,255,255,0.07); margin-bottom: 4px; }
.editor-section-toggle {
  width: 100%; min-height: 48px; display: flex; align-items: center; justify-content: space-between;
  background: none; border: none; color: #F5F5F7;
  font-size: 12px; font-weight: 750; letter-spacing: 0.08em; cursor: pointer; padding: 0 2px;
}
.editor-section-chevron { color: #6E6E78; transition: transform 0.2s ease; }
.editor-section.is-open .editor-section-chevron { transform: rotate(90deg); }
/* CSS-grid accordion (item 11: smooth open/close, no instant display
   flip) - the 0fr/1fr row trick animates real height without JS ever
   measuring scrollHeight; the inner wrapper clips content and carries
   the padding so it collapses to true zero, not just visually hidden. */
.editor-section-body { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 0.28s cubic-bezier(0.4, 0, 0.2, 1); }
.editor-section.is-open .editor-section-body { grid-template-rows: 1fr; }
.editor-section-body-inner { overflow: hidden; min-height: 0; padding: 4px 2px 20px; }

.field-label { display: block; font-size: 11.5px; font-weight: 700; color: #9A9AA4; letter-spacing: 0.03em; margin: 14px 0 6px; }
.field-label:first-child { margin-top: 0; }
.field-input {
  width: 100%; max-width: 100%; box-sizing: border-box;
  min-height: 44px; border-radius: 10px;
  border: 1px solid rgba(255,255,255,0.1); background: rgba(255,255,255,0.04);
  color: #F5F5F7; font-size: 15px; padding: 10px 12px;
}
.field-input:focus { outline: none; border-color: #3B82F6; }
.field-textarea { min-height: 140px; resize: vertical; line-height: 1.5; font-family: inherit; }
.field-counter { font-size: 11px; color: #6E6E78; text-align: right; margin-top: 4px; }
.field-static { min-height: 44px; display: flex; align-items: center; font-size: 14.5px; color: #D8D8DE; }

.editor-content-actions { display: flex; align-items: center; gap: 12px; margin-top: 16px; flex-wrap: wrap; }
.editor-generate-status { flex: 1; min-width: 0; font-size: 12.5px; color: #9A9AA4; }
.btn-small { min-height: 36px; padding: 0 14px; font-size: 13px; }

.editor-media-preview { width: 100%; border-radius: 14px; object-fit: cover; max-height: 320px; margin-bottom: 12px; background: rgba(255,255,255,0.04); transition: opacity 0.12s ease; }

/* Real card-based media manager (item 3, 2026-09-23 pass) - replaces
   the old small-square horizontal thumbnail strip as the PRIMARY
   editing interface. Each .editor-media-tile is now a full-width
   row card (handle + thumb + COVER/rank badge + "..." menu) stacked
   vertically, so order is legible at a glance without horizontal
   scrolling - the exact "cards with COVER/01/02 labels" shape asked
   for. The drag engine itself (_mediaDragState, hold-then-drag,
   pointer capture, FLIP reflow) is unchanged from the prior pass -
   only its axis flips from X to Y, see updateMediaDrag() in editor.js. */
.editor-media-manager { display: flex; flex-direction: column; gap: 8px; padding: 2px 2px 6px; touch-action: pan-y; }
.editor-media-tile {
  position: relative; display: flex; align-items: center; gap: 10px; width: 100%;
  border-radius: 12px; padding: 8px 10px;
  background: rgba(255,255,255,0.04); border: 2px solid transparent;
  transition: transform 0.12s ease, opacity 0.12s ease, border-color 0.12s ease, box-shadow 0.12s ease;
  touch-action: pan-y;
  /* Real iOS Safari bug (item 7): a hold on a plain <img> triggers the
     OS-level Save/Copy/Share callout and a native drag-ghost BEFORE any
     JS pointer handler runs, hijacking the custom hold-then-drag
     gesture below. These suppress both without disabling pointer
     events - the callout/native-drag are separate iOS behaviors from
     the CSS user-select/touch-action properties. */
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}
.editor-media-handle {
  flex-shrink: 0; width: 24px; text-align: center; font-size: 16px; line-height: 1;
  color: #6E6E78; letter-spacing: -1px; pointer-events: none;
}
.editor-media-thumb {
  flex-shrink: 0; width: 52px; height: 52px; border-radius: 8px; overflow: hidden; background: rgba(255,255,255,0.06);
}
.editor-media-thumb img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  -webkit-user-drag: none; -webkit-touch-callout: none; pointer-events: none;
}
.editor-media-rank-badge {
  font-size: 11.5px; font-weight: 750; letter-spacing: 0.04em; color: #9A9AA4; flex-shrink: 0;
}
.editor-media-rank-badge.is-cover { color: #3DDC84; }
.editor-media-tile.is-selected { border-color: #3B82F6; }
/* "card lifts slightly" (item 3 spec) - a subtle raise + shadow, not
   the old small-tile scale-up, matches a full-width row card better. */
.editor-media-tile.is-armed { transform: translateY(-2px); box-shadow: 0 6px 16px rgba(0,0,0,0.3); transition: transform 0.15s ease, box-shadow 0.15s ease; }
.editor-media-tile.is-dragging { transform: translateY(-2px) scale(1.015); opacity: 0.92; z-index: 5; box-shadow: 0 10px 26px rgba(0,0,0,0.45); touch-action: none; }
.editor-media-more-btn {
  flex-shrink: 0; margin-left: auto; width: 30px; height: 30px; border-radius: 999px;
  background: rgba(255,255,255,0.06); border: none; color: #D8D8DE; display: flex; align-items: center; justify-content: center;
  font-size: 15px; line-height: 1; cursor: pointer; padding: 0;
}
.editor-media-add-btn { width: 100%; margin-top: 2px; }

/* "+ Add Mockup" sheet (item 3) - reuses .file-card's established
   look as a real <button>, stacked vertically. */
#addMockupSheetBody { display: flex; flex-direction: column; gap: 8px; }
.addable-mockup-row { width: 100%; text-align: left; font: inherit; color: inherit; }
.addable-mockup-row .editor-media-thumb { width: 44px; height: 44px; }
.editor-media-context-menu {
  position: fixed; z-index: 40; min-width: 150px; border-radius: 12px; overflow: hidden;
  background: #1C1C20; border: 1px solid rgba(255,255,255,0.1); box-shadow: 0 10px 30px rgba(0,0,0,0.5);
}
.editor-media-context-item {
  display: block; width: 100%; text-align: left; min-height: 44px; padding: 0 16px;
  background: none; border: none; color: #F5F5F7; font-size: 14px; cursor: pointer;
  border-bottom: 1px solid rgba(255,255,255,0.06);
}
.editor-media-context-item:last-child { border-bottom: none; }
.editor-media-context-item.is-danger { color: #FF5E5E; }
.editor-media-context-overlay { position: fixed; inset: 0; z-index: 39; background: transparent; }

.editor-files-actions { display: flex; gap: 10px; margin-bottom: 12px; }
.editor-files-list { display: flex; flex-direction: column; gap: 8px; }
.file-card {
  display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: 12px;
  border: 1px solid rgba(255,255,255,0.08); background: rgba(255,255,255,0.03); cursor: pointer; min-height: 44px;
}
.file-card.is-selected { border-color: rgba(59,130,246,0.5); background: rgba(59,130,246,0.08); }
.file-card-check {
  width: 20px; height: 20px; border-radius: 6px; border: 1px solid rgba(255,255,255,0.18);
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
  font-size: 13px; color: #3B82F6; font-weight: 750;
}
.file-card.is-selected .file-card-check { border-color: #3B82F6; background: rgba(59,130,246,0.18); }
.file-card-title { font-size: 14px; font-weight: 650; }
.file-card-sub { font-size: 12px; color: #9A9AA4; margin-top: 1px; }
.file-card-size { font-size: 11.5px; color: #6E6E78; margin-top: 1px; }

.tag-editor { border-radius: 10px; border: 1px solid rgba(255,255,255,0.1); background: rgba(255,255,255,0.04); padding: 10px 10px 4px; }
.tag-chip-row { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 6px; }
.tag-chip {
  display: inline-flex; align-items: center; gap: 5px;
  background: rgba(255,255,255,0.08); border-radius: 999px; padding: 5px 6px 5px 11px;
  font-size: 12.5px; font-weight: 600;
}
.tag-chip-remove { background: none; border: none; color: #9A9AA4; font-size: 14px; cursor: pointer; line-height: 1; padding: 2px; }
.tag-input { width: 100%; border: none; background: none; color: #F5F5F7; font-size: 14px; min-height: 36px; padding: 0 4px 6px; }
.tag-input:focus { outline: none; }

.editor-sticky-footer {
  /* Real, reported regression fix: this used to sit at bottom:0 with a
     LOWER z-index than .bottom-nav (also bottom:0) - the nav bar
     rendered directly on top of it, making the Add/Update Etsy Draft
     button exist in the DOM but be completely invisible. Now anchored
     just above the real nav bar height, matching the same established
     pattern .create-sticky-footer already uses. */
  position: fixed; left: 0; right: 0; bottom: calc(56px + env(safe-area-inset-bottom)); z-index: 25;
  padding: 12px 18px;
  background: rgba(9,9,11,0.94);
  backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
  border-top: 1px solid rgba(255,255,255,0.08);
}
.sticky-btn { width: 100%; }
.sticky-review-btn { color: #F5C453; border-color: rgba(245,196,83,0.3); }
.sticky-progress-text, .sticky-partial-text, .sticky-success-text {
  font-size: 13px; text-align: center; padding: 6px 0; color: #D8D8DE;
}
.sticky-success, .sticky-partial { display: flex; flex-direction: column; gap: 8px; animation: statusFadeIn 260ms ease-out; }
.sticky-success-text { color: #3DDC84; font-weight: 650; }

/* Real Etsy submission status pill (item 1, 2026-09-23 pass) - the
   label text is always derived from the real record.submission.steps
   state (computeSubmitLabel(), editor.js), never a fabricated
   percentage. Fixed min-height so label-text length changes (e.g.
   "Creating Etsy draft..." -> "Uploading media - 4/6") never shift
   surrounding layout; the label itself crossfades rather than
   hard-swapping (see .is-fading, toggled in updateStatusPillLabel()). */
.etsy-status-pill {
  display: flex; align-items: center; justify-content: center; gap: 9px;
  min-height: 40px; border-radius: 999px;
  background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.08);
  padding: 0 16px; animation: statusFadeIn 200ms ease-out;
}
.etsy-status-spinner {
  width: 14px; height: 14px; border-radius: 999px; flex-shrink: 0;
  border: 2px solid rgba(255,255,255,0.16); border-top-color: #3B82F6;
  animation: analyticsRefreshSpin 0.7s linear infinite;
}
.etsy-status-label {
  font-size: 13px; font-weight: 600; color: #D8D8DE;
  transition: opacity 140ms ease;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 260px;
}
.etsy-status-label.is-fading { opacity: 0; }
@keyframes statusFadeIn { from { opacity: 0; transform: translateY(3px); } to { opacity: 1; transform: translateY(0); } }

/* Item 5 (2026-09-23 pass): brief highlight applied to the exact
   invalid field when "N items need attention" is tapped - a real,
   visible pulse rather than just a silent scroll/open. */
.field-needs-attention {
  animation: fieldAttentionPulse 1.6s ease-out;
  border-radius: 10px;
}
@keyframes fieldAttentionPulse {
  0% { box-shadow: 0 0 0 0 rgba(245,196,83,0.55); }
  25% { box-shadow: 0 0 0 6px rgba(245,196,83,0.22); }
  100% { box-shadow: 0 0 0 0 rgba(245,196,83,0); }
}

/* ---------------- ANALYTICS ---------------- */
.analytics-hero { margin: 6px 0 20px; }
.analytics-hero-value { font-size: 40px; font-weight: 750; letter-spacing: -0.02em; line-height: 1.05; }
.analytics-hero-label { font-size: 12.5px; color: #9A9AA4; margin-top: 2px; }
.analytics-secondary-row { display: flex; gap: 10px; margin-bottom: 12px; flex-wrap: wrap; }
.analytics-secondary-item { flex: 1; min-width: 64px; }
.analytics-secondary-value { font-size: 19px; font-weight: 750; }
.analytics-secondary-label { font-size: 11.5px; color: #9A9AA4; margin-top: 2px; }

.poster-perf-header { display: flex; align-items: center; gap: 12px; margin-bottom: 18px; }
.poster-perf-status { font-size: 12.5px; font-weight: 700; letter-spacing: 0.05em; color: #9A9AA4; margin: 6px 0 18px; }
.poster-perf-open-btn { width: 100%; text-align: center; text-decoration: none; display: flex; align-items: center; justify-content: center; }

/* ---------------- PROCESSING ---------------- */
.processing-card { text-align: center; padding-top: 12px; }
.processing-name { font-size: 15px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.01em; margin-bottom: 18px; }
.processing-percent { font-size: 44px; font-weight: 750; letter-spacing: -0.02em; }
.processing-stage { font-size: 13px; color: #9A9AA4; margin: 8px 0 26px; }
.processing-checklist { display: flex; flex-direction: column; gap: 12px; text-align: left; max-width: 320px; margin: 0 auto; }
.processing-step { display: flex; align-items: center; gap: 10px; font-size: 14px; color: #6E6E78; transition: color 0.2s ease; }
.processing-step.is-active { color: #F5F5F7; font-weight: 650; }
.processing-step.is-done { color: #3DDC84; }
.processing-step.is-failed { color: #FF5E5E; }
.processing-step-icon { width: 18px; text-align: center; font-size: 13px; display: flex; align-items: center; justify-content: center; }
.processing-step.is-active .processing-step-icon { position: relative; }
.processing-step.is-active .processing-step-dot {
  width: 6px; height: 6px; border-radius: 999px; background: #3B82F6; animation: processingPulse 1.1s ease-in-out infinite;
}
@keyframes processingPulse { 0%, 100% { opacity: 0.35; transform: scale(0.85); } 50% { opacity: 1; transform: scale(1.15); } }
.processing-done-text, .processing-failed-text { font-size: 14px; margin: 28px 0 14px; }
.processing-failed-text { color: #FF5E5E; }
.processing-review-btn { width: 100%; max-width: 320px; }
#processingResult { text-align: center; }

@media (min-width: 480px) {
  .app-main { padding-left: 20px; padding-right: 20px; }
}

/* ================================================================
   SPLASH - item 12 replacement: an extremely restrained native-feeling
   launch screen. Black screen, centered real Hermes glyph + wordmark,
   nothing else - no blob/planet/tagline/decorative composition. Real
   sequence: 0-250ms pure black, 250-600ms glyph+wordmark fade in and
   rise ~5px, hold to 1000ms, then crossfade into Home starting at
   1000ms (app.js's runSplash() times the JS-driven dissolve/removal to
   match).
   ================================================================ */
.splash-screen {
  position: fixed; inset: 0; z-index: 200;
  background: #000;
  display: flex; align-items: center; justify-content: center;
  overflow: hidden;
  transition: opacity 0.4s ease;
}
.splash-screen.is-dissolving { opacity: 0; pointer-events: none; }
.splash-content {
  display: flex; flex-direction: column; align-items: center;
}
/* Real timing (items 15/16) - a restrained "luxury software boot
   sequence", not a loading indicator: no spin, no bounce, no progress
   value, no color but white-on-black. The symbol is the real
   hermes_glyph.png asset (larger than the wordmark below it); the
   glow is achieved purely via filter: brightness()+drop-shadow(),
   both animatable together without interpolation glitches, kept
   deliberately subtle (low blur radius, low alpha). */
.splash-mark {
  width: 88px; height: 88px; object-fit: contain;
  opacity: 0;
  animation: splashSymbolReveal 950ms ease-out 150ms forwards;
}
@keyframes splashSymbolReveal {
  0%   { opacity: 0;    filter: brightness(0.5) drop-shadow(0 0 0 rgba(255,255,255,0)); }
  47%  { opacity: 0.55; filter: brightness(0.75) drop-shadow(0 0 0 rgba(255,255,255,0)); }
  100% { opacity: 1;    filter: brightness(1) drop-shadow(0 0 14px rgba(255,255,255,0.3)); }
}
.splash-wordmark {
  margin-top: 16px; height: 13px; width: auto; object-fit: contain;
  opacity: 0;
  animation: splashWordmarkReveal 450ms ease-out 800ms forwards;
}
@keyframes splashWordmarkReveal {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .splash-mark, .splash-wordmark { animation: none !important; opacity: 1 !important; filter: none !important; }
}
.splash-screen.is-reduced-motion .splash-mark,
.splash-screen.is-reduced-motion .splash-wordmark {
  animation: none !important; opacity: 1 !important; filter: none !important;
}

/* ================================================================
   HOME
   ================================================================ */
/* Real, shared Hermes brand mark (item 14) - the exact same two real
   assets (glyph + wordmark PNGs) used by the splash screen, never a
   typed-text approximation. "One brand system, one source of truth"
   across Splash/Header/App icon (item 16). */
.hermes-brand { display: inline-flex; align-items: center; gap: 7px; }
.app-header-glyph { width: 16px; height: 16px; display: block; }
.hermes-brand-wordmark { height: 10px; width: auto; display: block; }
.home-greeting-block { margin: 4px 0 20px; }
.home-greeting { font-size: 22px; font-weight: 750; letter-spacing: -0.01em; line-height: 1.25; }
.home-tagline { font-size: 13px; color: #9A9AA4; margin-top: 6px; }

/* Item 1: one compact Etsy performance module replaces the old 2x2
   grid of four near-identical stat cards (the real complaint: Revenue
   and Est. Profit read as duplicated primary cards). Revenue is now
   the single primary figure; Orders/Listings/Est. Profit are a
   visually smaller secondary row underneath the real chart - a real
   hierarchy, not four same-weight rectangles. */
.home-perf-skeleton {
  height: 220px; border-radius: 16px; margin-bottom: 18px;
  background: linear-gradient(90deg, rgba(255,255,255,0.04) 25%, rgba(255,255,255,0.08) 37%, rgba(255,255,255,0.04) 63%);
  background-size: 400% 100%; animation: hermesShimmer 1.4s ease infinite;
}
.home-perf-card {
  background: rgba(255,255,255,0.035); border: 1px solid rgba(255,255,255,0.07);
  border-radius: 16px; padding: 16px 16px 14px; margin-bottom: 18px;
}
.home-perf-range-chips { margin-bottom: 12px; }
.home-perf-primary-value { font-size: 34px; font-weight: 750; letter-spacing: -0.02em; line-height: 1.05; transition: opacity 0.15s ease; }
.home-perf-primary-label { font-size: 12.5px; color: #9A9AA4; margin-top: 2px; }
.home-perf-chart-block.analytics-chart-block { margin: 12px 0 16px; }
.home-chart { height: 64px; }
.home-perf-secondary-row { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px; padding-top: 14px; border-top: 1px solid rgba(255,255,255,0.06); }
.home-perf-secondary-item { min-width: 0; }
.home-perf-secondary-icon { display: block; width: 14px; height: 14px; color: #7A7A84; margin-bottom: 6px; }
.home-perf-secondary-icon svg { width: 100%; height: 100%; }
.home-perf-secondary-value { font-size: 15px; font-weight: 700; letter-spacing: -0.01em; }
.home-perf-secondary-label { font-size: 10.5px; color: #9A9AA4; margin-top: 1px; }
/* Est. Profit stays visually secondary even within the secondary row -
   a real, deliberate one-notch de-emphasis vs. Orders/Listings, since
   it's a derived estimate rather than a hard Etsy number. */
.home-perf-secondary-item.is-profit .home-perf-secondary-value { color: #C4C4CC; font-weight: 650; }
.home-perf-secondary-item.is-profit .home-perf-secondary-icon { color: #6E6E78; }

.home-create-cta {
  width: 100%; min-height: 50px; border-radius: 14px;
  background: #F5F5F7; color: #09090B; border: none;
  font-size: 14.5px; font-weight: 750;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  margin-bottom: 14px; cursor: pointer;
}
.home-create-cta-icon { font-size: 17px; line-height: 1; }
.home-create-cta-arrow { width: 16px; height: 16px; }

.home-active-job-card {
  display: block; width: 100%; text-align: left; background: rgba(59,130,246,0.10);
  border: 1px solid rgba(59,130,246,0.25); border-radius: 12px; padding: 11px 14px;
  margin-bottom: 20px; cursor: pointer; font-family: inherit; -webkit-tap-highlight-color: transparent;
}
.home-active-job-title-row { display: flex; align-items: center; gap: 7px; margin-bottom: 5px; }
.home-active-job-dot { width: 7px; height: 7px; border-radius: 999px; background: #3B82F6; flex-shrink: 0; animation: processingPulse 1.1s ease-in-out infinite; }
/* flex:1 + min-width:0 is required for the ellipsis below to actually
   engage - without it a flex item won't shrink past its content size
   and long text pushes the whole card wider than the viewport. */
.home-active-job-title { flex: 1; min-width: 0; font-size: 13px; font-weight: 650; color: #F5F5F7; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.home-active-job-stage-row { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; margin-bottom: 6px; }
.home-active-job-stage { flex: 1; min-width: 0; font-size: 12px; color: #9A9AA4; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.home-active-job-percent { font-size: 12px; font-weight: 700; color: #3B82F6; flex-shrink: 0; }

.home-tools-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 10px; }
.home-tool-card {
  min-height: 68px; border-radius: 14px;
  background: rgba(255,255,255,0.035); border: 1px solid rgba(255,255,255,0.07);
  display: flex; flex-direction: column; align-items: flex-start; justify-content: center; gap: 8px;
  padding: 0 16px; font-size: 13.5px; font-weight: 650; color: #F5F5F7; cursor: pointer;
}
.home-tool-icon { width: 18px; height: 18px; color: #9A9AA4; }
.home-tool-icon svg { width: 100%; height: 100%; }

/* ================================================================
   CREATE
   ================================================================ */
#view-create { padding-bottom: 90px; }
#view-listing-editor { padding-bottom: 100px; }
.view-header-centered { text-align: center; font-size: 17px; font-weight: 750; margin: 2px 0 16px; }
.create-type-tabs { margin-bottom: 16px; }
.create-drop-card {
  padding: 34px 20px; border-radius: 18px;
  border: 1.5px dashed rgba(255,255,255,0.14); text-align: center;
}
.create-drop-icon { width: 40px; height: 40px; margin: 0 auto 16px; color: #6E6E78; transition: color 0.18s ease; }
.create-drop-icon svg { width: 100%; height: 100%; }
.create-drop-icon svg circle { transition: fill 0.18s ease; }
/* Item 9: the custom poster-outline + upload-arrow glyph animates
   toward Hermes blue on the real interactions mobile actually has for
   "selecting a file" (there's no native drag-and-drop on a phone) -
   an active tap/press on the drop card, or keyboard/VoiceOver focus
   landing on its file-picker control. */
.create-drop-card:active .create-drop-icon,
.create-drop-card:focus-within .create-drop-icon,
.create-drop-card.is-drag-active .create-drop-icon { color: #3B82F6; }
.create-drop-title { font-size: 15px; font-weight: 700; margin: 0 0 4px; }
.create-drop-body { font-size: 12.5px; color: #6E6E78; margin: 0 0 20px; }
.create-picker-row { display: flex; gap: 8px; justify-content: center; }
.create-picker-btn { min-width: 160px; text-align: center; display: flex; align-items: center; justify-content: center; cursor: pointer; }
.create-picker-row-secondary { margin-top: 14px; gap: 18px; }
.create-picker-link { font-size: 13px; font-weight: 650; color: #3B82F6; cursor: pointer; }

.create-preview-card { margin-top: 14px; text-align: center; }
.create-preview-img { width: 100%; max-height: 260px; object-fit: cover; border-radius: 16px; margin-bottom: 8px; }
.create-preview-name { font-size: 13px; color: #9A9AA4; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.create-capability-list { margin-top: 18px; display: flex; flex-direction: column; }
.create-capability-row {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 2px; border-bottom: 1px solid rgba(255,255,255,0.07); cursor: pointer;
}
.create-capability-row:last-child { border-bottom: none; }
.create-capability-icon { width: 19px; height: 19px; color: #7A7A84; flex-shrink: 0; }
.create-capability-icon svg { width: 100%; height: 100%; }
.create-capability-text { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.create-capability-title { font-size: 14px; font-weight: 650; }
.create-capability-sub { font-size: 12px; color: #9A9AA4; margin-top: 1px; }

.ios-toggle { position: relative; display: inline-block; flex-shrink: 0; }
.ios-toggle input { opacity: 0; width: 0; height: 0; position: absolute; }
.ios-toggle-track {
  display: block; width: 44px; height: 26px; border-radius: 999px;
  background: rgba(255,255,255,0.14); transition: background-color 0.15s ease; position: relative;
}
.ios-toggle-thumb {
  position: absolute; top: 2px; left: 2px; width: 22px; height: 22px; border-radius: 999px;
  background: #fff; transition: transform 0.15s ease; box-shadow: 0 1px 3px rgba(0,0,0,0.3);
}
.ios-toggle input:checked + .ios-toggle-track { background: #3B82F6; }
.ios-toggle input:checked + .ios-toggle-track .ios-toggle-thumb { transform: translateX(18px); }

.create-uploading-card { margin-top: 40px; text-align: center; }
.create-uploading-text { font-size: 14px; color: #9A9AA4; }

.create-sticky-footer {
  position: fixed; left: 0; right: 0; bottom: calc(56px + env(safe-area-inset-bottom));
  z-index: 25; padding: 12px 18px;
  background: rgba(9,9,11,0.94);
  backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
  border-top: 1px solid rgba(255,255,255,0.08);
}
.create-start-btn { width: 100%; margin-bottom: 8px; display: flex; align-items: center; justify-content: center; gap: 6px; }
.create-cancel-btn { width: 100%; }
#processingBackgroundBtn { width: 100%; }

.processing-poster-preview {
  width: 78%; max-width: 240px; margin: 4px auto 18px; display: block;
  border-radius: 12px; box-shadow: 0 18px 40px -12px rgba(0,0,0,0.6);
  transform: perspective(700px) rotateX(2deg);
}
.processing-label { font-size: 13px; color: #9A9AA4; margin-bottom: 4px; }
.processing-done-title { font-size: 17px; font-weight: 750; margin: 20px 0 14px; }
.processing-done-actions { display: flex; flex-direction: column; gap: 8px; max-width: 280px; margin: 0 auto; }
.processing-failed-title { font-size: 15px; font-weight: 700; color: #FF5E5E; margin: 20px 0 8px; }
.processing-add-another-btn { width: 100%; max-width: 280px; margin: 18px auto 0; display: block; }

/* ================================================================
   LIBRARY
   ================================================================ */
.library-header-row { display: flex; align-items: center; justify-content: space-between; margin: 2px 0 16px; }
.library-title { font-size: 24px; font-weight: 750; letter-spacing: -0.01em; margin: 0; }
.library-header-actions { display: flex; align-items: center; gap: 16px; }
.icon-only-btn { background: none; border: none; color: #F5F5F7; width: 24px; height: 24px; cursor: pointer; }
.icon-only-btn svg { width: 100%; height: 100%; }
.text-link-btn { background: none; border: none; color: #3B82F6; font-size: 14px; font-weight: 650; cursor: pointer; padding: 0; }

.library-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-top: 4px; max-width: 100%; overflow-x: hidden; }
.library-grid-skeleton { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
/* min-width:0 is required on a grid item for its own nowrap/ellipsis
   children to actually shrink - without it, a long unbroken card name
   can force the 1fr column (and the whole grid) wider than the
   viewport. */
.library-card { cursor: pointer; min-width: 0; }
.library-card-thumb {
  width: 100%; aspect-ratio: 3/4; object-fit: cover; border-radius: 12px;
  background: rgba(255,255,255,0.05); margin-bottom: 8px;
}
/* Real poster artwork must show the whole image, never cropped - a
   mockup/listing photo (composited scene) still crops fine with
   object-fit: cover, but the raw poster IS the product. */
.library-card.is-poster .library-card-thumb { object-fit: contain; background: #000; }
.library-card-name { font-size: 13px; font-weight: 650; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.library-card-meta { font-size: 11.5px; color: #6E6E78; margin-top: 1px; }
/* Item 9: Mockups is a real image-first visual asset manager - no
   name/meta text renders for a mockup card at all (see library.js),
   so its thumbnail loses the bottom margin that made room for that
   text on Posters/Listings cards. Posters (item 8) are completely
   unaffected - this rule only ever matches .is-mockup. */
.library-card.is-mockup .library-card-thumb { margin-bottom: 0; }

.library-detail-preview { width: 100%; max-height: 340px; object-fit: cover; border-radius: 16px; margin-bottom: 16px; }
.library-detail-title { font-size: 19px; font-weight: 750; margin: 0 0 4px; }
.library-detail-meta { font-size: 13px; color: #9A9AA4; margin-bottom: 18px; }
.library-detail-actions { display: flex; gap: 8px; margin-bottom: 22px; }
.library-detail-action-btn { flex: 1; }
.library-detail-row {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 2px; border-bottom: 1px solid rgba(255,255,255,0.07);
  font-size: 14px; font-weight: 600; cursor: pointer;
}
.library-detail-row-chevron { color: #4A4A52; }
.library-detail-row-value { color: #9A9AA4; font-weight: 500; }

/* ================================================================
   ANALYTICS (chart + redesigned metrics)
   ================================================================ */
.view-header-plain { font-size: 24px; font-weight: 750; letter-spacing: -0.01em; margin: 2px 0 16px; }
.analytics-title-row { display: flex; align-items: center; justify-content: space-between; }
.analytics-title-row .view-header-plain { margin-bottom: 16px; }
/* Item 6 (2026-09-23 pass): the old 24px, background-less icon button
   was genuinely easy to miss (real reported bug) - a bordered
   circular control at a real touch-target size makes it read as an
   intentional control, not a decorative glyph, while staying
   restrained (no label text, no heavy fill). */
.analytics-refresh-btn {
  width: 36px; height: 36px; border-radius: 999px;
  background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.1);
  display: flex; align-items: center; justify-content: center;
  transition: opacity 0.15s ease, background 0.15s ease;
}
.analytics-refresh-btn svg { width: 17px; height: 17px; }
.analytics-refresh-btn:active { background: rgba(255,255,255,0.12); }
.analytics-refresh-btn:disabled { opacity: 0.5; cursor: default; }
.analytics-refresh-btn.is-spinning svg { animation: analyticsRefreshSpin 0.7s linear infinite; }
@keyframes analyticsRefreshSpin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
.analytics-hero-card { margin-bottom: 4px; }
.analytics-hero-label-row { display: flex; align-items: center; gap: 8px; margin-top: 2px; }
.analytics-hero-delta { font-size: 13px; font-weight: 700; color: #3DDC84; }
.analytics-chart-block { position: relative; margin: 14px 0 20px; }
.analytics-chart { display: block; width: 100%; touch-action: pan-y; }
.analytics-chart-tooltip {
  position: absolute; top: -6px;
  background: rgba(20,20,23,0.95); border: 1px solid rgba(255,255,255,0.1);
  border-radius: 8px; padding: 5px 9px; color: #F5F5F7; white-space: nowrap; pointer-events: none;
  text-align: center; transition: opacity 0.12s ease;
}
.analytics-chart-tooltip-date { font-size: 9.5px; font-weight: 700; letter-spacing: 0.04em; color: #9A9AA4; }
.analytics-chart-tooltip-value { font-size: 13px; font-weight: 750; margin-top: 1px; }
.analytics-metrics-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px 8px; margin: 4px 0 12px; }
.analytics-metric-cell { text-align: left; }
.analytics-metric-value { font-size: 17px; font-weight: 750; }
.analytics-metric-label { font-size: 11px; color: #9A9AA4; margin-top: 1px; }

/* ---------------- misc shared status colors ---------------- */
.is-status-other { background: rgba(255,255,255,0.06); color: #7A7A84; }

/* Subtle fade for an image's FIRST successful load only (setStableImageSrc
   in app.js adds this class once per element, never again on later swaps -
   that's what keeps polling/refresh from re-triggering it). */
@keyframes imgFadeIn { from { opacity: 0; } to { opacity: 1; } }
.img-fade-in { animation: imgFadeIn 220ms ease-out; }
