/* ==========================================================================
   Okami-ID Account settings

   Only for the signed-in /account/* screens rendered by AccountSettingsShell.razor
   (profile, password, two-factor).

   Like admin.css, this file does NOT redeclare any color token: it reuses the :root
   variables of _content/Okami.Shared.Pwa/css/auth.css, which App.razor loads first.

   The shape is the one every account screen worth copying converges on — a thin top bar,
   then a centred group of sidebar plus content, on a background that runs edge to edge.
   An earlier attempt reused the sign-in frame: a card capped at 1080px floating in the
   middle of the screen, with the content column centred inside it again. That reads as a
   small box lost on a large monitor, and double-centring left a wide dead margin on both
   sides of every form. A settings page should read as a page.

   The top bar follows Okami Mall's customer header (Components/Layout/SiteHeader.razor in
   the okami-mall repo): the wolf beside a 20px wordmark on the left, and the account as a
   pill on the right. Mall sends users here to change a password and takes them back
   afterwards, so the bar they arrive under should not look like a different product. Only
   the bar is borrowed — the rest of this file predates that and is deliberately unchanged.

   The type scale below the bar also references Mall's (12 / 14 / 15), because the first
   pass ran a step or two under it and read as small print.

   Kept apart from admin.css on purpose. The console and the account screens look alike
   today, but they serve different people; sharing one stylesheet means a change made
   for the console silently reshapes the screens users see.

   Local tokens sit on .account-page rather than :root so they cannot reach the sign-in
   screen, which shares the same body.
   ========================================================================== */

.account-page {
  --account-space-1: 4px;
  --account-space-2: 8px;
  --account-space-3: 12px;
  --account-space-4: 16px;
  --account-space-5: 20px;
  --account-space-6: 24px;
  --account-space-8: 32px;

  --account-radius-sm: 8px;
  --account-radius-md: 12px;
  --account-radius-lg: 16px;

  /* Mall's container: max-w-[1200px] with px-4 md:px-10. Taken verbatim so the gutters here
     are the ones a user sees on the page they came from — 1000px left too much empty margin
     on a wide monitor. */
  --account-measure: 1200px;
  --account-gutter: 16px;
  --account-sidebar-width: 232px;

  --account-line: rgba(18, 19, 25, 0.09);
  --account-focus-ring: 0 0 0 3px rgba(123, 97, 255, 0.28);

  /* Mall's scale, which is Tailwind's: text-xs 12, text-sm 14, base 16, text-xl 20, and
     text-3xl 30 for the page title. Size only — the colours and shapes below the bar are
     this file's own. */
  --account-text-xs: 12px;
  --account-text-sm: 14px;
  --account-text-base: 16px;
  --account-text-xl: 20px;
}

/* auth.css centres the body for the fixed 1120x720 sign-in frame: flex, centred both ways,
   24px of padding. None of that suits a full-page layout, and this file must not restyle
   body outright — App.razor renders one body for every page in the host, the sign-in screen
   included. Scoping the reset to a body that actually contains an account page keeps the
   override off every other screen. */
@media (min-width: 768px) {
  .account-page {
    --account-gutter: 40px;
  }
}

body:has(.account-page) {
  display: block;
  padding: 0;
  align-items: initial;
  justify-content: initial;
}

.account-page {
  position: relative;
  z-index: 1;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  font-size: var(--account-text-base);
}

/* These pages carry no JavaScript, so the keyboard is the only way past the navigation. */
.account-skip-link {
  position: absolute;
  left: var(--account-space-4);
  top: var(--account-space-4);
  z-index: 60;
  padding: 10px 16px;
  border-radius: var(--account-radius-sm);
  background: #ffffff;
  color: var(--color-purple);
  font-size: var(--account-text-sm);
  font-weight: 700;
  text-decoration: none;
  transform: translateY(-180%);
  transition: transform 0.15s ease;
  /* No shadow while parked: the link sits off the top of the page, but a 60px blur still
     paints back down into the corner as a grey smudge. */
  box-shadow: none;
}

.account-skip-link:focus-visible {
  transform: translateY(0);
  box-shadow: var(--shadow-panel);
}

.account-page a:focus-visible,
.account-page button:focus-visible,
.account-page summary:focus-visible {
  outline: none;
  box-shadow: var(--account-focus-ring);
  border-radius: var(--account-radius-sm);
}

/* --------------------------------------------------------------------------
   Top bar — Okami Mall's header: sticky, white, one hairline border, the wolf beside a
   20px wordmark, and the account as a pill on the far right.
   -------------------------------------------------------------------------- */
.account-topbar {
  position: sticky;
  top: 0;
  z-index: 40;
  background: #ffffff;
  border-bottom: 1px solid #f0f3f5;
}

/* The bar runs edge to edge; its contents line up with the group below it. */
.account-topbar-inner {
  max-width: var(--account-measure);
  margin: 0 auto;
  padding: var(--account-space-3) var(--account-gutter);
  display: flex;
  align-items: center;
  gap: var(--account-space-4);
}

/* Mall shows the wolf as it is, not inside a tile: at 32px the mark carries the brand on
   its own, and a coloured plate behind it competes with the wordmark beside it. */
.account-logo {
  display: flex;
  align-items: center;
  gap: var(--account-space-3);
  color: var(--color-text-main);
  text-decoration: none;
  margin-right: auto;
}

.account-logo-img {
  width: 32px;
  height: 32px;
  flex-shrink: 0;
}

.account-logo-text {
  font-size: var(--account-text-xl);
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -0.015em;
  white-space: nowrap;
}

/* Mall's account control: a pill on the neutral grey it uses for every header button. */
.account-user-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--account-space-2);
  min-width: 0;
  height: 40px;
  padding: 0 var(--account-space-4);
  border-radius: 999px;
  background: #f0f3f5;
  color: var(--color-text-main);
  font-size: var(--account-text-sm);
  font-weight: 700;
}

.account-user-chip-icon {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  stroke: currentColor;
  fill: none;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* The user's picture in place of the icon: a touch larger than the 20px glyph, since a photo
   reads smaller than a line drawing at the same size. */
.account-user-chip-avatar {
  width: 28px;
  height: 28px;
  flex-shrink: 0;
  margin-left: calc(-1 * var(--account-space-2));
  border-radius: 50%;
  object-fit: cover;
}

/* A long address must not push the bar wider; it is clipped at the tail and stays readable
   in full through the title attribute. */
.account-user-chip-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* App mode (#158): a screen opened in the whole window from Okami Wallet's popup, to add a passkey where WebKit allows
   it. Wallet's own header takes the top bar's place — back on the left, the section in the middle — so the step does not
   read as leaving the app. Hidden unless App.razor set .okami-app-mode. */
.account-app-bar {
  display: none;
}

.okami-app-mode .account-topbar {
  display: none;
}

.okami-app-mode .account-app-bar {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 56px;
  padding: 0 56px;
  background: #ffffff;
  border-bottom: 1px solid var(--account-line);
}

.account-app-back {
  position: absolute;
  left: 6px;
  top: 50%;
  transform: translateY(-50%);
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--account-radius-md);
  color: var(--color-text-main);
}

.account-app-back:hover {
  background: rgba(18, 19, 25, 0.05);
}

.account-app-back svg {
  width: 22px;
  height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.account-app-title {
  font-size: 17px;
  font-weight: 600;
  color: var(--color-text-main);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Adding a passkey inside the popup on WebKit (AccountPasskey.razor): the in-frame button cannot work there, so the link
   that moves the whole window to app mode takes its place. Everywhere else the link stays hidden. */
.passkey-add-top {
  display: none;
  text-decoration: none;
}

.okami-framed.okami-webkit .passkey-add-inline {
  display: none;
}

.okami-framed.okami-webkit .passkey-add-top {
  display: inline-flex;
  margin-top: 20px;
}

/* The Passkey row in the popup on WebKit (AccountSettingsShell.razor): its whole-window twin replaces it, so opening the
   section goes straight to app mode instead of to a button that has to be tapped again. Selectors outweigh the phone
   rule that shows every .account-acc-row. */
.account-acc-row.account-acc-row-top {
  display: none;
}

.okami-framed.okami-webkit .account-acc-row[data-section="Passkey"] {
  display: none;
}


/* The phone accordion (#159) in AccountSettingsShell.razor. Hidden here, so every width above 560px renders exactly
   what it did before; the 560px rule further down shows it. */
.account-acc-identity,
.account-acc-row,
.account-acc-logout-form {
  display: none;
}

/* --------------------------------------------------------------------------
   The centred group: navigation beside the screen
   -------------------------------------------------------------------------- */
.account-body {
  flex: 1;
  width: 100%;
  max-width: var(--account-measure);
  margin: 0 auto;
  /* py-10 like Mall's account main. */
  padding: 40px var(--account-gutter) 64px;
  display: flex;
  align-items: flex-start;
  gap: var(--account-space-8);
}

.account-sidebar {
  width: var(--account-sidebar-width);
  flex-shrink: 0;
  /* Follows the reader down a long form instead of scrolling away with it. The offset
     clears the sticky bar above it. */
  position: sticky;
  top: calc(64px + var(--account-space-6));
}

/* The way back to the RP that sent the user here. It sits above the navigation, where it
   is visible before anything is scrolled — a "back" link under a long form is a way out
   only for whoever reaches the end. Rendered only when a returnUrl survived validation. */
.account-back {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  margin-bottom: var(--account-space-5);
  border-radius: var(--account-radius-md);
  font-size: var(--account-text-sm);
  font-weight: 700;
  color: var(--color-text-main);
  text-decoration: none;
  transition: var(--transition-fast);
}

.account-back:hover {
  background: rgba(18, 19, 25, 0.05);
}

.account-back-icon {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  stroke: currentColor;
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: var(--transition-fast);
}

.account-back:hover .account-back-icon {
  transform: translateX(-2px);
}

.account-nav {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.account-nav-heading {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--color-text-muted);
  padding: var(--account-space-2) var(--account-space-3) var(--account-space-1);
}

.account-nav-link {
  position: relative;
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 10px 12px;
  border-radius: var(--account-radius-md);
  font-size: var(--account-text-sm);
  font-weight: 700;
  color: var(--color-text-muted);
  text-decoration: none;
  transition: var(--transition-fast);
}

.account-nav-link:hover {
  background: rgba(18, 19, 25, 0.04);
  color: var(--color-text-main);
}

.account-nav-link.active {
  background: rgba(123, 97, 255, 0.1);
  color: var(--color-purple);
}

/* A bar down the left edge: the pale purple fill alone is not enough for the eye to catch
   the open entry in a single sweep. */
.account-nav-link.active::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 3px;
  height: 18px;
  border-radius: 0 3px 3px 0;
  background: var(--color-primary-gradient);
}

.account-nav-icon {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  stroke: currentColor;
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Ends the session, at the foot of the menu and set apart from it — Mall puts its own there
   for the same reason: it is the one control that undoes everything above it. */
.account-logout-form {
  margin: var(--account-space-3) 0 0;
  padding-top: var(--account-space-3);
  border-top: 1px solid var(--account-line);
}

.account-logout {
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
  padding: 10px 12px;
  border: none;
  border-radius: var(--account-radius-md);
  background: none;
  font-family: inherit;
  font-size: var(--account-text-sm);
  font-weight: 700;
  /* Red from the first look, not only on hover: this is the one control in the sidebar that
     undoes the session, and it should read that way before the pointer reaches it.
     --color-error-text is auth.css's own danger colour, so no new value is introduced. */
  color: var(--color-error-text);
  text-align: left;
  cursor: pointer;
  transition: var(--transition-fast);
}

.account-logout:hover {
  background: rgba(239, 68, 68, 0.08);
}

/* --------------------------------------------------------------------------
   Content

   Left-aligned against the sidebar and filling what is left, rather than centred inside the
   remaining width. Centring a column inside the content area leaves a dead margin on both
   sides and makes the screen look like it failed to load the rest of itself.
   -------------------------------------------------------------------------- */
.account-main {
  flex: 1;
  min-width: 0;
}

.account-page-header {
  margin-bottom: var(--account-space-5);
}

.account-page-title {
  font-size: 30px;
  font-weight: 800;
  letter-spacing: -0.8px;
  line-height: 1.15;
  color: var(--color-text-main);
}

.account-page-subtitle {
  font-size: var(--account-text-sm);
  color: var(--color-text-muted);
  margin-top: 6px;
  line-height: 1.5;
  word-break: break-word;
}

/* auth.css hides .alert-banner by default and lets a form reveal it; here it is only ever
   rendered when it should be shown, so pages need no inline display style. */
.account-alert {
  display: flex;
  margin-bottom: var(--account-space-5);
  font-size: var(--account-text-sm);
}

.account-panel {
  background: rgba(255, 255, 255, 0.72);
  border: 1px solid var(--account-line);
  border-radius: var(--account-radius-lg);
  padding: var(--account-space-6) var(--account-space-8);
  box-shadow: 0 1px 2px rgba(18, 19, 25, 0.03);
  font-size: var(--account-text-base);
  line-height: 1.55;
}

/* Uppercase and bold, so these read a size larger than their font-size says: set at 14px they
   dominated the fields they label and outweighed the collapsed actions beside them (`Get new
   backup codes`, `Turn off two-factor`, both 14px sentence case). Two pixels down puts the cap
   height back level with those, which is where a field label belongs. */
.account-panel .input-label {
  font-size: var(--account-text-xs);
  margin-bottom: 6px;
}

.account-panel .form-input {
  font-size: var(--account-text-base);
  padding: 13px 16px;
}

/* A file picker carries its own intrinsic width and is styled as a full-width text field by
   auth.css, so left alone it spans the whole panel to hold a button and the words "No file
   chosen". Capped to the width it actually needs. */
.account-panel input[type="file"].form-input {
  max-width: 340px;
}

/* auth.css centres .signup-wrapper for the sign-in column. Inside a panel it is one more
   line of the form and belongs on the same left edge as everything above it. */
.account-panel .signup-wrapper {
  text-align: left;
  font-size: var(--account-text-sm);
}

.account-panel .signup-link {
  margin-left: 0;
}

/* auth.css makes .btn-primary fill its container, which is right for the narrow sign-in
   column and wrong here — a submit button as wide as the panel reads as a banner. Scoped
   to the panel so the sign-in screen keeps its own. */
.account-panel .btn-primary {
  width: auto;
  min-width: 190px;
  /* Mall's primary action is h-12 px-6 font-bold. */
  padding: 14px 24px;
  font-size: var(--account-text-base);
  margin-top: var(--account-space-2);
}

/* --------------------------------------------------------------------------
   Profile picture field

   The browser's own file input renders as a grey button welded to the words "No file
   chosen", which cannot be styled and says nothing useful. It is hidden and driven by a
   label instead — a label pointing at a file input opens the picker with no JavaScript, so
   the form still works when js/account.js does not load.
   -------------------------------------------------------------------------- */
.account-avatar-field {
  display: flex;
  align-items: center;
  gap: var(--account-space-4);
  flex-wrap: wrap;
}

.account-avatar-preview {
  display: grid;
  place-items: center;
  width: 72px;
  height: 72px;
  flex-shrink: 0;
  border-radius: 50%;
  overflow: hidden;
  background: #edf1f7;
  border: 1px solid var(--account-line);
}

.account-avatar-preview img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* No picture yet: the img carries no src at all, so nothing is requested and no broken-image
   glyph appears — the circle below simply shows through. */
.account-avatar-preview.is-empty img {
  display: none;
}

.account-avatar-placeholder {
  width: 30px;
  height: 30px;
  stroke: var(--color-text-muted);
  fill: none;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.account-avatar-preview:not(.is-empty) .account-avatar-placeholder {
  display: none;
}

.account-avatar-actions {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  min-width: 0;
}

.account-avatar-button {
  display: inline-flex;
  align-items: center;
  gap: var(--account-space-2);
  padding: 10px 18px;
  border: 1px solid var(--account-line);
  border-radius: 999px;
  background: #ffffff;
  font-size: var(--account-text-sm);
  font-weight: 700;
  color: var(--color-text-main);
  cursor: pointer;
  transition: var(--transition-fast);
}

.account-avatar-button:hover {
  border-color: var(--color-input-focus-border);
  box-shadow: 0 4px 10px rgba(18, 19, 25, 0.06);
}

/* The hidden input still has to be focusable, or the button is unreachable by keyboard.
   `display: none` would take it out of the tab order, so it is clipped instead. */
.account-avatar-input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.account-avatar-input:focus-visible + .account-avatar-actions .account-avatar-button {
  box-shadow: var(--account-focus-ring);
}

.account-avatar-button-icon {
  width: 18px;
  height: 18px;
  stroke: currentColor;
  fill: none;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.account-avatar-hint {
  font-size: var(--account-text-xs);
  color: var(--color-text-muted);
}

/* Filled in by js/account.js once a file is picked. Empty otherwise, so it takes no room. */
.account-avatar-file:not(:empty) {
  font-size: var(--account-text-xs);
  font-weight: 700;
  color: var(--color-text-main);
  word-break: break-all;
}

/* Two short fields to a row. A first name on a line of its own turns a six-field form into
   a column tall enough to scroll with most of the width unused. */
.account-fields-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 var(--account-space-5);
}

/* A rule between the form and the identity facts below it, which are read-only and belong
   to a different act than the fields above. */
.account-readonly {
  margin-top: var(--account-space-6);
  padding-top: var(--account-space-5);
  border-top: 1px solid var(--account-line);
}

/* --------------------------------------------------------------------------
   Motion

   These pages render statically and reload in full on every submit. A short entrance is
   what tells the user the page changed; without it each click is a white flash. Only
   opacity and transform are animated — both run on the compositor and shift no layout.
   -------------------------------------------------------------------------- */
@keyframes account-rise {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
}

@keyframes account-slide-in {
  from {
    opacity: 0;
    transform: translateX(-10px);
  }
}

@keyframes account-bar-grow {
  from {
    transform: translateY(-50%) scaleY(0.15);
    opacity: 0;
  }
}

.account-sidebar {
  animation: account-slide-in 0.32s cubic-bezier(0.22, 0.8, 0.3, 1) both;
}

.account-page-header {
  animation: account-rise 0.34s cubic-bezier(0.22, 0.8, 0.3, 1) both;
}

.account-panel {
  animation: account-rise 0.34s cubic-bezier(0.22, 0.8, 0.3, 1) 0.05s both;
}

.account-alert {
  animation: account-rise 0.3s cubic-bezier(0.22, 0.8, 0.3, 1) both;
}

.account-nav-link.active::before {
  animation: account-bar-grow 0.32s cubic-bezier(0.22, 0.8, 0.3, 1) 0.12s both;
}

/* --------------------------------------------------------------------------
   Responsive — the sidebar becomes a horizontal bar above the screen
   -------------------------------------------------------------------------- */
@media (max-width: 900px) {
  .account-body {
    flex-direction: column;
    /* Back to stretch. `flex-start` is what keeps the sidebar from growing to the height of
       the screen beside it, but once the two are stacked the same rule applies to width and
       shrinks the content to fit its own text, leaving half the screen empty. */
    align-items: stretch;
    gap: var(--account-space-5);
    padding: var(--account-space-6) var(--account-gutter) 48px;
  }

  /* Every entry stays on screen, wrapping onto a second row when it has to. This used to be one
     row scrolling sideways, which on a phone hid Web3 wallet and Log out past the right edge
     with nothing to say they were there (#92). */
  .account-sidebar {
    width: 100%;
    position: static;
    display: flex;
    flex-wrap: wrap;
    gap: var(--account-space-2);
    padding-bottom: var(--account-space-2);
    border-bottom: 1px solid var(--account-line);
  }

  /* A row of its own above the menu, so it keeps its label. */
  .account-back {
    width: 100%;
    min-height: 44px;
    margin-bottom: 0;
  }

  .account-nav {
    width: 100%;
    flex-direction: row;
    flex-wrap: wrap;
    gap: var(--account-space-1);
  }

  .account-nav-heading {
    display: none;
  }

  /* 44px is the smallest target a thumb hits reliably. */
  .account-nav-link {
    min-height: 44px;
    white-space: nowrap;
  }

  .account-nav-link.active::before {
    display: none;
  }

  /* Its own row under the menu, still behind the hairline that sets it apart. As a pill at the
     end of the row it wrapped onto two lines and sat below the others' baseline. */
  .account-logout-form {
    width: 100%;
    margin-top: 0;
    padding-top: var(--account-space-2);
  }

  .account-logout,
  .account-avatar-button,
  .account-panel .method-add,
  .account-panel .method-remove {
    min-height: 44px;
  }

  .account-panel .account-action > summary {
    padding: 13px 0;
  }

  .account-page-title {
    font-size: 26px;
  }

  .account-panel {
    padding: var(--account-space-5);
  }
}

@media (max-width: 560px) {
  /* Signed in, the account screens become one accordion (#159) with no bottom tab bar. The sections are rows in
     <main>; the screen being viewed is the open one. The top bar keeps the logo alone: language comes from the
     calling app (`?lang=`), and the account and Log out are the accordion's head and foot.

     Inside Okami Wallet's popup (an iframe — App.razor sets .okami-embedded) the bar goes entirely, because the
     popup already sits under the app's own. */
  .account-sidebar.has-nav,
  .account-topbar .lang-selector,
  .account-topbar .account-user-chip,
  .okami-embedded .account-topbar {
    display: none;
  }

  .account-body {
    padding-top: var(--account-space-4);
  }

  .account-main:has(.account-acc-open) {
    display: flex;
    flex-direction: column;
    gap: 10px;
  }

  .account-acc-identity {
    display: flex;
    align-items: center;
    gap: 13px;
    margin-bottom: var(--account-space-1);
  }

  .account-acc-avatar {
    width: 48px;
    height: 48px;
    flex-shrink: 0;
    border-radius: 50%;
    object-fit: cover;
    background: var(--color-btn-secondary-bg);
    color: #94a3b8;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  .account-acc-avatar svg {
    width: 24px;
    height: 24px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.5;
  }

  .account-acc-identity-text {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
  }

  .account-acc-identity-name {
    font-size: 17px;
    font-weight: 600;
    letter-spacing: -0.2px;
    color: var(--color-text-main);
    overflow-wrap: anywhere;
  }

  .account-acc-identity-email {
    font-size: var(--account-text-xs);
    color: var(--color-text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .account-acc-row {
    display: flex;
    align-items: center;
    gap: 13px;
    min-height: 58px;
    padding: 0 17px;
    border: 1px solid rgba(18, 19, 25, 0.05);
    border-radius: 17px;
    background: #ffffff;
    color: var(--color-text-main);
    text-decoration: none;
    cursor: pointer;
  }

  /* App mode (#158): the whole window shows the one section it was opened for — the header's back button and title, then
     that section's content. The account's head, the other rows, the open row's own header and Logout all belong to the
     accordion the user came from, which is still behind the back button. */
  .okami-app-mode .account-acc-identity,
  .okami-app-mode .account-acc-row,
  .okami-app-mode .account-acc-logout-form {
    display: none;
  }

  /* The Passkey row's whole-window twin, in the popup on WebKit (#158) — phones only, like the accordion itself. */
  .okami-framed.okami-webkit .account-acc-row.account-acc-row-top {
    display: flex;
  }

  .account-acc-open {
    border: 1px solid rgba(0, 130, 255, 0.22);
    border-radius: 17px;
    background: #ffffff;
    overflow: hidden;
    box-shadow: 0 8px 24px rgba(0, 130, 255, 0.07);
    /* The row's own anchor target: when a row is opened the page lands on it, not on the identity above — and clear
       of the sticky logo bar, 57px tall (12px padding either side of the 32px logo, plus its 1px border). In the
       popup that bar is gone. */
    scroll-margin-top: calc(57px + var(--account-space-4));
  }

  .okami-embedded .account-acc-open {
    scroll-margin-top: var(--account-space-4);
  }

  /* App mode (#158) is embedded too, but under its own sticky 56px header: clear it, or the start of the section lands
     beneath the header. The section is the only thing on the page there, so this leaves it unscrolled. */
  .okami-app-mode .account-acc-open {
    scroll-margin-top: calc(56px + var(--account-space-4));
  }

  /* Folded on arrival (#159) or by the user: it reads as one more closed row. */
  .account-acc-open:not([open]) {
    border-color: rgba(18, 19, 25, 0.05);
    box-shadow: none;
  }

  .account-acc-open:not([open]) > summary .account-acc-label {
    font-weight: 500;
  }

  .account-acc-open > summary.account-acc-row {
    border: none;
    list-style: none;
  }

  .account-acc-open > summary::-webkit-details-marker {
    display: none;
  }

  .account-acc-open > summary .account-acc-label {
    font-weight: 600;
  }

  .account-acc-open > summary .account-acc-chevron {
    stroke: var(--color-blue);
    transform: rotate(180deg);
  }

  .account-acc-open:not([open]) > summary .account-acc-chevron {
    stroke: #cbd5e1;
    transform: none;
  }

  .account-acc-row:focus-visible {
    outline: none;
    box-shadow: var(--account-focus-ring);
  }

  .account-acc-icon {
    display: flex;
    color: var(--color-purple);
  }

  .account-acc-icon.blue {
    color: var(--color-blue);
  }

  .account-acc-icon svg {
    width: 20px;
    height: 20px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.7;
    stroke-linecap: round;
    stroke-linejoin: round;
  }

  .account-acc-label {
    flex-grow: 1;
    font-size: 15px;
    font-weight: 500;
  }

  .account-acc-summary {
    max-width: 45%;
    font-size: var(--account-text-xs);
    color: #94a3b8;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .account-acc-badge {
    height: 22px;
    padding: 0 9px;
    border-radius: 999px;
    background: rgba(18, 19, 25, 0.06);
    color: var(--color-text-muted);
    font-size: 10px;
    font-weight: 600;
    display: inline-flex;
    align-items: center;
  }

  .account-acc-badge.on {
    background: var(--color-success-bg);
    color: #15803d;
  }

  .account-acc-chevron {
    width: 17px;
    height: 17px;
    flex-shrink: 0;
    fill: none;
    stroke: #cbd5e1;
    stroke-width: 2.2;
    stroke-linecap: round;
    stroke-linejoin: round;
  }

  /* Inside the open row the page's own heading repeats the row's label, so it is kept for screen readers only;
     the subtitle, the error and the panel follow the row as its body. */
  .account-acc-open .account-page-header {
    margin: 0;
    padding: 4px 17px 0;
  }

  .account-acc-open .account-page-title {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }

  .account-acc-open .account-alert {
    margin: var(--account-space-3) 17px 0;
  }

  .account-acc-open .account-panel {
    border: none;
    border-radius: 0;
    background: none;
    box-shadow: none;
    padding: var(--account-space-3) 17px 18px;
  }

  .account-acc-logout-form {
    display: block;
    margin-top: 6px;
  }

  /* Inside Okami Wallet's popup the session belongs to the app around it: logging out of Okami ID there would leave
     Wallet signed in over a dead IdP session. Closing the popup is the way out. */
  .okami-embedded .account-acc-logout-form {
    display: none;
  }

  .account-acc-logout {
    width: 100%;
    height: 50px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 9px;
    border: 1px solid var(--color-error-border);
    border-radius: 14px;
    background: #ffffff;
    color: var(--color-error-text);
    font-family: inherit;
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
  }

  .account-acc-logout svg {
    width: 18px;
    height: 18px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.7;
    stroke-linecap: round;
    stroke-linejoin: round;
  }

  .account-page-title {
    font-size: 23px;
  }

  /* Two fields to a row stops helping once each is barely wider than its own label. */
  .account-fields-2 {
    grid-template-columns: 1fr;
  }

  .account-panel {
    padding: var(--account-space-4);
  }

  .account-panel .btn-primary {
    width: 100%;
  }
}

/* The motion here is decoration; whoever turned it off loses no information with it gone. */
@media (prefers-reduced-motion: reduce) {
  .account-page *,
  .account-page *::before,
  .account-page *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    /* Without clearing the delay the element stays on its "from" frame (opacity 0) for the
       whole wait, turning "no animation" into a blinking page. */
    animation-delay: 0ms !important;
  }
}

/* --------------------------------------------------------------------------
   Language selector in the top bar (LanguageSelector.razor). The control itself is styled in auth.css, which
   every page loads; in the bar it is simply part of the flex row, and only has to keep its width when the
   account chip beside it shrinks.
   -------------------------------------------------------------------------- */
.account-topbar .lang-selector {
  flex-shrink: 0;
}

/* --------------------------------------------------------------------------
   Two-factor screen: the backup codes' Copy / Download buttons, and the fixed
   "Always on" state of the withdrawals scope, which has no switch.
   -------------------------------------------------------------------------- */
.backup-codes-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--account-space-2);
  margin-bottom: var(--account-space-2);
}

.backup-codes-actions {
  display: flex;
  gap: var(--account-space-2);
}

.method-add.backup-codes-action {
  margin-top: 0;
  padding: 6px 12px;
  font-size: var(--account-text-xs);
}

.scope-badge {
  flex-shrink: 0;
  padding: 4px 10px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.12);
  color: #15803d;
  font-size: var(--account-text-xs);
  font-weight: 600;
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   Two-factor screen: the setup key under "Cannot scan it?", and the button
   that copies it (wired in account.js).
   -------------------------------------------------------------------------- */
/* Key and button read as one centred run, the way Okami Wallet's "Setup key" does.

   Not a flex row: that put the button at the far end of the line, and on a phone — where the key
   wraps to two lines and where this button exists in the first place — it ended up marooned
   against the right margin, vertically centred against nothing. Inline, it follows the last group
   of the key wherever that group lands. */
.setup-key {
  position: relative;
  text-align: center;
}

.setup-key-value {
  /* An explicit Latin stack, not the generic `monospace` keyword. The browser resolves that keyword
     against the page language, and on <html lang="ja"> it picks a CJK monospace whose characters are
     wider — the same 32-character key measured 262px in English and 301px in Japanese, which pushed
     the button onto a second line there and nowhere else. The key is Base32, so it has no use for a
     CJK face. */
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", "Courier New", monospace;
  /* Small enough that all 32 characters and the button fit one line at 390px, the narrowest phone
     worth designing for. The key used to be cut into groups of four at body size and wrapped to two
     lines there, which left the button trailing under the key rather than beside it. */
  font-size: var(--account-text-xs);
  letter-spacing: 1px;
  /* Last resort only. Nothing narrower than 390px is expected, but an unbroken 32-character string
     must not be allowed to push the panel wider than the screen. */
  overflow-wrap: anywhere;
}

/* Room under the key for the floating confirmation, which sits outside the flow and would otherwise
   land on the label of the code field below. Padding rather than a margin on .setup-key itself: that
   margin is the group's last, so it collapses into the group's own and buys almost nothing — measured
   3px of overlap. Held always, so nothing moves when the confirmation comes and goes. */
.input-group:has(.setup-key) {
  padding-bottom: var(--account-space-5);
}

.setup-key-copy {
  /* Borderless and 24px, not a bordered 40px box: the key beside it is one line of 12px monospace,
     and a boxed button that size read as the heavier of the two — the eye went to the control
     instead of the thing it acts on. The border only comes back on hover. */
  position: relative;
  display: inline-flex;
  vertical-align: middle;
  margin-left: var(--account-space-1);
  width: 24px;
  height: 24px;
  align-items: center;
  justify-content: center;
  border: 1px solid transparent;
  border-radius: var(--account-radius-sm);
  background: none;
  color: var(--color-text-muted);
  cursor: pointer;
  transition: var(--transition-fast);
}

/* The visible square is 24px but a thumb needs 44px, so the target is widened past the paint
   rather than the button being drawn larger. Nothing sits close enough for it to swallow. */
.setup-key-copy::before {
  content: "";
  position: absolute;
  inset: -10px;
}

.setup-key-copy:hover {
  color: var(--color-text-main);
  border-color: var(--color-input-border);
  background: var(--color-input-bg);
}

.setup-key-copy:focus-visible {
  outline: none;
  box-shadow: var(--account-focus-ring);
}

.setup-key-copy svg {
  width: 14px;
  height: 14px;
}

/* The copied state, held for a moment by account.js: the clipboard becomes a tick and goes green.
   The tick is the confirmation a sighted user actually reads — the words below it repeat the same
   thing for a screen reader. */
.setup-key-copy.is-done,
.setup-key-copy.is-done:hover {
  color: #15803d;
  border-color: transparent;
  background: none;
}

/* Taken out of the flow. In the flow it had to hold a line's height so the code field below would not
   jump when the words appeared, and that left a blank gap under the key for as long as nobody had
   pressed anything. Floating, it costs no space at all and still lands where the eye already is. */
.setup-key-copied {
  position: absolute;
  left: 50%;
  top: calc(100% + var(--account-space-1));
  transform: translateX(-50%);
  white-space: nowrap;
  pointer-events: none;
  font-size: var(--account-text-xs);
  font-weight: 600;
  color: #15803d;
  opacity: 0;
  transition: opacity 0.15s ease;
}

.setup-key-copied.is-visible {
  opacity: 1;
}

/* --------------------------------------------------------------------------
   Two-factor screen: the modal that asks for a code (native <dialog>, opened
   by account.js) and the red "Turn off" button in the row.
   -------------------------------------------------------------------------- */
.code-dialog {
  position: fixed;
  width: min(420px, calc(100vw - 32px));
  max-height: calc(100dvh - 32px);
  padding: 32px 28px 20px;
  border: 0;
  border-radius: 20px;
  background: #fff;
  color: var(--color-text-main);
  text-align: center;
  box-shadow: 0 24px 60px rgba(18, 19, 25, 0.25);
}

.code-dialog::backdrop {
  background: rgba(18, 19, 25, 0.5);
  backdrop-filter: blur(2px);
}

.code-dialog[open] {
  animation: code-dialog-in 0.18s ease-out;
}

@keyframes code-dialog-in {
  from { opacity: 0; transform: translateY(8px) scale(0.98); }
  to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .code-dialog[open] { animation: none; }
}

.code-dialog-close {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 10px;
  background: transparent;
  color: var(--color-text-muted);
  cursor: pointer;
}

.code-dialog-close:hover { background: #edf1f7; color: var(--color-text-main); }
.code-dialog-close svg { width: 18px; height: 18px; }

.code-dialog-icon {
  width: 48px;
  height: 48px;
  margin: 0 auto 16px;
  display: grid;
  place-items: center;
  border-radius: 14px;
  background: #eef2ff;
  color: var(--color-purple);
}

.code-dialog-icon svg { width: 24px; height: 24px; }
.code-dialog.is-danger .code-dialog-icon { background: #fef2f2; color: #dc2626; }

.code-dialog-title {
  margin: 0;
  font-size: 22px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.code-dialog-desc {
  margin: 8px 0 0;
  color: var(--color-text-muted);
  font-size: var(--account-text-sm);
  line-height: 1.55;
}

.code-dialog-callout {
  display: flex;
  gap: 10px;
  margin-top: 16px;
  padding: 12px 14px;
  border: 1px solid rgba(239, 68, 68, 0.25);
  border-radius: 12px;
  background: #fef2f2;
  color: #991b1b;
  font-size: 13px;
  line-height: 1.5;
  text-align: left;
}

.code-dialog-callout svg { flex-shrink: 0; width: 18px; height: 18px; margin-top: 1px; }

.code-dialog-entry { margin-top: 24px; text-align: left; }

.code-boxes {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 8px;
}

.code-boxes input {
  width: 100%;
  height: 56px;
  padding: 0;
  border: 1px solid rgba(18, 19, 25, 0.12);
  border-radius: 12px;
  background: #fff;
  color: var(--color-text-main);
  font: 600 22px var(--font-family);
  text-align: center;
}

.code-boxes input:focus,
.code-dialog-entry .form-input:focus {
  outline: none;
  border-color: var(--color-purple);
  box-shadow: 0 0 0 3px rgba(123, 97, 255, 0.18);
}

.code-dialog-label {
  display: block;
  margin-bottom: 8px;
  font-size: 13px;
  font-weight: 600;
}

.code-dialog-actions {
  display: grid;
  gap: 8px;
  margin-top: 24px;
}

.code-dialog-actions .btn-primary { width: 100%; margin: 0; }

.code-dialog-danger,
.code-dialog-cancel {
  min-height: 48px;
  border: 0;
  border-radius: 12px;
  font: 600 15px var(--font-family);
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}

.code-dialog-danger { background: #dc2626; color: #fff; }
.code-dialog-danger:hover { background: #b91c1c; }
.code-dialog-cancel { background: transparent; color: var(--color-text-muted); }
.code-dialog-cancel:hover { background: #edf1f7; color: var(--color-text-main); }

.code-dialog-actions button[disabled] { opacity: 0.45; cursor: not-allowed; transform: none; }

.code-dialog-link {
  justify-self: center;
  min-height: 32px;
  border: 0;
  background: none;
  color: var(--color-purple);
  font: 500 14px var(--font-family);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

.code-dialog button:focus-visible {
  outline: 2px solid var(--color-purple);
  outline-offset: 2px;
}

@media (max-width: 480px) {
  .code-dialog { padding: 28px 18px 16px; }
  .code-boxes { gap: 6px; }
  .code-boxes input { height: 48px; font-size: 20px; }
}

.account-danger-button {
  flex-shrink: 0;
  padding: 8px 14px;
  border: 0;
  border-radius: 10px;
  background: #dc2626;
  color: #fff;
  font-family: inherit;
  font-size: var(--account-text-xs);
  font-weight: 600;
  cursor: pointer;
  transition: background 0.2s ease;
}

.account-danger-button:hover,
.account-danger-button:focus-visible {
  background: #b91c1c;
}

/* --------------------------------------------------------------------------
   Confirm-before-removing dialog (#173): left-aligned, purple primary, Cancel + confirm side by side.
   Reuses the .code-dialog shell and its open/close wiring in account.js.
   -------------------------------------------------------------------------- */
.confirm-dialog {
  padding: 28px;
  text-align: left;
}

.confirm-dialog .code-dialog-icon {
  width: 40px;
  height: 40px;
  margin: 0 0 14px;
  border-radius: 12px;
  background: #f4f2ff;
  color: var(--color-purple);
}

.confirm-dialog .code-dialog-icon svg { width: 20px; height: 20px; }
.confirm-dialog .code-dialog-title { font-size: 20px; }
.confirm-dialog .code-dialog-desc { margin-top: 10px; }

.confirm-dialog-name {
  display: table;
  margin-bottom: 6px;
  padding: 2px 8px;
  border-radius: 8px;
  background: #f4f2ff;
  color: #5b43e0;
  font-weight: 600;
  overflow-wrap: anywhere;
}

.confirm-dialog .code-dialog-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 24px;
}

.confirm-dialog .code-dialog-cancel,
.confirm-dialog .code-dialog-confirm {
  min-height: 46px;
  padding: 0 22px;
  border: 0;
  border-radius: 12px;
  font: 600 15px var(--font-family);
  cursor: pointer;
  transition: background 0.15s ease;
}

.confirm-dialog .code-dialog-cancel { background: #eef1f7; color: var(--color-text-main); }
.confirm-dialog .code-dialog-cancel:hover { background: #e2e7f0; }
.confirm-dialog .code-dialog-confirm { background: var(--color-purple); color: #fff; }
.confirm-dialog .code-dialog-confirm:hover { background: #6a4ff0; }

@media (max-width: 420px) {
  .confirm-dialog .code-dialog-actions > * { flex: 1; padding: 0; }
}
