/* =====================================================================
   profile.css — the profile menu, the avatar face and the profile screen.

   Loaded by the attendee shell only (src/views/layout.js adds the link on
   portal pages; the concierge admin has no avatar and no menu). Everything
   here is built from the tokens app.css defines on :root, so the menu inherits
   the brand ramp rather than restating it. Nothing in this file is inline: the
   CSP has no 'unsafe-inline' and never will.

   Three groups:

     .avatar-photo / .avatar-img   a stored photograph inside the circle that
                                   used to hold initials only
     .pmenu*                       the topbar profile menu
     .profile*                     the /me screen

   THE INITIALS ARE ALWAYS IN THE MARKUP, even when there is a photograph. The
   image is laid over them, so a picture that will not load — deleted by the
   retention sweep, or a request that failed — leaves the initials showing
   rather than a broken-image glyph. That fallback needs no JavaScript.

   THEMING. This file defines no colour of its own. Every hue below is a
   var(--token) that app.css declares on :root for light and redeclares for
   dark, so the menu and the profile screen follow the theme without a single
   duplicated rule here and without one prefers-color-scheme branch. Two things
   were NOT free and are worth knowing about:

     - .route-live-now and .route-live-check carried raw hexes (#0F5C3B and
       #6F4900). They were correct greens and browns for a white page and
       nothing else, so on a dark ground they would have stayed dark text on a
       dark tint. They are now --ok-ink and --warn, which are the tokens the
       rest of this codebase already uses for ink on --ok-bg and on --warn-bg.

     - .pmenu-panel floats over the content plate, and both are --surface. On a
       light page the drop shadow does the separating and the border only tidies
       the edge. On a dark page a soft black shadow over a dark ground reads as
       a smudge, not as height, so the EDGE has to carry the separation instead.
       The panel therefore takes --line-2, the stronger of the two hairlines,
       rather than --line.
   ===================================================================== */

/* ------------------------------------------------------------ avatar face */

.avatar-photo {
  position: relative;
  overflow: hidden;
  padding: 0;
}

/*
 * TRANSPARENT ON PURPOSE, and it is the whole reason the fallback works.
 *
 * This element used to paint background: var(--accent-l). An <img> whose file
 * is gone still occupies its box and still paints its own background, so that
 * one declaration covered the initials underneath with a flat tint and left a
 * broken-image glyph sitting on nothing. The promise at the top of this file
 * was not being kept, in either theme, and dark mode is where you notice: a
 * tinted disc with no letters in it reads as a rendering fault rather than as
 * a person.
 *
 * With no background, the ground is the .avatar circle itself, which already
 * carries --accent-l and the initials. A photograph that loads covers them,
 * because JPEG, PNG and WebP uploads are opaque; a photograph that does not
 * load leaves them showing. The one case this trades away is a PNG the
 * attendee uploaded WITH an alpha channel, where the initials sit faintly
 * behind it. That is rarer than a retention sweep deleting a file, and much
 * less alarming to look at.
 */
.avatar-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 50%;
  display: block;
  background: transparent;
}

/* ------------------------------------------------------------ profile menu */

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

.pmenu-btn {
  display: block;
  border-radius: 50%;
  text-decoration: none;
  color: inherit;
  position: relative;
  transition: box-shadow var(--dur) var(--ease);
}

.pmenu-btn:hover .avatar { border-color: var(--accent); }
.pmenu-btn[aria-expanded="true"] .avatar { border-color: var(--accent); background: var(--accent-l2); }

/* The 36px circle keeps its size and still takes a 44px thumb. */
.pmenu-btn::after {
  content: '';
  position: absolute;
  inset: -4px;
  border-radius: 50%;
}

.pmenu-panel {
  position: absolute;
  top: calc(100% + var(--sp-2));
  right: 0;
  z-index: 40;
  min-width: 15.5rem;
  max-width: min(19rem, calc(100vw - var(--sp-5)));
  background: var(--surface);
  /* --line-2, not --line: this panel floats over a plate of its own colour and
     the shadow is the only other thing separating them. See the header. */
  border: 1px solid var(--line-2);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-3);
  padding: var(--sp-2);
  overflow: hidden;
}

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

.pmenu-head {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--line);
  margin-bottom: var(--sp-2);
  min-width: 0;
}

.pmenu-id { min-width: 0; display: block; }

.pmenu-name {
  display: block;
  font-weight: 700;
  font-size: var(--fs-sm);
  color: var(--ink);
  line-height: 1.3;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pmenu-mail {
  display: block;
  font-size: var(--fs-xs);
  color: var(--muted);
  line-height: 1.35;
  margin-top: 2px;
  overflow-wrap: anywhere;
}

.pmenu-form { margin: 0; display: block; }

.pmenu-item {
  display: flex;
  align-items: center;
  width: 100%;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  min-height: var(--tap);
  border: 0;
  border-radius: var(--r-sm);
  background: none;
  font-family: inherit;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--ink);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease);
}

.pmenu-item:hover { background: var(--accent-l); color: var(--accent-ink); }
.pmenu-item:active { background: var(--accent-l2); }

.pmenu-sep {
  height: 1px;
  background: var(--line);
  margin: var(--sp-2) var(--sp-2);
}

.pmenu-out { color: var(--danger); }
.pmenu-out:hover { background: var(--bad-bg); color: var(--danger); }

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

.profile-head {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  margin-bottom: var(--sp-4);
  flex-wrap: wrap;
}

.avatar-xl { width: 72px; height: 72px; font-size: var(--fs-lg); }

.profile-headtext { min-width: 0; flex: 1 1 12rem; }
.profile-headtext strong { display: block; font-size: var(--fs-lg); line-height: 1.3; }
.profile-headtext span {
  display: block;
  font-size: var(--fs-xs);
  color: var(--muted);
  margin-top: 2px;
  overflow-wrap: anywhere;
}

/* Two across from 34rem up, stacked on a phone. The event is a phone-first
   audience: the QR code at the venue is the first touch. */
.profile-pair { display: grid; gap: 0 var(--sp-4); }

@media (min-width: 34rem) {
  .profile-pair { grid-template-columns: 1fr 1fr; }
}

/* A field that cannot be edited must not look like one that can. */
.profile-locked {
  display: block;
  width: 100%;
  padding: var(--sp-3);
  border: 1px dashed var(--line-2);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  color: var(--muted);
  font-family: var(--mono);
  font-size: var(--fs-sm);
  overflow-wrap: anywhere;
  min-height: var(--tap);
}

.profile-photo {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-4);
  flex-wrap: wrap;
}

.profile-photo-face { flex: 0 0 auto; }
.profile-photo-body { flex: 1 1 14rem; min-width: 0; }
.profile-photo-body .field { margin-bottom: var(--sp-3); }

/* ------------------------------------------------------ invitation routing */

/* The two paths an invitation can take, said out loud before it is sent. */
.route-list {
  list-style: none;
  margin: 0 0 var(--sp-4);
  padding: 0;
  display: grid;
  gap: var(--sp-2);
}

.route-item {
  display: flex;
  gap: var(--sp-3);
  align-items: flex-start;
  padding: var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-alt);
  font-size: var(--fs-sm);
  line-height: 1.5;
  color: var(--muted);
}

.route-item strong { display: block; color: var(--ink); }

.route-badge {
  flex: 0 0 auto;
  display: inline-grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  font-size: var(--fs-2xs);
  font-weight: 700;
  background: var(--lav);
  border: 1px solid var(--lav-2);
  color: var(--ink);
}

.route-badge-now { background: var(--accent-l); border-color: var(--accent-l2); color: var(--accent-ink); }
.route-badge-check { background: var(--warn-bg); border-color: var(--warn-line); color: var(--warn); }

/* The live line under the colleague's address in the invite dialogue. It is
   written by public/portal.js with textContent, never innerHTML. */
.route-live {
  font-size: var(--fs-xs);
  line-height: 1.5;
  margin-top: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  color: var(--muted);
}

.route-live[hidden] { display: none; }
/* --ok-ink and --warn are the codebase's ink tokens for these two tints:
   --ok-ink is declared against --ok-bg, and --warn is what .route-badge-check
   two rules up already uses on --warn-bg. Light: 6.30:1 and 5.33:1. */
.route-live-now { background: var(--ok-bg); color: var(--ok-ink); }
.route-live-check { background: var(--warn-bg); color: var(--warn); }
