/* Import Inter Font from Google Fonts */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');


/* ============================================================================
   PALETTE - "Quiet Shell"

   ONE place where a colour is chosen, and the ONLY place a literal appears.
   Radzen, Bootstrap and every component below resolve through these tokens, so
   the dark theme further down is a pure token flip rather than a second
   stylesheet. If you find yourself adding a hex anywhere else, add a token here
   instead - that is the whole mechanism.

   The shape of the problem this replaced: four unrelated primaries were live at
   once - Radzen's coral (#FF6D41), app.css's indigo (#4F46E5), Bootstrap's blue
   (#0D6EFD) and the menus' plum (#592263) - so which accent a control got
   depended only on which library drew it.

   The rule the palette follows: colour means something. Plum is "you can act on
   this" (buttons, links, selection). Orange is "this needs you" and nothing
   else - deliberately absent from the chrome. Everything structural is a warm
   neutral: greys that share a hue with the accent read as chosen rather than
   inherited, which is why they are red-biased instead of the cool blue-greys
   Radzen and Bootstrap both ship.

   Every foreground/background pair clears WCAG AA in BOTH themes. That was not
   true before: white on Radzen's warning amber measured 1.6:1, on a screen
   showing balances and due dates.

   NAMING, because it is counter-intuitive in dark mode: "-dark" means "the
   hover/pressed direction", not literally darker. On a light ground that is a
   darker shade; on a dark ground it is a LIGHTER one. Radzen's own variables
   are named the same way and expect exactly this.
   ============================================================================ */
:root {
  /* --- Brand ------------------------------------------------------------- */
  --app-primary:        #592263;   /* plum: actions, links, selection        */
  --app-primary-rgb:    89, 34, 99;
  --app-primary-hover:  #47184F;
  --app-primary-darker: #3E1745;
  --app-primary-light:  #6E2B7B;
  --app-primary-tint:   rgba(89, 34, 99, 0.14);
  --app-primary-soft:   #EBDDEE;   /* selected nav row, selected grid row    */
  --app-primary-softer: #F2ECF3;
  --app-primary-ink:    #4A1B54;   /* text/icon ON a soft plum surface       */
  --app-on-primary:     #FFFFFF;   /* 11.4:1 on --app-primary                */
  --app-on-status:      #FFFFFF;   /* ink on a status FILL; flips in dark    */

  /* Attention. Never chrome, never decoration - only "this needs you".
     #C0431A rather than Radzen's #FF6D41 because white on that measured
     2.8:1; this is 5.2:1. */
  --app-attention:       #C0431A;
  --app-attention-hover: #A5380F;
  --app-attention-soft:  #FBEADF;
  --app-attention-ink:   #8F3212;

  /* --- Surfaces ---------------------------------------------------------- */
  --app-ground:      #F8F6F5;   /* the page behind the cards                 */
  --app-surface:     #FFFFFF;   /* cards, inputs, grid body                  */
  --app-surface-2:   #F2EFED;   /* grid headers, toolbars, inset panels      */
  --app-surface-2-rgb: 242, 239, 237;
  --app-header:      #FFFFFF;   /* the app header bar                        */
  --app-rail:        #F5F2F0;   /* the menu rails                            */
  --app-rail-ink:    #3E3639;
  --app-rail-hover:  #EBE4EC;

  /* --- Ink and rules ----------------------------------------------------- */
  --app-ink:         #2B2528;
  --app-ink-rgb:     43, 37, 40;
  --app-ink-2:       #6B615F;
  --app-ink-2-rgb:   107, 97, 95;
  --app-ink-3:       #8C8286;
  --app-rule:        #E5DFDC;
  --app-rule-strong: #D6CED1;

  /* The two ends of the neutral ramp Radzen derives from. Named separately
     because they INVERT in dark mode: "the lightest surface" becomes the
     darkest, and "the darkest ink" becomes the lightest. */
  --app-base-50:  #FFFFFF;
  --app-base-400: #D0C8C6;
  --app-base-500: #A79EA1;
  --app-base-900: #1E1A1C;

  /* Quiet Shell has no second accent hue, so a "secondary" action is neutral. */
  --app-neutral:        var(--app-ink-2);
  --app-neutral-rgb:    107, 97, 95;
  --app-neutral-dark:   #574F4D;
  --app-neutral-darker: #443E3C;
  --app-neutral-tint:   rgba(107, 97, 95, 0.16);

  /* --- Status ------------------------------------------------------------ */
  --app-success: #2E7D4F; --app-success-rgb: 46, 125, 79;
  --app-success-dark: #276B43; --app-success-light: #3E9463;
  --app-success-soft: #E3F2E8; --app-success-ink: #1F5A38;
  --app-success-tint: rgba(46, 125, 79, 0.14);

  --app-warning: #A85B00; --app-warning-rgb: 168, 91, 0;
  --app-warning-dark: #8E4D00; --app-warning-light: #C06A00;
  --app-warning-soft: #FDEEDC; --app-warning-ink: #7A4200;
  --app-warning-tint: rgba(168, 91, 0, 0.14);

  --app-danger: #B3261E; --app-danger-rgb: 179, 38, 30;
  --app-danger-dark: #9A201A; --app-danger-light: #C9332A;
  --app-danger-soft: #FBE4E2; --app-danger-ink: #8A1C16;
  --app-danger-tint: rgba(179, 38, 30, 0.14);

  --app-info: #1F6A8C; --app-info-rgb: 31, 106, 140;
  --app-info-dark: #1A5A78; --app-info-light: #2A7EA4;
  --app-info-soft: #E2EFF5; --app-info-ink: #164E67;
  --app-info-tint: rgba(31, 106, 140, 0.14);

  /* --- Duotone icon tones (see the .fa-primary / .fa-secondary rules) ----- */
  --app-icon-1:      #4A3F44;   /* content icons: quiet, warm neutral        */
  --app-icon-2:      #C7BCC2;
  --app-rail-icon-1: #7B4886;   /* rail icons: the one place colour earns it */
  --app-rail-icon-2: #C7BCC2;

  /* --- Geometry and effects ----------------------------------------------
     Two radii, not three. Controls take Radzen's 4px (which the grids and
     dropdowns already use and cannot easily be talked out of); cards take 8px.
     The 12-16px card radius this replaced read as a different product sitting
     next to a 4px dropdown. */
  --app-radius-control: 4px;
  --app-radius-card:    8px;
  --app-focus-ring:     0 0 0 3px rgba(89, 34, 99, 0.22);
  --app-shadow-card:    0 1px 2px rgba(43, 37, 40, 0.06), 0 8px 24px -16px rgba(43, 37, 40, 0.28);
  --app-shadow-hover:   0 2px 4px rgba(43, 37, 40, 0.08), 0 12px 28px -14px rgba(43, 37, 40, 0.34);
}

/* ============================================================================
   DARK THEME

   Redefines the tokens above and NOTHING else. Everything downstream - Radzen,
   Bootstrap, the menu rails, the workspace - resolves through var(), so this
   block is the entire theme.

   THREE states, not two, and the structure matters:
   - the bare :root above is the complete LIGHT palette;
   - the media query covers the default "system" setting, where the server
     stamps no attribute at all and only prefers-color-scheme separates the two.
     It is guarded :not([data-theme="light"]) so an explicit light choice still
     beats a dark OS;
   - [data-theme="dark"] repeats it so an explicit dark choice beats a light OS.

   The attribute is stamped on <html> during SSR from the icco_theme cookie, so
   the first byte of HTML already carries the right theme and there is no flash
   of the wrong one. A cookie rather than localStorage precisely because the
   server can read it; see Components/App.razor.

   The plum inverts rather than dims: #592263 on a dark ground is unreadable
   (1.4:1), so dark uses #C79BD4 at 8.1:1 and flips --app-on-primary to a dark
   ink for text sitting ON that fill.
   ============================================================================ */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --app-primary:        #C79BD4;
    --app-primary-rgb:    199, 155, 212;
    --app-primary-hover:  #D9B6E2;
    --app-primary-darker: #E4CBEB;
    --app-primary-light:  #B387C0;
    --app-primary-tint:   rgba(199, 155, 212, 0.18);
    --app-primary-soft:   #3A2A40;
    --app-primary-softer: #2B2130;
    --app-primary-ink:    #E7D3EC;
    --app-on-primary:     #2A1330;
    --app-on-status:      #1A1416;

    --app-attention:       #F0834F;
    --app-attention-hover: #FF9A6B;
    --app-attention-soft:  #3A2419;
    --app-attention-ink:   #FFC3A3;

    --app-ground:      #161415;
    --app-surface:     #1F1C1E;
    --app-surface-2:   #272325;
    --app-surface-2-rgb: 39, 35, 37;
    --app-header:      #1F1C1E;
    --app-rail:        #221E20;
    --app-rail-ink:    #D6CFD2;
    --app-rail-hover:  #2E2830;

    --app-ink:         #EAE6E7;
    --app-ink-rgb:     234, 230, 231;
    --app-ink-2:       #A9A1A4;
    --app-ink-2-rgb:   169, 161, 164;
    --app-ink-3:       #857D80;
    --app-rule:        #332E31;
    --app-rule-strong: #453E42;

    --app-base-50:  #1F1C1E;
    --app-base-400: #4A4347;
    --app-base-500: #6E6669;
    --app-base-900: #F5F1F2;

    --app-neutral:        #A9A1A4;
    --app-neutral-rgb:    169, 161, 164;
    --app-neutral-dark:   #BDB5B8;
    --app-neutral-darker: #D2CBCE;
    --app-neutral-tint:   rgba(169, 161, 164, 0.18);

    --app-success: #5FBF85; --app-success-rgb: 95, 191, 133;
    --app-success-dark: #7CCF9C; --app-success-light: #4EA972;
    --app-success-soft: #16301F; --app-success-ink: #A6E0BC;
    --app-success-tint: rgba(95, 191, 133, 0.18);

    --app-warning: #E3A551; --app-warning-rgb: 227, 165, 81;
    --app-warning-dark: #EFBA74; --app-warning-light: #C98F42;
    --app-warning-soft: #33260F; --app-warning-ink: #F0CB93;
    --app-warning-tint: rgba(227, 165, 81, 0.18);

    --app-danger: #FF8A80; --app-danger-rgb: 255, 138, 128;
    --app-danger-dark: #FFA9A1; --app-danger-light: #E0776E;
    --app-danger-soft: #3A1A18; --app-danger-ink: #FFB3AC;
    --app-danger-tint: rgba(255, 138, 128, 0.18);

    --app-info: #6BB6D8; --app-info-rgb: 107, 182, 216;
    --app-info-dark: #8CC8E3; --app-info-light: #559FC0;
    --app-info-soft: #142A33; --app-info-ink: #A9D6EA;
    --app-info-tint: rgba(107, 182, 216, 0.18);

    --app-icon-1:      #B9AFB4;
    --app-icon-2:      #5A5054;
    --app-rail-icon-1: #C79BD4;
    --app-rail-icon-2: #5F5266;

    --app-focus-ring:   0 0 0 3px rgba(199, 155, 212, 0.30);
    --app-shadow-card:  0 1px 2px rgba(0, 0, 0, 0.50), 0 8px 24px -16px rgba(0, 0, 0, 0.80);
    --app-shadow-hover: 0 2px 4px rgba(0, 0, 0, 0.55), 0 12px 28px -14px rgba(0, 0, 0, 0.85);

    color-scheme: dark;
  }
}

:root[data-theme="dark"] {
  --app-primary:        #C79BD4;
  --app-primary-rgb:    199, 155, 212;
  --app-primary-hover:  #D9B6E2;
  --app-primary-darker: #E4CBEB;
  --app-primary-light:  #B387C0;
  --app-primary-tint:   rgba(199, 155, 212, 0.18);
  --app-primary-soft:   #3A2A40;
  --app-primary-softer: #2B2130;
  --app-primary-ink:    #E7D3EC;
  --app-on-primary:     #2A1330;
  --app-on-status:      #1A1416;

  --app-attention:       #F0834F;
  --app-attention-hover: #FF9A6B;
  --app-attention-soft:  #3A2419;
  --app-attention-ink:   #FFC3A3;

  --app-ground:      #161415;
  --app-surface:     #1F1C1E;
  --app-surface-2:   #272325;
  --app-surface-2-rgb: 39, 35, 37;
  --app-header:      #1F1C1E;
  --app-rail:        #221E20;
  --app-rail-ink:    #D6CFD2;
  --app-rail-hover:  #2E2830;

  --app-ink:         #EAE6E7;
  --app-ink-rgb:     234, 230, 231;
  --app-ink-2:       #A9A1A4;
  --app-ink-2-rgb:   169, 161, 164;
  --app-ink-3:       #857D80;
  --app-rule:        #332E31;
  --app-rule-strong: #453E42;

  --app-base-50:  #1F1C1E;
  --app-base-400: #4A4347;
  --app-base-500: #6E6669;
  --app-base-900: #F5F1F2;

  --app-neutral:        #A9A1A4;
  --app-neutral-rgb:    169, 161, 164;
  --app-neutral-dark:   #BDB5B8;
  --app-neutral-darker: #D2CBCE;
  --app-neutral-tint:   rgba(169, 161, 164, 0.18);

  --app-success: #5FBF85; --app-success-rgb: 95, 191, 133;
  --app-success-dark: #7CCF9C; --app-success-light: #4EA972;
  --app-success-soft: #16301F; --app-success-ink: #A6E0BC;
  --app-success-tint: rgba(95, 191, 133, 0.18);

  --app-warning: #E3A551; --app-warning-rgb: 227, 165, 81;
  --app-warning-dark: #EFBA74; --app-warning-light: #C98F42;
  --app-warning-soft: #33260F; --app-warning-ink: #F0CB93;
  --app-warning-tint: rgba(227, 165, 81, 0.18);

  --app-danger: #FF8A80; --app-danger-rgb: 255, 138, 128;
  --app-danger-dark: #FFA9A1; --app-danger-light: #E0776E;
  --app-danger-soft: #3A1A18; --app-danger-ink: #FFB3AC;
  --app-danger-tint: rgba(255, 138, 128, 0.18);

  --app-info: #6BB6D8; --app-info-rgb: 107, 182, 216;
  --app-info-dark: #8CC8E3; --app-info-light: #559FC0;
  --app-info-soft: #142A33; --app-info-ink: #A9D6EA;
  --app-info-tint: rgba(107, 182, 216, 0.18);

  --app-icon-1:      #B9AFB4;
  --app-icon-2:      #5A5054;
  --app-rail-icon-1: #C79BD4;
  --app-rail-icon-2: #5F5266;

  --app-focus-ring:   0 0 0 3px rgba(199, 155, 212, 0.30);
  --app-shadow-card:  0 1px 2px rgba(0, 0, 0, 0.50), 0 8px 24px -16px rgba(0, 0, 0, 0.80);
  --app-shadow-hover: 0 2px 4px rgba(0, 0, 0, 0.55), 0 12px 28px -14px rgba(0, 0, 0, 0.85);

  color-scheme: dark;
}

/* ============================================================================
   LIBRARY REMAP - Radzen and Bootstrap both read from the palette above.

   Override the variables; NEVER fork Radzen's theme file. Every value here is a
   variable the shipped theme already defines, so an upgrade re-supplies its own
   defaults and these keep winning. Every value is a var() reference, which is
   what makes the dark block above sufficient on its own.

   Two things about Radzen worth knowing before editing this:
   - The -dark / -light / -lighter derivatives are LITERALS in the theme, not
     computed from --rz-primary. Overriding only --rz-primary leaves coral on
     every hover and every translucent tint.
   - --rz-link-color resolves to var(--rz-secondary), not the primary. Secondary
     is remapped to a neutral here (a secondary ACTION should be quiet), so the
     link colour is pointed at the primary explicitly below. Miss that and every
     link in the app turns grey.
   ============================================================================ */
:root {
  /* --- Radzen: primary = plum ------------------------------------------- */
  --rz-primary:          var(--app-primary);
  --rz-primary-dark:     var(--app-primary-hover);
  --rz-primary-darker:   var(--app-primary-darker);
  --rz-primary-light:    var(--app-primary-light);
  --rz-primary-lighter:  var(--app-primary-tint);
  --rz-on-primary:         var(--app-on-primary);
  --rz-on-primary-dark:    var(--app-on-primary);
  --rz-on-primary-darker:  var(--app-on-primary);
  --rz-on-primary-light:   var(--app-on-primary);
  --rz-on-primary-lighter: var(--app-primary);

  /* --- Radzen: secondary = neutral -------------------------------------- */
  --rz-secondary:         var(--app-neutral);
  --rz-secondary-dark:    var(--app-neutral-dark);
  --rz-secondary-darker:  var(--app-neutral-darker);
  --rz-secondary-light:   var(--app-ink-3);
  --rz-secondary-lighter: var(--app-neutral-tint);

  /* Links follow the ACTION colour, not the neutral secondary. */
  --rz-link-color:       var(--app-primary);
  --rz-link-hover-color: var(--app-primary-hover);

  /* --- Radzen: status ---------------------------------------------------- */
  --rz-success:         var(--app-success);
  --rz-success-dark:    var(--app-success-dark);
  --rz-success-darker:  var(--app-success-ink);
  --rz-success-light:   var(--app-success-light);
  --rz-success-lighter: var(--app-success-tint);
  --rz-warning:         var(--app-warning);
  --rz-warning-dark:    var(--app-warning-dark);
  --rz-warning-darker:  var(--app-warning-ink);
  --rz-warning-light:   var(--app-warning-light);
  --rz-warning-lighter: var(--app-warning-tint);
  --rz-danger:          var(--app-danger);
  --rz-danger-dark:     var(--app-danger-dark);
  --rz-danger-darker:   var(--app-danger-ink);
  --rz-danger-light:    var(--app-danger-light);
  --rz-danger-lighter:  var(--app-danger-tint);
  --rz-info:            var(--app-info);
  --rz-info-dark:       var(--app-info-dark);
  --rz-info-darker:     var(--app-info-ink);
  --rz-info-light:      var(--app-info-light);
  --rz-info-lighter:    var(--app-info-tint);

  /* --- Radzen: the neutral ramp -----------------------------------------
     Radzen ships a COOL blue-grey ramp (#F6F7FA .. #28363C). Restated warm so
     the greys belong to the plum. The ramp drives more than it looks:
     --rz-body-background-color is base-100, --rz-text-color is base-800, and
     every border is a base-* step - which is also why the ramp INVERTS in dark
     mode rather than merely darkening. */
  --rz-base-50:  var(--app-base-50);
  --rz-base-100: var(--app-ground);
  --rz-base-200: var(--app-surface-2);
  --rz-base-300: var(--app-rule);
  --rz-base-400: var(--app-base-400);
  --rz-base-500: var(--app-base-500);
  --rz-base-600: var(--app-ink-3);
  --rz-base-700: var(--app-ink-2);
  --rz-base-800: var(--app-ink);
  --rz-base-900: var(--app-base-900);
  --rz-base-lighter: var(--app-ground);
  --rz-base-light:   var(--app-surface-2);
  --rz-base-dark:    var(--app-ink-3);
  --rz-base-darker:  var(--app-base-900);

  --rz-base-background-color:  var(--app-surface);
  --rz-body-background-color:  var(--app-ground);
  --rz-panel-background-color: var(--app-surface);
  --rz-input-background-color: var(--app-surface);
  --rz-text-color:             var(--app-ink);
  --rz-text-secondary-color:   var(--app-ink-2);
  --rz-border-color:           var(--app-rule);
  --rz-grid-header-background-color: var(--app-surface-2);
  --rz-border-radius: var(--app-radius-control);

  /* --- Bootstrap 5.3 -----------------------------------------------------
     The -rgb pairs are load-bearing: .bg-primary / .text-bg-* are built as
     rgba(var(--bs-primary-rgb), var(--bs-bg-opacity)), so setting only
     --bs-primary leaves those utilities blue. They are tokens rather than
     literals for the same reason as everything else - so dark mode flips them. */
  --bs-primary:      var(--app-primary);
  --bs-primary-rgb:  var(--app-primary-rgb);
  --bs-secondary:     var(--app-neutral);
  --bs-secondary-rgb: var(--app-neutral-rgb);
  --bs-success:      var(--app-success);   --bs-success-rgb: var(--app-success-rgb);
  --bs-warning:      var(--app-warning);   --bs-warning-rgb: var(--app-warning-rgb);
  --bs-danger:       var(--app-danger);    --bs-danger-rgb:  var(--app-danger-rgb);
  --bs-info:         var(--app-info);      --bs-info-rgb:    var(--app-info-rgb);
  --bs-light:        var(--app-surface-2);
  --bs-dark:         var(--app-ink);

  --bs-body-bg:         var(--app-ground);
  --bs-body-color:      var(--app-ink);
  --bs-body-color-rgb:  var(--app-ink-rgb);
  --bs-border-color:    var(--app-rule);
  --bs-link-color:       var(--app-primary);
  --bs-link-color-rgb:   var(--app-primary-rgb);
  --bs-link-hover-color: var(--app-primary-hover);
  --bs-border-radius:    var(--app-radius-control);
  --bs-emphasis-color:   var(--app-ink);
}

/* ============================================================================
   BOOTSTRAP COMPONENTS

   Setting --bs-primary is NOT enough, and this is the trap worth remembering:
   only the UTILITIES (.bg-primary, .text-primary) read --bs-primary-rgb.
   Every COMPONENT in Bootstrap 5.3 carries its own baked variable -
   .list-group sets --bs-list-group-active-bg: #0d6efd on itself, .btn-primary
   sets --bs-btn-bg, and so on - so the blue survives a --bs-primary override
   and shows up on exactly the controls people click. The Reports category list
   was still Bootstrap blue after the palette landed, for this reason.

   The surface/ink variables here matter for a second reason: Bootstrap bakes
   WHITE backgrounds into .card, .modal, .dropdown-menu, .list-group and the
   form controls. Without these the dark theme would leave white panels on a
   dark page.
   ============================================================================ */
:root {
  --bs-primary-bg-subtle:     var(--app-primary-soft);
  --bs-primary-border-subtle: var(--app-primary-light);
  --bs-primary-text-emphasis: var(--app-primary-ink);
  --bs-blue: var(--app-primary);
}

.btn-primary {
  --bs-btn-bg:                  var(--app-primary);
  --bs-btn-color:               var(--app-on-primary);
  --bs-btn-border-color:        var(--app-primary);
  --bs-btn-hover-bg:            var(--app-primary-hover);
  --bs-btn-hover-color:         var(--app-on-primary);
  --bs-btn-hover-border-color:  var(--app-primary-hover);
  --bs-btn-active-bg:           var(--app-primary-hover);
  --bs-btn-active-color:        var(--app-on-primary);
  --bs-btn-active-border-color: var(--app-primary-hover);
  --bs-btn-disabled-bg:         var(--app-primary);
  --bs-btn-disabled-color:      var(--app-on-primary);
  --bs-btn-disabled-border-color: var(--app-primary);
}

.btn-outline-primary {
  --bs-btn-color:               var(--app-primary);
  --bs-btn-border-color:        var(--app-primary);
  --bs-btn-hover-bg:            var(--app-primary);
  --bs-btn-hover-color:         var(--app-on-primary);
  --bs-btn-hover-border-color:  var(--app-primary);
  --bs-btn-active-bg:           var(--app-primary);
  --bs-btn-active-color:        var(--app-on-primary);
  --bs-btn-active-border-color: var(--app-primary);
  --bs-btn-disabled-color:      var(--app-primary);
}

.list-group {
  --bs-list-group-bg:                  var(--app-surface);
  --bs-list-group-color:               var(--app-ink);
  --bs-list-group-border-color:        var(--app-rule);
  --bs-list-group-action-hover-bg:     var(--app-surface-2);
  --bs-list-group-action-hover-color:  var(--app-ink);
  --bs-list-group-active-bg:           var(--app-primary);
  --bs-list-group-active-border-color: var(--app-primary);
  --bs-list-group-active-color:        var(--app-on-primary);
}

.nav-pills {
  --bs-nav-pills-link-active-bg:    var(--app-primary);
  --bs-nav-pills-link-active-color: var(--app-on-primary);
}

.dropdown-menu {
  --bs-dropdown-bg:                var(--app-surface);
  --bs-dropdown-color:             var(--app-ink);
  --bs-dropdown-border-color:      var(--app-rule);
  --bs-dropdown-link-color:        var(--app-ink);
  --bs-dropdown-link-hover-bg:     var(--app-surface-2);
  --bs-dropdown-link-hover-color:  var(--app-ink);
  --bs-dropdown-link-active-bg:    var(--app-primary);
  --bs-dropdown-link-active-color: var(--app-on-primary);
}

.pagination {
  --bs-pagination-bg:                  var(--app-surface);
  --bs-pagination-color:               var(--app-primary);
  --bs-pagination-border-color:        var(--app-rule);
  --bs-pagination-hover-bg:            var(--app-surface-2);
  --bs-pagination-active-bg:           var(--app-primary);
  --bs-pagination-active-color:        var(--app-on-primary);
  --bs-pagination-active-border-color: var(--app-primary);
}

.progress { --bs-progress-bg: var(--app-surface-2); --bs-progress-bar-bg: var(--app-primary); }

.card {
  --bs-card-bg:           var(--app-surface);
  --bs-card-color:        var(--app-ink);
  --bs-card-border-color: var(--app-rule);
  --bs-card-cap-bg:       var(--app-surface-2);
}

.modal {
  --bs-modal-bg:           var(--app-surface);
  --bs-modal-color:        var(--app-ink);
  --bs-modal-border-color: var(--app-rule);
}

.table {
  --bs-table-bg:           var(--app-surface);
  --bs-table-color:        var(--app-ink);
  --bs-table-border-color: var(--app-rule);
  --bs-table-hover-bg:     var(--app-surface-2);
  --bs-table-hover-color:  var(--app-ink);
}

.form-control, .form-select {
  background-color: var(--app-surface);
  color: var(--app-ink);
  border-color: var(--app-rule);
}

/* Focus: the ring is the palette's, on every control that draws one. Bootstrap
   bakes #86b7fe + rgba(13,110,253,.25) as literals in these rules, so they have
   to be restated rather than re-pointed. */
.form-control:focus,
.form-select:focus,
.form-check-input:focus {
  border-color: var(--app-primary);
  box-shadow: var(--app-focus-ring);
}

.form-check-input {
  background-color: var(--app-surface);
  border-color: var(--app-rule-strong);
}

.form-check-input:checked {
  background-color: var(--app-primary);
  border-color: var(--app-primary);
}

.nav-link:focus-visible { box-shadow: var(--app-focus-ring); }

:root {
  --primary-gradient: var(--app-primary);
  --secondary-gradient: var(--app-success);
  --danger-gradient: var(--app-danger);
  --card-shadow: var(--app-shadow-card);
  --hover-shadow: var(--app-shadow-hover);
  --bg-glass: var(--app-surface);
  --border-glass: var(--app-rule);
  --text-dark: var(--app-ink);
  --text-muted: var(--app-ink-2);
  --border-color: var(--app-rule);
  /* Radzen custom font family override */
  --rz-font-family: Arial, sans-serif !important;
  --rz-text-font-family: Arial, sans-serif !important;
  /* Decrease radzen grid header font size globally */
  --rz-grid-header-font-size: 0.7rem;
  --rz-grid-cell-font-size: 0.7rem;
  --bs-body-font-size: 0.7rem;
  /* Icon palette - see the .fa-primary / .fa-secondary rules below. These two values are the
     tones every duotone glyph in the app. Warm neutral by default so a content icon stays quiet;
     the menu rail overrides them to plum (RadzenNavMenu2.razor.css) because that is where the
     colour earns its place. */
  --fa-primary-color: var(--app-icon-1);
  --fa-secondary-color: var(--app-icon-2);

  /* ==========================================================================
     SPACING SCALE

     One scale for the whole app, so a gap means the same thing on every screen.
     Steps are 4px apart at the low end and jump at the top; anything that is not
     on the scale is a bug, not a nuance.
     ========================================================================== */
  --sp-1: 0.25rem;   /*  4px - icon-to-label, chip innards            */
  --sp-2: 0.5rem;    /*  8px - inside a dense control, cell padding   */
  --sp-3: 0.75rem;   /* 12px - between siblings in a card            */
  --sp-4: 1rem;      /* 16px - card padding, gap between cards       */
  --sp-5: 1.5rem;    /* 24px - between major sections on a page      */
  --sp-6: 2rem;      /* 32px - page-level separation, rare           */

  /* The inset between the chrome (menu rails, header) and page content. Owned by
     the LAYOUT content container and by nothing else - see the "PAGE GUTTER"
     block further down for why a page must never add its own. */
  --content-gutter: var(--sp-4);

  /* Card/panel geometry. A "card" is any raised white surface on the page
     background: dashboard widgets, profile tiles, the settings panels. */
  --card-pad: var(--sp-4);
  --card-gap: var(--sp-3);
  --card-radius: 8px;
}

/* ---------------------------------------------------------------------------
   FontAwesome duotone tones.

   MUST live here in the GLOBAL stylesheet, never in a scoped .razor.css. FontAwesomeIcon and
   SvgIcon inline the file as a MarkupString, so the <svg> and its <path>s are not part of any
   component's markup and carry no b-xxxxx scope attribute. A scoped rule compiles to
   ".fa-primary[b-xxxxx]" and silently matches nothing - the same trap already documented in
   SettingsExplorer.razor.css, and the reason ".fa-icon-v7 svg" in RadzenNavMenu2.razor.css has
   never applied.

   IconSvg.Normalise puts these two classes on the artwork; overriding either variable in any
   narrower scope retints every icon under it. For example:
       [data-theme="dark"]           { --fa-secondary-color: #3a4a57; }
       .rz-button:hover .fa-icon-v7  { --fa-primary-color: #fff; }
   Single-tone icons (the FA solid exports) deliberately carry neither class and keep following
   the inherited text colour through their own currentColor.
   --------------------------------------------------------------------------- */
/* Default geometry. The inner <svg> is sized in em, so font-size scales the icon exactly the way
   it scaled the Radzen icon font this replaced - which is what let ~700 migrated call sites keep
   their existing Style="font-size:..." verbatim. Call sites that need fixed pixels (the card,
   chat, grid-toolbar and report-row icons) override this with a more specific rule. */
.fa-icon-v7 {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  vertical-align: middle;
  flex: none;
}

.fa-icon-v7 > svg {
  width: 1em;
  height: 1em;
  display: block;
}

.fa-icon-v7 .fa-primary {
  fill: var(--fa-primary-color);
}

.fa-icon-v7 .fa-secondary {
  fill: var(--fa-secondary-color);
}

/* Report-list type icon (Reports.razor TypeIconHtml). Global rather than scoped for two reasons:
   the markup is built as a string in C# so it carries no component scope, and it is injected into
   a grid cell that belongs to CSGrid rather than to Reports. Sizes match the 16px img it replaced. */
.reports-type-icon.fa-icon-v7 {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  vertical-align: middle;
}

.reports-type-icon.fa-icon-v7 svg {
  width: 16px;
  height: 16px;
  display: block;
}

/* An icon sitting before a label inside a button. Replaces Radzen's ImageStyle on the Image=
   parameter, which only exists because Image renders an <img> - and an <img> cannot take the
   duotone tones from CSS. Same metrics the ImageStyle carried. Global, because the icon is
   rendered by SvgIcon and so belongs to no calling component's scope. */
.fa-icon-v7.icon-inline-sm {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.1rem;
  height: 1.1rem;
  margin-right: 0.35rem;
  vertical-align: middle;
}

.fa-icon-v7.icon-inline-sm svg {
  width: 1.1rem;
  height: 1.1rem;
  display: block;
}

/* Same metrics on an icon-ONLY button, where the trailing gap would just skew the padding. */
.fa-icon-v7.icon-inline-sm.icon-inline-bare {
  margin-right: 0;
}

*, *::before, *::after {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

html, body {
  font-family: Arial, sans-serif;
  background-color: var(--app-ground);
  color: var(--app-ink);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Base Link Color */
a, .btn-link {
  color: var(--app-primary);
  transition: color 0.2s ease;
}
a:hover, .btn-link:hover {
  color: var(--app-primary-hover);
  text-decoration: none;
}

/* CSTextBox & general input styles */
.form-control, .rz-textbox, .rz-textarea, .rz-numeric, .rz-dropdown, .rz-multiselect, .rz-inputtext {
  /* these make everything look bad, I don't know why we added them ? The dropdowns have too much padding and the text is not visible, and then some inherit a double border */
  /*
  border-radius: 8px !important;
  border: 1px solid var(--border-color) !important;
  padding: 0.6rem 0.80rem !important;
  transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1) !important;
  background-color: #fff !important;
  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05) !important;
    */
  /* This makes the text in the controls jagged and too big for dropdowns
  font-family: "Segoe UI", sans-serif !important;
  font-size: 0.95rem !important;
    */

  box-shadow: none !important;
}

.form-control:focus, .rz-state-focus, .rz-textbox:focus, .rz-textarea:focus {
  border-color: var(--app-primary) !important;
  box-shadow: var(--app-focus-ring) !important;
  outline: none !important;
}

/* Buttons */
.btn {
  border-radius: var(--app-radius-control);
  font-weight: 600;
  /* Try not to change the default icon styles... use the wi_btn_* instead */
  /* Removing padding so default buttons don't have so much */
  /* padding: 0.625rem 1.25rem;*/
  transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}

.wi_btn_primary {
  background: var(--app-primary) !important;
  border: none !important;
  color: var(--app-on-primary) !important;
  box-shadow: none !important;
}

.wi_btn_primary:hover:not(:disabled) {
  transform: translateY(-1px);
  background: var(--app-primary-hover) !important;
}

.wi_btn_primary:active:not(:disabled) {
  transform: translateY(1px);
}

.wi_btn_secondary {
  border: 1px solid var(--border-color) !important;
  /* NOT the literal `white` this carried until 2026-09-05. --text-dark aliases --app-ink, which flips
     to near-white in dark mode, so a literal white ground made the label invisible. The class had no
     users at the time, so the bug had never shipped - the DQ "Finish Later" button is the first. */
  background-color: var(--app-surface) !important;
  color: var(--text-dark) !important;
  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05) !important;
}

.wi_btn_secondary:hover:not(:disabled) {
  background-color: var(--app-surface-2) !important;
  border-color: var(--app-rule-strong) !important;
}

/* Premium Form Container */
.wi_dqform_container {
  max-width: 960px;
  /* unnecessary... pushes the next control too much 
    margin-bottom: 3rem;
    */
}

.wi_dq_card {
  border-radius: var(--app-radius-card) !important;
  background: var(--bg-glass);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid var(--border-glass) !important;
  box-shadow: var(--card-shadow) !important;
  overflow: hidden;
  transition: box-shadow 0.3s ease;
}

.wi_dq_card:hover {
  box-shadow: var(--hover-shadow) !important;
}

.wi_dq_header {
  /* unnecessary...
  background: var(--primary-gradient) !important;
  padding: 1.75rem 2rem !important;
    */
}

.wi_dq_title {
  /* Bootstrap's .text-white on the header div does NOT reach this: Radzen's default.css sets
     h3, .h3 { color: var(--rz-text-title-color) } which - being an explicit declaration on the
     element itself rather than an inherited one - wins over the ancestor's text-white regardless
     of specificity or !important. --app-on-primary is the token this palette already defines for
     text sitting on a --app-primary fill (see .btn-primary, .list-group), and it flips correctly
     in dark mode where --app-primary itself flips to a light tint. */
  color: var(--app-on-primary);
  letter-spacing: -0.025em;
  font-weight: 700;
  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.wi_dq_desc {
  font-size: 1.1rem;
  color: var(--text-muted);
  margin-bottom: 2rem;
  font-weight: 400;
}

/* Section Styling */
  .wi_section_card {
  border-radius: var(--app-radius-card) !important;
  border: 1px solid var(--border-color) !important;
  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.05) !important;
  margin-bottom: 1.75rem !important;
  overflow: hidden;
}

.wi_section_header {
  background-color: var(--app-surface-2) !important;
  padding: 1.25rem 1.5rem !important;
  border-bottom: 1px solid var(--border-color) !important;
}

.wi_section_title {
  font-weight: 600;
  color: var(--app-ink) !important;
  font-size: 1.15rem;
}

.wi_section_body {
  padding: 1.5rem !important;
  background-color: #ffffff;
}

/* Control Row Styling */
.wi_layout_control_row {
  margin-bottom: 1.25rem !important;
  transition: all 0.3s ease;
}

.wi_control_label {
  color: var(--app-ink-2);
  font-size: 0.925rem;
  font-weight: 600 !important;
}

/* Readonly fields display */
.wi_readonly_value {
  background-color: var(--app-surface-2) !important;
  border-color: var(--app-rule) !important;
  color: var(--app-ink-2) !important;
  font-weight: 500;
  border-radius: var(--app-radius-control);
  padding: 0.625rem 0.875rem !important;
}

/* Error message indicators */
.wi_validation_error {
  color: var(--app-danger) !important;
  font-size: 0.825rem;
  margin-top: 0.375rem;
  display: flex;
  align-items: center;
  animation: slideDown 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Alerts custom design */
.wi_alert_success {
  background-color: var(--app-success-soft);
  border: 1px solid var(--app-success);
  color: var(--app-success-ink);
  border-radius: var(--app-radius-control);
}

.wi_alert_danger {
  background-color: var(--app-danger-soft);
  border: 1px solid var(--app-danger);
  color: var(--app-danger-ink);
  border-radius: var(--app-radius-control);
}

/* File upload styling */
.wi_fileupload_placeholder {
  border: 2px dashed var(--app-rule-strong) !important;
  border-radius: var(--app-radius-card);
  background-color: var(--app-surface-2) !important;
  text-align: center;
  padding: var(--sp-4) !important;
  color: var(--app-ink-2) !important;
  transition: all 0.2s ease;
}
.wi_fileupload_placeholder:hover {
  border-color: var(--app-primary) !important;
  background-color: var(--app-primary-softer) !important;
}

/* Radzen Override Fixes */
.rz-dropdown, .rz-multiselect {
  display: inline-flex !important;
  align-items: center;
}

.rz-dropdown-trigger {
  background-color: transparent !important;
}

/* Multiselect popups are reparented to <body> and JS-sized to the trigger's width; CSGrid's
   icon-only column picker (28px trigger) needs the panel wide enough for names + checkboxes.
   !important because Radzen.js sets width AND min-width inline when opening the popup. */
.rz-multiselect-panel {
  min-width: 200px !important;
}

.rz-chkbox-box {
  border-radius: 4px !important;
  border: 2px solid #cbd5e1 !important;
  width: 20px !important;
  height: 20px !important;
  transition: all 0.15s ease !important;
}

.rz-chkbox-box.rz-state-active {
  background: var(--primary-gradient) !important;
  border-color: var(--app-primary) !important;
}

/* Fullscreen Submitting Overlay */
.wi_saving_overlay {
  animation: fadeIn 0.3s ease;
  backdrop-filter: blur(8px);
}

/* Progress bar modernizer */
.wi_progress_container {
  background: var(--app-surface-2);
  padding: 1rem;
  border-radius: 12px;
  border: 1px solid var(--border-color);
}

.wi_progress_bar .rz-progressbar-value {
  background: var(--primary-gradient) !important;
}

/* The DQ progress bar sitting INSIDE the form's action bar rather than as a standalone panel above
   the questions (2026-09-05). The panel chrome is dropped - a boxed, filled panel on the same line as
   the buttons reads as a second control - but the wi_progress_container class name stays on the
   element because it is the documented hook for per-agency custom CSS.

   min-width matters: without it the flex item's basis is its content, so on a narrow dialog the bar
   refuses to shrink and pushes the buttons out of the row instead of the row wrapping. */
.wi_progress_inline {
  background: none;
  padding: 0;
  border: none;
  border-radius: 0;
  min-width: 12rem;
}

/* Phone: the action bar wraps (flex-wrap in the markup), so the bar takes its own line above the
   buttons and the buttons stay right-aligned under it. Radzen forces a dialog to 100% width below
   768px, which leaves roughly 310px inside the card body - not enough for a bar plus two buttons. */
@media (max-width: 575.98px) {
  .wi_progress_inline {
    min-width: 100%;
  }

  .wi_form_actions_buttons {
    width: 100%;
    justify-content: flex-end;
  }
}

/* Standard blazor features */
.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI5OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA5OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3LjgyOSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljg4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNzcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

/* Collapse the inspected-customer submenu column when there's no menu to show.
   RadzenNavMenu2 renders no .nav2-wrapper when empty, so :has() detects the gap. */
nav.nested-customer-menu:not(:has(.nav2-wrapper)) {
  display: none;
}

/* make menus flush left */
.internal-menu .nav2-wrapper {
  height: 100%;
}
.nested-customer-menu .nav2-wrapper {
  height: 100%;
}
.internal-menu .nav2-wrapper-compact {
  position: relative !important;
  left: unset !important;
  top: unset !important;
  height: 100% !important;
}
.nested-customer-menu .nav2-wrapper-compact {
  /*position: relative !important; */
  left: unset !important;
  top: unset !important;
  height: 100% !important;
}

/* ==========================================================================
   PAGE GUTTER

   ONE owner for the inset between the chrome and the page: the layout's content
   container. A page must not add its own padding at its root - that is what
   produced the three different gutters this replaces (0px on the internal
   screens, 16px where a page wrapped itself in .p-3, 32px on the customer
   portal where .customer-body's 1rem and the page's own .p-3 stacked up).

   Global rather than scoped to each layout's .razor.css for two reasons: the
   rules have to see across component boundaries (the :has() below matches a
   child rendered by a DIFFERENT component, whose scope attribute a scoped rule
   would never carry), and the gutter is one decision, so it reads better in one
   place than split three ways.

   The internal shell nests: .internal-body holds EITHER the page or the
   inspected-customer submenu column. When it holds the submenu, the gutter
   belongs to .nested-customer-body inside it - padding out here would push that
   submenu down and right, breaking its alignment with the main rail.
   ========================================================================== */
.internal-body:not(:has(> .nested-customer-layout)),
.nested-customer-body,
.customer-body {
  padding: var(--content-gutter);
}

/* Opt-out for a screen that genuinely wants the full bleed - a canvas, a
   split-pane workspace that draws its own edges. Put it on the page root. */
.page-flush,
.internal-body:has(> .page-flush),
.nested-customer-body:has(> .page-flush),
.customer-body:has(> .page-flush) {
  padding: 0;
}

/* A Bootstrap .container / .container-fluid used as the page ROOT brings its own
   horizontal gutter (--bs-gutter-x / 2 = 12px), which lands on top of the one
   above. Cancelled at the boundary rather than in each screen, and only for a
   DIRECT child, so containers nested inside a page keep their gutter.
   Padding, not --bs-gutter-x: that variable inherits, and zeroing it here would
   also flatten every .row gutter inside the page. */
.internal-body > .container, .internal-body > .container-fluid,
.nested-customer-body > .container, .nested-customer-body > .container-fluid,
.customer-body > .container, .customer-body > .container-fluid {
  padding-left: 0;
  padding-right: 0;
}

/* DynamicQuestionnaire dynamic questionnaires */
.dq-container {
  /*
  border: 1px solid green; /*dev outline while DynamicQuestionnaire layout is in progress */
}

.dq-question-container { /*
  border: 1px solid blue; dev outline while DynamicQuestionnaire layout is in progress */
}

.rz-navigation-item-text {
  /* make menus a bit "lighter" and compact */
  font-weight: normal;
  font-stretch: normal;
  font-size: small;
  line-height: 1.2;
}

.rz-navigation-item-link {
  /* make menu items closer, compact */
  margin: 0px !important;
}

/* The active row's icon gets NO plate of its own.

   This used to paint #FFEDE4 behind it, from when the selected row was a solid
   plum slab and the icon needed a light chip to stay legible on it. The selected
   row is now a soft plum TINT with plum ink on top, so the icon already contrasts
   with its own row - and the leftover peach was actively harmful in dark mode: the
   plate stayed light while the icon inverted to light, so the selected item was
   the one icon you could not see.

   The collapsed rail keeps a deliberate chip of its own (RadzenNavMenu2.razor.css,
   tooltip mode) for a different reason - there the caption pill slides UNDER the
   icon, so it needs a plate to sit on. That one follows --app-rail. */


/* Question inputs fill the container; selectors target the root element of each
   Radzen input used by the DynamicQuestionnaire question components (Style="" used to go there).
   The container may carry a wi_* width class (section below) that caps how far "100%" can go. */
.dq-question-input .rz-textbox,
.dq-question-input .rz-textarea,
.dq-question-input .rz-numeric,
.dq-question-input .rz-dropdown,
.dq-question-input .rz-datepicker {
  width: 100%;
}

/* Checkbox questions lay the caption out INLINE, to the right of the box, rather than stacked above it
   like every other question type: a lone box under its caption becomes unreadable as soon as two
   checkboxes sit near each other, because the caption floats between them and neither pairing is
   obvious. Applied by DQQuestionContainer.InnerLayoutClass; a question authored with
   AnswerRelativePositionWithRespectToQuestion = BOTTOM opts out and keeps the stacked layout. */
.dq-inline-check {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  column-gap: 0.5rem;
}

/* order, not DOM order, does the swap: DQQuestionLabel keeps emitting the caption first, so its
   for=/id= association with the input is untouched. */
.dq-inline-check > .dq-question-input {
  order: 0;
  flex: 0 0 auto;
}

.dq-inline-check > .dq-question-label {
  order: 1;
  flex: 0 1 auto;
  margin: 0;
  cursor: pointer;
}

/* validation text and the debug strip belong on their own line under the pair, not beside it */
.dq-inline-check > .dq-question-validation,
.dq-inline-check > .dq-question-debug {
  order: 2;
  flex: 0 0 100%;
}

.dq-question-validation .rz-text-caption {
  color: var(--rz-danger);
  display: block;
}

/* ===== Field width classes — port of the CSWebApp CSWebV2.css question classes =====
   Same class names and widths as CSWebApp on purpose (documented in "Question Classes.md",
   Feature Specifications/Custom Forms (DQ)), so the convention and per-site override knowledge
   apply to both UIs. Bounded fields (SSN, ZIP, dates, phone…) look wrong stretched to the full
   column, so each class caps its element at the field's natural width; width:100% below the cap
   keeps fields responsive on narrow screens (they shrink, never grow past the cap).
   Usage: hand-built forms put the class straight on the Radzen control (or its wrapper div);
   DQ forms get it automatically on .dq-question-input (see DQQuestionContainer.FieldWidthClass). */
.wi_fc_numbers     { --fieldw: 160px; min-width: 100px; }
.wi_fc_numbersdays { --fieldw: 70px;  min-width: 60px;  }
.wi_fg_cspct       { --fieldw: 120px; min-width: 30px;  }
.wi_ig_csc         { --fieldw: 125px; }                    /* currency */
.wi_fc_email       { --fieldw: 300px; min-width: 160px; }
.wi_fc_ssn_ein     { --fieldw: 170px; }
.wi_ig_csphone     { --fieldw: 200px; min-width: 150px; }
.wi_fc_micr        { --fieldw: 280px; }
.wi_fc_d           { --fieldw: 150px; }                    /* Open ShortDate */
.wi_fc_dt          { --fieldw: 190px; }                    /* Open ShortDateAndTime */
.wi_ig_csd         { --fieldw: 155px; }                    /* SearchBox CalendarDateOnly */
.wi_ig_csdt        { --fieldw: 240px; }                    /* SearchBox Calendar (date+time) */
.wi_month_dd       { --fieldw: 170px; }
.wi_day_dd         { --fieldw: 90px;  }
.wi_year_dd        { --fieldw: 85px;  }
.wi_dq_dropdown    { --fieldw: 300px; min-width: 180px; }
/* web-app-only additions, not in the legacy doc table (bounded fields outside DQ forms) */
.wi_fc_zip         { --fieldw: 120px; }                    /* 12345-6789 */
.wi_fc_state       { --fieldw: 70px;  }                    /* 2-letter state */

.wi_fc_numbers, .wi_fc_numbersdays, .wi_fg_cspct, .wi_ig_csc, .wi_fc_email,
.wi_fc_ssn_ein, .wi_ig_csphone, .wi_fc_micr, .wi_fc_d, .wi_fc_dt,
.wi_ig_csd, .wi_ig_csdt, .wi_month_dd, .wi_day_dd, .wi_year_dd,
.wi_dq_dropdown, .wi_fc_zip, .wi_fc_state {
  width: 100%;
  max-width: var(--fieldw);
}

/* Encrypted open questions render the input and a Clear button side by side: lift the cap off
   the pair and cap the input itself instead (--fieldw inherits down from the wrapper). */
.dq-question-input:has(> .dq-encrypted) { max-width: none; }
.dq-encrypted .rz-textbox { max-width: var(--fieldw, none); }

/* Animations */
@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 0.85; }
}

@keyframes slideDown {
  from {
    opacity: 0;
    transform: translateY(-4px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Document tree hover and selection behavior: only adds a blue border outline,
   preventing background/color wipes on sent items */
.document-tree .rz-treenode-content:hover .rz-treenode-label {
  background-color: transparent !important;
  color: inherit !important;
}

.document-tree .rz-treenode-content-selected .rz-treenode-label {
  background-color: transparent !important;
  color: inherit !important;
  font-weight: bold !important;
}

.document-tree .rz-treenode-content:hover {
  box-shadow: inset 0 0 0 1px var(--app-primary) !important;
}

.document-tree .rz-treenode-content-selected {
  box-shadow: inset 0 0 0 1.5px var(--app-primary) !important;
}

/* RadzenDatePicker trigger icon: swap the Material "calendar_today" glyph for the Font Awesome
   duotone calendar-days SVG (keeps the icon's own bluegray colors, so a mask isn't used). Applies
   to every date control app-wide for a consistent look. */
.rz-datepicker-trigger .rzi-calendar::before {
  content: none !important;
}
.rz-datepicker-trigger .rzi-calendar {
  display: inline-block;
  width: var(--rz-datepicker-trigger-icon-width);
  height: var(--rz-datepicker-trigger-icon-height);
  /* MASK, not background-image: this is Radzen own trigger element, so there is no markup of
     ours to inline an SvgIcon into - and a background-image paints the file baked palette and
     cannot be retinted, so the date pickers stayed FontAwesome-blue in both themes. */
  background-color: var(--app-icon-1);
  -webkit-mask: url("assets/icons/calendar-daysbluegray.svg") no-repeat center / contain;
  mask: url("assets/icons/calendar-daysbluegray.svg") no-repeat center / contain;
}

/* No alternating (zebra) row striping in any grid, anywhere in the app. CreditSoft rows are
   colored by DATA — appointment types, statuses, queue-visit fades, the backcolor column
   convention — and a parity stripe both fights those colors and implies a meaning that isn't
   there. Radzen's default theme stripes even rows via these two variables on its
   .rz-grid-table-striped class; pointing both at the base background makes every row match.
   (Scoped to the class, not :root, because the chart tooltip hover reuses the stripe var.) */
.rz-grid-table-striped {
  --rz-grid-stripe-background-color: var(--rz-base-background-color);
  --rz-grid-stripe-odd-background-color: var(--rz-base-background-color);
}

/* ---------------------------------------------------------------------------
   Work queues — the collector loop
   (Docs/WorkQueues/WorkQueues-SavedSearch-BlazorPort.md, Phase 3)

   These rules must live HERE and not in CSGrid.razor.css. A scoped stylesheet only
   attributes elements that appear in the component's own markup, and every one of these
   targets a <tr>/<td> that RadzenDataGrid renders inside CSGrid — a scoped rule would
   never match. (The plan records an earlier design that made exactly this mistake.)
   --------------------------------------------------------------------------- */

/* The keyboard cursor. Left bar rather than a background, so it stays legible on top of a
   row the queue's own SQL coloured and on top of the already-worked grey below. */
.csgrid .rz-grid-table > tbody > tr.csgrid-row-focused > td {
  box-shadow: inset 0 -1px 0 var(--rz-primary), inset 0 1px 0 var(--rz-primary);
}

.csgrid .rz-grid-table > tbody > tr.csgrid-row-focused > td:first-child {
  box-shadow: inset 3px 0 0 var(--rz-primary),
              inset 0 -1px 0 var(--rz-primary),
              inset 0 1px 0 var(--rz-primary);
}

.csgrid:focus {
  outline: none;
}

.csgrid:focus-visible {
  outline: 2px solid var(--rz-primary);
  outline-offset: 2px;
}

/* "Already worked" fade. Ported verbatim from CSWebApp/CSWebV2.css, where the shades have
   existed since v11 and nothing has ever applied them — the legacy portal defines the classes
   and leaves it to each agency's saved-search SQL to emit them, which no deployed search does.
   QueueVisitService picks the level: darkest right after the row was worked, one step lighter
   an hour, gone after 13. There is no wi_gray_14 — the plan quotes 1..14, the stylesheet
   stops at 13. */
.csgrid .rz-grid-table > tbody > tr.wi_gray_1 > td { background-color: #F8F8F8 !important; }
.csgrid .rz-grid-table > tbody > tr.wi_gray_2 > td { background-color: #F0F0F0 !important; }
.csgrid .rz-grid-table > tbody > tr.wi_gray_3 > td { background-color: #E8E8E8 !important; }
.csgrid .rz-grid-table > tbody > tr.wi_gray_4 > td { background-color: #E0E0E0 !important; }
.csgrid .rz-grid-table > tbody > tr.wi_gray_5 > td { background-color: #D8D8D8 !important; }
.csgrid .rz-grid-table > tbody > tr.wi_gray_6 > td { background-color: #D0D0D0 !important; }
.csgrid .rz-grid-table > tbody > tr.wi_gray_7 > td { background-color: #C8C8C8 !important; }
.csgrid .rz-grid-table > tbody > tr.wi_gray_8 > td { background-color: #C0C0C0 !important; }
.csgrid .rz-grid-table > tbody > tr.wi_gray_9 > td { background-color: #B8B8B8 !important; }
.csgrid .rz-grid-table > tbody > tr.wi_gray_10 > td { background-color: #B0B0B0 !important; }
.csgrid .rz-grid-table > tbody > tr.wi_gray_11 > td { background-color: #A8A8A8 !important; }
.csgrid .rz-grid-table > tbody > tr.wi_gray_12 > td { background-color: #A0A0A0 !important; }
.csgrid .rz-grid-table > tbody > tr.wi_gray_13 > td { background-color: #989898 !important; }

/* The thirteen shades above are fixed light greys, so the ink on them has to be fixed too - the
   dark theme's light ink on #F8F8F8 is the same unreadable pairing the data-driven row colors
   had. Radzen's .rz-cell-data carries its own color, hence the second selector; see the matching
   note in CSGrid.razor.css. */
.csgrid .rz-grid-table > tbody > tr[class*="wi_gray_"] > td,
.csgrid.csgrid-cards .rz-grid-table > tbody > tr[class*="wi_gray_"] > td {
  color: #000000;
}

.csgrid .rz-grid-table > tbody > tr[class*="wi_gray_"] > td .rz-cell-data {
  color: inherit;
}

/* A link inside a data-coloured grid row, DARK THEME ONLY.

   The theme's link colour is chosen for the theme's own surface; a data-driven backcolor is not
   that surface. Under the dark theme the pale plum (#C79BD4) landing on a white AccountStatus row
   is 1.9:1 - the same "light on light" failure as the cell text, one layer down. So the link takes
   the row's own ink, which CSGridModel.BuildStyle has already picked to contrast with that fill.
   The row still reads as a link because .csgrid-command underlines unconditionally, deliberately
   (see the note on that rule in CSGrid.razor.css).

   Guarded to dark because under the LIGHT theme there is nothing to fix: the plum is already a
   light-surface colour, which is exactly what a data-coloured row is. Both guards are needed for
   the same reason the palette needs them - "system" stamps no attribute, an explicit choice does. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .csgrid tr[style*="background-color"] > td a,
  :root:not([data-theme="light"]) .csgrid tr[style*="background-color"] > td a:hover,
  :root:not([data-theme="light"]) .csgrid td[style*="background-color"] a,
  :root:not([data-theme="light"]) .csgrid td[style*="background-color"] a:hover {
    color: inherit;
  }
}

:root[data-theme="dark"] .csgrid tr[style*="background-color"] > td a,
:root[data-theme="dark"] .csgrid tr[style*="background-color"] > td a:hover,
:root[data-theme="dark"] .csgrid td[style*="background-color"] a,
:root[data-theme="dark"] .csgrid td[style*="background-color"] a:hover {
  color: inherit;
}

/* Card view renders each row as a block. The shade goes on the block and the cells inherit it,
   rather than thirteen more rules painting individual cells inside a card. */
.csgrid.csgrid-cards .rz-grid-table > tbody > tr[class*="wi_gray_"] > td {
  background-color: inherit !important;
}

.csgrid.csgrid-cards .rz-grid-table > tbody > tr[class*="wi_gray_"] {
  background-color: #E8E8E8;
}

/* The untouched-row marker. The Last Visited cell is genuinely empty on a row nobody has
   opened — the column stays a real datetime so it sorts and filters — so the label is drawn
   by CSS rather than written into the data. Bold orange is the legacy portal's own rendering
   (SavedSearch.aspx.vb:527-530). */
.csgrid td.wi_queue_new::after {
  content: "*New*";
  color: #d97706;
  font-weight: 600;
}

/* Triage drawer: a column beside the grid on wide screens, a full-width panel below it on
   narrow ones (never a modal — the point is to keep the queue on screen). */
.queue-drawer {
  border-left: 1px solid var(--rz-base-300, #dee2e6);
  background: var(--rz-base-background-color, #fff);
  max-height: calc(100vh - 6rem);
  overflow-y: auto;
  position: sticky;
  top: 0.5rem;
}

.queue-drawer .queue-drawer-note {
  max-height: 9rem;
  overflow-y: auto;
  font-size: 0.85rem;
}

.queue-shortcut-key {
  display: inline-block;
  min-width: 1.6rem;
  padding: 0 0.35rem;
  border: 1px solid var(--rz-base-400, #adb5bd);
  border-bottom-width: 2px;
  border-radius: 0.25rem;
  font-family: var(--bs-font-monospace, monospace);
  font-size: 0.8rem;
  text-align: center;
}

/* ==========================================================================
   Dashboard canvas (/dashboard "My board") — DashboardCanvas, DashboardWidgetFrame, WidgetQueues.
   Shared here rather than in scoped .razor.css files because the three components render one visual
   family and .dash-empty is used by all of them.
   ========================================================================== */

/* The persona picker: a segmented control, not a dropdown. There are only ever four, switching is the
   point rather than an edge case, and the current one has to be readable at a glance. */
.dash-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 0.5rem;
}

.dash-persona {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 0.15rem;
  padding: 0.15rem;
  border: 1px solid var(--rz-base-300, #dee2e6);
  border-radius: 999px;
  background: var(--rz-base-50, #f8f9fa);
}

.dash-persona-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  border: 0;
  border-radius: 999px;
  padding: 0.25rem 0.75rem;
  font: inherit;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--rz-text-secondary-color, #6c757d);
  background: transparent;
  cursor: pointer;
}

.dash-persona-btn .rzi {
  font-size: 1rem;
}

.dash-persona-btn:hover:not(.is-on):not(:disabled) {
  background: var(--rz-base-200, #e9ecef);
}

.dash-persona-btn.is-on {
  color: var(--rz-primary);
  background: var(--rz-base-background-color, #fff);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
}

.dash-persona-btn:disabled {
  cursor: default;
  opacity: 0.7;
}

/* On a phone the label alone is enough — four icon+label pills overflow a 375px viewport. */
@media (max-width: 575.98px) {
  .dash-persona {
    width: 100%;
    justify-content: space-between;
  }

  .dash-persona-btn {
    padding: 0.25rem 0.5rem;
  }

  .dash-persona-btn .rzi {
    display: none;
  }
}

.dash-board-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 0.75rem;
}

.dash-widget {
  display: flex;
  flex-direction: column;
  height: 100%;
  border: 1px solid var(--rz-base-300, #dee2e6);
  border-radius: 0.5rem;
  background: var(--rz-base-background-color, #fff);
  overflow: hidden;
}

.dash-widget.is-collapsed {
  height: auto;
}

.dash-widget-head {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.4rem 0.5rem 0.4rem 0.7rem;
  border-bottom: 1px solid var(--rz-base-200, #e9ecef);
  background: var(--rz-base-50, #f8f9fa);
}

.dash-widget.is-collapsed .dash-widget-head {
  border-bottom: 0;
}

.dash-widget-title {
  flex: 1;
  min-width: 0;
  margin: 0;
  font-size: 0.85rem;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dash-widget-kind {
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--rz-text-secondary-color, #6c757d);
  border: 1px solid var(--rz-base-300, #dee2e6);
  border-radius: 0.2rem;
  padding: 0 0.3rem;
  flex: none;
}

.dash-widget-actions {
  display: flex;
  align-items: center;
  gap: 0.15rem;
  flex: none;
}

.dash-widget-body {
  padding: 0.5rem;
  flex: 1;
}

/* Dashed outline while editing, so it is obvious which surface the controls act on. */
.dash-editing .dash-widget {
  border-style: dashed;
  border-color: var(--rz-primary-light);
}

/* --- Agency custom-form slots (P7) ---------------------------------------------------------------
   A slot element only exists when the agency actually has that form, so its spacing lives here rather
   than on a wrapper div in DashboardView — a wrapper would reserve margin on the usual empty case. */
.dash-slot {
  margin-top: 1rem;
  border: 1px solid var(--rz-base-300, #dee2e6);
  border-radius: 0.5rem;
  background: var(--rz-base-background-color, #fff);
  overflow: hidden;
}

.dash-slot-head {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.4rem 0.5rem 0.4rem 0.7rem;
  border-bottom: 1px solid var(--rz-base-200, #e9ecef);
  background: var(--rz-base-50, #f8f9fa);
}

.dash-slot.is-collapsed .dash-slot-head {
  border-bottom: 0;
}

.dash-slot-title {
  flex: 1;
  min-width: 0;
  margin: 0;
  font-size: 0.85rem;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The DQ engine brings its own Bootstrap .container and .card. Inside a slot that reads as a card in a
   card, and the container's max-width would centre a narrow form in a full-width slot. Scoped to
   .dash-slot-body so no other DQ host is affected. */
.dash-slot-body .wi_dqform_container {
  max-width: none;
  padding: 0;
}

.dash-slot-body .wi_dq_card {
  border-radius: 0;
  box-shadow: none !important;
}

.dash-palette {
  border: 1px dashed var(--rz-primary-light);
  border-radius: 0.5rem;
  padding: 0.75rem 0.9rem;
  margin-bottom: 0.9rem;
  background: var(--rz-base-50, #f8f9fa);
}

.dash-palette-group + .dash-palette-group {
  margin-top: 0.6rem;
}

.dash-palette-cat {
  font-size: 0.65rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--rz-text-secondary-color, #6c757d);
  margin-bottom: 0.3rem;
}

.dash-queue-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}

.dash-queue-list li {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.3rem 0.35rem;
  border-radius: 0.25rem;
  cursor: pointer;
}

.dash-queue-list li:hover,
.dash-queue-list li:focus-visible {
  background: var(--rz-base-100, #f1f3f5);
}

.dash-queue-name {
  flex: 1;
  min-width: 0;
  font-size: 0.8rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dash-empty {
  padding: 0.9rem 0.5rem;
  text-align: center;
  font-size: 0.8rem;
  color: var(--rz-text-secondary-color, #6c757d);
}

/* --------------------------------------------------------------------------
   Dashboard "Today" spine — DashboardToday, DashboardIndicatorStrip.
   Severity is carried by shape (chip, stripe) as well as colour, so the page still reads correctly
   without relying on colour alone.
   -------------------------------------------------------------------------- */

.dash-today {
  border: 1px solid var(--rz-base-300, #dee2e6);
  border-radius: 0.5rem;
  background: var(--rz-base-background-color, #fff);
  overflow: hidden;
  height: 100%;
}

.dash-rail {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  flex-wrap: wrap;
  padding: 0.5rem 0.6rem;
  border-bottom: 1px solid var(--rz-base-200, #e9ecef);
  background: var(--rz-base-50, #f8f9fa);
}

.dash-rail-label {
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--rz-text-secondary-color, #6c757d);
}

.dash-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  border: 1px solid;
  border-radius: 999px;
  padding: 0.15rem 0.6rem;
  font: inherit;
  font-size: 0.75rem;
  font-weight: 600;
  background: var(--rz-base-background-color, #fff);
  cursor: pointer;
}

.dash-chip .dash-chip-n {
  font-size: 0.85rem;
  font-weight: 700;
}

.dash-chip.is-on {
  box-shadow: 0 0 0 2px rgba(31, 95, 139, 0.25);
}

.dash-chip-crit {
  border-color: var(--app-danger-soft);
  background: var(--app-danger-soft);
  color: var(--app-danger-ink);
}

.dash-chip-due {
  border-color: var(--app-warning-soft);
  background: var(--app-warning-soft);
  color: var(--app-warning-ink);
}

.dash-chip-calm {
  border-color: var(--rz-base-300, #dee2e6);
  color: var(--rz-text-secondary-color, #6c757d);
}

.dash-clear {
  font-size: 0.75rem;
  font-weight: 600;
  color: #2c6e49;
}

.dash-today-body {
  padding: 0.6rem;
}

.dash-today-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin-bottom: 0.4rem;
}

.dash-todo {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}

.dash-todo li {
  display: grid;
  grid-template-columns: 4px auto 1fr auto;
  align-items: center;
  gap: 0 0.55rem;
  padding: 0.35rem 0.3rem;
  border-bottom: 1px solid var(--rz-base-200, #e9ecef);
}

.dash-todo li:last-child {
  border-bottom: 0;
}

.dash-todo li.is-link {
  cursor: pointer;
  border-radius: 0.25rem;
}

.dash-todo li.is-link:hover,
.dash-todo li.is-link:focus-visible {
  background: var(--rz-base-100, #f1f3f5);
}

.dash-todo-stripe {
  width: 4px;
  height: 1.6rem;
  border-radius: 2px;
  background: var(--rz-base-300, #dee2e6);
}

.dash-todo-overdue .dash-todo-stripe { background: var(--app-danger); }
.dash-todo-today .dash-todo-stripe { background: var(--app-warning); }

/* SvgIcon now, so font-size drives the size (the inner svg is sized in em). Colour has to be set
   BOTH ways: a duotone icon paints from the two variables, while a single-tone one (the FA solid
   exports) paints fill="currentColor" and follows plain color. Setting only the variables left
   these rendering the inherited near-black instead of grey/red/amber. */
.dash-todo-icon {
  font-size: 1rem;
  color: var(--rz-text-secondary-color, #6c757d);
  --fa-primary-color: var(--rz-text-secondary-color, #6c757d);
  --fa-secondary-color: var(--rz-text-secondary-color, #6c757d);
}

.dash-todo-overdue .dash-todo-icon { color: var(--app-danger); --fa-primary-color: var(--app-danger); --fa-secondary-color: var(--app-danger); }
.dash-todo-today .dash-todo-icon { color: var(--app-warning); --fa-primary-color: var(--app-warning); --fa-secondary-color: var(--app-warning); }

.dash-todo-main {
  min-width: 0;
}

.dash-todo-text {
  display: block;
  font-size: 0.82rem;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dash-todo-sub {
  display: block;
  margin-top: 0.05rem;
}

.dash-todo-tag {
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 0.05rem 0.3rem;
  border-radius: 0.2rem;
  background: var(--rz-base-100, #f1f3f5);
  color: var(--rz-text-secondary-color, #6c757d);
}

.dash-todo-overdue .dash-todo-tag { background: var(--app-danger-soft); color: var(--app-danger-ink); }
.dash-todo-today .dash-todo-tag { background: var(--app-warning-soft); color: var(--app-warning-ink); }

.dash-todo-when {
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--rz-text-secondary-color, #6c757d);
  white-space: nowrap;
}

.dash-todo-overdue .dash-todo-when { color: var(--app-danger); }

/* KPI strip */
.dash-kpi-head {
  margin-bottom: 0.5rem;
}

.dash-kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
  gap: 0.5rem;
}

.dash-kpi {
  border: 1px solid var(--rz-base-300, #dee2e6);
  border-radius: 0.5rem;
  padding: 0.5rem 0.6rem;
  background: var(--rz-base-background-color, #fff);
}

.dash-kpi.is-failed {
  border-style: dashed;
}

.dash-kpi-value {
  font-size: 1.3rem;
  font-weight: 700;
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
}

.dash-kpi-name {
  font-size: 0.72rem;
  color: var(--rz-text-secondary-color, #6c757d);
}

/* Bulletin board widget (MainComments) */
.dash-bulletin {
  font-size: 0.85rem;
  line-height: 1.5;
  overflow-x: auto;
}

.dash-bulletin img {
  max-width: 100%;
  height: auto;
}

.dash-bulletin-edit {
  margin-top: 0.6rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--rz-base-200, #e9ecef);
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  font-size: 0.72rem;
}

/* Manager scope toggle + team item owner (Today spine) */
.dash-scope {
  display: inline-flex;
  gap: 0.2rem;
  align-items: center;
}

.dash-todo-owner {
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 0.05rem 0.3rem;
  margin-left: 0.3rem;
  border-radius: 0.2rem;
  border: 1px solid var(--rz-base-300, #dee2e6);
  color: var(--rz-text-secondary-color, #6c757d);
}

/* AI briefing card (Today spine)

   Tinted rather than plain, so it reads as the one generated card on the spine -
   but the tint now comes from the plum family the label and the rank chips
   already use. It was a hardcoded pale blue, which is the one thing the palette
   rules out: a literal does not flip, so the card stayed light while everything
   around it went dark. */
.dash-ai {
  border: 1px solid var(--app-primary-soft);
  border-radius: 0.5rem;
  background: linear-gradient(180deg, var(--app-primary-softer), var(--app-surface));
  padding: 0.6rem 0.7rem;
}

.dash-ai-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}

.dash-ai-label {
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--app-primary);
}

.dash-ai-asof,
.dash-ai-foot span {
  font-size: 0.68rem;
  color: var(--rz-text-secondary-color, #6c757d);
}

.dash-ai-running {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.78rem;
  color: var(--rz-text-secondary-color, #6c757d);
  padding: 0.5rem 0;
}

.dash-ai-empty {
  font-size: 0.78rem;
  color: var(--rz-text-secondary-color, #6c757d);
  padding: 0.5rem 0;
}

.dash-ai-list {
  list-style: none;
  margin: 0.5rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.dash-ai-list li {
  display: grid;
  grid-template-columns: 1.2rem 1fr;
  gap: 0.5rem;
  font-size: 0.78rem;
  line-height: 1.45;
}

.dash-ai-rank {
  width: 1.2rem;
  height: 1.2rem;
  border-radius: 0.25rem;
  background: var(--app-primary);
  color: #fff;
  font-size: 0.68rem;
  font-weight: 700;
  display: grid;
  place-items: center;
}

.dash-ai-title {
  font-weight: 600;
}

.dash-ai-why {
  display: block;
  color: var(--rz-text-secondary-color, #6c757d);
}

.dash-ai-foot {
  margin-top: 0.6rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--app-primary-soft);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  flex-wrap: wrap;
}

/* Dashboard filter bar */
.dash-filters {
  border: 1px solid var(--rz-base-300, #dee2e6);
  border-radius: 0.5rem;
  background: var(--rz-base-50, #f8f9fa);
  padding: 0.4rem 0.6rem;
  margin-bottom: 0.9rem;
}

.dash-filters-head {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
}

.dash-filters-summary {
  font-size: 0.75rem;
  color: var(--rz-text-secondary-color, #6c757d);
  flex: 1;
  min-width: 0;
}

.dash-filters-body {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  padding-top: 0.6rem;
  margin-top: 0.5rem;
  border-top: 1px solid var(--rz-base-200, #e9ecef);
}

.dash-filter {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

.dash-filter-label {
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--rz-text-secondary-color, #6c757d);
}

.dash-filter-range {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
}

/* A flex column that holds a grid must be allowed to SHRINK below the grid's natural width.
   A flex item's implicit min-width is its min-content size, and a many-column CSGrid's
   min-content easily exceeds 2000px - wider than the space beside the queue rail - so without
   this the .col refuses to fit, the .row wraps, and the whole workspace lands BELOW the rail
   with the right half of a large screen empty. The grid then scrolls horizontally inside its
   own container, which is exactly what AllowHorizontalScroll is for. */
.col-shrinkable {
  min-width: 0;
}

/* Payment Schedule Templates editor (System Setup > Client). Global rather than scoped because the
   same form layout is shared by the five-tab editor and its three modal sub-editors, and Blazor
   scopes an isolated stylesheet to one component only - four near-identical copies would drift. */
.pstd-form {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  padding: 0.5rem 0.25rem;
}

.pstd-field {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
}

/* The label column is fixed so the inputs line up down the form the way the desktop's absolute
   positioning did, and wide enough for the longest caption ("Settlement Fee Default Percentage
   from Balance:"). */
.pstd-field > label {
  flex: 0 0 19rem;
  padding-top: 0.35rem;
  font-size: 0.875rem;
}

.pstd-checks {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-left: 19.6rem;
}

.pstd-fieldset {
  margin-left: 19.6rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--rz-base-300, #dee2e6);
  border-radius: 0.25rem;
}

.pstd-fieldset > legend {
  float: none;
  width: auto;
  padding: 0 0.35rem;
  font-size: 0.8125rem;
  color: var(--rz-text-secondary-color, #6c757d);
}

/* Toolbar above the two child grids - the desktop's ToolStrip2 / ToolStrip3. */
.pstd-gridbar {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  margin-bottom: 0.5rem;
}

.pstd-footer {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 0.5rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--rz-base-200, #e9ecef);
  margin-top: 0.5rem;
}

/* A SQL formula field. The template editors store formulas, not amounts - real ones run to four or
   five lines of SELECT with joins - so these stack the label ABOVE a wide monospace box instead of
   using the 19rem label column, which left about a third of the dialog for the SQL itself. */
.pstd-formula {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.pstd-formula > label {
  font-size: 0.875rem;
  font-weight: 600;
}

.pstd-formula textarea {
  width: 100%;
  min-height: 9rem;
  /* Drag-to-grow: a formula longer than the box is common and the dialog cannot guess how long. */
  resize: vertical;
  font-family: Consolas, "Courier New", monospace;
  font-size: 0.8125rem;
  line-height: 1.45;
  white-space: pre;
  overflow-wrap: normal;
  overflow-x: auto;
}

/* The check-syntax button sits under its box rather than beside it, so the box keeps the full width. */
.pstd-formula-actions {
  display: flex;
  align-items: center;
  gap: 0.375rem;
}

/* ==========================================================================
   Legacy content compatibility (Landing Pages plan P4, defect ledger #38)

   The classic portal's landing content files are styled almost entirely with four wi_* classes,
   and an agency migrating one into Home_Main / Enroll_Main / Start_Main by copy-and-paste brings
   the class names with it. Without these rules that content renders as unstyled default serif -
   the migration LOOKS like it failed, on the front door of the site, and the obvious "fix" is to
   strip the markup back, which loses the agency's structure for good.

   Copied from CSWebApp\CSMasterStylesV2.css (the two text classes) and CSWebApp\CSWebV2.css (the
   two button classes) so migrated content keeps the size, spacing and colour it had. Deliberately
   a small closed set matching what the shipped ContentV2 files actually use, not a port of either
   stylesheet: everything else those files rely on is plain HTML or Bootstrap, which this app has.

   Do NOT scope these to .web-content-area. The same class names appear in the InternetMenus
   custom-content panels, which have exactly the same migration problem.
   ========================================================================== */

/* Body text in a migrated content file. */
.wi_loginwelcometext {
  font-size: 14px;
  padding-bottom: 10px;
}

/* Same, in the classic portal's heading blue. */
.wi_loginwelcometextblue {
  font-size: 14px;
  padding-top: 5px;
  padding-bottom: 15px;
  color: var(--app-primary-ink);
}

/* A call-to-action link or button inside migrated content. The legacy rule targeted an <input>
   painted by WebForms; here it is normally an <a>, so it needs the pieces a bare anchor lacks -
   inline-block, no underline, and a pointer - which the WebForms control got for free. */
.wi_button {
  display: inline-block;
  background: var(--app-primary);
  color: var(--app-on-primary);
  text-decoration: none;
  cursor: pointer;
  padding: 5px;
  border: none !important;
  border-radius: 5px;
  margin: 5px;
  min-width: 95px;
  width: auto;
  text-align: center;
}

.wi_button:hover,
.wi_button:focus {
  color: #fff;
  text-decoration: none;
}

/* Pairs with Bootstrap's .btn in the shipped Enrollment.htm, which supplies everything but the
   text colour. */
.wi_register_button {
  color: #fff !important;
}

/* ==========================================================================
   Enhanced-navigation progress bar (#icco-nav-progress, declared in App.razor)

   Routes is static SSR, so EVERY page change - a link, or a NavigateTo from an
   interactive component - is an enhanced navigation: a fetch of the whole new
   page. The browser shows nothing for one of those (no tab spinner, no cursor
   change), so a page that takes a second to render simply looks frozen, which
   is what the account grid -> account detail hop looked like.

   The element ships hidden and is activated by JS; it is declared in App.razor
   rather than created on the fly because enhanced navigation removes body nodes
   the incoming document does not have.
   ========================================================================== */
.icco-nav-progress {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  z-index: 2000; /* above the sticky app header and the Radzen menus, below dialogs */
  pointer-events: none;
  opacity: 0;
  transition: opacity .15s linear;
}

/* Appears instantly - the script already held it back 150ms, and fading in on top of that would
   make it miss short navigations entirely. Only the fade OUT is animated. */
.icco-nav-progress.active {
  opacity: 1;
  transition: none;
}

/* Indeterminate: there is no progress to report - the server is either still
   working or streaming - so the bar sweeps rather than filling. */
.icco-nav-progress .icco-nav-progress-bar {
  width: 100%;
  height: 100%;
  background: linear-gradient(90deg, rgba(89, 34, 99, 0) 0%, var(--app-primary) 45%, var(--app-primary-light) 55%, rgba(89, 34, 99, 0) 100%);
  transform: translateX(-100%);
}

.icco-nav-progress.active .icco-nav-progress-bar {
  animation: icco-nav-progress-sweep 1.1s ease-in-out infinite;
}

@keyframes icco-nav-progress-sweep {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(100%); }
}

/* Second, quieter signal for a user whose eyes are on the row they just clicked
   rather than on the top of the window. */
body.icco-navigating {
  cursor: progress;
}

@media (prefers-reduced-motion: reduce) {
  .icco-nav-progress.active .icco-nav-progress-bar {
    animation: none;
    transform: none;
    background: var(--app-primary);
  }
}

/* ============================================================================
   RADZEN ALERT SHADES

   A "lighter" alert paints a translucent tint of its severity colour and then
   sets the TEXT colour from a value the theme bakes rather than derives - so
   remapping --rz-info left the tint plum-warm and the words on top still the
   old teal. Nothing in the CSSOM exposes the rule that does it (the shipped
   theme is a single minified line, and the declaration does not surface through
   document.styleSheets), so this is stated directly rather than re-pointed.

   The -ink values are the darkest step of each severity, which is what a light
   tint needs behind text. Filled alerts with no shade class keep the theme's
   white-on-solid and are deliberately untouched.
   ============================================================================ */
.rz-alert.rz-shade-lighter.rz-info    { --rz-alert-color: var(--app-info-ink); }
.rz-alert.rz-shade-lighter.rz-success { --rz-alert-color: var(--app-success-ink); }
.rz-alert.rz-shade-lighter.rz-warning { --rz-alert-color: var(--app-warning-ink); }
.rz-alert.rz-shade-lighter.rz-danger  { --rz-alert-color: var(--app-danger-ink); }
.rz-alert.rz-shade-lighter.rz-primary { --rz-alert-color: var(--app-primary-ink); }

/* The title and the icon are THEIR OWN baked variables, not derived from
   --rz-alert-color - so a converted alert body still carried a teal heading. */
.rz-alert.rz-shade-lighter.rz-info    { --rz-alert-title-color: var(--app-info-ink);    --rz-alert-icon-color: var(--app-info); }
.rz-alert.rz-shade-lighter.rz-success { --rz-alert-title-color: var(--app-success-ink); --rz-alert-icon-color: var(--app-success); }
.rz-alert.rz-shade-lighter.rz-warning { --rz-alert-title-color: var(--app-warning-ink); --rz-alert-icon-color: var(--app-warning); }
.rz-alert.rz-shade-lighter.rz-danger  { --rz-alert-title-color: var(--app-danger-ink);  --rz-alert-icon-color: var(--app-danger); }
.rz-alert.rz-shade-lighter.rz-primary { --rz-alert-title-color: var(--app-primary-ink); --rz-alert-icon-color: var(--app-primary); }

/* ============================================================================
   THEME LEGIBILITY - the gaps the dark theme exposed

   Everything here is a colour one of the libraries BAKES as a literal, so it
   could not be reached by re-pointing a token. They were found by loading every
   route with the dark theme on and flagging any element whose background was
   light or whose text was near-black - the switch was built first precisely so
   this list could be measured rather than guessed at.

   Two of them were pre-existing LIGHT-theme bugs that dark mode merely made
   total, and both are called out below.
   ============================================================================ */
:root {
  /* Bootstrap bakes these as literal rgba(33,37,41,...) rather than deriving
     them from --bs-body-color-rgb, so muted text stayed near-black: the Reports
     category list, every .text-body-secondary, the work-queue rail captions. */
  --bs-secondary-color:  rgba(var(--app-ink-rgb), 0.75);
  --bs-tertiary-color:   rgba(var(--app-ink-rgb), 0.5);
  --bs-secondary-bg:     var(--app-surface-2);
  --bs-tertiary-bg:      var(--app-ground);
  --bs-emphasis-color-rgb: var(--app-ink-rgb);
  --bs-light-rgb:        var(--app-surface-2-rgb);
  --bs-dark-rgb:         var(--app-ink-rgb);

  /* The -subtle / -emphasis trio per severity. QueueCountBadge and the Bootstrap
     badges are written against these, so they follow once these are set. */
  --bs-success-bg-subtle: var(--app-success-soft);
  --bs-success-border-subtle: var(--app-success);
  --bs-success-text-emphasis: var(--app-success-ink);
  --bs-warning-bg-subtle: var(--app-warning-soft);
  --bs-warning-border-subtle: var(--app-warning);
  --bs-warning-text-emphasis: var(--app-warning-ink);
  --bs-danger-bg-subtle:  var(--app-danger-soft);
  --bs-danger-border-subtle: var(--app-danger);
  --bs-danger-text-emphasis: var(--app-danger-ink);
  --bs-info-bg-subtle:    var(--app-info-soft);
  --bs-info-border-subtle: var(--app-info);
  --bs-info-text-emphasis: var(--app-info-ink);
  --bs-light-bg-subtle:   var(--app-surface-2);
  --bs-dark-bg-subtle:    var(--app-surface-2);

  /* Radzen's "on base" trio is a literal dark slate (#28363c) - white text on a
     dark fill in light mode, invisible on a dark fill in dark mode. */
  --rz-on-base:         var(--app-ink);
  --rz-on-base-light:   var(--app-ink);
  --rz-on-base-lighter: var(--app-ink);
  --rz-on-base-dark:    var(--app-base-50);
  --rz-on-base-darker:  var(--app-base-50);
  --rz-light: var(--app-surface-2);
  --rz-dark:  var(--app-ink);
}

/* PRE-EXISTING BUG, not a dark-mode one. Radzen paints a text-variant "light"
   button with color: var(--rz-base-200) - a near-invisible pale grey even in the
   shipped light theme, and invisible outright once base-200 becomes a dark
   surface. These are the grid toolbar icons (column chooser, export, filter):
   controls, not decoration, so they get readable ink and a real hover. */
.rz-button.rz-variant-text.rz-light,
.rz-button.rz-variant-text.rz-base {
  color: var(--app-ink-2);
}

.rz-button.rz-variant-text.rz-light:not(.rz-state-disabled):hover,
.rz-button.rz-variant-text.rz-base:not(.rz-state-disabled):hover {
  color: var(--app-primary);
  background-color: var(--app-primary-softer);
}

/* NOTE - do not "help" the icon inside such a button by pinning its tones to the
   button's colour. That was tried and reverted: it forced --fa-primary-color to
   currentColor and flattened every DUOTONE glyph in a text-variant button to two
   greys - the Quick Search magnifier, Recent Records and the Help question mark
   all went monochrome. The colour fix above is enough on its own, because the two
   icon kinds need opposite things and both already get them:
     - a SINGLE-TONE icon has a bare currentColor and follows the button colour,
       which is exactly what the rule above just fixed;
     - a DUOTONE icon paints from .fa-primary / .fa-secondary and must keep the
       palette tones, not the button's ink.

/* ---------------------------------------------------------------------------
   Grid selection.

   Radzen derives the selected-row fill from --rz-secondary-dark and its text
   from --rz-on-secondary-dark. In the shipped theme "secondary" is a blue, so
   that reads as a proper accent; in this palette secondary is deliberately a
   NEUTRAL (a secondary ACTION should be quiet), which turned every selected
   grid row into a flat mid-grey - drab in light mode, and in dark mode a pale
   #BDB5B8 band carrying light text, which was unreadable.

   Selection is an accent state, not a quiet one, so it takes the primary. A
   tint rather than a solid fill because these grids are dense and the keyboard
   cursor (the left bar, further up this file) already marks the active row -
   two solid bands competing is worse than one tint plus a rule.
   --------------------------------------------------------------------------- */
:root {
  --rz-grid-selected-background-color: var(--app-primary-soft);
  --rz-grid-selected-color:            var(--app-primary-ink);
  --rz-grid-cell-focus-background-color: var(--app-primary-tint);
  --rz-grid-cell-focus-color:            var(--app-ink);
}

/* Two more baked literals the dark sweep turned up.
   --rz-base (the bare one, not the -50..-900 steps) is Radzen's chip / neutral-fill colour;
   --bs-*-bg-rgb are what .bg-body-tertiary and friends actually read, not the non-rgb pair. */
:root {
  --rz-base: var(--app-rule);
  --bs-secondary-bg-rgb: var(--app-surface-2-rgb);
  --bs-tertiary-bg-rgb:  var(--app-surface-2-rgb);
  --bs-body-tertiary-bg: var(--app-surface-2);
  --bs-body-secondary-bg: var(--app-surface-2);
}

/* ---------------------------------------------------------------------------
   Quick Search: the magnifier and the recent-records clock.

   SINGLE TONE by request. These two sit inside a text field rather than on a
   toolbar, at 18px, and at that size the duotone secondary reads as a smudge
   rather than as depth - so the secondary is made transparent and only the
   primary shape is drawn. Transparent rather than "same as primary" because a
   filled secondary would close up the counters (the magnifier's lens, the
   clock's face) and turn each glyph into a blob.

   The buttons are also forced to centre their content. Radzen leaves the icon
   on the text baseline, which put it 4px from the top and 10px from the bottom
   of a 28px button - visibly high, and the kind of thing you only see once you
   look for it. Flex centring makes it exact regardless of line-height.
   --------------------------------------------------------------------------- */
.quick-search .rz-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 4px;
}

.quick-search .rz-button .fa-icon-v7 {
  --fa-secondary-color: transparent;
  font-size: 18px;
  width: 18px;
  height: 18px;
  margin: 0;              /* rz-button-icon-left adds a right gap for a label these have no label */
}

.quick-search .rz-button .fa-icon-v7 svg {
  width: 18px;
  height: 18px;
}

.quick-search .rz-button:hover .fa-icon-v7 {
  --fa-primary-color: var(--app-primary);
}

/* ---------------------------------------------------------------------------
   HEADER HELP BUTTON (HelpButton.razor)

   Same two problems the quick-search buttons above had, for the same reason: a
   RadzenButton wrapping an inlined SvgIcon.

   1. It sat HIGH. Radzen leaves the icon on the text baseline, so in the 28px
      button the 14px glyph landed 4px from the top and 10px from the bottom -
      3px above the optical centre its neighbours share. Flex centring fixes it
      regardless of line-height.
   2. It read SMALL, at 14px against the 15.2px of the theme, language and
      account icons beside it. 0.95rem is that 15.2px: those three inherit it
      from their own toggle button, because the "font-size: 1.25rem" their
      scoped .razor.css declares on .theme_icon / .globe_icon / .avatar_icon has
      never applied - the <i> is rendered by FontAwesomeIcon and so carries no
      b-xxxxx attribute for the scoped selector to match. Matching what is on
      screen, not what those files say, is deliberate: the three icons are the
      size the header was signed off at.

   Global rather than a HelpButton.razor.css: the component's markup is nothing
   but child components, so it has no element of its own carrying a b-xxxxx
   scope attribute - a scoped rule (::deep included) would match nothing.
   --------------------------------------------------------------------------- */
.header-help-button.rz-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.header-help-button .fa-icon-v7 {
  font-size: 0.95rem;
  width: 0.95rem;
  height: 0.95rem;
  margin: 0;              /* rz-button-icon-left adds a right gap for a label this has no label */
}

.header-help-button .fa-icon-v7 > svg {
  width: 0.95rem;
  height: 0.95rem;
}

/* ---------------------------------------------------------------------------
   DUOTONE DEPTH - two places where the two tones were fighting instead of
   describing the shape.

   1. THE MENU RAIL. The recoloured (Form 1) exports carry a distinct GREY
      secondary at full opacity. At 20px that sits too close in weight to the
      plum primary, so the shapes merge: the Dashboard dial loses its needle and
      its tick dots, and the Task Search magnifier loses its handle. FontAwesome's
      own convention is the SAME hue at reduced opacity - that is what gives
      duotone its sense of depth - so restate it rather than living with the
      design share's flat grey.

   2. A FILLED BUTTON. A filled button paints its own background, so an icon on
      it must follow the button's FOREGROUND, not the content-icon tones. On the
      plum Search button the #4A3F44 primary was all but invisible.
      currentColor, never a literal, so it holds in both themes (white on plum in
      light, dark ink on light plum in dark) and for every ButtonStyle rather
      than just the primary one.

   Both rules live HERE and not in a scoped .razor.css: the SVG is inlined as a
   MarkupString, so its paths carry no b-xxxxx attribute and a scoped rule would
   compile to .fa-secondary[b-xxxxx] and match nothing.
   --------------------------------------------------------------------------- */
.nav2-wrapper .rz-navigation-item-icon .fa-secondary {
  fill: var(--app-rail-icon-1);
  opacity: .35;
}

.nav2-wrapper .rz-navigation-item-wrapper-active > .rz-navigation-item-link .rz-navigation-item-icon .fa-secondary {
  fill: var(--app-primary-ink);
  opacity: .4;
}

.rz-button.rz-variant-filled .fa-icon-v7 .fa-primary,
.rz-button.rz-variant-filled .fa-icon-v7 .fa-secondary,
.rz-button.rz-variant-flat .fa-icon-v7 .fa-primary,
.rz-button.rz-variant-flat .fa-icon-v7 .fa-secondary {
  fill: currentColor;
}

.rz-button.rz-variant-filled .fa-icon-v7 .fa-secondary,
.rz-button.rz-variant-flat .fa-icon-v7 .fa-secondary {
  opacity: .45;
}

/* A duotone-LIGHT glyph reversed out of a filled button reads thinner than it
   measures: light strokes on a dark ground optically shrink, and 14px of a
   640-unit viewBox leaves very little line. Scaling the glyph thickens the
   stroke with it - the honest fix, short of shipping a heavier FontAwesome
   weight as a second file for one button. 17px still clears the 36px button. */
.rz-button.rz-variant-filled .fa-icon-v7,
.rz-button.rz-variant-flat .fa-icon-v7 {
  font-size: 17px;
  width: 17px;
  height: 17px;
}

.rz-button.rz-variant-filled .fa-icon-v7 > svg,
.rz-button.rz-variant-flat .fa-icon-v7 > svg {
  width: 17px;
  height: 17px;
}

/* The lens/backplate carries part of the shape at this size, so it earns a
   little more presence than the 45% used elsewhere. */
.rz-button.rz-variant-filled .fa-icon-v7 .fa-secondary,
.rz-button.rz-variant-flat .fa-icon-v7 .fa-secondary {
  opacity: .55;
}

/* Thicken the glyph itself, on top of the size bump above.

   These are fill-only paths (FontAwesome ships no strokes), so adding a stroke in
   the SAME colour grows the shape. Two details make it safe:

   - `vector-effect: non-scaling-stroke` measures stroke-width in CSS pixels rather
     than in the 640-unit viewBox, so the weight stays constant at every icon size
     instead of needing a different number per call site.
   - `paint-order: stroke fill` paints the stroke UNDERNEATH the fill, so the glyph
     grows OUTWARD only. Painted the default way round (fill then stroke) the inner
     half of the stroke would eat into the counters and close up the magnifier's
     lens and the clock's face at these sizes.

   Only on filled/flat buttons: this is compensation for a light glyph reversed out
   of a solid fill, not a change to how icons look generally. */
.rz-button.rz-variant-filled .fa-icon-v7 .fa-primary,
.rz-button.rz-variant-filled .fa-icon-v7 .fa-secondary,
.rz-button.rz-variant-flat .fa-icon-v7 .fa-primary,
.rz-button.rz-variant-flat .fa-icon-v7 .fa-secondary {
  stroke: currentColor;
  stroke-width: 1.1;
  vector-effect: non-scaling-stroke;
  paint-order: stroke fill;
}

/* Radzen reserves 10px of space above a floating-label field for the label to
   rise into, so the visible INPUT sits below its own field box's centre. The box
   was perfectly centred in the header and the search box still looked ~4px lower
   than the dropdowns beside it, because the eye compares the input, not the box.
   Pull the field up by half the reservation so the input lines up. */
.app-header .quick-search {
  position: relative;
  top: -4px;
}

/* ---------------------------------------------------------------------------
   Status pills above the record workspace (Web access, Password reset pending,
   requirement alerts).

   They sat flush on the workspace card below them - a 0px gap - and a full
   gutter below the header, which read as "attached to the card" rather than as a
   status line belonging to the record. Pull them up into the gutter and give
   them real separation from the card.
   --------------------------------------------------------------------------- */
.nested-customer-body > .badge,
.customer-body > .badge {
  /* position, not margin-top: these pills are inline-block, and a vertical margin on an
     inline-level box does not shift its line box - the -4px had no visible effect at all.
     Relative offset moves the pill without changing the space it reserves, so the 10px
     gap to the card below is preserved. */
  position: relative;
  top: -6px;
  margin-bottom: 10px;
}

/* ---------------------------------------------------------------------------
   Foreground for the STATUS colours.

   Radzen hardcodes --rz-on-success / -warning / -danger / -info to #ffffff,
   which is right while those fills are dark. In the dark theme they invert to
   LIGHT (#5FBF85, #E3A551, #FF8A80, #6BB6D8), and white-on-light-green measured
   2.3:1 on the Collect Payment button - worse than the coral it replaced.

   Same trick as --app-on-primary: one token that flips with the theme, so the
   ink follows the fill instead of being pinned to white.
   --------------------------------------------------------------------------- */
:root {
  --rz-on-success:        var(--app-on-status);
  --rz-on-success-dark:   var(--app-on-status);
  --rz-on-success-darker: var(--app-on-status);
  --rz-on-success-light:  var(--app-on-status);
  --rz-on-warning:        var(--app-on-status);
  --rz-on-warning-dark:   var(--app-on-status);
  --rz-on-warning-darker: var(--app-on-status);
  --rz-on-warning-light:  var(--app-on-status);
  --rz-on-danger:         var(--app-on-status);
  --rz-on-danger-dark:    var(--app-on-status);
  --rz-on-danger-darker:  var(--app-on-status);
  --rz-on-danger-light:   var(--app-on-status);
  --rz-on-info:           var(--app-on-status);
  --rz-on-info-dark:      var(--app-on-status);
  --rz-on-info-darker:    var(--app-on-status);
  --rz-on-info-light:     var(--app-on-status);
}

/* The debug toggle's bug icon stays red in both themes - it marks a developer-only
   control, and that meaning does not change with the palette. Two tones so it still
   reads as a bug rather than a blob; the global rules cannot supply this because the
   colour is deliberately OFF-palette. Global, not scoped: the SVG is inlined as a
   MarkupString and carries no component scope attribute. */
.debug-toggle-icon.fa-icon-v7 {
  --fa-primary-color: #C0392B;
  --fa-secondary-color: #E8A6A0;
  font-size: 15px;
  width: 15px;
  height: 15px;
  vertical-align: -2px;
}

.debug-toggle-icon.fa-icon-v7 > svg {
  width: 15px;
  height: 15px;
}

/* ==========================================================================
   NOTES DOCK

   The two placements a record-detail screen offers for its Notes feed: inside
   the screen's own tab strip, or docked as a rail on the RIGHT of the whole
   page. Driven by NotesDock; shared by the task, lead, client and account
   detail screens.

   GLOBAL rather than scoped to NotesDock.razor.css because the two halves are
   rendered by DIFFERENT components: .notes-dock-main wraps the hosting
   screen's own markup, which carries that screen's scope attribute and never
   NotesDock's, so a scoped `.notes-dock-side > .notes-dock-main` would match
   nothing.
   ========================================================================== */

.notes-view-toggle {
  margin-bottom: 0.25rem;
}

/* Tab view leaves .notes-dock as a plain block, so the wrapper costs nothing. */
.notes-dock-side {
  display: grid;
  /* minmax(0, ...) on both tracks: a grid or a long note inside must scroll its
     own box, never widen the page (the flex/grid min-width overflow trap). */
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: 1rem;
  align-items: start;
}

/* No `order` anywhere: source order is main-then-rail, which is both the wide
   layout (screen left, notes right) and the narrow one (screen above notes). */
.notes-dock-side > .notes-dock-main,
.notes-dock-side > .notes-dock-rail {
  min-width: 0;
}

.notes-dock-rail-title {
  font-weight: 600;
  margin-bottom: 0.25rem;
}

@media (max-width: 1099.98px) {
  .notes-dock-side {
    display: block;
  }

  .notes-dock-side > .notes-dock-rail {
    margin-top: 1rem;
  }
}

/* Currency fields: feedback when the two-decimal guard in wwwroot/js/currency-input.js refuses a
   keystroke or a paste. Without it the character simply fails to appear and the field looks broken.
   Global rather than scoped because the input is rendered by RadzenNumeric and carries no b-xxxxx
   scope attribute, so a rule in a .razor.css would compile to a selector matching nothing. */
.cs-currency-reject,
.cs-percent-reject {
  animation: cs-currency-reject-flash 0.6s ease-out;
}

@keyframes cs-currency-reject-flash {
  0%, 100% {
    background-color: transparent;
    box-shadow: none;
  }
  15%, 55% {
    background-color: var(--rz-danger-lighter, #fdeaea);
    box-shadow: 0 0 0 2px var(--rz-danger, #f43f5e);
  }
}

@media (prefers-reduced-motion: reduce) {
  .cs-currency-reject,
  .cs-percent-reject {
    animation-duration: 0.01ms;
    outline: 2px solid var(--rz-danger, #f43f5e);
  }
}

/* ---- Date of birth field (Components/Shared/Controls/DateOfBirthPicker.razor) --------------
   Global rather than scoped: the calendar button holds an <SvgIcon>, whose file is inlined as a
   MarkupString and so carries no b-xxxxx scope attribute - a rule in a .razor.css would compile to
   a selector matching nothing, which is the trap SettingsExplorer.razor.css already fell into. */
.dob-row {
  display: flex;
  align-items: stretch;
  gap: 4px;
}

.dob-row > .dob-input {
  flex: 1 1 auto;
  min-width: 0;
}

.dob-cal {
  flex: 0 0 auto;
  width: 2rem;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: var(--app-ink-2);
  background: var(--rz-input-background-color, var(--app-surface));
  border: 1px solid var(--rz-border-color, var(--app-rule));
  border-radius: var(--app-radius-control);
}

.dob-cal:hover:not(:disabled) { background: var(--app-surface-2); }
.dob-cal:disabled { opacity: 0.55; cursor: default; }

.dob-cal:focus-visible {
  border-color: var(--app-primary);
  box-shadow: var(--app-focus-ring);
  outline: none;
}

.dob-cal .fa-icon-v7 { font-size: 0.95rem; line-height: 1; }

.dob-parts {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 6px;
}

/* Always present, empty or not: reserving the line is what stops the form from nudging the moment
   a date is read back or a message appears. */
.dob-readout {
  min-height: 1.05rem;
  font-size: 0.78rem;
  line-height: 1.05rem;
  color: var(--app-ink-2);
}

.dob-readout.dob-invalid { color: var(--rz-danger, #f43f5e); }

/* wi_ig_csd caps a plain short-date box at 155px, which this field outgrew when it gained a button
   and three dropdowns. Widened here - on the field itself and on a wrapper holding one - rather
   than making every host drop the class it shares with the rest of its form. */
.dob-field.wi_ig_csd,
.wi_ig_csd:has(> .dob-field) { max-width: 17.5rem; }

/* ---- SsnInput ------------------------------------------------------------------------------- */
/* Sized by the host (the field sits in form rows of very different widths), so the wrapper only
   stacks the message under the input rather than imposing a width of its own. */
.ssn-field { display: block; width: 100%; }

.ssn-message {
  margin-top: 2px;
  font-size: 0.78rem;
  line-height: 1.05rem;
  color: var(--rz-danger, #f43f5e);
}

/* The input carries the state too, not just the line under it: in a dense form the message can be
   the only red thing on screen and there is nothing tying it to the box it belongs to. */
.ssn-input-invalid.rz-textbox,
.ssn-input-invalid .rz-textbox {
  border-color: var(--rz-danger, #f43f5e);
}

/* ---- AddressOneLine suggestions ------------------------------------------------------------- */
/* The dropdown used to hardcode background:#fff inline and set no colour, so in dark mode the
   inherited light ink landed on a white panel and the suggestions were unreadable. Both ends come
   from the palette now so the panel flips with the theme. */
.address-suggestions {
  position: absolute;
  z-index: 20;
  left: 0;
  right: 0;
  margin-top: 2px;
  background: var(--app-surface);
  color: var(--app-ink);
  border: 1px solid var(--app-rule);
  border-radius: var(--app-radius-control, 4px);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
}

.address-suggestion {
  padding: 6px 10px;
  font-size: 0.85rem;
  cursor: pointer;
}

.address-suggestion:hover { background: var(--app-surface-2); }
