    [hidden] { display: none !important; }
    * { box-sizing: border-box; }
    body {
      margin: 0;
      background: var(--bg);
      color: var(--ink);
      font-family: var(--font-ui);
      /* 1rem, not a hard 16px -- otherwise body copy would ignore the root
         scale set on html and drift out of step with every rem-sized label. */
      font-size: 1rem;
      line-height: 1.45;
    }
    button, input, select, textarea, dialog { font: inherit; }
    h1, h2, h3 { margin: 0; line-height: 1.1; font-weight: 700; }
    .updated, .status-line, .panel-note { color: var(--muted); }
    .updated, .status-line { min-height: 1.5rem; margin-top: 8px; font-size: var(--type-body-sm); }
    /* Collapse the transient status line while it holds no message, so it does
       not reserve ~32px of blank space above the dashboard content. */
    .status-line:empty { display: none; }
    .status-line.error { color: var(--danger); font-weight: 600; }
    .status-line.success { color: var(--good); font-weight: 600; }
    .actions { display: flex; gap: 10px; justify-content: flex-end; flex-wrap: wrap; }
    .button-link, .primary-button, .secondary-button, .danger-button {
      align-items: center; border: 0; background: var(--button); color: #fff; display: inline-flex;
      border-radius: 8px; min-height: 40px; padding: 0 14px; font-weight: 600; cursor: pointer;
      text-decoration: none; white-space: nowrap; transition: background 0.2s;
    }
    .button-link:hover, .primary-button:hover { background: var(--button-hover); }
    .secondary-button { background: var(--navy); }
    .secondary-button:hover { background: #1e293b; }
    .danger-button { background: var(--danger); }
    .danger-button:hover { background: #be123c; }
    .primary-button:disabled,
    .secondary-button:disabled,
    .danger-button:disabled {
      background: #aab1b5;
      color: #eef1f2;
      cursor: not-allowed;
    }
    .panel { background: var(--panel); border: 1px solid var(--line); border-radius: 12px; overflow: hidden; margin-bottom: 18px; box-shadow: 0 14px 32px rgba(31, 37, 40, 0.04); }
    .panel-header { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; padding: 16px 18px 12px; border-bottom: 1px solid var(--line); background: var(--panel); }
    .panel-body { padding: 16px 18px; }
    .panel-note { font-size: var(--type-body-sm); }
    .input { width: 100%; min-height: 38px; border: 1px solid var(--line); border-radius: 6px; padding: 8px 12px; background: #fff; color: inherit; }
    .action-card {
      border: 1px solid var(--line);
      border-radius: 12px;
      padding: 16px;
      display: flex;
      flex-direction: column;
      gap: 12px;
      box-shadow: 0 4px 12px rgba(31, 37, 40, 0.02);
      transition: transform 0.2s, box-shadow 0.2s, opacity 0.35s ease, max-height 0.35s ease, margin 0.35s ease, padding 0.35s ease, border 0.35s ease;
      max-height: 800px;
      overflow: hidden;
    }
    .bundle-container, .action-group-section {
      transition: opacity 0.35s ease, max-height 0.35s ease, margin 0.35s ease, padding 0.35s ease;
      max-height: 5000px;
    }
    .dismissing {
      opacity: 0 !important;
      max-height: 0 !important;
      margin-top: 0 !important;
      margin-bottom: 0 !important;
      padding-top: 0 !important;
      padding-bottom: 0 !important;
      border-top-width: 0 !important;
      border-bottom-width: 0 !important;
      pointer-events: none;
      overflow: hidden !important;
    }
    .card-header { display: flex; justify-content: space-between; align-items: center; gap: 12px; }
    .card-title { font-size: var(--type-body-md); font-weight: 600; color: var(--ink); }
    .card-badge {
      display: inline-flex; align-items: center; border-radius: 999px; padding: 2px 10px; font-size: var(--type-label-caps); font-weight: 600; text-transform: uppercase;
    }
    .card-desc { font-size: var(--type-body-sm); margin: 0; color: var(--ink); }
    .card-meta { font-size: var(--type-label-caps); color: var(--muted); display: flex; gap: 12px; flex-wrap: wrap; }
    .card-actions { display: flex; gap: 10px; margin-top: 4px; }
    /* The Daily Run dialog (.zen-*) is styled in action-dashboard.css only.
       It is rendered on the dashboard alone, which loads that file, so a copy
       here could only ever drift -- and did: a stale one hid the run's queue
       and its footer setting at phone widths. Do not reinstate it. */
    .dismiss-card-btn {
      background: none;
      border: none;
      color: var(--muted);
      font-size: var(--type-body-lg);
      cursor: pointer;
      padding: 0 4px;
      line-height: 1;
      transition: color 0.2s;
    }
    .dismiss-card-btn:hover {
      color: var(--danger);
    }
    .empty-state { padding: 32px 16px; color: var(--muted); text-align: center; font-size: var(--type-body-md); }
    .table-wrap { overflow-x: auto; }
    table { width: 100%; min-width: 500px; border-collapse: collapse; }
    th, td { padding: 12px 16px; border-bottom: 1px solid var(--line); vertical-align: middle; text-align: left; }
    th { background: var(--bg); font-size: var(--type-label-caps); font-weight: 500; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); }
    td { font-size: var(--type-label-caps); }
    /* Inline code had no rule anywhere in the app, so any <code> outside the
       two settings blocks that name it fell back to the browser's generic
       monospace -- a third typeface on the page. Size stays inherited so a
       <code> reads correctly inside a caption as well as inside body copy. */
    code, kbd, samp { font-family: var(--font-mono); }
    tbody tr:hover { background: var(--panel-soft); }
    .dialog-shell {
      width: min(500px, calc(100% - 24px));
      border: 1px solid var(--line);
      border-radius: 20px;
      padding: 0;
      color: var(--ink);
      background: var(--panel);
      box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04), 0 8px 24px rgba(15, 23, 42, 0.08);
      max-height: min(88vh, 920px);
      display: flex;
      flex-direction: column;
      overflow: hidden;
    }
    .dialog-shell:not([open]) { display: none; }
    .dialog-shell::backdrop { background: rgba(23, 26, 28, 0.42); }
    .dialog-body { padding: 18px 18px 20px; flex: 1; overflow-y: auto; }
    /* Canonical dialog close control (corner icon "x"). One pattern for every
       dialog header across the app; see DESIGN.md > Components > Dialogs. The
       casino detail modal keeps its own .cdm-close because it sits on a dark
       branded header where this neutral treatment would be invisible. */
    .dialog-close {
      align-self: center;
      display: inline-grid;
      place-items: center;
      flex: 0 0 32px;
      width: 32px;
      height: 32px;
      padding: 0;
      border: 0;
      border-radius: 8px;
      background: transparent;
      color: var(--muted);
      line-height: 1;
      cursor: pointer;
      transition: background 150ms ease, color 150ms ease;
    }
    .dialog-close .ct-symbol { font-size: 20px; }
    .dialog-close:hover { background: var(--panel-soft); color: var(--ink); }
    .dialog-close:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
    /* Page panel headers intentionally stack on small screens. Dialog headers
       must remain a row so their close control stays in the top-right corner. */
    .dialog-shell > .panel-header {
      align-items: flex-start;
      flex-direction: row;
    }
    .dialog-shell > .panel-header > :first-child {
      min-width: 0;
    }
    .dialog-shell > .panel-header > .dialog-close {
      align-self: flex-start;
      margin-left: auto;
    }
    .dialog-grid {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: 12px;
      margin: 14px 0 18px;
    }
    .dialog-grid label { display: grid; gap: 6px; font-weight: 600; }
    .dialog-wide { grid-column: 1 / -1; }
    .prefill-warning {
      margin: 0 0 12px;
      padding: 10px 12px;
      border: 1px solid #facc15;
      border-radius: 6px;
      background: #fef3c7;
      color: #713f12;
      font-weight: 600;
    }
    .inline-help {
      position: relative;
      display: inline-flex;
    }
    .inline-help summary {
      list-style: none;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      width: 18px;
      height: 18px;
      border-radius: 999px;
      border: 1px solid var(--line);
      color: var(--muted);
      font-size: var(--type-label-caps);
      font-weight: 700;
      cursor: pointer;
      user-select: none;
      background: var(--panel);
    }
    .inline-help summary::-webkit-details-marker { display: none; }
    .inline-help[open] .inline-help-popover { display: block; }
    .inline-help summary:focus-visible {
      outline: 2px solid var(--focus-ring);
      outline-offset: 2px;
    }
    .inline-help-popover p { margin: 0; }
    .inline-help-popover p + p { margin-top: 8px; }
    .inline-help-popover {
      display: none;
      position: absolute;
      top: calc(100% + 8px);
      right: 0;
      width: min(280px, calc(100vw - 48px));
      padding: 10px 12px;
      border: 1px solid var(--line);
      border-radius: 8px;
      background: var(--panel);
      color: var(--ink);
      box-shadow: 0 18px 40px rgba(31, 37, 40, 0.18);
      font-size: var(--type-label-caps);
      font-weight: 500;
      line-height: 1.35;
      z-index: 20;
    }
    .casino-link-row { margin-top: -4px; }
    .casino-link-row a { color: var(--button); font-weight: 700; }
    .in-app-notification-item {
      background: var(--panel-soft);
      border: 1px solid var(--line);
      border-radius: 8px;
      padding: 10px 12px;
      display: flex;
      flex-direction: column;
      gap: 6px;
      position: relative;
    }
    .in-app-notification-item.unread {
      border-left: 4px solid var(--button);
      background: #f0f7fc;
    }
    .notification-item-header {
      display: flex;
      justify-content: space-between;
      align-items: baseline;
      gap: 8px;
    }
    .notification-item-title {
      font-weight: 700;
      font-size: var(--type-body-sm);
    }
    .notification-item-body {
      font-size: var(--type-body-sm);
      margin: 0;
    }
    .notification-item-time {
      font-size: var(--type-label-caps);
      color: var(--muted);
    }
    /* Design tokens now live in tokens.css, loaded ahead of this file. */
    html {
      background: var(--bg);
    }
    body {
      min-height: 100vh;
      background: var(--bg);
      color: var(--ink);
      font-family: var(--font-ui);
      letter-spacing: 0;
    }
    body.daily-run-active {
      overflow: hidden;
    }
    h1,
    h2,
    h3 {
      font-family: var(--font-heading);
      letter-spacing: 0;
    }
    button,
    input,
    select,
    textarea {
      font-family: var(--font-ui);
      letter-spacing: 0;
    }
    h1,
    h2,
    h3,
    button,
    input,
    select,
    textarea {
      letter-spacing: 0;
    }
    :focus-visible {
      outline: 3px solid rgba(15, 118, 110, 0.34);
      outline-offset: 2px;
    }
    .brand-title {
      color: var(--ink);
      font-family: var(--font-heading);
      font-size: var(--type-body-lg);
      font-weight: 600;
      line-height: 1.1;
    }
    .updated,
    .status-line,
    .panel-note,
    .brand-subtitle,
    .empty-state p,
    .next-collection-time,
    .expected-helper {
      color: var(--muted);
    }
    .metric strong,
    .summary-pill strong,
    [data-derived],
    [data-derived-roi],
    [data-field="amount"],
    [data-field="balance"],
    .money-good,
    .money-bad,
    .daily-bonus-stats b,
    .next-collection-time,
    .expected-date,
    .pending-amount {
      font-family: var(--font-mono);
      font-variant-numeric: tabular-nums;
    }
    .app-sidebar {
      position: fixed;
      inset: 0 auto 0 0;
      z-index: 20;
      display: flex;
      width: 240px;
      flex-direction: column;
      gap: 24px;
      background: var(--bg);
      padding: 22px 18px;
      transition: width 0.18s ease;
    }
    html.sidebar-state-loading .app-sidebar,
    html.sidebar-state-loading .app-main {
      transition: none !important;
    }
    html.sidebar-collapsed .app-sidebar,
    body.sidebar-collapsed .app-sidebar {
      width: 80px;
    }
    /* Screenshot mode: a per-browser, client-only preference (Settings ->
       About & Support) that hides the operator-only Admin sidebar link so
       marketing screenshots can be taken from a real account. Never sent to
       the server -- see global-actions.js. */
    html.screenshot-mode .nav-item[href="/admin"],
    body.screenshot-mode .nav-item[href="/admin"] {
      display: none;
    }
    .sidebar-brand {
      display: flex;
      min-height: 48px;
      align-items: center;
      gap: 12px;
    }
    .brand-mark {
      display: grid;
      width: 40px;
      height: 40px;
      flex: 0 0 auto;
      place-items: center;
      border-radius: 999px;
      background: var(--button);
      color: #ffffff;
      font-family: var(--font-heading);
      font-weight: 700;
    }
    img.brand-mark {
      border-radius: 10px;
      background: none;
      object-fit: contain;
    }
    html.sidebar-collapsed .brand-copy,
    html.sidebar-collapsed .nav-item span:last-child,
    body.sidebar-collapsed .brand-copy,
    body.sidebar-collapsed .nav-item span:last-child {
      display: none;
    }
    html.sidebar-collapsed .sidebar-brand,
    body.sidebar-collapsed .sidebar-brand {
      justify-content: center;
    }
    .sidebar-nav {
      display: grid;
      gap: 6px;
      /* The nav can outgrow a short window once the operator links are on it.
         Scrolling the nav rather than the whole sidebar keeps the brand on top
         and the account controls at the foot. min-height: 0 is what actually
         lets a flex child shrink enough to scroll at all.
         (The guide's tree used to open in here, which is what first made this
         necessary; it has its own column inside the guide now.) */
      min-height: 0;
      overflow-y: auto;
      scrollbar-width: thin;
      scrollbar-color: var(--surface-container-highest) transparent;
    }
    .sidebar-nav::-webkit-scrollbar {
      width: 8px;
    }
    .sidebar-nav::-webkit-scrollbar-thumb {
      border: 2px solid transparent;
      border-radius: 999px;
      background: var(--surface-container-highest);
      background-clip: content-box;
    }
    .nav-item,
    .mobile-bottom-nav a {
      color: var(--muted);
      font-size: var(--type-body-sm);
      font-weight: 500;
      text-decoration: none;
    }
    .nav-item {
      display: flex;
      align-items: center;
      gap: 12px;
      min-height: 42px;
      border-radius: 8px;
      padding: 0 12px;
    }
    .nav-item .ct-symbol {
      width: 22px;
      flex: 0 0 22px;
      font-size: 1.3rem;
    }
    .nav-item:hover,
    .nav-item.is-active {
      background: var(--surface-container-highest);
      color: var(--button);
    }
    .nav-item.is-active {
      font-weight: 600;
    }
    .ghost-button,
    .utility-toggle {
      min-height: 36px;
      border: 1px solid var(--line);
      border-radius: var(--radius-control);
      background: #ffffff;
      color: var(--button);
      cursor: pointer;
      font-weight: 600;
    }
    .sidebar-toggle {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      flex: 0 0 auto;
      border: 0;
      background: transparent;
      color: var(--muted);
      cursor: pointer;
    }
    .sidebar-toggle:hover {
      background: var(--surface-container-highest);
      color: var(--ink);
    }
    .icon-button {
      display: inline-flex;
      min-width: 40px;
      min-height: 40px;
      align-items: center;
      justify-content: center;
      gap: 8px;
      padding: 0 11px;
      border-radius: 12px;
    }
    .mobile-bottom-nav {
      display: none;
    }
    .app-main {
      width: auto;
      min-height: 100vh;
      margin: 0 0 0 240px;
      padding: 24px clamp(20px, 3vw, 40px) 48px;
      transition: margin-left 0.18s ease;
    }
    html.sidebar-collapsed .app-main,
    body.sidebar-collapsed .app-main {
      margin-left: 80px;
    }
    .app-topbar {
      position: sticky;
      top: 0;
      z-index: 15;
      display: flex;
      align-items: center;
      justify-content: flex-start;
      gap: 18px;
      margin: -24px calc(-1 * clamp(20px, 3vw, 40px)) 20px;
      /* Opaque, seamless bar. A translucent background + backdrop-filter here
         made sticky cards leave repaint "ghost" rectangles while scrolling in
         Chrome, so the bar now matches the page background. */
      background: var(--bg);
      padding: 12px clamp(20px, 3vw, 40px);
      /* The bar queries its own width (below), not the viewport's: collapsing
         the sidebar hands it 160px more room at an unchanged viewport. */
      container-type: inline-size;
      container-name: topbar;
      /* Elevation is earned, not resting: see the dissolve block below. */
      transition: box-shadow 0.18s ease;
    }
    /* Scroll-under dissolve, part 1 of 2: the nav.
       Content used to be guillotined at the bar's bottom edge -- headings and
       card titles sliced mid-letter, which reads as a rendering glitch rather
       than as one surface passing behind another. The bar now owns a short
       gradient dissolve zone beneath it and lifts off the page only while
       something is actually behind it. Nothing moves and no scrollbar appears.
       Pages opt in with `has-dissolve` on the header; scroll-dissolve.js
       injects .nav-scrim after the bar and sets data-lifted / --topbar-h. */
    .app-topbar.has-dissolve[data-lifted] {
      box-shadow: 0 8px 22px -14px rgba(16, 24, 40, 0.5);
    }
    /* A sticky sibling, not a pseudo-element on the bar: the bar's own
       stacking context (z-index 15) would paint the fade over the Daily Bonus
       card and the utility rail, which pin 8px lower and have nothing behind
       them. z-index 9 puts the scrim above the scrolling page and below those
       two columns, so only the gap between them fades. The negative margin
       cancels its flow height so the page below does not shift. */
    .nav-scrim {
      position: sticky;
      top: var(--topbar-h, 64px);
      z-index: 9;
      height: var(--dissolve-depth);
      margin: 0 calc(-1 * clamp(20px, 3vw, 40px)) calc(-1 * var(--dissolve-depth));
      opacity: 0;
      pointer-events: none;
      /* Opaque only at the very edge, where the clip line would otherwise be,
         then off fast. */
      background: linear-gradient(
        180deg,
        var(--bg) 0%,
        color-mix(in srgb, var(--bg) 55%, transparent) 34%,
        transparent 100%
      );
      transition: opacity 0.16s linear;
    }
    /* Tuck the menu toggle against the sidebar edge instead of floating inset. */
    .app-topbar .sidebar-toggle {
      margin-left: calc(-1 * clamp(20px, 3vw, 40px) + 4px);
    }
    /* When the bar is squeezed the title is what yields -- the action pills are
       fixed-size targets and the sidebar already says which page this is. */
    .topbar-title {
      min-width: 0;
    }
    .app-topbar h1,
    .app-topbar .topbar-label {
      margin: 0;
      font-size: var(--type-body-lg);
      font-weight: 600;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    .app-topbar .topbar-subtitle {
      margin: 4px 0 0;
    }
    .topbar-actions {
      display: flex;
      align-items: center;
      justify-content: flex-end;
      gap: 10px;
      /* Never wrap: a wrapped row dropped the whole quick-action group onto a
         second line. The container query below sheds the labels first. */
      flex-wrap: nowrap;
      /* And never shrink -- the pills inside are fixed-size targets that cannot
         absorb it, so a shrinking box just pushes them out past the bar. The
         title takes the squeeze instead (it ellipsises). */
      flex: 0 0 auto;
      min-width: 0;
      margin-left: auto;
    }
    /* Two topbar groups: the CTA quick-actions and the utility icons. On
       desktop they lay out as inline rows (visually unchanged from the old
       flat list); on mobile they become grid areas -- see the 760px block. */
    .topbar-quick,
    .topbar-utility {
      display: flex;
      align-items: center;
      gap: 10px;
      flex-wrap: nowrap;
      min-width: 0;
    }
    .quick-action,
    .primary-button,
    .secondary-button,
    .danger-button,
    .button-link {
      border-radius: var(--radius-control);
      font-family: var(--font-ui);
      font-weight: 700;
      letter-spacing: 0;
    }
    .quick-action {
      display: inline-flex;
      min-height: 34px;
      align-items: center;
      gap: 8px;
      border: 1px solid transparent;
      border-radius: 999px;
      padding: 0 12px;
      cursor: pointer;
      white-space: nowrap;
      font-weight: 500;
    }
    .quick-action .ct-symbol {
      font-size: 1.05rem !important;
    }
    .quick-action-purchase {
      border-color: #fecdd3;
      background: #fff1f2;
      color: #e11d48;
    }
    .quick-action-wager {
      border-color: #bfdbfe;
      background: #eff6ff;
      color: #2563eb;
    }
    .quick-action-redemption {
      border-color: #a7f3d0;
      background: #ecfdf5;
      color: #059669;
    }
    /* Neutral pill (not a bright CTA color like the 3 quick-actions above,
       since it isn't a financial action) -- a labeled button read clearer
       than the earlier icon-only trigger. */
    .feedback-button {
      display: inline-flex;
      min-height: 34px;
      align-items: center;
      gap: 8px;
      border: 1px solid var(--line);
      border-radius: 999px;
      padding: 0 12px;
      cursor: pointer;
      white-space: nowrap;
      font-weight: 500;
      font-family: var(--font-ui);
      background: transparent;
      color: var(--muted);
    }
    /* Icon-only on desktop as well as mobile. It was the widest labelled pill
       in the bar and it is not a peer of the three financial CTAs, so it joins
       the utility icon set rather than competing with them. The name is still
       announced -- see the aria-label/title in partials/feedback_button.html. */
    .feedback-button-label {
      display: none;
    }
    .topbar-utility > .feedback-button {
      width: 40px;
      min-width: 40px;
      min-height: 40px;
      padding: 0;
      justify-content: center;
      border: 0;
      border-radius: 12px;
    }
    .feedback-button:hover {
      background: var(--surface-container-highest);
      color: var(--ink);
    }
    /* Desktop only -- under 760px the bar becomes a grid and the quick actions
       get their own full-width row, where the labels fit and belong.
       Threshold measured, not guessed: with the labels in, the row's intrinsic
       content is 768px (40 toggle + 18 gap + 146 widest page title + 18 gap +
       346 pills + 10 + 190 utility icons). 780 sheds them just before the row
       would have to break, with a little slack for font-metric drift. */
    @media (min-width: 761px) {
      @container topbar (max-width: 780px) {
        .quick-action > span:not(.ct-symbol) {
          display: none;
        }
        .quick-action {
          padding: 0 10px;
        }
      }
    }
    .feedback-button .ct-symbol {
      font-size: 1.05rem !important;
    }
    .secondary-button {
      background: var(--navy);
    }
    .account-menu-trigger {
      border: 0;
      background: transparent;
      color: var(--muted);
      text-decoration: none;
      cursor: pointer;
    }
    .account-menu-trigger[aria-expanded="true"] {
      background: var(--surface-container-highest);
      color: var(--ink);
    }
    .account-menu-trigger:hover,
    .account-menu-trigger:focus-visible,
    .bell-button:hover {
      background: var(--surface-container-highest);
      color: var(--ink);
    }
    .bell-container {
      position: relative;
      display: inline-block;
      vertical-align: middle;
    }
    .bell-button {
      position: relative;
      border: 0;
      border-radius: 12px;
      background: transparent;
      color: var(--muted);
      cursor: pointer;
      transition: background 0.2s, color 0.2s;
    }
    .bell-badge {
      position: absolute;
      top: 0;
      right: 0;
      display: none;
      min-width: 17px;
      height: 17px;
      align-items: center;
      justify-content: center;
      border-radius: 999px;
      background: #ad2f38;
      color: #ffffff;
      font-size: var(--type-label-caps);
      font-weight: 700;
      line-height: 1;
      padding: 0 5px;
      transform: translate(28%, -22%);
    }
    .bell-dropdown {
      position: absolute;
      right: 0;
      top: 100%;
      z-index: 100;
      width: 320px;
      max-height: 400px;
      overflow-y: auto;
      margin-top: 8px;
      border: 1px solid var(--line);
      border-radius: 8px;
      background: var(--panel);
      box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
    }
    /* The account menu. Same dropdown vocabulary as .bell-dropdown (320px,
       8px radius, 1px var(--line), the same shadow, 8px below the bar) --
       but it lives at shell level, not in the topbar, and is positioned
       fixed by account-menu.js from the trigger's box.

       Layering, against the shell's existing layers rather than a number
       invented for it: the bar is 15, the guide's Contents bar 16, the
       sidebar 20, the mobile bottom nav 25 -- the menu (and its mobile sheet)
       must clear all of those, so 40. Everything above it -- the guide drawer
       at 50/60, Settings' modal backdrop at 50, the dashboard overlays at
       60-71 -- is a surface that cannot be open at the same time: opening the
       drawer closes the menu through the popup controller, and every modal is
       opened from a control the menu's own outside-click rule has already
       closed it for. So nothing ever needs to paint over an open menu, and
       the menu never needs to paint over a modal. */
    .account-menu-backdrop {
      position: fixed;
      inset: 0;
      z-index: 39;
      background: rgba(15, 23, 42, 0.32);
    }
    .account-menu-panel {
      position: fixed;
      z-index: 40;
      width: 320px;
      max-height: min(480px, calc(100vh - 80px));
      overflow-y: auto;
      padding: 6px 0;
      border: 1px solid var(--line);
      border-radius: 8px;
      background: var(--panel);
      box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
    }
    .account-menu-panel[hidden],
    .account-menu-backdrop[hidden] {
      display: none;
    }
    /* Desktop: a dropdown, no backdrop, no sheet header. */
    @media (min-width: 761px) {
      .account-menu-backdrop,
      .account-menu-sheet-head {
        display: none;
      }
    }
    .account-menu-identity {
      display: grid;
      gap: 2px;
      padding: 10px 14px 12px;
      border-bottom: 1px solid var(--line);
      margin-bottom: 6px;
    }
    .account-menu-identity-label {
      color: var(--muted);
      font-size: var(--type-label-caps);
      font-weight: 500;
    }
    .account-menu-identity-email {
      color: var(--ink);
      font-size: var(--type-body-sm);
      font-weight: 500;
      overflow-wrap: anywhere;
    }
    /* Rows share .nav-item's rhythm (42px, 0 12px, 12px gap): 40px minimum,
       0 14px, 12px gap, a --panel-soft hover. */
    .account-menu-item {
      display: flex;
      align-items: center;
      gap: 12px;
      width: 100%;
      min-height: 40px;
      padding: 0 14px;
      border: 0;
      border-radius: 0;
      background: transparent;
      color: var(--ink);
      font-family: inherit;
      font-size: var(--type-body-sm);
      font-weight: 500;
      text-align: left;
      text-decoration: none;
      cursor: pointer;
    }
    .account-menu-item .ct-symbol,
    .account-menu-item .ct-symbol-spacer {
      width: 22px;
      flex: 0 0 22px;
      font-size: 1.3rem;
    }
    .account-menu-item:hover,
    .account-menu-item:focus-visible {
      background: var(--panel-soft);
      color: var(--button);
      outline: none;
    }
    .account-menu-item[aria-current="page"] {
      color: var(--button);
    }
    .account-menu-item[aria-current="page"]::after {
      content: "";
      margin-left: auto;
      width: 6px;
      height: 6px;
      border-radius: 999px;
      background: var(--button);
    }
    .account-menu-item-quiet {
      min-height: 34px;
      color: var(--muted);
      font-size: var(--type-label-caps);
    }
    .account-menu-item:disabled {
      opacity: 0.5;
      cursor: default;
    }
    .account-menu-separator {
      height: 1px;
      margin: 6px 0;
      background: var(--line);
    }
    /* The one install control in the document, menu-scoped. It used to be
       hidden under html.sidebar-collapsed by a descendant rule that followed
       it wherever it was moved; a collapsed sidebar has no bearing on it now. */
    .account-menu-panel .pwa-install-button {
      color: var(--button);
    }
    .account-menu-panel .pwa-install-button:disabled {
      cursor: default;
      opacity: 0.7;
    }
    .account-menu-panel .pwa-install-status {
      margin: 0;
      padding: 0 14px 6px 48px;
      color: var(--muted);
      font-size: var(--type-label-caps);
    }
    .account-menu-panel .pwa-install-status[hidden],
    .account-menu-panel .pwa-install-button[hidden] {
      display: none;
    }
    .dashboard-layout {
      display: grid;
      grid-template-columns: minmax(0, 1fr) 320px;
      gap: 24px;
      margin-top: 14px;
      align-items: start;
      max-width: 1280px;
    }
    .dashboard-feed {
      display: grid;
      gap: 18px;
      min-width: 0;
    }
    .panel {
      border-color: var(--line);
      border-radius: var(--radius-panel);
      box-shadow: var(--shadow-panel);
    }
    /* The header belongs to the card, not to the page: painting it var(--bg)
       laid a page-grey band across the top of every white panel. */
    .panel-header {
      background: var(--panel);
    }
    /* The panel header's title had no rule at all, so it fell through to the
       browser default h2 (1.5em) and the blanket h1,h2,h3 weight -- the
       largest type on the dashboard. Applies to dialog headers too, which
       reuse .panel-header. */
    .panel-header h2 {
      font-size: var(--type-body-md);
      font-weight: 600;
    }
    .daily-bonus-float {
      position: sticky;
      top: 72px;
      z-index: 10;
      display: grid;
      gap: 16px;
      border: 1px solid var(--line);
      border-radius: var(--radius-panel);
      background: #ffffff;
      box-shadow: var(--shadow-panel);
      padding: 18px;
      transition: box-shadow 0.18s ease, border-radius 0.18s ease;
    }
    /* Scroll-under dissolve, part 2 of 2: the Daily Bonus card.
       The feed used to be cut off dead straight at this card's bottom edge.
       The dissolve is column-scoped -- a page-wide fade would be wrong, since
       the utility rail to the right has nothing pinned over it. It hangs off
       the card as a pseudo-element, so it costs no layout and the stats and
       Start Run button never move. Driven by scroll-dissolve.js, which sets
       --dissolve and data-lifted once the card is pushed past its pin line. */
    .daily-bonus-float::after {
      content: "";
      position: absolute;
      /* Straight band across the full width -- it must read as if the card
         had no rounded corners at all. Rounding it to match the card instead
         pinched a waist into the fade, and leaving the corners round left two
         crescents of un-dissolved content peeking out past them. The card
         squares its own bottom corners while lifted (below), so the two edges
         line up exactly. Offset by the 1px border so the card keeps its
         bottom edge, and pulled 1px wide on each side so no hairline of sharp
         content survives at the sides. */
      top: calc(100% + 1px);
      left: -1px;
      right: -1px;
      height: var(--dissolve-depth);
      opacity: var(--dissolve, 0);
      pointer-events: none;
      /* Opaque only at the very edge, where the clip line would otherwise be,
         then off fast. */
      background: linear-gradient(
        180deg,
        var(--bg) 0%,
        color-mix(in srgb, var(--bg) 55%, transparent) 34%,
        transparent 100%
      );
      transition: opacity 0.16s linear;
    }
    /* While the card is pinned its bottom edge is a cut line, not a corner:
       squaring it lets the dissolve run straight across and seals the card
       against whatever is passing behind. The radius comes back the moment
       the card drops out of its pin and has clear air beneath it again. */
    .daily-bonus-float[data-lifted] {
      border-bottom-left-radius: 0;
      border-bottom-right-radius: 0;
      box-shadow: 0 14px 30px -20px rgba(16, 24, 40, 0.42);
    }
    /* Two fixed columns: title block (title + status chip) | Start Run button.
       The chip may wrap below the title inside its own block; the button never
       moves, so chip and button cannot collide at any width.
       (Kept in sync with action-dashboard.css — the dashboard loads both.) */
    .daily-bonus-command-header {
      display: grid;
      grid-template-columns: minmax(0, 1fr) auto;
      align-items: center;
      gap: 10px 14px;
    }
    .daily-run-button {
      gap: 10px;
      min-height: 44px;
      padding: 0 24px;
      background: var(--button);
      box-shadow: 0 1px 3px rgba(15, 118, 110, 0.18);
    }
    .daily-run-button .ct-symbol {
      font-size: 1.25rem;
    }
    .daily-bonus-command-copy {
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      gap: 6px 12px;
      min-width: 0;
    }
    .daily-bonus-command-copy h2 {
      margin: 0;
      color: var(--ink);
      font-size: var(--type-headline-sm);
      font-weight: 500;
      line-height: 1.2;
      white-space: nowrap;
    }
    /* Status chip — the card's state machine. Always present (only hidden
       before the first data load); data-state selects the treatment. */
    .daily-bonus-chip {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      padding: 4px 12px;
      border: 1px solid var(--line);
      border-radius: 999px;
      background: var(--panel-soft);
      color: var(--muted);
      font-size: var(--type-label-caps);
      font-weight: 700;
      white-space: nowrap;
    }
    .daily-bonus-chip[hidden] {
      display: none;
    }
    .daily-bonus-chip b {
      color: var(--ink);
      font-weight: 700;
    }
    .daily-bonus-chip-icon {
      font-size: 0.95rem !important;
      color: inherit;
    }
    .daily-bonus-chip[data-state="ready"] {
      background: #d1fae5;
      border-color: #a7f3d0;
      color: #065f46;
    }
    .daily-bonus-chip[data-state="ready"] b {
      color: #065f46;
    }
    .daily-bonus-chip[data-state="done"] {
      background: #f0fdf4;
      border-color: #bbf7d0;
      color: #166534;
    }
    .daily-bonus-chip[data-state="done"] b {
      color: #166534;
    }
    .daily-bonus-chip-dot {
      flex: 0 0 auto;
      width: 7px;
      height: 7px;
      border-radius: 50%;
      background: #059669;
      animation: daily-bonus-chip-pulse 2s ease-in-out infinite;
    }
    @keyframes daily-bonus-chip-pulse {
      50% { opacity: 0.35; }
    }
    @media (prefers-reduced-motion: reduce) {
      .daily-bonus-chip-dot { animation: none; }
      /* The dissolve still appears and disappears -- it just does so with the
         scroll rather than easing in behind it. */
      .app-topbar,
      .nav-scrim,
      .daily-bonus-float,
      .daily-bonus-float::after,
      .ledger-scrim {
        transition: none;
      }
    }
    /* Empty catalog: Start Run becomes a quiet "Add casinos" link-button. */
    .daily-run-button.is-add-casinos {
      background: #ffffff;
      color: var(--button);
      border: 1px solid var(--line);
      box-shadow: none;
    }
    .daily-run-button.is-add-casinos .ct-symbol {
      display: none;
    }
    .daily-bonus-stats {
      display: grid;
      grid-template-columns: repeat(3, minmax(0, 1fr));
      gap: 16px;
      border-top: 1px solid var(--line);
      padding-top: 16px;
    }
    .daily-bonus-stats span {
      min-width: 0;
      padding: 0;
    }
    .daily-bonus-stats b,
    .daily-bonus-stats small {
      display: block;
    }
    /* Structure role, same as `th`: these head the three columns of the stat
       readout, they are not captions attached to one value. What made them
       fight the numbers was the 600 weight, not the caps -- 500 settles it
       while the value stays larger, darker and monospaced. */
    .daily-bonus-stats small {
      color: var(--muted);
      font-size: var(--type-label-caps);
      font-weight: 500;
      letter-spacing: 0.06em;
      text-transform: uppercase;
      white-space: nowrap;
    }
    .daily-bonus-stats b {
      margin-top: 5px;
      color: var(--ink);
      font-size: var(--type-mono);
      font-weight: 500;
      font-variant-numeric: tabular-nums;
      white-space: nowrap;
    }
    .daily-bonus-stats .stat-unit {
      color: var(--muted);
      font-size: var(--type-mono-sm);
      font-weight: 700;
    }
    #daily-bonus-net-profit {
      display: flex;
      align-items: baseline;
      gap: 4px;
    }
    #daily-bonus-net-profit.is-positive {
      color: var(--good);
    }
    #daily-bonus-net-profit.is-negative {
      color: var(--danger);
    }
    #daily-bonus-net-profit.is-neutral {
      color: var(--muted);
    }
    #daily-bonus-net-profit .net-profit-arrow {
      flex: 0 0 auto;
      align-self: center;
    }
    .net-profit-arrow-icon {
      font-size: 0.9rem !important;
    }
    /* Narrow cards flip the stats from columns to label/value rows, keyed to
       the card's own width (the feed column is the container), not the
       viewport. Rows cannot wrap, so the third stat can never collide with
       the card padding. Threshold: 3 columns hold down to a 480px card (the
       shortened labels fit); only genuinely narrow cards get the row layout.
       (Kept in sync with action-dashboard.css — the dashboard loads both.) */
    .dashboard-feed {
      container-type: inline-size;
    }
    @container (max-width: 479px) {
      .daily-bonus-command-copy h2 {
        font-size: var(--type-body-lg);
      }
      /* Stack the header: title + chip, then a full-width Start button. On a
         narrow card the title and button can no longer share a row without
         crowding, so the button gets its own — a designed state, not a wrap. */
      .daily-bonus-command-header {
        grid-template-columns: 1fr;
      }
      .daily-run-button {
        justify-content: center;
        width: 100%;
      }
      .daily-bonus-stats {
        grid-template-columns: 1fr;
        gap: 0;
        padding-top: 6px;
      }
      /* Direct children only: the value markup nests its own spans (the SC
         unit, the profit arrow) that must stay inline. */
      .daily-bonus-stats > span {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 12px;
        padding: 9px 0;
        border-bottom: 1px solid var(--panel-soft);
      }
      .daily-bonus-stats > span:last-child {
        border-bottom: 0;
        padding-bottom: 0;
      }
      .daily-bonus-stats b {
        margin-top: 0;
        font-size: var(--type-mono);
      }
    }
    .empty-state {
      padding: 44px 24px;
      text-align: left;
    }
    .empty-state.compact {
      padding: 20px 16px;
      text-align: center;
      font-size: var(--type-body-sm);
    }
    .empty-state-label {
      display: inline-flex;
      border-radius: 999px;
      background: #dcfce7;
      color: #047857;
      padding: 4px 10px;
      font-size: var(--type-label-caps);
      font-weight: 600;
      text-transform: uppercase;
    }
    .empty-state h3 {
      margin-top: 12px;
      font-size: var(--type-body-lg);
    }
    .utility-rail {
      display: grid;
      gap: 16px;
      min-width: 0;
      position: sticky;
      top: 72px;
      /* Above .nav-scrim (9), like the Daily Bonus card: the rail pins below
         the bar with nothing behind it, so the nav's fade must stop at its
         top edge instead of washing over the first panel. */
      z-index: 10;
    }
    .next-collections-list {
      display: grid;
      gap: 0;
    }
    .next-collection-row {
      display: grid;
      grid-template-columns: minmax(0, 1fr) auto;
      gap: 12px;
      align-items: baseline;
      padding: 13px 16px;
      border-bottom: 1px solid var(--line);
    }
    .next-collection-row:last-child {
      border-bottom: 0;
    }
    .next-collection-name {
      overflow: hidden;
      font-size: var(--type-body-sm);
      font-weight: 500;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    .next-collection-meta {
      margin-top: 3px;
      color: var(--muted);
      font-size: var(--type-label-caps);
    }
    .next-collection-time {
      font-size: var(--type-mono-sm);
      font-weight: 500;
    }
    .pending-table {
      min-width: 0;
    }
    .pending-table th,
    .pending-table td {
      padding: 11px 12px;
    }
    .pending-table th {
      background: var(--bg);
      letter-spacing: 0.05em;
    }
    .material-symbols-rounded,
    .material-symbols-outlined,
    .material-icons,
    .ct-symbol {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      width: 1.15rem;
      height: 1.15rem;
      overflow: hidden;
      font-family: "Material Symbols Rounded";
      font-size: 1.15rem !important;
      font-style: normal;
      font-weight: normal;
      line-height: 1;
      letter-spacing: 0;
      text-transform: none;
      white-space: nowrap;
      direction: ltr;
      font-feature-settings: "liga";
      -webkit-font-feature-settings: "liga";
      -webkit-font-smoothing: antialiased;
      font-variation-settings: "FILL" 0, "wght" 500, "GRAD" 0, "opsz" 24;
    }
    .material-symbols-outlined {
      font-family: "Material Symbols Outlined";
    }
    .material-icons {
      font-family: "Material Icons";
    }
    .nav-item.is-active .ct-symbol {
      font-variation-settings: "FILL" 1, "wght" 500, "GRAD" 0, "opsz" 24;
    }
    .action-feed {
      display: grid;
      gap: 16px;
      padding: 18px;
    }
    .action-section {
      display: grid;
      gap: 12px;
      min-width: 0;
    }
    .action-section-header {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 12px;
      border-bottom: 1px solid var(--line);
      padding-bottom: 8px;
    }
    /* Structure role: uppercase marks a boundary (section divider, column
       header). 500 is enough to hold caps together in grey -- 600 made these
       compete with the content they introduce. */
    .action-section-header h3 {
      color: var(--muted);
      font-size: var(--type-label-caps);
      font-weight: 500;
      letter-spacing: 0.06em;
      text-transform: uppercase;
    }
    .action-section-count {
      display: inline-flex;
      min-width: 26px;
      min-height: 24px;
      align-items: center;
      justify-content: center;
      border: 1px solid var(--line);
      border-radius: 999px;
      background: #ffffff;
      color: var(--muted);
      font-family: var(--font-mono);
      font-size: var(--type-mono-sm);
      font-weight: 700;
    }
    .actions-grid {
      display: grid;
      grid-template-columns: 1fr;
      gap: 14px;
      padding: 0;
    }
    .ct-action-card,
    .ct-bundle {
      position: relative;
      display: grid;
      grid-template-columns: auto minmax(0, 1fr) auto;
      gap: 14px;
      align-items: start;
      border: 1px solid var(--line);
      border-left-width: 6px;
      border-radius: 12px;
      background: #ffffff;
      padding: 14px;
      box-shadow: 0 8px 20px rgba(15, 23, 42, 0.04);
      transition: transform 0.2s, box-shadow 0.2s, opacity 0.35s ease, max-height 0.35s ease, margin 0.35s ease, padding 0.35s ease, border 0.35s ease;
    }
    .ct-action-card:hover,
    .ct-bundle:hover {
      transform: translateY(-1px);
      box-shadow: 0 14px 28px rgba(15, 23, 42, 0.07);
    }
    .ct-action-card.redeem_now,
    .ct-bundle-redeem {
      border-left-color: var(--good);
      background: #f8fffb;
    }
    .ct-action-card.daily_bonus_ready,
    .ct-bundle-daily_bonus {
      border-color: #ddd6fe;
      border-left-color: #7c3aed;
      background: #f7f3ff;
    }
    .ct-action-card.play_through_first,
    .ct-bundle-playthrough,
    .ct-action-card.wager_in_progress,
    .ct-bundle-wager_progress {
      border-color: #bfdbfe;
      border-left-color: #2563eb;
      background: #eff6ff;
    }
    .ct-action-card.purchase_needed,
    .ct-action-card.expiration_reminder,
    .ct-action-card.expiration_redeem,
    .ct-bundle-expiration {
      border-color: #fecdd3;
      border-left-color: #e11d48;
      background: #fff1f2;
    }
    .ct-action-icon {
      display: grid;
      width: 36px;
      height: 36px;
      place-items: center;
      border: 1px solid var(--line);
      border-radius: 12px;
      background: #ffffff;
      color: var(--button);
      box-shadow: 0 6px 14px rgba(15, 23, 42, 0.04);
    }
    .ct-action-body,
    .ct-bundle-body {
      min-width: 0;
    }
    .ct-action-label-row {
      display: flex;
      align-items: center;
      gap: 8px;
      flex-wrap: wrap;
      margin-bottom: 6px;
    }
    .ct-action-badge,
    .card-badge {
      display: inline-flex;
      align-items: center;
      border-radius: 999px;
      border: 1px solid var(--line);
      background: #ccfbf1;
      color: var(--button);
      padding: 3px 9px;
      font-size: var(--type-label-caps);
      font-weight: 600;
      line-height: 1.2;
      text-transform: uppercase;
    }
    .ct-action-card.daily_bonus_ready .ct-action-badge,
    .ct-bundle-daily_bonus .ct-action-badge {
      border-color: #c4b5fd;
      background: #ede9fe;
      color: #5b21b6;
    }
    .ct-action-card.redeem_now .ct-action-badge,
    .ct-bundle-redeem .ct-action-badge {
      border-color: #a7f3d0;
      background: #d1fae5;
      color: #047857;
    }
    .ct-action-card.play_through_first .ct-action-badge,
    .ct-action-card.wager_in_progress .ct-action-badge,
    .ct-bundle-playthrough .ct-action-badge,
    .ct-bundle-wager_progress .ct-action-badge {
      border-color: #bfdbfe;
      background: #dbeafe;
      color: #1d4ed8;
    }
    .ct-action-card.purchase_needed .ct-action-badge,
    .ct-action-card.expiration_reminder .ct-action-badge,
    .ct-action-card.expiration_redeem .ct-action-badge,
    .ct-bundle-expiration .ct-action-badge {
      border-color: #fda4af;
      background: #ffe4e6;
      color: #be123c;
    }
    .ct-action-kicker {
      color: var(--muted);
      font-size: var(--type-label-caps);
      font-weight: 400;
    }
    .ct-action-title,
    .card-title {
      margin: 0;
      color: var(--ink);
      font-size: var(--type-body-md);
      font-weight: 600;
      line-height: 1.2;
    }
    .ct-action-summary,
    .card-desc {
      margin: 5px 0 0;
      color: var(--ink);
      font-size: var(--type-body-sm);
      font-weight: 400;
      line-height: 1.4;
    }
    .ct-action-meta {
      display: flex;
      gap: 8px;
      flex-wrap: wrap;
      margin-top: 12px;
      color: var(--muted);
    }
    /* Duplicated from action-dashboard.css on purpose -- see the note on
       .ct-bundle-row-goto. */
    .ct-action-goto {
      display: flex;
      align-items: flex-start;
      gap: 6px;
      margin: 8px 0 0;
      color: var(--muted);
      font-size: var(--type-body-sm);
      line-height: 1.35;
    }
    .ct-action-goto strong {
      color: var(--ink);
      font-weight: 600;
    }
    .ct-action-goto .ct-symbol {
      flex: 0 0 auto;
      width: 17px;
      height: 17px;
      margin-top: 1px;
      color: #2563eb;
      font-size: 17px !important;
    }
    .ct-action-metric {
      display: inline-grid;
      gap: 2px;
      min-width: 92px;
      border: 1px solid var(--line);
      border-radius: 8px;
      background: rgba(255, 255, 255, 0.7);
      padding: 7px 9px;
      font-size: var(--type-label-caps);
    }
    .ct-action-metric > span {
      color: var(--muted);
      font-weight: 400;
    }
    .ct-action-metric > strong {
      color: var(--ink);
      font-family: var(--font-mono);
      font-size: var(--type-mono-sm);
      font-weight: 700;
      line-height: 1.25;
    }
    .ct-action-metric.is-warning > strong {
      color: var(--warning);
    }
    .ct-action-why {
      margin: 10px 0 0;
      color: var(--muted);
      font-size: var(--type-body-sm);
      font-style: italic;
      line-height: 1.4;
    }
    .ct-action-controls {
      display: flex;
      gap: 8px;
      flex-wrap: wrap;
      margin-top: 12px;
    }
    .ct-action-button {
      gap: 6px;
      min-height: 34px;
      padding: 0 11px;
      font-size: var(--type-label-caps);
      text-decoration: none;
    }
    .ct-action-button-success {
      background: var(--good);
    }
    .ct-action-card.daily_bonus_ready .primary-button,
    .ct-bundle-daily_bonus .primary-button {
      background: #6d28d9;
    }
    .ct-action-card.daily_bonus_ready .primary-button:hover,
    .ct-bundle-daily_bonus .primary-button:hover {
      background: #5b21b6;
    }
    .ct-action-card.daily_bonus_ready .secondary-button,
    .ct-bundle-daily_bonus .secondary-button {
      border: 1px solid #c4b5fd;
      background: rgba(255, 255, 255, 0.72);
      color: #5b21b6;
    }
    .ct-action-card.redeem_now .primary-button,
    .ct-bundle-redeem .primary-button {
      background: #047857;
    }
    .ct-action-card.redeem_now .primary-button:hover,
    .ct-bundle-redeem .primary-button:hover {
      background: #065f46;
    }
    .ct-action-card.purchase_needed .primary-button,
    .ct-action-card.expiration_reminder .primary-button,
    .ct-action-card.expiration_redeem .primary-button,
    .ct-bundle-expiration .primary-button {
      background: #e11d48;
    }
    .ct-action-card.purchase_needed .primary-button:hover,
    .ct-action-card.expiration_reminder .primary-button:hover,
    .ct-action-card.expiration_redeem .primary-button:hover,
    .ct-bundle-expiration .primary-button:hover {
      background: #be123c;
    }
    .ct-action-card.play_through_first .secondary-button,
    .ct-action-card.wager_in_progress .secondary-button,
    .ct-bundle-playthrough .secondary-button,
    .ct-bundle-wager_progress .secondary-button {
      border: 1px solid #bfdbfe;
      background: rgba(255, 255, 255, 0.72);
      color: #1d4ed8;
    }
    .ct-action-card.purchase_needed .secondary-button,
    .ct-action-card.expiration_reminder .secondary-button,
    .ct-action-card.expiration_redeem .secondary-button,
    .ct-bundle-expiration .secondary-button {
      border: 1px solid #fecdd3;
      background: rgba(255, 255, 255, 0.72);
      color: #881337;
    }
    .ct-bundle {
      align-items: center;
      cursor: pointer;
    }
    .ct-bundle-end {
      display: flex;
      align-items: center;
      justify-content: flex-end;
      gap: 8px;
    }
    .ct-bundle-controls {
      margin-top: 0;
    }
    .ct-bundle-toggle {
      color: var(--muted);
    }
    .ct-bundle-children {
      margin-top: 12px;
      border-left: 1px solid var(--line);
      padding-left: 16px;
    }
    .ct-bundle-row {
      position: relative;
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 14px;
      min-width: 0;
      border: 1px solid rgba(118, 119, 125, 0.22);
      border-radius: 12px;
      background: #ffffff;
      padding: 12px;
      box-shadow: 0 6px 14px rgba(15, 23, 42, 0.04);
    }
    .ct-bundle-row::before {
      content: "";
      position: absolute;
      left: -17px;
      top: 50%;
      width: 16px;
      border-top: 1px solid var(--line);
    }
    .ct-bundle-row-main {
      display: flex;
      align-items: center;
      gap: 12px;
      min-width: 0;
    }
    .ct-bundle-row-icon {
      display: grid;
      width: 32px;
      height: 32px;
      place-items: center;
      flex: 0 0 auto;
      border-radius: 8px;
      background: #ecfdf5;
      color: var(--good);
    }
    .ct-bundle-row h4 {
      margin: 0;
      color: var(--ink);
      font-size: var(--type-body-sm);
      font-weight: 700;
      line-height: 1.2;
    }
    .ct-bundle-row p {
      margin: 2px 0 0;
      color: var(--muted);
      font-size: var(--type-label-caps);
      line-height: 1.35;
    }
    /* Duplicated from action-dashboard.css on purpose — the two stylesheets carry
       the same bundle-row rules and drift if only one is edited. */
    .ct-bundle-row-goto {
      display: flex;
      /* Wraps rather than truncating -- see the note in action-dashboard.css. */
      align-items: flex-start;
      gap: 5px;
      margin: 3px 0 0;
      min-width: 0;
    }
    .ct-bundle-row-goto strong {
      color: var(--ink);
      font-weight: 600;
    }
    .ct-bundle-row-goto .ct-symbol {
      flex: 0 0 auto;
      width: 15px;
      height: 15px;
      margin-top: 1px;
      color: #2563eb;
      font-size: 15px !important;
    }
    .ct-bundle-row-actions {
      display: flex;
      align-items: center;
      justify-content: flex-end;
      gap: 7px;
      flex-wrap: wrap;
    }
    .ct-bundle-row .ct-action-button {
      min-height: 30px;
      padding: 0 10px;
      font-size: var(--type-label-caps);
    }
    .ct-bundle-row-daily_bonus .ct-bundle-row-icon {
      background: #ede9fe;
      color: #7c3aed;
    }
    .ct-bundle-row-daily_bonus::before,
    .ct-bundle-daily_bonus + .ct-bundle-children .ct-bundle-row::before {
      border-color: #c4b5fd;
    }
    .ct-bundle-row-expiration .ct-bundle-row-icon {
      background: #ffe4e6;
      color: #e11d48;
    }
    .ct-bundle-row-playthrough .ct-bundle-row-icon,
    .ct-bundle-row-wager_progress .ct-bundle-row-icon {
      background: #dbeafe;
      color: #2563eb;
    }
    .ct-bundle-more {
      align-self: center;
      width: fit-content;
      border-radius: 999px;
      color: #5b21b6;
      font-size: var(--type-label-caps);
      font-weight: 600;
      text-transform: uppercase;
    }
    .pending-casino {
      font-weight: 700;
    }
    .pending-requested {
      margin-top: 3px;
      color: var(--muted);
      font-size: var(--type-label-caps);
    }
    .expected-date {
      font-weight: 700;
      white-space: nowrap;
    }
    .expected-helper {
      margin-top: 3px;
      font-size: var(--type-label-caps);
      display: inline-flex;
      align-items: center;
      gap: 4px;
    }
    /* The community mark. Muted and small on purpose: it says where the range
       came from, it is not a status, and a personal range carries no mark at
       all -- marking the norm is what would make this column noisy. */
    .expected-source {
      display: inline-flex;
      flex: none;
      color: var(--muted);
    }
    .expected-source .ct-symbol {
      font-size: 14px;
      line-height: 1;
    }
    @media (max-width: 1080px) {
      .dashboard-layout {
        grid-template-columns: 1fr;
      }
      .utility-rail {
        display: grid;
        position: static;
      }
      .topbar-quick > .quick-action {
        flex: 0 1 auto;
      }
    }
    @media (max-width: 760px) {
      /* Nothing is pinned at this width -- the bar goes static and the Daily
         Bonus card returns to the flow -- so there is nothing to dissolve.
         Left in, the nav scrim would pin to the viewport on its own and drag
         a grey band down the page. */
      .nav-scrim,
      .daily-bonus-float::after {
        display: none;
      }
      .app-sidebar {
        display: none;
      }
      .mobile-bottom-nav {
        position: fixed;
        inset: auto 0 0 0;
        z-index: 25;
        display: grid;
        grid-template-columns: repeat(5, minmax(0, 1fr));
        border-top: 1px solid var(--line);
        background: #ffffff;
        box-shadow: 0 -12px 30px rgba(15, 23, 42, 0.08);
      }
      .mobile-bottom-nav a {
        display: grid;
        gap: 3px;
        min-height: 58px;
        place-items: center;
        padding: 0 4px;
        font-size: var(--type-label-caps);
      }
      .mobile-bottom-nav .ct-symbol {
        font-size: 1.25rem;
      }
      .mobile-bottom-nav a.is-active {
        color: var(--button);
      }
      .app-main,
      html.sidebar-collapsed .app-main,
      body.sidebar-collapsed .app-main {
        margin-left: 0;
        padding: 16px 16px 84px;
      }
      .app-topbar {
        position: relative;
        margin: -16px -16px 8px;
        padding: 16px;
        display: grid;
        grid-template-columns: 1fr auto;
        grid-template-areas:
          "title utility"
          "quick quick";
        align-items: center;
        column-gap: 12px;
        row-gap: 14px;
      }
      .sidebar-toggle {
        display: none;
      }
      .topbar-title {
        grid-area: title;
        min-width: 0;
      }
      /* Hoist the two action groups into the app-topbar grid so the utility
         icons ride on the title row (top-right) and the Purchase/Wager/Redeem
         quick actions take a single full-width row below -- no toggle, no
         overlay. */
      .topbar-actions {
        display: contents;
      }
      .topbar-utility {
        grid-area: utility;
        display: flex;
        align-items: center;
        justify-content: flex-end;
        gap: 6px;
      }
      /* Make the three utility icons one consistent set: identical 40x40
         borderless tap targets, same glyph size, all flex-centered. Without
         this the feedback button keeps its desktop pill border and the bell
         button renders inline-block -- baseline-aligning its glyph ~3px high. */
      .topbar-utility > .feedback-button,
      .topbar-utility > .account-menu-trigger,
      .topbar-utility .bell-container,
      .topbar-utility .bell-button {
        width: 40px;
        height: 40px;
        min-width: 40px;
        min-height: 40px;
        padding: 0;
        border: 0;
        background: transparent;
        border-radius: 12px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
      }
      .topbar-utility .ct-symbol {
        font-size: 1.25rem !important;
      }
      /* The dropdown is a fixed 320px anchored to the bell's own right edge,
         which sits ~58px in from the screen edge -- so on a narrow phone its
         left side ran off the viewport and the alert text was unreadable.
         Anchor it to the utility row instead (whose right edge is the page's
         own padding) and let it shrink to fit. */
      .topbar-utility {
        position: relative;
      }
      .topbar-utility .bell-container {
        position: static;
      }
      .bell-dropdown {
        width: min(320px, calc(100vw - 32px));
        max-height: min(400px, 60vh);
      }
      /* Under 760px the account menu is a bottom sheet. It is a sibling of
         .app-main (see base.html), so its z-index: 40 really does clear the
         bottom nav's 25 -- nested in the bar's z-index: 15 it never could. */
      .account-menu-panel {
        inset: auto 0 0 0;
        top: auto !important;
        right: 0 !important;
        width: auto;
        max-height: calc(100vh - 48px);
        max-height: calc(100dvh - 48px);
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
        padding: 0 0 calc(12px + env(safe-area-inset-bottom, 0px));
        border-radius: 16px 16px 0 0;
        border-bottom: 0;
        box-shadow: 0 -12px 30px rgba(15, 23, 42, 0.18);
      }
      .account-menu-sheet-head {
        position: sticky;
        top: 0;
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 10px 8px 10px 16px;
        margin-bottom: 6px;
        border-bottom: 1px solid var(--line);
        background: var(--panel);
      }
      .account-menu-sheet-title {
        font-size: var(--type-body-md);
        font-weight: 600;
      }
      .account-menu-close {
        border: 0;
        background: transparent;
        color: var(--muted);
        cursor: pointer;
      }
      .account-menu-item {
        min-height: 48px;
        padding: 0 16px;
      }
      /* Body scroll lock while the sheet is open; account-menu.js adds and
         removes the class on <html> from its one close routine, so the lock
         releases however the sheet was closed. */
      html.account-menu-open,
      html.account-menu-open body {
        overflow: hidden;
      }
      .topbar-quick {
        grid-area: quick;
        display: grid;
        grid-template-columns: repeat(3, minmax(0, 1fr));
        gap: 8px;
        width: 100%;
      }
      .topbar-quick > .quick-action {
        min-width: 0;
        width: 100%;
        justify-content: center;
        gap: 6px;
        padding: 0 8px;
        /* Up, not down: the desktop pill is 34px, which is below the minimum
           comfortable touch target. These are the primary actions on a phone. */
        min-height: 44px;
      }
      /* Icon-only (the label is hidden at every width now); this keeps the
         square 40px tap target it shares with the other utility icons. */
      .feedback-button {
        padding: 0;
        width: 40px;
        justify-content: center;
      }
      .dashboard-layout {
        grid-template-columns: 1fr;
      }
      /* Stat layout below this width is owned by the card's container query
         (columns → label/value rows); only the frame changes here. */
      .daily-bonus-float {
        position: relative;
        top: auto;
        padding: 18px;
      }
      .action-feed {
        padding: 12px;
      }
      .panel-header {
        align-items: flex-start;
        flex-direction: column;
      }
      .ct-action-card,
      .ct-bundle {
        grid-template-columns: 1fr;
        gap: 12px;
        padding: 14px;
      }
      .ct-action-icon {
        width: 38px;
        height: 38px;
      }
      .dismiss-card-btn {
        position: absolute;
        top: 10px;
        right: 10px;
      }
      .ct-bundle-end {
        justify-content: flex-start;
      }
      .ct-bundle-row {
        align-items: stretch;
        flex-direction: column;
      }
      .ct-bundle-row-actions {
        justify-content: flex-start;
      }
      .ct-action-controls {
        align-items: stretch;
        flex-direction: column;
      }
      .ct-action-button,
      .ct-action-controls .button-link {
        justify-content: center;
        min-width: 0;
        min-height: 44px;
        overflow-wrap: anywhere;
        padding-block: 8px;
        text-align: center;
        white-space: normal;
        width: 100%;
      }
      .ct-action-title,
      .ct-action-summary,
      .ct-action-why,
      .ct-bundle-row h4,
      .ct-bundle-row p {
        overflow-wrap: anywhere;
      }
      .pending-table {
        min-width: 560px;
      }
    }

    /* Resizable ledger columns (shared across casinos, transactions, wagers).
       Kept entirely inside the th's own box (not straddling the column
       border) because adjacent <th> cells are each `position: sticky` with
       their own z-index, which makes a later (rightward) sibling's stacking
       context always paint over anything overflowing from an earlier one -
       a handle centered on the border would have its right half unclickable. */
    .col-resizer {
      position: absolute;
      top: 0;
      right: 0;
      width: 12px;
      height: 100%;
      cursor: col-resize;
      touch-action: none;
      user-select: none;
      z-index: 2;
    }
    /* A full-height divider sits on every resizable column edge and is always
       visible, so the columns read as a grid you can obviously grab - no
       hunting for an invisible hit zone. It turns teal and thickens on hover /
       while dragging. */
    .col-resizer::after {
      content: "";
      position: absolute;
      top: 0;
      right: 0;
      width: 2px;
      height: 100%;
      background: rgba(110, 121, 119, 0.55);
      transition: background 0.15s ease, width 0.15s ease;
    }
    .col-resizer:hover::after,
    .col-resizer.is-dragging::after {
      width: 3px;
      background: var(--button, #0f766e);
    }
    body.is-col-resizing {
      cursor: col-resize;
      user-select: none;
    }

    /* Shared confirmation dialog — DESIGN.md "Quiet Precision".
       Dialogs: 20px radius, Level-2 tonal elevation, heading/body type tokens,
       24px (gutter) padding, 10px buttons, semantic colors for the action.
       Markup: partials/confirm_dialog.html · behavior: static/js/confirm-dialog.js */
    .confirm-dialog {
      width: min(440px, calc(100% - 32px));
      padding: 0;
      border: 1px solid var(--line);
      border-radius: 20px;
      background: var(--panel);
      color: var(--ink);
      box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04), 0 8px 24px rgba(15, 23, 42, 0.08);
      overflow: hidden;
    }
    .confirm-dialog:not([open]) {
      display: none;
    }
    .confirm-dialog::backdrop {
      background: rgba(15, 23, 42, 0.32);
    }
    /* Subtle entrance — no bounce, 200ms on the standard easing curve. */
    .confirm-dialog[open] {
      animation: confirm-dialog-in 200ms cubic-bezier(0.2, 0.8, 0.2, 1);
    }
    @keyframes confirm-dialog-in {
      from { opacity: 0; transform: translateY(8px) scale(0.98); }
      to { opacity: 1; transform: translateY(0) scale(1); }
    }
    @media (prefers-reduced-motion: reduce) {
      .confirm-dialog[open] { animation: none; }
    }
    .confirm-dialog__body {
      padding: 24px;
    }
    .confirm-dialog__title {
      margin: 0 0 8px;
      font-family: var(--font-heading);
      font-size: var(--type-body-lg);
      font-weight: 600;
      line-height: 1.25;
      letter-spacing: -0.01em;
      color: var(--ink);
    }
    .confirm-dialog__message {
      margin: 0 0 24px;
      font-family: var(--font-ui);
      font-size: var(--type-body-md);
      line-height: 1.5;
      color: var(--muted);
      /* Preserve line breaks so multi-line / bulleted messages render. */
      white-space: pre-line;
    }
    .confirm-dialog__actions {
      display: flex;
      justify-content: flex-end;
      gap: 8px;
    }
    .confirm-dialog__btn {
      min-height: 40px;
      padding: 0 16px;
      border: 1px solid transparent;
      border-radius: 10px;
      font-family: var(--font-ui);
      font-size: var(--type-body-sm);
      font-weight: 600;
      cursor: pointer;
      transition: background-color 160ms cubic-bezier(0.2, 0.8, 0.2, 1),
        border-color 160ms cubic-bezier(0.2, 0.8, 0.2, 1),
        color 160ms cubic-bezier(0.2, 0.8, 0.2, 1);
    }
    .confirm-dialog__btn:focus-visible {
      outline: 2px solid var(--focus-ring);
      outline-offset: 2px;
    }
    /* Secondary: white with a subtle border. */
    .confirm-dialog__btn--secondary {
      background: var(--panel);
      border-color: var(--line);
      color: var(--ink);
    }
    .confirm-dialog__btn--secondary:hover {
      background: var(--panel-soft);
    }
    /* Destructive: semantic red, consistent with other delete actions in-app. */
    .confirm-dialog__btn--danger {
      background: var(--danger);
      color: #fff;
    }
    .confirm-dialog__btn--danger:hover {
      background: #be123c;
    }
    /* Primary: muted teal brand accent for non-destructive confirmations. */
    .confirm-dialog__btn--primary {
      background: var(--button);
      color: #fff;
    }
    .confirm-dialog__btn--primary:hover {
      background: var(--button-hover);
    }

    /* New-device notification permission prompt (partials/notif_permission_banner.html),
       shown only by global-notifications.js when this device is eligible.
       It is a full-bleed strip flush under the sticky topbar rather than a card:
       every page constrains its content differently (the settings column is
       760px centred, the dashboard runs full width), so a boxed banner in
       .app-main can't line up with all of them. Bleeding to the edges reads as
       app chrome and puts its content on the topbar's own left edge. */
    .notif-permission-banner {
      display: flex;
      align-items: center;
      gap: 14px;
      flex-wrap: wrap;
      /* -20px cancels .app-topbar's bottom margin (flush under the bar); the
         side margins cancel .app-main's horizontal padding (edge to edge). */
      margin: -20px calc(-1 * clamp(20px, 3vw, 40px)) 24px;
      padding: 14px clamp(20px, 3vw, 40px);
      /* The accent bar anchors the strip's leading edge, which would otherwise
         be empty tint: the content is inset to line up with the page's own
         cards, so nothing occupies the first ~40px. Its 4px comes back out of
         padding-left so that alignment survives. */
      padding-left: calc(clamp(20px, 3vw, 40px) - 4px);
      background: #eef4f3;
      border-top: 1px solid #dbe7e4;
      border-bottom: 1px solid #dbe7e4;
      border-left: 4px solid var(--button);
      animation: notif-permission-banner-in 220ms cubic-bezier(0.2, 0.8, 0.2, 1);
    }
    .notif-permission-banner__badge {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      flex: 0 0 auto;
      width: 34px;
      height: 34px;
      border-radius: 10px;
      background: var(--panel);
      border: 1px solid #dbe7e4;
      color: var(--button);
    }
    .notif-permission-banner__badge .ct-symbol {
      font-size: 1.15rem;
    }
    .notif-permission-banner__copy {
      display: grid;
      gap: 2px;
      flex: 1 1 260px;
      min-width: 0;
    }
    .notif-permission-banner__title {
      margin: 0;
      font-size: var(--type-body-sm);
      font-weight: 600;
      line-height: 1.3;
      color: var(--ink);
    }
    .notif-permission-banner__text {
      margin: 0;
      font-size: var(--type-label-caps);
      line-height: 1.35;
      color: var(--muted);
    }
    .notif-permission-banner__actions {
      display: flex;
      align-items: center;
      gap: 6px;
      flex: 0 0 auto;
      margin-left: auto;
    }
    .notif-permission-banner__enable,
    .notif-permission-banner__dismiss {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      min-height: 34px;
      padding: 0 14px;
      border: 0;
      border-radius: var(--radius-control);
      font-family: var(--font-ui);
      font-size: var(--type-label-caps);
      font-weight: 600;
      white-space: nowrap;
      cursor: pointer;
      transition: background 160ms ease, color 160ms ease;
    }
    .notif-permission-banner__enable {
      background: var(--button);
      color: #fff;
    }
    .notif-permission-banner__enable:hover {
      background: var(--button-hover);
    }
    /* Dismiss stays a quiet text button so it never competes with Enable. */
    .notif-permission-banner__dismiss {
      background: transparent;
      color: var(--muted);
    }
    .notif-permission-banner__dismiss:hover {
      background: rgba(15, 118, 110, 0.08);
      color: var(--ink);
    }
    .notif-permission-banner__enable:focus-visible,
    .notif-permission-banner__dismiss:focus-visible {
      outline: 2px solid var(--focus-ring);
      outline-offset: 2px;
    }
    @keyframes notif-permission-banner-in {
      from { opacity: 0; transform: translateY(-6px); }
      to { opacity: 1; transform: translateY(0); }
    }
    @media (prefers-reduced-motion: reduce) {
      .notif-permission-banner { animation: none; }
    }
    /* The announcement banner used to borrow this anatomy with an .is-critical
       modifier. It does not any more: announcements v2 made it an inset card
       with a chip row, an identity row and a two-line clamp, which has nothing
       left in common with a permission prompt. Its styles now live in
       static/css/announcements.css. What is left here is the permission
       banner alone, which is still the full-bleed strip it always was. */
    @media (max-width: 760px) {
      .notif-permission-banner {
        /* Mobile topbar: margin -16px -16px 8px, .app-main padding 16px. */
        margin: -8px -16px 16px;
        padding: 12px 16px;
        padding-left: 12px; /* 16px inset less the 4px accent bar */
        gap: 12px;
        row-gap: 12px;
      }
      .notif-permission-banner__actions {
        width: 100%;
        margin-left: 46px; /* line the buttons up with the copy, past the badge */
        gap: 4px;
      }
      /* Comfortable touch targets; Enable keeps its natural width so it doesn't
         balloon across the screen for a low-stakes prompt. */
      .notif-permission-banner__enable,
      .notif-permission-banner__dismiss {
        min-height: 40px;
        padding: 0 18px;
        font-size: var(--type-body-sm);
      }
    }

    /* --- Open-All launcher -------------------------------------------------
       Shown when the browser refuses to open more tabs from a single click.
       The list holds ordinary links, because a link the user clicks is its own
       gesture and no pop-up blocker touches it. */
    .open-all-launcher {
      border: none;
      border-radius: 12px;
      padding: 0;
      max-width: 460px;
      width: 90%;
      background: var(--panel, #fff);
      color: var(--ink, #1d2120);
      box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15);
    }
    .open-all-launcher::backdrop {
      background: rgba(0, 0, 0, 0.35);
    }
    .open-all-launcher-head {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 12px;
      padding: 16px 20px;
      border-bottom: 1px solid var(--line, #e2e8f0);
    }
    .open-all-launcher-head h2 {
      margin: 0;
      font-size: var(--type-body-lg);
      font-weight: 700;
    }
    .open-all-launcher-body {
      padding: 16px 20px;
    }
    .open-all-launcher-body > p {
      margin: 0 0 12px;
      font-size: var(--type-body-sm);
      line-height: 1.45;
      color: var(--muted, #475569);
    }
    .open-all-launcher-list {
      list-style: none;
      margin: 0 0 14px;
      padding: 0;
      max-height: 46vh;
      overflow-y: auto;
      border: 1px solid var(--line, #e2e8f0);
      border-radius: 8px;
    }
    .open-all-launcher-list li + li {
      border-top: 1px solid var(--line, #e2e8f0);
    }
    .open-all-launcher-list a {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 10px;
      padding: 10px 14px;
      min-height: 44px; /* touch target */
      text-decoration: none;
      color: var(--ink, #1d2120);
      font-size: var(--type-body-sm);
      font-weight: 600;
    }
    .open-all-launcher-list a:hover,
    .open-all-launcher-list a:focus-visible {
      background: var(--hover, rgba(0, 0, 0, 0.04));
    }
    /* Opened rows are marked with text and a check, never colour alone. */
    .open-all-launcher-list li.is-opened a {
      color: var(--muted, #667077);
      text-decoration: line-through;
    }
    .open-all-launcher-list li.is-opened a::after {
      content: "Opened";
      font-size: var(--type-label-caps);
      font-weight: 600;
      letter-spacing: 0.03em;
      text-transform: uppercase;
      text-decoration: none;
    }
    .open-all-launcher-help summary {
      cursor: pointer;
      font-size: var(--type-body-sm);
      font-weight: 600;
      color: var(--muted, #475569);
    }
    .open-all-launcher-help ol {
      margin: 8px 0 0;
      padding-left: 20px;
      font-size: var(--type-label-caps);
      line-height: 1.5;
      color: var(--muted, #475569);
    }
    .open-all-launcher-foot {
      display: flex;
      gap: 10px;
      justify-content: flex-end;
      padding: 0 20px 18px;
    }

/* --- The region hold panel (ACCOUNT_PAGE_IMPLEMENTATION_PLAN.md §5.4.1) -----
 *
 * Stands where the dashboard's suggestion cards and the Discover grid would
 * have been when the reader's own region is on hold. Amber, not red, and the
 * same amber the onboarding gate's `.onb-hold` and the Account page's
 * `.account-hold` use -- nothing failed and nobody did anything wrong, it is
 * news about a place. onboarding.css is not loaded by base.html pages, so the
 * handful of rules it needs live here, next to the other shared shell rules.
 */
.region-hold {
  background: var(--warning-soft);
  border: 1px solid var(--warning-border);
  border-radius: 12px;
  padding: 16px 18px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  color: var(--warning-ink);
}
.region-hold[hidden] { display: none; }
.region-hold-head { display: flex; align-items: center; gap: 9px; }
.region-hold-head .material-symbols-rounded { font-size: 20px; color: var(--warning); }
.region-hold-title {
  margin: 0;
  font-family: var(--font-heading, Inter, sans-serif);
  font-size: 1.125rem;
  font-weight: 650;
  color: var(--warning-ink);
}
.region-hold-body {
  margin: 0;
  font-size: var(--type-body-sm);
  line-height: 1.55;
  color: var(--warning-ink);
}
.region-hold-link { color: var(--warning-ink); font-weight: 650; }
