/* The /account shell: page column, rail, panes, section heads, cards, buttons,
   tables. Shared by /account/ and /account/developer/, so the two pages are one
   object rather than two copies that drift, and by the OAuth consent page
   (/oauth/authorize/) for its card, buttons and form controls. Each page keeps
   its own content CSS inline (balance panel, metric tiles, storage table, keys
   table ...).

   Linked from inside <body> right after templates/header.php, BEFORE the page's
   own <style>, so a page rule with the same selector still wins by order. Every
   color comes from the --cat-* theme bridge in themes/base.css, which resolves
   each token across all nine themes and carries the light-theme overrides;
   nothing here is hardcoded. Selectors are all namespaced under .account-page
   because footer.php re-loads the theme CSS after the page -- an unscoped
   element selector would lose to it.

   Cache-busted as /account/shell.css?cb=N by every page that links it; bump
   all the links together when this file changes (grep "account/shell.css?cb="). */

/* width:100% is load-bearing, not filler. header.php sets `body { display: flex;
   flex-direction: column }` for the sticky footer, which makes this element a
   flex item -- and an auto margin on the CROSS axis overrides `align-items:
   stretch`, so `margin: … auto` alone shrink-wraps the page to its widest child
   instead of filling to max-width. Measured before the fix: 640px of a 1440px
   viewport, because the widest thing here is a 68ch paragraph. Setting the width
   explicitly restores the intended column and lets the auto margins go back to
   only centring it. (.library-shell on /my-creations has the same construction
   and is saved only by its tile grid being wide -- an empty library shrinks it.) */
.account-page {
  width: 100%;
  /* 1180px, not the 1080px the stacked page used: the rail beside the pane now
     takes 220px + 24px of this, and the panes are the same content that used to
     get the whole 1048px. 1180 keeps a pane of ~904px -- close enough to the old
     measure that the metric tiles and the storage table do not reflow. */
  max-width: 1180px;
  margin: 28px auto 56px;
  padding: 0 16px;
  color: var(--cat-text);
}
.account-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 22px;
}
.account-head h1 {
  margin: 0;
  font-size: clamp(1.9rem, 4.5vw, 2.9rem);
  line-height: 1.1;
}
.account-identity {
  margin: 6px 0 0;
  font-size: 14px;
  color: var(--cat-dim);
  word-break: break-word;
}
/* The shell ----------------------------------------------------------------
   A sticky rail of destinations beside ONE pane at a time (owner, 2026-09-14,
   after the design-lab review). Replaces the nine-section stack this page used
   to be, where Preferences and Delete account sat far enough down that "there is
   no other way to reach them" was the honest description.

   Everything below is written so the page still WORKS without it. The panes are
   plain sections, and only the `panes-on` class that the little script inside
   <main> adds — during parse, before the panes render — turns them into one at a
   time. With scripting off nothing is hidden: you get the old stacked page and a
   rail that does nothing, rather than a rail that does nothing and eight ninths
   of the page gone.

   A fixed rail width rather than a fraction: these are five short labels and one
   of them ("Delete account") is the widest thing in it, so the rail has no
   reason to grow on a large screen while the pane beside it does. 220px is the
   12px rail padding, 18px icon column, 10px gap and that label, with a little
   slack for translation. */
.account-shell {
  display: grid;
  grid-template-columns: 220px minmax(0, 1fr);
  gap: 24px;
  align-items: start;
}
.account-rail { position: sticky; top: 14px; }
.account-rail-nav {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 2px;
}
.account-rail-item,
.account-rail-link {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 9px 12px;
  border: 1px solid transparent;
  border-radius: 10px;
  background: none;
  color: var(--cat-dim);
  font-size: 14px;
  font-weight: 600;
  text-align: start;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 160ms ease, color 160ms ease, border-color 160ms ease;
}
/* The icon column is fixed so the six labels start on one vertical line whether
   or not their Font Awesome glyph happens to be wider than the others. */
.account-rail-item > i,
.account-rail-link > i { width: 18px; flex: none; text-align: center; }
.account-rail-item:hover,
.account-rail-item:focus-visible,
.account-rail-link:hover,
.account-rail-link:focus-visible {
  color: var(--cat-text);
  background: color-mix(in srgb, var(--cat-accent) 12%, transparent);
}
.account-rail-item:focus-visible,
.account-rail-link:focus-visible { outline: 2px solid var(--cat-accent); outline-offset: 2px; }
/* The open destination. Not color alone: the border is the second signal, so
   the state survives a monochrome theme and a color-blind reader. The link
   form is /account/developer/, which is a page of its own and marks itself
   the way a pane button does. */
.account-rail-item.is-on,
.account-rail-link.is-on {
  color: var(--cat-text);
  background: color-mix(in srgb, var(--cat-accent) 16%, transparent);
  border-color: color-mix(in srgb, var(--cat-accent) 40%, transparent);
}
/* The count beside a destination, for the two panes where "is there anything in
   here" is a real question before you click (files to manage, purchases to
   check). aria-hidden in the markup: it repeats a number the pane itself states,
   and a screen reader listing the rail should not hear "Storage 412" before it
   has any idea what 412 is. */
.account-rail-count {
  margin-inline-start: auto;
  font-size: 11px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--cat-dim);
}
/* The divider before Delete account + Logout. A rule rather than a gap, because
   those two are a different kind of thing: the five above are places in the
   account, these two leave it. */
.account-rail-sep {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--cat-border);
}
.account-panes { min-width: 0; }
.account-pane > * + * { margin-top: 22px; }
.account-page.panes-on .account-pane { display: none; }
.account-page.panes-on .account-pane.is-open { display: block; }
/* Sticky rail + a short pane on a narrow screen is the worst of both: the rail
   eats the width and the four metric tiles beside it get squeezed into a column
   each too narrow to print "Creations this month" without wrapping three times.
   Below this breakpoint the shell becomes one column and the rail turns into a
   horizontal scroller above the pane — the same control, the same order.

   The breakpoint is on the VIEWPORT, not on the pane, which is why it is this
   high: media queries cannot see the pane's own width, so the rail has to be
   guaranteed enough room above it. 1000px minus the 32px page padding and the
   244px the rail takes leaves the pane ~724px, which is still four-full-width
   tiles at this page's own 12px gap. (The tiles' own switch to two columns keeps
   keying on the viewport at 780px, which is now always the rail-less case.) */
@media (max-width: 1000px) {
  .account-shell { grid-template-columns: minmax(0, 1fr); gap: 14px; }
  .account-rail { position: static; }
  .account-rail-nav {
    grid-auto-flow: column;
    grid-auto-columns: max-content;
    gap: 6px;
    overflow-x: auto;
    padding-bottom: 4px;
    /* No scrollbar gutter: the rail is short enough to read at a glance and a
       visible bar under it looks like a broken second tab strip. */
    scrollbar-width: none;
  }
  .account-rail-nav::-webkit-scrollbar { display: none; }
  .account-rail-item,
  .account-rail-link { width: auto; padding: 8px 12px; }
  .account-rail-count { margin-inline-start: 6px; }
  .account-rail-sep {
    margin-top: 0;
    padding-top: 0;
    border-top: 0;
    border-inline-start: 1px solid var(--cat-border);
    padding-inline-start: 10px;
  }
}
.account-section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}
/* The pane's title, and any sub-head inside a pane, are the same object: one
   uppercase label, one tracking. Shared rule rather than two, so the second one
   cannot drift when the first is retuned. `:is()` covers the h3 that the credit
   chart's own heading needs — the pane title is the h2 and the chart sits a level
   under it, so the markup stays a legal outline (h1 Account > h2 pane > h3). */
.account-section-head :is(h2, h3) {
  margin: 0;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--cat-dim);
}
.account-note { font-size: 12.5px; color: var(--cat-dim); }
.account-card {
  background: var(--cat-surface);
  border: 1px solid var(--cat-border);
  border-radius: var(--cat-radius);
  padding: 18px;
}

/* Buttons -------------------------------------------------------------- */
.account-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 10px 17px;
  border-radius: 999px;
  border: 1px solid var(--cat-border);
  background: var(--cat-surface);
  color: var(--cat-text);
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 180ms ease, border-color 180ms ease, transform 180ms ease, color 180ms ease;
}
.account-btn:hover,
.account-btn:focus-visible {
  color: var(--cat-text);
  border-color: var(--cat-accent);
  background: color-mix(in srgb, var(--cat-accent) 14%, transparent);
  transform: translateY(-1px);
}
.account-btn:active { transform: translateY(0); }
.account-btn:focus-visible { outline: 2px solid var(--cat-accent); outline-offset: 2px; }
/* Dark ink on the accent, not white -- the site's existing filled-CTA convention
   (.plan-btn-primary, subscription/index.php). It is not a style preference: the
   mono theme's --accent is #ffd54a, so white label text on a filled accent button
   is unreadable there, while dark ink clears every one of the nine accents.
   --accent-contrast is the token base.css already reads for this; no theme
   defines it yet, so the fallback is doing the work and a theme can override it
   later without touching this file. Hover brightens rather than darkens, so the
   ink keeps its contrast. */
.account-btn-primary {
  border-color: transparent;
  background: var(--cat-accent);
  color: var(--accent-contrast, #09051a);
}
.account-btn-primary:hover,
.account-btn-primary:focus-visible {
  color: var(--accent-contrast, #09051a);
  background: var(--cat-accent);
  border-color: transparent;
  filter: brightness(1.08);
}

/* Tables --------------------------------------------------------------- */
.account-table-wrap { overflow-x: auto; }
.account-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}
.account-table th {
  text-align: start;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--cat-dim);
  padding: 0 12px 9px;
  white-space: nowrap;
}
.account-table td {
  padding: 11px 12px;
  border-top: 1px solid var(--cat-border);
  vertical-align: middle;
}
.account-table tbody tr { transition: background-color 160ms ease; }
.account-table tbody tr:hover { background: color-mix(in srgb, var(--cat-accent) 8%, transparent); }
.account-num {
  text-align: end;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* The `th` half of this needs its own rule, and the reason is specificity, not
   style: `.account-table th` above is (0,1,1) and `.account-num` is (0,1,0), so
   the header rule's `text-align: start` silently beat the modifier and every
   numeric column rendered with a left-aligned header sitting above right-aligned
   figures. A width hint on the same columns keeps the numbers as a tight block
   at the right rather than letting `table-layout: auto` spread three short
   values across a 1010px card; the first column absorbs the slack. */
.account-table th.account-num { text-align: end; }
/* The width hint is deliberately WIDE-VIEWPORT ONLY. Its job is to stop three
   short values spreading across a 1010px card -- a problem that does not exist
   on a phone, where applying it actively hurts: measured at 380px the table box
   is 310px, so two 130px numeric columns left ~50px for the tool name and broke
   "Generate Image (Fast)" over three lines. Below the breakpoint, `table-layout:
   auto` plus the `white-space: nowrap` above already gives the numeric columns
   exactly their content width and hands the rest to the first column, which is
   the behaviour we want there. */
@media (min-width: 620px) {
  .account-table th.account-num,
  .account-table td.account-num { width: 130px; }
}
.account-table a { color: var(--cat-text); text-decoration: none; }
.account-table a:hover,
.account-table a:focus-visible { color: var(--cat-accent); text-decoration: underline; }
.account-empty { color: var(--cat-dim); font-size: 14px; margin: 0; }

/* Hover TINTS rather than fills. Two reasons, and the first is the binding one:
   the nine --danger values span #a3341f (editorial brick) to #ff6b6b (mono's
   softened red), and no single label color is readable filled against both --
   white fails on the light reds, dark ink fails on the dark ones. Keeping the
   label as --danger on a wash of itself is legible against every one. It is also
   the honest weight for this control, which opens a mail client and deletes
   nothing by itself. */
.account-btn-danger {
  border-color: color-mix(in srgb, var(--danger, #ef4444) 55%, transparent);
  color: var(--danger, #ef4444);
}
.account-btn-danger:hover,
.account-btn-danger:focus-visible {
  color: var(--danger, #ef4444);
  background: color-mix(in srgb, var(--danger, #ef4444) 14%, transparent);
  border-color: var(--danger, #ef4444);
}
.account-btn-danger:focus-visible { outline-color: var(--danger, #ef4444); }

/* The one control on this page that is filled rather than tinted. Everything else
   here is a quiet outline button, so the filled treatment is what marks this as
   the destructive one -- and it is reserved for the CONFIRM inside the dialog and
   for "Cancel deletion", never for the card button that merely opens the dialog.
   `--danger-contrast` does not exist in base.css; white is chosen against the
   token rather than derived from it, and every one of the nine --danger values is
   a mid-to-dark red that carries white text (checked against editorial's #a3341f
   brick and mono's #ff6b6b, the two extremes). */
.account-btn-danger-solid {
  background: var(--danger, #ef4444);
  border-color: var(--danger, #ef4444);
  color: #fff;
}
.account-btn-danger-solid:hover,
.account-btn-danger-solid:focus-visible {
  background: color-mix(in srgb, var(--danger, #ef4444) 85%, #000);
  border-color: color-mix(in srgb, var(--danger, #ef4444) 85%, #000);
  color: #fff;
}

/* Form controls shared by /account/developer/ (the key form) and the OAuth
   consent page /oauth/authorize/: an input, a switch, and rows in a group.
   Moved here verbatim from the Developer page in P4 (owner pick 2026-09-21,
   early-looks/api-key-form-lab.html), so both pages keep one switch. Class
   selectors only, never an element, so they need no .account-page scope: the
   theme CSS footer.php re-loads never targets a devp- class. */

/* Inputs: the shipped input, plus a unit suffix and no number spinners (they
   are 12px targets that step a credit cap by one). */
.devp-input { position: relative; }
.devp-input input {
  width: 100%; box-sizing: border-box; font: inherit; font-size: 14px;
  padding: 9px 11px; border-radius: 9px;
  border: 1px solid var(--cat-field-border); background: var(--cat-field-bg); color: var(--cat-text);
  transition: border-color 160ms ease;
}
.devp-input input::placeholder { color: var(--cat-dim); opacity: .8; }
.devp-input input:focus-visible { outline: 2px solid var(--cat-accent); outline-offset: 1px; border-color: var(--cat-accent); }
.devp-input.has-suffix input { padding-inline-end: 64px; }
.devp-suffix { position: absolute; inset-inline-end: 11px; top: 50%; transform: translateY(-50%); font-size: 12.5px; color: var(--cat-dim); pointer-events: none; }
.devp-input input[type="number"] { -moz-appearance: textfield; appearance: textfield; }
.devp-input input::-webkit-outer-spin-button, .devp-input input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.devp-input-sm { width: 150px; }

/* The switch: Workspace v2's .ws-check geometry (38x22 track, 14px knob, 16px
   travel; workspace.css) in the account's tokens, so the site has one switch.
   The input stays a real checkbox with role="switch" and covers the track, so
   it is what gets clicked and focused; the knob is dark ink on the accent for
   the same reason as .account-btn-primary (mono's amber). */
.devp-switch { position: relative; display: inline-flex; flex: none; }
.devp-switch input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.devp-track {
  position: relative; width: 38px; height: 22px; border-radius: 999px;
  border: 1px solid var(--cat-field-border); background: var(--cat-field-bg);
  transition: background-color 180ms ease, border-color 180ms ease;
}
.devp-track::after {
  content: ''; position: absolute; top: 50%; inset-inline-start: 3px;
  width: 14px; height: 14px; border-radius: 50%; background: var(--cat-dim);
  transform: translateY(-50%);
  transition: transform 180ms ease, background-color 180ms ease;
}
.devp-switch input:checked + .devp-track { background: var(--cat-accent); border-color: var(--cat-accent); }
.devp-switch input:checked + .devp-track::after { background: var(--accent-contrast, #09051a); transform: translateY(-50%) translateX(16px); }
[dir="rtl"] .devp-switch input:checked + .devp-track::after { transform: translateY(-50%) translateX(-16px); }
.devp-switch input:focus-visible + .devp-track { outline: 2px solid var(--cat-accent); outline-offset: 2px; }
.devp-switch:hover .devp-track { border-color: var(--cat-accent); }

/* Rows in a group. A row that is a <label> toggles its switch from anywhere in
   it. Any-sibling divider rather than row + row: the top-up note between the
   last row and the footer is display:none until switched on, and the footer
   keeps its divider either way. */
.devp-group { border: 1px solid var(--cat-border); border-radius: var(--cat-radius); overflow: hidden; }
.devp-group > * + * { border-top: 1px solid var(--cat-border); }
.devp-row { display: flex; align-items: center; gap: 14px; padding: 12px 14px; min-height: 60px; }
label.devp-row { cursor: pointer; transition: background-color 160ms ease; }
label.devp-row:hover { background: color-mix(in srgb, var(--cat-accent) 6%, transparent); }
.devp-row-icon {
  width: 32px; height: 32px; border-radius: 9px; flex: none;
  display: grid; place-items: center; font-size: 14px;
  color: var(--cat-accent); background: color-mix(in srgb, var(--cat-accent) 14%, transparent);
}
.devp-row-text { flex: 1; min-width: 0; }
.devp-row-title { display: block; font-size: 14px; font-weight: 600; }
.devp-row-desc { display: block; font-size: 12.5px; color: var(--cat-dim); line-height: 1.45; margin-top: 1px; }
.devp-row-end { flex: none; display: flex; align-items: center; gap: 8px; }
.devp-group-foot { margin: 0; padding: 9px 14px; font-size: 12.5px; color: var(--cat-dim); line-height: 1.45; background: color-mix(in srgb, var(--cat-text) 3%, transparent); }
/* The note that appears only when it matters: top-up switched on. */
.devp-note { display: flex; gap: 8px; align-items: flex-start; }
.devp-note i { color: var(--warning, #f59e0b); margin-top: 2px; flex: none; }
.devp-note[hidden] { display: none; }
