/*
    The app skin.

    Every colour, size, spacing step and radius here comes from a custom property defined in
    css/tokens.css, which is GENERATED from design/tokens.json. Never write a raw hex value in this
    file: the same tokens are generated into design/generated/Tokens.xaml for the MAUI app, and a hex
    value written here is a colour that exists on web and nowhere else.

    Sections:
      1. Bootstrap, re-pointed at our tokens
      2. Page basics
      3. Numbers
      4. The shared UI kit  (Components/Ui - StatTile, StatusChip, InfoHint, Disclosure, EmptyState, AppModal)
      5. Bootstrap popovers and modals, re-skinned
      6. Motion, focus and Blazor's own furniture
*/

/* =========================================================================
   1. Bootstrap, re-pointed at our tokens

   Mapped with var(), not with copied hex values. --ground and the rest are redefined per theme in
   tokens.css, and var() resolves at use time, so every Bootstrap component follows the theme from
   this one block. ui.js also stamps data-bs-theme on <html> so Bootstrap's own dark variants cover
   anything not listed here.
   ========================================================================= */
:root {
    --bs-body-font-family: var(--font-ui);
    --bs-body-font-size: var(--text-base);
    --bs-body-line-height: var(--leading-normal);
    --bs-body-color: var(--ink);
    --bs-body-bg: var(--ground);
    --bs-emphasis-color: var(--ink);
    --bs-secondary-color: var(--muted);
    --bs-tertiary-bg: var(--sunken);
    --bs-border-color: var(--rule);
    --bs-border-radius: var(--radius-md);
    --bs-border-radius-sm: var(--radius-sm);
    --bs-border-radius-lg: var(--radius-lg);
    --bs-border-radius-pill: var(--radius-pill);
    --bs-heading-color: var(--ink);

    --bs-primary: var(--accent);
    --bs-link-color: var(--accent);
    --bs-link-hover-color: var(--accent);
    --bs-code-color: var(--accent);

    /* The semantic three, and nothing else, carry meaning. */
    --bs-success: var(--ok);
    --bs-warning: var(--warn);
    --bs-danger: var(--crit);

    --bs-font-monospace: var(--font-mono);
}

/* =========================================================================
   2. Page basics
   ========================================================================= */
html {
    /* Interface text sits at 15px, which is the --text-base token. */
    font-size: 100%;
}

body {
    /* Explicit, not inherited. A transparent body borrows whatever is behind the page. */
    background-color: var(--ground);
    color: var(--ink);
    font-family: var(--font-ui);
    font-size: var(--text-base);
    line-height: var(--leading-normal);
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, h5, h6 {
    color: var(--ink);
    font-weight: var(--weight-semibold);
    line-height: var(--leading-snug);
}

h1 { font-size: var(--text-xl); }
h2 { font-size: var(--text-lg); }
h3 { font-size: var(--text-md); }
h4, h5, h6 { font-size: var(--text-base); }

h1:focus {
    outline: none;
}

a {
    color: var(--accent);
    text-decoration-thickness: 1px;
    text-underline-offset: 0.15em;
}

code, kbd, samp, pre {
    font-family: var(--font-mono);
}

hr {
    border-color: var(--rule);
    opacity: 1;
}

.content {
    padding-top: var(--space-4);
}

/* A card. The default surface for anything that groups. */
.card {
    --bs-card-bg: var(--surface);
    --bs-card-border-color: var(--rule);
    --bs-card-border-radius: var(--radius-md);
    --bs-card-inner-border-radius: var(--radius-md);
    --bs-card-spacer-y: var(--space-4);
    --bs-card-spacer-x: var(--space-4);
}

.btn {
    --bs-btn-border-radius: var(--radius-sm);
    font-weight: var(--weight-medium);
}

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

.btn-primary:hover,
.btn-primary:focus-visible {
    filter: brightness(1.12);
}

.btn-outline-secondary {
    --bs-btn-color: var(--ink);
    --bs-btn-border-color: var(--rule);
    --bs-btn-hover-bg: var(--sunken);
    --bs-btn-hover-border-color: var(--muted);
    --bs-btn-hover-color: var(--ink);
    --bs-btn-active-bg: var(--sunken);
    --bs-btn-active-border-color: var(--muted);
    --bs-btn-active-color: var(--ink);
}

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

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

.text-muted {
    color: var(--muted) !important;
}

.small, small {
    font-size: var(--text-sm);
}

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

/* Wide content scrolls inside its own box. The page body never scrolls sideways. */
.ctt-scroll-x {
    overflow-x: auto;
}

/*
   The one line under a page heading that carries the section 8 disclaimer. Body text, never a muted
   caption: it is the sentence the app is required to keep visible, so it gets full contrast.

   Shared, not scoped per page. Three pages had written their own copy of this rule, which meant a
   fourth page using the same class name silently got no styling at all.
*/
.ctt-page-note {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
    color: var(--ink);
    max-width: 68ch;
    margin-bottom: var(--space-4);
}

/* =========================================================================
   3. Numbers

   Tabular figures everywhere a digit lines up under another digit. Proportional digits make a column
   of day counts look ragged, and this app is a column of day counts.
   ========================================================================= */
.ctt-nums,
.ctt-figure,
.ctt-tile__figure,
.ctt-tile__unit,
table td,
table th,
time,
output {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

/* =========================================================================
   4. The shared UI kit

   These class names belong to src/CTT.Web/Components/Ui. Any page may use the components; no page
   should reach past them and restyle these classes.
   ========================================================================= */

/* ---- StatTile ---- */
.ctt-tile {
    background-color: var(--surface);
    border: 1px solid var(--rule);
    border-left: 3px solid var(--rule);
    border-radius: var(--radius-md);
    padding: var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

/* The status colour is a left edge, not a fill. A filled card shouts; an edge marks. */
.ctt-tile--ok { border-left-color: var(--ok); }
.ctt-tile--warn { border-left-color: var(--warn); }
.ctt-tile--crit { border-left-color: var(--crit); }

.ctt-tile__label {
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    color: var(--muted);
    line-height: var(--leading-snug);
    display: flex;
    align-items: center;
    gap: var(--space-1);
    flex-wrap: wrap;
}

.ctt-tile__value {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
    flex-wrap: wrap;
}

.ctt-tile__figure {
    font-size: var(--text-figure);
    font-weight: var(--weight-semibold);
    line-height: var(--leading-tight);
    color: var(--ink);
}

.ctt-tile--sm .ctt-tile__figure {
    font-size: var(--text-figure-sm);
}

/* No answer is not a small number. It is a sentence, in muted type, where the number would be. */
.ctt-tile__figure--none {
    font-size: var(--text-md);
    font-weight: var(--weight-medium);
    color: var(--muted);
    line-height: var(--leading-snug);
}

.ctt-tile__figure--ok { color: var(--ok); }
.ctt-tile__figure--warn { color: var(--warn); }
.ctt-tile__figure--crit { color: var(--crit); }

.ctt-tile__unit {
    font-size: var(--text-sm);
    color: var(--muted);
}

.ctt-tile__caption {
    font-size: var(--text-sm);
    color: var(--muted);
    line-height: var(--leading-snug);
}

.ctt-tile__chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

/* ---- StatusChip ----
   Always visible, always short. The chip is the warning; the popover behind it is the explanation.
   Text on a wash is always --ink, so the chip reads at full contrast whatever it means. */
.ctt-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: 0.1rem var(--space-2);
    border: 1px solid var(--rule);
    border-radius: var(--radius-pill);
    background-color: var(--sunken);
    color: var(--ink);
    font-size: var(--text-xs);
    font-weight: var(--weight-medium);
    line-height: var(--leading-snug);
    white-space: nowrap;
    max-width: 100%;
}

/* A chip that explains itself is a button, and must not look like body text got a border. */
button.ctt-chip {
    cursor: help;
    text-align: left;
}

.ctt-chip__icon {
    font-size: var(--text-xs);
    line-height: 1;
}

.ctt-chip--ok {
    background-color: var(--ok-wash);
    border-color: var(--ok);
}

.ctt-chip--ok .ctt-chip__icon { color: var(--ok); }

.ctt-chip--warn {
    background-color: var(--warn-wash);
    border-color: var(--warn);
}

.ctt-chip--warn .ctt-chip__icon { color: var(--warn); }

.ctt-chip--crit {
    background-color: var(--crit-wash);
    border-color: var(--crit);
}

.ctt-chip--crit .ctt-chip__icon { color: var(--crit); }

.ctt-chip--neutral .ctt-chip__icon { color: var(--muted); }

/* ---- InfoHint ----
   The one control that carries prose off the page. Small, quiet, and reachable by keyboard. */
.ctt-hint {
    appearance: none;
    -webkit-appearance: none;
    background: none;
    border: 0;
    padding: 0 0.1rem;
    margin: 0;
    color: var(--muted);
    line-height: 1;
    cursor: help;
    border-radius: var(--radius-sm);
    vertical-align: baseline;
}

.ctt-hint:hover {
    color: var(--accent);
}

/* ---- Disclosure ----
   Level 2: the working, one click away. Collapsed on every load; it remembers nothing on purpose,
   because a panel that reopens itself hides the change from the reader who closed it. */
.ctt-disclosure {
    border-top: 1px solid var(--rule);
    margin-top: var(--space-3);
}

.ctt-disclosure__toggle {
    appearance: none;
    -webkit-appearance: none;
    background: none;
    border: 0;
    padding: var(--space-2) 0;
    width: 100%;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    color: var(--accent);
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    text-align: left;
    cursor: pointer;
    border-radius: var(--radius-sm);
}

.ctt-disclosure__toggle:hover {
    text-decoration: underline;
}

.ctt-disclosure__chevron {
    color: var(--muted);
    font-size: var(--text-xs);
    line-height: 1;
}

.ctt-disclosure__body {
    padding-bottom: var(--space-3);
    font-size: var(--text-sm);
    color: var(--ink);
}

/* ---- EmptyState ---- */
.ctt-empty {
    background-color: var(--surface);
    border: 1px dashed var(--rule);
    border-radius: var(--radius-md);
    padding: var(--space-6) var(--space-4);
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-3);
}

.ctt-empty__icon {
    font-size: var(--text-xl);
    color: var(--muted);
    line-height: 1;
}

.ctt-empty__line {
    color: var(--ink);
    font-size: var(--text-base);
    max-width: 46ch;
    margin: 0;
}

/* ---- Layout helpers the kit expects ---- */
.ctt-tile-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    gap: var(--space-3);
}

.ctt-chip-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    align-items: center;
}

/* =========================================================================
   5. Bootstrap popovers and modals, re-skinned

   Level 3. Everything that is prose lives in here, so it has to be readable: full body size, normal
   line height, and a real surface behind it.
   ========================================================================= */
.popover {
    --bs-popover-bg: var(--surface);
    --bs-popover-border-color: var(--rule);
    --bs-popover-border-radius: var(--radius-md);
    --bs-popover-inner-border-radius: var(--radius-md);
    --bs-popover-header-bg: var(--sunken);
    --bs-popover-header-color: var(--ink);
    --bs-popover-header-font-size: var(--text-sm);
    --bs-popover-body-color: var(--ink);
    --bs-popover-body-padding-x: var(--space-3);
    --bs-popover-body-padding-y: var(--space-3);
    --bs-popover-font-size: var(--text-sm);
    --bs-popover-max-width: 22rem;
    box-shadow: 0 0.5rem 1.25rem rgb(0 0 0 / 0.18);
}

.popover-header {
    font-weight: var(--weight-semibold);
}

.popover-body {
    line-height: var(--leading-normal);
}

.popover-body p:last-child {
    margin-bottom: 0;
}

.modal {
    --bs-modal-bg: var(--surface);
    --bs-modal-color: var(--ink);
    --bs-modal-border-color: var(--rule);
    --bs-modal-border-radius: var(--radius-lg);
    --bs-modal-header-border-color: var(--rule);
    --bs-modal-footer-border-color: var(--rule);
    --bs-modal-padding: var(--space-4);
}

.modal-title {
    font-size: var(--text-md);
    font-weight: var(--weight-semibold);
}

.tooltip {
    --bs-tooltip-bg: var(--ink);
    --bs-tooltip-color: var(--ground);
    --bs-tooltip-border-radius: var(--radius-sm);
    --bs-tooltip-font-size: var(--text-xs);
    --bs-tooltip-opacity: 1;
}

.alert {
    --bs-alert-border-radius: var(--radius-md);
}

/* =========================================================================
   6. Motion, focus and Blazor's own furniture
   ========================================================================= */

/* One focus ring for the whole app, on the token colour so it stays visible on an accent button. */
:focus-visible {
    outline: 2px solid var(--focus);
    outline-offset: 2px;
}

.btn:focus,
.btn:active:focus,
.btn-link.nav-link:focus,
.form-control:focus,
.form-check-input:focus {
    /* Bootstrap's own glow, replaced by the ring above. */
    box-shadow: none;
}

/*
    Nothing animates for a reader who asked for no motion. Bootstrap's collapse and fade both animate
    by default, so they are switched off rather than shortened - a 1ms transition still fires events
    in an order that assumes a transition.
*/
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
        scroll-behavior: auto !important;
    }

    .collapsing {
        transition: none !important;
    }
}

/* An icon that means something is never hidden from a screen reader; a decorative one always is. */
.bi[aria-hidden="true"] {
    speak: none;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid var(--ok);
}

.invalid {
    outline: 1px solid var(--crit);
}

.validation-message {
    color: var(--crit);
    font-size: var(--text-sm);
}

#blazor-error-ui {
    color-scheme: light only;
    background: #fff8d6;
    color: #12191c;
    bottom: 0;
    box-shadow: 0 -1px 2px rgb(0 0 0 / 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

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

.blazor-error-boundary {
    background: var(--crit);
    padding: var(--space-4);
    color: #ffffff;
    border-radius: var(--radius-md);
}

.blazor-error-boundary::after {
    content: "An error has occurred.";
}

.loading-progress {
    position: absolute;
    display: block;
    width: 8rem;
    height: 8rem;
    inset: 20vh 0 auto 0;
    margin: 0 auto 0 auto;
}

.loading-progress circle {
    fill: none;
    stroke: var(--sunken);
    stroke-width: 0.6rem;
    transform-origin: 50% 50%;
    transform: rotate(-90deg);
}

.loading-progress circle:last-child {
    stroke: var(--accent);
    stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
    transition: stroke-dasharray 0.05s ease-in-out;
}

.loading-progress-text {
    position: absolute;
    text-align: center;
    font-weight: var(--weight-semibold);
    color: var(--ink);
    inset: calc(20vh + 3.25rem) 0 auto 0.2rem;
}

.loading-progress-text:after {
    content: var(--blazor-load-percentage-text, "Loading");
}

.form-floating > .form-control-plaintext::placeholder,
.form-floating > .form-control::placeholder {
    color: var(--muted);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder,
.form-floating > .form-control:focus::placeholder {
    text-align: start;
}

/* Popover bodies from InfoHint and StatusChip are plain text, set with textContent so rule data
   cannot inject markup. pre-line is what turns the paragraph breaks in that text into real breaks. */
.ctt-popover .popover-body {
    white-space: pre-line;
}

/* EmptyState: one short line under the action, and nothing more. */
.ctt-empty__extra {
    font-size: var(--text-sm);
    color: var(--muted);
    max-width: 46ch;
}

/* =========================================================================
   9. The rest of Bootstrap, pointed at the tokens

   These were written in Layout/MainLayout.razor.css as ::deep rules while app.css was believed to
   have no token wiring in it. It does, so keeping a second copy there meant two files to change and
   two chances for the app to disagree with itself about what amber is. Here they are global, which
   is what an app-wide skin should be.

   Every value is a token. No hex, no font stack, no rule, no threshold, no country.
   ========================================================================= */

.btn-link {
    color: var(--accent);
}

code {
    color: var(--accent);
    font-family: var(--font-mono);
}

.btn-outline-primary {
    border-color: var(--accent);
    color: var(--accent);
    background-color: transparent;
}

.btn-outline-secondary:hover,
.btn-outline-primary:hover {
    background-color: var(--accent);
    color: var(--accent-ink);
}

.btn-outline-danger {
    border-color: var(--crit);
    color: var(--crit);
    background-color: transparent;
}

.btn-outline-danger:hover {
    background-color: var(--crit);
    color: var(--accent-ink);
}

.list-group-item {
    background-color: var(--surface);
    border-color: var(--rule);
    color: var(--ink);
}

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

/* Alerts: the semantic colours as a wash and a border, with ink on top. Never a filled block - a
   card filled red is a card the reader learns to close, and some of these carry the warning. */
.alert-secondary,
.alert-info,
.alert-light {
    background-color: var(--sunken);
    border-color: var(--rule);
}

.alert-success {
    background-color: var(--ok-wash);
    border-color: var(--ok);
}

.alert-warning {
    background-color: var(--warn-wash);
    border-color: var(--warn);
}

.alert-danger {
    background-color: var(--crit-wash);
    border-color: var(--crit);
}

/* Bootstrap's contextual badges. Kept because older screens still use them; the semantic tokens
   mean one thing each, so a bg-success badge can never be the accent by accident. */
.badge.bg-success {
    background-color: var(--ok) !important;
}

.badge.bg-warning {
    background-color: var(--warn) !important;
    color: var(--accent-ink) !important;
}

.badge.bg-danger {
    background-color: var(--crit) !important;
}

.badge.bg-secondary {
    background-color: var(--muted) !important;
}

/* =========================================================================================
   THE APP MARK
   =========================================================================================
   BrandGlyph renders an <svg> carrying only a viewBox, which has NO intrinsic size inside a
   flex row - so with no width it collapses to zero and the logo is silently absent. That
   already happened once, when a size rule was written without ::deep and matched nothing.

   A default size here means the mark is always visible. A surface that wants a different one
   overrides it, and a surface that forgets still gets a logo rather than a gap. This file is
   global and unscoped, so it reaches the svg wherever BrandGlyph is used.

   Colours are deliberately NOT set here: they come from --brand-deep, --brand-soft and
   --brand-cut, which the component already defaults to accent, accent-soft and ground. Only a
   surface that changes its own background needs to restate them - the accent-filled title bar
   is the one that does. */
.brand-glyph {
    width: 1.5rem;
    height: 1.5rem;
    flex: none;
}

/* =========================================================================================
   THE LEGAL PAGES
   =========================================================================================
   The privacy policy and the terms. Global rather than scoped to the component, because these
   are the only pages in the app that are mostly prose, and prose needs different rules from a
   dashboard: a measure narrow enough to read, and headings that separate parts rather than
   label tiles.

   A measure of 68 characters, not the full column width. A policy set across a wide screen is
   a policy nobody finishes, and these two pages exist to be read rather than skimmed. */
.legal {
    max-width: 68ch;
}

.legal__head {
    margin-bottom: var(--space-6);
}

.legal__draft {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    margin: var(--space-4) 0;
}

.legal__lede {
    font-size: var(--text-md);
    color: var(--muted);
    line-height: var(--leading-normal);
}

.legal__date {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    color: var(--muted);
    margin: 0;
}

/* A card per part, so a reader can see where one ends. Sections in flat prose all run together. */
.legal__section {
    background: var(--surface);
    border: 1px solid var(--rule);
    border-radius: var(--radius-lg);
    padding: var(--space-5);
    margin-bottom: var(--space-4);

    /* The fragment links land here, and a heading flush against the top of the viewport reads as
       though the section above it is missing. */
    scroll-margin-top: var(--space-7);
}

.legal__section h2 {
    display: flex;
    align-items: baseline;
    gap: var(--space-3);
    font-size: var(--text-lg);
    line-height: var(--leading-snug);
    margin: 0 0 var(--space-3);
}

/* The number is the part's address, the thing somebody quotes on the phone. Monospace and quiet:
   it identifies the part without competing with what the part says. */
.legal__number {
    font-family: var(--font-mono);
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    color: var(--accent);
    flex: none;
}

.legal__section p {
    margin: 0 0 var(--space-3);
}

.legal__section p:last-child,
.legal__section ul:last-child {
    margin-bottom: 0;
}

.legal__section ul {
    margin: 0 0 var(--space-3);
    padding-left: 1.25rem;
    display: grid;
    gap: var(--space-2);
}

.legal__toc {
    background: var(--sunken);
    border-radius: var(--radius-md);
    padding: var(--space-4) var(--space-5);
    margin-bottom: var(--space-5);
}

.legal__toc ol {
    margin: 0;
    padding-left: 1.5rem;
    display: grid;
    gap: var(--space-1);
    font-size: var(--text-sm);
}

.legal__toc li::marker {
    font-family: var(--font-mono);
    color: var(--muted);
}

.legal__foot {
    font-size: var(--text-sm);
    color: var(--muted);
    margin-top: var(--space-5);
}
