/* ══════════════════════════════════════════════════════════════════════════
   controls.css — MarketsMill ™ unified button + surface geometry (shared)

   WHY THIS FILE EXISTS
   An audit of the 30 signed-in member pages found 429 distinct control rules
   using 20 different border-radius values, 83 different padding values and
   TEN different "primary button" fills (--color-BtnBg yellow, --lc-accent
   blue, --color-Buy green, --color-PrimaryText ink, #ED7B30 orange, two
   different accent gradients, a white gradient, a near-black v2 gradient and
   three per-tier plan gradients). The same "Manage" button rendered grey in
   one settings card and accent-blue in the next; the same "Connect Strategy"
   CTA rendered blue, gold and purple side by side on one page. This file is
   the single place that decides what a button looks like.

   RELATIONSHIP TO glass.css
   glass.css owns SURFACES (the translucent card language lifted out of the
   dashboard). It normalised nine button classes as a side effect; those rules
   still stand and this file is a superset of them — it is linked AFTER
   glass.css so it wins on source order at equal specificity.

   It is deliberately a SEPARATE file, not more glass.css, because two of the
   highest-traffic member pages (localchain-dashboard-cards.html and
   investment-plan.html) link neither glass.css NOR settings-common.css. They
   can adopt this control layer without also inheriting glass.css's card fills,
   which would collide with the inline card language those two pages already
   own.

   HOW TO ADOPT ON A PAGE
     <link rel="stylesheet" href="/controls.css?v=1">   LAST of the stylesheets

   RULES THIS FILE FOLLOWS (each one is a bug that was found in the audit):
   - It never sets `width`, `min-width` or `flex` on a control. Many rows size
     their tracks to the button (.ldd-btn-ghost/.ldd-btn-accent are flex:1
     siblings; the deposit Share/Copy pair splits 50/50 on inline flex:1;
     .st-btns steals its track from the date fields; kyc's step buttons carry
     inline flex:1 / flex:2). A width here re-balances all of them.
   - It never fixes a button's height where JS rewrites the label
     (.btn-resend cycles "Resend (60s)"/"Sending…", .btn-confirm flips to
     "Confirming…", .detail-copy-btn flips to "Copied!"). min-height only,
     so the box grows with the longest label instead of clipping it.
   - It never repaints a fill that ENCODES MEANING. Status chips, .method-badge
     free/fee, .tx-status-*, statement .in/.out, toggles and .checkup-dot carry
     information in their colour; this file unifies their GEOMETRY only. Same
     contract glass.css already set for .sp-chip.
   - It never touches the app shell (topbar, sidebar, profile dropdown, command
     palette). Those already come from one file each and are consistent; and
     .profile-btn's 36px box is measured by app-shell.js to position the avatar
     ring.
   - It never touches statement.html's @media print block. Nineteen !important
     declarations there re-hard-code the printed ink, and a print sheet has no
     on-screen symptom when it breaks.

   THE CONTRAST TRAP THIS FILE FIXES — read before changing --ctl-primary-*.
   --lc-accent inverts between themes: #38BDF8 (light blue) in dark, #0284C7
   (mid blue) in light. glass.css's existing `.sp-btn-primary { background:
   var(--lc-accent); color:#fff }` therefore renders white on light blue in
   dark theme — about 1.9:1, unreadable. investment-plan.html hit the same wall
   and worked around it with a hand-tuned deep gradient plus an in-file comment
   ("a flat accent + white would fail contrast in dark mode. Do not
   re-tokenise it."). So the primary button does NOT reuse --lc-accent. It gets
   its own pair of tokens that flip fill AND ink together:
     dark  #38BDF8 fill + #062338 ink  = 7.6:1
     light #0369A1 fill + #FFFFFF ink  = 5.9:1
   Both clear AA for 15px/600 text. Change one half of a pair and you break it.
   ══════════════════════════════════════════════════════════════════════════ */


/* ── 1. Tokens ───────────────────────────────────────────────────────────
   Self-contained on purpose: this file is linked by two pages that load
   neither glass.css nor settings-common.css, so it cannot depend on
   --glass-ctl-bd / --glass-hover existing. Where glass.css IS present these
   values are the same ones it uses. */
:root {
  /* Geometry — one scale, matching glass.css's --glass-r-* series. */
  --ctl-r:        12px;   /* every button, every input */
  --ctl-r-sm:     10px;   /* compact / in-row buttons */
  --ctl-r-chip:    7px;   /* status badges */

  /* Vertical rhythm. min-height, never height — labels are JS-rewritten. */
  --ctl-h:        44px;
  --ctl-h-sm:     36px;
  --ctl-h-lg:     52px;

  --ctl-pad:      11px 20px;
  --ctl-pad-sm:    7px 14px;
  --ctl-pad-lg:   14px 26px;

  --ctl-fs:       15px;
  --ctl-fs-sm:    14px;
  --ctl-fs-lg:    16px;
  --ctl-fw:       600;

  --ctl-gap:       8px;
  --ctl-bw:        1px;
  --ctl-tr:       background .18s ease, border-color .18s ease, color .18s ease, box-shadow .18s ease;

  /* Primary. Fill and ink flip together — see the contrast note above. */
  --ctl-primary-bg:    #38BDF8;
  --ctl-primary-bg-h:  #7DD3FC;
  --ctl-primary-fg:    #062338;

  /* Ghost / secondary. A hairline on the card, never a fill. */
  --ctl-ghost-bd:      rgba(255,255,255,.18);
  --ctl-ghost-bd-h:    var(--ctl-primary-bg);
  --ctl-ghost-fg:      var(--color-PrimaryText);
  --ctl-ghost-bg-h:    rgba(255,255,255,.06);

  /* Danger. Outline, not a fill — a destructive button should read as a
     warning, not as the page's main call to action. */
  --ctl-danger-fg:     var(--color-Sell);

  /* Disabled. An explicit neutral TRIPLE — fill, border and ink — not
     `opacity` on the live fill.

     Two things had to be got right here, and the first attempt got both wrong:
     1. Opacity is not enough on its own. Fading the accent primary to 50% put
        white ink on pale blue at 2.2:1 on public-profile's Save button, and
        that is the state the button is in at page load, so it is what most
        users see. Opacity also makes the button translucent over a glass card,
        so the card's own fill shows through the "button".
     2. A disabled fill alone is not enough either. A grey fill sitting on a
        grey card is a 1.1:1 edge — the button disappears rather than reading
        as inert. settings-notifications' "Save preferences" and
        public-profile's "Save changes" are each the ONLY action on their page
        and both ship `disabled` at rest, so an invisible disabled button means
        a page with no visible action at all. The BORDER is what carries the
        boundary: --ctl-disabled-bd clears 3:1 against the card in both themes,
        which is the WCAG threshold for a non-text boundary. Ink clears 4.7:1
        against its own fill. */
  --ctl-disabled-bg:   #2A313C;
  --ctl-disabled-bd:   #6B7585;
  --ctl-disabled-fg:   #9AA4B4;
}

[data-theme="light"] {
  --ctl-primary-bg:    #0369A1;
  --ctl-primary-bg-h:  #075985;
  --ctl-primary-fg:    #FFFFFF;

  --ctl-ghost-bd:      rgba(16,20,30,.16);
  --ctl-ghost-bg-h:    rgba(16,20,30,.04);

  --ctl-disabled-bg:   #E9ECF0;
  --ctl-disabled-bd:   #8A93A1;
  --ctl-disabled-fg:   #5F6875;
}


/* ── 2. The button base ──────────────────────────────────────────────────
   Everything a button shares regardless of variant. Deliberately absent:
   width, min-width, flex, margin — see the rules block in the header.

   `display:inline-flex` is set because the majority of these already declare
   it and the rest need it to centre a label against min-height. Buttons that
   want to fill their row keep doing so: their own `width:100%` still applies
   (this file never sets width), and inline-flex + width:100% is a full-width
   button. */
/* Bare `.btn` is safe to claim here: within the member app it exists only on
   kyc.html (as the base for .btn-primary/-secondary/-ghost) and
   public-profile.html (the Copy / View pair). Every other .btn rule in the
   repo lives on an admin-*.html page, and none of those link this file. */
body.has-sidebar .btn,
body.has-sidebar .btn-save,
body.has-sidebar .btn-submit,
body.has-sidebar .btn-continue,
body.has-sidebar .btn-confirm,
body.has-sidebar .btn-primary,
body.has-sidebar .btn-secondary,
body.has-sidebar .btn-ghost,
body.has-sidebar .btn-outline,
body.has-sidebar .btn-manage,
body.has-sidebar .btn-manage-default,
body.has-sidebar .btn-manage-primary,
body.has-sidebar .btn-manage-yellow,
body.has-sidebar .btn-cancel-modal,
body.has-sidebar .btn-cancel-link,
body.has-sidebar .btn-resend,
body.has-sidebar .btn-invest,
body.has-sidebar .btn-accent,
body.has-sidebar .step-back-btn,
body.has-sidebar .sp-btn,
body.has-sidebar .sp-btn-sm,
body.has-sidebar .ap-btn,
body.has-sidebar .nm-btn,
body.has-sidebar .nm-save,
body.has-sidebar .nm-cancel,
body.has-sidebar .psplit-btn,
body.has-sidebar .st-btn,
body.has-sidebar .tfa-btn,
body.has-sidebar .action-btn,
body.has-sidebar .ldd-btn-ghost,
body.has-sidebar .ldd-btn-accent,
body.has-sidebar .inbox-btn,
body.has-sidebar .inbox-page-btn,
body.has-sidebar .vr-page-btn,
body.has-sidebar .prefs-save-btn,
body.has-sidebar .rz-btn,
body.has-sidebar .pl-btn,
body.has-sidebar .pb-action,
body.has-sidebar .sv-action-btn,
body.has-sidebar .detail-copy-btn,
body.has-sidebar .wh-statement-link,
body.has-sidebar .plan-cta,
body.has-sidebar .plan-cta-secondary,
body.has-sidebar .acct-empty-cta,
body.has-sidebar .retry-btn,
body.has-sidebar .sb-cta,
body.has-sidebar .copilot-btn,
/* withdraw-verify's only button. Its page rule is `.expired-card a.btn-link`
   (0,2,1), so a bare `.btn-link` here would tie and lose on source order —
   it has to carry the same descendant. */
body.has-sidebar .expired-card a.btn-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--ctl-gap);
  box-sizing: border-box;
  min-height: var(--ctl-h);
  padding: var(--ctl-pad);
  border-radius: var(--ctl-r);
  border-width: var(--ctl-bw);
  border-style: solid;
  font-family: inherit;
  font-size: var(--ctl-fs);
  font-weight: var(--ctl-fw);
  line-height: 1.2;
  letter-spacing: .2px;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: var(--ctl-tr);
}

/* Compact buttons — the ones that live inside a table row, a list row or a
   card header, where a 44px box would push the row open. Same language, one
   step down. */
body.has-sidebar .btn-manage,
body.has-sidebar .btn-manage-default,
body.has-sidebar .btn-manage-primary,
body.has-sidebar .btn-manage-yellow,
body.has-sidebar .sp-btn,
body.has-sidebar .sp-btn-sm,
body.has-sidebar .nm-btn,
body.has-sidebar .psplit-btn,
body.has-sidebar .inbox-btn,
body.has-sidebar .inbox-page-btn,
body.has-sidebar .vr-page-btn,
body.has-sidebar .rz-btn,
body.has-sidebar .pl-btn,
body.has-sidebar .detail-copy-btn,
body.has-sidebar .sv-action-btn,
body.has-sidebar .st-btn,
body.has-sidebar .pb-action,
body.has-sidebar .ap-btn {
  min-height: var(--ctl-h-sm);
  padding: var(--ctl-pad-sm);
  border-radius: var(--ctl-r-sm);
  font-size: var(--ctl-fs-sm);
}

/* The page-level call to action — the one button a screen is built around. */
body.has-sidebar .btn-submit,
body.has-sidebar .btn-continue,
body.has-sidebar .btn-confirm,
body.has-sidebar .btn-invest,
body.has-sidebar .plan-cta {
  min-height: var(--ctl-h-lg);
  padding: var(--ctl-pad-lg);
  font-size: var(--ctl-fs-lg);
}

/* Disabled reads the same everywhere. Pages currently use opacity .4, .5, .6
   and .65, and three of them forget cursor entirely. */
body.has-sidebar .btn-save[disabled],
body.has-sidebar .btn-submit[disabled],
body.has-sidebar .btn-continue[disabled],
body.has-sidebar .btn-confirm[disabled],
body.has-sidebar .btn-primary[disabled],
body.has-sidebar .btn-secondary[disabled],
body.has-sidebar .btn-manage[disabled],
body.has-sidebar .btn-resend[disabled],
body.has-sidebar .btn-invest[disabled],
body.has-sidebar .sp-btn[disabled],
body.has-sidebar .ap-btn[disabled],
body.has-sidebar .nm-btn[disabled],
body.has-sidebar .psplit-btn[disabled],
body.has-sidebar .st-btn[disabled],
body.has-sidebar .tfa-btn[disabled],
body.has-sidebar .ldd-btn-accent[disabled],
body.has-sidebar .prefs-save-btn[disabled],
body.has-sidebar .pb-action[disabled],
body.has-sidebar .plan-cta[disabled],
body.has-sidebar .page-btn[disabled],
body.has-sidebar .pg-btn[disabled],
body.has-sidebar .ptx-page-btn[disabled],
body.has-sidebar .inbox-page-btn[disabled],
body.has-sidebar .vr-page-btn[disabled],
body.has-sidebar button[disabled].btn-save,
body.has-sidebar button[disabled].btn-submit {
  background-color: var(--ctl-disabled-bg);
  background-image: none;
  border-color: var(--ctl-disabled-bd);
  color: var(--ctl-disabled-fg);
  /* Load-bearing. settings-notifications and public-profile both declare
     `.btn:disabled { opacity: .5 }` in their own <style>; without this reset
     the neutral fill above renders at half strength and the button vanishes
     into the card. These selectors are (0,3,1) and beat those (0,2,0) rules. */
  opacity: 1;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

/* One focus ring for the whole app. :focus-visible only, so a mouse click
   does not leave a ring behind. */
body.has-sidebar .btn-save:focus-visible,
body.has-sidebar .btn-submit:focus-visible,
body.has-sidebar .btn-continue:focus-visible,
body.has-sidebar .btn-confirm:focus-visible,
body.has-sidebar .btn-primary:focus-visible,
body.has-sidebar .btn-secondary:focus-visible,
body.has-sidebar .btn-ghost:focus-visible,
body.has-sidebar .btn-manage:focus-visible,
body.has-sidebar .btn-cancel-modal:focus-visible,
body.has-sidebar .btn-invest:focus-visible,
body.has-sidebar .sp-btn:focus-visible,
body.has-sidebar .ap-btn:focus-visible,
body.has-sidebar .nm-btn:focus-visible,
body.has-sidebar .psplit-btn:focus-visible,
body.has-sidebar .st-btn:focus-visible,
body.has-sidebar .tfa-btn:focus-visible,
body.has-sidebar .plan-cta:focus-visible,
body.has-sidebar .plan-cta-secondary:focus-visible,
body.has-sidebar .action-btn:focus-visible,
body.has-sidebar .pb-action:focus-visible {
  outline: 2px solid var(--ctl-primary-bg);
  outline-offset: 2px;
}


/* ── 3. Primary ──────────────────────────────────────────────────────────
   One fill for every "do the thing" button in the member app. Replaces the
   yellow --color-BtnBg CTA, the green --color-Buy CTA, the ink-coloured
   --color-PrimaryText CTA, the two accent gradients and the near-black v2
   gradient.

   `background-image:none` is load-bearing: several of these set a gradient
   via `background:` shorthand, and a later `background-color` alone would
   leave the old gradient painted on top. */
body.has-sidebar .btn-save,
body.has-sidebar .btn-submit,
body.has-sidebar .btn-continue,
body.has-sidebar .btn-confirm,
body.has-sidebar .btn-primary,
body.has-sidebar .btn-invest,
body.has-sidebar .btn-accent,
body.has-sidebar .btn-manage-primary,
body.has-sidebar .btn-manage-yellow,
body.has-sidebar .sp-btn-primary,
body.has-sidebar .ap-btn-primary,
body.has-sidebar .nm-btn-primary,
body.has-sidebar .nm-save,
body.has-sidebar .psplit-btn-primary,
body.has-sidebar .st-btn.primary,
body.has-sidebar .action-btn-primary,
body.has-sidebar .tfa-btn,
body.has-sidebar .ldd-btn-accent,
body.has-sidebar .prefs-save-btn,
body.has-sidebar .rz-btn,
body.has-sidebar .acct-empty-cta,
body.has-sidebar .pb-action,
body.has-sidebar .copilot-btn-primary,
body.has-sidebar .expired-card a.btn-link {
  background-color: var(--ctl-primary-bg);
  background-image: none;
  border-color: var(--ctl-primary-bg);
  color: var(--ctl-primary-fg);
  box-shadow: none;
}
body.has-sidebar .btn-save:hover:not([disabled]),
body.has-sidebar .btn-submit:hover:not([disabled]),
body.has-sidebar .btn-continue:hover:not([disabled]),
body.has-sidebar .btn-confirm:hover:not([disabled]),
body.has-sidebar .btn-primary:hover:not([disabled]),
body.has-sidebar .btn-invest:hover:not([disabled]),
body.has-sidebar .btn-accent:hover:not([disabled]),
body.has-sidebar .btn-manage-primary:hover:not([disabled]),
body.has-sidebar .btn-manage-yellow:hover:not([disabled]),
body.has-sidebar .sp-btn-primary:hover:not([disabled]),
body.has-sidebar .ap-btn-primary:hover:not([disabled]),
body.has-sidebar .nm-btn-primary:hover:not([disabled]),
body.has-sidebar .nm-save:hover:not([disabled]),
body.has-sidebar .psplit-btn-primary:hover:not([disabled]),
body.has-sidebar .st-btn.primary:hover:not([disabled]),
body.has-sidebar .action-btn-primary:hover:not([disabled]),
body.has-sidebar .tfa-btn:hover:not([disabled]),
body.has-sidebar .ldd-btn-accent:hover:not([disabled]),
body.has-sidebar .prefs-save-btn:hover:not([disabled]),
body.has-sidebar .rz-btn:hover:not([disabled]),
body.has-sidebar .acct-empty-cta:hover:not([disabled]),
body.has-sidebar .pb-action:hover:not([disabled]),
body.has-sidebar .copilot-btn-primary:hover:not([disabled]),
body.has-sidebar .expired-card a.btn-link:hover {
  background-color: var(--ctl-primary-bg-h);
  border-color: var(--ctl-primary-bg-h);
  color: var(--ctl-primary-fg);
}


/* ── 4. Ghost / secondary ────────────────────────────────────────────────
   Transparent with a hairline. --ctl-ghost-bd inverts per theme; do NOT
   substitute a card token here (glass.css's --glass-stroke is .85-alpha WHITE
   in light theme and leaves the button with no visible edge at all). */
/* The :not() guards are load-bearing, not decoration. A primary button ships
   BOTH classes (class="btn-manage btn-manage-primary", class="nm-btn
   nm-btn-primary"), so the base class here and the variant class in §3 match
   the same element at the same specificity (0,2,1) — and this block parses
   later, so without the guards the ghost fill silently wins and every page
   loses its primary action. That is exactly what happened on settings.html
   and settings-nominee.html on the first pass. */
body.has-sidebar .btn:not(.btn-primary),
body.has-sidebar .btn-secondary,
body.has-sidebar .btn-ghost,
body.has-sidebar .btn-outline,
body.has-sidebar .btn-manage:not(.btn-manage-primary):not(.btn-manage-yellow),
body.has-sidebar .btn-manage-default,
body.has-sidebar .btn-cancel-modal,
body.has-sidebar .btn-resend,
body.has-sidebar .step-back-btn,
body.has-sidebar .sp-btn:not(.sp-btn-primary):not(.sp-btn-danger),
body.has-sidebar .sp-btn-ghost,
body.has-sidebar .sp-btn-sm:not(.sp-btn-primary):not(.sp-btn-danger),
body.has-sidebar .ap-btn:not(.ap-btn-primary):not(.ap-btn-danger),
body.has-sidebar .ap-btn-ghost,
body.has-sidebar .nm-btn:not(.nm-btn-primary):not(.nm-btn-danger),
body.has-sidebar .nm-btn-ghost,
body.has-sidebar .nm-cancel,
body.has-sidebar .psplit-btn:not(.psplit-btn-primary):not(.psplit-btn-danger),
body.has-sidebar .psplit-btn-ghost,
body.has-sidebar .st-btn:not(.primary),
body.has-sidebar .page-btn,
body.has-sidebar .pg-btn,
body.has-sidebar .ptx-page-btn,
body.has-sidebar .action-btn-secondary,
body.has-sidebar .ldd-btn-ghost,
body.has-sidebar .inbox-btn,
body.has-sidebar .inbox-page-btn,
body.has-sidebar .vr-page-btn,
body.has-sidebar .pl-btn,
body.has-sidebar .sv-action-btn,
body.has-sidebar .detail-copy-btn,
body.has-sidebar .wh-statement-link,
body.has-sidebar .plan-cta-secondary,
body.has-sidebar .retry-btn,
body.has-sidebar .sb-cta,
body.has-sidebar .copilot-btn-ghost {
  background-color: transparent;
  background-image: none;
  border-color: var(--ctl-ghost-bd);
  color: var(--ctl-ghost-fg);
  box-shadow: none;
}

/* Hover must EXCLUDE the semantic variants of the same class. Without the
   :not() chain, `body.has-sidebar .sp-btn:hover` (0,3,1) outranks the
   .sp-btn-primary rule above (0,2,1) and the primary CTA loses its fill on
   the very hover that is meant to confirm it. Same for every family that
   shares a base class with its variants. */
body.has-sidebar .btn:not(.btn-primary):hover:not([disabled]),
body.has-sidebar .btn-secondary:hover:not([disabled]),
body.has-sidebar .btn-ghost:hover:not([disabled]),
body.has-sidebar .btn-outline:hover:not([disabled]),
body.has-sidebar .btn-manage:not(.btn-manage-primary):not(.btn-manage-yellow):hover:not([disabled]),
body.has-sidebar .btn-manage-default:hover:not([disabled]),
body.has-sidebar .btn-cancel-modal:hover:not([disabled]),
body.has-sidebar .btn-resend:hover:not([disabled]),
body.has-sidebar .step-back-btn:hover:not([disabled]),
body.has-sidebar .sp-btn:not(.sp-btn-primary):not(.sp-btn-danger):hover:not([disabled]),
body.has-sidebar .ap-btn:not(.ap-btn-primary):not(.ap-btn-danger):hover:not([disabled]),
body.has-sidebar .nm-btn:not(.nm-btn-primary):not(.nm-btn-danger):hover:not([disabled]),
body.has-sidebar .psplit-btn:not(.psplit-btn-primary):not(.psplit-btn-danger):hover:not([disabled]),
body.has-sidebar .st-btn:not(.primary):hover:not([disabled]),
body.has-sidebar .action-btn-secondary:hover:not([disabled]),
body.has-sidebar .ldd-btn-ghost:hover:not([disabled]),
body.has-sidebar .inbox-btn:hover:not([disabled]),
body.has-sidebar .inbox-page-btn:hover:not([disabled]),
body.has-sidebar .vr-page-btn:hover:not([disabled]),
body.has-sidebar .page-btn:hover:not([disabled]),
body.has-sidebar .pg-btn:hover:not([disabled]),
body.has-sidebar .ptx-page-btn:hover:not([disabled]),
body.has-sidebar .pl-btn:hover:not([disabled]),
body.has-sidebar .sv-action-btn:hover:not([disabled]),
body.has-sidebar .detail-copy-btn:hover:not([disabled]),
body.has-sidebar .wh-statement-link:hover:not([disabled]),
body.has-sidebar .plan-cta-secondary:hover:not([disabled]),
body.has-sidebar .retry-btn:hover:not([disabled]),
body.has-sidebar .sb-cta:hover:not([disabled]),
body.has-sidebar .copilot-btn-ghost:hover:not([disabled]) {
  background-color: var(--ctl-ghost-bg-h);
  border-color: var(--ctl-ghost-bd-h);
  color: var(--ctl-ghost-fg);
}


/* ── 5. Danger ───────────────────────────────────────────────────────────
   Outline, never a fill: on the pages that ship one, the destructive button
   sits directly beside the confirm button, and two solid fills side by side
   read as two equal choices. */
body.has-sidebar .sp-btn-danger,
body.has-sidebar .ap-btn-danger,
body.has-sidebar .nm-btn-danger,
body.has-sidebar .psplit-btn-danger,
body.has-sidebar .tfa-btn-danger,
body.has-sidebar .btn-cancel-link,
body.has-sidebar .pb-action-cancel {
  background-color: transparent;
  background-image: none;
  border-color: var(--ctl-danger-fg);
  color: var(--ctl-danger-fg);
  box-shadow: none;
}
body.has-sidebar .sp-btn-danger:hover:not([disabled]),
body.has-sidebar .ap-btn-danger:hover:not([disabled]),
body.has-sidebar .nm-btn-danger:hover:not([disabled]),
body.has-sidebar .psplit-btn-danger:hover:not([disabled]),
body.has-sidebar .tfa-btn-danger:hover:not([disabled]),
body.has-sidebar .btn-cancel-link:hover:not([disabled]),
body.has-sidebar .pb-action-cancel:hover:not([disabled]) {
  background-color: color-mix(in srgb, var(--ctl-danger-fg) 12%, transparent);
  border-color: var(--ctl-danger-fg);
  color: var(--ctl-danger-fg);
}


/* ── 6. The plan CTAs ────────────────────────────────────────────────────
   investment-plan.html and the dashboard both render three plan cards whose
   "Connect Strategy" buttons were gold (.plan-cta), blue (.best-value /
   .tier1) and purple (.direct / .tier3) — the single most visible instance of
   the inconsistency this file exists to fix.

   They keep a GRADIENT rather than the flat primary fill, because the in-file
   comment on the blue variant is correct: this button carries white ink at
   15px/700 on a card that is itself translucent, and a flat --lc-accent would
   fail contrast in dark theme. The fix is to keep the technique and drop the
   three-way colour split — all three now use what was Tier 01's blue, which
   is the app accent deepened where the label sits (#075985 under the text is
   12.6:1 against white).

   Tier identity is NOT lost: .plan-badge and the ::after corner ribbon still
   carry the per-tier gold / blue / purple, which is where a tier cue belongs.

   Specificity: the page's own rules are `.plan-overview-card.direct .plan-cta`
   and `.plan-card.tier3 .plan-cta` (0,3,0), and investment-plan's third style
   block parses AFTER this stylesheet, so (0,2,1) would lose twice over. The
   selectors below are (0,4,1). */
body.has-sidebar .plan-cta,
body.has-sidebar .plan-overview-card.direct .plan-cta,
body.has-sidebar .plan-overview-card.best-value .plan-cta,
body.has-sidebar .plan-card.tier1 .plan-cta,
body.has-sidebar .plan-card.tier2 .plan-cta,
body.has-sidebar .plan-card.tier3 .plan-cta {
  color: #fff;
  /* Deepened from the original Tier-01 ramp (#38BDF8 -> #075985). That ramp
     put white ink over #38BDF8/#0284C7 through the middle of the button, where
     the label actually sits, measuring ~2.9:1 — below AA for a 15px/700 label.
     Starting at #0284C7 keeps the same premium depth while the label band lands
     on #0369A1 (5.9:1) and the foot on #075985 (7.6:1). */
  background-image: linear-gradient(160deg, #0284C7 0%, #0369A1 45%, #075985 100%);
  background-color: #075985;
  border-color: rgba(3,66,105,.45);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.38),
    inset 0 -1px 0 rgba(3,66,105,.25),
    0 6px 18px rgba(2,132,199,.32),
    0 1px 2px rgba(0,0,0,.16);
}
body.has-sidebar .plan-cta:hover,
body.has-sidebar .plan-overview-card.direct .plan-cta:hover,
body.has-sidebar .plan-overview-card.best-value .plan-cta:hover,
body.has-sidebar .plan-card.tier1 .plan-cta:hover,
body.has-sidebar .plan-card.tier2 .plan-cta:hover,
body.has-sidebar .plan-card.tier3 .plan-cta:hover {
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.48),
    inset 0 -1px 0 rgba(3,66,105,.25),
    0 12px 26px rgba(2,132,199,.45),
    0 2px 4px rgba(0,0,0,.18);
}
/* The MarketsMill ™ .ai CTA shared the gold fill and only overrode its ink to
   white; with the gold gone that override is a no-op, but it is left matching
   so the class keeps meaning if the fill is ever forked again. */
body.has-sidebar .plan-cta.plan-cta--ai { color: #fff; }


/* ── 6b. The dashboard hero pair ─────────────────────────────────────────
   "Deposit funds" / "Withdraw" sit on the dashboard's dark gradient hero and
   were the app's most-seen buttons — the landing page's main action — yet they
   were the last pair still on their own language: a white-to-#EEEFF2 fill with
   near-black ink, inverting to near-black-on-white in light theme. That put
   two different primary treatments on one screen, since "Browse Plans" one
   card below is the unified accent fill.

   These use the SHARED tokens, not pinned values. An earlier attempt pinned
   the dark-theme pair here on the assumption that the hero stays a dark
   gradient in both themes. It does not — in light theme the hero card is
   near-white, so a pinned white ghost label landed white-on-white at 1.05:1
   and the Withdraw button, a money-path action, became unreadable. The shared
   tokens already invert correctly per theme, which is the whole point of them.

   Specificity: the page pairs these with `[data-theme="light"]
   .acct-hero-btn--primary` (0,2,0) inside an inline <style> that parses AFTER
   this file, so (0,2,1) is the minimum that wins in both themes. */
body.has-sidebar .acct-hero-btn--primary {
  background-color: var(--ctl-primary-bg);
  background-image: none;
  border-color: var(--ctl-primary-bg);
  color: var(--ctl-primary-fg);
  box-shadow: none;
}
body.has-sidebar .acct-hero-btn--primary:hover {
  background-color: var(--ctl-primary-bg-h);
  border-color: var(--ctl-primary-bg-h);
  color: var(--ctl-primary-fg);
}
body.has-sidebar .acct-hero-btn--ghost {
  background-color: transparent;
  background-image: none;
  border-color: var(--ctl-ghost-bd);
  color: var(--ctl-ghost-fg);
  box-shadow: none;
}
body.has-sidebar .acct-hero-btn--ghost:hover {
  background-color: var(--ctl-ghost-bg-h);
  border-color: var(--ctl-ghost-bd-h);
  color: var(--ctl-ghost-fg);
}
/* Both are (0,2,1) above, which also beats the page's own radius/padding rule,
   so bring them onto the shared control geometry too. min-width stays at the
   page's 174px — it sizes the hero's right-hand column. */
body.has-sidebar .acct-hero-btn {
  border-radius: var(--ctl-r);
  border-width: var(--ctl-bw);
  border-style: solid;
  font-size: var(--ctl-fs);
  font-weight: var(--ctl-fw);
}


/* ── 7. Icon-only buttons ────────────────────────────────────────────────
   Copy / refresh / expand affordances. Square with the small radius, not the
   nine different circles and rounded rects they ship today.

   NOT in this group: .profile-btn (app-shell.js measures its 36px box to
   position the avatar ring), .wn-info and .info-icon (deliberate circles that
   read as glyphs, not buttons), and .earn-chevron (a rotating disclosure
   marker whose 50% radius is the affordance). */
body.has-sidebar .copy-btn,
body.has-sidebar .uid-copy-btn,
body.has-sidebar .ip-copy-btn,
body.has-sidebar .desc-copy-btn,
body.has-sidebar .icon-btn,
body.has-sidebar .row-action-btn,
body.has-sidebar .tool-btn {
  border-radius: var(--ctl-r-sm);
  border-width: var(--ctl-bw);
  border-style: solid;
  border-color: var(--ctl-ghost-bd);
  background-color: transparent;
  background-image: none;
  color: var(--ctl-ghost-fg);
  cursor: pointer;
  transition: var(--ctl-tr);
}
body.has-sidebar .copy-btn:hover,
body.has-sidebar .uid-copy-btn:hover,
body.has-sidebar .ip-copy-btn:hover,
body.has-sidebar .desc-copy-btn:hover,
body.has-sidebar .icon-btn:hover,
body.has-sidebar .row-action-btn:hover,
body.has-sidebar .tool-btn:hover {
  background-color: var(--ctl-ghost-bg-h);
  border-color: var(--ctl-ghost-bd-h);
}


/* ── 8. Tabs, segments and pagination ────────────────────────────────────
   Three idioms coexisted for "pick one of these": an underline tab, an
   accent-wash pill and a raised pill, twice within 10px of each other in the
   dashboard's own chart header. They all become the same recessed track with
   a filled active pill.

   Geometry only on the TRACK — no fill — because several tracks are
   width:fit-content and a background changes where the row appears to end. */
body.has-sidebar .tab-btn,
body.has-sidebar .seg-btn,
body.has-sidebar .cf-seg-btn,
body.has-sidebar .vr-tab,
body.has-sidebar .bk-tab,
body.has-sidebar .chart-range-tab,
body.has-sidebar .chart-type-tab,
body.has-sidebar .wp-mode-btn,
body.has-sidebar .filter-tab,
body.has-sidebar .inbox-tab,
body.has-sidebar .cl-chip,
body.has-sidebar .filter-chip,
body.has-sidebar .st-quick button {
  border-radius: var(--ctl-r-sm);
  font-family: inherit;
  font-size: var(--ctl-fs-sm);
  font-weight: var(--ctl-fw);
  cursor: pointer;
  transition: var(--ctl-tr);
}

/* The filter/range chips were the last four different pill radii in the app
   (999px on wallet-history, 20px on statement, 8px on changelog, a square
   slab on wallet). They keep their own border because several sit on the page
   background rather than on a card, where a borderless chip has no edge. */
body.has-sidebar .inbox-tab,
body.has-sidebar .filter-tab {
  border-bottom-width: 0;
}
body.has-sidebar .tab-btn.active,
body.has-sidebar .seg-btn.active,
body.has-sidebar .cf-seg-btn.active,
body.has-sidebar .vr-tab.active,
body.has-sidebar .bk-tab.active,
body.has-sidebar .chart-range-tab.active,
body.has-sidebar .chart-type-tab.active,
body.has-sidebar .wp-mode-btn.active,
body.has-sidebar .filter-tab.active,
body.has-sidebar .inbox-tab.active,
body.has-sidebar .cl-chip.on,
body.has-sidebar .filter-chip.is-active {
  background-color: color-mix(in srgb, var(--ctl-primary-bg) 16%, transparent);
  border-color: color-mix(in srgb, var(--ctl-primary-bg) 40%, transparent);
  color: var(--ctl-primary-bg);
}

/* Pagination: one pill size across inbox, vouchers, transactions and the
   partner tree. */
body.has-sidebar .page-btn,
body.has-sidebar .pg-btn,
body.has-sidebar .ptx-page-btn,
body.has-sidebar .inbox-page-btn,
body.has-sidebar .vr-page-btn {
  min-height: var(--ctl-h-sm);
  padding: var(--ctl-pad-sm);
  border-radius: var(--ctl-r-sm);
  font-size: var(--ctl-fs-sm);
}


/* ── 9. Surfaces ─────────────────────────────────────────────────────────
   RADIUS AND BORDER WIDTH ONLY. No background, no padding, no display.

   Backgrounds are glass.css's job on the 28 pages that link it, and the
   dashboard's / investment-plan's own inline language on the two that do not.
   Repainting here would collide with both. What was actually inconsistent
   across pages is the SHAPE: the same card rendered at 6, 8, 10, 12, 14, 16,
   18 and 20px on different screens.

   Padding is excluded because .section-card is padding-less by contract — its
   children supply the 24px inset — and adding padding here double-insets every
   row on every settings page. */
body.has-sidebar .section-card,
body.has-sidebar .form-card,
body.has-sidebar .inbox-card,
body.has-sidebar .method-card,
body.has-sidebar .wh-card,
body.has-sidebar .plan-card,
body.has-sidebar .plan-overview-card,
body.has-sidebar .summary-card,
body.has-sidebar .expired-card,
body.has-sidebar .settings-card,
body.has-sidebar .account-card,
body.has-sidebar .kyc-card,
body.has-sidebar .kyc-result-card,
body.has-sidebar .stat-card,
body.has-sidebar .tx-card,
body.has-sidebar .net-card,
body.has-sidebar .nm-card,
body.has-sidebar .ac-card,
body.has-sidebar .log-card,
body.has-sidebar .sm-card,
body.has-sidebar .ncard,
body.has-sidebar .psplit-card,
body.has-sidebar .table-card,
body.has-sidebar .history-card,
body.has-sidebar .balance-card,
body.has-sidebar .partner-balance-card,
body.has-sidebar .partner-level-card,
body.has-sidebar .partner-link-card,
body.has-sidebar .pool-card,
body.has-sidebar .mi-card,
body.has-sidebar .wp-card,
body.has-sidebar .top-user-card,
body.has-sidebar .tree-card,
body.has-sidebar .verification-steps,
body.has-sidebar .profile-hero,
body.has-sidebar .inv-table,
body.has-sidebar .wh-table {
  border-radius: 18px;
  border-width: 1px;
  border-style: solid;
}

/* Stat tiles keep the slightly rounder geometry the dashboard established. */
body.has-sidebar .sp-tile,
body.has-sidebar .acct-stat,
body.has-sidebar .dw-tile,
body.has-sidebar .st-sum-tile,
body.has-sidebar .mi-tier,
body.has-sidebar .wp-tier,
body.has-sidebar .leg-box,
body.has-sidebar .progress-detail-box {
  border-radius: 20px;
}

/* Recessed panels sitting ON a card. */
body.has-sidebar .ldd-addr-box,
body.has-sidebar .ldd-recipient,
body.has-sidebar .ds-investor,
body.has-sidebar .crypto-summary,
body.has-sidebar .addr-card,
body.has-sidebar .balance-row,
body.has-sidebar .amount-input-wrap,
body.has-sidebar .pay-info-box,
body.has-sidebar .form-summary,
body.has-sidebar .vr-recipient,
body.has-sidebar .vr-list-row,
body.has-sidebar .form-error,
body.has-sidebar .form-success,
body.has-sidebar .ldd-notice,
body.has-sidebar .pending-banner,
body.has-sidebar .eo-panel,
body.has-sidebar .earn-breakdown-empty,
body.has-sidebar .empty-state,
body.has-sidebar .eo-empty {
  border-radius: 14px;
}

/* Inputs share the button radius so a field and the button beside it line up. */
body.has-sidebar .form-input,
body.has-sidebar .sp-input,
body.has-sidebar .sp-pct-wrap,
body.has-sidebar .tfa-input,
body.has-sidebar .vr-search-input,
body.has-sidebar .st-field input,
body.has-sidebar .st-field select,
body.has-sidebar .form-card select,
body.has-sidebar .form-card textarea,
body.has-sidebar .form-card input[type="text"] {
  border-radius: var(--ctl-r);
}


/* ── 10. Chips and badges ────────────────────────────────────────────────
   GEOMETRY ONLY — the fill is left to the page on every one of these because
   it carries state: .method-badge.free vs .fee is the P2P fee model,
   .tx-status-* is approved/pending/rejected, .vr-list-status is the voucher
   decision, .hero-badge is KYC. Unifying those fills deletes information. */
body.has-sidebar .sp-chip,
body.has-sidebar .wpr-badge,
body.has-sidebar .ds-row-status,
body.has-sidebar .method-badge,
body.has-sidebar .vr-id-plan,
body.has-sidebar .vr-list-code,
body.has-sidebar .vr-list-status,
body.has-sidebar .tx-status,
body.has-sidebar .hero-badge,
body.has-sidebar .plan-badge,
body.has-sidebar .pl-level-badge,
body.has-sidebar .st-pending,
body.has-sidebar .pp-chip,
body.has-sidebar .sm-card-count {
  border-radius: var(--ctl-r-chip);
  /* 12px, not glass.css's 11px. Several of these carry real information at
     colours the page owns and this file must not repaint — wallet-history's
     "Done" is green on mint at 2.97:1 in light theme, which 11px made
     materially harder to read, and it appears on every ledger row. 12px is
     still unmistakably a chip and costs nothing in layout. */
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .4px;
  padding: 3px 9px;
}


/* ── 11. Responsive ──────────────────────────────────────────────────────
   Cards tighten on phones, matching glass.css's 760px step so the two files
   do not disagree about the same card. Buttons keep their full 44px target —
   shrinking a tap target on touch is the wrong direction. */
@media (max-width: 760px) {
  body.has-sidebar .section-card,
  body.has-sidebar .form-card,
  body.has-sidebar .inbox-card,
  body.has-sidebar .method-card,
  body.has-sidebar .wh-card,
  body.has-sidebar .plan-card,
  body.has-sidebar .plan-overview-card,
  body.has-sidebar .settings-card,
  body.has-sidebar .account-card,
  body.has-sidebar .kyc-card,
  body.has-sidebar .tx-card,
  body.has-sidebar .nm-card,
  body.has-sidebar .sm-card,
  body.has-sidebar .profile-hero,
  body.has-sidebar .sp-tile,
  body.has-sidebar .acct-stat {
    border-radius: 14px;
  }
}
