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

   A real page rather than a settings card: cover photo, identity strip, then a
   scrollable timeline with details parked in a sidebar. */

.profile { max-width: 1140px; margin: 0 auto; padding: 0 var(--s4) var(--s6); }

.profile__cover {
  position: relative;
  height: clamp(160px, 26vh, 300px);
  border: var(--edge);
  border-top: 0;
  background-color: #101010;
  background-image: var(--cover);
  background-size: cover;
  background-position: center;
}
.profile__cover--empty {
  background-image:
    repeating-linear-gradient(135deg, #0e0e0e 0 18px, #141414 18px 36px);
}
.profile__cover::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.85), transparent 60%);
  pointer-events: none;
}

/* z-index 3 trapped this control's panel below .profile__identity (z-index 5),
   which is transparent where it overlaps but still captures clicks; the panel
   would render yet the UPLOAD button underneath it could be unclickable. It now
   sits above the identity strip, and higher still while open. */
.profile__cover-edit { position: absolute; right: var(--s3); top: var(--s3); z-index: 30; }
.profile__cover-edit[open] { z-index: 60; }
.profile__cover-edit > summary,
.profile__edit > summary { list-style: none; cursor: pointer; font-size: 0.78rem; }
.profile__cover-edit > summary::-webkit-details-marker,
.profile__edit > summary::-webkit-details-marker { display: none; }

.profile__edit-panel {
  position: absolute;
  right: 0;
  top: calc(100% + 8px);
  z-index: 40;
  width: min(330px, 86vw);
  display: grid;
  gap: var(--s3);
  padding: var(--s3);
  background: var(--ink-soft);
  border: var(--edge);
  border-top: 6px solid var(--accent);
  box-shadow: 10px 10px 0 rgba(0, 0, 0, 0.6);
  text-align: left;
  animation: slam 220ms var(--ease-slam) both;
}
.profile__edit-panel form { display: grid; gap: var(--s2); }
.profile__edit-panel label {
  display: grid;
  gap: var(--s1);
  font-family: var(--display);
  font-size: 0.72rem;
  letter-spacing: 0.12em;
  color: var(--paper-dim);
}
.profile__edit-panel input[type="text"],
.profile__edit-panel input[type="file"],
.profile__edit-panel textarea {
  font: inherit;
  font-size: 0.85rem;
  padding: var(--s1) var(--s2);
  color: var(--paper);
  background: #000;
  border: 1px solid var(--paper-dim);
}
.profile__edit-panel .btn { transform: none; font-size: 0.78rem; }
.profile__details-form { border-top: 1px solid #2c2c2c; padding-top: var(--s3); }

/* Identity strip overlaps the cover, the way a profile header usually does. */
.profile__identity {
  position: relative;
  display: flex;
  align-items: flex-end;
  gap: var(--s3);
  margin-top: -46px;
  padding: 0 var(--s3) var(--s4);
  z-index: 5;
}

/* The saved collection reuses this layout for its heading, but has no cover photo to
   hang off; the negative margin exists to pull the avatar up over one, and without a
   cover it drags the title off the top of the page. */
.profile__identity--plain { margin-top: 0; padding-top: var(--s4); }

/* A notched square, not a circle and not the four-point star used in the header:
   a star crops away most of a face, which is the one thing an avatar must keep. */
.profile__avatar {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: clamp(96px, 13vw, 132px);
  aspect-ratio: 1;
  background: var(--accent);
  color: var(--on-accent);
  border: 3px solid var(--ink);
  clip-path: polygon(18% 0, 100% 0, 100% 82%, 82% 100%, 0 100%, 0 18%);
  overflow: hidden;
}
.profile__avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.profile__initial { font-family: var(--display); font-size: 3rem; line-height: 1; }

.profile__names { min-width: 0; padding-bottom: var(--s1); }
.profile__names h1 { margin: 0; font-size: clamp(1.6rem, 5vw, 3rem); color: var(--paper); }
.profile__handle {
  margin: var(--s1) 0 0;
  font-size: 0.85rem;
  letter-spacing: 0.08em;
  color: var(--paper-dim);
}
.profile__rank {
  margin-left: var(--s2);
  padding: 1px 8px;
  font-family: var(--display);
  font-size: 0.62rem;
  letter-spacing: 0.18em;
  color: var(--on-accent);
  background: var(--accent);
}
.profile__bio { margin: var(--s2) 0 0; max-width: 60ch; line-height: 1.5; font-size: 0.92rem; }

.profile__edit { position: relative; margin-left: auto; padding-bottom: var(--s1); }

.profile__layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: var(--s4);
  align-items: start;
}
.profile__feed { min-width: 0; }
.profile__side { display: grid; gap: var(--s3); position: sticky; top: var(--s3); }

.profile__where {
  margin: 0 0 calc(var(--s1) * -1);
  font-family: var(--display);
  font-size: 0.66rem;
  letter-spacing: 0.16em;
  color: var(--paper-dim);
}

@media (max-width: 940px) {
  .profile__layout { grid-template-columns: 1fr; }
  .profile__side { position: static; }
}

@media (max-width: 620px) {
  .profile__identity { flex-wrap: wrap; margin-top: -34px; }
  .profile__edit { margin-left: 0; width: 100%; }
  /* Only the identity-strip panel: that DETAILS spans the card here, so its left
     edge is the card's. The cover-photo DETAILS sits in the top right corner, and
     left-aligning its panel there threw it off the right of the screen. */
  .profile__edit > .profile__edit-panel { right: auto; left: 0; }
}

/* .stat-list is defined in auth.css, which the profile page does not load.
   Restating it here keeps the sidebar readable without pulling in a stylesheet
   built for the login card. */
.profile .stat-list {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--s1) var(--s3);
  margin: 0 0 var(--s3);
  font-size: 0.82rem;
}
.profile .stat-list dt {
  font-family: var(--display);
  letter-spacing: 0.12em;
  font-size: 0.7rem;
  color: var(--accent);
  align-self: center;
}
.profile .stat-list dd { margin: 0; color: var(--paper); overflow-wrap: anywhere; }

/* The masked mark stands in until someone uploads a picture. */
.profile__anon { width: 58%; height: 58%; object-fit: contain; opacity: 0.9; }

/* ------------------------------------------------------------------- the door

   An unmarked diamond in the sidebar of one profile. It is not hidden from the
   DOM; hiding a control from assistive technology to keep a secret is hostile,
   and the secret is the phrase, not the button. It is simply quiet: dim until
   hovered, no label, no explanation of what lies behind it. */
.side-card--host { position: relative; }

/* Tucked into the corner of a card that was already there: a full stop a shade
   lighter than the panel behind it, with no border and no box of its own. It is a
   real button at a real size for anyone who taps or tabs to it; the secret is the
   phrase, not the target. */
.secret { position: absolute; right: 4px; bottom: 2px; }
.secret__dot {
  list-style: none;
  cursor: default;
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  font-size: 1.1rem;
  line-height: 0;
  color: #202020;
  transition: color var(--slow) linear;
}
.secret__dot::-webkit-details-marker { display: none; }
.secret__dot::marker { content: ""; }
.secret__dot:hover { color: #3a3a3a; }
.secret[open] .secret__dot { color: var(--accent); }
/* Keyboard users get a real target rather than an invisible one. */
.secret__dot:focus-visible { color: var(--accent); }

.secret__form {
  position: absolute;
  right: 0;
  bottom: calc(100% + 6px);
  z-index: 30;
  display: grid;
  gap: var(--s2);
  width: min(240px, 70vw);
  padding: var(--s3);
  background: var(--ink);
  border: var(--edge);
  border-top: 4px solid var(--accent);
  box-shadow: 8px 8px 0 rgba(0, 0, 0, 0.6);
  animation: slam 180ms var(--ease-slam) both;
}
.secret__label {
  font-family: var(--display);
  font-size: 0.66rem;
  letter-spacing: 0.24em;
  color: var(--paper-dim);
}
.secret__input {
  font: inherit;
  letter-spacing: 0.3em;
  padding: var(--s2);
  color: var(--paper);
  background: #000;
  border: 2px solid var(--paper-dim);
}
.secret__input:focus { border-color: var(--accent); outline: none; }
.secret__form .btn { transform: none; }

.secret--open { display: grid; gap: var(--s2); justify-items: start; }

/* -------------------------------------------------------- phones: hanging panels

   These three hang off a trigger that sits near the right edge, and the slam
   animation settles on a skew, which shifts the panel a further ~60px right. At
   390px that pushed the layout viewport out to 588px; Chrome widens the layout
   viewport to fit overflowing content, so the whole site rendered zoomed out.
   Dropping the skew and clamping the width to the screen keeps them anchored
   without the sideways drift. `position: fixed` is not available: #main carries
   the camera transform and becomes the containing block for it. */
@media (max-width: 640px) {
  .profile__edit-panel,
  .secret__form {
    /* Anchored by the right edge: every one of these triggers sits at or near the
       right of its card, so the right edge is the one that stays put. */
    right: 0;
    left: auto;
    width: min(330px, calc(100vw - 72px));
    transform: none;
    animation-name: panel-rise;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.7);
  }
}

/* ----------------------------------------------------------------- cropper

   Appears under the file input once a picture is chosen, and shows the frame the
   picture will actually live in; a square for the avatar, a banner for the cover.
   Hidden until then, and absent entirely without JavaScript, where the upload is
   the plain one it has always been. */
.cropper { display: grid; gap: var(--s2); margin: var(--s2) 0; }
.cropper[hidden] { display: none; }

.cropper__frame {
  position: relative;
  overflow: hidden;
  width: 100%;
  max-width: 320px;
  background: #000;
  border: var(--edge);
  /* The picture is dragged, so the browser must not claim the gesture for
     scrolling; on a phone that is the difference between framing a photo and
     the page sliding away under your finger. */
  touch-action: none;
  cursor: grab;
  user-select: none;
}
.cropper__frame:active { cursor: grabbing; }
.cropper__frame:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.cropper__image {
  position: absolute;
  top: 0;
  left: 0;
  max-width: none;
  transform-origin: top left;
  pointer-events: none;
}

.cropper__zoom { display: flex; align-items: center; gap: var(--s2); max-width: 320px; }
.cropper__zoom span {
  font-family: var(--display);
  font-size: 0.62rem;
  letter-spacing: 0.14em;
  color: var(--paper-dim);
}
.cropper__zoom input[type="range"] { flex: 1; accent-color: var(--accent); }
.cropper__hint { margin: 0; font-size: 0.72rem; color: var(--paper-dim); }

/* ------------------------------------------------------------ profile tabs

   POSTS and REPOSTS. Reposts stopped being mixed into the main list, so this is
   the only thing saying the other half exists; it reads as navigation rather
   than decoration, and marks which half you are on. */
.profile-tabs {
  display: flex;
  gap: var(--s4);
  margin: var(--s4) 0 var(--s3);
  padding-bottom: var(--s2);
  border-bottom: var(--edge);
}
.profile-tabs__tab {
  font-family: var(--display);
  font-size: 0.78rem;
  letter-spacing: 0.18em;
  color: var(--paper-dim);
  padding-bottom: 6px;
  border-bottom: 2px solid transparent;
}
.profile-tabs__tab:hover { color: var(--paper); text-decoration: none; }
.profile-tabs__tab.is-current { color: var(--accent); border-bottom-color: var(--accent); }
.profile-tabs__count { font-size: 0.68rem; color: var(--paper-dim); }

.profile__avatar--small { width: 54px; height: 54px; }
.profile__identity--plain { align-items: center; gap: var(--s3); }

/* Sits under the actions row on your own reposts page: the one way to take down a
   repost that carries a caption, where the caption is on screen to be read first. */
.profile__repost-remove { margin: var(--s2) 0 var(--s4); text-align: right; }
.profile__repost-remove .linkish {
  font-family: var(--display);
  font-size: 0.62rem;
  letter-spacing: 0.12em;
  color: var(--paper-dim);
}
.profile__repost-remove .linkish:hover { color: var(--accent-sentai); }
