/* helm admin density tweaks layered on top of local Bulma.
   No external resources are referenced from this file by design. */

/* Theme tokens. Bulma follows the OS colour scheme (prefers-color-scheme) and
   honours an explicit data-theme on <html>; the tokens below do the same for
   the app's own colours so every custom rule in this file picks up the right
   value. Light is the base, and the two dark blocks mirror Bulma's own
   selectors: the media query for the system preference (unless the page is
   pinned light) and data-theme="dark" for an explicit choice. Anything that
   must stay the same in both schemes (the charcoal navbar, avatar colours, the
   QR code's white backing) doesn't go through a token. */
:root {
  --helm-page-bg: #fafafa;
  --helm-link: #6b6233;
  --helm-link-hover: #544d28;
  --helm-brand-text: #4a4524;
  --helm-brand-accent: #6b6233;
  --helm-brand-muted: #8a8568;
  --helm-icon-muted: #8a8778;
  --helm-sort-idle: #b5b1a0;
  --helm-muted: #7a7a7a;
  --helm-muted-faint: #b5b5b5;
  --helm-border: #e8e6da;
  --helm-tint: #f3f2ea;
  --helm-tint-strong: #f7f5ec;
  --helm-tip-bg: #1f2229;
  --helm-tip-text: #fff;
  --helm-chart-empty: #dbdbdb;
  --helm-chart-share: #1f4a8f;
  --helm-chart-share-neg: #a3263f;
  --helm-chart-milestone: #0d8050;
  --helm-chart-marker-ring: #fff;
  --helm-chart-band-opacity: 0.22;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --helm-page-bg: hsl(221, 14%, 6%);
    --helm-link: #b8ae70;
    --helm-link-hover: #d3ca92;
    --helm-brand-text: #d3cca0;
    --helm-brand-accent: #a89d5e;
    --helm-brand-muted: #a29b7a;
    --helm-icon-muted: #9a9787;
    --helm-sort-idle: #6e6b5e;
    --helm-muted: #9096a3;
    --helm-muted-faint: #6b7078;
    --helm-border: hsl(50, 8%, 22%);
    --helm-tint: hsl(50, 8%, 13%);
    --helm-tint-strong: hsl(50, 8%, 15%);
    --helm-tip-bg: #e8e9ee;
    --helm-tip-text: #1f2229;
    --helm-chart-empty: #3a3d45;
    --helm-chart-share: #7aa2e8;
    --helm-chart-share-neg: #e0607a;
    --helm-chart-milestone: #2ecc8a;
    --helm-chart-marker-ring: hsl(221, 14%, 9%);
    --helm-chart-band-opacity: 0.1;
  }
}
:root[data-theme="dark"] {
  --helm-page-bg: hsl(221, 14%, 6%);
  --helm-link: #b8ae70;
  --helm-link-hover: #d3ca92;
  --helm-brand-text: #d3cca0;
  --helm-brand-accent: #a89d5e;
  --helm-brand-muted: #a29b7a;
  --helm-icon-muted: #9a9787;
  --helm-sort-idle: #6e6b5e;
  --helm-muted: #9096a3;
  --helm-muted-faint: #6b7078;
  --helm-border: hsl(50, 8%, 22%);
  --helm-tint: hsl(50, 8%, 13%);
  --helm-tint-strong: hsl(50, 8%, 15%);
  --helm-tip-bg: #e8e9ee;
  --helm-tip-text: #1f2229;
  --helm-chart-empty: #3a3d45;
  --helm-chart-share: #7aa2e8;
  --helm-chart-share-neg: #e0607a;
  --helm-chart-milestone: #2ecc8a;
  --helm-chart-marker-ring: hsl(221, 14%, 9%);
  --helm-chart-band-opacity: 0.1;
}

html {
  font-size: 15px;
  /* Bulma paints <html> in its scheme colour; match the page so a short page
     doesn't show a differently shaded strip below the body in either scheme. */
  background-color: var(--helm-page-bg);
}

body {
  background-color: var(--helm-page-bg);
}

/* Retheme `is-primary` from Bulma's default muted turquoise (which reads as a
   disabled button) to a confident blue. This recolours every primary submit
   button app-wide (Save, Sign in, Grant access, …). We reuse Bulma's own
   link-blue HSL so these match the blue already used for navigation buttons. */
:root {
  --bulma-primary-h: 233deg;
  --bulma-primary-s: 100%;
  --bulma-primary-l: 63%;
  /* Bulma derives is-primary's text from a light shade of the base colour,
     which lands too dark to read on this blue. Force the button text white. */
  --bulma-primary-invert-l: 100%;
}

/* Default link color: a muted olive that complements the dark charcoal navbar,
   instead of Bulma's bright default link blue. The base rule only outranks
   Bulma's element-level `a`, so class-based links (.navbar-item, .button) keep
   their own colors. The hover is scoped to in-page content (.section, where the
   navbar never lives) and excludes buttons so it can't bleed into either. */
a {
  color: var(--helm-link);
}
.section a:not(.button):hover,
.section a:not(.button):focus {
  color: var(--helm-link-hover);
}

.section {
  padding: 1.5rem 1.5rem;
}

/* Public key-claim page. Bulma paints a white background on <html>, so the
   body's grey only reaches the content height; min-height makes the grey fill
   the viewport. The copy is also given roomier line spacing for easy reading,
   and the intro subtitle isn't pulled tight under the greeting. */
.claim-page {
  min-height: 100vh;
  line-height: 1.7;
}
.claim-page .title:not(.is-spaced) + .subtitle {
  margin-top: 0.5rem;
}
.claim-logo {
  height: 5rem;
  width: auto;
}

.container {
  max-width: 1140px;
}

/* Align the navbar's contents with the page body's column. The body insets its
   .container via .section's 1.5rem padding, which sits *outside* the centred
   1140px column; the previous rule instead padded the navbar's inner .container,
   which eats *into* that column and (together with the navbar-item's own 0.75rem
   padding) pushed the header ~2.25rem further right than the body. Mirror the
   body by putting the inset on the .navbar element so its .container lands at the
   same x, then cancel the edge navbar-items' 0.75rem padding with negative
   margins so the brand and right-hand items sit flush with the body content. */
.navbar {
  padding-left: 1.5rem;
  padding-right: 1.5rem;
}
.navbar-brand {
  margin-left: -0.75rem;
}
/* The right-hand group only sits at the column's edge once the navbar is
   horizontal (desktop); scoped so it can't shift the collapsed mobile menu. */
@media screen and (min-width: 1024px) {
  .navbar-end {
    margin-right: -0.75rem;
  }
}

/* Header links: pure white. Bulma dims dark-navbar items to 90% lightness;
   bumping the lightness var to 100% keeps the hover/active states white too.
   The burger defaults to Bulma's link colour; force it white so the
   hamburger and its open "X" (spans inherit currentColor) match. */
.navbar.is-dark {
  --bulma-navbar-item-color-l: 100%;
  --bulma-navbar-burger-color: #fff;
}

/* Brand logo: drop a PNG at src/public/logo.png (served at
   /assets/logo.png). Bulma caps navbar images at 1.75rem; allow a
   slightly taller mark. The alt text shows until the file exists. */
.navbar-item.brand-logo img {
  max-height: 2rem;
}

/* The grouped superuser dropdowns (Revenue / Admin). The panel is Bulma's
   light dropdown against the dark bar; items get a muted leading icon on a
   fixed column so labels align, and a little more breathing room than Bulma's
   dense default. Colors come from Bulma's navbar-dropdown-item variables, so
   the white-text override on .navbar.is-dark above doesn't bleed in. */
.navbar-dropdown {
  min-width: 13rem;
}
.navbar-dropdown .navbar-item {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding-top: 0.5rem;
  padding-bottom: 0.5rem;
}
.navbar-dropdown .navbar-item .icon {
  width: 1.1rem;
  justify-content: center;
  color: var(--helm-icon-muted);
}

/* The collapsed navbar opens as a full-width drawer below Bulma's 1024px
   breakpoint. Bulma stacks the items but leaves the account block (avatar +
   log out) visually fused to the page links and the log-out button floating as
   a small pill. Tidy the drawer: roomier rows, a divider before the account
   block, a clear account row, and a full-width log-out button. */
@media screen and (max-width: 1023px) {
  .navbar.is-dark .navbar-menu {
    padding-bottom: 1rem;
    box-shadow: 0 8px 16px rgba(10, 10, 10, 0.3);
  }
  .navbar-menu .navbar-item {
    padding: 0.85rem 1.5rem;
  }
  /* The grouped dropdowns render their items inline in the drawer (Bulma
     always expands them below the desktop breakpoint and hides the arrow), so
     each group label reads as a section heading with its items indented
     beneath it. Bulma's dropdown-item colors are dark-on-light for the
     desktop panel and would render as white rows inside the dark drawer;
     restore the drawer's own white-on-dark scheme instead. */
  .navbar-menu .navbar-item.has-dropdown {
    padding: 0;
  }
  .navbar-menu .navbar-link {
    padding: 0.85rem 1.5rem;
    font-weight: 600;
  }
  .navbar-menu .navbar-dropdown .navbar-item {
    padding: 0.6rem 1.5rem 0.6rem 2.25rem;
  }
  .navbar.is-dark .navbar-dropdown .navbar-item:not(.is-active, .is-selected) {
    background-color: transparent;
    color: #fff;
  }
  .navbar.is-dark .navbar-dropdown .navbar-item .icon {
    color: rgba(255, 255, 255, 0.55);
  }
  /* Separate the account block from the page links above it. */
  .navbar-menu .navbar-end {
    margin-top: 0.5rem;
    padding-top: 0.75rem;
    border-top: 1px solid rgba(255, 255, 255, 0.15);
  }
  /* The username reads as the section's heading rather than another link. */
  .navbar-end .navbar-user span {
    font-weight: 600;
  }
  /* The log-out control fills its row at a comfortable touch size instead of
     sitting as a small pill against the left edge. */
  .navbar-end .navbar-item:has(form) {
    padding-top: 0.25rem;
  }
  .navbar-end .navbar-item form {
    width: 100%;
  }
  .navbar-end .navbar-item form .button.is-small {
    width: 100%;
    justify-content: center;
    font-size: 1rem;
    height: 2.75rem;
  }
}

/* Bare `is-light` tags and buttons (no colour modifier — the contact type
   "Other", the @username chip, Cancel). Bulma paints the bare tag's text in the
   light colour's own light invert, which is barely distinguishable from the
   pill, so use the regular invert instead. In dark mode both the tag and the
   button would otherwise stay as bright white pills; scope the light colour's
   lightness down so they become neutral dark chips (hover deltas still apply).
   The :not() chain leaves the coloured `is-info is-light` etc. variants alone. */
.tag.is-light:not(.is-primary, .is-link, .is-info, .is-success, .is-warning, .is-danger, .is-dark, .is-black, .is-white) {
  --bulma-tag-color-l: var(--bulma-light-invert-l);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .tag.is-light:not(.is-primary, .is-link, .is-info, .is-success, .is-warning, .is-danger, .is-dark, .is-black, .is-white),
  :root:not([data-theme="light"]) .button.is-light:not(.is-primary, .is-link, .is-info, .is-success, .is-warning, .is-danger, .is-dark, .is-black, .is-white) {
    --bulma-light-l: 22%;
    --bulma-light-invert-l: 90%;
  }
}
:root[data-theme="dark"] .tag.is-light:not(.is-primary, .is-link, .is-info, .is-success, .is-warning, .is-danger, .is-dark, .is-black, .is-white),
:root[data-theme="dark"] .button.is-light:not(.is-primary, .is-link, .is-info, .is-success, .is-warning, .is-danger, .is-dark, .is-black, .is-white) {
  --bulma-light-l: 22%;
  --bulma-light-invert-l: 90%;
}

/* Tighter tables for a dense admin UI. */
.table td,
.table th {
  padding: 0.4em 0.6em;
  vertical-align: middle;
}

/* Sortable column headers: keep the header text in the normal dark colour
   (not the olive link colour) and show a muted sort glyph that darkens on
   hover and when its column is the active sort. */
.table th a.th-sort {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  color: inherit;
  white-space: nowrap;
}
.table th a.th-sort .icon {
  color: var(--helm-sort-idle);
}
.table th a.th-sort:hover,
.table th a.th-sort:hover .icon,
.table th a.th-sort.is-active .icon {
  color: var(--helm-brand-text);
}

/* Constrain stacked forms to a comfortable reading width. */
.form-grid {
  max-width: 32rem;
}

/* Two-factor setup: a scannable QR plus the manual-entry secret beneath it. */
.totp-qr {
  width: 12rem;
  height: 12rem;
  margin-bottom: 1rem;
  padding: 0.5rem;
  /* Stays white in dark mode: the QR is black-on-white so phone cameras can
     read it. */
  background: #fff;
  border: 1px solid var(--helm-border);
  border-radius: 6px;
}
.totp-qr svg {
  display: block;
  width: 100%;
  height: 100%;
}
.totp-secret {
  font-size: 1rem;
  letter-spacing: 0.08em;
  word-break: break-all;
}

/* Group related fields (e.g. the USD:CAD rate and the CAD amount) in a tinted,
   bordered box so they read as one unit. */
.field-group {
  min-width: 0;
  margin: 0 0 0.75rem;
  padding: 0.85rem 1rem 1rem;
  background-color: var(--helm-tint);
  border: 1px solid var(--helm-border);
  border-radius: 6px;
}
.field-group > .field:last-child {
  margin-bottom: 0;
}
.field-group-title {
  margin-bottom: 0.6rem;
  font-weight: 600;
  color: var(--helm-brand-text);
}

.box {
  margin-bottom: 1.25rem;
}

/* Section title for a .box. Distinct from Bulma's tiny uppercase .heading label
   (still used for the stat columns): a proper heading in the brand olive, led by
   an accent bar and closed by a hairline divider across the box. */
.box-title {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 1rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--helm-border);
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--helm-brand-text);
}
.box-title::before {
  content: "";
  flex: none;
  width: 0.25rem;
  height: 1.15em;
  border-radius: 2px;
  background-color: var(--helm-brand-accent);
}
/* Secondary note pinned to the right of a .box-title (e.g. last-synced time). */
.box-title-note {
  margin-left: auto;
  font-size: 0.8rem;
  font-weight: 400;
  letter-spacing: 0;
  color: var(--helm-brand-muted);
}

/* Mobile-only stacked cards: the per-period sales figures, one card each, used
   in place of the wide table on narrow screens. */
.sales-cards {
  margin-bottom: 1rem;
}
.sales-card {
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--helm-border);
  border-radius: 6px;
}
.sales-card + .sales-card {
  margin-top: 0.5rem;
}
.sales-card-period {
  margin-bottom: 0.35rem;
  font-weight: 600;
  color: var(--helm-brand-text);
}
.sales-card-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 0.15rem 0;
}
.sales-card-row > span:first-child {
  color: var(--helm-brand-muted);
}
.sales-card-value {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* Page heading + lede pair. */
.page-head {
  margin-bottom: 1.25rem;
}
.page-head .title {
  margin-bottom: 0.25rem;
}

/* Project detail heading: the icon sits beside the title on one row. The source
   images are large (1024x1024), so we scale them right down to icon size. */
.project-head {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}
.project-head .title {
  margin-bottom: 0;
}
/* Action buttons (Revenue shares/payments, Financial access, Edit) sit grouped
   at the far right of the project heading row. */
.project-head-actions {
  margin-left: auto;
  margin-bottom: 0;
  justify-content: flex-end;
}
.project-head-actions .button {
  margin-bottom: 0;
}
.project-icon {
  flex: none;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 8px;
  object-fit: cover;
}
/* Mobile-only replacement for the action button row: a single dropdown pushed to
   the far right of the heading, with icon + label aligned in each menu item. */
.project-head-menu {
  margin-left: auto;
}
.project-head-menu .dropdown-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

/* Project name shown beside its icon in list/dashboard table rows. */
.project-cell {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.project-icon-sm {
  flex: none;
  width: 1.75rem;
  height: 1.75rem;
  /* Bulma's global `img { max-width: 100% }` would squish the icon into a
     vertical sliver when its table cell runs out of room; the icon's size is
     fixed, so opt out and let the cell wrap instead. */
  max-width: none;
  border-radius: 6px;
  object-fit: cover;
}
/* On narrow screens the game names crowd out the table columns, so hide the
   name and show only the icon (still a link via the surrounding anchor). */
@media (max-width: 768px) {
  .project-cell .project-name {
    display: none;
  }
  /* The Projects table has a column to spare, so keep the full game title. */
  .projects-table .project-cell .project-name {
    display: inline;
  }
  /* Drop the "Est. amount"/"Amount" prefix in table headers, leaving just the
     currency, e.g. "(USD)" / "(CAD)". */
  .amount-label {
    display: none;
  }
  /* Show the compact "06-26" period instead of "June 2026". */
  .period-long {
    display: none;
  }
  /* Show the compact "08-31" date instead of the full "2026-08-31". */
  .date-long {
    display: none;
  }
  /* Show abbreviated amounts ("$128.6K") instead of full ("$128,599"). */
  .amount-full {
    display: none;
  }
  /* Generic opt-out for table columns that don't fit a phone (e.g. the key
     requests list hides Created by / Created / Expires). */
  .hide-narrow {
    display: none;
  }
  /* Even with the abbreviations above, five-column tables (dashboard payment
     tables) only fit a 375px phone with slimmer gutters between columns. */
  .table td,
  .table th {
    padding: 0.4em 0.35em;
  }
}
/* The abbreviated amount is only shown on narrow screens (rule below). Declared
   after the media query that hides .amount-full so the two never collide. */
.amount-short {
  display: none;
}
/* The compact period is only shown on narrow screens (see media query above).
   Both compact forms contain a hyphen the browser would happily break the
   line at when a phone-width table squeezes their column; keep them whole. */
.period-short {
  display: none;
  white-space: nowrap;
}
/* Likewise the compact date. */
.date-short {
  display: none;
  white-space: nowrap;
}
/* For table cells whose content must never break across lines (e.g. the
   Recent payments period "2026-06", which would otherwise split at the
   hyphen on a squeezed phone-width table). */
.nowrap {
  white-space: nowrap;
}
@media (max-width: 768px) {
  .amount-short {
    display: inline;
  }
  .period-short {
    display: inline;
  }
  .date-short {
    display: inline;
  }
}
/* Inline icon when a breadcrumb crumb carries one (e.g. project crumbs). */
.title .project-icon-sm {
  display: inline-block;
  vertical-align: middle;
  margin-right: 0.4rem;
}

/* Free-form list of games rendered under a bundle name on the sales-by-bundle
   report. Preserves user-entered line breaks. */
.bundle-games {
  font-size: 0.85em;
  color: var(--helm-muted);
  white-space: pre-line;
  margin-top: 0.15rem;
}

/* Inline forms inside table cells should not add vertical rhythm. */
td form {
  margin: 0;
}

/* Confirmation modal: a near-black, high-opacity backdrop. */
.modal-background {
  background-color: rgba(0, 0, 0, 0.85);
  backdrop-filter: blur(2px);
}
.modal-card {
  max-width: 28rem;
}
.modal-card-foot {
  gap: 0.5rem;
}

/* Daily sales bar chart. The hover tooltip and highlight are driven by
   /assets/chart.js (data-tip attributes), replacing the slow native <title>. */
.sales-chart .bar {
  cursor: pointer;
  /* `fill` is a presentation attribute, so brightness keeps each bar's own
     colour (blue/red) while making the hovered one pop. */
  transition: filter 0.08s ease;
}
.sales-chart .bar:hover {
  filter: brightness(1.18);
}
/* The chart markup bakes its light-scheme colours into SVG attributes (and the
   tests pin them); CSS outranks presentation attributes, so the parts that
   don't survive a dark background are re-pointed at theme tokens here. Blue and
   red bars/lines read fine in both schemes and are left alone. */
.sales-chart .bar-empty {
  fill: var(--helm-chart-empty);
}
.sales-chart .bar-share {
  fill: var(--helm-chart-share);
}
.sales-chart .bar-share-neg {
  fill: var(--helm-chart-share-neg);
}
.sales-line-share {
  stroke: var(--helm-chart-share);
}
.sales-line-marker-share {
  fill: var(--helm-chart-share);
}
.sales-line-marker-net,
.sales-line-marker-share {
  stroke: var(--helm-chart-marker-ring);
}
.sales-milestone {
  stroke: var(--helm-chart-milestone);
}
.sales-chart .axis-label,
.sales-line-chart .axis-label {
  fill: var(--helm-muted);
}
.sales-chart .axis-label-secondary,
.sales-line-chart .axis-label-secondary {
  fill: var(--helm-muted-faint);
}
.sales-chart .axis-baseline,
.sales-line-chart .axis-baseline {
  stroke: var(--helm-muted-faint);
}
.sales-line-crosshair {
  stroke: var(--helm-muted);
}
.sales-event-band {
  fill-opacity: var(--helm-chart-band-opacity);
}

.chart-tip {
  position: fixed;
  z-index: 50;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.06s ease;
  background-color: var(--helm-tip-bg);
  color: var(--helm-tip-text);
  font-size: 0.75rem;
  line-height: 1.2;
  padding: 0.3rem 0.5rem;
  border-radius: 4px;
  white-space: nowrap;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
}
.chart-tip.is-visible {
  opacity: 1;
}

/* User detail page: avatar + heading + status tags on the left, actions on
   the right. Mirrors the project-head pattern but for people. */
.user-head-info {
  display: flex;
  align-items: center;
  gap: 1rem;
}
.user-head-info .title {
  margin-bottom: 0;
}
/* Reusable initials-in-a-circle avatar. Rendered by the `userAvatar` view
   helper so the markup stays consistent everywhere a person is shown. The
   background colour comes from a `.user-avatar-cN` class chosen by hashing
   the user's initials, so the same initials are always the same colour. */
.user-avatar {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  font-weight: 600;
  font-size: 1.1rem;
  color: #fff;
  background: #6b6233;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  line-height: 1;
}
.user-avatar.is-small {
  width: 1.75rem;
  height: 1.75rem;
  font-size: 0.7rem;
}
/* 24 dark backgrounds, all chosen to keep ≥4.5:1 contrast with white text. */
.user-avatar-c0  { background: #b91c1c; } /* red */
.user-avatar-c1  { background: #991b1b; } /* deep red */
.user-avatar-c2  { background: #c2410c; } /* orange */
.user-avatar-c3  { background: #b45309; } /* amber */
.user-avatar-c4  { background: #a16207; } /* ochre */
.user-avatar-c5  { background: #4d7c0f; } /* olive */
.user-avatar-c6  { background: #15803d; } /* green */
.user-avatar-c7  { background: #166534; } /* forest */
.user-avatar-c8  { background: #047857; } /* emerald */
.user-avatar-c9  { background: #0f766e; } /* teal */
.user-avatar-c10 { background: #155e75; } /* deep cyan */
.user-avatar-c11 { background: #0e7490; } /* cyan */
.user-avatar-c12 { background: #0369a1; } /* sky */
.user-avatar-c13 { background: #1d4ed8; } /* blue */
.user-avatar-c14 { background: #1e3a8a; } /* navy */
.user-avatar-c15 { background: #4338ca; } /* indigo */
.user-avatar-c16 { background: #6d28d9; } /* violet */
.user-avatar-c17 { background: #7e22ce; } /* purple */
.user-avatar-c18 { background: #a21caf; } /* fuchsia */
.user-avatar-c19 { background: #86198f; } /* magenta */
.user-avatar-c20 { background: #be185d; } /* pink */
.user-avatar-c21 { background: #be123c; } /* rose */
.user-avatar-c22 { background: #334155; } /* slate */
.user-avatar-c23 { background: #44403c; } /* stone */

/* Navbar pairing: the small avatar sits beside the username text. */
.navbar-user {
  gap: 0.5rem;
}
/* Username + avatar pairing used in the user list table. */
.user-cell {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}
.user-head-tags {
  margin-top: 0.45rem;
  margin-bottom: 0;
}
.user-head-tags .tag {
  margin-bottom: 0;
}

/* Shared two-column "label / value" table used on detail pages. Caps the
   label column so values get the space; values pick up the brand text colour. */
.detail-table th {
  width: 9rem;
  color: var(--helm-brand-text);
  font-weight: 600;
}
.detail-table td.num {
  font-variant-numeric: tabular-nums;
}
.user-address {
  white-space: pre-line;
}

/* Royalty payment hero: the amount paid is the headline; the status pill and
   paid-on date sit at the far right. Stacks on narrow viewports. */
.payment-hero {
  display: flex;
  align-items: flex-start;
  gap: 1.5rem;
  flex-wrap: wrap;
}
.payment-hero-amount {
  flex: 1 1 16rem;
  min-width: 0;
}
.payment-hero-amount .heading {
  margin-bottom: 0.35rem;
}
.payment-hero-amount .title {
  margin-bottom: 0.25rem;
  font-variant-numeric: tabular-nums;
}
.payment-hero-unit {
  font-size: 0.55em;
  color: var(--helm-muted);
  font-weight: 500;
  margin-left: 0.25rem;
  letter-spacing: 0.02em;
}
.payment-hero-cad {
  color: var(--helm-brand-text);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}
.payment-hero-rate {
  color: var(--helm-muted);
  margin-left: 0.4rem;
  font-weight: 400;
}
.payment-hero-meta {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.6rem;
  text-align: right;
}
.payment-hero-date {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  color: var(--helm-brand-text);
  font-weight: 500;
}

/* Calculation row: keep the "Net × Rate = Result" expression muted; the
   bolded headline amount in the hero is the answer. */
.payment-calc-formula {
  color: var(--helm-muted);
}

/* Sales-periods editor: tighten the inline-edit table so date inputs, label
   and the icon-only Save/Delete actions all land on one baseline. */
.sale-periods-table td {
  vertical-align: middle;
}
/* Icon-only Save/Delete sit side by side, right-aligned. Each lives in its
   own <form> (different actions), so we wrap both forms in a flex container
   to keep them on a single row instead of letting the block-level forms
   stack vertically. */
.sale-periods-actions {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 0.25rem;
}
.sale-periods-actions form {
  margin: 0;
}

/* Add form: From | To | Label (stretches) | Add. Single row on the desktop,
   stacked on mobile so the label input still gets the full width it needs. */
.sale-periods-add {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.75rem;
}
.sale-periods-add .field {
  margin-bottom: 0;
}
.sale-periods-add-label {
  flex: 1 1 14rem;
}



/* Email-template body shown on a template's detail page: a monospace block that
   keeps the author's line breaks (a plain <pre>) but wraps long lines so a stray
   long URL can't force a horizontal scrollbar. */
.email-template-subject {
  font-weight: 600;
  margin-bottom: 1rem;
}
.email-template-body {
  white-space: pre-wrap;
  word-break: break-word;
  background-color: var(--helm-tint-strong);
  border-radius: 4px;
  padding: 0.75rem 1rem;
}

/* Earnings page: rows are grouped per person, each group opened by a bold
   name row and closed by a bold subtotal row; the spacer row separates one
   person's group from the next. */
.earnings-user td,
.earnings-subtotal td {
  font-weight: 600;
}
.earnings-spacer td {
  border: none;
  padding: 0.75rem 0;
  /* Bulma paints the table white; matching the page background makes the
     spacer read as a true gap between groups rather than an empty row. */
  background-color: var(--helm-page-bg);
}

/* Royalty create form: the per-game calculation lines the server computes for
   the selected user + Steam payment, one line per game plus a total. */
.royalty-calc {
  white-space: pre-line;
}

/* Dashboard "Upcoming payments": one row per month; the Projects cell lists
   each game on one line — icon, name, then its slice of the combined payment
   as a muted figure after a separator dot. The project link is itself a flex
   box (.project-cell), so each game line must be flex too or the amount wraps
   underneath it. */
/* Rows grow when a month covers several games, so top-align the cells rather
   than centring them (overrides the global .table middle alignment). The
   single-line cells take the same 1.75rem line height as an icon'd game row
   so their text sits level with the first game name. */
.upcoming-table tbody td {
  vertical-align: top;
  line-height: 1.75rem;
}
.upcoming-game {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.upcoming-game + .upcoming-game {
  margin-top: 0.35rem;
}
.upcoming-game-amount {
  font-size: 0.85em;
  color: var(--helm-muted);
  white-space: nowrap;
}
.upcoming-game-amount::before {
  content: "·";
  margin-right: 0.5rem;
}
/* Narrow screens hide the game names (icons only, like other tables), so the
   per-game dollar split — a full unabbreviated figure — is what blows the
   column budget. Drop it (the month's totals remain in the USD/local columns)
   and flow the now icon-only games side by side so each month is one line. */
@media (max-width: 768px) {
  .upcoming-games {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.35rem;
  }
  .upcoming-game + .upcoming-game {
    margin-top: 0;
  }
  .upcoming-game-amount {
    display: none;
  }
}

/* Royalty payment view: a Calculation line's game name with, on tiered games,
   the tier band the line covers beside it in muted small text. Same flex
   arrangement as .upcoming-game — the project link is a flex box, so the
   label must sit in a flex row or it wraps underneath. */
.calc-game {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.calc-tier {
  font-size: 0.85em;
  color: var(--helm-muted);
  white-space: nowrap;
}
.calc-tier::before {
  content: "·";
  margin-right: 0.5rem;
}
