/*
 * LimitedHub - Author profile page styles.
 *
 * Own stylesheet, same reasoning as marketplace/, admin/ and
 * marketplace/product/. The shared "chrome" below (tokens, reset, navbar,
 * mobile menu, account popover, auth modal, buttons, footer) is copied
 * from css/style.css - if you change one of those there, mirror the
 * change here too. The `.mp-product-*` product card styles further down
 * are copied from marketplace/css/style.css for the same reason. The
 * `.au-*` block at the very end is specific to this page.
 */

:root {
  /* Tells the browser to render its OWN native UI (select dropdown popups,
     scrollbars, date pickers, etc.) using a dark palette instead of the
     OS/browser default light one - without this, a <select>'s closed box
     picks up our dark .auth-input/.sell-select/etc styling just fine, but
     the popup list of <option>s that appears on click is native browser
     chrome and ignored our CSS entirely, showing up as a jarring white
     dropdown on an otherwise all-dark page. */
  color-scheme: dark;
  --bg: #08080a;
  --border: #1e1e26;
  --border-soft: #16161c;
  --accent: #ff9d2e;
  --accent-dim: #7a4d1c;
  --text: #f4f2ee;
  --text-dim: #8c8b96;
  --text-faint: #55555f;
  --glass-bg: rgba(15, 15, 19, 0.55);
  --avatar-empty: #2b2b33;
  --avatar-empty-ring: #38383f;
  --danger: #ff6b5e;
  --ok: #34d399;
  --font-display: 'Rubik', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-premium: cubic-bezier(0.16, 1, 0.3, 1);
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-display);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* ---------- custom scrollbar ---------- */

html {
  scrollbar-width: thin;
  scrollbar-color: var(--accent-dim) var(--bg);
  scroll-behavior: smooth;
}

section[id] {
  scroll-margin-top: 90px;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
}

::-webkit-scrollbar {
  width: 11px;
  height: 11px;
}

::-webkit-scrollbar-track {
  background: var(--bg);
}

::-webkit-scrollbar-thumb {
  background-color: var(--accent-dim);
  border: 3px solid var(--bg);
  border-radius: 999px;
  transition: background-color 0.2s var(--ease);
}

::-webkit-scrollbar-thumb:hover {
  background-color: var(--accent);
}

::-webkit-scrollbar-corner {
  background: var(--bg);
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition: none !important;
    animation: none !important;
  }
}

a {
  color: inherit;
  text-decoration: none;
}

button {
  font-family: inherit;
  color: inherit;
  background: none;
  border: none;
  cursor: pointer;
}

.stage {
  position: relative;
  min-height: 100vh;
  width: 100%;
  background-color: var(--bg);
  background-image:
    linear-gradient(rgba(255, 255, 255, 0.05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.05) 1px, transparent 1px);
  background-size: 44px 44px;
  /* background-attachment: fixed removed - it forced the browser to
     repaint this whole grid pattern on every single scroll frame instead
     of letting it composite/scroll cheaply, which is a major source of
     the scroll lag reported on this page. The pattern now scrolls with
     the page instead of staying perfectly pinned in place - a small,
     barely-noticeable visual difference (the code comment above already
     flagged this as an accepted fallback behavior on browsers that don't
     support "fixed" attachment anyway, so this just makes that the
     behavior everywhere, on purpose, for the performance win). */
  display: flex;
  flex-direction: column;
}

/* Grid pattern folded directly into .stage's own background instead of
   a separate .stage::before pseudo-element (that's what used to bleed
   through card backgrounds - see git history/DEPLOY notes). A box's own
   background always paints behind its own content, no matter what -
   there's no stacking-context/z-index class of bug possible here at
   all, which is strictly more robust than the earlier z-index:-1 patch.
   background-attachment: fixed was later removed on purpose (see the
   comment right on that property above) - it used to silently fall back
   to plain scroll behavior on some browsers anyway, and forcing that
   scroll behavior everywhere fixed a real scroll-lag complaint. Same
   change mirrored into every page's own css/style.css copy - see
   build.js's header comment for why there's no single shared
   stylesheet. */

/* ---------- NAVBAR (glass) ---------- */

.navbar {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--glass-bg);
  /* blur radius cut from 22px to 12px - this bar sits sticky at the top
     of every page, so the browser re-computes this blur on every scroll
     frame the whole time you scroll; blur cost roughly scales with the
     radius squared, so this is a large, continuous saving in exchange for
     a barely-noticeable difference in how "frosted" it looks. */
  backdrop-filter: blur(12px) saturate(140%);
  -webkit-backdrop-filter: blur(12px) saturate(140%);
  border-bottom: 1px solid var(--border);
}

.nav-inner {
  width: 100%;
  padding: 0 clamp(24px, 5vw, 72px);
  height: 68px;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 24px;
}

/* logo */

.logo {
  display: inline-flex;
  align-items: center;
  justify-self: start;
  outline-offset: 6px;
  padding: 4px 0;
}

.logo:focus-visible {
  outline: 1px solid var(--accent);
}

.logo-mark {
  display: block;
  height: 22px;
  width: auto;
  flex: none;
  transition: transform 0.25s var(--ease), filter 0.25s var(--ease);
  filter: drop-shadow(0 0 0 rgba(255, 157, 46, 0));
}

.logo:hover .logo-mark {
  transform: translateY(-1px) scale(1.04);
  filter: drop-shadow(0 0 14px rgba(255, 157, 46, 0.35));
}

.logo:active .logo-mark {
  transform: translateY(0) scale(0.98);
}

/* center nav */

.nav-links {
  list-style: none;
  display: flex;
  align-items: center;
  gap: clamp(4px, 1.4vw, 20px);
  margin: 0;
  padding: 0;
  justify-self: center;
}

.nav-link {
  position: relative;
  display: inline-block;
  padding: 9px 13px 11px;
  font-size: 0.81rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-dim);
  transition: color 0.25s var(--ease), letter-spacing 0.25s var(--ease);
}

.nav-link-label {
  display: inline-block;
  transition: transform 0.25s var(--ease);
}

.nav-link::after {
  content: '';
  position: absolute;
  left: 13px;
  right: 13px;
  bottom: 5px;
  height: 2px;
  background: var(--accent);
  opacity: 0;
  transform: scaleX(0);
  transform-origin: center;
  transition: transform 0.25s var(--ease), opacity 0.25s var(--ease);
}

.nav-link:hover,
.nav-link:focus-visible {
  color: var(--text);
  letter-spacing: 0.055em;
}

.nav-link:hover .nav-link-label,
.nav-link:focus-visible .nav-link-label {
  transform: translateY(-1px);
}

.nav-link:hover::after,
.nav-link:focus-visible::after {
  opacity: 0.5;
  transform: scaleX(1);
}

.nav-link:focus-visible {
  outline: none;
}

.nav-link.is-active {
  color: var(--text);
  font-weight: 700;
}

.nav-link.is-active::after {
  opacity: 1;
  transform: scaleX(1);
}

/* avatar + name */

.nav-right {
  justify-self: end;
  position: relative;
  display: flex;
  align-items: center;
  gap: 6px;
}

/* cart icon (shared across all pages) */

.cart-btn {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  flex: none;
  border-radius: 50%;
  color: var(--text-dim);
  transition: background-color 0.25s var(--ease), color 0.25s var(--ease);
}

.cart-btn:hover {
  background-color: rgba(255, 255, 255, 0.045);
  color: var(--text);
}

.cart-btn:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 3px;
}

/* .cart-btn sets its own `display: flex` for layout (icon centering),
   which - being an ordinary author-stylesheet class rule - always wins
   over the browser's own `[hidden] { display: none }` default, since
   author rules beat UA rules regardless of selector specificity. Without
   this, any button/link carrying .cart-btn while also `hidden` (e.g. the
   notification bell before js/notifications.js decides whether to show
   it - see #notifBtn) renders anyway, as an empty circle, for every
   visitor including signed-out ones. */
.cart-btn[hidden] {
  display: none;
}

.cart-icon {
  width: 19px;
  height: 19px;
}

.cart-badge {
  position: absolute;
  top: 1px;
  right: 1px;
  min-width: 15px;
  height: 15px;
  padding: 0 3px;
  border-radius: 999px;
  background: var(--accent);
  color: #06070a;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  font-weight: 700;
  line-height: 15px;
  text-align: center;
}

.cart-badge[hidden] {
  display: none;
}

/* hamburger (mobile only) */

.hamburger-btn {
  display: none;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 5px;
  width: 44px;
  height: 44px;
  flex: none;
  border-radius: 50%;
  transition: background-color 0.25s var(--ease);
}

.hamburger-btn:hover {
  background-color: rgba(255, 255, 255, 0.045);
}

.hamburger-btn:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 3px;
}

.hamburger-line {
  display: block;
  width: 19px;
  height: 1.5px;
  background: var(--text);
  transition: transform 0.22s var(--ease), opacity 0.22s var(--ease);
}

.hamburger-btn[aria-expanded='true'] .hamburger-line:nth-child(1) {
  transform: translateY(6.5px) rotate(45deg);
}

.hamburger-btn[aria-expanded='true'] .hamburger-line:nth-child(2) {
  opacity: 0;
}

.hamburger-btn[aria-expanded='true'] .hamburger-line:nth-child(3) {
  transform: translateY(-6.5px) rotate(-45deg);
}

/* mobile dropdown menu */

.mobile-menu {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  display: flex;
  flex-direction: column;
  background: var(--glass-bg);
  /* same 22px -> 12px cut as .navbar above, same reason - mobile GPUs feel
     a large blur radius even more than desktop does. */
  backdrop-filter: blur(12px) saturate(140%);
  -webkit-backdrop-filter: blur(12px) saturate(140%);
  border-bottom: 1px solid var(--border);
  padding: 0 clamp(24px, 5vw, 72px);
  max-height: 0;
  overflow: hidden;
  opacity: 0;
  transition: max-height 0.28s var(--ease), opacity 0.2s var(--ease);
}

.mobile-menu.is-open {
  max-height: 320px;
  opacity: 1;
  padding-top: 6px;
  padding-bottom: 14px;
}

.mobile-link {
  padding: 14px 4px;
  border-radius: 6px;
  font-size: 0.95rem;
  font-weight: 500;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--text-dim);
  border-bottom: 1px solid var(--border-soft);
  transition: color 0.2s var(--ease), background-color 0.2s var(--ease);
}

.mobile-link:last-child {
  border-bottom: none;
}

.mobile-link:hover {
  color: var(--text);
  background-color: rgba(255, 255, 255, 0.04);
}

.mobile-link.is-active {
  color: var(--text);
  font-weight: 700;
}

.mobile-link:active {
  color: var(--accent);
}

.account-btn {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 4px 10px 4px 4px;
  border-radius: 20px;
  transition: background-color 0.25s var(--ease);
}

.account-btn:hover {
  background-color: rgba(255, 255, 255, 0.045);
}

.account-btn:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 3px;
}

.avatar-ring {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  overflow: hidden;
  border: 1px solid var(--avatar-empty-ring);
  background: var(--avatar-empty);
  transition: border-color 0.25s var(--ease), background 0.25s var(--ease), transform 0.25s var(--ease);
}

.account-btn:hover .avatar-ring {
  border-color: var(--accent-dim);
  transform: scale(1.06);
}

.avatar-glyph {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--text-faint);
}

.avatar-photo {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: none;
}

.avatar-ring[data-photo='1'] .avatar-glyph {
  display: none;
}

.avatar-ring[data-photo='1'] .avatar-photo {
  display: block;
}

.stage[data-auth='in'] .avatar-glyph {
  color: var(--accent);
  font-weight: 600;
}

.account-name {
  font-size: 0.83rem;
  font-weight: 600;
  color: var(--text);
  display: none;
  transition: color 0.25s var(--ease);
}

.account-btn:hover .account-name {
  color: var(--accent);
}

/* state: logged in */

.stage[data-auth='in'] .avatar-ring {
  border-color: var(--accent-dim);
  background: linear-gradient(145deg, rgba(255, 157, 46, 0.22) 0%, rgba(255, 157, 46, 0.03) 100%);
}

.stage[data-auth='in'] .account-name {
  display: inline;
}

/* popover */

.popover {
  position: absolute;
  top: calc(100% + 12px);
  right: 0;
  width: 248px;
  background: #101014;
  border: 1px solid var(--border);
  box-shadow: 0 20px 40px -12px rgba(0, 0, 0, 0.6);
  padding: 18px;
  opacity: 0;
  transform: translateY(-6px);
  pointer-events: none;
  transition: opacity 0.16s var(--ease), transform 0.16s var(--ease);
}

.popover.is-open {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

.popover-eyebrow {
  font-family: var(--font-mono);
  font-size: 0.65rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin: 0 0 10px;
}

.popover-title {
  font-size: 1rem;
  font-weight: 700;
  margin: 0 0 6px;
}

.popover-body {
  font-size: 0.8rem;
  line-height: 1.5;
  color: var(--text-dim);
  margin: 0 0 16px;
}

.popover-user {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 14px;
}

.popover-avatar {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: linear-gradient(145deg, #3a2c1a 0%, #1c1610 100%);
  border: 1px solid var(--accent-dim);
  flex: none;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.popover-avatar-initial {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--accent);
}

.popover-avatar-photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: none;
}

.popover-avatar[data-photo='1'] .popover-avatar-initial {
  display: none;
}

.popover-avatar[data-photo='1'] .popover-avatar-photo {
  display: block;
}

.popover-user-name {
  display: block;
  font-size: 0.85rem;
  font-weight: 600;
}

.popover-user-email {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--text-faint);
}

.popover-btn {
  width: 100%;
  padding: 10px 12px;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-align: center;
  transition: background 0.15s var(--ease), color 0.15s var(--ease), border-color 0.15s var(--ease);
}

.popover-btn:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 2px;
}

.popover-btn.primary {
  background: var(--accent);
  color: #1a1104;
  border: 1px solid var(--accent);
}

.popover-btn.primary:hover {
  background: #ffb257;
}

.popover-btn.ghost {
  background: transparent;
  color: var(--text-dim);
  border: 1px solid var(--border);
  margin-top: 8px;
}

.popover-btn.ghost:hover {
  color: var(--text);
  border-color: var(--text-faint);
}

.popover-menu {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-bottom: 4px;
}

.popover-link {
  display: block;
  padding: 8px 6px;
  font-size: 0.8rem;
  color: var(--text-dim);
  border-radius: 2px;
  transition: color 0.15s var(--ease), background 0.15s var(--ease);
}

.popover-link[hidden] {
  display: none;
}

.popover-link:disabled {
  color: var(--text-faint);
  cursor: default;
  pointer-events: none;
}

.popover-link:hover {
  color: var(--text);
  background: var(--border-soft);
}

.popover-link.is-accent {
  color: var(--accent);
  font-weight: 600;
}

.popover-link.is-accent:hover {
  background: rgba(255, 157, 46, 0.1);
}

.popover-divider {
  height: 1px;
  background: var(--border);
  margin: 10px 0;
  border: none;
}

/* ---------- AUTH MODAL (login / register) ---------- */

.auth-overlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(6, 5, 4, 0.5);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  opacity: 0;
  /* visibility (not just opacity/pointer-events) matters here: this class
     is reused by every modal on the site, including the always-present
     sign-in modal's hCaptcha widget. A third-party iframe (hCaptcha's
     checkbox) can re-assert its own `pointer-events: auto` internally,
     which un-does an ancestor's `pointer-events: none` for that iframe
     specifically - opacity/pointer-events alone were not enough to stop
     the CLOSED sign-in modal's captcha from still being clickable through
     whatever modal was actually open on top of it (both share this exact
     class, position and z-index). `visibility: hidden` has no such
     escape hatch - a descendant cannot un-hide itself - so it closes that
     gap for every .auth-overlay on the site, not just this one page.
     Delayed via the transition below so the existing opacity fade-out
     still plays in full before the element actually stops being
     interactive/hit-testable. */
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.22s var(--ease), visibility 0s linear 0.22s;
  /* Promotes this element's own blurred backdrop onto a persistent GPU
     layer instead of a plain (non-composited) paint. Without this, some
     browsers keep re-sampling/re-blurring the ENTIRE fixed, viewport-
     covering backdrop on every frame while content scrolls inside the
     modal sitting on top of it (e.g. a long Tools/Disciplines pill list),
     even though what's actually behind the overlay isn't changing - that
     was the remaining cause of choppy scrolling there after the modal
     itself (.au-section-modal below) was already promoted separately. */
  will-change: backdrop-filter;
}

.auth-overlay.is-open {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity 0.22s var(--ease), visibility 0s linear 0s;
}

.auth-modal {
  width: 100%;
  max-width: 400px;
  background: #121216;
  border: 1px solid var(--border);
  border-radius: 22px;
  box-shadow: 0 30px 70px -20px rgba(0, 0, 0, 0.75);
  padding: 30px 30px 28px;
  position: relative;
  transform: translateY(10px) scale(0.98);
  transition: transform 0.3s var(--ease);
}

.auth-modal--tall {
  max-height: min(88vh, 720px);
  overflow-y: auto;
}

.auth-overlay.is-open .auth-modal {
  transform: translateY(0) scale(1);
}

.auth-close {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-faint);
  font-size: 1.2rem;
  line-height: 1;
  border-radius: 50%;
  transition: color 0.2s var(--ease), background-color 0.2s var(--ease);
}

.auth-close:hover {
  color: var(--text);
  background-color: rgba(255, 255, 255, 0.06);
}

/* brand row */

.auth-brand {
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 4px 0 24px;
}

.auth-brand-logo {
  height: 30px;
  width: auto;
  display: block;
}

/* segmented pill switch */

.auth-switch {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  background: #1a1a20;
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 4px;
}

.auth-switch-thumb {
  position: absolute;
  top: 4px;
  left: 4px;
  width: calc(50% - 4px);
  height: calc(100% - 8px);
  background: #f1efe8;
  border-radius: 9px;
  transform: translateX(0);
  transition: transform 0.32s var(--ease);
  will-change: transform;
}

.auth-modal[data-mode='signup'] .auth-switch-thumb {
  transform: translateX(100%);
}

.auth-switch-btn {
  position: relative;
  z-index: 1;
  padding: 13px 12px;
  font-family: var(--font-mono);
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-align: center;
  color: var(--text-dim);
  transition: color 0.25s var(--ease);
}

.auth-switch-btn.is-active {
  color: #14141a;
}

.auth-switch-btn:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 2px;
  border-radius: 8px;
}

/* heading + copy */

.auth-panel {
  margin-top: 22px;
}

.auth-heading {
  font-family: var(--font-display);
  font-size: 1.7rem;
  font-weight: 800;
  line-height: 1.18;
  margin: 0 0 8px;
  white-space: nowrap;
}

.auth-heading-accent {
  color: var(--accent);
  font-style: italic;
  font-weight: 800;
}

.auth-subcopy {
  font-size: 0.85rem;
  line-height: 1.5;
  color: var(--text-dim);
  margin: 0 0 22px;
}

/* form */

.auth-form {
  display: flex;
  flex-direction: column;
}

.auth-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}

.auth-label {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin: 12px 0 6px;
}

.auth-label-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 12px 0 6px;
}

.auth-label-row .auth-label {
  margin: 0;
}

.auth-forgot-link {
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--text-faint);
  transition: color 0.2s var(--ease);
}

.auth-forgot-link:hover {
  color: var(--accent);
}

.auth-forgot-link:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}

.auth-input {
  width: 100%;
  padding: 12px 14px;
  background: #18181e;
  border: 1px solid transparent;
  border-radius: 10px;
  color: var(--text);
  font-family: var(--font-display);
  font-size: 0.88rem;
  transition: border-color 0.2s var(--ease), box-shadow 0.2s var(--ease);
}

.auth-input::placeholder {
  color: var(--text-faint);
}

.auth-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(255, 157, 46, 0.14);
}

/* Chrome/Edge/Safari autofill (a saved email/password, address or payment
   autofill) forcibly repaints an input's background AND text color with
   its own yellow/light-blue styling the moment it's autofilled - this
   completely ignores .auth-input's own `background`/`color` above, and a
   real `background-color` override on `:-webkit-autofill` gets ignored
   by the browser too (this is the "browser overrides our style" bug
   people notice on login/signup/checkout forms). The fix is the standard
   trick: an inset box-shadow big enough to cover the whole field is NOT
   one of the properties the browser locks, so painting our own dark
   color that way (instead of `background-color`) actually sticks, and
   `-webkit-text-fill-color` forces the text back to our own color too.
   The absurdly long `transition` delay defeats Chrome's own animation
   that reveals the yellow tint after a short delay. Applies everywhere
   .auth-input is used (login/signup, checkout, profile editing, "Start a
   Project", tutorials/add, etc.) since they all share this one class. */
.auth-input:-webkit-autofill,
.auth-input:-webkit-autofill:hover,
.auth-input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--text);
  -webkit-box-shadow: 0 0 0 1000px #18181e inset;
  box-shadow: 0 0 0 1000px #18181e inset;
  transition: background-color 600000s 0s, color 600000s 0s;
}

/* Belt-and-suspenders for the <select> popup on top of `color-scheme: dark`
   above (root of the file) - explicit dark colors on every <option> site-
   wide, in case a browser only partially dark-themes the native dropdown. */
select option {
  background: #18181e;
  color: var(--text);
}

.auth-textarea {
  min-height: 110px;
  resize: vertical;
  font-family: var(--font-display);
  line-height: 1.5;
}

.freelancer-guidelines {
  background: #18181e;
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 16px 18px;
  margin-bottom: 18px;
}

.freelancer-guidelines p {
  font-size: 0.84rem;
  color: var(--text-dim);
  margin: 0 0 10px;
}

.freelancer-guidelines-list {
  margin: 0 0 10px;
  padding-left: 18px;
  font-size: 0.82rem;
  color: var(--text-dim);
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.freelancer-guidelines-note {
  font-size: 0.76rem;
  color: var(--text-faint);
  margin: 0 !important;
}

/* show/hide password */

.auth-password-wrap {
  position: relative;
}

.auth-password-wrap .auth-input {
  padding-right: 46px;
}

.auth-password-toggle {
  position: absolute;
  top: 50%;
  right: 4px;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 8px;
  color: var(--text-faint);
  transition: color 0.2s var(--ease), background-color 0.2s var(--ease);
}

.auth-password-toggle:hover {
  color: var(--text-dim);
  background-color: rgba(255, 255, 255, 0.06);
}

.auth-password-toggle:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 2px;
}

.auth-password-toggle.is-visible {
  color: var(--accent);
}

.icon-eye {
  display: block;
  width: 18px;
  height: 18px;
  background-color: currentColor;
  -webkit-mask: url('/assets/icons/eye.svg') no-repeat center / contain;
  mask: url('/assets/icons/eye.svg') no-repeat center / contain;
}

.auth-password-toggle.is-visible .icon-eye {
  -webkit-mask-image: url('/assets/icons/eye-slash.svg');
  mask-image: url('/assets/icons/eye-slash.svg');
}

.auth-error {
  font-size: 0.78rem;
  line-height: 1.4;
  color: var(--danger);
  background: rgba(255, 107, 94, 0.08);
  border: 1px solid rgba(255, 107, 94, 0.25);
  border-radius: 8px;
  padding: 9px 11px;
  margin-top: 12px;
}

.auth-success {
  font-size: 0.78rem;
  line-height: 1.4;
  color: var(--ok);
  background: rgba(52, 211, 153, 0.08);
  border: 1px solid rgba(52, 211, 153, 0.25);
  border-radius: 8px;
  padding: 9px 11px;
  margin-top: 12px;
}

.auth-submit {
  margin-top: 18px;
  padding: 13px 16px;
  border-radius: 12px;
  background: var(--accent);
  color: #1a1104;
  font-size: 0.83rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  box-shadow: 0 16px 32px -12px rgba(255, 157, 46, 0.5);
  transition: transform 0.2s var(--ease), box-shadow 0.2s var(--ease), filter 0.2s var(--ease);
}

.auth-submit-arrow {
  transition: transform 0.2s var(--ease);
}

.auth-submit:hover {
  filter: brightness(1.05);
  transform: translateY(-1px);
  box-shadow: 0 20px 38px -12px rgba(255, 157, 46, 0.6);
}

.auth-submit:hover .auth-submit-arrow {
  transform: translateX(3px);
}

.auth-submit:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 2px;
}

.auth-submit:disabled {
  opacity: 0.6;
  cursor: default;
  transform: none;
}

/* google */

.auth-divider {
  height: 1px;
  background: var(--border);
  margin: 20px 0 16px;
}

.auth-google-btn {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 11px 16px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: #18181e;
  color: var(--text);
  font-size: 0.85rem;
  font-weight: 600;
  transition: background-color 0.2s var(--ease), border-color 0.2s var(--ease);
}

.auth-google-btn:hover {
  background: #1e1e25;
  border-color: var(--text-faint);
}

.auth-google-btn:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 2px;
}

.google-icon {
  flex: none;
  display: block;
}

/* footer lines */

.auth-legal {
  margin: 14px 0 0;
  font-size: 0.72rem;
  line-height: 1.5;
  color: var(--text-faint);
  text-align: center;
}

.auth-legal a {
  color: var(--text-dim);
  text-decoration: underline;
}

.auth-legal a:hover {
  color: var(--text);
}

.auth-consent-row {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin: 4px 0 2px;
  font-size: 0.72rem;
  line-height: 1.5;
  color: var(--text-faint);
  cursor: pointer;
}

.auth-consent-checkbox {
  flex-shrink: 0;
  width: 15px;
  height: 15px;
  margin-top: 2px;
  accent-color: var(--accent);
  cursor: pointer;
}

.auth-consent-row a {
  color: var(--text-dim);
  text-decoration: underline;
}

.auth-consent-row a:hover {
  color: var(--text);
}

@media (max-width: 480px) {
  .auth-modal {
    padding: 24px 20px 24px;
    border-radius: 18px;
  }

  .auth-row {
    grid-template-columns: 1fr;
  }
}

/* ---------- shared: wide modal + custom select dropdown ----------
   Added for the "Start a Project" modal (partials/project-inquiry-modal.html,
   see js/site-forms.js) - a full-width modifier and a from-scratch <select>
   re-skin, both promoted to shared chrome since the project inquiry modal
   is injected on every page. If you change one of these, mirror the
   change in every other page's own copy (same rule as the rest of this
   "shared chrome" block - see the comment at the top of this file). */

.auth-modal--wide {
  max-width: 600px;
}

/* A native <select>'s closed box happily takes .auth-input's dark
   styling, but its OPEN popup is OS/browser chrome - `color-scheme: dark`
   (root of this file) gets it part of the way, but the browser still
   paints its own blue highlight on the hovered/selected row and there is
   no CSS hook to change that. So any <select> that opts into this (see
   enhanceSelect() in js/site-forms.js) gets visually hidden via
   `.select-native` below - it stays in the DOM as the real source of
   truth for .value - and a fully custom trigger button + option list is
   layered on top instead, themed with our own accent color. */
.select-native {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.select-wrap {
  position: relative;
}

.select-trigger {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  text-align: left;
  cursor: pointer;
}

.select-value {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.select-value--placeholder {
  color: var(--text-faint);
}

.select-arrow {
  flex: none;
  width: 8px;
  height: 8px;
  border-right: 1px solid var(--text-dim);
  border-bottom: 1px solid var(--text-dim);
  transform: rotate(45deg) translateY(-3px);
  transition: transform 0.2s var(--ease), border-color 0.2s var(--ease);
}

.select-wrap.is-open .select-arrow {
  transform: rotate(-135deg) translateY(1px);
  border-color: var(--accent);
}

.select-list {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(100% + 6px);
  z-index: 20;
  background: #18181e;
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 6px;
  max-height: 220px;
  overflow-y: auto;
  box-shadow: 0 20px 40px -12px rgba(0, 0, 0, 0.6);
}

.select-option {
  padding: 9px 10px;
  border-radius: 7px;
  font-family: var(--font-display);
  font-size: 0.88rem;
  color: var(--text);
  cursor: pointer;
}

.select-option:hover,
.select-option.is-active {
  background: rgba(255, 157, 46, 0.14);
}

.select-option[aria-selected='true'] {
  color: var(--accent);
  font-weight: 600;
}

/* ---------- shared: "Start a Project" modal extras ----------
   Added back alongside the modal itself (partials/project-inquiry-modal.html,
   js/site-forms.js) when "Start a Project" reverted from its own page back
   to a popup. Mirrors the "success panel" pattern already used elsewhere
   (tutorials/add's .admin-gate, the old /start-project page's
   .sp-success-panel) but under its own class names since this modal is
   shared on every page and shouldn't depend on the admin-only .admin-gate
   styling. If you change one of these, mirror the change in every other
   page's own copy (same rule as the rest of this "shared chrome" block). */

/* .auth-form sets `display: flex`, which (being an author-stylesheet rule)
   otherwise wins over the browser's own `[hidden] { display: none }` -
   without this, `someForm.hidden = true` on anything carrying .auth-form
   silently does nothing. */
.auth-form[hidden] {
  display: none;
}

.project-success-panel {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 180px;
  text-align: center;
  color: var(--text-dim);
  border: 1px solid rgba(52, 211, 153, 0.3);
  border-radius: 16px;
  background: rgba(52, 211, 153, 0.05);
  padding: 32px 24px;
}

.project-success-panel[hidden] {
  display: none;
}

.project-success-panel-title {
  font-size: 1.1rem;
  font-weight: 700;
  color: var(--text);
  margin: 0;
}

.project-success-panel-text {
  font-size: 0.9rem;
  line-height: 1.5;
  margin: 0;
  max-width: 420px;
}

.project-optional {
  text-transform: none;
  font-weight: 400;
  color: var(--text-faint);
  letter-spacing: 0;
}

/* ---------- main content / hero ---------- */

.main-content {
  flex: 1;
}

@media (max-width: 720px) {
  .nav-links {
    display: none;
  }
  .nav-inner {
    grid-template-columns: auto 1fr;
  }
  .account-name {
    display: none !important;
  }
  .hamburger-btn {
    display: flex;
  }
  .popover {
    width: min(280px, calc(100vw - 48px));
  }
}

/* ---------- buttons (shared, copied from css/style.css) ---------- */

.hero-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 16px 26px;
  border-radius: 10px;
  overflow: hidden;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  transition: transform 0.2s var(--ease), background-color 0.2s var(--ease), border-color 0.2s var(--ease), filter 0.2s var(--ease), box-shadow 0.2s var(--ease);
}

.hero-btn[hidden] {
  display: none;
}

.hero-btn::before {
  content: '';
  position: absolute;
  top: 0;
  left: -60%;
  width: 40%;
  height: 100%;
  background: linear-gradient(120deg, transparent, rgba(255, 255, 255, 0.35), transparent);
  transform: skewX(-20deg);
  transition: left 0.65s var(--ease-premium);
  pointer-events: none;
}

.hero-btn:hover::before {
  left: 130%;
}

.hero-btn.primary {
  background: var(--accent);
  color: #1a1104;
  box-shadow: 0 20px 40px -18px rgba(255, 157, 46, 0.55);
}

.hero-btn.primary:hover {
  transform: translateY(-1px);
  filter: brightness(1.06);
  box-shadow: 0 24px 46px -16px rgba(255, 157, 46, 0.65);
}

.hero-btn-arrow {
  transition: transform 0.2s var(--ease);
}

.hero-btn.primary:hover .hero-btn-arrow {
  transform: translateX(3px);
}

.hero-btn.outline {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text);
}

.hero-btn.outline:hover {
  border-color: var(--text-faint);
  background: rgba(255, 255, 255, 0.03);
}

.hero-btn:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 2px;
}

/* ---------- footer ---------- */

.footer {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: #000000;
  border-top: 1px solid var(--border);
  padding: 40px clamp(24px, 5vw, 72px) 0;
}

.footer-inner {
  position: relative;
  z-index: 1;
  width: 100%;
}

.footer-top {
  display: grid;
  grid-template-columns: minmax(220px, 320px) 1fr;
  gap: 48px;
  padding-bottom: 32px;
}

.footer-brand {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 13px;
}

.footer-logo {
  display: inline-flex;
  align-items: center;
  gap: 9px;
}

.footer-logo-mark {
  width: 22px;
  height: 22px;
  object-fit: contain;
}

.footer-logo-word {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 0.98rem;
  letter-spacing: -0.01em;
  color: var(--text);
}

.footer-tagline {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 0.82rem;
  line-height: 1.6;
  color: var(--text-faint);
  margin: 0;
  max-width: 300px;
}

.footer-social {
  display: flex;
  gap: 8px;
  margin-top: 2px;
}

.footer-social-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 8px;
  border: 1px solid var(--border);
  color: var(--text-faint);
  transition: border-color 0.25s var(--ease), color 0.25s var(--ease), transform 0.25s var(--ease-premium);
}

.footer-social-link:hover {
  border-color: var(--accent-dim);
  color: var(--accent);
  transform: translateY(-2px);
}

.footer-social-link svg {
  width: 14px;
  height: 14px;
}

.footer-links {
  display: grid;
  grid-template-columns: repeat(3, minmax(110px, 150px));
  gap: 28px;
  justify-content: end;
}

.footer-col {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
}

.footer-col-title {
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin: 0 0 4px;
}

.footer-link {
  font-family: var(--font-display);
  font-size: 0.82rem;
  color: var(--text-faint);
  transition: color 0.2s var(--ease), transform 0.2s var(--ease-premium);
}

.footer-link:hover {
  color: var(--text);
  transform: translateX(2px);
}

.footer-bottom {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 16px 0;
  border-top: 1px solid var(--border);
  flex-wrap: wrap;
}

.footer-copyright,
.footer-signature {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--text-faint);
  margin: 0;
}

.footer-watermark {
  display: block;
  text-align: center;
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(1.8rem, 5vw, 3.2rem);
  line-height: 1;
  letter-spacing: -0.01em;
  color: transparent;
  -webkit-text-stroke: 1px var(--border);
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.025), transparent 90%);
  -webkit-background-clip: text;
  background-clip: text;
  pointer-events: none;
  user-select: none;
  margin-top: 2px;
  padding-bottom: 14px;
  overflow: hidden;
  white-space: nowrap;
}

@media (max-width: 900px) {
  .footer-top {
    grid-template-columns: 1fr;
    gap: 40px;
  }
  .footer-links {
    justify-content: start;
    grid-template-columns: repeat(3, minmax(100px, 1fr));
    gap: 24px;
  }
  .footer-brand {
    max-width: 420px;
  }
}

@media (max-width: 560px) {
  .footer {
    padding-top: 36px;
  }
  .footer-links {
    grid-template-columns: repeat(2, 1fr);
  }
  .footer-bottom {
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
  }
}
/* ---------- related products: card (copied from marketplace/css/style.css) ---------- */

.mp-product-card {
  position: relative;
  display: flex;
  flex-direction: column;
  border-radius: 14px;
  border: 1px solid var(--border);
  background: #0e0e12;
  overflow: hidden;
  color: var(--text);
  opacity: 0;
  transform: translateY(32px);
  transition: opacity 0.7s var(--ease-premium), transform 0.5s var(--ease-premium), border-color 0.3s var(--ease);
}

/* The card is a plain div now (not the link itself) so the wishlist heart
   button can sit beside the link instead of nested inside it - a <button>
   inside an <a> is invalid HTML and flaky across browsers/screen readers.
   `display: contents` on the link means its children (thumb + body) still
   lay out exactly as if they were direct children of .mp-product-card, so
   none of the flex/grid rules below needed to change. */
.mp-product-card-link {
  display: contents;
  color: inherit;
  text-decoration: none;
}

.mp-product-wishlist-btn {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 2;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(8, 8, 10, 0.55);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.14);
  transition: background-color 0.2s var(--ease), border-color 0.2s var(--ease), color 0.2s var(--ease), transform 0.15s var(--ease);
}

.mp-product-wishlist-btn:hover {
  border-color: var(--accent-dim);
}

.mp-product-wishlist-btn:active {
  transform: scale(0.9);
}

.mp-product-wishlist-btn:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 2px;
}

.mp-product-heart-icon {
  width: 15px;
  height: 15px;
  flex: none;
}

.mp-product-heart-icon.is-popping {
  animation: mpHeartPop 0.4s var(--ease-premium);
}

@keyframes mpHeartPop {
  0% { transform: scale(1); }
  40% { transform: scale(1.35); }
  100% { transform: scale(1); }
}

.mp-product-wishlist-btn.is-active {
  background: rgba(255, 157, 46, 0.18);
  border-color: var(--accent);
  color: var(--accent);
}

.mp-product-wishlist-btn.is-active .mp-product-heart-icon {
  fill: var(--accent);
}

.mp-product-card.is-visible {
  opacity: 1;
  transform: translateY(0);
}

.mp-product-card:hover {
  border-color: var(--accent-dim);
  transform: translateY(-4px);
}

.mp-product-card.is-visible:hover {
  transform: translateY(-4px);
}

.mp-product-thumb {
  position: relative;
  /* 1:1 - see marketplace/css/style.css's own .mp-product-thumb comment. */
  aspect-ratio: 1 / 1;
  background: linear-gradient(155deg, #1a1a20 0%, #0c0c10 62%);
  overflow: hidden;
}

.mp-product-thumb-grid {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(255, 255, 255, 0.05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.05) 1px, transparent 1px);
  background-size: 24px 24px;
  -webkit-mask-image: linear-gradient(to top, black, transparent 70%);
  mask-image: linear-gradient(to top, black, transparent 70%);
  opacity: 0.6;
  transition: opacity 0.35s var(--ease);
}

.mp-product-card:hover .mp-product-thumb-grid {
  opacity: 1;
}

.mp-product-body {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 14px 16px 16px;
}

.mp-product-top-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}

.mp-product-name {
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mp-product-price {
  flex: none;
  font-family: var(--font-mono);
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--accent);
  white-space: nowrap;
}

.mp-product-author {
  display: flex;
  align-items: center;
  gap: 8px;
}

.mp-product-avatar {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  overflow: hidden;
  border: 1px solid var(--avatar-empty-ring);
  background: var(--avatar-empty);
}

.mp-product-avatar-glyph {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  color: var(--text-faint);
}

.mp-product-avatar-photo {
  display: none;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.mp-product-avatar[data-photo='1'] .mp-product-avatar-glyph {
  display: none;
}

.mp-product-avatar[data-photo='1'] .mp-product-avatar-photo {
  display: block;
}

.mp-product-author-name {
  font-size: 0.78rem;
  color: var(--text-dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mp-product-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.mp-product-tag {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-faint);
  padding: 3px 8px;
  border-radius: 999px;
  border: 1px solid var(--border);
}


/* ---------- author profile page ---------- */

.au-page {
  padding: 32px clamp(24px, 5vw, 72px) 90px;
  max-width: 1180px;
  margin: 0 auto;
}

.au-top-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 28px;
}

.au-back {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--text-dim);
  margin-bottom: 0;
  transition: color 0.2s var(--ease), transform 0.2s var(--ease);
}

.au-back:hover {
  color: var(--accent);
  transform: translateX(-2px);
}

.au-copy-link-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 13px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--glass-bg);
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 0.74rem;
  font-weight: 600;
  cursor: pointer;
  transition: color 0.2s var(--ease), border-color 0.2s var(--ease), background 0.2s var(--ease);
}

.au-copy-link-btn:hover {
  color: var(--text);
  border-color: var(--accent-dim);
}

.au-copy-link-btn[hidden] {
  display: none;
}

.au-copy-link-btn.is-copied {
  color: var(--ok);
  border-color: var(--ok);
}

/* gate: loading / not found */

.au-gate {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 360px;
  text-align: center;
  color: var(--text-dim);
}

.au-gate[hidden] {
  display: none;
}

.au-gate-title {
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--text);
  margin: 0;
}

.au-gate-text {
  font-size: 0.88rem;
  margin: 0;
  max-width: 380px;
}

/* hero */

.au-hero {
  display: flex;
  align-items: center;
  gap: 28px;
  padding: 32px clamp(20px, 4vw, 40px);
  border-radius: 20px;
  border: 1px solid var(--border);
  background: linear-gradient(155deg, #15151b 0%, #0b0b0f 68%);
  position: relative;
  overflow: hidden;
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.6s var(--ease-premium), transform 0.6s var(--ease-premium);
}

.au-hero[hidden] {
  display: none;
}

.au-hero.is-visible {
  opacity: 1;
  transform: translateY(0);
}

.au-hero::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(255, 255, 255, 0.05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.05) 1px, transparent 1px);
  background-size: 34px 34px;
  -webkit-mask-image: radial-gradient(circle at 12% 50%, black, transparent 68%);
  mask-image: radial-gradient(circle at 12% 50%, black, transparent 68%);
  opacity: 0.7;
  pointer-events: none;
}

.au-avatar {
  position: relative;
  z-index: 1;
  width: 96px;
  height: 96px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  overflow: hidden;
  border: 1px solid var(--avatar-empty-ring);
  background: var(--avatar-empty);
  box-shadow: 0 0 0 4px rgba(255, 157, 46, 0.08);
}

.au-avatar-glyph {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 2.1rem;
  color: var(--text-faint);
}

.au-avatar-photo {
  display: none;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.au-avatar[data-photo='1'] .au-avatar-glyph {
  display: none;
}

.au-avatar[data-photo='1'] .au-avatar-photo {
  display: block;
}

.au-hero-body {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
}

.au-eyebrow {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
}

.au-name-row {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

.au-name {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(1.6rem, 3vw, 2.2rem);
  line-height: 1.1;
  margin: 0;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.au-official-badge {
  display: inline-flex;
  align-items: center;
  flex: none;
  padding: 5px 12px;
  border-radius: 999px;
  background: rgba(255, 157, 46, 0.14);
  border: 1px solid rgba(255, 157, 46, 0.4);
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--accent);
}

.au-official-badge[hidden] {
  display: none;
}

.au-stats {
  display: flex;
  gap: 22px;
  flex-wrap: wrap;
  margin-top: 4px;
}

.au-stat {
  display: flex;
  align-items: baseline;
  gap: 6px;
}

.au-stat-value {
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 1.05rem;
  color: var(--text);
}

.au-stat-label {
  font-size: 0.78rem;
  color: var(--text-dim);
}

/* products section */

.au-products {
  margin-top: 56px;
}

.au-products-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 20px;
}

.au-section-title {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 1.3rem;
  margin: 0;
  color: var(--text);
}

.au-products-count {
  font-family: var(--font-mono);
  font-size: 0.8rem;
  color: var(--text-dim);
}

.au-products-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 20px;
}

.au-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 200px;
  text-align: center;
  color: var(--text-dim);
  border: 1px dashed var(--border);
  border-radius: 14px;
}

.au-empty[hidden] {
  display: none;
}

.au-empty-title {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--text);
  margin: 0;
}

.au-empty-text {
  font-size: 0.85rem;
  margin: 0;
}

.au-portfolio-gate-btn {
  align-self: center;
  margin-top: 8px;
}

@media (max-width: 640px) {
  .au-hero {
    flex-direction: column;
    align-items: flex-start;
    text-align: left;
  }
  .au-avatar {
    width: 78px;
    height: 78px;
  }
}

/* ---------- profile: bio / tools / languages / socials ---------- */

.au-bio {
  font-size: 0.92rem;
  line-height: 1.55;
  color: var(--text-dim);
  margin: 0;
  max-width: 560px;
}

.au-bio[hidden] {
  display: none;
}

/* .au-bio is now a <div> holding one or more <p>s written by
   renderBioHtml() (js/main.js) - one per blank-line-separated paragraph in
   the bio someone typed. No bold/italic markup - tried it, looked bad,
   dropped it; just paragraphs. */
.au-bio p {
  margin: 0 0 12px;
}

.au-bio p:last-child {
  margin-bottom: 0;
}

.au-meta {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin-top: 2px;
}

.au-meta-group {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.au-meta-group[hidden] {
  display: none;
}

.au-meta-label {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.au-chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

/* renderProfileExtras() (marketplace/author/js/main.js) sets
   #auDisciplines.hidden = true on a failed/missing profile load - without
   this, .au-chip-row's own `display: flex` wins over the browser's
   `[hidden] { display: none }` default and the (empty) row stays laid
   out instead of collapsing. */
.au-chip-row[hidden] {
  display: none;
}

.au-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--text-dim);
  padding: 4px 10px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.02);
}

.au-chip-icon {
  width: 13px;
  height: 13px;
  border-radius: 2px;
  flex: none;
  object-fit: contain;
}

/* Tool app-badge icon (Photoshop/Blender/etc.) and language flag icon -
   real inline SVG (see js/profile-meta.js), sized to sit neatly inside a
   chip next to its text label. Different aspect ratios (tools are square,
   flags are 20:14) so each gets its own fixed dimension and lets the SVG's
   own viewBox handle the rest. */
.au-chip-tool-icon {
  width: 15px;
  height: 15px;
  border-radius: 3px;
  overflow: hidden;
  flex: none;
  line-height: 0;
}

.au-chip-tool-icon svg {
  width: 100%;
  height: 100%;
  display: block;
}

.au-chip-flag-icon {
  width: 16px;
  height: 11.2px;
  border-radius: 2px;
  overflow: hidden;
  flex: none;
  line-height: 0;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.08);
}

.au-chip-flag-icon svg {
  width: 100%;
  height: 100%;
  display: block;
}

/* discipline tags - same chip shape, accent-tinted to stand apart from
   the muted tools/languages chips. */
.au-disciplines {
  margin-top: 6px;
}

.au-disciplines[hidden] {
  display: none;
}

.au-disciplines .au-chip {
  color: var(--accent);
  border-color: rgba(255, 157, 46, 0.35);
  background: rgba(255, 157, 46, 0.08);
}

.au-socials {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.au-social-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.03);
  /* text-dim, not text-faint - the icon is the whole point of this button,
     so it needs to actually read at a glance instead of all but
     disappearing against the dark background until hovered. */
  color: var(--text-dim);
  transition: border-color 0.25s var(--ease), color 0.25s var(--ease), transform 0.25s var(--ease-premium);
}

.au-social-link:hover {
  border-color: var(--accent-dim);
  color: var(--accent);
  transform: translateY(-2px);
}

.au-social-link svg,
.au-social-link img {
  width: 17px;
  height: 17px;
  object-fit: contain;
}

.au-social-link-text {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 700;
}

/* Large, unmissable contact CTA - distinct from the small labeled
   social-icon row up in .au-meta (that row is the full list; this picks
   just the single best entry - email > discord > website > first - as a
   one-click shortcut). Hidden entirely when the profile has no socials. */
.au-contact-btn {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  align-self: flex-start;
  margin-top: 6px;
  padding: 13px 22px;
  border-radius: 10px;
  background: var(--accent);
  color: #17110a;
  font-family: var(--font-mono);
  font-size: 0.82rem;
  font-weight: 700;
  transition: transform 0.2s var(--ease-premium), box-shadow 0.2s var(--ease);
}

.au-contact-btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 10px 26px rgba(255, 157, 46, 0.28);
}

.au-contact-btn[hidden] {
  display: none;
}

/* ---------- profile: tabs (Listings / Portfolio) ---------- */

.au-tabs {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin: 40px 0 24px;
}

.au-tabs[hidden] {
  display: none;
}

.au-tab-btn {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--text-dim);
  padding: 9px 18px;
  border-radius: 999px;
  border: 1px solid var(--border);
  transition: border-color 0.2s var(--ease), color 0.2s var(--ease), background-color 0.2s var(--ease);
}

.au-tab-btn:hover {
  border-color: var(--text-faint);
  color: var(--text);
}

.au-tab-btn.is-active {
  border-color: var(--accent-dim);
  color: var(--accent);
  background: rgba(255, 157, 46, 0.08);
}

/* ---------- profile: portfolio grid ---------- */

.au-portfolio-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 20px;
}

.au-portfolio-thumb {
  position: relative;
  aspect-ratio: 4 / 3;
  background: linear-gradient(155deg, #1a1a20 0%, #0c0c10 62%);
  transition: transform 0.4s var(--ease-premium);
}

.au-portfolio-piece-badge {
  position: absolute;
  bottom: 10px;
  right: 10px;
  z-index: 2;
  font-family: var(--font-mono);
  font-size: 0.66rem;
  font-weight: 600;
  padding: 3px 8px;
  border-radius: 6px;
  background: rgba(8, 8, 10, 0.65);
  color: var(--text);
  border: 1px solid rgba(255, 255, 255, 0.12);
}

.au-portfolio-item:hover .au-portfolio-thumb {
  transform: scale(1.03);
}

.au-portfolio-item-caption {
  /* It's a <p> - without this the browser's default ~1em top/bottom
     margin on <p> added roughly 25px of extra height that .padding below
     didn't account for. Harmless on its own, but it's exactly what made
     a portfolio piece card render taller than a listing card once both
     started sharing the same markup/CSS - see .au-listing-item-caption. */
  margin: 0;
  padding: 10px 12px;
  font-size: 0.8rem;
  color: var(--text-dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---------- profile: portfolio lightbox ---------- */

.au-lightbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: rgba(4, 4, 6, 0.92);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  overflow: hidden;
}

.au-lightbox.is-open {
  display: flex;
}

.au-lightbox-stage {
  max-width: min(94vw, 1800px);
  max-height: 82vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

.au-lightbox-img {
  max-width: 100%;
  max-height: 82vh;
  border-radius: 10px;
  object-fit: contain;
}

.au-lightbox-frame {
  width: min(88vw, 960px);
  aspect-ratio: 16 / 9;
  max-height: 78vh;
  border: 0;
  border-radius: 10px;
  background: #000;
}

.au-lightbox-frame[hidden],
.au-lightbox-img[hidden] {
  display: none;
}

.au-portfolio-video-badge {
  position: absolute;
  bottom: 10px;
  left: 10px;
  z-index: 2;
  width: 24px;
  height: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.6rem;
  border-radius: 50%;
  background: rgba(8, 8, 10, 0.65);
  color: var(--accent);
  border: 1px solid rgba(255, 255, 255, 0.12);
}

.pa-video-tag {
  position: absolute;
  bottom: 6px;
  left: 6px;
  font-family: var(--font-mono);
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--accent);
  background: rgba(8, 8, 10, 0.72);
  border-radius: 999px;
  padding: 3px 8px;
}

.au-lightbox-close {
  position: absolute;
  top: 20px;
  right: 24px;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.6rem;
  line-height: 1;
  color: var(--text-dim);
  border: 1px solid var(--border);
  background: rgba(15, 15, 19, 0.6);
  transition: color 0.2s var(--ease), border-color 0.2s var(--ease);
}

.au-lightbox-close:hover {
  color: var(--text);
  border-color: var(--text-faint);
}

.au-lightbox-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 44px;
  height: 44px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.8rem;
  line-height: 1;
  color: var(--text-dim);
  border: 1px solid var(--border);
  background: rgba(15, 15, 19, 0.6);
  transition: color 0.2s var(--ease), border-color 0.2s var(--ease);
}

.au-lightbox-nav:hover {
  color: var(--text);
  border-color: var(--text-faint);
}

.au-lightbox-nav[hidden] {
  display: none;
}

.au-lightbox-prev {
  left: 20px;
}

.au-lightbox-next {
  right: 20px;
}

.au-lightbox-caption {
  margin-top: 14px;
  font-size: 0.85rem;
  color: var(--text-dim);
  max-width: 70vw;
  text-align: center;
}

.au-lightbox-caption[hidden] {
  display: none;
}

.au-lightbox-counter {
  margin-top: 6px;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--text-faint);
}

.au-lightbox-counter[hidden] {
  display: none;
}

@media (max-width: 640px) {
  .au-lightbox-nav {
    width: 36px;
    height: 36px;
    font-size: 1.4rem;
  }
  .au-lightbox-prev {
    left: 8px;
  }
  .au-lightbox-next {
    right: 8px;
  }
  .au-lightbox-close {
    top: 12px;
    right: 12px;
  }
}

/* ---------- cookie consent banner (shared chrome, see
   partials/cookie-banner.html + js/cookie-consent.js - if you change one
   of those, mirror the change here too). ---------- */

.cookie-banner {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 200;
  padding: 0 clamp(16px, 4vw, 32px) clamp(16px, 4vw, 32px);
  transform: translateY(120%);
  opacity: 0;
  transition: transform 0.4s var(--ease-premium), opacity 0.3s var(--ease);
  pointer-events: none;
}

.cookie-banner[hidden] {
  display: none;
}

.cookie-banner.is-visible {
  transform: translateY(0);
  opacity: 1;
  pointer-events: auto;
}

.cookie-banner-inner {
  max-width: 920px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
  background: #101014;
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 18px 22px;
  box-shadow: 0 24px 60px -20px rgba(0, 0, 0, 0.65);
}

.cookie-banner-text {
  flex: 1 1 320px;
  font-size: 0.84rem;
  line-height: 1.55;
  color: var(--text-dim);
  margin: 0;
}

.cookie-banner-link {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.cookie-banner-link:hover {
  color: var(--text);
}

.cookie-banner-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: none;
  flex-wrap: wrap;
}

.cookie-banner-btn {
  font-family: var(--font-mono);
  font-size: 0.76rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 14px 20px;
  border-radius: 999px;
  white-space: nowrap;
  transition: border-color 0.2s var(--ease), background-color 0.2s var(--ease), color 0.2s var(--ease), filter 0.2s var(--ease);
}

.cookie-banner-btn.ghost {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
}

.cookie-banner-btn.ghost:hover {
  border-color: var(--text-faint);
  color: var(--text);
}

.cookie-banner-btn.primary {
  background: var(--accent);
  border: 1px solid var(--accent);
  color: #1a1104;
}

.cookie-banner-btn.primary:hover {
  filter: brightness(1.06);
}

@media (prefers-reduced-motion: reduce) {
  .cookie-banner {
    transition: none;
  }
}

@media (max-width: 640px) {
  .cookie-banner-inner {
    flex-direction: column;
    align-items: stretch;
    text-align: left;
  }
  .cookie-banner-text {
    flex-basis: auto;
  }
  .cookie-banner-actions {
    justify-content: stretch;
  }
  .cookie-banner-btn {
    flex: 1 1 0;
    text-align: center;
  }
}

/* ---------- owner-only inline section editing (marketplace/author/js/main.js's
   wireOwnerEditing()) - a small pencil button next to each part of the hero
   card (name/avatar, bio, tags, tools, languages, socials), each opening a
   small modal scoped to just that one section instead of a separate full
   edit page. Reuses the same checkbox-pill (.pe-tool-tag/.pe-discipline-tag)
   and social-row (.pe-social-row) patterns as marketplace/profile/'s big
   edit form (same CSS, copied here rather than shared across pages - see
   build.js's header comment for why there's no single shared stylesheet),
   so the two look and behave identically even though this page edits one
   field at a time instead of the whole profile at once. ---------- */

.au-editable-row {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* #auBioRow/#auDisciplinesRow (marketplace/author/js/main.js's
   renderProfileExtras()) toggle `.hidden` based on isOwnerProfile/content
   - without this, .au-editable-row's own `display: flex` above always
   wins over the browser's `[hidden] { display: none }` default, so the
   row stays laid out (currently masked only by its children also being
   independently hidden/empty - fixing this here is the correct, durable
   guard rather than relying on that coincidence). */
.au-editable-row[hidden] {
  display: none;
}

.au-editable-row .au-meta-label {
  margin: 0;
}

.au-bio-row,
#auBioRow.au-editable-row,
#auDisciplinesRow.au-editable-row {
  align-items: flex-start;
}

.au-section-edit-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 7px;
  border: 1px solid var(--border);
  color: var(--text-faint);
  background: transparent;
  flex: none;
  transition: border-color 0.2s var(--ease), color 0.2s var(--ease), background-color 0.2s var(--ease);
}

.au-section-edit-btn:hover {
  border-color: var(--accent-dim);
  color: var(--accent);
  background: rgba(255, 157, 46, 0.1);
}

.au-section-edit-btn[hidden] {
  display: none;
}

.au-section-edit-btn svg {
  width: 13px;
  height: 13px;
}

/* small section-scoped modal - same .auth-overlay/.auth-modal chrome as
   the sign-in modal, just a smaller, single-purpose body instead of the
   auth form's tabs. */

.au-section-modal {
  max-width: 640px;
  max-height: min(88vh, 760px);
  overflow-y: auto;
  /* .auth-overlay (this modal's parent) runs backdrop-filter: blur(4px) -
     without its own compositing layer, scrolling THIS element's content
     forces the browser to keep re-sampling that blur every frame, which
     is what made scrolling the (now much longer, since Tools/Disciplines
     got grouped into many more pills) Tools/Tags lists so laggy.
     will-change: transform promotes the modal onto its own GPU layer (it
     already animates transform on open via .auth-modal/.auth-overlay.is-
     open .auth-modal below - this just hints the browser to keep that
     layer around) so its internal scroll repaints stop touching the
     blurred backdrop. Not `transform: translateZ(0)` here - that would
     get overridden anyway by .auth-overlay.is-open .auth-modal's own
     higher-specificity transform, which already includes translateY/
     scale for the open animation. */
  will-change: transform;
}

/* Add/Edit portfolio piece only (openSectionModal()'s 4th argument, see
   openPieceModal()) - team feedback that the default 640px width made
   same-looking photo thumbnails too hard to tell apart. */
.au-section-modal--photos {
  max-width: 880px;
}

.au-section-modal-title {
  font-family: var(--font-display);
  font-size: 1.15rem;
  font-weight: 800;
  color: var(--text);
  margin: 0 0 16px;
}

.au-section-modal-body {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 16px;
}

.au-section-modal-body .auth-label {
  margin-top: 4px;
}

.au-section-modal-body .auth-label-row {
  margin-top: 4px;
}

.au-section-textarea {
  min-height: 220px;
  resize: vertical;
  line-height: 1.5;
  font-family: var(--font-display);
}

/* ---------- inline "i" info icon + hover/tap tooltip, used next to a
   field's label wherever it isn't obvious what belongs there (see
   buildInfoTip() in js/main.js). Deliberately plain class-toggling
   (.is-open) for the tap/touch case rather than :hover-only, since this
   site avoids relying on hover for anything that must also work on
   mobile. ---------- */

.pe-info-tip {
  position: relative;
  display: inline-flex;
  align-items: center;
  margin-left: 6px;
  vertical-align: middle;
}

.pe-inline-tip-row {
  display: inline-flex;
  align-items: center;
}

.pe-info-tip-btn {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 1px solid var(--text-faint);
  color: var(--text-faint);
  font-family: var(--font-mono);
  font-size: 0.62rem;
  font-weight: 700;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  transition: border-color 0.2s var(--ease), color 0.2s var(--ease);
}

.pe-info-tip-btn:hover,
.pe-info-tip-btn:focus-visible,
.pe-info-tip.is-open .pe-info-tip-btn {
  border-color: var(--accent);
  color: var(--accent);
  outline: none;
}

.pe-info-tip-bubble {
  position: absolute;
  bottom: calc(100% + 8px);
  right: 0;
  left: auto;
  transform: translateY(4px);
  width: max-content;
  max-width: min(230px, 65vw);
  background: #1c1c22;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px 10px;
  font-size: 0.72rem;
  line-height: 1.45;
  font-weight: 400;
  text-transform: none;
  letter-spacing: normal;
  color: var(--text-dim);
  box-shadow: 0 12px 30px -10px rgba(0, 0, 0, 0.6);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.16s var(--ease), transform 0.16s var(--ease);
  z-index: 5;
}

/* the socials-hint icon sits mid-row rather than at a row's right edge -
   right-anchoring the bubble there would push most of it off to the left
   past the modal's own padding, so that one spot opts back into a
   centered bubble via .pe-info-tip--center (added in JS next to it). */
.pe-info-tip--center .pe-info-tip-bubble {
  right: auto;
  left: 50%;
  transform: translateX(-50%) translateY(4px);
}

.pe-info-tip-btn:hover + .pe-info-tip-bubble,
.pe-info-tip-btn:focus-visible + .pe-info-tip-bubble,
.pe-info-tip.is-open .pe-info-tip-bubble {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

.pe-info-tip--center .pe-info-tip-btn:hover + .pe-info-tip-bubble,
.pe-info-tip--center .pe-info-tip-btn:focus-visible + .pe-info-tip-bubble,
.pe-info-tip--center.is-open .pe-info-tip-bubble {
  transform: translateX(-50%) translateY(0);
}

@media (max-width: 480px) {
  .pe-info-tip-bubble {
    max-width: 68vw;
    font-size: 0.7rem;
  }
}

.au-section-hint {
  font-size: 0.76rem;
  color: var(--text-faint);
  line-height: 1.5;
  margin: 6px 0 0;
}

.au-section-modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  flex-wrap: wrap;
}

/* ---------- ported from marketplace/profile/css/style.css: checkbox-pill
   tag pickers (disciplines/tools) and the socials repeater ---------- */

.pe-images-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.pe-add-image-btn {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--accent);
  border: 1px solid var(--accent-dim);
  background: rgba(255, 157, 46, 0.2);
  padding: 6px 14px;
  border-radius: 999px;
  transition: border-color 0.2s var(--ease), background-color 0.2s var(--ease);
  flex: none;
}

.pe-add-image-btn:hover {
  border-color: var(--accent);
  background: rgba(255, 157, 46, 0.3);
}

.pe-add-image-btn[disabled] {
  opacity: 0.4;
  cursor: not-allowed;
  pointer-events: none;
}

.pe-images {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-top: 14px;
}

.pe-image-remove-btn {
  width: 32px;
  height: 32px;
  border-radius: 8px;
  border: 1px solid var(--border);
  color: var(--text-faint);
  font-size: 1rem;
  line-height: 1;
  transition: border-color 0.2s var(--ease), color 0.2s var(--ease), background-color 0.2s var(--ease);
}

.pe-image-remove-btn:hover {
  border-color: var(--danger);
  color: var(--danger);
  background: rgba(255, 107, 94, 0.1);
}

.pe-tag-groups {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.pe-tag-group-label {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin: 14px 0 2px;
}

.pe-tag-groups > .pe-tag-group-label:first-child {
  margin-top: 0;
}

.pe-discipline-tags,
.pe-tool-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.pe-discipline-tag,
.pe-tool-tag {
  display: inline-flex;
  align-items: center;
  gap: 0;
  cursor: pointer;
}

.pe-discipline-tag input,
.pe-tool-tag input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
  pointer-events: none;
}

.pe-discipline-tag-label {
  font-family: var(--font-mono);
  font-size: 0.76rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  padding: 7px 14px;
  border-radius: 999px;
  border: 1px solid var(--border);
  color: var(--text-dim);
  transition: border-color 0.2s var(--ease), background-color 0.2s var(--ease), color 0.2s var(--ease);
}

.pe-tool-tag-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: 0.76rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  padding: 7px 14px;
  border-radius: 999px;
  border: 1px solid var(--border);
  color: var(--text-dim);
  transition: border-color 0.2s var(--ease), background-color 0.2s var(--ease), color 0.2s var(--ease);
}

.pe-tool-tag-icon {
  width: 15px;
  height: 15px;
  border-radius: 3px;
  overflow: hidden;
  flex: none;
  line-height: 0;
}

.pe-tool-tag-icon svg {
  width: 100%;
  height: 100%;
  display: block;
}

.pe-discipline-tag input:checked + .pe-discipline-tag-label,
.pe-tool-tag input:checked + .pe-tool-tag-label {
  border-color: var(--accent);
  background: rgba(255, 157, 46, 0.14);
  color: var(--accent);
}

.pe-discipline-tag input:focus-visible + .pe-discipline-tag-label,
.pe-tool-tag input:focus-visible + .pe-tool-tag-label {
  outline: 1px solid var(--accent);
  outline-offset: 2px;
}

.pe-social-row {
  display: grid;
  grid-template-columns: 32px 170px 1fr 32px;
  gap: 10px;
  align-items: center;
  padding: 12px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: #0e0e12;
}

.pe-social-icon-preview {
  width: 32px;
  height: 32px;
  border-radius: 8px;
  border: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--accent);
  flex: none;
}

.pe-social-icon-preview.is-empty {
  border-style: dashed;
}

.pe-social-icon-preview svg {
  width: 15px;
  height: 15px;
}

.pe-social-primary-row {
  grid-column: 1 / -1;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--text-faint);
  cursor: pointer;
}

.pe-social-primary-row input[type='radio'] {
  accent-color: var(--accent);
  cursor: pointer;
}

.pe-social-primary-row input[type='radio']:checked ~ span {
  color: var(--accent);
}

.pe-social-row .auth-input,
.pe-social-row .pe-social-select {
  padding: 9px 12px;
  font-size: 0.84rem;
}

.pe-social-select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  border-radius: 8px;
  border: 1px solid var(--border);
  background-color: rgba(255, 255, 255, 0.02);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238c8b96' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
  background-size: 10px;
  padding-right: 28px;
  color: var(--text);
  font-family: var(--font-display);
  cursor: pointer;
}

.pe-social-select option {
  background: #0e0e12;
  color: var(--text);
}

/* ---------- ported from marketplace/profile/css/style.css: the edit-
   listing form's own layout classes (peEditForm) and the plain photo-URL
   row used by the portfolio-piece modal (marketplace/author/js/main.js's
   openPieceModal()/addPieceImageRow()) ---------- */

.pe-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}

.pe-optional {
  text-transform: none;
  font-weight: 400;
  color: var(--text-faint);
  letter-spacing: 0;
}

.pe-textarea {
  min-height: 110px;
  resize: vertical;
  line-height: 1.5;
  font-family: var(--font-display);
}

.pe-hint {
  font-size: 0.76rem;
  color: var(--text-faint);
  line-height: 1.5;
  margin: 6px 0 0;
}

.pe-image-row {
  display: grid;
  grid-template-columns: 32px 1.3fr 1fr 32px;
  gap: 10px;
  align-items: center;
  padding: 12px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: #0e0e12;
}

.pe-image-index {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--text-faint);
  text-align: center;
}

.pe-image-row .auth-input {
  padding: 9px 12px;
  font-size: 0.84rem;
}

/* ---------- per-row upload control (js/image-upload.js), added under each
   pasted-URL row so a photo can come from a real file too - see
   addPieceImageRow() in js/main.js. Same rules as
   marketplace/profile/css/style.css. ---------- */

.pe-image-row-wrap {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.pe-image-upload-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding-left: 34px;
}

.lh-upload-btn-compact {
  padding: 5px 10px;
  font-size: 0.72rem;
}

@media (max-width: 720px) {
  .pe-row {
    grid-template-columns: 1fr;
  }
  .pe-image-row {
    grid-template-columns: 1fr;
  }
  .pe-image-index {
    text-align: left;
  }
  .pe-social-row {
    grid-template-columns: 1fr;
  }
  .pe-social-icon-preview {
    display: none;
  }
}

/* ---------- ported from marketplace/profile/css/style.css: status colors
   for the badge on each owner-only listing card in the Listings tab (see
   createOwnerListingCard() in marketplace/author/js/main.js). ---------- */

.pe-listing-status--pending {
  color: var(--accent);
}

.pe-listing-status--approved {
  color: var(--ok);
}

.pe-listing-status--rejected {
  color: var(--danger);
}

/* ---------- owner-only: "+ Add" tile - "Add Piece" on the Portfolio grid,
   "List New Item" on the Listings grid. Same dashed-tile shape works in
   both since .au-portfolio-grid and .au-products-grid share the same
   repeat(auto-fill, minmax(220px, 1fr)) column track. ---------- */

.au-add-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 180px;
  border-radius: 14px;
  border: 1px dashed var(--border);
  color: var(--text-dim);
  background: rgba(255, 255, 255, 0.015);
  font-family: var(--font-mono);
  font-size: 0.8rem;
  font-weight: 600;
  text-decoration: none;
  transition: border-color 0.2s var(--ease), color 0.2s var(--ease), background-color 0.2s var(--ease);
}

.au-add-tile:hover {
  border-color: var(--accent-dim);
  color: var(--accent);
  background: rgba(255, 157, 46, 0.05);
}

.au-add-tile-icon {
  font-size: 1.7rem;
  line-height: 1;
}

/* ---------- owner-only: portfolio piece edit/delete overlay buttons.
   .au-portfolio-item used to be the clickable element itself (a <button>);
   it's now a plain positioned wrapper (still a grid cell, same background/
   radius/overflow as before) so these two buttons can sit beside the
   lightbox-opening button instead of nesting inside it - a <button> inside
   a <button> is invalid HTML, same reasoning as .mp-product-wishlist-btn
   above. ---------- */

.au-portfolio-item {
  position: relative;
  border-radius: 14px;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.02);
}

.au-portfolio-open-btn {
  display: block;
  width: 100%;
  padding: 0;
  border: none;
  text-align: left;
  background: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
}

.au-portfolio-edit-btn,
.au-portfolio-delete-btn {
  position: absolute;
  top: 10px;
  z-index: 3;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(8, 8, 10, 0.6);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.14);
  transition: border-color 0.2s var(--ease), color 0.2s var(--ease), background-color 0.2s var(--ease);
}

.au-portfolio-edit-btn {
  right: 44px;
}

.au-portfolio-delete-btn {
  right: 10px;
  font-size: 1.05rem;
  line-height: 1;
}

.au-portfolio-edit-btn svg {
  width: 13px;
  height: 13px;
}

.au-portfolio-edit-btn:hover,
.au-portfolio-delete-btn:hover {
  border-color: var(--accent-dim);
  color: var(--accent);
}

/* ---------- owner-only: each of the owner's own listing cards in the
   Listings tab (any status, not just approved - see refreshListings() in
   marketplace/author/js/main.js) is now built on the exact same classes as
   a portfolio piece card (.au-portfolio-item/.au-portfolio-thumb/the pencil
   and "×" overlay buttons) instead of the sitewide .mp-product-card, so
   switching between the Listings and Portfolio tabs doesn't visibly change
   the grid's card size - see createOwnerListingCard()'s comment in
   marketplace/author/js/main.js. Only the open-link wrapper (an <a>, not a
   <button> - it navigates to the product page) and the name+price caption
   are new; the thumb, badge position and edit/delete buttons reuse the
   portfolio piece's own rules above. ---------- */

.au-listing-open-link {
  display: block;
  width: 100%;
  padding: 0;
  border: none;
  text-align: left;
  background: none;
  color: inherit;
  font: inherit;
  text-decoration: none;
  cursor: pointer;
}

.au-listing-badge {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 2;
  font-family: var(--font-mono);
  font-size: 0.64rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 6px;
  background: rgba(8, 8, 10, 0.65);
  border: 1px solid rgba(255, 255, 255, 0.12);
}

/* Same padding/font-size as .au-portfolio-item-caption below, just a flex
   row (name left, price right, name truncates first) instead of one plain
   line of text - keeping that a pixel-for-pixel match is exactly what
   keeps both cards the same height. */
.au-listing-item-caption {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 10px 12px;
  font-size: 0.8rem;
  color: var(--text-dim);
}

.au-listing-item-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.au-listing-item-price {
  flex: none;
  font-family: var(--font-mono);
  font-weight: 600;
  color: var(--text);
}

/* ---------- owner-only: "use as portfolio cover" checkbox in the piece
   modal - a plain checkbox, not the radio group the full-page piece
   editor uses (see marketplace/profile/js/main.js's PIECE_COVER_RADIO_NAME)
   since only one piece is ever open in this modal at a time; cross-piece
   exclusivity is instead enforced server-side - see savePortfolioPiece()
   in marketplace/author/js/main.js. ---------- */

.au-cover-checkbox-row {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--text-dim);
  cursor: pointer;
  margin-top: 4px;
}

.au-cover-checkbox-row input {
  accent-color: var(--accent);
  cursor: pointer;
}

/* ---------- text selection highlight (site-wide) - restyled per team
   feedback (Discord: "Wyłączyć zaznaczanie tekstu (lub je uładnić, np.
   lekko pomarańczowe i cieńsze)") to a light, thin accent-orange
   highlight instead of the harsh browser default, rather than disabling
   selection outright - keeping text selectable matters for accessibility
   (copying, screen readers, translation tools), it just needed to look
   intentional instead of default. Same rule copied into every
   css/style.css on the site - see build.js's header comment for why
   there's no single shared stylesheet to add this to instead. ---------- */

::selection {
  background: rgba(255, 157, 46, 0.28);
  color: var(--text);
}

/* ---------- shared image-upload widget (js/image-upload.js) - same
   classes reused everywhere a real file upload was added: product
   thumbnail/photos on marketplace/sell, avatar + portfolio photos on
   marketplace/profile and marketplace/author, course thumbnail on
   tutorials/add and admin/tutorials. Copied into each of those 5 pages'
   own css/style.css, same reasoning as the text-selection rule elsewhere
   in this file.

   Markup shape every wired field uses:
     <div class="lh-upload">
       <label class="lh-upload-btn">
         Upload photo
         <input type="file" accept="image/*" class="lh-upload-input" hidden>
       </label>
       <span class="lh-upload-status" hidden></span>
       <span class="lh-upload-error" hidden></span>
     </div>
   ...plus an optional <img class="lh-upload-preview" hidden> wherever a
   thumbnail preview belongs in that field's own layout (add
   -preview-round for an avatar, -preview-wide for a full-width
   thumbnail). ---------- */

.lh-upload-input {
  display: none;
}

.lh-upload {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 8px;
}

.lh-upload-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--text-dim);
  background: var(--border-soft);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px 14px;
  cursor: pointer;
  transition: border-color 0.2s var(--ease), color 0.2s var(--ease), background-color 0.2s var(--ease);
}

.lh-upload-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.lh-upload-status {
  font-size: 0.76rem;
  color: var(--text-faint);
}

.lh-upload-error {
  font-size: 0.76rem;
  color: #ff6b5e;
}

.lh-upload-status[hidden],
.lh-upload-error[hidden] {
  display: none;
}

.lh-upload-preview {
  display: block;
  width: 64px;
  height: 64px;
  object-fit: cover;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: #0e0e12;
}

.lh-upload-preview[hidden] {
  display: none;
}

.lh-upload-preview-round {
  border-radius: 50%;
}

.lh-upload-preview-wide {
  width: 100%;
  height: 120px;
  border-radius: 10px;
}

/* ---------- ported from marketplace/profile/css/style.css: the circular
   avatar editor used by this page's own "Edit name & photo" modal
   (openBasicsModal() in js/main.js) - one big clickable circle (photo,
   "+" glyph when empty, hover overlay inviting a new upload) instead of a
   plain URL text field with an unrelated upload button and a small
   preview stacked underneath. ---------- */

.pe-avatar-edit {
  display: flex;
  align-items: flex-start;
  gap: 18px;
  margin-top: 8px;
  flex-wrap: wrap;
}

.pe-avatar-edit-circle {
  position: relative;
  width: 112px;
  height: 112px;
  flex: none;
  border-radius: 50%;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  border: 1px solid var(--avatar-empty-ring, var(--border));
  background: var(--avatar-empty, var(--border-soft));
  transition: border-color 0.2s var(--ease);
}

.pe-avatar-edit-circle:hover,
.pe-avatar-edit-circle:focus-within {
  border-color: var(--accent);
}

.pe-avatar-edit-glyph {
  font-family: var(--font-display);
  font-size: 1.8rem;
  font-weight: 400;
  color: var(--text-faint);
  pointer-events: none;
}

.pe-avatar-edit-photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.pe-avatar-edit-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  background: rgba(10, 10, 13, 0.72);
  color: var(--text);
  opacity: 0;
  transition: opacity 0.2s var(--ease);
  text-align: center;
  padding: 0 6px;
}

.pe-avatar-edit-circle:hover .pe-avatar-edit-overlay,
.pe-avatar-edit-circle:focus-within .pe-avatar-edit-overlay {
  opacity: 1;
}

.pe-avatar-edit-icon {
  width: 20px;
  height: 20px;
  flex: none;
}

.pe-avatar-edit-label {
  font-size: 0.68rem;
  font-weight: 600;
  line-height: 1.3;
}

.pe-avatar-edit-meta {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-top: 4px;
  min-width: 0;
  /* Stretches to fill the rest of the row beside the avatar circle - this
     column now holds the Display Name field (not just small upload
     status text like the original marketplace/profile version this was
     ported from), so it needs to actually claim the modal's width
     instead of shrink-wrapping to the input's intrinsic size. */
  flex: 1 1 auto;
}

.pe-avatar-url-details {
  font-size: 0.76rem;
  color: var(--text-faint);
}

.pe-avatar-url-details summary {
  cursor: pointer;
  color: var(--text-dim);
  font-weight: 600;
}

.pe-avatar-url-details summary:hover {
  color: var(--accent);
}

.pe-avatar-url-details .auth-label {
  margin: 12px 0 6px;
}

.pe-avatar-url-details .auth-input {
  margin-bottom: 0;
}

@media (max-width: 480px) {
  .pe-avatar-edit-circle {
    width: 88px;
    height: 88px;
  }
}

/* ---------- redesigned "Add Portfolio Piece" card (js/main.js's
   addPieceRow()/addPieceImageRow()): title + a compact star "cover" chip
   in the header, photos shown as an actual thumbnail grid instead of bare
   URL text rows, reorderable with left/right arrows (same pattern as
   marketplace/sell's reorderable render list), and a trailing dashed
   "Add Photo URL" tile inside the grid itself rather than a separate
   button below it. "Upload Photo(s)" stays as its own row underneath so
   multi-file picking is still one click. ---------- */

.pcp-piece-head {
  display: grid;
  grid-template-columns: 1fr auto 32px;
  gap: 10px;
  align-items: center;
  margin-bottom: 14px;
}

.pcp-piece-title {
  font-weight: 600;
}

.pcp-cover-chip-row {
  display: flex;
  align-items: center;
  margin-top: 14px;
}

.pcp-cover-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--text-faint);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 7px 12px;
  cursor: pointer;
  white-space: nowrap;
  transition: border-color 0.2s var(--ease), color 0.2s var(--ease);
}

.pcp-cover-chip:hover {
  border-color: var(--text-dim);
  color: var(--text-dim);
}

.pcp-cover-chip input[type='radio'] {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.pcp-cover-chip-star {
  font-size: 0.86rem;
  line-height: 1;
}

.pcp-cover-chip.pcp-is-checked {
  border-color: var(--accent);
  color: var(--accent);
  background: rgba(255, 157, 46, 0.08);
}

.pcp-piece-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-faint);
  font-size: 1rem;
  line-height: 1;
  transition: border-color 0.2s var(--ease), color 0.2s var(--ease);
}

.pcp-piece-remove:hover {
  border-color: var(--danger);
  color: var(--danger);
}

.pcp-photo-frame {
  position: relative;
  aspect-ratio: 1 / 1;
  border-radius: 10px;
  overflow: hidden;
  background: var(--border-soft);
  border: 1px solid var(--border);
}

.pcp-photo-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.pcp-photo-img[hidden] {
  display: none;
}

.pcp-photo-placeholder {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-faint);
}

.pcp-photo-placeholder svg {
  width: 26px;
  height: 26px;
}

.pcp-photo-frame.is-broken .pcp-photo-placeholder {
  color: var(--danger);
}

.pcp-photo-spinner {
  display: none;
}

.pcp-photo-frame.is-uploading .pcp-photo-placeholder {
  display: none;
}

.pcp-photo-frame.is-uploading .pcp-photo-spinner {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.pcp-photo-frame.is-uploading .pcp-photo-spinner::after {
  content: '';
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: 2px solid var(--border);
  border-top-color: var(--accent);
  animation: pcp-photo-spin 0.7s linear infinite;
}

@keyframes pcp-photo-spin {
  to {
    transform: rotate(360deg);
  }
}

/* ---------- redesigned "Add/Edit portfolio piece" photo grid - one
   unified tile per photo (star + remove live directly on it) instead of
   the old preview-frame + URL text box + move-arrows stack, plus a single
   dashed "add" tile that opens the file picker directly. Replaces the old
   .pcp-photo-card, .pcp-photo-num, .pcp-photo-remove, .pcp-photo-url,
   .pcp-photo-move (and its -row), .pcp-photo-add-tile (and its -icon) and
   .pcp-piece-upload-row rules that used to live here. ---------- */

.pa-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 12px;
  border-radius: 12px;
  transition: background-color 0.15s var(--ease), box-shadow 0.15s var(--ease);
}

/* Shown while dragging image files in from the desktop over this grid
   (see wirePieceUpload()'s dragover/drop handlers in js/main.js) - a
   dashed accent outline makes it obvious the drop will actually land
   here, since nothing else about the grid changes on a plain dragover. */
.pa-grid--drop-active {
  background: rgba(255, 157, 46, 0.08);
  box-shadow: 0 0 0 2px var(--accent) inset;
}

.pcp-photo-frame.pa-is-primary {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px rgba(255, 157, 46, 0.2);
}

.pa-star-btn {
  position: absolute;
  top: 6px;
  left: 6px;
  width: 24px;
  height: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  border: none;
  background: rgba(8, 8, 10, 0.72);
  color: var(--text-faint);
  font-size: 0.86rem;
  line-height: 1;
  transition: color 0.15s var(--ease), background-color 0.15s var(--ease);
}

.pa-star-btn:hover {
  color: var(--accent);
}

.pcp-photo-frame.pa-is-primary .pa-star-btn {
  color: var(--accent);
  background: rgba(8, 8, 10, 0.85);
}

.pa-remove-btn {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 22px;
  height: 22px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  border: none;
  background: rgba(8, 8, 10, 0.72);
  color: var(--text);
  font-size: 0.9rem;
  line-height: 1;
  opacity: 0;
  transition: opacity 0.15s var(--ease), background-color 0.15s var(--ease), color 0.15s var(--ease);
}

.pcp-photo-frame:hover .pa-remove-btn,
.pa-remove-btn:focus-visible {
  opacity: 1;
}

.pa-remove-btn:hover {
  background: var(--danger);
  color: #fff;
}

.pa-primary-tag {
  position: absolute;
  bottom: 6px;
  left: 6px;
  font-family: var(--font-mono);
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--accent);
  background: rgba(8, 8, 10, 0.72);
  border-radius: 999px;
  padding: 3px 8px;
}

.pa-add-tile {
  aspect-ratio: 1 / 1;
  align-self: start;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  border-radius: 10px;
  border: 1px dashed var(--border);
  background: transparent;
  color: var(--text-faint);
  font-family: var(--font-mono);
  font-size: 0.64rem;
  font-weight: 700;
  text-align: center;
  padding: 8px;
  cursor: pointer;
  transition: border-color 0.2s var(--ease), color 0.2s var(--ease);
}

.pa-add-tile:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.pa-add-tile-icon {
  font-size: 1.2rem;
  line-height: 1;
}

/* Drag handle - the only way (besides the star) to control photo order in
   this grid, since the redesign dropped the old move-arrows. Grabbing it
   sets the tile draggable (see addPieceImageTile in main.js) so dragging
   the photo itself, or clicking the star/remove buttons, never starts a
   reorder by accident. */
.pa-drag-handle {
  position: absolute;
  bottom: 6px;
  right: 6px;
  width: 22px;
  height: 22px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  border: none;
  background: rgba(8, 8, 10, 0.72);
  color: var(--text-faint);
  cursor: grab;
  opacity: 0;
  transition: opacity 0.15s var(--ease), color 0.15s var(--ease);
}

.pcp-photo-frame:hover .pa-drag-handle,
.pa-drag-handle:focus-visible {
  opacity: 1;
}

.pa-drag-handle:hover {
  color: var(--accent);
}

.pa-drag-handle:active {
  cursor: grabbing;
}

.pa-drag-handle svg {
  width: 14px;
  height: 14px;
}

.pcp-photo-frame.pa-is-dragging {
  opacity: 0.4;
}

.pa-url-toggle-row {
  margin-top: 10px;
}

.pa-url-toggle-btn {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--text-faint);
  transition: color 0.2s var(--ease);
}

.pa-url-toggle-btn:hover {
  color: var(--accent);
}

.pa-url-entry-row {
  display: flex;
  gap: 8px;
  align-items: center;
}

.pa-url-entry-row .auth-input {
  flex: 1;
}

.lh-upload-btn-compact {
  padding: 5px 10px;
  font-size: 0.72rem;
}


/* ---------- notification bell (js/notifications.js) - shown once
   signed in, a small red dot appears while there's at least one unread
   notification (a REAL one - see notifications_migration.sql - not a
   decorative reuse of some other count). The bell reuses .cart-btn/
   .cart-icon for identical sizing; the dropdown below it is the same
   visual language as .popover, just anchored to the bell itself (not the
   whole .nav-right) via .notif-wrap so it doesn't have to share
   .popover's own right:0 anchor. ---------- */

.notif-wrap {
  position: relative;
  display: flex;
  align-items: center;
}

.notif-dot {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: #ff6b5e;
  border: 2px solid #06070a;
}

.notif-dot[hidden] {
  display: none;
}

.notif-panel {
  position: absolute;
  top: calc(100% + 12px);
  right: 0;
  width: 320px;
  max-width: calc(100vw - 32px);
  max-height: 420px;
  overflow-y: auto;
  background: #101014;
  border: 1px solid var(--border);
  box-shadow: 0 20px 40px -12px rgba(0, 0, 0, 0.6);
  padding: 14px;
  opacity: 0;
  transform: translateY(-6px);
  pointer-events: none;
  transition: opacity 0.16s var(--ease), transform 0.16s var(--ease);
  z-index: 40;
}

.notif-panel.is-open {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

.notif-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 10px;
}

.notif-panel-title {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.notif-mark-all-btn {
  font-size: 0.74rem;
  font-weight: 600;
  color: var(--accent);
  transition: opacity 0.2s var(--ease);
}

.notif-mark-all-btn:hover {
  opacity: 0.8;
}

.notif-mark-all-btn[hidden] {
  display: none;
}

.notif-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.notif-item {
  display: block;
  width: 100%;
  text-align: left;
  padding: 10px;
  border-radius: 8px;
  transition: background-color 0.2s var(--ease);
}

.notif-item:hover {
  background-color: rgba(255, 255, 255, 0.045);
}

.notif-item.is-unread {
  background-color: rgba(255, 157, 46, 0.07);
}

.notif-item-title {
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--text);
  margin: 0 0 3px;
}

.notif-item-body {
  font-size: 0.78rem;
  line-height: 1.4;
  color: var(--text-dim);
  margin: 0 0 4px;
}

.notif-item-time {
  font-family: var(--font-mono);
  font-size: 0.66rem;
  color: var(--text-faint);
}

.notif-empty {
  font-size: 0.82rem;
  color: var(--text-faint);
  text-align: center;
  padding: 18px 6px;
  margin: 0;
}

.notif-empty[hidden] {
  display: none;
}

@media (max-width: 480px) {
  .notif-panel {
    width: calc(100vw - 32px);
    right: -8px;
  }
}

/* Link tile in the portfolio-piece films grid (YouTube / Vimeo): no video
   preview, so a faint play glyph fills the square instead. */
.pcp-video-link {
  display: flex;
  align-items: center;
  justify-content: center;
}

.pcp-video-link::before {
  content: '\25B6';
  font-size: 1.5rem;
  color: var(--text-faint);
}

.pa-video-link-row {
  display: flex;
  gap: 8px;
  margin-top: 10px;
}

.pa-video-link-row .auth-input {
  flex: 1;
  min-width: 0;
}

.pa-video-link-btn {
  flex: none;
  padding: 0 16px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 700;
  cursor: pointer;
  transition: border-color 0.2s var(--ease), color 0.2s var(--ease);
}

.pa-video-link-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}

/* Portfolio card of a video-only piece with no still to show (Vimeo). */
.au-portfolio-thumb--video {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--border-soft);
}

.au-portfolio-thumb--video::before {
  content: '\25B6';
  font-size: 1.8rem;
  color: var(--text-faint);
}
