/*
 * Profile page — ported 1:1 from animeoshi.com/profile/{username} (CDP-measured
 * + AO CSS-module values resolved). AO's tokens differ from this repo's
 * tokens.css, so the real values are pinned in a scoped token map on .apf-page
 * (per CLAUDE.md § Match the LIVE site). Section cards use translucent-pebble
 * surfaces on the charcoal page; rating stars are ivory (NOT gold); MyTopOshi
 * score + streak bars are sundrop.
 *
 * The hero's floating character avatar (AO ProfileCharacterAvatar) is rendered
 * from the public avatar endpoint's sprite layers — see .apf-char-avatar below.
 */
/* Token map — also applied to the CSR-built modal roots, which are appended to
   document.body (OUTSIDE .apf-page), so without this their var() references
   would not resolve and the modals would render unstyled. */
.apf-page,
.apf-modal,
.apf-badges-modal,
.apf-pick-overlay,
.aoca-overlay {
  /* ── AO token map (resolved literals) ──────────────────────── */
  --charcoal: hsl(271 45% 9%);
  --pebble: rgb(237, 237, 237);
  --ivory: #fff;
  --sundrop: hsl(68 100% 50%);
  --surface: rgba(237, 237, 237, 0.05);
  --surface-10: rgba(237, 237, 237, 0.1);
  --border: rgba(237, 237, 237, 0.2);
  --border-light: rgba(237, 237, 237, 0.1);
  --text-primary: rgb(237, 237, 237);
  --text-secondary: rgba(237, 237, 237, 0.8);
  --text-tertiary: rgba(237, 237, 237, 0.5);
  --accent: hsl(68 100% 50%);
  --accent-light: hsl(68 100% 50% / 0.3);
  /* AO RankBanner lime — a distinct, more-muted lime than --accent/--sundrop. */
  --rank-lime: #c5e500;
  /* AO --color-danger = --cherry-top = hsl(0 85% 60%) → rgb(240,66,66). (Not
     the #ff6b6b generic red this map previously carried, which is lighter.) */
  --danger: hsl(0 85% 60%);
  --btn-material: rgba(237, 237, 237, 0.15);
  --btn-light: rgba(237, 237, 237, 0.05);
  --montra: var(--font-montra, 'montra', sans-serif);
  --bricolage: var(--font-bricolage, 'Bricolage Grotesque', sans-serif);
}
.apf-page {
  color: var(--text-primary);
  font-family: var(--bricolage);
  /* Header offset comes from the shared .page-content wrapper. The 32px top pad
     (AO --spacing-xl) matches the episode page's hero-inner top padding, so the
     breadcrumb lands at the same offset below the header (top≈129, not 97). */
  padding-block: 32px;
}
.apf-container {
  width: 100%;
  /* AO's global content wrapper (main.container) is max-width 1940px; the gutter
     below already equals AO's --page-gutter = clamp(--spacing-md, 5vw, --spacing-10xl). */
  max-width: 1940px;
  margin: 0 auto;
  padding-inline: clamp(16px, 5vw, 104px);
  box-sizing: border-box;
}

/* ── 2-column grid (7fr main / 3fr sidebar) ──────────────────── */
.apf-grid {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 3fr);
  gap: 24px;
  align-items: start;
}
.apf-col-main {
  display: flex;
  flex-direction: column;
  gap: 32px;
  min-width: 0;
}
.apf-col-side {
  display: flex;
  flex-direction: column;
  gap: 32px;
  min-width: 0;
  position: sticky;
  top: 112px; /* header 96px + 16px */
}
@media (max-width: 1024px) {
  .apf-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 320px); gap: 16px; }
  .apf-col-main, .apf-col-side { gap: 24px; }
  .apf-col-side { position: static; }
}
@media (max-width: 768px) {
  .apf-grid { grid-template-columns: minmax(0, 1fr); gap: 16px; }
  .apf-col-main, .apf-col-side { gap: 16px; }
}

/* ── Shared card + header + title ─────────────────────────────── */
.apf-card {
  background: var(--surface);
  border-radius: 12px;
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.apf-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.apf-card-title {
  margin: 0;
  font-family: var(--montra);
  font-size: 18px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-primary);
  flex-shrink: 0;
}
.apf-view-all,
.apf-view-more {
  background: none;
  border: none;
  padding: 0;
  color: var(--text-secondary);
  font-family: var(--bricolage);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}
.apf-view-more { margin-left: auto; }
.apf-view-all:hover,
.apf-view-more:hover { color: var(--text-primary); text-decoration: underline; }
.apf-view-all-caret { display: inline-flex; align-items: center; gap: 2px; text-decoration: none; }
.apf-view-all-caret:hover { text-decoration: none; }
.apf-view-all-caret svg { flex-shrink: 0; }

/* Section empty states (AO renders muted copy, e.g. "No activity yet"). */
/* AO empty states (RecentActivity/CurrentlyWatching .emptyState): CENTERED,
   --spacing-xl --spacing-md padding, --color-text-tertiary, 14px. */
.apf-empty {
  margin: 0;
  padding: 32px 16px;
  text-align: center;
  color: var(--text-tertiary);
  font-size: 14px;
}
/* Badges uses the same look with tighter padding (--spacing-md 0). */
.apf-empty-badges { padding: 16px 0; }

/* ── Hero ─────────────────────────────────────────────────────── */
.apf-hero {
  position: relative;
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
  /* AO's profile hero uses the /assets/profile/hero.svg banner (object-fit:cover),
     not a gradient. Vendored to src/assets/profile-hero.svg → ships in the same
     _assets/<version>/ dir as this file, so the relative url() resolves. */
  background: var(--surface) url(profile-hero.svg) center / cover no-repeat;
}
/* Bright-lime branded top edge (AO RankBanner `rankBannerEmpty`, #c5e500, 30px).
   Sits flush above the hero body; the hero's overflow:hidden + 12px radius clip
   its top corners. */
.apf-hero-rank {
  height: 30px;
  background: var(--rank-lime);
}
.apf-hero-body {
  position: relative; /* positioning context for the floating character avatar */
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 24px;
  align-items: center;
  padding: 24px;
}
/* Reserve the right gutter only when the character avatar is present (AO's
   heroBody padding-right:180px), so a fetch-less hero keeps symmetric padding. */
.apf-hero-body:has(.apf-char-avatar) { padding-right: 180px; }

/* ── Floating character avatar (AO ProfileCharacterAvatar) ─────────
   Bleeds into the hero's bottom-right corner (clipped by .apf-hero's
   overflow:hidden + radius, exactly like AO's heroCard). */
.apf-char-avatar {
  position: absolute;
  right: -20px;
  bottom: -12px;
  z-index: 2;
  display: flex;
  align-items: flex-end;
  justify-content: flex-end;
  transform: scale(1.3);
  transform-origin: bottom right;
  pointer-events: none;
}
/* AO characterAvatarColumn.clickable — owner-only (added by the CSR), which is
   also what re-enables pointer events on the otherwise inert sprite stack. */
.apf-char-avatar-clickable {
  pointer-events: auto;
  cursor: pointer;
}
.apf-char-avatar-clickable:focus-visible { outline: 2px solid var(--pebble); outline-offset: 2px; }
.apf-char-avatar-stack {
  position: relative;
  width: 140px;
  height: 180px;
}
.apf-char-avatar-layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  user-select: none;
}
/* AO .avatarWrapper — 96px circle, overflow hidden; .clickable only for the
   owner, whose hover reveals the camera overlay (AO .avatarOverlay). */
.apf-avatar-wrap {
  position: relative;
  width: 96px;
  height: 96px;
  border-radius: 50%;
  overflow: hidden;
  flex: 0 0 auto;
}
.apf-avatar-clickable { cursor: pointer; }
.apf-avatar-clickable:focus-visible { outline: 2px solid var(--pebble); outline-offset: 2px; }
.apf-avatar-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.6);   /* AO --color-overlay-dark-60 */
  opacity: 0;
  transition: opacity 0.2s ease;
  pointer-events: none;
}
.apf-avatar-clickable:hover .apf-avatar-overlay,
.apf-avatar-clickable:focus-visible .apf-avatar-overlay { opacity: 1; }
.apf-avatar {
  width: 96px;
  height: 96px;
  border-radius: 50%;
  object-fit: cover;
  flex: 0 0 auto;
}
/* AO infoColumn: a flex column with a 5px (--spacing-xs) gap and ZERO margins on
   the children — measured live (name 33 → bio +5 → follow +5 → actions +5+8). */
.apf-hero-main {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 5px;
}
.apf-name-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.apf-name {
  margin: 0;
  font-family: var(--montra);
  font-size: 30px;
  font-weight: 500;
  line-height: 1.1;
  color: var(--text-primary);
  max-width: 16ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.apf-verified {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--sundrop);
  color: var(--charcoal);
  font-size: 12px;
  font-weight: 700;
}
.apf-points {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: var(--bricolage);
  font-size: 16px;
  font-weight: 600;
  color: var(--text-primary);
}
.apf-points-star { color: #ffd54a; font-size: 16px; line-height: 1; }
.apf-bio {
  margin: 0; /* AO .description — spacing comes from the infoColumn gap */
  font-size: 16px;
  line-height: 1.4;
  color: var(--text-secondary);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.apf-follow-counts {
  margin: 0; /* AO .followLine */
  font-size: 14px;
  line-height: 1.6;
  color: var(--text-secondary);
  display: flex;
  align-items: center;
  gap: 5px;
  flex-wrap: wrap;
}
.apf-count-btn {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
}
.apf-count-btn strong { color: var(--text-primary); font-weight: 600; }
.apf-count-btn:hover { opacity: 0.8; text-decoration: underline; }
.apf-dot { opacity: 0.6; } /* AO .followLineDot */
/* "Followed by @user +N" mutuals line (AO mutualButton). */
.apf-mutual-btn { background: none; border: none; padding: 0; font: inherit; color: inherit; cursor: pointer; }
.apf-mutual-btn:hover { opacity: 0.8; text-decoration: underline; }
.apf-mutual-handle { color: var(--text-primary); font-weight: 600; }
.apf-mutual-more { color: var(--text-secondary); }
.apf-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px; /* AO .actionsRow margin-top --spacing-sm (on top of the 5px gap) */
  flex-wrap: wrap;
}
.apf-btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 5px 10px;
  border-radius: 9999px;
  border: 1px solid var(--border);
  background-color: var(--btn-material);
  color: var(--text-primary);
  font-family: var(--bricolage);
  font-size: 14px;
  font-weight: 600;
  line-height: 1.2;
  cursor: pointer;
}
.apf-btn-ic { width: 14px; height: 14px; flex-shrink: 0; }
/* AO .pillButton transitions + hover/active/disabled (hover & active are
   :not(:disabled)-gated there). --color-button-text = --ivory. */
.apf-btn { transition: background-color 0.2s ease, color 0.2s ease, transform 0.15s ease; }
.apf-btn:hover:not(:disabled) { background-color: var(--btn-light); color: var(--ivory); }
.apf-btn:active:not(:disabled) { transform: scale(0.97); }
.apf-btn:disabled { opacity: 0.6; cursor: not-allowed; }
/* Icon-only owner pill (AO heroIconButton) — symmetric padding, no label. */
.apf-btn-icon { padding-left: 12px; padding-right: 12px; }

/* ≤1024 the hero restructures exactly like AO's heroBody media block: the round
   avatar spans rows 1–2 top-aligned, name/bio take column 2, and the follow line
   + actions go full-width below. Keeping the hero body as short as AO's is what
   makes the character avatar (anchored to the body's bottom) bleed the same way
   up over the lime rank banner. Must come after the base hero rules — the resets
   below have equal specificity and would otherwise lose to them. */
@media (max-width: 1024px) {
  .apf-hero-body {
    column-gap: 16px;
    row-gap: 8px;
    padding: 16px;
    /* Reserve matches the desktop bleed — AO has no mobile override for the
       character avatar. */
    padding-right: 180px;
    align-items: start;
  }
  .apf-hero-body:has(.apf-char-avatar) { padding-right: 180px; }
  /* min-width pins the auto column: as a direct grid item the img would
     otherwise shrink to fit the full-width rows below it. */
  .apf-avatar-wrap { grid-column: 1; grid-row: 1 / span 2; align-self: start; min-width: 96px; }
  .apf-hero-main { display: contents; }
  .apf-name-row { grid-column: 2; grid-row: 1; align-self: end; }
  .apf-bio { grid-column: 2; grid-row: 2; align-self: start; margin: 0; }
  .apf-follow-counts { grid-column: 1 / -1; grid-row: 3; margin: 0; }
  .apf-actions { grid-column: 1 / -1; grid-row: 4; margin-top: 5px; } /* AO --spacing-xs */
}
@media (max-width: 768px) {
  /* AO drops the username to --font-size-2xl / 12ch here. */
  .apf-name { font-size: 24px; max-width: 12ch; }
}
@media (max-width: 480px) {
  /* AO shrinks the bio to --font-size-sm only at ≤480, not at 768. */
  .apf-bio { font-size: 14px; }
}
.apf-btn-share .apf-btn-ic { width: 16px; height: 16px; }
/* More menu dropdown (block/unblock), built by the CSR.
   FIXED-positioned (coords set by the CSR from the button rect) so it escapes
   the hero's `overflow: hidden` — mirrors AO ProfileMoreMenu (position: fixed;
   z-index: 1000). An absolute dropdown would be clipped by the hero card. */
/* AO .container / .menuButton — a bare icon trigger (no pill), 24px dots. */
.apf-more-wrap { position: relative; display: inline-flex; z-index: 200; }
.apf-more-btn {
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  line-height: 0;
  cursor: pointer;
  color: var(--text-primary);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: opacity 0.2s ease, transform 0.1s ease;
}
.apf-more-btn:hover:not(:disabled) { opacity: 0.7; }
.apf-more-btn:active:not(:disabled) { transform: scale(0.95); }
.apf-more-btn:disabled { opacity: 0.5; cursor: not-allowed; }
/* AO .dropdown: --radius-md 8px, --color-surface fill, 180px min-width,
   overflow hidden (so the options' square corners are clipped, hence no
   per-item radius or padding on the container) + the fade-in. */
.apf-more-menu {
  position: fixed;
  z-index: 1000;
  min-width: 180px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); /* --color-overlay-dark-15 */
  overflow: hidden;
  animation: apf-more-fade-in 0.15s ease-out;
}
@keyframes apf-more-fade-in {
  from { opacity: 0; transform: translateY(-8px); }
  to { opacity: 1; transform: translateY(0); }
}
.apf-more-menu[hidden] { display: none; }
/* AO .option — opaque --color-bg fill, 8/16 padding, 14px/500, and a "hover"
   that is the same fill (AO's hover is a no-op; kept 1:1). */
.apf-more-item {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 8px 16px;
  border: none;
  background: var(--charcoal);
  color: var(--text-primary);
  font-family: var(--bricolage);
  font-size: 14px;
  font-weight: 500;
  text-align: left;
  cursor: pointer;
  transition: background 0.2s ease;
}
.apf-more-item svg { flex-shrink: 0; }
.apf-more-item:hover:not(:disabled) { background: var(--charcoal); }
.apf-more-item:disabled { opacity: 0.5; cursor: not-allowed; }
.apf-more-item.apf-danger { color: var(--danger); }
.apf-more-item.apf-danger:hover:not(:disabled) { background: rgba(239, 68, 68, 0.1); }
/* Followed state — AO PublicProfileActions `.followActive`:
     background --color-button (= --pebble, the off-white; NOT sundrop —
     --color-button differs between the two repos, see CLAUDE.md),
     color --color-button-text-primary (= --charcoal), transparent border,
     and a hover that only drops opacity. */
.apf-btn-follow.apf-following {
  background-color: var(--pebble);
  border-color: transparent;
  color: var(--charcoal);
}
.apf-btn-follow.apf-following:hover:not(:disabled) {
  background-color: var(--pebble);
  color: var(--charcoal);
  opacity: 0.85;
}

/* ── Followers / Following modal (built by profileCsr) ────────── */
.apf-modal {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  /* AO BaseModal .overlay: --color-overlay-dark-80 + --blur-sm. */
  background: rgba(0, 0, 0, 0.8);
  backdrop-filter: blur(5px);
}
.apf-modal[hidden] { display: none; }
.apf-modal-panel {
  width: min(420px, 100%);
  max-height: 80vh;
  display: flex;
  flex-direction: column;
  background: var(--charcoal);
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
}
.apf-modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px;
  border-bottom: 1px solid var(--border-light);
}
.apf-modal-title {
  margin: 0;
  font-family: var(--montra);
  font-size: 18px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-primary);
}
.apf-modal-close {
  background: none;
  border: none;
  color: var(--text-secondary);
  font-size: 24px;
  line-height: 1;
  cursor: pointer;
  padding: 0 4px;
}
.apf-modal-close:hover { color: var(--text-primary); }
.apf-modal-list { overflow-y: auto; padding: 8px; display: flex; flex-direction: column; gap: 4px; }

/* ── Followers / Following / Mutual list — 1:1 with AO UserListModal
      (`components/Profile/UserListModal/userListModal.module.css`) inside
      BaseModal `variant="userProfile"`. Token literals resolved from AO
      variables.css / palette.css:
        --spacing-xs 5 / -sm 8 / -md 16 / -xl 32 / -2xl 40, --radius-sm 4,
        --radius-4xl 32, --radius-max 100, --radius-full 9999,
        --font-size-2xs 10 / -sm 14 / -lg 18, --blur-lg 15px,
        --color-surface-8/10/15/20 = pebble 8/10/15/20%,
        header band = hsl(--charcoal-h --charcoal-s 34%). ────────────── */
.apf-modal.apf-ulm-overlay { padding: 0; }
/* BaseModal `.modal` + `.modal.userProfile` (padding 0, no border, overflow
   visible, lifted by --spacing-2xl). */
.apf-ulm-shell {
  position: relative;
  width: auto;
  height: auto;
  background: var(--charcoal);       /* --color-modal-bg */
  border-radius: 32px;               /* --radius-4xl */
  overflow: visible;
  transform: translateY(-40px);      /* --spacing-2xl */
}
/* BaseModal .closeWrapper / .closeButton — 32px circle, --modal-close-inset 12px. */
.apf-ulm-close {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: var(--surface);
  color: var(--text-primary);
  font-size: 20px;                   /* --font-size-xl */
  line-height: 1;
  cursor: pointer;
  z-index: 3;
}
.apf-ulm-container {
  display: flex;
  flex-direction: column;
  width: min(420px, 92vw);
  max-width: 92vw;
  height: min(720px, 80vh);
  background: var(--charcoal);       /* --color-bg */
  color: var(--text-primary);
  overflow: hidden;
  border-radius: 32px;
}
.apf-ulm-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 16px;
  background: hsl(271 45% 34%);
  flex-shrink: 0;
}
.apf-ulm-back {
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  color: var(--text-primary);
  cursor: pointer;
  padding: 5px;
  border-radius: 4px;
}
.apf-ulm-back:hover { background: rgba(255, 255, 255, 0.1); } /* --color-overlay-light-10 */
.apf-ulm-back svg { width: 20px; height: 20px; }
.apf-ulm-title {
  font-family: var(--montra);
  font-size: 18px;
  font-weight: normal;
  text-transform: uppercase;
  margin: 0;
  flex: 1;
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.apf-ulm-spacer { width: 28px; flex-shrink: 0; }
.apf-ulm-body {
  flex: 1;
  overflow-y: auto;
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.apf-ulm-count {
  margin: 0;
  font-size: clamp(10px, 9px + 0.1786vw, 12px); /* --p-small-font-size */
  color: var(--text-secondary);
  text-align: left;
  align-self: flex-start;
}
.apf-ulm-list { display: flex; flex-direction: column; }
.apf-ulm-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 0;
  text-decoration: none;
  color: inherit;
  border-top: 1px solid var(--border);
}
.apf-ulm-row:hover { background: var(--surface); }
.apf-ulm-avatar {
  flex-shrink: 0;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  object-fit: cover;
}
.apf-ulm-avatar-fallback {
  flex-shrink: 0;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-secondary);
}
.apf-ulm-info {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 5px;
  text-align: left;
}
.apf-ulm-name {
  font-size: clamp(12px, 11px + 0.1786vw, 16px); /* --p-font-size */
  font-weight: 600;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
}
.apf-ulm-pills { display: flex; gap: 5px; }
.apf-ulm-pill-archetype,
.apf-ulm-pill-reviews {
  font-size: 10px;
  font-weight: 500;
  line-height: 12px;
  padding: 2px 5px;
  border-radius: 100px;
}
.apf-ulm-pill-reviews {
  background: var(--surface-10);
  color: var(--text-primary);
}
.apf-ulm-follow {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  height: 30px;
  padding: 0 15px;
  background: rgba(237, 237, 237, 0.15); /* --color-surface-15 */
  backdrop-filter: blur(15px);
  border: none;
  border-radius: 100px;
  color: var(--text-primary);
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}
.apf-ulm-follow svg { width: 16px; height: 16px; }
.apf-ulm-follow:hover:not(:disabled) { background: rgba(237, 237, 237, 0.2); }
.apf-ulm-follow.apf-ulm-followed {
  background: rgba(237, 237, 237, 0.08); /* --color-surface-8 */
  color: var(--text-secondary);
}
.apf-ulm-follow:disabled { opacity: 0.6; cursor: not-allowed; }
.apf-ulm-follow.apf-ulm-hidden { visibility: hidden; pointer-events: none; }
.apf-ulm-status {
  padding: 32px;
  text-align: center;
  color: var(--text-tertiary);
  font-size: clamp(12px, 11px + 0.1786vw, 16px);
}
.apf-ulm-more { padding: 16px; text-align: center; }
.apf-ulm-more-btn {
  background: none;
  border: 1px solid var(--border);
  color: var(--text-secondary);
  border-radius: 9999px;
  padding: 6px 14px;
  font-family: inherit;
  font-size: clamp(10px, 9px + 0.1786vw, 12px);
  cursor: pointer;
}
.apf-ulm-more-btn:hover:not(:disabled) { background: var(--surface); }
.apf-ulm-more-btn:disabled { opacity: 0.6; cursor: not-allowed; }

@media (max-width: 640px) {
  /* BaseModal overlay goes bottom-sheet, but `.modalShell` re-centers this one. */
  .apf-modal.apf-ulm-overlay { align-items: flex-end; }
  .apf-ulm-shell {
    align-self: center;
    margin-top: 5dvh;
    margin-bottom: auto;
    border-radius: 32px;
  }
}

/* ── Badges modal — 1:1 with AO AllCrestsModal (BaseModal variant="userProfile"
      + CrestsSection). Token literals resolved from AO variables.css. ────── */
.apf-badges-modal {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  background: rgba(0, 0, 0, 0.8); /* --color-overlay-dark-80 */
  backdrop-filter: blur(5px); /* --blur-sm */
}
.apf-badges-modal[hidden] { display: none; }
.apf-badges-container {
  position: relative;
  display: flex;
  flex-direction: column;
  width: min(720px, 92vw);
  max-width: 92vw;
  max-height: 85vh;
  background: var(--charcoal); /* --color-bg */
  color: var(--text-primary);
  border-radius: 24px; /* --radius-3xl */
  overflow: hidden;
}
.apf-badges-head {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px; /* --spacing-md */
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.apf-badges-title {
  margin: 0;
  font-family: var(--montra);
  font-size: 18px; /* --font-size-lg */
  font-weight: 400;
  text-transform: uppercase;
  color: var(--text-primary);
  letter-spacing: 0.04em;
}
.apf-badges-body {
  flex: 1;
  overflow-y: auto;
  padding: 16px 24px 24px; /* --spacing-md --spacing-lg --spacing-lg */
}
.apf-badges-close {
  position: absolute;
  top: 12px; /* --modal-close-inset (--spacing-smd) */
  right: 12px;
  width: 32px; /* --modal-close-size */
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: var(--surface);
  color: var(--text-primary);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  z-index: 3;
}
.apf-badges-close:hover { color: #fff; }

/* CrestsSection groups */
/* AO .crestsSubtitle sets no text-align of its own, but BaseModal's `.modal`
   does (`text-align: center`) and it inherits — so group headings are CENTERED
   in the live modal. */
.apf-crest-subtitle {
  font-size: 18px; /* --font-size-lg */
  font-family: var(--bricolage);
  color: var(--text-primary);
  margin: 8px 0;
  max-width: 100%;
  text-align: center;
}
.apf-crest-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px; /* --spacing-sm */
  margin-bottom: 16px; /* --spacing-md */
}
.apf-crest {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px; /* --spacing-md */
  height: 140px;
  padding: 16px 8px 0; /* --spacing-md --spacing-sm 0 */
  border: 1px solid var(--border);
  border-radius: 16px; /* --radius-xl */
  overflow: hidden;
  /* CONTENT-BOX, deliberately. AO's reset only sets border-box on
     `*::before, *::after` — never on `*` — so `.crestItem`'s height: 140px is
     the CONTENT height and the 16px top padding sits on top of it (~158px
     total). With border-box the content box is only 122px, which is shorter
     than image + name + tier + bar, so `overflow: hidden` silently clipped the
     progress bar off the bottom of every genre cell. */
  box-sizing: content-box;
}
.apf-crest-img { width: 48px; height: 48px; object-fit: contain; }
/* AO locked crest = the Locked-Badges tier art (72×72), vendored to _assets. */
.apf-crest-locked { width: 72px; height: 72px; background: url(crest-locked.svg) center / contain no-repeat; }
.apf-crest-name { width: 100%; font-size: 14px; color: var(--text-secondary); text-align: center; line-height: 1.2; }
.apf-crest-tier {
  font-size: 12px; /* --font-size-xs */
  color: var(--text-tertiary);
  text-transform: capitalize;
  margin-top: -11px; /* AO calc(-1*spacing-md + spacing-xs) = -(16-5) */
  min-height: 1lh;
}
/* Owner pin/unpin toggle (AO crestsSection .crestPinButton / .crestPinned).
   AO's pin art is an <img> with fill #EDEDED baked in, so its color tokens
   (text-tertiary → text-primary on hover) have no visible effect there — the
   only real state difference is filled vs outline art. Mirrored: pebble icon in
   both states, hover only lifts the background.
   AO's hover `background: var(--color-surface-light)` references an UNDEFINED
   token, so nothing paints; --surface-10 here is the equivalent faint tint. */
.apf-crest-pin {
  position: absolute;
  top: 4px;
  right: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: none;
  border-radius: 4px; /* --radius-sm */
  background: transparent;
  color: var(--text-primary);
  cursor: pointer;
  transition: all 0.2s ease;
}
.apf-crest-pin:hover { background: var(--surface-10); }
/* Owner-only genre progress bar + hover tooltip (AO .crestProgressWrapper). */
.apf-crest-progress {
  width: 100%;
  margin-top: auto;
  position: relative;
  padding-top: 8px; /* --spacing-sm */
  cursor: default;
}
.apf-crest-progress-tip {
  display: none;
  position: absolute;
  top: -4px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 12px; /* --font-size-xs */
  color: var(--text-secondary);
  white-space: nowrap;
}
.apf-crest-progress:hover .apf-crest-progress-tip { display: block; }
.apf-crest-progress-bar { width: 100%; height: 4px; background: var(--border); }
.apf-crest-progress-fill { height: 100%; background: var(--text-tertiary); transition: width 0.3s ease; }
@media (max-width: 640px) {
  .apf-badges-container { border-radius: 32px; } /* --radius-4xl */
}

/* ── Import banner (owner-only; mirrors AO ImportBanner) ──────── */
.apf-import {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 8px 16px;
  background: var(--surface);
  border-radius: 8px;
  box-sizing: border-box;
  color: var(--text-primary);
  text-align: left;
}
.apf-import-icon { width: 30px; height: 30px; margin-right: 8px; flex-shrink: 0; color: var(--text-primary); }
/* AO --p-large-font-size (fluid), not a fixed 16px. */
.apf-import-text { min-width: 0; font-size: clamp(16px, 13px + 0.1786vw, 18px); font-weight: 600; word-break: break-word; }
.apf-import-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 25px;
  padding: 0 10px;
  margin-left: auto;
  flex-shrink: 0;
  border: none;
  border-radius: 9999px;
  background: var(--text-primary);
  color: var(--charcoal);
  font-family: var(--bricolage);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: transform 0.15s ease;
}
.apf-import-btn:hover { transform: scale(1.05); }

/* Import-watchlist modal — AO ImportWatchlistModal + BaseModal
   variant="importWatchlist". The panel differs from the followers/following
   modal (520px wide, 32px radius, no padding), so it carries its own variant
   class on top of .apf-modal-panel. Values resolved from AO:
   modal-padding 20px, modal-header-padding 16px 20px,
   modal-footer-padding 16px 20px 20px, modal-close-clearance 56px. */
.apf-modal-panel.apf-import-panel {
  width: min(520px, 92vw);
  max-height: none;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 32px;            /* AO --radius-4xl (BaseModal .modal) */
  overflow: hidden;
}
.apf-import-panel .apf-modal-head {
  padding: 16px 20px;
  padding-right: 56px;            /* AO --modal-close-clearance */
  border-bottom: 1px solid var(--border);  /* --color-border, not border-light */
}
.apf-import-panel .apf-modal-title { font-size: 18px; letter-spacing: 0.5px; text-align: left; }
/* AO BaseModal .closeWrapper/.closeButton: 32px circle, --color-surface fill,
   inset --modal-close-inset (12px), 20px glyph. The header reserves 56px for it
   (--modal-close-clearance), so the panel needs position: relative. */
.apf-modal-panel.apf-import-panel { position: relative; }
.apf-import-panel .apf-modal-close {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border-radius: 50%;
  background: var(--surface);
  color: var(--text-primary);
  font-size: 20px;
  z-index: 3;
}
.apf-import-body { padding: 20px; display: flex; flex-direction: column; gap: 24px; text-align: left; }
.apf-import-sub { margin: 0; font-size: 14px; color: var(--text-secondary); }
.apf-import-field { display: flex; flex-direction: column; gap: 5px; }  /* AO --spacing-xs */
/* AO .label — sentence case, 14px/500. (It is NOT an uppercase micro-label.) */
.apf-import-label { font-size: 14px; font-weight: 500; color: var(--text-secondary); }
.apf-source-toggle { display: flex; gap: 8px; }
.apf-source-btn {
  flex: 1;
  padding: 8px 16px;
  border-radius: 9999px;          /* AO --radius-full, not 8px */
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-secondary);
  font-family: var(--bricolage);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s ease-in-out;
}
.apf-source-btn:hover:not(:disabled) { transform: scale(1.02); }
/* Active = AO --color-button / --color-button-text-primary. Pinned to pebble
   because this repo's --color-button is sundrop (see CLAUDE.md). AO also sets
   border-color: var(--color-primary), which is undefined in both repos, so the
   declaration is invalid and the border falls back to currentColor — mirrored. */
.apf-source-btn[data-active="1"] {
  background: var(--pebble);
  color: var(--charcoal);
  border-color: currentColor;
}
.apf-source-btn:disabled { cursor: not-allowed; opacity: 0.6; }
/* AO Commons/Form/Input size="md": 16px padding, 24px radius, transparent fill,
   pebble-15 hairline; focus lifts to pebble-10 with a sundrop border. */
.apf-import-input {
  width: 100%;
  box-sizing: border-box;
  padding: 16px;
  border-radius: 24px;
  border: 1px solid rgba(237, 237, 237, 0.15);
  background: transparent;
  color: var(--text-primary);
  font-family: var(--bricolage);
  font-size: 14px;
  transition: all 0.3s ease;
}
.apf-import-input:hover { border-color: var(--border); }
.apf-import-input:focus {
  outline: none;
  background: var(--surface-10);
  border-color: var(--accent);
}
.apf-import-input::placeholder { color: var(--text-tertiary); }
/* AO Input error prop → --color-danger hairline (cherry-top). */
.apf-import-input[data-error="1"] { border-color: var(--danger); }
.apf-import-input[data-error="1"]:focus { border-color: var(--danger); background: hsl(0 85% 60% / 0.1); }
/* AO .wrapper.disabled: opacity .6 + --color-surface-disabled (pebble-15). */
.apf-import-input:disabled { opacity: 0.6; background: var(--btn-material); cursor: not-allowed; }
/* AO .errorText */
.apf-import-error { font-size: 12px; color: var(--danger); }
.apf-import-error[hidden] { display: none; }
/* AO .checkboxRow / .checkbox / .checkboxLabel. accent-color references
   --color-primary, which is undefined in BOTH repos, so the browser default
   accent is what AO actually renders — deliberately not "fixed" to sundrop
   (CLAUDE.md § Match the LIVE site). */
.apf-import-check-row { display: flex; align-items: center; gap: 8px; cursor: pointer; }
.apf-import-check {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  accent-color: var(--color-primary);
  cursor: pointer;
}
.apf-import-check:disabled { cursor: not-allowed; }
.apf-import-check-label { font-size: 14px; color: var(--text-secondary); }
/* AO footer: both buttons flex:1 side by side (no border-top), stacking
   column-reverse under 640px. */
.apf-import-foot { display: flex; gap: 8px; padding: 16px 20px 20px; }
.apf-import-foot button { flex: 1; }
.apf-import-cancel,
.apf-import-go {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 8px 16px;
  border-radius: 9999px;
  font-family: var(--bricolage);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.3s ease, color 0.3s ease, border-color 0.3s ease;
}
/* AO Button variant="secondary" (dark theme resolves the label to ivory). */
.apf-import-cancel {
  border: 1px solid var(--border);
  background: transparent;
  color: var(--ivory);
}
.apf-import-cancel:hover { background: var(--btn-light); color: var(--ivory); }
/* AO Button variant="primary" — --color-button is pebble in AO. */
.apf-import-go {
  border: none;
  background: var(--pebble);
  color: var(--charcoal);
}
.apf-import-go:hover { opacity: 0.8; }
.apf-import-go:disabled { background: hsl(from var(--pebble) h s l / 0.7); cursor: not-allowed; }

/* Mobile: AO turns this modal into a bottom sheet and stacks the footer. */
@media (max-width: 640px) {
  .apf-modal:has(.apf-import-panel) { align-items: flex-end; padding: 0; }
  .apf-modal-panel.apf-import-panel {
    width: 100%;
    max-width: none;
    border-radius: 32px 32px 0 0;
    border-bottom: none;
  }
  .apf-import-foot { flex-direction: column-reverse; }
  .apf-import-foot button { width: 100%; }
}

/* ── Filter pills (Recent Activity) ───────────────────────────── */
/* AO RecentActivity `.header` is NOT space-between: title is flex-shrink:0,
   the tab row takes the remaining space (flex:1) and "View more" is pushed
   right by its own margin-left:auto. With space-between the pills would jump
   to the right edge whenever "View more" is hidden (e.g. a tab with ≤4 rows). */
.apf-activity-card .apf-card-head { justify-content: flex-start; }
.apf-activity-card .apf-card-title { flex-shrink: 0; }
.apf-activity-card .apf-view-more { flex-shrink: 0; }
.apf-pills {
  display: flex;
  gap: 5px;
  flex: 1;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
}
.apf-pills::-webkit-scrollbar { display: none; }
.apf-pill {
  flex-shrink: 0;
  padding: 5px 12px;
  border-radius: 9999px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-secondary);
  font-family: var(--bricolage);
  font-size: 14px;
  font-weight: 600;
  line-height: 1.2;
  cursor: pointer;
}
.apf-pill-active {
  background: var(--btn-material);
  color: var(--text-primary);
  border-color: var(--text-primary);
}

/* ── Recent Activity rows ─────────────────────────────────────── */
.apf-activity-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.apf-activity-item { display: block; }
/* Collapsed default shows 4; "View more" removes .apf-activity-collapsed (CSR). */
.apf-activity-collapsed .apf-activity-item:nth-child(n + 5) { display: none; }
.apf-activity-link {
  display: flex;
  gap: 8px;
  padding: 8px;
  background: var(--surface);
  border-radius: 8px;
  color: inherit;
  text-decoration: none;
}
/* AO ActivityRow shows the profile user's round avatar (32px), not the poster. */
.apf-activity-avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
}
.apf-activity-body { display: flex; flex-direction: column; flex: 1; gap: 5px; min-width: 0; }
.apf-activity-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; }
.apf-activity-text { font-size: 14px; color: var(--text-secondary); line-height: 1.4; }
.apf-activity-actor { color: var(--text-primary); font-weight: 600; }
.apf-activity-title { color: var(--text-primary); font-weight: 600; }
.apf-activity-time { font-size: 14px; color: var(--text-tertiary); white-space: nowrap; flex-shrink: 0; }
.apf-activity-excerpt {
  margin: 2px 0 0;
  font-size: 14px;
  color: var(--text-secondary);
  line-height: 1.4;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ── Stars (ivory, readonly) ──────────────────────────────────── */
.apf-stars { display: inline-flex; align-items: center; gap: 2px; line-height: 1; }
.apf-star { font-size: 16px; color: var(--border); }
.apf-star-full { color: var(--ivory); }
.apf-star-half {
  background: linear-gradient(90deg, var(--ivory) 50%, var(--border) 50%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

/* ── Poster rails (My Top Oshi / Currently Watching) ──────────── */
.apf-rail {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 16px;
}
.apf-rail-item { min-width: 0; }
.apf-rail-item a {
  display: flex;
  flex-direction: column;
  gap: 5px;
  color: inherit;
  text-decoration: none;
}
.apf-poster-wrap { position: relative; display: block; }
.apf-rail-poster {
  width: 100%;
  aspect-ratio: 84 / 120;
  border-radius: 8px;
  object-fit: cover;
  background: var(--charcoal);
  display: block;
}
.apf-rail-title {
  font-family: var(--bricolage);
  font-size: 14px;
  font-weight: 600;
  color: var(--text-primary);
  line-height: 1.3;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.apf-rail-meta {
  margin-top: auto;
  display: flex;
  align-items: baseline;
  gap: 4px;
  font-size: 12px;
  color: var(--text-secondary);
}
.apf-rail-score { font-family: var(--bricolage); font-weight: 700; font-size: 16px; line-height: 1; color: var(--sundrop); }
.apf-rail-pts { font-weight: 500; }
/* ── Currently Watching (AO currentlyWatching.module.css) ───────
   5-up card grid; each card is cover + body, and the episode pill sits at the
   BOTTOM OF THE BODY under the 2-line title (margin-top:auto), left-aligned —
   AO does not overlay it on the poster. The title's 2.6em min-height is what
   keeps the pills on one baseline across cards. */
.apf-cw-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 16px;
}
.apf-cw-item { min-width: 0; display: flex; }
.apf-cw-card {
  display: flex;
  flex-direction: column;
  gap: 5px;
  width: 100%;
  height: 100%;
  min-width: 0;
  color: inherit;
  text-decoration: none;
}
.apf-cw-card:hover .apf-cw-title { opacity: 0.85; }
.apf-cw-cover {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 84 / 120;
  border-radius: 8px; /* --radius-md */
  overflow: hidden;
  background: var(--charcoal);
  flex-shrink: 0;
}
.apf-cw-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.apf-cw-body {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-width: 0;
  gap: 5px;
}
.apf-cw-title {
  font-family: var(--bricolage);
  font-size: 14px;
  font-weight: 600;
  color: var(--text-primary);
  line-height: 1.3;
  min-height: 2.6em; /* AO reserves both lines so the pills line up */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.apf-ep-badge {
  margin-top: auto;
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  padding: 5px 10px;
  border-radius: 9999px;
  background: var(--surface-10);
  font-family: var(--bricolage);
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 0.04em;
  line-height: 1;
  color: var(--text-primary);
}
/* ≤768 AO swaps the grid for a snap-scrolling row showing 4 cards. */
@media (max-width: 768px) {
  .apf-cw-grid {
    display: flex;
    gap: 8px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    padding-bottom: 5px;
  }
  .apf-cw-grid::-webkit-scrollbar { display: none; }
  .apf-cw-grid > * { flex: 0 0 calc((100% - 8px * 3) / 4); min-width: 0; scroll-snap-align: start; }
}
/* ── My Top Oshi (AO MyTopOshi grid — cards, ✕ remove, + add-slots) ──
   Ported 1:1 from animeoshi-web myTopOshi.module.css. The card grid replaces
   the old poster rail; the owner-only ✕ / + / "Pick your Oshi" affordances are
   layered by the CSR (public sees plain cards + empty fillers). */
.apf-card:has(#apf-oshi-h) { border: 1px solid var(--accent-light); }
.apf-oshi-content { position: relative; width: 100%; }
.apf-oshi-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 16px; }
/* Collapsed shows the first 5 (AO initial limit); "View all" (CSR) removes it. */
.apf-oshi-collapsed > *:nth-child(n + 6) { display: none; }
.apf-oshi-card {
  display: flex;
  flex-direction: column;
  gap: 5px;
  text-decoration: none;
  color: inherit;
  min-width: 0;
  height: 100%;
}
.apf-oshi-card:hover .apf-oshi-title { opacity: 0.85; }
.apf-oshi-cover {
  position: relative;
  width: 100%;
  aspect-ratio: 84 / 120;
  border-radius: 8px;
  overflow: hidden;
  background: var(--charcoal);
  flex-shrink: 0;
  display: block;
}
.apf-oshi-img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Owner-only remove (AO removeButton, XMark) — added by the CSR. */
.apf-oshi-remove {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 24px;
  height: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: none;
  border-radius: 9999px;
  background: rgba(0, 0, 0, 0.6);
  color: var(--ivory);
  cursor: pointer;
  z-index: 1;
  transition: background 0.15s ease;
}
.apf-oshi-remove:hover:not(:disabled) { background: rgba(0, 0, 0, 0.8); }
.apf-oshi-remove:disabled { opacity: 0.5; cursor: not-allowed; }
.apf-oshi-remove svg { width: 16px; height: 16px; }
.apf-oshi-body { display: flex; flex-direction: column; flex: 1; min-width: 0; gap: 5px; }
.apf-oshi-title {
  margin: 0;
  font-family: var(--bricolage);
  font-size: 14px;
  font-weight: 600;
  color: var(--text-primary);
  line-height: 1.3;
  min-height: 2.6em;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.apf-oshi-scorerow { margin-top: auto; display: flex; align-items: baseline; justify-content: space-between; gap: 5px; }
.apf-oshi-score { font-family: var(--bricolage); font-weight: 700; font-size: 16px; line-height: 1; color: var(--accent); }
.apf-oshi-pts { display: inline-flex; align-items: center; gap: 2px; font-family: var(--bricolage); font-size: 12px; font-weight: 500; line-height: 1; color: var(--text-secondary); }
.apf-oshi-pts-star { color: #ffd54a; }
/* Empty grid slots (AO emptyCard) + owner add-slots (AO addSlot, + icon). */
.apf-oshi-empty-card { width: 100%; aspect-ratio: 84 / 120; align-self: start; border-radius: 8px; background: var(--charcoal); }
.apf-oshi-add {
  width: 100%;
  aspect-ratio: 84 / 120;
  align-self: start;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: none;
  border-radius: 8px;
  background: var(--charcoal);
  color: var(--text-secondary);
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.apf-oshi-add:hover { background: var(--btn-material); color: var(--text-primary); }
.apf-oshi-add svg { width: 32px; height: 32px; }
/* Owner empty state "Pick your Oshi" pill + public "No Top Oshi selected yet". */
.apf-oshi-pick,
.apf-oshi-empty-overlay {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  padding: 10px 18px;
  border-radius: 9999px;
  background: var(--btn-material);
  font-family: var(--bricolage);
  font-size: 16px;
  font-weight: 600;
  white-space: nowrap;
  z-index: 1;
}
.apf-oshi-pick { display: inline-flex; align-items: center; gap: 6px; color: var(--text-primary); border: none; cursor: pointer; }
.apf-oshi-pick:hover { background: var(--surface); }
.apf-oshi-pick svg { width: 20px; height: 20px; }
.apf-oshi-empty-overlay { color: var(--text-secondary); }
/* Mobile: 4 cards in a horizontally-scrolling row (AO myTopOshi @768). */
@media (max-width: 768px) {
  .apf-oshi-grid {
    display: flex;
    gap: 8px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    padding-bottom: 5px;
  }
  .apf-oshi-grid::-webkit-scrollbar { display: none; }
  .apf-oshi-grid > * { flex: 0 0 calc((100% - 8px * 3) / 4); min-width: 0; scroll-snap-align: start; }
}

/* ── Pick Your Oshi modal (AO PickOshiModal, ported 1:1) ───────────
   Bottom-sheet on mobile → centered panel ≥768px. Built by profileCsr for the
   owner; opens from the + add-slots / "Pick your Oshi" button. */
.apf-pick-overlay {
  position: fixed;
  inset: 0;
  z-index: 1200;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: hsl(271 45% 9% / 0.7);
  backdrop-filter: blur(10px);
}
.apf-pick-overlay[hidden] { display: none; }
.apf-pick-sheet {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 90vh;
  max-height: 90vh;
  background: var(--charcoal);
  overflow: hidden;
  isolation: isolate;
  position: relative;
  border-top-left-radius: 30px;
  border-top-right-radius: 30px;
}
@media (min-width: 768px) {
  .apf-pick-overlay { align-items: flex-start; }
  .apf-pick-sheet {
    max-width: 720px;
    height: min(900px, 92vh);
    margin: 32px auto;
    border-radius: 30px;
    border: 1px solid var(--border);
  }
}
.apf-pick-header {
  flex-shrink: 0;
  position: relative;
  padding: 16px 20px;
  background-image: linear-gradient(115.41deg, #4b307e 55%, #000 194%);
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.apf-pick-header-top { display: flex; align-items: center; gap: 5px; padding: 8px; }
.apf-pick-back {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--text-primary);
  cursor: pointer;
}
.apf-pick-back svg { width: 16px; height: 16px; }
.apf-pick-titleblock { display: flex; flex-direction: column; gap: 5px; }
.apf-pick-title { margin: 0; font-family: var(--montra); font-size: 16px; font-weight: 400; line-height: 1; letter-spacing: 0.02em; text-transform: uppercase; color: var(--text-primary); }
.apf-pick-subtitle { margin: 0; font-family: var(--bricolage); font-size: 14px; font-weight: 500; line-height: 1.3; color: var(--text-secondary); }
.apf-pick-search {
  display: flex;
  align-items: center;
  gap: 5px;
  height: 30px;
  padding: 0 16px;
  border-radius: 100px;
  background: var(--btn-material);
  backdrop-filter: blur(15px);
}
.apf-pick-search-ic { width: 14px; height: 16px; color: var(--text-tertiary); flex-shrink: 0; }
.apf-pick-search-ic svg { width: 100%; height: 100%; }
.apf-pick-input { flex: 1; min-width: 0; background: transparent; border: none; outline: none; color: var(--text-primary); font-family: var(--bricolage); font-size: 14px; font-weight: 600; }
.apf-pick-input::placeholder { color: var(--text-tertiary); }
.apf-pick-input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }
.apf-pick-clear { display: inline-flex; align-items: center; justify-content: center; padding: 0; border: none; background: transparent; color: var(--text-primary); cursor: pointer; flex-shrink: 0; }
.apf-pick-clear svg { width: 16px; height: 16px; }
.apf-pick-filters { flex-shrink: 0; padding: 8px 16px 0; display: flex; flex-direction: column; gap: 8px; }
.apf-pick-filters[hidden] { display: none; }
.apf-pick-primary-row,
.apf-pick-sub-row { display: flex; gap: 5px; overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
.apf-pick-primary-row::-webkit-scrollbar,
.apf-pick-sub-row::-webkit-scrollbar { display: none; }
.apf-pick-primary {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  height: 30px;
  padding: 0 8px;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: transparent;
  color: var(--text-primary);
  font-family: var(--bricolage);
  font-size: 14px;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.apf-pick-primary[data-active="true"] { background: var(--text-primary); color: var(--charcoal); border-color: transparent; border-radius: 100px; }
.apf-pick-sub {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  height: 21px;
  padding: 0 8px;
  border: none;
  border-radius: 100px;
  background: var(--surface-10);
  color: var(--text-primary);
  font-family: var(--bricolage);
  font-size: 12px;
  font-weight: 500;
  line-height: 1;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s ease, color 0.15s ease;
}
.apf-pick-sub[data-active="true"] { background: var(--text-primary); color: var(--charcoal); }
.apf-pick-body { flex: 1 1 0; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 20px; box-sizing: border-box; }
.apf-pick-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
@media (min-width: 768px) { .apf-pick-grid { grid-template-columns: repeat(6, minmax(0, 1fr)); } }
.apf-pick-card { display: flex; flex-direction: column; gap: 7px; padding: 0; border: none; background: transparent; text-align: left; cursor: pointer; color: inherit; font: inherit; position: relative; }
.apf-pick-cover {
  position: relative;
  aspect-ratio: 90 / 128;
  width: 100%;
  border-radius: 8px;
  overflow: hidden;
  background: var(--surface);
  transition: outline 0.15s ease;
  outline: 2px solid transparent;
  outline-offset: -2px;
}
.apf-pick-cover img { width: 100%; height: 100%; object-fit: cover; }
.apf-pick-card[data-state="picked"] .apf-pick-cover { outline-color: var(--accent); }
.apf-pick-card-title {
  margin: 0;
  font-family: var(--bricolage);
  font-size: 12px;
  font-weight: 500;
  line-height: 14px;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  word-break: break-word;
}
.apf-pick-placeholder { padding: 24px 16px; text-align: center; color: var(--text-secondary); font-family: var(--bricolage); font-size: 14px; }
.apf-pick-noresults { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 24px; width: 100%; padding: 80px 16px; text-align: center; box-sizing: border-box; color: var(--text-secondary); font-family: var(--bricolage); font-size: 16px; }
.apf-pick-bottom {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  padding: 16px 20px 20px;
  background: hsl(271 45% 9% / 0.7);
  backdrop-filter: blur(15px);
}
.apf-pick-reorder-hint { margin: 0; font-family: var(--bricolage); font-size: 12px; font-weight: 500; color: var(--text-tertiary); letter-spacing: 0.02em; }
.apf-pick-bottomcard {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  max-width: 720px;
  padding: 5px 8px;
  border: 1px solid var(--accent);
  border-radius: 8px;
  background: var(--surface);
}
.apf-pick-slots { display: flex; gap: 5px; flex: 1; min-width: 0; }
.apf-pick-slot,
.apf-pick-slot-empty { position: relative; flex: 1 1 0; max-width: 80px; aspect-ratio: 90 / 128; border-radius: 10px; }
.apf-pick-slot-empty { background: var(--surface); }
.apf-pick-slot-cover { position: absolute; inset: 0; border-radius: 10px; overflow: hidden; background: var(--surface); }
.apf-pick-slot-cover img { width: 100%; height: 100%; object-fit: cover; }
.apf-pick-slot-remove {
  position: absolute;
  top: -6px;
  right: -6px;
  width: 18px;
  height: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: none;
  border-radius: 9999px;
  background: var(--text-primary);
  color: var(--charcoal);
  cursor: pointer;
  z-index: 1;
}
.apf-pick-slot-remove svg { width: 12px; height: 12px; }
.apf-pick-save {
  flex: 0 0 auto;
  height: 32px;
  padding: 0 16px;
  border: none;
  border-radius: 100px;
  background: var(--pebble);
  color: var(--charcoal);
  font-family: var(--bricolage);
  font-size: 14px;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
  transition: opacity 0.15s ease;
}
.apf-pick-save:disabled { opacity: 0.5; cursor: not-allowed; }

/* ── Badges ───────────────────────────────────────────────────── */
/* AO Badges .grid / .gridItem / .icon — the CELL is the aspect-1 surface tile
   (radius --radius-md, --spacing-xs padding); the icon inside is capped at
   64px, so a wide sidebar doesn't blow the art up past AO's size. */
.apf-badge-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; width: 100%; }
.apf-badge-cell {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 1 / 1;
  background: var(--surface);
  border: none;
  border-radius: 8px;
  padding: 5px;
  box-sizing: border-box;
}
.apf-badge {
  width: 100%;
  height: 100%;
  max-width: 64px;
  max-height: 64px;
  object-fit: contain;
}

/* ── OshiRank (sidebar) ───────────────────────────────────────── */
.apf-rank-rail {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(5, 1fr);   /* AO OshiRank shows top 5 → smaller posters */
  gap: 5px;
  align-items: start;
}
.apf-rank-rail .apf-rail-poster { border: 1px solid var(--border-light); border-radius: 4px; }
.apf-rank-rail .apf-rail-title { font-size: 12px; font-weight: 500; line-height: 1.5; }
.apf-rank-badge {
  position: absolute;
  top: -6px;
  left: -4px;
  width: 20px;
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 9999px;
  background: var(--ivory);
  color: var(--charcoal);
  font-family: var(--bricolage);
  font-size: 12px;
  font-weight: 800;
  line-height: 1;
}
/* Top-3 star medal (AO RankMedal SVG) with the rank number overlaid. */
.apf-rank-medal {
  position: absolute;
  top: -6px;
  left: -4px;
  width: 22px;
  height: 22px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.apf-rank-medal-svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.apf-rank-medal-num {
  position: relative;
  font-family: var(--bricolage);
  font-size: 11px;
  font-weight: 800;
  line-height: 1;
  color: var(--charcoal);
}

/* ── Oshi Diary ───────────────────────────────────────────────── */
/* AO oshiDiary .section: flex column, --spacing-xs gap (the streak card and the
   timeline are its two children). */
.apf-diary-card { gap: 5px; }
/* ── Activity streak card (AO Home/HomeStatsRow, desktop = ≥1024) ──
   A bordered, TRANSPARENT card whose grid is
     "header header"
     "stats  bars"
   with the header row full-bleed (negative side margins) on a surface fill. */
.apf-streak {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-areas:
    'header header'
    'stats bars';
  align-items: center;
  gap: 8px 16px;
  width: 100%;
  align-self: stretch;
  padding: 0 16px 16px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: transparent;
  box-sizing: border-box;
  color: inherit;
  text-decoration: none;
}
.apf-streak-head {
  grid-area: header;
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 0 -16px 5px;
  padding: 16px;
  background: var(--surface);
  border-radius: 12px 12px 0 0;
  transition: background 0.2s ease;
}
.apf-streak:hover .apf-streak-head { background: rgba(237, 237, 237, 0.08); }
.apf-streak-title {
  font-family: var(--montra);
  font-size: 20px; /* --font-size-xl */
  color: var(--text-primary);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  line-height: 1;
}
.apf-streak-cta {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: var(--bricolage);
  font-size: 14px;
  font-weight: 500;
  color: var(--text-secondary);
  line-height: 1;
}
.apf-streak-cta-ic { width: 14px; height: 14px; flex-shrink: 0; }
.apf-streak-stats {
  grid-area: stats;
  display: flex;
  flex-direction: column;
  gap: 5px; /* --spacing-xs ≥1024 */
  min-width: 0;
}
.apf-streak-label {
  font-family: var(--bricolage);
  font-size: 12px;
  font-weight: 500;
  color: var(--text-secondary);
  letter-spacing: 0.02em;
  line-height: 1;
}
.apf-streak-value {
  font-family: var(--montra);
  font-size: 14px; /* AO .value = --font-size-sm (NOT the 20px used elsewhere) */
  font-weight: 500;
  color: var(--text-primary);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  line-height: 1.1;
}
/* Desktop "Best: N days" (AO .trophyDesktop). */
.apf-streak-best {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 2px 0 0;
  font-family: var(--bricolage);
  font-size: 14px;
  font-weight: 700;
  color: var(--accent);
  line-height: 1;
}
.apf-streak-trophy-ic { width: 14px; height: 14px; color: var(--accent); flex-shrink: 0; }
.apf-streak-bars {
  grid-area: bars;
  display: flex;
  gap: 2px;
  flex: 1 1 auto;
  width: auto;
  min-width: 0;
}
.apf-streak-bar {
  position: relative;
  flex: 1 1 0;
  height: 28px;
  min-width: 4px;
  border-radius: 4px; /* --radius-sm */
  background: var(--surface);
}
.apf-streak-bar-on { background: var(--accent); }                  /* in current streak */
.apf-streak-bar-faded { background: hsl(68 100% 50% / 0.3); }      /* active, outside it */
.apf-streak-bar-empty { background: var(--surface); }
.apf-streak-bar-today { outline: 1.5px solid hsl(305 100% 76%); outline-offset: 1px; } /* --kawaii-core */
/* CSS-only per-day tooltip (AO .activityBar[data-tooltip]). */
.apf-streak-bar[data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  background: hsl(271 45% 9% / 0.92); /* charcoal @92% */
  color: var(--pebble);
  font-family: var(--bricolage);
  font-size: 12px;
  font-weight: 500;
  line-height: 1.3;
  white-space: nowrap;
  padding: 5px 8px;
  border-radius: 4px;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.15s ease;
  z-index: 10;
}
.apf-streak-bar[data-tooltip]:hover::after { opacity: 1; }
/* Mobile-only trophy + footer CTA — AO hides both ≥1024. */
.apf-streak-best-mobile,
.apf-streak-foot { display: none; }
@media (max-width: 1023px) {
  .apf-streak {
    grid-template-areas:
      'stats bars'
      'trophy footer';
    gap: 5px 16px;
    align-self: flex-start;
    padding: 8px 16px;
    border: none;
    background: var(--surface);
  }
  .apf-streak:hover { background: rgba(237, 237, 237, 0.08); }
  .apf-streak-head { display: none; }
  .apf-streak-stats { gap: 1px; }
  .apf-streak-best { display: none; }
  .apf-streak-bars { width: 100%; flex: 0 1 auto; }
  .apf-streak-bar { height: 20px; min-width: 0; }
  .apf-streak-best-mobile {
    grid-area: trophy;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-family: var(--bricolage);
    font-size: 12px;
    font-weight: 700;
    color: var(--accent);
    line-height: 1;
  }
  .apf-streak-foot {
    grid-area: footer;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    min-width: 0;
  }
  .apf-streak-foot-cta {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-family: var(--bricolage);
    font-size: 12px;
    font-weight: 500;
    color: var(--text-secondary);
    line-height: 1;
  }
  .apf-streak-foot-ic { width: 12px; height: 12px; flex-shrink: 0; }
}
/* AO timelineCard: the diary entries sit in a surface sub-card (radius 8, pad 8 16). */
.apf-diary-list { list-style: none; margin: 0; padding: 8px 16px; background: var(--surface); border-radius: 8px; display: flex; flex-direction: column; }
/* One group per DAY (AO .group): a 36px date column beside that day's rows,
   stretched so the column's connector line can span the whole group. */
.apf-diary-group { display: flex; align-items: stretch; gap: 8px; padding: 8px 0; }
.apf-diary-date {
  flex: 0 0 36px;
  display: flex;
  flex-direction: column;
  align-items: center;
  color: var(--text-secondary);
  font-family: var(--bricolage);
}
/* The timeline's vertical line (AO .groupLabel::after) — a 1px rounded rule that
   fills whatever height is left under the date, i.e. the full day group. */
.apf-diary-date::after {
  content: '';
  flex: 1 1 auto;
  width: 1px;
  margin-top: 5px;
  border-radius: 9999px; /* --radius-max */
  background: var(--border);
}
.apf-diary-date-num { font-size: 18px; font-weight: 700; line-height: 1; color: var(--text-primary); }
.apf-diary-date-dow {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-top: 2px;
}
.apf-diary-rows {
  flex: 1 1 0;
  min-width: 0;
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.apf-diary-row { display: grid; grid-template-columns: 48px 1fr; gap: 8px; align-items: start; }
.apf-diary-poster {
  display: block;
  width: 48px;
  height: 68px;
  border-radius: 4px;
  overflow: hidden;
  background: var(--charcoal);
  flex-shrink: 0;
}
.apf-diary-thumb { width: 100%; height: 100%; object-fit: cover; }
.apf-diary-body { min-width: 0; display: flex; flex-direction: column; gap: 5px; padding-top: 2px; }
.apf-diary-title { margin: 0; font-size: 14px; color: var(--text-secondary); line-height: 1.4; }
.apf-diary-verb { color: var(--text-secondary); }
.apf-diary-target { color: var(--text-primary); font-weight: 600; text-decoration: none; }
.apf-diary-target:hover { text-decoration: underline; }
.apf-diary-excerpt {
  margin: 2px 0 0;
  font-size: 14px;
  color: var(--text-secondary);
  line-height: 1.4;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* ── Stats grid ───────────────────────────────────────────────── */
.apf-stats-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px; }
.apf-stat-cell {
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 16px;
  background: var(--surface);
  border-radius: 8px;
  min-width: 0;
}
/* "Anime Completed" cell is a link in AO (→ /lists?status=completed). */
a.apf-stat-cell { text-decoration: none; color: inherit; }
a.apf-stat-cell:hover { background: var(--surface-10); }
.apf-stat-label { font-size: 12px; color: var(--text-secondary); font-weight: 500; letter-spacing: 0.02em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.apf-stat-value { font-family: var(--montra); font-weight: 500; font-size: 20px; letter-spacing: 0.04em; line-height: 1.1; color: var(--text-primary); }

/* ── Socials ──────────────────────────────────────────────────── */
.apf-socials { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }
.apf-social-row {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  background: var(--surface);
  border-radius: 9999px;
  min-width: 0;
}
/* Per-platform icon (AO Socials): brand SVG for discord/instagram/x/youtube,
   a letter badge for mal/anilist. */
.apf-social-ic {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
}
.apf-social-ic-discord { background-image: url(social-discord.svg); }
.apf-social-ic-instagram { background-image: url(social-instagram.svg); }
.apf-social-ic-x { background-image: url(social-x.svg); }
.apf-social-ic-youtube { background-image: url(social-youtube.svg); }
.apf-social-ic-mal,
.apf-social-ic-anilist {
  border-radius: 4px;
  background: var(--surface-10);
  color: var(--text-primary);
  font-family: var(--bricolage);
  font-size: 10px;
  font-weight: 700;
}
.apf-social-handle {
  font-size: 14px;
  font-weight: 500;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ══ Character avatar editor (AO Profile/CharacterAvatarModal) ═════
   Owner-only editor opened by clicking the hero's floating character
   avatar. Mirrors characterAvatarModal.module.css + BaseModal's
   .overlay/.modal (variant "avatarEditor"), with AO's tokens resolved:
     --color-modal-bg     = --charcoal
     --color-border       = rgba(pebble,0.2)   (opaque here → use --border)
     --color-surface      = rgba(pebble,0.05)  (opaque here → use --surface)
     --color-surface-secondary is UNDEFINED in AO too, so the category
       buttons/arrows render transparent by default — mirrored, not "fixed".
     --radius-4xl = 32px, --radius-md = 8px, --font-size-sm = 14px,
     --spacing-xs/sm/md/lg/xl = 4/8/16/24/32px, --modal-close-size = 32px,
     --modal-close-inset = --spacing-smd = 12px. */
.aoca-overlay {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.8);              /* --color-overlay-dark-80 */
  backdrop-filter: blur(5px);                  /* --blur-sm */
  -webkit-backdrop-filter: blur(5px);
}
.aoca-modal {
  position: relative;
  width: min(880px, 92vw);
  max-width: 880px;
  padding: 0;
  overflow: hidden;
  text-align: left;
  border: 1px solid var(--border);
  border-radius: 32px;                         /* --radius-4xl */
  background: var(--charcoal);                 /* --color-modal-bg */
  color: var(--text-primary);
  font-family: var(--bricolage);
}
.aoca-close-wrap {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 44px;                                 /* .modal.avatarEditor .closeWrapper */
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--surface);
  border-radius: 50%;
  z-index: 3;
}
.aoca-close {
  width: 100%;
  height: 100%;
  padding: 0;
  border: none;
  background: none;
  color: var(--text-primary);
  font-size: 24px;
  line-height: 1;
  cursor: pointer;
}
.aoca-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  height: min(560px, 90vh);
}
.aoca-preview {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: radial-gradient(circle at 50% 32%, var(--surface), var(--charcoal));
}
.aoca-preview-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  user-select: none;
  pointer-events: none;
}
.aoca-character {
  position: relative;
  z-index: 1;
  height: 85%;
  max-height: 460px;
  aspect-ratio: 320 / 400;
}
.aoca-preview-layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  user-select: none;
  pointer-events: none;
}
.aoca-editor {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 32px 24px 24px;
  background: var(--charcoal);
  min-width: 0;
  min-height: 0;
}
.aoca-title {
  font-size: 1.5rem;
  font-weight: 500;
  font-family: var(--montra);
  color: var(--text-primary);
  margin: 0;
  text-align: center;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.aoca-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  overflow-y: auto;
  padding-right: 4px;
  flex: 1;
  min-height: 0;
  align-content: start;
  scrollbar-width: none;
}
.aoca-grid::-webkit-scrollbar { display: none; }
.aoca-tile {
  position: relative;
  aspect-ratio: 1 / 1;
  background: var(--surface);
  border: 2px solid transparent;
  border-radius: 8px;
  padding: 8px;
  cursor: pointer;
  transition: border-color 0.15s ease, transform 0.15s ease;
  display: flex;
  align-items: center;
  justify-content: center;
}
.aoca-tile-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  pointer-events: none;
  user-select: none;
}
.aoca-tile:hover { border-color: var(--border); }
.aoca-tile:active { transform: scale(0.97); }
.aoca-tile-selected,
.aoca-tile-selected:hover { border-color: var(--text-primary); }
.aoca-tile-none {
  font-family: var(--bricolage);
  font-size: 14px;
  font-weight: 600;
  color: var(--text-secondary);
}
/* Loading placeholders (AO renders <Skeleton/> inside the same tile). */
.aoca-tile-skeleton {
  cursor: default;
  background: var(--surface-10);
  animation: aoca-pulse 1.4s ease-in-out infinite;
}
@keyframes aoca-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
.aoca-state {
  grid-column: 1 / -1;
  padding: 24px;
  text-align: center;
  font-size: 14px;
  color: var(--text-secondary);
}
.aoca-catnav {
  display: flex;
  align-items: center;
  gap: 4px;
}
.aoca-arrow {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 9999px;
  border: none;
  background: transparent;                     /* --color-surface-secondary (undefined in AO) */
  color: var(--text-primary);
  cursor: pointer;
  transition: background-color 0.15s ease, opacity 0.15s ease;
}
.aoca-arrow:hover { background: var(--surface); }
.aoca-arrow:disabled { opacity: 0; pointer-events: none; }
.aoca-strip {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 4px 0;
  flex: 1;
  min-width: 0;
  overflow-x: auto;
  scroll-behavior: smooth;
  scrollbar-width: none;
}
.aoca-strip::-webkit-scrollbar { display: none; }
.aoca-cat {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 9999px;
  border: none;
  background: transparent;                     /* --color-surface-secondary (undefined in AO) */
  color: var(--text-secondary);
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease;
}
.aoca-cat:hover { background: var(--surface); color: var(--text-primary); }
.aoca-cat-active,
.aoca-cat-active:hover { background: var(--ivory); color: var(--charcoal); }
.aoca-save {
  height: 56px;
  border-radius: 9999px;
  border: none;
  background: var(--text-primary);
  color: var(--charcoal);
  font-family: var(--bricolage);
  font-size: 1.0625rem;
  font-weight: 600;
  cursor: pointer;
  transition: transform 0.15s ease, opacity 0.15s ease;
}
.aoca-save:hover { opacity: 0.92; }
.aoca-save:active { transform: scale(0.98); }
.aoca-save:disabled { opacity: 0.6; cursor: default; }

@media (max-width: 768px) {
  /* Full-screen modal on mobile (AO characterAvatarModal @768). */
  .aoca-modal {
    width: 100vw;
    max-width: none;
    height: 100dvh;
    border: none;
    border-radius: 0;
  }
  .aoca-layout {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: 1fr auto;
    height: 100dvh;
  }
  .aoca-preview { min-height: 0; }
  .aoca-character { height: 88%; }
  .aoca-title { display: none; }
  .aoca-editor {
    padding: 16px 16px 24px;
    gap: 16px;
    overflow-y: auto;
  }
  .aoca-grid {
    display: flex;
    flex: 0 0 auto;
    column-gap: 8px;
    row-gap: 0;
    overflow-x: auto;
    overflow-y: hidden;
    padding-right: 0;
    padding-bottom: 4px;
  }
  .aoca-tile { flex: 0 0 84px; }
  .aoca-arrow { display: none; }
  .aoca-save { height: 48px; }
}

/* Import banner, job-status state (AO ImportBanner + ImportStatusBadge).
   With a watchlist-import job the WHOLE row becomes the button (AO
   .bannerButton) and the "Import" pill is replaced by the status badge. */
.apf-import-btnrow {
  border: none;
  cursor: pointer;
  font-family: var(--bricolage);
  transition: all 0.2s ease;
}
.apf-import-btnrow:hover { transform: translateY(-1px); }
.apf-import-badge {
  display: flex;
  align-items: center;
  justify-content: center;
  margin-left: auto;                  /* AO .badgeSlot */
  flex-shrink: 0;
  padding: 2px 8px;
  border-radius: 9999px;
  background: var(--btn-material);    /* AO --color-surface-15 = --pebble-15 */
  font-size: 12px;
  font-weight: 500;
  white-space: nowrap;
}
.apf-import-badge[data-tone="progress"] { color: var(--text-secondary); }
.apf-import-badge[data-tone="success"] { color: var(--accent); }   /* AO --sundrop */
.apf-import-badge[data-tone="failed"] { color: var(--danger); }
