/* =========================================================================
   PFP generator (/pfp) - page-specific styles.

   Tokens, the two type faces and the button treatment all come from
   style.css. This file adds the page layout, the fixed nav/bar and the
   canvas stage. No token is redefined here.

   ONE VIEWPORT, NO SCROLL: html/body get overflow:hidden and .pfp sits
   between the fixed nav and the fixed action bar with its own height, so
   everything has to fit. See the sizing notes below .pfp.

   STATE: whether a photo is loaded is tracked with a single class,
   body.has-photo (toggled by pfp.js). Every element that differs between
   the two states is written as a plain pair of rules - unguarded selector
   for the "before" look, "body.has-photo <selector>" for "after" - and
   never relies on the [hidden] attribute for elements that also carry a
   plain author `display` rule. (That combination is a real footgun: a
   bare author `display` on an element always beats the UA's
   `[hidden] { display: none }`, no matter the specificity, because it's a
   higher-priority origin. Mixing the two silently breaks hiding - it did,
   once, on this page. state-class pairs sidestep it entirely.)

   Radius rule from style.css: "buttons are pills; cards use --radius-card;
   nothing else rounds." Buttons, the nav button, the pencil badge and the
   slider track/thumb are pills. The mock profile card (20px) and mock
   timeline row (16px) inside the preview overlay use their own literal
   radii, per spec, rather than --radius-card (18px) - they are content
   mockups of an X UI, not site chrome, so they don't answer to the site's
   radius scale.
   ========================================================================= */

/* The page never scrolls - everything is sized to fit between the fixed nav
   and the fixed action bar. overscroll-behavior stops iOS/Android rubber-
   banding from peeking past that edge. */
html,
body {
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;
}

body {
  /* Reserved height for the action bar (see .pfp-bar's own comment for the
     arithmetic): .pfp's bottom padding matches this so centred content
     never sits under the bar. One shared variable so the two can't drift
     apart. */
  --pfp-bar-reserve: calc(136px + env(safe-area-inset-bottom, 0px));
}

/* --- fixed nav --------------------------------------------------------------
   The shared .site-header/.site-nav/.brand/.hamburger from style.css, with
   the --static modifier (also shared) seating the logo/hamburger in their
   settled nav spot from first paint - this page has no hero to animate
   from. See style.css for the actual rules. */

/* --- page shell -------------------------------------------------------------
   Fixed between the nav and the action bar. Anchored to the top (not
   centred) so the heading sits high with the slack landing below the last
   element, above the bar, rather than split around the whole block. The
   gap is a fluid vh value so it compresses first on a short viewport,
   before anything would need to shrink. */

.pfp {
  position: fixed;
  inset: var(--nav-h) 0 0 0;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: clamp(6px, 1.8vh, 16px);
  /* Dialled back from an earlier pass that pushed the heading too far
     down; still comfortably inside the fit budget at 375x667. The gap
     between the sub and the circle is set separately, by .pfp__circle's
     margin-top - untouched here. */
  padding: clamp(10px, 4vh, 32px) var(--space-inline) var(--pfp-bar-reserve);
  background: var(--surface);
  overflow: hidden;
}

.no-js .pfp { display: none; }

/* --- heading + sub ----------------------------------------------------------
   Same tight display-type convention as the landing headings, sized down
   for a page that has to fit in one screen (32px mobile / 44px desktop
   instead of the landing's 44-82px clamp). */

.pfp__intro {
  flex: none;
  max-width: 320px;
  text-align: center;
}

.pfp__title {
  margin: 0 0 4px;
  font: 700 32px/0.95 var(--font-display);
  letter-spacing: -0.03em;
}

@media (min-width: 768px) {
  .pfp__title { font-size: 44px; }
}

.pfp__sub {
  margin: 0;
  font: 500 15px/1.45 var(--font-body);
  color: var(--grey-600);
}

/* --- circle -------------------------------------------------------------
   No container chrome - the circular frame art is the only visible edge.
   210px on mobile (250px from 768px up); min() with a vw floor is just a
   safety net for anything narrower than tested, not a redesign of the
   size. The canvas is 1600x1600 internally (see pfp.js) and scaled to fill
   this box by CSS; that scaling never touches the export resolution.

   margin-top pulls it closer to the sub than the shared flex gap alone
   would - the gap itself is untouched so the circle-to-zoom and
   zoom-to-hint spacing stay exactly as they were. */

.pfp__circle {
  position: relative;
  flex: none;
  width: min(210px, 80vw);
  aspect-ratio: 1 / 1;
  margin-top: 2px;
  touch-action: none;   /* dragging the photo must not scroll the page */
  cursor: default;
}

@media (min-width: 768px) {
  .pfp__circle { width: min(250px, 80vw); }
}

.pfp__circle.is-loaded { cursor: grab; }
.pfp__circle.is-loaded:active { cursor: grabbing; }

.pfp__canvas {
  display: block;
  width: 100%;
  height: 100%;
}

/* Standard avatar silhouette - shown until a photo is chosen, gone once one
   is (body.has-photo). Purely decorative: inert, never clickable. */
.pfp__silhouette {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 100px;
  height: 100px;
  fill: var(--ink);
  opacity: 0.24;
  pointer-events: none;
}

body.has-photo .pfp__silhouette { display: none; }

/* Change-photo pencil. Does not exist in the "before" state. Positioned at
   roughly the 3:50 mark rather than the naive bottom-right corner: measured
   from frame.png, its curved "MAKE ART GREAT AGAIN" lettering runs from
   about 4:15 to 7 o'clock around the bottom of the ring, and the naive
   corner position (~4:30) sits squarely on top of that. Pulled back to
   3:50 leaves a clear ~25px gap of plain gold ring between the badge and
   the first letter. left/top are the badge's CENTRE as a % of the circle
   box (so this still lines up if the circle's size ever changes), pulled
   back to actually centre on that point with translate(). */
.pfp__pencil {
  position: absolute;
  left: 94.7%;
  top: 70.8%;
  transform: translate(-50%, -50%);
  display: none;
  align-items: center;
  justify-content: center;
  width: 50px;
  height: 50px;
  padding: 0;
  background: var(--accent);
  border: var(--bd-w) solid var(--ink);
  border-radius: var(--radius-pill);
  box-shadow: 0 3px 8px rgba(26, 26, 26, 0.35);
  color: var(--ink);
  cursor: pointer;
}

body.has-photo .pfp__pencil { display: flex; }

.pfp__pencil svg { width: 22px; height: 22px; }
.pfp__pencil:hover { background: var(--accent-hover); }
.pfp__pencil:active { transform: translate(-50%, -50%) scale(0.92); }

/* --- zoom + drag hint -----------------------------------------------------
   Both only exist once a photo is loaded. */

.pfp__zoom {
  display: none;
  flex: none;
  align-items: center;
  gap: calc(var(--space) * 1.5);
  width: min(250px, 80vw);
}

body.has-photo .pfp__zoom { display: flex; }

.pfp__zoom label {
  font: 700 0.7rem/1 var(--font-body);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--grey-600);
}

/* Range input styled to the site, not the browser default: an ink track and
   a gold thumb with the same heavy black outline as the buttons. The
   ::-webkit-* and ::-moz-* pseudo-elements cannot share a rule, so the
   track and thumb declarations are repeated per engine. */
.pfp__zoom input[type="range"] {
  flex: 1;
  height: 44px;   /* full-height hit area for touch; the visible track is 10px */
  margin: 0;
  background: transparent;
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
}

.pfp__zoom input[type="range"]:disabled {
  cursor: not-allowed;
  opacity: 0.4;
}

.pfp__zoom input[type="range"]::-webkit-slider-runnable-track {
  height: 10px;
  border-radius: var(--radius-pill);
  background: var(--ink);
}

.pfp__zoom input[type="range"]::-moz-range-track {
  height: 10px;
  border-radius: var(--radius-pill);
  background: var(--ink);
}

.pfp__zoom input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 26px;
  height: 26px;
  margin-top: -8px;   /* centre the 26px thumb on the 10px track */
  border: var(--bd-w) solid var(--ink);
  border-radius: var(--radius-pill);
  background: var(--accent);
}

.pfp__zoom input[type="range"]::-moz-range-thumb {
  width: 26px;
  height: 26px;
  border: var(--bd-w) solid var(--ink);
  border-radius: var(--radius-pill);
  background: var(--accent);
}

.pfp__hint {
  display: none;
  flex: none;
  margin: 0;
  font: 500 12px/1.4 var(--font-body);
  color: var(--grey-600);
  text-align: center;
}

body.has-photo .pfp__hint { display: block; }

.pfp__error {
  flex: none;
  margin: 0;
  padding: calc(var(--space) * 1.5) calc(var(--space) * 2);
  font: 700 0.9rem/1.4 var(--font-body);
  color: var(--ink);
  background: var(--lose);   /* the payoff-grid "lose" tone, reused for errors */
  border: var(--bd-w) solid var(--ink);
  border-radius: var(--radius-card);
}

.pfp__noscript {
  margin: calc(var(--nav-h) + 24px) auto 0;
  max-width: 320px;
  padding: calc(var(--space) * 2);
  text-align: center;
  font: 500 0.95rem/1.5 var(--font-body);
  color: var(--ink);
  background: var(--grey-100);
  border: var(--bd-w) solid var(--ink);
  border-radius: var(--radius-card);
}

/* --- action bar -----------------------------------------------------------
   Fixed to the foot, full width, cream. A short gradient above it fades
   content passing underneath rather than cutting it off with a hard edge.

   Height arithmetic (kept in sync with --pfp-bar-reserve above):
   16 padding-top + 48 button row + 12 gap + ~32 two-line privacy copy
   + 16 padding-bottom = 124, rounded up to 136 for breathing room, then
   env(safe-area-inset-bottom) on top for the home-indicator area. */

.pfp-bar {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 45;
  display: flex;
  justify-content: center;
  padding: calc(var(--space) * 2) var(--space-inline)
           calc(env(safe-area-inset-bottom, 0px) + var(--space) * 2);
  background: var(--surface);
}

.no-js .pfp-bar { display: none; }

.pfp-bar::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 100%;
  height: 40px;
  background: linear-gradient(to bottom, transparent, var(--surface));
  pointer-events: none;
}

.pfp-bar__inner {
  width: 100%;
  max-width: 340px;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: calc(var(--space) * 1.5);
}

/* Button: the site's primary treatment (see .site-menu__link--cta in
   style.css) without the fixed positioning - gold fill, heavy black
   outline, hard offset shadow, pill. */
.pfp-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 48px;
  padding: 0.6em 1.2em;
  font: 700 1rem/1 var(--font-display);
  letter-spacing: 0.01em;
  white-space: nowrap;
  color: var(--accent-ink);
  background: var(--accent);
  border: var(--bd-w) solid var(--ink);
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-hard);
  cursor: pointer;
}

.pfp-btn:hover { background: var(--accent-hover); }

.pfp-btn:active {
  box-shadow: 2px 2px 0 var(--ink);
  transform: translate(2px, 2px);
}

.pfp-btn:disabled {
  background: var(--grey-200);
  color: var(--grey-600);
  box-shadow: none;
  cursor: not-allowed;
  transform: none;
}

.pfp-btn__icon { flex: none; width: 20px; height: 20px; }

/* The single before-state button - full width, hidden once a photo loads. */
.pfp-btn--full { display: flex; width: 100%; }
body.has-photo .pfp-btn--full { display: none; }

/* Secondary treatment for "Preview": cream fill instead of gold, so
   "Download" (gold, primary) is the one action that reads as the point of
   the page. */
.pfp-btn--secondary {
  background: var(--surface);
  color: var(--ink);
}
.pfp-btn--secondary:hover { background: var(--grey-100); }
.pfp-btn--secondary:disabled { background: var(--grey-100); color: var(--grey-400); }

/* The after-state pair - equal width, hidden until a photo loads. */
.pfp-bar__actions {
  display: none;
  gap: calc(var(--space) * 1.5);
}
body.has-photo .pfp-bar__actions { display: flex; }
.pfp-bar__actions .pfp-btn { flex: 1 1 0; }

/* Always visible, in both states. */
.pfp__privacy {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  margin: 0;
  font: 500 11.5px/1.4 var(--font-body);
  color: var(--grey-600);
  text-align: left;
}

.pfp__lock {
  flex: none;
  width: 14px;
  height: 14px;
  margin-top: 1px;
}

/* --- preview overlay --------------------------------------------------------
   Full-screen, dimmed + blurred backdrop. .pfp-overlay itself carries
   [hidden] - display is only ever set from the :not([hidden]) rule below,
   never unconditionally, so it never fights the attribute (see the top-of-
   file note on that footgun). Its children don't need the same guard: an
   ancestor's display:none already hides them regardless of their own
   display value. */

.pfp-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  padding: calc(var(--space) * 3) var(--space-inline);
  background: rgba(26, 26, 26, 0.55);
  -webkit-backdrop-filter: blur(6px);
          backdrop-filter: blur(6px);
}

.pfp-overlay:not([hidden]) {
  display: flex;
  align-items: center;
  justify-content: center;
}

.pfp-overlay__close {
  position: fixed;
  top: calc(env(safe-area-inset-top, 0px) + 16px);
  right: 16px;
  z-index: 101;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  background: var(--surface);
  border: var(--bd-w) solid var(--ink);
  border-radius: var(--radius-pill);
  color: var(--ink);
  cursor: pointer;
}

.pfp-overlay__close:hover { background: var(--grey-100); }
.pfp-overlay__close svg { width: 18px; height: 18px; }

.pfp-overlay__sheet {
  width: 100%;
  max-width: 360px;
  max-height: 100%;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: calc(var(--space) * 2);
}

.pfp-overlay__caption {
  margin: 0;
  font: 700 11px/1 var(--font-body);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: rgba(255, 255, 255, 0.75);
  text-align: center;
}

/* --- mock profile card ----------------------------------------------------
   Content mockup, not site chrome - its own card radius and its own
   (non-token) blue banner colour, reusing --field so it still ties back to
   the brand rather than an arbitrary hue. */

.pfp-card {
  position: relative;
  background: #fff;
  border-radius: 20px;
  overflow: hidden;
  padding-bottom: calc(var(--space) * 2);
}

.pfp-card__banner {
  height: 100px;
  background: linear-gradient(135deg, var(--field), #2e5c8a);
}

.pfp-card__avatar {
  position: absolute;
  left: 20px;
  top: 40px;   /* banner height (100) - half the avatar (60) */
  width: 120px;
  height: 120px;
  border: 4px solid #fff;
  border-radius: 50%;
  background: var(--grey-100);
  object-fit: cover;
}

.pfp-card__follow {
  position: absolute;
  top: 112px;
  right: 20px;
  display: inline-flex;
  align-items: center;
  padding: 6px 16px;
  font: 700 13px/1 var(--font-body);
  color: #fff;
  background: var(--ink);
  border-radius: var(--radius-pill);
  text-decoration: none;
}

.pfp-card__body {
  /* avatar bottom (40 + 120 = 160) - banner bottom (100) = 60, +8 gap */
  padding: 68px 20px 4px;
}

.pfp-card__name {
  margin: 0;
  font: 700 17px/1.25 var(--font-body);
  color: var(--ink);
}

.pfp-card__handle {
  margin: 2px 0 0;
  font: 500 14px/1.3 var(--font-body);
  color: var(--grey-600);
}

.pfp-card__bio {
  margin: 10px 0 0;
  font: 500 14px/1.4 var(--font-body);
  color: var(--ink);
}

.pfp-card__stats {
  margin: 10px 0 0;
  font: 500 13px/1.3 var(--font-body);
  color: var(--grey-600);
}

.pfp-card__stats strong { color: var(--ink); }

/* --- mock timeline row ------------------------------------------------------
   The 44px avatar is the point of this mockup: it shows whether the frame
   still reads at true timeline size. */

.pfp-tweet {
  display: flex;
  gap: 10px;
  background: #fff;
  border-radius: 16px;
  padding: 14px;
}

.pfp-tweet__avatar {
  flex: none;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--grey-100);
  object-fit: cover;
}

.pfp-tweet__meta {
  margin: 0;
  font: 500 13px/1.3 var(--font-body);
  color: var(--ink);
}

.pfp-tweet__meta strong { font-weight: 700; }
.pfp-tweet__meta span { font-weight: 500; color: var(--grey-600); }

.pfp-tweet__text {
  margin: 4px 0 0;
  font: 500 14px/1.4 var(--font-body);
  color: var(--ink);
}

/* --- reduced motion -------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .pfp-btn:active,
  .pfp__pencil:active { transform: none; }
}
