/* Plotstead — dark theme, matching the FineDay / Tideline NZ house style.
   Design tokens + base elements + shared button/input primitives only.
   Component styles live in their .razor.css files. */

@font-face { font-family: "Inter"; font-style: normal; font-weight: 400; font-display: swap; src: url("fonts/Inter-Regular.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 500; font-display: swap; src: url("fonts/Inter-Medium.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 600; font-display: swap; src: url("fonts/Inter-SemiBold.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 700; font-display: swap; src: url("fonts/Inter-Bold.woff2") format("woff2"); }

/* Dark is the default and stays the default: no attribute, no light styles.
   The app writes data-theme="light" or "dark" onto <html> and never "auto" —
   auto is resolved in code against the device, so the CSS only ever deals in
   two concrete themes and the palette is written once each. */
:root {
    --bg: #0d1117;
    --bg-glow: #141b29;
    --bg-card: rgba(26, 31, 46, 0.9);
    --bg-row: rgba(26, 31, 46, 0.4);
    --bg-chip: #1a1f2e;
    --bg-chip-hover: #1f2538;
    --bg-sheet: #141923;
    /* The tab bar, on screen the whole time. */
    --bg-bar: rgba(13, 17, 23, 0.88);
    --border: #252932;
    --border-card: rgba(255, 255, 255, 0.07);
    --border-row: rgba(255, 255, 255, 0.03);
    /* The boundary of every input, select and outline button. At #2a3448 this
       measured 1.32:1 against the field's own fill, which is not a faint border,
       it is no border: a text box with nothing to show where it begins. 3:1 is
       what WCAG asks of a control's edge, and this is the lowest value that
       reaches it while keeping the blue-grey cast. */
    --border-chip: #626d80;
    --text: #ffffff;
    /* Both of these carry real text - list sub-lines, hints, "No date set" -
       and both were below AA: 0.42 measured 4.01:1 and 0.28 measured 3.09:1,
       against the 4.5 needed. Raised to the lowest values that clear it on the
       lightest surface they land on, rather than to round numbers, so the theme
       moves as little as it can while still being readable.

       The gap between them is kept at roughly the original 0.14, so there are
       still two levels of quiet rather than one. */
    --text-dim: rgba(255, 255, 255, 0.6);

    --text-faint: rgba(255, 255, 255, 0.48);

    --text-on-accent: #ffffff;
    --accent: #4a90d9;
    --accent-strong: #58a0e6;
    --amber: #fca01a;
    --green: #69d84f;
    --red: #e06c75;
    --red-strong: #e8808a;

    /* Tints. These were written inline as rgba() of each accent in 58 places,
       which is fine until the surface underneath changes colour: a 12% white-ish
       wash reads as a highlight on a dark card and as dirt on a white one. */
    --accent-soft: rgba(74, 144, 217, 0.12);
    --accent-line: rgba(74, 144, 217, 0.4);
    --amber-soft: rgba(252, 160, 26, 0.12);
    --amber-line: rgba(252, 160, 26, 0.4);
    --green-soft: rgba(105, 216, 79, 0.12);
    --green-line: rgba(105, 216, 79, 0.4);
    --red-soft: rgba(224, 108, 117, 0.12);
    --red-line: rgba(224, 108, 117, 0.4);

    --scrim: rgba(255, 255, 255, 0.18);
    --scrim-strong: rgba(255, 255, 255, 0.36);
    --shadow: rgba(0, 0, 0, 0.45);

    /* The dropdown arrow is an inline SVG, so its stroke is baked into a URL
       rather than inherited. White on a light background is invisible, which is
       exactly the sort of thing that survives a whole theme review unnoticed. */
    --chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='none' stroke='rgba(255,255,255,0.42)' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");

    --radius-card: 16px;
    --radius-chip: 20px;
    --radius-input: 12px;

    /* Subtle depth: a soft sheen for card surfaces, layered over their bg. */
    --sheen: linear-gradient(160deg, rgba(255, 255, 255, 0.05) 0%, rgba(255, 255, 255, 0) 55%);

    /* iOS reports the bottom inset via env(); Android edge-to-edge bridges it
       in natively as --safe-bottom. Use --inset-b wherever content must clear
       the bottom of the screen. */
    --inset-b: max(env(safe-area-inset-bottom, 0px), var(--safe-bottom, 0px));
}

/* Light.
   Every value here was measured rather than eyeballed: text is at or above
   4.5:1 on every surface it can land on, and the input border clears 3:1 on all
   three. The four accent colours are darker than their dark-theme twins because
   the originals are tuned to glow on near-black and sit at around 2:1 on white,
   which is unreadable rather than merely pale. */
:root[data-theme="light"] {
    --bg: #eef1f6;
    --bg-glow: #ffffff;
    --bg-card: #ffffff;
    --bg-row: #f6f8fb;
    --bg-chip: #e4e9f1;
    --bg-chip-hover: #dae1ec;
    --bg-sheet: #ffffff;
    --bg-bar: rgba(255, 255, 255, 0.92);
    --border: #dde3ec;
    --border-card: rgba(15, 23, 42, 0.1);
    --border-row: rgba(15, 23, 42, 0.05);
    --border-chip: #7b8494;
    --text: #11161f;
    --text-dim: #545b68;
    --text-faint: #5f6672;
    --text-on-accent: #ffffff;
    --accent: #2a67a8;
    --accent-strong: #3a7cc0;
    --amber: #945700;
    --green: #2c762f;
    --red: #c0303c;
    --red-strong: #a52833;

    --accent-soft: rgba(42, 103, 168, 0.1);
    --accent-line: rgba(42, 103, 168, 0.35);
    --amber-soft: rgba(148, 87, 0, 0.1);
    --amber-line: rgba(148, 87, 0, 0.35);
    --green-soft: rgba(44, 118, 47, 0.1);
    --green-line: rgba(44, 118, 47, 0.35);
    --red-soft: rgba(192, 48, 60, 0.1);
    --red-line: rgba(192, 48, 60, 0.35);

    --scrim: rgba(15, 23, 42, 0.18);
    --scrim-strong: rgba(15, 23, 42, 0.36);
    --shadow: rgba(15, 23, 42, 0.14);

    --chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='none' stroke='rgba(17,22,31,0.55)' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");

    /* A white-on-white sheen is either invisible or dirty. Nothing is better
       than something here. */
    --sheen: none;
}

* {
    box-sizing: border-box;
}

html, body {
    margin: 0;
    padding: 0;
    height: 100%;
    /* Android's WebView "font boosting" inflates text in any block it decides is
       wide, scaling the words but not the boxes around them. On a phone that
       turned a 12px due date into something half the screen wide, which crushed
       asset names to a sliver and made the tab labels collide. Pinning the
       adjustment means the type scale below is the one that actually renders. */
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
    /* Faint blue-tinted glow at the top so the dark canvas isn't dead flat. */
    background: radial-gradient(120% 60% at 50% 0%, var(--bg-glow) 0%, var(--bg) 60%) fixed, var(--bg);
    color: var(--text);
    font-family: "Inter", system-ui, -apple-system, sans-serif;
    overflow: hidden;
    overscroll-behavior: none;
}

#app {
    height: 100%;
}

h1 {
    font-size: 22px;
    font-weight: 600;
    margin: 0 0 4px;
}

h2 {
    font-size: 15px;
    font-weight: 600;
    margin: 0;
}

a {
    color: var(--accent);
    text-decoration: none;
}

/* ── Focus ──────────────────────────────────────────────────────────── */

/* The router's FocusOnNavigate focuses the page <h1> after every navigation so
   screen readers announce the new screen. Worth keeping — but Chromium then
   paints a focus ring around the title, which reads as text selected by
   accident. (:focus-visible does not help here: Chromium still matches it for
   this programmatic focus.) A heading is not interactive and cannot be tabbed
   to, so suppressing its ring costs keyboard users nothing. */
h1:focus,
h1:focus-visible {
    outline: none;
}

:focus:not(:focus-visible) {
    outline: none;
}

:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: 6px;
}

/* ── Inputs ─────────────────────────────────────────────────────────── */

input, select, textarea {
    background: var(--bg-chip);
    border: 1px solid var(--border-chip);
    border-radius: var(--radius-input);
    color: var(--text);
    font: inherit;
    font-size: 14px;
    padding: 10px 12px;
    outline: none;
}

input::placeholder, textarea::placeholder {
    color: var(--text-faint);
}

input:focus, select:focus, textarea:focus {
    border-color: var(--accent);
}

select {
    appearance: none;
    background-image: var(--chevron);
    background-repeat: no-repeat;
    background-position: right 10px center;
    padding-right: 32px;
}

/* Native date/time picker indicators render black on dark otherwise */
input[type="date"]::-webkit-calendar-picker-indicator {
    filter: invert(0.7);
}

/* Date fields size themselves from the browser's own idea of how wide a date is,
   which does not follow the system font scale. Left to it they stayed the width
   they would be at the default size and clipped the year off - "24/07/" with
   nothing after it. Filling the container instead means the space comes from the
   layout, which does scale. min-width: 0 so they can still shrink inside a grid
   rather than pushing it wider than the screen. */
input[type="date"] {
    width: 100%;
    min-width: 0;
}

/* ── Buttons (bootstrap-compatible class names, house look) ─────────── */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    border: 1px solid transparent;
    border-radius: var(--radius-chip);
    padding: 9px 16px;
    font: inherit;
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    transition: background 0.15s, color 0.15s, border-color 0.15s;
    white-space: nowrap;
}

.btn i {
    font-size: 17px;
}

.btn-primary {
    background: linear-gradient(180deg, var(--accent-strong) 0%, var(--accent) 100%);
    color: var(--text-on-accent);
}

.btn-primary:hover {
    background: linear-gradient(180deg, var(--accent-strong) 0%, var(--accent-strong) 100%);
}

.btn-primary:disabled {
    background: var(--bg-chip);
    color: var(--text-faint);
    cursor: default;
}

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

.btn-outline-primary:hover {
    background: var(--bg-chip-hover);
}

.btn-outline-secondary {
    background: var(--bg-chip);
    border-color: var(--border-chip);
    color: var(--text-dim);
}

.btn-outline-secondary:hover {
    background: var(--bg-chip-hover);
    color: var(--text);
}

.btn-outline-danger {
    background: none;
    border-color: var(--red-line);
    color: var(--red);
}

.btn-outline-danger:hover {
    background: var(--red-soft);
}

.btn-sm {
    padding: 5px 12px;
    font-size: 13px;
}

.btn-link {
    background: none;
    border: none;
    color: var(--accent);
    padding: 0;
    font: inherit;
    cursor: pointer;
}

.p-0 { padding: 0; }
.align-baseline { vertical-align: baseline; }

/* ── Shared primitives ──────────────────────────────────────────────── */

.medallion {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border-radius: 11px;
    flex-shrink: 0;
}

.medallion i {
    font-size: 20px;
}

/* The bar itself is drawn by the pseudo-element, so the element can be tall
   enough to actually grab: 4px of hittable area is nothing, and this is a drag
   handle now rather than decoration. touch-action stops the browser scrolling
   the sheet out from under the gesture.

   Still hidden above 640px below — dragging a sheet away is a touch gesture, and
   on a desktop the backdrop and Cancel are both easier. */
.sheet-handle {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 24px;
    margin: -6px 0 2px;
    flex-shrink: 0;
    cursor: grab;
    touch-action: none;
}

.sheet-handle::before {
    content: "";
    width: 36px;
    height: 4px;
    border-radius: 2px;
    background: var(--scrim);
    transition: background 0.15s;
}

.sheet-handle:active {
    cursor: grabbing;
}

.sheet-handle:active::before {
    background: var(--scrim-strong);
}

@media (min-width: 640px) {
    .sheet-handle {
        display: none;
    }
}

.empty-state {
    text-align: center;
    padding: 44px 16px;
    color: var(--text-dim);
    font-size: 14px;
}

.empty-state i {
    display: block;
    font-size: 34px;
    color: var(--text-faint);
    margin-bottom: 8px;
}

/* ── Scrollbars (thin, dark-friendly) ───────────────────────────────── */

.content-scroll, .modal-scroll {
    scrollbar-width: thin;
    scrollbar-color: var(--scrim) transparent;
    scrollbar-gutter: stable;
}

.content-scroll::-webkit-scrollbar, .modal-scroll::-webkit-scrollbar {
    width: 6px;
}

.content-scroll::-webkit-scrollbar-track, .modal-scroll::-webkit-scrollbar-track {
    background: transparent;
}

.content-scroll::-webkit-scrollbar-thumb, .modal-scroll::-webkit-scrollbar-thumb {
    background: var(--scrim);
    border-radius: 3px;
}

/* Bounds the reading column without bounding the scroll container.
   Deliberately the children rather than a wrapper element: the map page is
   height:100% against main, so an extra div between them collapses it. And
   deliberately here rather than in MainLayout.razor.css, because scoped CSS
   rewrites "main > *" to match only MainLayout's own elements, and every one of
   these belongs to the page being rendered.

   No effect below 900px, where the window is narrower than this anyway. */
main > * {
    max-width: 1440px;
}

/* Except the overlays, which are not content.

   A modal renders at the top level of whatever page opened it, so its backdrop
   lands as a direct child of main and gets capped along with everything else.
   It is position: fixed with inset: 0, so it asks to be the size of the window
   — and then stops at 1440px. On a 2K screen that dims the app and leaves a
   bright undimmed strip down the right-hand side, with the dialog's own shadow
   ending in mid-air.

   Matched on the class rather than listed one by one, because every one of the
   thirteen overlays is already named *-backdrop and a hand-written list would be
   out of date the first time somebody adds a fourteenth. */
main > [class*="backdrop"] {
    max-width: none;
}

/* ── Loading screen (pre-Blazor) ────────────────────────────────────── */

.loading-screen {
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 18px;
    background: var(--bg);
}

.loading-logo {
    color: var(--text);
    font-size: 22px;
    font-weight: 600;
}

.loading-logo-accent {
    color: var(--accent);
}

/* ── System chrome ──────────────────────────────────────────────────── */

.status-bar-safe-area {
    background-color: var(--bg);
    height: env(safe-area-inset-top);
    width: 100%;
    position: fixed;
    top: 0;
    z-index: 999;
}

/* Blazor's own bar, shown when something fails after the app is already running.
   Left on the template's lightyellow until now, which on a dark theme read as a
   rendering fault in itself - exactly the wrong impression for the element whose
   job is to explain a fault. */
#blazor-error-ui {
    display: none;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1000;
    padding: 12px 44px 12px 16px;
    background: var(--red-soft);
    border-top: 1px solid var(--red-line);
    color: var(--text);
    font-size: 13px;
}

#blazor-error-ui .reload {
    color: var(--accent);
    text-decoration: underline;
    margin-left: 6px;
}

#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: 14px;
    top: 10px;
    color: var(--text-dim);
}

/* Solid danger, for the button that actually performs a destructive action.
   btn-outline-danger stays for the one that merely asks. */
.btn-danger {
    background: var(--red);
    color: var(--text-on-accent);
}

.btn-danger:hover {
    background: var(--red-strong);
}
