/*
  A personal dashboard, read on a phone as often as a laptop.

  Two rules drive the visual language:
    - A gain and a loss must never be told apart by colour alone. Every signed figure carries its
      own + or -, so colour reinforces the sign rather than carrying the meaning.
    - A figure that is not known renders as an em dash in muted grey, never as a zero. "We could
      not price this" and "this is worth nothing" must not look the same.
*/

:root {
    color-scheme: light dark;

    --bg: #f6f7f9;
    --surface: #ffffff;
    --border: #e3e6ea;
    --text: #1c2126;
    --muted: #6b7480;
    --accent: #2f6feb;
    --gain: #1a7f4b;
    --loss: #c0392b;
    --warn-bg: #fff6e5;
    --warn-border: #f0c36d;
    --warn-text: #6b4e00;

    --radius: 10px;
    --gap: 1rem;
}

@media (prefers-color-scheme: dark) {
    :root {
        --bg: #14171a;
        --surface: #1c2126;
        --border: #2c333b;
        --text: #e6eaee;
        --muted: #98a2ae;
        --accent: #5b9bff;
        --gain: #46c07f;
        --loss: #f0705e;
        --warn-bg: #3a2f16;
        --warn-border: #7a6427;
        --warn-text: #f2d79b;
    }
}

* {
    box-sizing: border-box;
}

html {
    -webkit-text-size-adjust: 100%;
}

body {
    margin: 0;
    background: var(--bg);
    color: var(--text);
    font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    font-size: 16px;
    line-height: 1.5;
}

.app {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

/* Header and navigation ---------------------------------------------------- */

.app-header {
    display: flex;
    align-items: center;
    gap: var(--gap);
    flex-wrap: wrap;
    padding: 0.75rem 1.25rem;
    background: var(--surface);
    border-bottom: 1px solid var(--border);
    position: sticky;
    top: 0;
    z-index: 10;
}

.brand {
    font-weight: 700;
    font-size: 1.15rem;
    color: var(--text);
    text-decoration: none;
    letter-spacing: -0.02em;
}

.nav {
    display: flex;
    gap: 0.25rem;
    margin-left: auto;
}

.nav a {
    padding: 0.4rem 0.75rem;
    border-radius: var(--radius);
    color: var(--muted);
    text-decoration: none;
    font-size: 0.95rem;
}

.nav a:hover {
    background: var(--bg);
    color: var(--text);
}

.nav a.active {
    background: var(--accent);
    color: #fff;
}

.nav-toggle {
    display: none;
    margin-left: auto;
    flex-direction: column;
    justify-content: center;
    gap: 4px;
    width: 40px;
    height: 40px;
    padding: 0 9px;
    background: none;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    cursor: pointer;
}

.nav-toggle span {
    display: block;
    height: 2px;
    background: var(--text);
    border-radius: 2px;
}

.app-main {
    flex: 1;
    width: 100%;
    max-width: 1180px;
    margin: 0 auto;
    padding: 1.5rem 1.25rem 3rem;
}

.app-footer {
    padding: 1rem 1.25rem 2rem;
    color: var(--muted);
    font-size: 0.8rem;
    text-align: center;
}

/* Typography --------------------------------------------------------------- */

h1 {
    font-size: 1.6rem;
    margin: 0;
    letter-spacing: -0.02em;
}

h1:focus {
    outline: none;
}

h2 {
    font-size: 1.05rem;
    margin: 0 0 0.75rem;
    letter-spacing: -0.01em;
}

.page-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--gap);
    flex-wrap: wrap;
    margin-bottom: 1.25rem;
}

.subtitle {
    color: var(--muted);
    font-size: 0.875rem;
    margin: 0.25rem 0 0;
}

/* Cards -------------------------------------------------------------------- */

.cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
    gap: var(--gap);
    margin-bottom: 1.5rem;
}

.card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1rem 1.1rem;
}

.card .label {
    color: var(--muted);
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.card .value {
    font-size: 1.5rem;
    font-weight: 650;
    letter-spacing: -0.02em;
    margin-top: 0.35rem;
    font-variant-numeric: tabular-nums;
}

.card .note {
    color: var(--muted);
    font-size: 0.8rem;
    margin-top: 0.2rem;
}

/* Panels and tables -------------------------------------------------------- */

.panel {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1.1rem;
    margin-bottom: 1.5rem;
}

/* A wide table scrolls inside its panel rather than pushing the page sideways. */
.table-scroll {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

/* A long preview scrolls in place rather than burying the button underneath it. */
.table-scroll.tall {
    max-height: 26rem;
    overflow-y: auto;
}

tr.muted td {
    opacity: 0.55;
}

.panel-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--gap);
}

/* Lots ---------------------------------------------------------------------- */

/* The purchases a holding is made of. Indented and quieter than the row they belong to, so the
   totals stay the thing you read first and the parts are there when you want them. */
tr.lot td {
    background: var(--bg);
    font-size: 0.85rem;
    border-bottom: 1px solid var(--border);
}

/* Only the label is quieter. Nothing here may set a colour on the figures: a rule like
   `tr.lot td.num` out-specifies .gain and .loss and would silently strip a lot's gain of its
   green while the holding above it kept its own. */
tr.lot .lot-when,
tr.lot .lot-empty {
    color: var(--muted);
    padding-left: 2.1rem;
}

tr.lot .lot-when {
    white-space: nowrap;
}

tr.lot .lot-empty {
    font-style: italic;
}

tr.expanded td {
    border-bottom: none;
}

.disclose {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    border: none;
    background: none;
    padding: 0;
    margin: 0;
    font: inherit;
    text-align: left;
    color: inherit;
    cursor: pointer;
}

.disclose:hover:not(:disabled) {
    border: none;
    color: var(--accent);
}

.disclose .caret {
    color: var(--muted);
    font-size: 0.7rem;
    width: 0.7rem;
    flex: none;
}

table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.9rem;
}

th, td {
    padding: 0.6rem 0.7rem;
    text-align: left;
    white-space: nowrap;
    border-bottom: 1px solid var(--border);
}

th {
    color: var(--muted);
    font-weight: 600;
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

tbody tr:last-child td {
    border-bottom: none;
}

td.num, th.num {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

tfoot td {
    font-weight: 650;
    border-top: 2px solid var(--border);
}

.symbol {
    font-weight: 650;
}

.name {
    color: var(--muted);
    font-size: 0.8rem;
}

/* Signed figures ----------------------------------------------------------- */

.gain {
    color: var(--gain);
}

.loss {
    color: var(--loss);
}

.flat, .unknown {
    color: var(--muted);
}

/* Quote state -------------------------------------------------------------- */

.chip {
    display: inline-block;
    padding: 0.1rem 0.45rem;
    border-radius: 999px;
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    border: 1px solid var(--border);
    color: var(--muted);
}

.chip.live {
    color: var(--gain);
    border-color: currentColor;
}

.chip.stale, .chip.unavailable {
    color: var(--warn-text);
    background: var(--warn-bg);
    border-color: var(--warn-border);
}

/* Trade side. Buy and sell also read as words, so the colour is never the only signal. */
.chip.buy {
    color: var(--gain);
    border-color: currentColor;
}

.chip.sell {
    color: var(--accent);
    border-color: currentColor;
}

/* Expandable sales ---------------------------------------------------------- */

tr.expandable {
    cursor: pointer;
}

tr.expandable:hover td {
    background: var(--bg);
}

/* A consumed lot, indented under the sale that consumed it. */
tr.allocation td {
    background: var(--bg);
    color: var(--muted);
    font-size: 0.82rem;
    padding-top: 0.35rem;
    padding-bottom: 0.35rem;
}

/* Selects match the inputs beside them. */
select {
    font: inherit;
    width: 100%;
    padding: 0.5rem 0.6rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg);
    color: var(--text);
}

select:focus {
    outline: 2px solid var(--accent);
    outline-offset: -1px;
}

a.btn {
    display: inline-block;
    text-decoration: none;
    line-height: 1.5;
}

a.btn:hover {
    border-color: var(--accent);
    color: var(--accent);
}

/* Notices ------------------------------------------------------------------ */

.notice {
    padding: 0.75rem 1rem;
    border-radius: var(--radius);
    border: 1px solid var(--warn-border);
    background: var(--warn-bg);
    color: var(--warn-text);
    font-size: 0.875rem;
    margin-bottom: var(--gap);
}

.notice.error {
    border-color: var(--loss);
    background: color-mix(in srgb, var(--loss) 12%, transparent);
    color: var(--loss);
}

.empty {
    padding: 2rem 1rem;
    text-align: center;
    color: var(--muted);
}

/* Controls ----------------------------------------------------------------- */

.controls {
    display: flex;
    gap: 0.5rem;
    align-items: center;
    flex-wrap: wrap;
}

button, .btn {
    font: inherit;
    font-size: 0.9rem;
    padding: 0.45rem 0.9rem;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text);
    cursor: pointer;
}

button:hover:not(:disabled) {
    border-color: var(--accent);
    color: var(--accent);
}

button:disabled {
    opacity: 0.55;
    cursor: default;
}

button.primary {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
}

button.primary:hover:not(:disabled) {
    color: #fff;
    filter: brightness(1.08);
}

button.danger:hover:not(:disabled) {
    border-color: var(--loss);
    color: var(--loss);
}

button.link {
    border: none;
    background: none;
    padding: 0.2rem 0.4rem;
    color: var(--accent);
}

.toggle {
    display: inline-flex;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
}

.toggle button {
    border: none;
    border-radius: 0;
    background: var(--surface);
}

.toggle button.on {
    background: var(--accent);
    color: #fff;
}

/* Forms -------------------------------------------------------------------- */

.form-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: var(--gap);
    align-items: end;
}

label {
    display: block;
    font-size: 0.78rem;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    margin-bottom: 0.3rem;
}

input {
    font: inherit;
    width: 100%;
    padding: 0.5rem 0.6rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg);
    color: var(--text);
}

input:focus {
    outline: 2px solid var(--accent);
    outline-offset: -1px;
}

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

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

.validation-message {
    color: var(--loss);
    font-size: 0.8rem;
}

/* A checkbox reads as a sentence, not as a form field: the label sits beside it, in the body
   text's case rather than the shouty uppercase the grid labels use. */
label.check {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    text-transform: none;
    letter-spacing: normal;
    font-size: 0.85rem;
    color: var(--text);
    margin: 0.5rem 0 1rem;
    max-width: 62ch;
    cursor: pointer;
}

label.check input {
    width: auto;
    flex: none;
    align-self: center;
}

.hint {
    color: var(--muted);
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    margin-left: 0.4rem;
}

/* Uploads ------------------------------------------------------------------ */

.upload {
    display: grid;
    gap: 0.9rem;
    margin: 1rem 0;
}

.upload-row {
    display: grid;
    grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
    gap: var(--gap);
    align-items: start;
    padding: 0.9rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg);
}

.upload-label strong {
    font-size: 0.95rem;
}

.upload-label .note {
    color: var(--muted);
    font-size: 0.85rem;
    margin: 0.35rem 0 0;
    max-width: 62ch;
}

.upload-control {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    align-items: flex-start;
}

.upload-control .name {
    font-size: 0.85rem;
    word-break: break-all;
}

.required, .optional {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 0.1rem 0.4rem;
    border-radius: 999px;
    margin-left: 0.5rem;
    white-space: nowrap;
}

.required {
    background: color-mix(in srgb, var(--accent) 16%, transparent);
    color: var(--accent);
}

.optional {
    background: color-mix(in srgb, var(--muted) 16%, transparent);
    color: var(--muted);
}

/* An input carrying its unit, so "12" cannot be mistaken for a fraction. */
.suffixed {
    display: flex;
    align-items: center;
    gap: 0.4rem;
}

.suffixed span {
    color: var(--muted);
    font-size: 0.85rem;
}

/* Choices whose consequences need explaining, rather than a dropdown of jargon. */
.choices {
    display: grid;
    gap: 0.6rem;
}

.choice {
    display: flex;
    gap: 0.7rem;
    align-items: flex-start;
    padding: 0.8rem 0.9rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    cursor: pointer;
    text-transform: none;
    letter-spacing: normal;
    color: var(--text);
    font-size: 1rem;
    margin: 0;
}

.choice:hover {
    border-color: var(--accent);
}

.choice.chosen {
    border-color: var(--accent);
    background: color-mix(in srgb, var(--accent) 7%, transparent);
}

.choice input {
    width: auto;
    margin-top: 0.25rem;
    accent-color: var(--accent);
}

.choice-title {
    font-weight: 600;
    font-size: 0.95rem;
}

.choice-note {
    color: var(--muted);
    font-size: 0.85rem;
    margin-top: 0.15rem;
}

/* Framework error UI ------------------------------------------------------- */

.blazor-error-boundary {
    background: #b32121;
    padding: 1rem;
    color: white;
}

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

/* Phones ------------------------------------------------------------------- */

@media (max-width: 720px) {
    .nav-toggle {
        display: flex;
    }

    .nav {
        display: none;
        flex-direction: column;
        width: 100%;
        margin-left: 0;
        gap: 0;
    }

    .nav.open {
        display: flex;
    }

    .nav a {
        padding: 0.7rem 0.5rem;
        border-radius: 0;
    }

    .app-main {
        padding: 1rem 0.85rem 2.5rem;
    }

    .upload-row {
        grid-template-columns: 1fr;
    }

    .cards {
        grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
        gap: 0.7rem;
    }

    .card .value {
        font-size: 1.2rem;
    }

    h1 {
        font-size: 1.35rem;
    }

    .account {
        margin-left: auto;
    }
}

/* Account -------------------------------------------------------------------- */

.account {
    display: flex;
    align-items: center;
    gap: 0.6rem;
}

.account-name {
    color: var(--muted);
    font-size: 0.85rem;
}

.account form {
    margin: 0;
}

.sign-out {
    font-size: 0.85rem;
    padding: 0.35rem 0.7rem;
}

/* Sign in -------------------------------------------------------------------- */

main.plain {
    flex: 1;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: 3rem 1.25rem;
}

.login {
    width: 100%;
    max-width: 340px;
    margin-top: 8vh;
    padding: 1.75rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}

.login h1 {
    margin-bottom: 1.25rem;
}

.login label {
    display: block;
    margin-bottom: 1rem;
    font-size: 0.85rem;
    color: var(--muted);
}

.login input {
    display: block;
    width: 100%;
    margin-top: 0.3rem;
    padding: 0.55rem 0.7rem;
    font: inherit;
    color: var(--text);
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}

.login input:focus {
    outline: none;
    border-color: var(--accent);
}

.login button {
    width: 100%;
    margin-top: 0.5rem;
    padding: 0.6rem;
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
    font-size: 0.95rem;
}

.login button:hover:not(:disabled) {
    color: #fff;
    filter: brightness(1.08);
}

.login-error {
    margin: 0 0 1rem;
    color: var(--loss);
    font-size: 0.9rem;
}
