/* Profile Page Styles */

/* The page is built like the landing and build pages: a full-bleed .landing
   scroll region between the fixed header/footer (shared shell in
   common/style.css -- including the html/body scroll lock, applied
   automatically via :has). Only the identity components below are
   profile-specific. */

/* ====================
   IDENTITY FEATURE ROW
   ==================== */

/* Skeleton: hide the row's content until ProfileHeader renders it, with
   the shared shimmer overlay (gradient/animation from Section.css)
   painted across the row meanwhile. */
.profile-header-skeleton {
  position: relative;
}

.profile-header-skeleton::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
}

.profile-header-skeleton > * {
  visibility: hidden;
}

.profile-username {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  /* A flex item will not shrink past its content without this, so the ellipsis
     above never gets the chance to fire. */
  min-width: 0;
}

.profile-username-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

/* Sign Out keeps its square: in a full row only the name gives way. */
.profile-username-row > .button-square {
  flex-shrink: 0;
}

/* Pushed to the far end of the name row. The name yields to it rather than
   the other way round -- a long one ellipses (see .profile-username), which
   needs the min-width floor lifted off it as a flex item. */
.profile-plan-edit {
  margin-left: auto;
  flex-shrink: 0;
}

.button-bare-inst-profile-edit {
  color: var(--color-text-dark);
  padding: var(--space-1);
  flex-shrink: 0;
}

.button-bare-inst-profile-edit:hover {
  color: var(--color-text);
}

.button-bare-inst-profile-edit svg {
  width: 16px;
  height: 16px;
}

/* The row's three sections -- Plan (your name over Build / Play / Connect,
   with the plan line), Credits (the card) and Avatar -- on a grid of their
   own inside the section. The section is the query container that decides
   the layout, and a container cannot query itself, so the grid lives on the
   wrapper and the section, a .feature grid of one item, runs one column.

   Three layouts by the section's width:
   - wide: one row, plan | credits | avatar, in fifths -- two each for Plan
     and Credits, one for Avatar, which is what its 16:9 floor is figured
     against;
   - middle, under 768px: plan | avatar over credits full width;
   - narrow, under 512px: all three stacked.
   minmax(0, ...) is load-bearing: a plain 2fr floors its track at its
   content's own min-width, and the stats block would squeeze the avatar out
   of shape.

   The plan line, the account buttons and the credits card are own-profile
   only. All three are keyed off the same class that lays the row out rather
   than a hidden attribute, so they are in flow from first paint and the
   skeleton reserves their space: profile.js drops .profile-header-own while
   the skeleton is still up, well before anything loads, and anyone else's
   profile is two plain columns, plan | avatar. */
.profile-header {
  grid-template-columns: 1fr;
}

.profile-header-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--content-gap);
}

.profile-header-own .profile-header-grid {
  grid-template-columns: minmax(0, 2fr) minmax(0, 2fr) minmax(0, 1fr);
  grid-template-areas: 'plan credits avatar';
}

.profile-header-own .feature-text {
  grid-area: plan;
}

.profile-header-own .profile-credits {
  grid-area: credits;
}

.profile-header-own .profile-avatar-container {
  grid-area: avatar;
}

/* The avatar's 16:9 floor, against its own track: half the row across on
   anyone else's profile, a fifth of it on your own, a third in your own
   middle layout, the whole row stacked. Restated per layout here, because
   the shared .feature-media rules (common/style.css) assume the tile sits
   in the section's own grid -- half the row, then the whole row once the
   section stacks under 768px -- and the row now lays itself out on the
   wrapper by its own width instead. These selectors outrank the shared
   mobile rule, which also locks a tile to 16:9 on a small screen; the
   avatar stays free of that, so beside Plan or Credits it stretches to
   their height, and only alone in its row does the floor set its height. */
.profile-header .feature-media {
  min-height: calc((100cqw - var(--content-gap)) / 2 * 9 / 16);
  aspect-ratio: auto;
}

.profile-header-own .feature-media {
  min-height: calc((100cqw - 2 * var(--content-gap)) / 5 * 9 / 16);
}

@container (max-width: 767px) {
  .profile-header-own .profile-header-grid {
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    grid-template-areas:
      'plan avatar'
      'credits credits';
  }

  .profile-header-own .feature-media {
    min-height: calc((100cqw - var(--content-gap)) / 3 * 9 / 16);
  }
}

@container (max-width: 511px) {
  .profile-header-grid {
    grid-template-columns: 1fr;
  }

  /* Restated for the own row: its middle-layout tracks above outrank the
     shared line by a class. */
  .profile-header-own .profile-header-grid {
    grid-template-columns: 1fr;
    grid-template-areas:
      'plan'
      'credits'
      'avatar';
  }

  /* Either row, own or not: the avatar has the row to itself. Later than
     the own row's fifths and thirds above at the same specificity, so
     order decides. */
  .profile-header .feature-media {
    min-height: calc(100cqw * 9 / 16);
  }
}

.profile-header:not(.profile-header-own) .profile-credits,
.profile-header:not(.profile-header-own) .profile-plan,
.profile-header:not(.profile-header-own) .profile-plan-edit {
  display: none;
}

/* The 3D avatar fills the row's media column (drag to rotate), framed as a
   surface card. Its height matches the landing's media panels via the
   universal media-panel rule in common/style.css (fills, floored at 16:9). */
.profile-avatar-container {
  position: relative;
  width: 100%;
  cursor: grab;
  background: var(--color-surface);
  border: var(--border-width) var(--border-style) var(--color-border);
  border-radius: var(--radius-lg);
  overflow: hidden;
}

.profile-avatar-container:active {
  cursor: grabbing;
}

.profile-avatar-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transition: opacity 0.2s ease;
}

.profile-avatar-placeholder {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-text-dark);
}

.profile-avatar-placeholder svg {
  width: 48px;
  height: 48px;
}

/* Follow/Unfollow overlays the avatar card on other users' profiles
   (their identity row has no account column). */
.profile-avatar-container .profile-follow-btn {
  position: absolute;
  top: var(--space-2);
  right: var(--space-2);
  z-index: 1;
}

.button-bare-inst-avatar-edit {
  position: absolute;
  top: var(--space-1);
  right: var(--space-1);
  color: var(--color-text-dark);
  padding: var(--space-1);
  z-index: 1;
}

.button-bare-inst-avatar-edit:hover {
  color: var(--color-text);
}

.button-bare-inst-avatar-edit svg {
  width: 16px;
  height: 16px;
}

/* ====================
   PROFILE STATS
   ==================== */

/* The stats block re-flows against its own column's width (container
   query below), not the viewport -- the identity row's column width and
   the 768px stack both change it independently. */
.profile-header .feature-text {
  container-type: inline-size;
}

/* Build | Play | Connect, side by side. The grid is on this wrapper rather
   than on #profile-stats because ProfileHeader rewrites that element's
   contents; display:contents below hands its columns up to be items here. */
.profile-identity-columns {
  display: grid;
  /* auto-fit rather than a fixed three: the count then follows the space it
     actually has, which no hand-picked breakpoint managed -- the block tops
     out at 606px, so a fold written for 620 fired at every width. It also
     covers the case this grid holds only two columns, on somebody else's
     profile, where there is no Play.

     90px is a column's own min-content with small figures ("0 Followers" is
     86); a bigger count (the formatter caps at five characters, "99.9M")
     needs up to 123, and past the floor its label clips to an ellipsis
     rather than widening the column (see .profile-stats-header-label). The
     gap comes down a step with the floor: it sets the fold point as surely
     as the floor does. */
  grid-template-columns: repeat(auto-fit, minmax(90px, 1fr));
  gap: var(--space-2);
  margin-top: var(--space-2);
  /* Reserve the block before the figures land, so the row does not grow under
     the reader. One row of three; the transposed fold below reserves its own. */
  min-height: 95px;
}

/* A pass-through: ProfileHeader owns what is inside it, but its columns are
   items of the grid above. */
.profile-stats {
  display: contents;
}

.profile-stats-column {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

/* Build / Play / Connect, and the credits card's own heading, which reuses
   this. The gap is for the accent icon each one carries. */
.profile-stats-column-header {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-bold);
  color: var(--color-text-dark);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  padding-bottom: var(--space-1);
  border-bottom: var(--border-width) var(--border-style) var(--color-border);
}

/* The accent marks the heading, not the words under it -- same weight and
   colour as the meter icons inside the credits card, so all four headings in
   the row read as one set. */
.profile-stats-column-header svg {
  flex: 0 0 16px;
  width: 16px;
  height: 16px;
  color: var(--color-accent-text);
}

.profile-stats-group {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.profile-stats-header {
  display: flex;
  align-items: baseline;
  gap: var(--space-1);
  /* The figure always shows whole; the label gives way first. */
  min-width: 0;
}

.profile-stats-header-value {
  font-size: var(--font-size-lg);
  font-weight: var(--font-weight-bold);
  color: var(--color-text);
}

.profile-stats-header-label {
  font-size: var(--font-size-sm);
  color: var(--color-text-dark);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  /* Clips to an ellipsis when its column is narrower than figure + word
     (a big count in a column at the floor), so the columns stay a set. */
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Below the width three columns need (a 90px floor and a 10px gap makes 290),
   transpose rather than wrap. Wrapping leaves two categories side by side and
   the third stranded on a row of its own, which reads as a mistake; transposed,
   each category is a full-width row -- its header spanning, its two figures
   side by side beneath -- and the three rows stay a set.

   The base rule above stays auto-fit for the other case it has to serve:
   somebody else's profile, where the grid holds two categories rather than
   three and their empty track should collapse. */
@container (max-width: 289px) {
  .profile-identity-columns {
    grid-template-columns: 1fr;
    /* Three category rows, each a header over one line of figures. */
    min-height: 205px;
  }

  .profile-stats-column {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-2);
  }

  .profile-stats-column-header {
    grid-column: 1 / -1;
  }
}

/* ====================
   PROFILE PLAN
   ==================== */

/* The plan is the lead line under your name -- same shape as every panel's
   heading and line. It holds its line before the tier and reset date arrive,
   so the stats below it do not step down the page as they land. */
.profile-plan {
  min-height: calc(1.5 * var(--font-size-lg));
  /* The tier is the line; the reset is an aside on it. .feature-lead is one
     colour throughout, so the two steps here are the plan name taking the
     brighter of the two text tokens and the bracket keeping the dimmer. */
  color: var(--color-text);
}

.profile-plan span {
  color: var(--color-text-dark);
}

/* Below 310px the line takes a second one once the reset aside lands, so
   the reservation does too -- for as long as the aside is still to come.
   ProfileHeader drops the marker when it settles the line either way, so a
   line that stays short (a preview, or a reset the server could not name)
   does not hold a blank one open under itself. Placed after the rule above
   rather than beside the column folds: same specificity, so source order is
   what decides which wins. */
@container (max-width: 309px) {
  .profile-plan-pending {
    min-height: calc(3 * var(--font-size-lg));
  }
}

/* ====================
   PROFILE CREDITS
   ==================== */

/* The one card inside the identity panel, because the credits are the only
   part of the row you can act on. Stats and plan stay on the same hairline
   headers the rest of the site uses. */
.profile-credits {
  container-type: inline-size;
  padding: var(--space-3);
  background: var(--color-surface);
  border: var(--border-width) var(--border-style) var(--color-border);
  border-radius: var(--radius-lg);
}

/* The head's own rule spans the whole card, so the column header reused
   inside it drops its hairline and the padding that went with it. */
/* One column of the identity row is not wide enough to promise the heading
   and the button a line each, so they wrap when they have to. */
.profile-credits-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-2);
  padding-bottom: var(--space-2);
  border-bottom: var(--border-width) var(--border-style) var(--color-border);
}

.profile-credits-head .profile-stats-column-header {
  padding-bottom: 0;
  border-bottom: none;
}

.profile-credits-groups {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-top: var(--space-2);
  /* Reserve the meters before they load -- the same trick .profile-stats
     uses above. Every tier shows both groups (Media always has an allowance,
     Chat always has Quick and Standard), so the floor is two group rows and
     the card never changes height once the balances land. */
  min-height: 140px;
}

.profile-credits-group-label {
  font-size: var(--font-size-sm);
  color: var(--color-text-dark);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  margin-bottom: var(--space-2);
}

/* One track per group, sized by ProfileHeader to the buckets that group
   actually shows -- a tier missing one (Advanced on Basic) narrows the row
   rather than leaving a hole at the end of it. */
.profile-credits-grid {
  display: grid;
  grid-template-columns: repeat(var(--credit-columns, 3), minmax(0, 1fr));
  gap: var(--space-2) var(--space-4);
}

/* Narrow card -- which is every card in the identity row now that it is one
   of its three sections, as well as the stacked mobile one. The per-group
   track (up to four Media buckets) does not fit, so every group falls back
   to two. */
@container (max-width: 700px) {
  .profile-credits-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  /* Two columns means twice the rows, so the reservation above is short by
     the same amount. Without this the card still grows as the balances land. */
  .profile-credits-groups {
    min-height: 225px;
  }
}

/* Narrower still (a small phone): two meters no longer fit side by side
   without the names truncating to nothing, so they stack. */
@container (max-width: 220px) {
  .profile-credits-grid {
    grid-template-columns: 1fr;
  }
}

.profile-meter {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.profile-meter-top {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.profile-meter-icon {
  display: inline-flex;
  flex: 0 0 16px;
  color: var(--color-accent-text);
}

.profile-meter-icon svg {
  width: 16px;
  height: 16px;
}

.profile-meter-name {
  flex: 1;
  min-width: 0;
  font-size: var(--font-size-sm);
  color: var(--color-text-dark);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The number spent is the figure being read; the allowance behind it is the
   scale it is read against, so it stays in the quieter weight and color. */
.profile-meter-count {
  font-size: var(--font-size);
  font-weight: var(--font-weight-bold);
  color: var(--color-text);
  white-space: nowrap;
}

.profile-meter-count span {
  font-weight: var(--font-weight);
  color: var(--color-text-dark);
}

/* A bucket this plan does not include: still listed, so the level is visible
   as something to upgrade to, but held back so it never reads as a meter
   that failed to load. */
.profile-meter-empty {
  opacity: 0.5;
}

.profile-meter-track {
  height: 5px;
  border-radius: var(--radius-sm);
  background: var(--color-border);
  overflow: hidden;
}

.profile-meter-fill {
  height: 100%;
  border-radius: var(--radius-sm);
  background: var(--color-accent);
}

/* ====================
   PEOPLE ROWS
   ==================== */

/* Following / Children — avatar tiles use contain-fit, not cover-crop */
#section-following .project-thumbnail,
#section-children .project-thumbnail {
  background: var(--color-background);
}

#section-following .project-screenshot,
#section-children .project-screenshot {
  object-fit: contain;
}

/* ====================
   FOLDED (home)
   ==================== */

/* The row folded to its first line, whatever the width lays out, with the
   rest behind a Show More -- how the home page carries it (home.js toggles
   the class). Across, the first line is the whole row: nothing folds, so the
   control has nothing to show and hides, and the band it would float in
   closes back to the panel's normal padding. In the middle layout Credits
   folds under Plan beside Avatar; stacked, Credits and Avatar fold under
   Plan. The control is the grids' own (.grid-more, common/style.css) and
   sits in the same bottom band; a grid's reaches it from the grid's foot
   (top: 100%), while here the section is the positioned box, so it is
   pinned to the band's bottom instead. The band itself: a section cannot
   size its own padding by its own width, so the panel keeps its normal
   padding and the grid inside carries the rest of the band as a bottom
   margin while the control shows. */
.profile-header > .grid-more {
  display: none;
  top: auto;
  bottom: 0;
}

.profile-header:has(> .grid-more) {
  padding-bottom: var(--content-gap);
}

@container (max-width: 767px) {
  .profile-header > .grid-more {
    display: inline-flex;
  }

  .profile-header:has(> .grid-more) .profile-header-grid {
    margin-bottom: calc(max(2 * var(--content-gap), 2 * var(--space-3)) - var(--content-gap));
  }

  .profile-header-collapsed .profile-credits {
    display: none;
  }

  .profile-header-collapsed .profile-header-grid {
    grid-template-areas: 'plan avatar';
  }
}

@container (max-width: 511px) {
  .profile-header-collapsed .profile-avatar-container {
    display: none;
  }

  .profile-header-collapsed .profile-header-grid {
    grid-template-areas: 'plan';
  }
}
