/* ============================== Reset ============================== */
*, *::before, *::after { box-sizing: border-box; }
html { color-scheme: dark; }
body, h1, h2, h3, h4, p, figure, blockquote, dl, dd { margin: 0; }
ul[class], ol[class] { list-style: none; margin: 0; padding: 0; }
img, picture, svg { display: block; max-width: 100%; }
input, button, textarea, select { font: inherit; color: inherit; }
button { cursor: pointer; }
a { color: inherit; text-decoration: none; }

/* ============================== Tokens ============================== */
:root {
  --bg: #000000;
  --bg-soft: #0a0a0a;
  --panel: #050505;
  --border: #242424;
  --border-soft: #1a1a1a;
  /* Interactive form-field borders need to be visible against their fill,
     not just decorative - #242424 is ~1.35:1 on --bg-soft, well under the
     3:1 WCAG AA floor for UI component boundaries. #666 clears ~3.7:1. */
  --border-strong: #666666;
  --text: #ffffff;
  --text-muted: #a3a3a3;
  /* #6b6b6b measured 3.9:1 on black - fails WCAG AA (4.5:1) for normal-size
     text, and this token is used at small sizes sitewide (labels, chips,
     timestamps), not just decorative captions. #808080 clears 5.3:1. */
  --text-faint: #808080;

  --fg-invert: #000000;

  /* Semantic status colors - the site is otherwise strictly monochrome,
     so these are reserved for state (success/danger/warning/info) and
     shouldn't be reused for anything decorative. Each has a matching
     *-bg wash for subtle fills (badges, banners) at readable contrast. */
  --color-success: #4ade80;
  --color-success-bg: rgba(74, 222, 128, 0.1);
  --color-danger: #ff6b6b;
  --color-danger-bg: rgba(255, 107, 107, 0.08);
  --color-danger-hover: #ff9a9a;
  --color-warning: #fbbf24;
  --color-warning-bg: rgba(251, 191, 36, 0.1);
  --color-info: #60a5fa;
  --color-info-bg: rgba(96, 165, 250, 0.1);

  --radius-sm: 10px;
  --radius-md: 16px;
  --radius-lg: 24px;

  --font-display: 'Space Grotesk', 'Inter', system-ui, sans-serif;
  --font-body: 'Inter', system-ui, -apple-system, sans-serif;

  --container: 1180px;
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

.container { max-width: var(--container); margin-inline: auto; padding-inline: 24px; }

h1, h2, h3, h4 { font-family: var(--font-display); font-weight: 700; letter-spacing: -0.01em; }

.skip-link {
  position: absolute; left: -9999px; top: 0; background: #fff; color: #000;
  padding: 10px 16px; border-radius: 0 0 10px 0; z-index: 1000; font-weight: 600;
}
.skip-link:focus { left: 0; }

/* Default focus ring for most controls. Elements packed tightly in a grid
   (masonry cards, thumbnails, chips) use an inset ring instead, drawn
   inside the box so it can never bleed into a neighboring element. */
a:focus-visible, button:focus-visible, input:focus-visible, textarea:focus-visible {
  outline: none; box-shadow: 0 0 0 2px #fff;
}
.pw-card:focus-visible, .lightbox__thumb:focus-visible {
  outline: none; box-shadow: inset 0 0 0 2px #fff;
}

/* ============================== Skeleton loaders ============================== */
/* Applied to an image (or its container) while its src is still loading;
   main.js removes it and reveals the image on `load` (or immediately if
   the image was already cached and `complete` by the time JS runs). */
@keyframes skeleton-shimmer { 0% { background-position: 150% 0; } 100% { background-position: -50% 0; } }
.is-skeleton { background: linear-gradient(100deg, var(--bg-soft) 30%, var(--border-soft) 50%, var(--bg-soft) 70%) !important; background-size: 200% 100%; animation: skeleton-shimmer 1.6s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) {
  .is-skeleton { animation: none; }
}

/* ============================== Buttons ============================== */
.btn {
  display: inline-flex; align-items: center; gap: 8px; justify-content: center;
  padding: 13px 22px; border-radius: 999px; font-weight: 600; font-size: 0.95rem;
  border: 1px solid transparent; transition: transform .15s ease, opacity .15s ease, background .15s ease, border-color .15s ease;
  white-space: nowrap;
}
.btn:active { transform: scale(0.97); }
.btn--primary { background: #fff; color: #000; }
.btn--primary:hover { opacity: 0.82; }
.btn--outline { border-color: var(--border); color: var(--text); background: transparent; }
.btn--outline:hover { border-color: #fff; }
.btn--danger { background: var(--color-danger); color: #fff; }
.btn--danger:hover { opacity: 0.85; }
.btn--danger[disabled] { background: var(--color-danger); }
.btn--sm { padding: 9px 16px; font-size: 0.85rem; }
.btn--block { width: 100%; }
.btn[disabled] { opacity: 0.5; cursor: not-allowed; }

/* ============================== Header ============================== */
.site-header {
  position: sticky; top: 0; z-index: 100;
  background: var(--bg);
  border-bottom: 1px solid var(--border-soft);
}
.site-header__bar { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; padding-block: 20px; gap: 24px; }
.brand { font-family: var(--font-display); font-weight: 700; font-size: 1.25rem; letter-spacing: -0.02em; justify-self: start; grid-column: 1; }
.nav { display: flex; align-items: center; gap: 28px; justify-self: center; grid-column: 2; }
.nav__link { color: var(--text-muted); font-weight: 500; font-size: 0.94rem; transition: color .15s ease; position: relative; }
.nav__link:hover, .nav__link.is-active { color: var(--text); }
.nav__link.is-active::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: -6px; height: 2px; background: #fff; border-radius: 2px;
}
.site-header__actions { display: flex; align-items: center; gap: 14px; justify-self: end; grid-column: 3; }

/* ---- Signed-in user menu (Discord identity + dropdown) ---- */
.user-menu { position: relative; }
.user-menu__trigger {
  display: flex; align-items: center; gap: 10px; background: none; border: 0; padding: 4px;
  border-radius: 999px; cursor: pointer;
}
.user-menu__avatar { width: 32px; height: 32px; border-radius: 50%; flex: none; border: 1px solid var(--border); }
.user-menu__name { display: flex; flex-direction: column; align-items: flex-start; line-height: 1.25; }
.user-menu__name strong { font-size: 0.86rem; font-weight: 600; color: var(--text); }
.user-menu__name span { font-size: 0.76rem; color: var(--text-faint); }
.user-menu__chevron { flex: none; color: var(--text-faint); transition: transform .15s ease; }
.user-menu__trigger[aria-expanded="true"] .user-menu__chevron { transform: rotate(180deg); }
.user-menu__dropdown {
  display: none; position: absolute; top: calc(100% + 10px); right: 0; min-width: 180px; z-index: 110;
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius-md);
  padding: 6px; box-shadow: 0 20px 40px -20px rgba(0,0,0,0.7);
}
.user-menu__dropdown.is-open { display: block; }
.user-menu__dropdown a {
  display: block; padding: 10px 12px; border-radius: var(--radius-sm); font-size: 0.88rem;
  font-weight: 500; color: var(--text-muted);
}
.user-menu__dropdown a:hover { background: var(--bg-soft); color: var(--text); }

/* 44x44 is the minimum tappable area (Apple HIG) - the visible icon stays
   20px, padding pads the box out to a full touch target since this is the
   primary mobile-nav trigger. */
.nav-toggle {
  display: none; flex-direction: column; justify-content: center; align-items: center; gap: 4px;
  background: none; border: 0; width: 44px; height: 44px; padding: 0;
}
.nav-toggle span { width: 20px; height: 2px; background: var(--text); border-radius: 2px; }
.mobile-nav { display: none; flex-direction: column; padding: 8px 24px 20px; border-top: 1px solid var(--border-soft); }
.mobile-nav a { padding: 12px 0; color: var(--text-muted); font-weight: 500; border-bottom: 1px solid var(--border-soft); }
.mobile-nav a:last-child { border-bottom: 0; }
body.nav-open .mobile-nav { display: flex; }

@media (max-width: 860px) {
  .nav { display: none; }
  .site-header__actions .btn--primary,
  .site-header__actions .btn--outline,
  .site-header__actions .user-menu { display: none; }
  .nav-toggle { display: flex; }
}

/* ============================== Error page ============================== */
.error-page {
  min-height: calc(100vh - 73px);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; gap: 16px; padding: 80px 24px;
}
.error-page__code {
  font-family: var(--font-display); font-weight: 700; font-size: 0.85rem;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-faint);
}
.error-page h1 { font-size: clamp(1.75rem, 4vw, 2.5rem); }
.error-page p:not(.error-page__code) { color: var(--text-muted); max-width: 440px; line-height: 1.6; }
.error-page .btn { margin-top: 8px; }

/* ============================== Hero ============================== */
/* Centered, quiet composition. One CTA - an underlined text link, not a
   filled button - and the stats collapse into a single plain inline
   line instead of a bordered strip. No cards, no rotation, no
   background pattern. */
.hero {
  position: relative; overflow: hidden;
  padding-block: 130px 110px;
  border-bottom: 1px solid var(--border-soft);
  text-align: center;
}
.hero__inner { position: relative; max-width: 700px; margin-inline: auto; }

.hero h1 { font-size: clamp(2.2rem, 4.6vw, 3.6rem); line-height: 1.1; font-weight: 700; letter-spacing: -0.01em; }
.hero__lede { margin: 22px auto 0; font-size: 1.06rem; line-height: 1.6; color: var(--text-muted); max-width: 48ch; }
.hero__cta {
  display: inline-block; margin-top: 32px; font-family: var(--font-display); font-weight: 600; font-size: 1.1rem;
  color: var(--text); text-decoration: underline; text-underline-offset: 6px;
}
.hero__stats {
  margin-top: 40px; display: flex; align-items: center; justify-content: center; gap: 14px; flex-wrap: wrap;
  font-size: 0.86rem; color: var(--text-muted);
}
.hero__stats strong { color: var(--text); font-family: var(--font-display); font-weight: 600; }
.hero__stats-dot { color: var(--border-strong); }

@media (max-width: 640px) {
  .hero { padding-block: 90px 70px; }
  .hero__stats { gap: 8px 12px; font-size: 0.8rem; }
}

/* ============================== Section shell ============================== */
.section { padding-block: 84px; }
.section--tight { padding-block: 60px; }
.section--divider { border-top: 1px solid var(--border-soft); }
.section-head { max-width: 640px; margin-bottom: 44px; }
.section-head h2 { font-size: clamp(1.7rem, 3.2vw, 2.3rem); }
.section-head p { color: var(--text-muted); margin-top: 10px; font-size: 1.02rem; }
/* A count nested inside the header block, not a separate section below
   it - .section-head's own margin-bottom is the only gap before whatever
   comes next, so this can't add a second one on top of it. */
.section-head .section-head__caption { margin-top: 10px; margin-bottom: 0; }
.section-head--split { display: flex; align-items: flex-end; justify-content: space-between; gap: 24px; flex-wrap: wrap; }

/* ============================== Tools marquee ============================== */
/* The viewport is a `.container`, so the visible strip starts/ends at the
   same left/right edges as the Reviews section below it - only the inner
   track (twice the tool list, back to back) extends past those edges and
   loops via the -50% keyframe. Animation never pauses, so it's always moving. */
.marquee { border-top: 1px solid var(--border-soft); border-bottom: 1px solid var(--border-soft); padding-block: 32px; }
.marquee__viewport {
  overflow: hidden;
  /* Fade to nothing at both edges instead of a hard clip. */
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 10%, #000 90%, transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0, #000 10%, #000 90%, transparent 100%);
}
.marquee__track { display: flex; gap: 64px; width: max-content; animation: scroll 60s linear infinite; }
.marquee__item { display: flex; align-items: center; white-space: nowrap; }
.tool-logo {
  width: 34px; height: 34px; object-fit: contain;
  filter: grayscale(1) brightness(0.55); opacity: 0.75;
  transition: filter .2s ease, opacity .2s ease;
}
.marquee__item:hover .tool-logo { filter: none; opacity: 1; }
@keyframes scroll { from { transform: translateX(0); } to { transform: translateX(-50%); } }

/* ============================== Carousel (Reviews + Clientele) ============================== */
/* Shows up to 3 full items at once and steps by exactly one: the leftmost
   item leaves, the rest shift left, and the next item slides in on the
   right. `--carousel-per-page` is read by JS (via getComputedStyle) to
   know how many items are visible at the current breakpoint, so it can
   compute the last valid scroll position - keep it in sync with the
   flex-basis media queries below. */
.carousel { --carousel-per-page: 3; }
.carousel__viewport { overflow: hidden; }
.carousel__track { position: relative; display: flex; gap: 20px; transition: transform .4s cubic-bezier(.4,0,.2,1); }
/* Fewer items than fit on one page (set by JS, see main.js initCarousel):
   center the leftover cards instead of leaving them stuck against the left
   edge with dead space to their right. */
.carousel__track--center { justify-content: center; }
.carousel__item { flex: 0 0 calc((100% - 20px * 2) / 3); min-width: 0; }
@media (max-width: 980px) {
  .carousel { --carousel-per-page: 2; }
  .carousel__item { flex-basis: calc((100% - 20px) / 2); }
}
@media (max-width: 640px) {
  .carousel { --carousel-per-page: 1; }
  .carousel__item { flex-basis: 100%; }
}

.review-card {
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius-md); padding: 26px;
  height: 100%;
}
.review-card__header { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin-bottom: 16px; }
.review-card__meta { display: flex; flex-direction: column; align-items: flex-end; gap: 5px; flex: none; }
.review-card__stars { color: #fff; letter-spacing: 2px; font-size: 0.85rem; white-space: nowrap; padding-top: 2px; }
.review-card__date { color: var(--text-faint); font-size: 0.76rem; white-space: nowrap; }
.review-card p { color: var(--text-muted); font-size: 0.95rem; }
.review-card__who { display: flex; align-items: center; gap: 10px; min-width: 0; }
.review-card__avatar {
  width: 36px; height: 36px; border-radius: 50%; flex: none;
  border: 1px solid var(--border); object-fit: cover;
}
img.review-card__avatar { opacity: 0; transition: opacity .25s ease; }
img.review-card__avatar.is-loaded { opacity: 1; }
.review-card__who span.review-card__avatar--fallback {
  background: transparent; display: grid; place-items: center;
  font-weight: 700; color: #fff; font-size: 0.9rem; font-family: var(--font-display);
}
.review-card__who > div { min-width: 0; }
.review-card__who strong { display: block; font-size: 0.92rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.review-card__who span { color: var(--text-faint); font-size: 0.82rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: block; }

.carousel__controls { display: flex; align-items: center; justify-content: center; gap: 20px; margin-top: 28px; }
/* 44x44 minimum tap target (Apple HIG). */
.carousel__arrow {
  width: 44px; height: 44px; border-radius: 50%; border: 1px solid var(--border); background: var(--panel);
  color: #fff; display: grid; place-items: center; flex: none; transition: border-color .15s ease, opacity .15s ease;
}
.carousel__arrow:hover { border-color: #fff; }
.carousel__arrow:disabled { opacity: 0.3; cursor: default; }
.carousel__arrow:disabled:hover { border-color: var(--border); }

/* ============================== Cards grid (Past Work, shared) ============================== */
/* Plain CSS grid, not a `columns:` masonry - multi-column layouts have a
   well-documented Chromium/WebKit bug where a bordered child's outline
   fragments and repaints across the whole column box on hover/repaint,
   drawing stray lines outside the card. Grid doesn't fragment children at
   all, so it can't happen here. Rows size to the tallest card in that row
   instead of packing tightly, which is a fair trade for correctness. */
.pw-masonry { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; align-items: start; }
@media (max-width: 860px) { .pw-masonry { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .pw-masonry { grid-template-columns: 1fr; } }

/* Image on top, caption below in normal flow - never overlaid, so the
   title/tags can't cover the design. Tags are intentionally left out of
   the card face entirely; they only show up in the lightbox. */
.pw-card {
  position: relative; border-radius: var(--radius-md); border: 1px solid var(--border);
  background: var(--panel); display: flex; flex-direction: column; width: 100%; overflow: hidden; isolation: isolate;
}
/* Every card's media box uses the same ratio regardless of the source
   photo's own dimensions, so every card in a row is the same height.
   object-fit: contain (not cover) so a differently-shaped image - e.g. the
   wide, short "single uniform" format - is never cropped, just centered
   with its own background filling the rest of the box. */
.pw-card__media { position: relative; display: block; overflow: hidden; background: var(--bg-soft); aspect-ratio: 4 / 3; }
.pw-card__media img { width: 100%; height: 100%; object-fit: contain; opacity: 0; transition: opacity .25s ease, transform .35s ease; }
.pw-card__media img.is-loaded { opacity: 1; }
.pw-card:hover .pw-card__media img { transform: scale(1.04); }
.pw-card__meta { padding: 14px; text-align: left; }
.pw-card__meta strong { display: block; font-family: var(--font-display); font-size: 0.95rem; color: #fff; font-weight: 600; }
.pw-card__pack-badge {
  position: absolute; top: 12px; right: 12px; font-size: 0.7rem; font-weight: 700;
  padding: 5px 10px; border-radius: 999px; color: #000; background: #fff;
}
.pw-card--pack { border-color: rgba(255,255,255,0.35); }
/* Animated logos are always square - a different showcase type gets a
   different frame instead of being squeezed into the clothing 4:3 box. */
.pw-card--logo .pw-card__media { aspect-ratio: 1 / 1; }

/* ============================== Contact ============================== */
.contact-panel {
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius-lg);
  padding: clamp(36px, 6vw, 60px); max-width: 900px; margin-inline: auto; text-align: center;
}
.contact-panel h2 { font-size: clamp(1.8rem, 3.4vw, 2.3rem); }
.contact-panel > p { color: var(--text-muted); margin-top: 16px; font-size: 1.1rem; }
.contact-panel .btn { margin-top: 32px; }

.field { display: flex; flex-direction: column; gap: 8px; }
.field label { font-size: 0.85rem; font-weight: 600; color: var(--text-muted); }
.field input, .field textarea, .field select {
  background: var(--bg-soft); border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  padding: 13px 14px; color: var(--text); font-size: 0.95rem; transition: border-color .15s ease;
}
.field input:focus, .field textarea:focus, .field select:focus { outline: none; border-color: #fff; }
.field textarea { resize: vertical; min-height: 110px; }

/* File inputs: the surrounding box already matches the theme via
   `.field input`, but the native "Choose File" button inside it doesn't -
   it renders as an unstyled OS-grey button that clashes with everything
   else. Restyle it as a small pill button matching `.btn--primary`. */
.field input[type="file"] { padding: 7px 10px; font-size: 0.82rem; color: var(--text-muted); }
.field input[type="file"]::file-selector-button,
.field input[type="file"]::-webkit-file-upload-button {
  background: #fff; color: #000; border: 0; border-radius: 999px;
  padding: 7px 14px; margin-right: 10px; font: inherit; font-weight: 600; font-size: 0.8rem;
  cursor: pointer; transition: opacity .15s ease;
}
.field input[type="file"]:hover::file-selector-button,
.field input[type="file"]:hover::-webkit-file-upload-button { opacity: 0.82; }

/* Flash-message banner shared by any plain form on the public site (the
   old contact form, now the profile page's account actions). */
.form-status { margin-top: 14px; padding: 12px 14px; border-radius: var(--radius-sm); font-size: 0.9rem; display: none; border: 1px solid var(--border); }
.form-status.is-visible { display: block; }
.form-status--ok { color: var(--color-success); border-color: var(--color-success); background: var(--color-success-bg); }
.form-status--err { color: var(--color-danger); border-color: var(--color-danger); background: var(--color-danger-bg); }

/* ============================== Past Work page ============================== */
.pw-toolbar {
  position: sticky; top: 81px; z-index: 40; background: var(--bg);
  border: 1px solid var(--border); border-radius: var(--radius-md); padding: 16px; margin-bottom: 44px;
}
.pw-search { position: relative; }
.pw-search input {
  width: 100%; background: var(--bg-soft); border: 1px solid var(--border); border-radius: 999px;
  padding: 13px 52px; color: var(--text); font-size: 0.96rem;
}
.pw-search input:focus { outline: none; border-color: #fff; }
.pw-search svg { position: absolute; left: 16px; top: 50%; transform: translateY(-50%); color: var(--text-faint); }
/* 44x44 minimum tap target (Apple HIG) - was a 26px circle floating in a
   52px-tall bar with room to spare, so this only grows the hit area. */
.pw-search__clear {
  position: absolute; right: 3px; top: 50%; transform: translateY(-50%); background: var(--panel);
  border: 1px solid var(--border); color: var(--text-muted); width: 44px; height: 44px; border-radius: 50%;
  display: none; align-items: center; justify-content: center; font-size: 0.8rem;
}
.pw-search__clear.is-visible { display: flex; }

.pw-count { color: var(--text-faint); font-size: 0.88rem; margin-bottom: 28px; }

.pw-empty { display: none; text-align: center; padding: 90px 20px; color: var(--text-muted); }
.pw-empty.is-visible { display: block; }
.pw-empty h2 { font-family: var(--font-display); font-size: 1.3rem; margin-bottom: 8px; color: var(--text); }

/* Lightbox */
.lightbox {
  position: fixed; inset: 0; z-index: 200; display: none; align-items: center; justify-content: center;
  background: rgba(0,0,0,0.95); padding: 30px; overflow-y: auto;
}
.lightbox.is-open { display: flex; }
.lightbox__frame { max-width: 820px; width: 100%; }
.lightbox__frame img { width: 100%; border-radius: var(--radius-md); border: 1px solid var(--border); max-height: 70vh; object-fit: contain; background: var(--panel); }
.lightbox__caption { display: flex; align-items: center; justify-content: space-between; margin-top: 16px; gap: 16px; flex-wrap: wrap; }
.lightbox__caption strong { font-family: var(--font-display); font-size: 1.15rem; }
.lightbox__close {
  position: absolute; top: 24px; right: 24px; width: 44px; height: 44px; border-radius: 50%;
  background: var(--panel); border: 1px solid var(--border); color: var(--text); font-size: 1.2rem;
}
.lightbox__thumbs { display: none; gap: 10px; margin-top: 16px; flex-wrap: wrap; }
.lightbox__thumbs.is-visible { display: flex; }
.lightbox__thumb {
  width: 76px; height: 54px; border-radius: 8px; overflow: hidden; border: 2px solid var(--border);
  padding: 0; background: var(--panel); flex: none;
}
.lightbox__thumb img { width: 100%; height: 100%; object-fit: cover; }
.lightbox__thumb.is-active { border-color: #fff; }

/* ============================== Clientele ============================== */
/* Banner (if any) bleeds to the card's edges; body keeps normal padding.
   With a banner, the logo overlaps its bottom edge (Discord/Twitter-style
   cover + profile pic); without one, it just sits inline at the top. With
   neither image set, a plain letter-monogram avatar fills in instead. */
.client-card {
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius-md);
  display: flex; flex-direction: column; height: 100%; overflow: hidden;
}
.client-card__banner { aspect-ratio: 3 / 1; background: var(--bg-soft); }
.client-card__banner img { width: 100%; height: 100%; object-fit: cover; opacity: 0; transition: opacity .25s ease; }
.client-card__banner img.is-loaded { opacity: 1; }
.client-card__body { padding: 26px; display: flex; flex-direction: column; gap: 14px; flex: 1; }
.client-card.has-banner .client-card__body { padding-top: 12px; }
.client-card__logo {
  width: 46px; height: 46px; border-radius: 12px; background: transparent; border: 1px solid var(--border);
  display: grid; place-items: center; font-weight: 800; color: #fff; font-family: var(--font-display); flex: none;
}
.client-card__avatar { width: 46px; height: 46px; border-radius: 12px; object-fit: cover; border: 1px solid var(--border); flex: none; opacity: 0; transition: opacity .25s ease; }
.client-card__avatar.is-loaded { opacity: 1; }
.client-card__avatar--overlap {
  width: 54px; height: 54px; margin-top: -30px; border: 3px solid var(--panel); background: var(--panel);
}
.client-card h3 { font-size: 1.1rem; }
.client-card p { color: var(--text-muted); font-size: 0.92rem; flex: 1; }
.client-card a { color: #fff; font-weight: 600; font-size: 0.9rem; text-decoration: underline; text-underline-offset: 4px; }

/* ============================== Courses ============================== */
/* A stacked list of full-width bars, not a card grid - one row per
   course: a small square thumbnail (if any), title/description in the
   middle, price + enroll action pinned to the right. */
.course-grid { display: flex; flex-direction: column; gap: 14px; }
.course-card {
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius-md);
  display: flex; align-items: center; gap: 20px; padding: 18px 22px;
}
.course-card__media { width: 88px; height: 88px; flex: none; border-radius: var(--radius-sm); overflow: hidden; background: var(--bg-soft); }
.course-card__media img { width: 100%; height: 100%; object-fit: cover; opacity: 0; transition: opacity .25s ease; }
.course-card__media img.is-loaded { opacity: 1; }
.course-card__body { flex: 1; min-width: 0; }
.course-card__title-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.course-card h3 { font-size: 1.05rem; }
.course-card p { color: var(--text-muted); font-size: 0.9rem; margin-top: 4px; }
.course-card__status {
  font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
  padding: 3px 9px; border-radius: 999px; color: #fff; background: rgba(255,255,255,0.08); border: 1px solid var(--border);
}
.course-card__action { flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: 8px; }
.course-card__price { font-family: var(--font-display); font-weight: 600; color: #fff; font-size: 0.95rem; }
.course-card__soon-label { color: var(--text-faint); font-size: 0.85rem; font-weight: 600; white-space: nowrap; }
/* .hero__cta's own margin-top is sized for sitting below the hero's
   paragraph - reset it here, and drop the size a touch to fit a compact
   bar row instead of a full hero. */
.course-card__cta { margin-top: 0; font-size: 0.85rem; white-space: nowrap; }

@media (max-width: 640px) {
  .course-card { flex-wrap: wrap; }
  .course-card__media { width: 64px; height: 64px; }
  .course-card__action { flex-direction: row; align-items: center; justify-content: space-between; width: 100%; margin-top: 4px; }
}

/* ============================== Course player (admin preview) ============================== */
.course-player-layout { display: grid; grid-template-columns: 1fr 320px; gap: 24px; align-items: start; }
.course-player {
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius-md); padding: 16px;
  position: sticky; top: 100px;
}
/* The wrap sizes itself exactly to the video's rendered box (no padding
   of its own), so the watermark - positioned relative to *this*, not the
   padded .course-player panel around it - always sits on the video
   itself instead of drifting into the panel's gutter. */
.course-player__video-wrap { position: relative; }
.course-player video {
  width: 100%; max-height: 60vh; border-radius: var(--radius-sm); background: #000; display: block;
}
/* A CSS overlay still shows up in any screen recording (it's part of
   what's rendered on screen) even though it's not baked into the video
   pixels - good enough as a "this leaked from your account" deterrent
   without needing server-side video processing. Percentage offsets (not
   fixed px) keep it anchored to the video itself across every lesson's
   own resolution/aspect ratio. */
.course-player__watermark {
  position: absolute; bottom: 14%; right: 4%; pointer-events: none; user-select: none;
  color: rgba(255,255,255,0.6); font-size: 0.78rem; font-weight: 600; text-shadow: 0 1px 3px rgba(0,0,0,0.9);
}
.course-player__title { margin-top: 14px; font-family: var(--font-display); font-weight: 600; font-size: 1rem; }
.course-player__notes { margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--border-soft); color: var(--text-muted); line-height: 1.7; }
.course-player__notes h1, .course-player__notes h2, .course-player__notes h3 { font-family: var(--font-display); color: var(--text); margin: 16px 0 8px; }
.course-player__notes h1:first-child, .course-player__notes h2:first-child, .course-player__notes h3:first-child { margin-top: 0; }
.course-player__notes p { margin-bottom: 10px; }
.course-player__notes ul, .course-player__notes ol { margin: 0 0 10px 20px; display: flex; flex-direction: column; gap: 4px; }
.course-player__notes code { background: var(--bg-soft); padding: 2px 6px; border-radius: 4px; font-size: 0.88em; }
.course-player__notes pre { background: var(--bg-soft); padding: 14px; border-radius: var(--radius-sm); overflow-x: auto; margin-bottom: 10px; }
.course-player__notes a { text-decoration: underline; }

.course-curriculum { display: flex; flex-direction: column; gap: 10px; }
.course-module {
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius-md); overflow: hidden;
}
.course-module summary {
  padding: 14px 16px; cursor: pointer; font-weight: 600; font-size: 0.92rem;
  display: flex; align-items: center; justify-content: space-between; gap: 10px; list-style: none;
}
.course-module summary::-webkit-details-marker { display: none; }
.course-module__count { color: var(--text-faint); font-weight: 500; font-size: 0.8rem; }
.course-lesson-list { display: flex; flex-direction: column; border-top: 1px solid var(--border-soft); }
.course-chapter-label {
  padding: 10px 16px 4px; font-size: 0.72rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--text-faint); border-top: 1px solid var(--border-soft);
}
.course-lesson-list > .course-chapter-label:first-child { border-top: none; }
.course-lesson {
  background: transparent; border: none; border-bottom: 1px solid var(--border-soft); width: 100%;
  text-align: left; padding: 11px 16px; font: inherit; font-size: 0.85rem; color: var(--text-muted);
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
}
.course-lesson:last-child { border-bottom: none; }
.course-lesson:hover { color: var(--text); background: var(--bg-soft); }
.course-lesson.is-active { color: #fff; background: var(--bg-soft); font-weight: 600; }
.course-lesson__tag {
  font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--text-faint); border: 1px solid var(--border-soft); border-radius: 999px; padding: 2px 8px; flex: none;
}

.course-downloads { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 18px; }
.course-download-group {
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius-md); padding: 18px;
}
.course-download-group h3 { font-size: 0.95rem; margin-bottom: 10px; }
.course-download-group ul { display: flex; flex-direction: column; gap: 8px; }
.course-download-row { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.course-download-group a { font-size: 0.86rem; }
.course-download-group span { color: var(--text-faint); font-size: 0.76rem; white-space: nowrap; }
.course-download-note { color: var(--text-faint); font-size: 0.76rem; margin-top: 2px; }

@media (max-width: 860px) {
  .course-player-layout { grid-template-columns: 1fr; }
  .course-player { position: static; }
}

/* ============================== Page header (past-work) ============================== */
.page-header { padding-block: 74px 40px; }
.page-header h1 { font-size: clamp(2rem, 4vw, 2.8rem); }
.page-header p { color: var(--text-muted); margin-top: 12px; font-size: 1.05rem; max-width: 60ch; }

/* ============================== Clothing Viewer ============================== */
.viewer-layout { display: grid; grid-template-columns: 280px 1fr; gap: 24px; align-items: start; }
.viewer-panel {
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius-md); padding: 24px;
}
/* 1rem was the same size as body copy - indistinguishable as a heading.
   Matches the dashboard's compact-h2 size for a consistent scale. */
.viewer-panel h2 { font-size: 1.15rem; margin-bottom: 16px; }
.viewer-panel--form { position: sticky; top: 100px; }
.viewer-stage { display: flex; flex-direction: column; gap: 20px; }
.viewer-2d { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.viewer-2d__slot {
  position: relative; aspect-ratio: 4 / 3; background: var(--bg-soft); border: 1px solid var(--border-soft);
  border-radius: var(--radius-sm); display: grid; place-items: center; overflow: hidden;
}
.viewer-2d__slot img { display: none; width: 100%; height: 100%; object-fit: contain; }
.viewer-2d__label {
  position: absolute; top: 10px; left: 10px; font-size: 0.7rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--text-faint);
}
.viewer-2d__empty { color: var(--text-faint); font-size: 0.85rem; }
.viewer-3d { position: relative; aspect-ratio: 16 / 10; border: 1px solid var(--border-soft); border-radius: var(--radius-sm); overflow: hidden; background: radial-gradient(120% 100% at 50% 10%, #17181d 0%, #08090b 70%); }
.viewer-3d canvas { display: block; width: 100% !important; height: 100% !important; }
.viewer-composite {
  background: var(--bg-soft); border: 1px solid var(--border-soft); border-radius: var(--radius-sm);
  overflow: hidden; display: flex;
}
.viewer-composite canvas { display: block; width: 100%; height: auto; }

@media (max-width: 860px) {
  .viewer-layout { grid-template-columns: 1fr; }
  .viewer-panel--form { position: static; }
}

/* ============================== Legal pages ============================== */
.legal-content { max-width: 70ch; display: flex; flex-direction: column; gap: 6px; }
.legal-content h2 { font-size: 1.1rem; margin-top: 28px; }
.legal-content h2:first-child { margin-top: 0; }
.legal-content p { color: var(--text-muted); line-height: 1.7; }
.legal-content ul { margin: 4px 0 0 20px; display: flex; flex-direction: column; gap: 8px; }
.legal-content li { color: var(--text-muted); line-height: 1.6; list-style: disc; }
.legal-content a { color: var(--text); text-decoration: underline; text-underline-offset: 2px; }

/* ============================== Modal dialog ============================== */
/* Generic <dialog>-based confirmation modal - replaces browser confirm()
   for anything destructive/important enough to need a deliberate second
   step. Not profile-specific; reusable anywhere a confirm() would've been
   reached for. */
dialog.modal {
  background: var(--panel); color: var(--text); border: 1px solid var(--border); border-radius: var(--radius-lg);
  padding: 28px; width: 100%; max-width: 440px; margin: auto;
}
dialog.modal::backdrop { background: rgba(0, 0, 0, 0.6); }
dialog.modal h3 { font-size: 1.1rem; margin-bottom: 10px; }
dialog.modal p { color: var(--text-muted); font-size: 0.9rem; line-height: 1.6; }
dialog.modal a { color: var(--text); text-decoration: underline; text-underline-offset: 2px; }
dialog.modal .modal-links { font-size: 0.82rem; margin-top: 4px; }
.modal-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 20px; }

/* ============================== Profile ============================== */
/* Card chrome reuses .dash-panel (dashboard.css) rather than a separate
   look-alike class - this page is styled to match the dashboard, not
   invent its own variant of the same card. */
.profile-layout { display: flex; flex-direction: column; gap: 20px; }
.profile-identity { display: flex; align-items: center; gap: 14px; }
.profile-identity__avatar { width: 56px; height: 56px; border-radius: 50%; border: 1px solid var(--border); flex: none; }
.profile-identity__avatar--fallback {
  display: inline-flex; align-items: center; justify-content: center; background: var(--bg-soft);
  color: var(--text); font-weight: 700; font-size: 1.4rem; font-family: var(--font-display);
}
.profile-identity div { display: flex; flex-direction: column; gap: 2px; flex: 1; }
.profile-identity strong { font-size: 1.05rem; }
.profile-identity span { color: var(--text-faint); font-size: 0.85rem; }
.profile-code {
  font-family: var(--font-display); font-weight: 700; font-size: 1.3rem; letter-spacing: 0.05em;
  background: var(--bg-soft); border: 1px solid var(--border-soft); border-radius: var(--radius-sm);
  padding: 14px 16px; text-align: center; margin-bottom: 16px; user-select: all;
}
.profile-fallback { margin-top: 14px; }
.profile-fallback summary { color: var(--text-faint); font-size: 0.85rem; cursor: pointer; }
.profile-fallback summary:hover { color: var(--text-muted); }
.profile-fallback .profile-inline-form { margin-top: 14px; }
.profile-inline-form { display: flex; align-items: flex-end; gap: 12px; flex-wrap: wrap; }
.profile-inline-form .field { flex: 1; min-width: 200px; margin-bottom: 0; }

/* ============================== Footer ============================== */
.site-footer { border-top: 1px solid var(--border-soft); padding-block: 50px 26px; margin-top: 60px; }
.site-footer__grid { display: flex; justify-content: space-between; align-items: flex-start; gap: 24px; flex-wrap: wrap; }
.site-footer__tagline { color: var(--text-faint); margin-top: 10px; max-width: 32ch; font-size: 0.9rem; }
.site-footer__links { display: flex; gap: 22px; flex-wrap: wrap; }
.site-footer__links a { color: var(--text-muted); font-size: 0.9rem; }
.site-footer__links a:hover { color: var(--text); }
.site-footer__bottom {
  margin-top: 40px; padding-top: 20px; border-top: 1px solid var(--border-soft); color: var(--text-faint);
  font-size: 0.82rem; display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap;
}
.site-footer__legal { display: flex; align-items: center; gap: 16px; }
.site-footer__legal a { color: var(--text-faint); font-size: 0.82rem; }
.site-footer__legal a:hover { color: var(--text-muted); }

/* Fixed, not just scrolled-to-the-bottom - stays put over page content no
   matter how far down (or which page) you are, same idea as the sticky
   header but anchored to the opposite corner. */
.view-counter {
  position: fixed; left: 16px; bottom: 16px; z-index: 90;
  background: var(--panel); border: 1px solid var(--border); border-radius: 999px;
  padding: 8px 12px; font-size: 0.78rem; color: var(--text-faint);
  display: flex; align-items: center; gap: 6px;
}
.view-counter svg { flex: none; }

@media (max-width: 640px) {
  .section { padding-block: 56px; }
  .pw-toolbar { top: 73px; }
  .pw-masonry { grid-template-columns: 1fr; }
}
