/* App-level overrides. BlazorBlueprint's component CSS lives in the `bb` cascade
   layer and wins over this file regardless of <link> order, so retheme through
   the documented CSS custom properties rather than by restyling elements. */

/* Charcoal dark palette
   This is the app's dark theme, not one palette among several. It applies to
   every data-base-color on purpose: a value persisted in localStorage from an
   earlier session (Slate, say, at chroma 0.042 / hue 264) would otherwise tint
   the whole app navy. themes.css defines its dark values at
   [data-base-color="x"].dark (specificity 0,2,0), so adding the element type
   outranks it whatever x happens to be. Every value below is zero-chroma:
   a true charcoal, no tint. Accent colour still comes from --primary. */

html[data-base-color].dark,
html.dark[data-base-color] {
    /* Outer chrome — the darkest surface. The inset sidebar sits on this. */
    --sidebar: oklch(0.1450 0 0);
    --sidebar-border: oklch(0.2400 0 0);
    --sidebar-accent: oklch(0.2300 0 0);
    --sidebar-accent-foreground: oklch(0.9700 0 0);
    --sidebar-foreground: oklch(0.8700 0 0);
    --sidebar-ring: oklch(0.4400 0 0);

    /* Inset content panel — one step lighter so it reads as a raised surface. */
    --background: oklch(0.1850 0 0);
    --foreground: oklch(0.9700 0 0);

    --card: oklch(0.2100 0 0);
    --card-foreground: oklch(0.9700 0 0);
    --popover: oklch(0.2100 0 0);
    --popover-foreground: oklch(0.9700 0 0);

    --secondary: oklch(0.2600 0 0);
    --secondary-foreground: oklch(0.9700 0 0);
    --muted: oklch(0.2600 0 0);
    --muted-foreground: oklch(0.6600 0 0);
    --accent: oklch(0.2600 0 0);
    --accent-foreground: oklch(0.9700 0 0);

    --border: oklch(0.2600 0 0);
    --input: oklch(0.2800 0 0);
    --ring: oklch(0.4400 0 0);
}

/* The standard icon button for this app: 28px and circular, borderless.
   ButtonSize.Icon's own 36px reads oversized in the header row, and a 16px glyph
   inside 28px leaves 6px of breathing room. Declared here rather than as Tailwind
   utilities so it reliably beats each component's own size/rounded-* classes
   (equal specificity, and app.css is linked last). */
.app-icon-circle {
    width: 28px;
    height: 28px;
    min-width: 28px;
    padding: 0;
    border-radius: 9999px;
    border: none;
}

/* Only the account avatar carries a visible ring. */
.app-icon-bordered {
    border: 1px solid var(--border);
}

html,
body {
    height: 100%;
}

/* The app shell is pinned to the viewport (h-screen) and scrolls internally,
   so the document itself never should. */
body {
    overflow: hidden;
}

/* Interactivity is not prerendered, so the document paints before Blazor renders
   anything. Painting body on the themed background keeps that moment on the
   charcoal ground instead of the browser's default white. */
body {
    background-color: var(--background);
    color: var(--foreground);
}

/* FocusOnNavigate targets the page h1; suppress its focus ring. */
h1:focus {
    outline: none;
}

#blazor-error-ui {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 1000;
    display: none;
    padding: 0.75rem 1.25rem;
    background: #ffe8e8;
    color: #7a1010;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
}

#blazor-error-ui .dismiss {
    position: absolute;
    top: 0.5rem;
    right: 0.75rem;
    cursor: pointer;
}

/* Header navigation. Sized to sit inside the 40px header strip without stretching it. */
.app-nav-link {
    display: inline-flex;
    align-items: center;
    height: 24px;
    padding: 0 0.5rem;
    border-radius: 0.375rem;
    color: var(--muted-foreground);
    text-decoration: none;
    transition: color 120ms ease, background-color 120ms ease;
}

.app-nav-link:hover {
    color: var(--foreground);
    background-color: var(--accent);
}

/* Blazor's NavLink adds .active to the matching route. */
.app-nav-link.active {
    color: var(--foreground);
    background-color: var(--accent);
    font-weight: 500;
}

/* Chart palette.
   BlazorBlueprint's chart components read --chart-1..5 (see BbAreaChart et al). themes.css
   ships defaults tuned for its own palettes, which read wrong against the charcoal above, so
   they are defined here for both schemes. Assignment is semantic, not decorative - keep it
   stable so a colour means the same thing on every chart:
     1 delivered · 2 failed · 3 quarantined/degraded · 4 pending · 5 other */
/* CareDx brand colours, sampled from caredx.com and cross-checked against the logo files in
   wwwroot/icons - #A6192E and #BDD6F6 appear in CDNA.svg, #004762 in CDNA_BIG.svg. Reference
   values: use the chart tokens below for data, not these directly. */
:root {
    --brand-petrol:  #004762;   /* headings, footer, buttons.  OKLCh L 0.374  C 0.076  H 232 */
    --brand-crimson: #A6192E;   /* logo mark, top bar.         OKLCh L 0.470  C 0.173  H  20 */
    --brand-red:     #E40032;   /* logo highlight.             OKLCh L 0.580  C 0.234  H  22 */
    --brand-sky:     #BDD6F6;   /* section band.               OKLCh L 0.868  C 0.052  H 255 */
    --brand-butter:  #EACE86;   /* stats band.                 OKLCh L 0.859  C 0.096  H  89 */
    --brand-cream:   #F8EFD6;   /* section band.               OKLCh L 0.953  C 0.034  H  90 */
}

/* Chart palette, derived from those brand hues rather than invented.
   The brand only really has three hue families - red ~21, blue 232-255, gold ~89 - so the five
   series are separated by lightness as much as by hue: the two blues sit 0.13 apart in L so they
   stay distinct even stacked adjacently.

   Every colour is pulled to a usable mid-tone. The brand values themselves are unusable as data
   colours: petrol at L 0.37 is nearly black on a column, and sky and butter at L 0.86 disappear
   against white. Hue is what carries the brand; lightness is what makes it legible.

   Create is the calmest, since it carries ~60% of every column and a dominant series should not
   also be the loudest. Failed keeps the most chroma - it is a small slice that must be noticed. */
:root {
    --chart-1: oklch(0.6200 0.0850 232);   /* petrol blue - delivered / Create */
    --chart-2: oklch(0.5800 0.1500 21);    /* crimson     - failed */
    --chart-3: oklch(0.7200 0.1050 55);    /* amber       - quarantined */
    --chart-4: oklch(0.7550 0.0700 250);   /* sky blue    - Complete */
    --chart-5: oklch(0.7800 0.0950 89);    /* butter gold - Cancel */
}

html[data-base-color].dark,
html.dark[data-base-color] {
    /* Lifted so they separate from the charcoal, with chroma trimmed - the same saturation reads
       brighter on a dark ground than on white. */
    --chart-1: oklch(0.6900 0.0800 232);
    --chart-2: oklch(0.6450 0.1350 21);
    --chart-3: oklch(0.7700 0.0950 55);
    --chart-4: oklch(0.7950 0.0650 250);
    --chart-5: oklch(0.8200 0.0850 89);
}

/* Utilities missing from BlazorBlueprint's prebuilt stylesheet.
   There is no Tailwind build step in this app - blazorblueprint.css ships pre-compiled and only
   contains the utilities BlazorBlueprint itself uses. Anything else, including every arbitrary
   value like max-w-[1600px], is simply absent, so the class silently does nothing. That is not
   obvious from the markup: it looks like ordinary Tailwind and fails without error.

   Declared here with their Tailwind names so existing markup keeps working. Audit with the
   snippet in the session notes if spacing ever looks ignored again. */
.mt-1\.5 { margin-top: 0.375rem; }
.pt-5 { padding-top: 1.25rem; }
.py-0\.5 { padding-top: 0.125rem; padding-bottom: 0.125rem; }
.ml-4 { margin-left: 1rem; }

.border-y {
    border-top-width: 1px;
    border-bottom-width: 1px;
    border-style: solid;
}

.max-w-\[1600px\] { max-width: 1600px; }
.max-w-\[280px\] { max-width: 280px; }
.w-\[170px\] { width: 170px; }
.text-\[10px\] { font-size: 10px; line-height: 1; }

.text-muted-foreground\/60 {
    color: color-mix(in oklch, var(--muted-foreground) 60%, transparent);
}

/* Responsive variants.

   BlazorBlueprint's prebuilt stylesheet carries NO breakpoint variants at all - not one `lg:`
   rule anywhere in the file - so every `lg:grid-cols-*` in this app was silently inert and the
   grids stayed at their base column count on every screen size. Declared here at Tailwind's own
   lg breakpoint (64rem) so the markup means what it says. Add further variants here as markup
   needs them rather than reaching for a Tailwind build step for a handful of rules. */
@media (min-width: 64rem) {
    .lg\:grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .lg\:grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* Legend swatch for the hand-rolled chart legends.

   Radzen's own legend is switched off on the donut: it wrapped onto two rows inside the plot
   area, which both shrank the chart and pushed the pie off-centre, breaking the centred label
   overlaid on it. Rendering the legend in the card footer instead costs one class. */
.app-legend-dot {
    display: inline-block;
    width: 0.625rem;
    height: 0.625rem;
    border-radius: 9999px;
    flex: none;
}

/* Per-column hover.
   Radzen has no notion of highlighting a single data point on a column chart. Its only chart
   hover is series-level: AllowSeriesHover adds .rz-chart-series-hover, whose rules highlight the
   whole series and dim the others - which on a single-series chart reads as the entire chart
   reacting to one bar. That is switched off on the component; this fills the gap.

   Only the hovered column changes. Deliberately not dimming the rest: the point is to pick one
   bar out, not to repaint the chart every time the pointer crosses it.

   Both path and rect are targeted because Radzen's column geometry differs by radius setting. */
.rz-column-series path,
.rz-column-series rect,
.rz-bar-series path,
.rz-bar-series rect {
    transition: filter 120ms ease;
}

.rz-column-series path:hover,
.rz-column-series rect:hover,
.rz-bar-series path:hover,
.rz-bar-series rect:hover {
    /* Darken on light surfaces: the columns are mid-tones on white, so going down reads as
       "active" more clearly than going up. */
    filter: brightness(0.88);
    cursor: pointer;
}

html[data-base-color].dark .rz-column-series path:hover,
html[data-base-color].dark .rz-column-series rect:hover,
html.dark[data-base-color] .rz-column-series path:hover,
html.dark[data-base-color] .rz-column-series rect:hover {
    /* Inverted against charcoal - darkening a bar on a dark ground just makes it disappear. */
    filter: brightness(1.2);
}

/* Flat surfaces. BbCard ships shadow-sm; this app reads better as flat panels separated by
   borders alone, so the shadow is removed globally rather than per-usage. */
.shadow-sm,
.shadow,
.shadow-md {
    box-shadow: none !important;
}

/* Filter select.
   Not BbNativeSelect: that component does not write a non-string bound value onto the
   underlying <select>, so an int-valued select renders with selectedIndex -1 (verified in the
   browser - the `selected` attribute was present on the right option but the component reset
   .value afterwards). A plain <select> with Blazor's own @bind binds correctly. The class list
   mirrors what BbNativeSelect emits so the two look identical, and data-bb-native-select keeps
   the library's chevron styling. */
.app-select {
    display: flex;
    height: 2.5rem;
    padding: 0.5rem 0.75rem;
    border-radius: 0.375rem;
    border: 1px solid var(--input);
    background-color: var(--background);
    color: var(--foreground);
    font-size: 0.875rem;
    line-height: 1.25rem;
    appearance: none;
}

.app-select:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--ring);
}

/* Radzen chart chrome, re-pointed at this app's tokens.
   Radzen ships a light palette baked into :root in default-base.css. Rather than swapping to
   dark-base.css when the theme toggles - two stylesheets to keep in sync with BbDarkModeToggle -
   only the variables the charts actually use are remapped. These inherit from
   --background/--foreground/--border, so light and dark follow the app automatically.

   Names taken from Radzen's own :root block, not guessed. An earlier version invented
   --rz-chart-tooltip-background-color (no such variable, so it did nothing) and set
   --rz-base-background-color to transparent - which the tooltip background derives from, so the
   tooltip rendered with no background at all.

   Series colours are NOT set here: pass --chart-1..5 explicitly per series so a colour keeps
   the same meaning across every chart. */
:root {
    --rz-text-color: var(--foreground);
    --rz-text-secondary-color: var(--muted-foreground);
    --rz-border-color: var(--border);

    /* Axis labels, gridlines and ticks. */
    --rz-chart-tick-line-color: var(--border);
    --rz-chart-grid-line-color: var(--border);
    --rz-chart-axis-line-color: var(--border);
    --rz-chart-title-color: var(--foreground);
    --rz-chart-subtitle-color: var(--muted-foreground);

    /* Tooltip, so it reads as part of this app rather than of Radzen. --rz-chart-tooltip-background
       is the real name; it normally derives from --rz-base-background-color, which is deliberately
       left alone here so nothing else that inherits from it loses its background. */
    --rz-chart-tooltip-background: var(--popover);
    --rz-chart-tooltip-color: var(--popover-foreground);
    --rz-chart-tooltip-border-radius: 0.5rem;
    --rz-tooltip-padding: 0.375rem 0.625rem;
    --rz-tooltip-shadow: 0 6px 16px -6px rgb(0 0 0 / 28%);
}

/* The chart's own surface should be the card it sits on, not Radzen's white. Set on the element
   rather than through --rz-base-background-color, which the tooltip also derives from. */
.rz-chart,
.rz-chart svg {
    background: transparent;
}

/* Radzen borders the tooltip in the series colour. Against this app's cards a neutral hairline
   sits better, and the value inside already carries the colour. */
.rz-chart-tooltip-content {
    border: 1px solid var(--border) !important;
    background: var(--popover);
    color: var(--popover-foreground);
}

/* Radzen sizes its text off its own font stack; inherit the app's instead. */
.rz-chart text {
    font-family: inherit;
}

/* Chart card: a plot resting on a single sheet that shows only beneath it.

   The outer element is the sheet. The plot sits flush against its top and sides, so the sheet
   is visible as one band along the bottom carrying the footer - not as a frame on four sides.
   The heading lives outside this card entirely, as page text above it. */
.app-chart-card {
    background: var(--chart-sheet);
    border: 1px solid var(--border);
    border-radius: 1rem;
    padding: 0;
    overflow: hidden;
}

.app-chart-plot {
    background: var(--chart-surface);

    /* Top corners match the outer radius so the two edges coincide exactly where they meet;
       the bottom pair stays rounded so the plot reads as a card resting on the sheet. */
    border-radius: 1rem 1rem 0.75rem 0.75rem;

    /* Downward only - a large negative spread keeps it off the sides, so the plot casts onto
       the band below rather than floating over the page. A deliberate exception to the
       flat-surfaces rule below; without it the two surfaces read as one tinted panel. */
    box-shadow: 0 6px 12px -7px rgb(0 0 0 / 22%);
}

html[data-base-color].dark .app-chart-plot,
html.dark[data-base-color] .app-chart-plot {
    /* Shadows carry almost no contrast against charcoal, so darken considerably to keep the
       layering readable in dark mode. */
    box-shadow: 0 6px 14px -7px rgb(0 0 0 / 62%);
}

/* Light: the plot is pure white and the sheet a step down, so the data is the brightest thing
   on the page. Dark inverts the lightness but keeps that relationship - plot lighter than
   sheet - so the sheet still recedes rather than competing with the columns. */
:root {
    --chart-surface: oklch(1 0 0);
    --chart-sheet: oklch(0.9700 0 0);
}

html[data-base-color].dark,
html.dark[data-base-color] {
    --chart-surface: oklch(0.2400 0 0);
    --chart-sheet: oklch(0.1750 0 0);
}

/* ---------------------------------------------------------------------------
   Sign-in page.

   The page itself is built from utility classes, as the rest of the app is. Only what the
   prebuilt stylesheet is missing is declared here - see the note further up: blazorblueprint.css
   carries only the utilities BlazorBlueprint itself uses, so anything else silently does
   nothing. Checked against the file rather than assumed.
   --------------------------------------------------------------------------- */

/* The stylesheet contains no hover: variants at all - one occurrence in the whole file - so
   every hover: utility is inert. Declared with their Tailwind names so the markup means what
   it says, here and anywhere else that reaches for them. */
.hover\:underline:hover { text-decoration-line: underline; }
.hover\:text-primary:hover { color: var(--primary); }

/* The SSO button: 44px tall and spanning the column, so the one action on the page carries
   some weight and the Salesforce mark has room to sit at full size.

   Declared here rather than as utilities for the same reason as .app-icon-circle: the height
   has to beat the component's own size class, which it does at equal specificity because
   app.css is linked last. Width comes from w-full in the markup. */
.app-login-sso {
    /* The two knobs worth touching. Width is fixed rather than w-full so the button does not
       span the whole 24rem column, and fixed rather than fit-content so the label and the mark
       can change size without the button resizing around them. */
    width: 14rem;
    height: 2rem;
    min-height: 2.5rem;
    padding-inline: 1rem;
    gap: 0;

    /* Centres itself rather than relying on the wrapper. As a fixed-width block-level flex
       box, auto inline margins split the leftover column space evenly - which holds whether
       or not the parent is a flex container, so the button cannot end up flush left again. */
    display: flex;
    align-items: center;
    justify-content: center;
    margin-inline: auto;
}

/* The theme toggle is chrome, so it is pinned to the viewport corner rather than placed in
   the centred stack. */
.app-login-theme {
    position: absolute;
    top: 1rem;
    right: 1rem;
    z-index: 20;
}

/* The app shell sets body{overflow:hidden} for the pinned dashboard layout. The sign-in page
   is a normal centred document, and min-h-screen inside a non-scrolling body clips its own
   bottom on a short viewport, so scrolling is restored while this page is shown. */
body:has(.app-login-theme) {
    overflow: auto;
}
