/* ==========================================================================
   Account
   ========================================================================== */

.account-layout {
  max-width: calc(var(--col-wide) + 2 * var(--gutter-page));
  padding: var(--page-top) var(--gutter-page) 0;
}
.account-layout-narrow { max-width: calc(560px + 2 * var(--gutter-page)); }

/* ---- Identity header: unboxed on the field ------------------------------ */
.account-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px;
  margin-bottom: 24px;
}
.account-identity { flex: 1 1 220px; min-width: 0; }
.account-header h1 {
  margin: 0 0 4px;
  font: 700 1.5rem/1.2 var(--font);
  letter-spacing: -0.02em;
  color: var(--text);
  overflow-wrap: anywhere;
}
.account-email {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 10px;
  margin: 0;
  font: 500 var(--step--1)/1.4 var(--font);
  color: var(--ink-2);
  overflow-wrap: anywhere;
}
.account-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.account-actions form { margin: 0; }
/* Narrow: the actions drop under the name rather than under the avatar. */
@media (max-width: 559.98px) {
  .account-header { display: grid; grid-template-columns: 56px minmax(0, 1fr); align-items: start; gap: 12px 16px; }
  .account-header > .avatar { align-self: center; }
  .account-actions { grid-column: 2; }
}

/* The letter tile when there is no picture: the selection fill of whichever
   accent the element sits in, with that palette's measured label ink. */
.avatar {
  display: grid;
  place-items: center;
  flex: none;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--mat-select);
  color: var(--on-select);
  text-shadow: var(--on-select-shadow);
  font: 700 1.375rem/1 var(--font);
}
/* A picture that fails to load shows only its background, because every
   avatar img carries alt="". Same glyph and cover recipe as the leaderboard
   and profile avatars in community.css. */
.avatar-photo {
  position: relative;
  object-fit: cover;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 96 96' fill='%239ea4b8'%3E%3Ccircle cx='48' cy='38' r='16'/%3E%3Cpath d='M18,86 C18,64 32,54 48,54 C64,54 78,64 78,86 Z'/%3E%3C/svg%3E") center / 100% no-repeat,
    var(--mat-etched);
  outline: 1px solid rgb(var(--ink) / .14);
  outline-offset: -1px;
}
:root[data-theme='light'] .avatar-photo {
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 96 96' fill='%23595f74'%3E%3Ccircle cx='48' cy='38' r='16'/%3E%3Cpath d='M18,86 C18,64 32,54 48,54 C64,54 78,64 78,86 Z'/%3E%3C/svg%3E") center / 100% no-repeat,
    var(--mat-etched);
}
/* A failed image renders its pseudo-element (a loaded one never does), so
   this layer covers the browser's broken-image icon with the same glyph. */
.avatar-photo::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: inherit;
  background-color: var(--on-glass-solid);
}

/* ---- Rail and pages ------------------------------------------------------
   site.js (initAccountPages) adds .is-paged and shows one .account-page at a
   time; with scripting off every page is on one scroll and the rail links
   are anchors down it. */
.account-body { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; }
@media (min-width: 760px) {
  .account-body { grid-template-columns: 240px minmax(0, 1fr); gap: 24px; align-items: start; }
  /* The rail column runs the page's full height so the sticky list inside
     it has room to travel. */
  .account-rail { align-self: stretch; }
  .account-nav { height: 100%; }
}
.account-rail { min-width: 0; }
.account-nav { min-width: 0; }
/* The positioned ancestor site.js measures the marker against
   (link.offsetTop), so it carries no padding of its own. */
.account-nav-inner { position: relative; }
.account-nav-inner.is-sticky {
  position: sticky;
  top: calc(var(--header-height, var(--header-clear)) + 28px);
}
.account-nav ul {
  list-style: none;
  margin: 0;
  padding: 8px;
  display: grid;
  gap: 2px;
  border-radius: var(--r-group);
  background: var(--mat-neutral);
  box-shadow: var(--glass-rim);
}
.account-nav li a {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  min-height: 40px;
  padding: 9px 14px;
  border-radius: 18px;
  font: 500 .875rem/1.3 var(--font);
  color: var(--text-soft);
  text-decoration: none;
  transition: background var(--dur-chip) linear, color var(--dur-chip) linear;
}
.account-nav li a:hover { color: var(--text); }
.account-nav li a:not([aria-current]):hover { background: var(--row-hover); }
.account-nav li a:focus-visible { outline-offset: -2px; }
.account-nav li a[aria-current='page'] {
  color: var(--on-accent);
  text-shadow: var(--on-accent-shadow);
  font-weight: 600;
}
/* site.js writes transform and height, then adds .is-placed. Not glass, so
   its opacity may fade. The fill is stretched so the marker shows the middle
   of the gradient: the label sits at its left end, and the selection inks are
   measured over the middle span (light ember read 4.3:1 at the red end). */
.account-nav-marker {
  position: absolute;
  left: 8px;
  right: 8px;
  top: 0;
  z-index: 0;
  height: 0;
  border-radius: 18px;
  background: var(--mat-accent);
  background-size: 160% 100%;
  background-position: 50% 0;
  box-shadow: inset 0 0 0 .5px rgb(255 255 255 / .22);
  opacity: 0;
  pointer-events: none;
  transition: transform var(--dur-segment) var(--ease-out-cubic), height var(--dur-segment) var(--ease-out-cubic), opacity var(--dur-fade) linear;
}
.account-nav-marker.is-placed { opacity: 1; }

/* The latest release note: one unboxed row under the rail. */
.account-nav-note {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 14px;
  padding: 4px 10px;
  color: inherit;
  text-decoration: none;
}
.account-nav-note-body { display: grid; gap: 2px; min-width: 0; }
.account-nav-note-label {
  font: 700 var(--step--3)/1.4 var(--font);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--ink-2);
}
.account-nav-note-title {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font: 500 var(--step--1)/1.35 var(--font);
  color: var(--text-soft);
  transition: color var(--dur-chip) linear;
}
.account-nav-note:hover .account-nav-note-title { color: var(--text); }

/* Phones: the rail becomes a strip of chips that scrolls sideways; the
   current page is the accent chip and the marker stands down. */
@media (max-width: 759.98px) {
  .account-nav ul {
    display: flex;
    gap: 8px;
    margin-inline: calc(-1 * var(--gutter-page));
    padding: 4px var(--gutter-page);
    overflow-x: auto;
    scrollbar-width: none;
    border-radius: 0;
    background: none;
    box-shadow: none;
  }
  .account-nav ul::-webkit-scrollbar { display: none; }
  .account-nav li { flex: none; }
  .account-nav li a {
    min-height: 34px;
    padding: 8px 14px;
    border-radius: var(--r-chip);
    font: 600 var(--step-chip)/1.2 var(--font);
    color: var(--ink-2);
    white-space: nowrap;
    background: var(--mat-neutral);
    box-shadow: var(--glass-rim);
  }
  .account-nav li a:not([aria-current]):hover { background: var(--mat-neutral-hover); color: var(--text); }
  .account-nav li a[aria-current='page'] { background: var(--mat-accent); background-size: 160% 100%; background-position: 50% 0; font-weight: 700; }
  .account-nav li a:focus-visible { outline-offset: 2px; }
  .account-nav-marker, .account-nav-note { display: none; }
}

.account-pages { display: grid; gap: 16px; min-width: 0; container-type: inline-size; }
.account-page {
  display: grid;
  gap: 16px;
  min-width: 0;
  scroll-margin-top: calc(var(--header-height, var(--header-clear)) + 20px);
}
@container (min-width: 640px) {
  .account-page:has(> .panel-pair) { grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; }
}
.has-js .account-body.is-paged .account-page:not(.is-active) { display: none; }
.account-page:focus { outline: none; }

@media (forced-colors: active) {
  .account-nav ul { border: 1px solid CanvasText; }
  .account-nav-marker { display: none; }
  .account-nav li a[aria-current='page'] { forced-color-adjust: none; background: Highlight; color: HighlightText; }
}

/* ---- Panels --------------------------------------------------------------
   Scoped to .account-layout: the creator panel keeps its own .panel. */
.account-layout .panel {
  position: relative;
  min-width: 0;
  padding: 20px;
  border-radius: var(--r-card);
  background: var(--mat-neutral);
  box-shadow: var(--glass-rim);
  color: var(--text);
}
@media (min-width: 760px) {
  .account-layout .panel { padding: 24px; }
}
.account-layout .panel h2 {
  margin: 0 0 6px;
  font: 700 var(--step-1)/1.25 var(--font);
  letter-spacing: var(--track-title);
  color: var(--text);
}
.account-layout .panel > p { margin: 0 0 18px; font-size: var(--step-0s); line-height: 1.55; color: var(--ink-2); }
.account-layout .panel > p:last-child { margin-bottom: 0; }
.account-layout .panel > .field-hint { font-size: var(--step--1); line-height: 1.45; }
.account-layout .panel form > .btn { margin-top: 4px; }
.account-layout .panel form:last-child > .field:last-child { margin-bottom: 0; }
.account-layout .panel.is-featured { background: var(--mat-card); }
.account-layout .panel.is-featured > p,
.account-layout .panel.is-featured .field-hint { color: var(--ink-2-strong); }
.account-layout .panel-danger h2 { display: flex; align-items: center; gap: 10px; }
.account-layout .panel-danger h2::before {
  content: '';
  flex: none;
  width: 20px;
  height: 20px;
  background: var(--field-error-ink);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 7.5v5'/%3E%3Cpath d='M12 16v.5'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 7.5v5'/%3E%3Cpath d='M12 16v.5'/%3E%3C/svg%3E") center / contain no-repeat;
}
.account-layout .panel .eyebrow { display: block; margin: 0 0 4px; }
.form-actions { display: flex; flex-wrap: wrap; gap: 10px; }
.account-layout :is(.field-hint, .field > label) code {
  padding: .12em .42em;
  border-radius: var(--r-inline);
  font: 500 .875em/1 var(--mono);
  background: rgb(var(--ink) / .08);
  box-shadow: inset 0 0 0 1px rgb(var(--ink) / .10);
  color: var(--text);
}

/* Rows with hairlines only: the panel is already the glass. */
.account-layout .definition-list { display: grid; margin: 6px 0 0; }
.account-layout .definition-list > div {
  display: grid;
  grid-template-columns: minmax(110px, 34%) 1fr;
  gap: 4px 16px;
  align-items: baseline;
  padding: 12px 0;
}
.account-layout .definition-list > div + div { box-shadow: inset 0 1px 0 var(--hairline); }
.account-layout .definition-list dt {
  margin: 0;
  font: 700 .6875rem/1.4 var(--font);
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--ink-2);
}
.account-layout .definition-list dd {
  margin: 0;
  text-align: left;
  font: 500 var(--step-0s)/1.4 var(--font);
  color: var(--text);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

/* ---- Username gate: a row until Edit opens the field ------------------- */
.username-edit summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  cursor: pointer;
  list-style: none;
}
.username-edit summary::-webkit-details-marker { display: none; }
.username-edit-current {
  min-width: 0;
  overflow-wrap: anywhere;
  font: 600 var(--step-0l)/1.3 var(--font);
  color: var(--text);
}
.username-edit-body { display: grid; gap: 8px; justify-items: start; margin-top: 12px; }
.username-edit-body > .input { justify-self: stretch; }
.username-edit-body > .btn { margin-top: 6px; }

/* ---- Profile accent picker ----------------------------------------------
   The swatch look is the shared .swatch recipe; the fill comes from each
   label's own data-accent row in tokens.css. The radio stays in the layout
   and the tab order, only invisible. */
.accent-swatches { margin: 2px 0 4px; }
.accent-swatch { background-image: linear-gradient(145deg, var(--indigo), var(--violet), var(--blue), var(--teal)); }
.accent-swatch input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  border-radius: 50%;
  opacity: 0;
  cursor: pointer;
}
.accent-swatch:has(input:focus-visible) { outline: 2px solid var(--focus-ring); outline-offset: 4px; }

/* ---- Name style tiles ----------------------------------------------------- */
.name-style-swatches { display: flex; flex-wrap: wrap; gap: 10px; }
.name-style-swatch {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-width: 96px;
  min-height: 76px;
  padding: 14px 16px;
  border-radius: var(--r-control);
  background: var(--mat-etched);
  box-shadow: var(--rim-etched);
  cursor: pointer;
  transition: background var(--dur-chip) linear, box-shadow var(--dur-chip) linear;
}
.name-style-swatch:hover { background: var(--mat-etched-hover); box-shadow: inset 0 0 0 1px var(--etch-line-hover); }
.name-style-swatch:has(input:checked) { background: var(--mat-row-selected); box-shadow: inset 0 0 0 1.5px var(--eyebrow-ink); }
.name-style-swatch:has(input:focus-visible) { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.name-style-swatch input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}
.name-style-swatch .name-styled { font-size: var(--step-1); pointer-events: none; }
/* Etched tile on glass is one layer brighter than glass: --ink-2 measured
   4.1:1 here in dark mint, and 4.0 on the selected wash; hence the stronger
   inks. */
.name-style-swatch-label {
  font: 600 var(--step--2)/1.2 var(--font);
  color: var(--text-soft);
  pointer-events: none;
}
.name-style-swatch:has(input:checked) .name-style-swatch-label { color: var(--text); }
/* Locked effects stay visible, dimmed under a lock; the radio is disabled. */
.name-style-swatch.is-locked { opacity: .5; cursor: default; }
.name-style-swatch.is-locked:hover { background: var(--mat-etched); box-shadow: var(--rim-etched); }
.name-style-swatch.is-locked input { cursor: default; }
.name-style-lock {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 14px;
  height: 14px;
  color: var(--ink-2);
  pointer-events: none;
}
.name-style-lock .stroke { fill: none; stroke: currentColor; stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }

/* ---- Picture and banner: one cover composition --------------------------
   The avatar overlaps the banner's bottom edge by half, the way
   /u/<username> draws the two. 4 / 1 is tied to .profile-banner and to
   BANNER_W / BANNER_H in site.js. */
.profile-cover-edit { position: relative; margin: 4px 0 60px; }
.profile-cover-banner {
  position: relative;
  aspect-ratio: 4 / 1;
  border-radius: var(--r-group);
  overflow: clip;
  background: var(--mat-card);
}
/* The rim rides above the picture; an inset shadow on the box itself would
   paint under the image. */
.profile-cover-banner::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: var(--glass-rim);
  pointer-events: none;
}
.profile-cover-banner-image,
.profile-cover-avatar-image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.profile-cover-banner-image { position: absolute; inset: 0; }
/* The ring paints the panel's own colour so the avatar reads as cut out. */
.profile-cover-avatar {
  position: absolute;
  left: 24px;
  bottom: -44px;
  width: 88px;
  height: 88px;
  border-radius: 50%;
  overflow: clip;
  background: var(--on-glass-solid);
  box-shadow: 0 0 0 4px var(--on-glass-solid);
}
.profile-cover-control { position: absolute; }
.profile-cover-control[hidden] { display: none; }
.profile-cover-control-avatar { left: 82px; bottom: -48px; }
.profile-cover-control-banner { right: 12px; bottom: 12px; }
/* Marks on art: not glass, a dark stadium with a hairline. */
.profile-cover-edit-btn {
  position: relative;
  display: inline-grid;
  place-items: center;
  width: 36px;
  height: 36px;
  margin: 0;
  border-radius: 50%;
  background: rgb(0 0 0 / .58);
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / .14);
  color: #fff;
  cursor: pointer;
  transition: background var(--dur-chip) linear;
}
.profile-cover-edit-btn:hover { background: rgb(0 0 0 / .72); }
.profile-cover-edit-btn:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.profile-cover-edit-btn svg { width: 16px; height: 16px; }
.profile-cover-control:has(input:focus-visible) .profile-cover-edit-btn { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
/* site.js sets .is-busy on the button for the length of an upload. */
.profile-cover-edit-btn.is-busy { pointer-events: none; color: transparent; }
.profile-cover-edit-btn.is-busy::after {
  content: '';
  position: absolute;
  inset: 0;
  margin: auto;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 2px solid rgb(255 255 255 / .35);
  border-top-color: #fff;
}
@media (prefers-reduced-motion: no-preference) {
  .profile-cover-edit-btn.is-busy::after { animation: cover-busy-spin 800ms linear infinite; }
}
@keyframes cover-busy-spin { to { transform: rotate(360deg); } }

/* The label is the button; the file input only has to stay reachable. */
.avatar-file,
.banner-file {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.profile-cover-remove { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 4px; }
.profile-cover-remove form { margin: 0; }
.account-layout .panel > :is(.avatar-status, .banner-status) { margin: 8px 0 0; font: 400 var(--step--1)/1.45 var(--font); color: var(--ink-2); }
.account-layout .panel > :is(.avatar-status, .banner-status):empty { margin: 0; }
.account-layout .panel > :is(.avatar-status, .banner-status).is-error { color: var(--field-error-ink); }
.account-layout .panel > .banner-status + .field-hint { margin-top: 14px; }

/* The creator panel's user page still draws the picture on its own. */
.avatar-preview {
  position: relative;
  width: 96px;
  height: 96px;
  margin-bottom: 14px;
  border-radius: 50%;
  overflow: clip;
  background: var(--mat-etched);
  box-shadow: var(--rim-etched);
}
.avatar-preview-image { position: absolute; inset: 0; display: block; width: 100%; height: 100%; object-fit: cover; }

/* ---- Badges page -------------------------------------------------------- */
.account-layout .badge-next {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 14px 0 0;
  font: 500 var(--step--1)/1.4 var(--font);
  color: var(--ink-2);
}
.account-layout .badge-next b { color: var(--text); font-weight: 600; }
.account-layout .badge-ghost {
  flex: none;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  border: 1px dashed rgb(var(--ink) / .28);
}
.account-layout .badge-field > .field-hint { margin-top: 14px; }

/* ---- Discord rank --------------------------------------------------------
   The ranked page is the view's featured card (.panel.is-featured); what
   sits on it is unboxed or etched. The rank's own colour stays on the
   badge, which is identity data. */
.account-layout .rank-card {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 20px;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
}
.account-layout .rank-badge { border-radius: var(--r-group); }
.account-layout .rank-body { flex: 1 1 300px; display: grid; gap: 16px; align-content: start; }
.account-layout .rank-figures {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
  gap: 14px 16px;
  margin: 0;
}
.account-layout .rank-figures dt {
  margin: 0 0 4px;
  font: 700 .6875rem/1.4 var(--font);
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--ink-2-strong);
}
.account-layout .rank-figures dd {
  margin: 0;
  font: 700 var(--step-1)/1.2 var(--font);
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.account-layout .rank-progress-bar {
  height: 6px;
  border-radius: var(--r-pill);
  overflow: clip;
  background: rgb(var(--ink) / .12);
}
.account-layout .rank-progress-bar span {
  display: block;
  width: var(--p, 0%);
  height: 100%;
  min-width: 6px;
  border-radius: var(--r-pill);
  background: var(--grad-select);
}
.account-layout .rank-progress .field-hint { margin-top: 8px; }
.account-layout .rank-perks { display: flex; flex-wrap: wrap; gap: 8px; }
.account-layout .panel > h2 + .rank-perks { margin-top: 14px; }
.account-rank-actions { margin-top: 18px; }

/* The link code, in the copy pill's shape; etched because it sits on glass.
   A real text node, selectable in one go, since it is read and retyped. */
.account-layout .link-code {
  display: inline-flex;
  align-items: center;
  min-height: 52px;
  margin: 2px 0 14px;
  padding: 0 22px;
  border: 0;
  border-radius: 26px;
  background: var(--mat-etched);
  box-shadow: var(--rim-etched);
  font: 500 1.0625rem/1 var(--mono);
  letter-spacing: .08em;
  color: var(--text);
  user-select: all;
}
.account-layout .link-code + .field-hint { margin-bottom: 18px; }
.account-layout .panel > .panel-hint { margin-top: 12px; }

/* ---- Preferences: switch rows with hairlines ---------------------------- */
.switch-list { display: grid; margin: 0 0 18px; }
.switch-list > .checkbox { padding: 14px 0; }
.switch-list > .checkbox + .checkbox { box-shadow: inset 0 1px 0 var(--hairline); }
.switch-list + .eyebrow { margin-top: 6px; }

/* ==========================================================================
   Image crop modal (site.js openImageCropModal). A dialog on wide screens,
   a sheet on phones. The backdrop stays free of backdrop-filter and opacity
   animation: it is the modal's parent, and either would stop the modal
   blurring the page.
   ========================================================================== */
.crop-modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: grid;
  place-items: center;
  padding: 16px;
  background: rgb(0 0 0 / .55);
}
:root[data-theme='light'] .crop-modal-backdrop { background: rgb(20 22 40 / .35); }
.crop-modal {
  width: min(560px, 100%);
  max-height: calc(100dvh - 32px);
  overflow: auto;
  padding: 22px 20px 20px;
  border-radius: var(--r-card);
  background: var(--mat-sheet);
  box-shadow: var(--glass-rim), var(--shadow-pop);
  -webkit-backdrop-filter: var(--blur-sheet);
          backdrop-filter: var(--blur-sheet);
  color: var(--text);
}
.crop-modal:focus { outline: none; }
.crop-modal-title { margin: 0 0 6px; font: 700 1.3125rem/1.2 var(--font); letter-spacing: -0.5px; color: var(--text); }
.crop-modal-hint { margin: 0 0 16px; font-size: var(--step--1); line-height: 1.45; color: var(--ink-2); }
/* The light sheet sits over a dimmed page: --ink-2 measured 4.2:1 there. */
:root[data-theme='light'] .crop-modal-hint { color: var(--ink-2-strong); }
/* A fixed height whatever the crop aspect: layoutFrame() leaves margin to
   drag through on both axes only while the stage's shape differs from the
   frame's. */
.crop-modal-stage {
  position: relative;
  width: 100%;
  height: min(52vh, 420px);
  border-radius: var(--r-group);
  overflow: clip;
  background: rgb(0 0 0 / .4);
  cursor: grab;
  touch-action: none;
  user-select: none;
}
.crop-modal-stage.is-dragging { cursor: grabbing; }
.crop-modal-image {
  position: absolute;
  top: 0;
  left: 0;
  max-width: none;
  transform-origin: top left;
  pointer-events: none;
  will-change: transform;
}
/* The frame's spread shadow dims everything outside it, and follows the
   circle for an avatar through border-radius. */
.crop-modal-frame {
  position: absolute;
  border: 2px solid #fff;
  box-shadow: 0 0 0 9999px rgb(0 0 0 / .55);
  pointer-events: none;
  transition: opacity var(--dur-fade) linear;
}
.crop-modal-frame.is-circle { border-radius: 50%; }
.crop-modal-stage.is-previewing .crop-modal-frame { opacity: 0; }

.crop-modal-zoom-row {
  display: flex;
  align-items: center;
  gap: 12px;
  max-width: 360px;
  margin: 18px auto 0;
}
.crop-modal-zoom-row svg { flex: none; width: 16px; height: 16px; color: var(--ink-2); }
.crop-modal-zoom {
  flex: 1 1 auto;
  height: 20px;
  margin: 0;
  background: transparent;
  appearance: none;
  cursor: pointer;
}
.crop-modal-zoom::-webkit-slider-runnable-track { height: 4px; border-radius: var(--r-pill); background: rgb(var(--ink) / .18); }
.crop-modal-zoom::-moz-range-track { height: 4px; border-radius: var(--r-pill); background: rgb(var(--ink) / .18); }
.crop-modal-zoom::-webkit-slider-thumb {
  appearance: none;
  width: 20px;
  height: 20px;
  margin-top: -8px;
  border: 0;
  border-radius: 50%;
  background: linear-gradient(#fff, #e9eaf0);
  box-shadow: 0 1.5px 7px rgb(0 0 0 / .28);
}
.crop-modal-zoom::-moz-range-thumb {
  width: 20px;
  height: 20px;
  border: 0;
  border-radius: 50%;
  background: linear-gradient(#fff, #e9eaf0);
  box-shadow: 0 1.5px 7px rgb(0 0 0 / .28);
}
.crop-modal-zoom:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 4px; border-radius: var(--r-pill); }

.crop-modal-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 18px;
}
.crop-modal-actions-left,
.crop-modal-actions-right { display: flex; align-items: center; gap: 8px; }

/* Etched close and zoom chips on the sheet. */
.btn-icon {
  display: inline-grid;
  place-items: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--mat-etched);
  box-shadow: var(--rim-etched);
  color: var(--text);
  cursor: pointer;
  transition: background var(--dur-chip) linear, box-shadow var(--dur-chip) linear;
}
.btn-icon svg { width: 17px; height: 17px; }
.btn-icon:hover { background: var(--mat-etched-hover); }
.btn-icon[aria-pressed='true'] { background: var(--mat-quiet); box-shadow: var(--rim-quiet); }
.btn-icon:disabled { opacity: .4; pointer-events: none; }

@media (prefers-reduced-motion: no-preference) {
  .crop-modal { animation: crop-modal-rise var(--dur-chrome) var(--ease-out-cubic); }
}
@keyframes crop-modal-rise { from { transform: translateY(12px); } }

@media (max-width: 759.98px) {
  .crop-modal-backdrop { place-items: end stretch; padding: 0; }
  .crop-modal {
    width: 100%;
    max-height: 88dvh;
    padding-bottom: calc(20px + env(safe-area-inset-bottom));
    border-radius: var(--r-card) var(--r-card) 0 0;
  }
  .crop-modal::before {
    content: '';
    display: block;
    width: 36px;
    height: 4px;
    margin: -8px auto 14px;
    border-radius: 2px;
    background: rgb(var(--ink) / .22);
  }
  .crop-modal-stage { height: min(46vh, 380px); }
  @keyframes crop-modal-rise { from { transform: translateY(100%); } }
}
@media (max-width: 559.98px) {
  .crop-modal-actions-right { flex: 1 1 100%; }
  .crop-modal-actions-right .btn { flex: 1 1 0; }
}
