:root {
    --bg: #0f1115;
    --panel: #161a22;
    --panel-2: #1c222c;
    --border: #262c38;
    --text: #e6e9ef;
    --muted: #8892a6;
    --accent: #4ea8ff;
    --good: #3ddc97;
    --bad: #ff6b6b;
    --warn: #ffb454;
}

* { box-sizing: border-box; }

/* Must beat any author rule (.actions, .user-badge, etc.) that sets display.
 * Without this, `hidden` HTML attribute gets overridden and elements leak. */
[hidden] { display: none !important; }

body {
    margin: 0;
    background: var(--bg);
    color: var(--text);
    font: 14px/1.4 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

.top {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    padding: 14px 20px;
    border-bottom: 1px solid var(--border);
    background: var(--panel);
    position: sticky;
    top: 0;
    z-index: 10;
}

.top h1 { margin: 0; font-size: 18px; font-weight: 600; letter-spacing: .3px; }

.controls {
    display: flex;
    gap: 12px;
    align-items: center;
    flex-wrap: wrap;
    flex: 1;
    justify-content: flex-end;
}
.controls label { color: var(--muted); font-size: 12px; display: flex; gap: 6px; align-items: center; }

.filter { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.filter-label { color: var(--muted); font-size: 12px; }
.filter-sep { color: var(--muted); font-size: 11px; }
.presets { display: inline-flex; background: var(--panel-2); border: 1px solid var(--border); border-radius: 6px; overflow: hidden; }
.presets .preset { background: transparent; border: none; padding: 5px 10px; color: var(--muted); border-radius: 0; font-size: 12px; }
.presets .preset:hover { color: var(--text); }
.presets .preset.active { background: var(--accent); color: #0a0e14; font-weight: 600; }
.presets .preset + .preset { border-left: 1px solid var(--border); }

.actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }

input[type="date"], button {
    background: var(--panel-2);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 6px 10px;
    font: inherit;
}

button { cursor: pointer; }
button:hover { border-color: var(--accent); }
button.primary { background: var(--accent); color: #0a0e14; border-color: var(--accent); font-weight: 600; }
button.primary:hover { filter: brightness(1.1); }

/* Import XML is admin-only. Hide for public viewers and signed-in
 * non-admins; the existing @media (max-width: 720px) rule below hides it
 * on mobile even for admins. */
body:not(.mode-admin) #upload-label { display: none; }

.upload { cursor: pointer; }
.upload .btn-like {
    display: inline-block;
    background: var(--panel-2);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 6px 10px;
    font: inherit;
}
.upload:hover .btn-like { border-color: var(--accent); }

.auth-bar { display: flex; gap: 8px; align-items: center; }
.user-badge { display: inline-flex; gap: 8px; align-items: center; font-size: 13px; color: var(--text); }
.user-badge img { width: 24px; height: 24px; border-radius: 50%; object-fit: cover; border: 1px solid var(--border); }
button.linky { background: transparent; border: none; color: var(--muted); padding: 4px 6px; font-size: 12px; }
button.linky:hover { color: var(--text); border-color: transparent; }

.public-banner {
    background: var(--panel-2);
    border-bottom: 1px solid var(--border);
    color: var(--muted);
    padding: 8px 20px;
    font-size: 12px;
    text-align: center;
}
.public-banner .linky { color: var(--accent); padding: 0; font-size: 12px; }
.public-banner .linky:hover { color: var(--text); }


main { padding: 20px 24px 80px; max-width: 1400px; margin: 0 auto; }

.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; margin-bottom: 24px; }
.card {
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 14px 16px;
}
.card .label { color: var(--muted); font-size: 11px; text-transform: uppercase; letter-spacing: .5px; }
.card .value { font-size: 22px; font-weight: 600; margin-top: 4px; }
.card .sub { color: var(--muted); font-size: 12px; margin-top: 2px; }
.card.good .value { color: var(--good); }
.card.bad .value { color: var(--bad); }

/* Discipline-card affordances: green pill when we're flat right now, amber
 * warning pill when a position is still open. Inline in the `sub` line. */
.flat-tick { color: var(--good); font-weight: 600; }
.flat-warn { color: var(--warn); font-weight: 600; }

/* Positive empty state for the Open Positions table — turns the neutral
 * "No open positions" row into a green "all clear" banner so closing out
 * is visually rewarded. */
.empty.flat-clear {
    color: var(--good);
    font-weight: 500;
    background: rgba(61, 220, 151, 0.06);
}
.flat-tick-big {
    display: inline-block;
    width: 22px; height: 22px; line-height: 22px;
    border-radius: 50%;
    background: var(--good);
    color: #0f1115;
    font-weight: 700;
    text-align: center;
    margin-left: 8px;
}

h2 { margin: 24px 0 10px; font-size: 14px; color: var(--muted); text-transform: uppercase; letter-spacing: .5px; font-weight: 600; }

/* Section header — when a section needs an inline control (e.g. the Charts
 * currency filter) the h2 and the control sit on one row. Scoped so it
 * doesn't affect plain `<h2>`-only sections like Open Positions. */
.section-header { display: flex; align-items: center; gap: 12px; margin: 24px 0 10px; }
.section-header h2 { margin: 0; }

.table-wrap {
    overflow-x: auto;
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: 8px;
    /* Soft right-edge fade hints that there's more content when a wide table
     * overflows horizontally on narrow screens. Harmless when it fits. */
    background-image:
        linear-gradient(to left, var(--panel), transparent 30px),
        linear-gradient(to left, rgba(0,0,0,.25), transparent 30px);
    background-repeat: no-repeat;
    background-position: right;
    background-size: 30px 100%;
    background-attachment: local, scroll;
}

table { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
th, td { padding: 8px 12px; text-align: left; border-bottom: 1px solid var(--border); white-space: nowrap; }
th { background: var(--panel-2); color: var(--muted); font-weight: 500; font-size: 11px; text-transform: uppercase; letter-spacing: .4px; }
tbody tr:last-child td { border-bottom: 0; }
tbody tr:hover { background: #1a1f28; }
.num { text-align: right; }

.pnl-pos { color: var(--good); font-weight: 600; }
.pnl-neg { color: var(--bad); font-weight: 600; }
.pnl-zero { color: var(--muted); }

.tag {
    font-size: 11px;
    padding: 1px 6px;
    border-radius: 10px;
    border: 1px solid var(--border);
    color: var(--muted);
}
.tag.buy  { border-color: #2a5c45; color: var(--good); }
.tag.sell { border-color: #6b2e2e; color: var(--bad); }
.tag.long  { border-color: #2a5c45; color: var(--good); }
.tag.short { border-color: #6b2e2e; color: var(--bad); }

.empty { padding: 24px; color: var(--muted); text-align: center; }

.legend {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: 12px;
    margin-top: 12px;
    padding: 16px;
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: 8px;
    font-size: 12.5px;
    line-height: 1.45;
}
.legend .item { display: flex; gap: 12px; align-items: flex-start; }
.legend .badge { font-size: 18px; min-width: 1.6em; text-align: center; line-height: 1.2; }
.legend .text { color: var(--muted); }
.legend .tag-name { color: var(--text); font-weight: 600; margin-right: 6px; letter-spacing: .3px; }
.legend .risk { display: block; margin-top: 3px; color: #c0a05a; }
.legend .risk::before { content: "Risk: "; font-weight: 600; color: var(--warn); }

.tag.strat {
    display: inline-flex;
    gap: 4px;
    align-items: center;
    border-color: var(--border);
    color: var(--text);
    background: var(--panel-2);
}
.tag.strat .icon { font-size: 13px; }
.tag.strat.scalp      { border-color: #8a6a2e; }
.tag.strat.day        { border-color: #6a7f3e; }
.tag.strat.swing      { border-color: #3d5a8a; }
.tag.strat.dca        { border-color: #6b2e2e; }
.tag.strat.martingale { border-color: #7a1f7a; }
.tag.strat.pyramid    { border-color: #2a5c45; }
.tag.strat.stacked    { border-color: #5a5a5a; }
.tag.strat.cut        { border-color: #8a4a30; }
.tag.strat.open       { border-color: #3ddc97; }
.tag.strat.re-entry   { border-color: #b85959; }
.tag.strat.reversal   { border-color: #8a6a2e; }
.tag.strat.overnight  { border-color: #4e6ea8; }
.tag.strat.stopped    { border-color: #707070; }

.open-dot { color: var(--good); margin-left: 4px; }
.muted-sub { color: var(--muted); font-size: 11px; }

/* Time-to-fill tiers */
.ttf { font-variant-numeric: tabular-nums; padding: 1px 6px; border-radius: 10px; border: 1px solid var(--border); font-size: 11px; }
.ttf-good { color: var(--good); border-color: #2a5c45; }
.ttf-warn { color: var(--warn); border-color: #8a6a2e; }
.ttf-bad  { color: var(--bad);  border-color: #6b2e2e; background: rgba(255, 107, 107, .08); font-weight: 600; }

/* Held-duration tiers */
.held { font-variant-numeric: tabular-nums; padding: 1px 6px; border-radius: 10px; border: 1px solid var(--border); font-size: 11px; }
.held-best { color: var(--good); border-color: #2a5c45; }
.held-mid  { color: var(--warn); border-color: #8a6a2e; }
.held-long { color: var(--muted); }

/* Open-position age — longer = more flag-worthy. */
.held-open { font-variant-numeric: tabular-nums; padding: 1px 6px; border-radius: 10px; border: 1px solid var(--border); font-size: 11px; }
.held-open-fresh { color: var(--muted); }
.held-open-mid   { color: var(--warn); border-color: #8a6a2e; }
.held-open-long  { color: var(--bad);  border-color: #6b2e2e; background: rgba(255, 107, 107, .08); font-weight: 600; }

.trophy { margin-left: 4px; filter: drop-shadow(0 0 2px rgba(255, 180, 84, .45)); }

/* FIFO-click summary row in the closed-trades table. Represents one trader
 * click that closed N open lots via FIFO; the per-lot rows live underneath
 * as .fifo-detail rows hidden by default. Single-lot closes don't get this
 * treatment — they render as plain rows alongside everything else. */
.fifo-summary { cursor: pointer; user-select: none; }
.fifo-summary:hover td { background: #1f2530; }
.fifo-summary:focus { outline: none; }
.fifo-summary:focus-visible td:first-child { box-shadow: inset 2px 0 0 var(--accent); }

.fifo-caret {
    display: inline-block;
    width: 12px;
    margin-right: 8px;
    color: var(--muted);
    transition: transform .15s ease;
    text-align: center;
}
.fifo-caret::before { content: "▸"; }
.fifo-summary.expanded .fifo-caret { transform: rotate(90deg); }

/* Per-lot rows under a summary — subtle muted styling so the eye reads them
 * as detail nested under their summary, not as peer rows. */
.fifo-detail td { background: rgba(255, 255, 255, .02); font-size: 12.5px; }
.fifo-detail td:first-child { color: var(--muted); padding-left: 28px; }
.fifo-marker { color: var(--muted); }

/* Notes & stars column */
.meta-col { width: 1%; }  /* shrink-to-content header */
.meta-cell {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 14px;
    line-height: 1;
}
.meta-star, .meta-note {
    user-select: none;
    line-height: 1;
    padding: 2px 4px;
    border-radius: 4px;
    transition: background .12s ease, color .12s ease;
}
.meta-star.on  { color: var(--warn); }
.meta-note.on  { color: var(--accent); }
.meta-cell .clickable { cursor: pointer; }
/* .meta-cell .clickable:hover { background: #2a2f3a; } */
.meta-cell .clickable:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* "Off" icons (no note, not starred) are hidden unless the row is hovered —
 * keeps the table clutter-free, with the affordance still discoverable.
 * `visibility: hidden` instead of `display: none` so the cell width stays
 * stable between hover and non-hover states. The reveal-on-hover affordance
 * is admin-only: non-admin viewers can't write, so a "click to add note"
 * cue would be a lie. They only ever see icons that are actually `.on`. */
.meta-star.off, .meta-note.off { visibility: hidden; color: var(--border); }
@media (hover: hover) {
    body.mode-admin tr:hover .meta-star.off,
    body.mode-admin tr:hover .meta-note.off { visibility: visible; opacity: .45; }
    body.mode-admin tr:hover .meta-star.off:hover,
    body.mode-admin tr:hover .meta-note.off:hover { opacity: 1; }
}
@media (hover: none) {
    body.mode-admin .meta-star.off,
    body.mode-admin .meta-note.off { visibility: visible; opacity: .25; }
}

/* Pinned trades — horizontal-scroll strip of compact cards. Shown above the
 * charts, independent of the active date filter (always all-time). */
.starred-strip {
    display: flex;
    gap: 12px;
    overflow-x: auto;
    padding: 4px 2px 12px;
    /* Scrollbar styling — thin and unobtrusive. */
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
}
.starred-strip::-webkit-scrollbar       { height: 8px; }
.starred-strip::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
.starred-strip::-webkit-scrollbar-track { background: transparent; }
.starred-card {
    flex: 0 0 260px;
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 12px 14px;
    display: flex;
    flex-direction: column;
    gap: 8px;
    /* Subtle warm border tint to match the ⭐ visual. */
    box-shadow: inset 3px 0 0 var(--warn);
}
.starred-card-clickable        { cursor: pointer; transition: border-color .12s ease, transform .12s ease; }
.starred-card-clickable:hover  { border-color: var(--accent); transform: translateY(-1px); }
.starred-card header {
    display: flex;
    gap: 8px;
    align-items: center;
    flex-wrap: wrap;
}
.starred-sym { font-size: 14px; }
.starred-meta {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 8px;
    color: var(--muted);
    font-size: 11.5px;
    font-variant-numeric: tabular-nums;
}
.starred-pnl { font-weight: 700; font-size: 13px; }
.starred-pnl.muted { color: var(--muted); font-weight: 400; font-style: italic; font-size: 12px; }
.starred-note {
    margin: 0;
    color: var(--text);
    font-size: 12.5px;
    line-height: 1.45;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* Native <dialog> note editor */
.note-editor {
    background: var(--panel);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 18px 20px;
    min-width: 360px;
    max-width: 90vw;
    box-shadow: 0 12px 40px rgba(0,0,0,.6);
}
.note-editor::backdrop { background: rgba(8,10,14,.65); backdrop-filter: blur(2px); }
.note-editor header h3 { margin: 0 0 4px; font-size: 14px; text-transform: uppercase; letter-spacing: .5px; color: var(--muted); font-weight: 600; }
.note-editor #note-editor-context { display: block; margin-bottom: 12px; font-size: 12px; }
.note-editor textarea {
    width: 100%;
    background: var(--bg);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 10px 12px;
    font: inherit;
    font-size: 13px;
    resize: vertical;
    min-height: 90px;
}
.note-editor textarea:focus { outline: 2px solid var(--accent); outline-offset: -2px; }
.note-editor-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    margin-top: 12px;
}
.note-editor-actions button.danger { color: var(--bad); }
.note-editor-actions button.danger:hover { color: var(--text); }

.result-win  { color: var(--good); font-weight: 700; }
.result-loss { color: var(--bad);  font-weight: 700; }
.result-flat { color: var(--muted); }

/* Charts */
.charts-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
    gap: 12px;
}
.chart-card {
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 14px 16px 16px;
    position: relative;
}
/* Inline info panel — sits top-right of each chart and updates on hover or
 * tap. Replaces native SVG tooltips so the readout has a consistent location
 * the user can glance at without chasing a popup around the chart. */
.chart-info {
    position: absolute;
    top: 38px;
    right: 16px;
    font-size: 11px;
    color: var(--text);
    border: 1px solid transparent;
    border-radius: 4px;
    padding: 2px 8px;
    pointer-events: none;
    max-width: 70%;
    text-align: right;
    line-height: 1.35;
    z-index: 2;
    transition: border-color 0.15s, background 0.15s;
}
.chart-info:not(:empty) {
    border-color: var(--border);
    background: var(--panel-2);
}
.chart-info strong { font-weight: 600; color: var(--text); }
.chart-info .info-ccy { color: var(--muted); font-weight: 500; }
.chart-card h3 {
    margin: 0 0 10px;
    font-size: 12px;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: .5px;
    font-weight: 600;
    display: flex;
    align-items: center;
    gap: 10px;
}
.chart-toggle {
    display: inline-flex;
    background: var(--panel-2);
    border: 1px solid var(--border);
    border-radius: 6px;
    overflow: hidden;
    margin-left: auto;
}
.chart-toggle .mode {
    background: transparent;
    border: none;
    padding: 2px 8px;
    color: var(--muted);
    border-radius: 0;
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: .3px;
    cursor: pointer;
}
.chart-toggle .mode:hover { color: var(--text); }
.chart-toggle .mode + .mode { border-left: 1px solid var(--border); }
.chart-toggle .mode.active { background: var(--accent); color: #0a0e14; font-weight: 600; }
.chart { width: 100%; height: 220px; position: relative; }
.chart svg { width: 100%; height: 100%; display: block; }
.chart .axis line, .chart .axis path { stroke: var(--border); }
.chart .grid line { stroke: var(--border); stroke-dasharray: 2 3; opacity: .6; }
.chart .tick { fill: var(--muted); font-size: 11px; font-family: inherit; }
.chart .bar-pos { fill: var(--good); }
.chart .bar-neg { fill: var(--bad); }
.chart .line { fill: none; stroke: var(--accent); stroke-width: 2; }
.chart .area { fill: var(--accent); opacity: .12; }
.chart .dot { fill: var(--accent); }
.chart .label { fill: var(--text); font-size: 12px; }
.chart .zero { stroke: var(--muted); stroke-dasharray: 3 3; opacity: .7; }
.chart .empty { display: flex; align-items: center; justify-content: center; height: 100%; color: var(--muted); font-size: 12px; }

/* Top-scalps scoreboard — compact <table> ranked list. Rows stack from the
 * top; the card holds its 220px min-height to align with the SVG charts but
 * doesn't stretch rows to fill (3 rows look like 3 rows, not an accordion).
 * Using a real <table> guarantees column alignment across rows in every
 * browser without depending on CSS subgrid. */
.chart.scalp-list {
    height: auto;
    min-height: 220px;
    padding: 2px 6px;
    overflow: visible;
    display: block;
}
.scalp-list table {
    width: 100%;
    border-collapse: collapse;
    table-layout: auto;
}
/* Override the global `th, td` defaults (8px padding, bottom border, etc.)
 * — we want a denser look here than the data tables below. */
.scalp-list td {
    padding: 3px 6px;
    border: none;
    font-size: 12px;
    white-space: nowrap;
}
.scalp-list tbody tr:hover { background: transparent; }
.scalp-list .sym  { font-weight: 600; }
.scalp-list .when {
    color: var(--muted);
    font-variant-numeric: tabular-nums;
    font-size: 11px;
}
.scalp-list .pnl {
    text-align: right;
    font-variant-numeric: tabular-nums;
    font-size: 12.5px;
}
.scalp-list .trophy-slot {
    width: 18px;
    text-align: center;
}
/* Condensed pills — keep color identity (long/short borders, held-best
 * green) but shrink padding + font so the row density matches the SVG
 * charts next door. */
.scalp-list .tag,
.scalp-list .held {
    font-size: 10px;
    padding: 0 5px;
    line-height: 14px;
}
/* Suppress the iOS Safari grey tap-highlight square. Without this, tapping
 * a pie slice or bar paints a rectangular highlight over the element's
 * bounding box instead of letting our own affordance show through. */
.chart-card, .chart-card * { -webkit-tap-highlight-color: transparent; }

/* Hover/sticky affordance — applied to every interactive chart element.
 * Brightness lift (above baseline, never below) plus a soft white halo
 * so thin elements like reference lines visibly stand out. The halo mimics
 * the trophy-emoji glow that the user pointed at as the desired feel.
 *
 * Critical: the at-rest filter has to carry the SAME function list as the
 * hover filter (brightness + drop-shadow with transparent/zero values) so
 * the transition interpolates smoothly. Going from `none` to a multi-func
 * filter list causes browsers to flash through an undefined intermediate,
 * which is what the user described as the "dark flash" on hover. */
.chart .hot-target { cursor: pointer; }
.chart .hot-target:not(.bar-group):not(.slice-group),
.chart .bar-seg,
.chart .slice-seg,
.chart .ref-visible {
    filter: brightness(1) drop-shadow(0 0 0 transparent);
    transition: filter 0.15s ease-out;
}
.chart rect.hot-target:hover,
.chart rect.hot-target.sticky,
.chart circle.hot-target:hover,
.chart circle.hot-target.sticky,
.chart path.hot-target:hover,
.chart path.hot-target.sticky,
.chart g.hot-target:hover .ref-visible,
.chart g.hot-target.sticky .ref-visible,
.chart .bar-seg:hover,
.chart .bar-seg.sticky,
.chart .slice-seg:hover,
.chart .slice-seg.sticky {
    filter: brightness(1.5) drop-shadow(0 0 6px rgba(255, 255, 255, 0.6));
}

/* Segmented bar (vertical or horizontal). Segments are rendered FIRST so
 * they sit behind the base rect; base painted last sits on top and covers
 * them at rest. `pointer-events: none` on the base lets the pointer pass
 * through to the segment beneath, so seg-specific :hover actually fires.
 * On hover the base fades to 0 and the always-visible (opacity 1) segments
 * are revealed — no dual fade, no dark flash mid-transition. */
.chart .bar-base { transition: opacity 0.12s; pointer-events: none; }
.chart .bar-seg { transition: filter 0.12s; }
.chart .bar-group:hover .bar-base,
.chart .bar-group:has(.sticky) .bar-base { opacity: 0; }

/* Pie slices — same trick. slice-base painted last sits on top; sub-slices
 * are always at full opacity behind it. Base ignores pointer events so the
 * sub-slice underneath receives the hover and fires its info-panel update. */
.chart .slice-base { transition: opacity 0.12s, filter 0.12s; pointer-events: none; }
.chart .slice-seg { transition: filter 0.12s; }
.chart .slice-group:hover .slice-base,
.chart .slice-group:has(.sticky) .slice-base { opacity: 0; }

/* Cumulative stacked area — each currency renders at its own opacity at rest;
 * hovering a band brightens it (via the rule above). The combined dots ride
 * on top for date-specific breakdown via the info panel. */
.chart .cum-area { transition: filter 0.12s, opacity 0.12s; cursor: pointer; }

/* Reference lines (averages, moving averages). Wider invisible hit area so
 * the thin visible line is easy to grab; visible child lights up via the
 * generic g.hot-target rule above. */
.chart .ref-hit { stroke: transparent; pointer-events: stroke; cursor: pointer; }
.chart .ref-visible { pointer-events: none; transition: filter 0.12s; }

/* Touch-primary devices: instead of the brightness + halo (which Safari
 * sometimes renders inconsistently on path fills and where the trapped
 * `:hover` state confuses the visual), draw an explicit white outline on
 * the sticky element. Clearer affordance, no rendering quirks. */
@media (hover: none) {
    .chart rect.hot-target.sticky,
    .chart circle.hot-target.sticky,
    .chart path.hot-target.sticky,
    .chart .bar-seg.sticky,
    .chart .slice-seg.sticky {
        filter: none;
        stroke: #ffffff;
        stroke-width: 2;
    }
    .chart g.hot-target.sticky .ref-visible {
        filter: none;
        stroke: #ffffff;
    }
}


/* Recent viewers — bottom-of-page "who was here" strip. Built from the
 * audit_log; only signed-in viewers get recorded, so the public dashboard
 * shows an aggregate of named viewers + when they were last here. */
.visitors-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 8px 14px;
}
.visitor {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: var(--panel-2);
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 4px 10px 4px 4px;
    font-size: 12px;
    color: var(--text);
}
.visitor-pic {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    object-fit: cover;
    border: 1px solid var(--border);
    background: var(--panel);
    display: inline-block;
}
.visitor-pic-placeholder { background: var(--panel-2); }
.visitor-name { font-weight: 500; }
.visitor-when { color: var(--muted); font-size: 11px; }

/* Public dashboard: cards + charts + legend + pinned strip + closes only.
 * Open positions, raw executions, the per-fill hourly chart, and the
 * "Recent viewers" feed are hidden — and the corresponding fields are
 * stripped from the /public API payload, so this isn't just visual. */
body.mode-public #section-positions,
body.mode-public #section-trades,
body.mode-public #section-visitors,
body.mode-public #chart-card-hourly {
    display: none;
}

/* Preset date buttons are visible but inert for public viewers — clicks and
 * keyboard activations are blocked so the rendered data stays in lockstep
 * with what the server actually sent. Sign-in is the only way to change
 * the filter. The active button keeps full opacity so the default ("This
 * month") still reads as the selected window. */
body.mode-public .preset {
    pointer-events: none;
    opacity: 0.5;
}
body.mode-public .preset.active { opacity: 1; }

/* Mobile */
@media (max-width: 720px) {
    main { padding: 14px 12px 60px; }
    .top { padding: 10px 12px; gap: 8px; }
    /* Row 1: title left, auth-bar (with Sync + avatar) right. */
    .top h1 {
        flex: 1; min-width: 0; font-size: 16px;
        white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    }
    .auth-bar { order: 0; margin-left: auto; flex-wrap: wrap; gap: 8px; }
    .auth-bar .actions { flex-wrap: nowrap; }
    /* Row 2: controls full-width below. */
    .controls { justify-content: flex-start; gap: 8px; order: 10; flex-basis: 100%; width: 100%; }
    .filter { width: 100%; }
    .presets { flex: 1; max-width: 100%; }
    .presets .preset:not([hidden]) { flex: 1; text-align: center; }
    .filter-sep { display: none; }
    /* Actions now live inside .auth-bar so Sync sits next to the username /
     * sign-in button on row 1. */
    .actions { display: flex; align-items: center; gap: 8px; }
    /* Mobile file picker for IBKR XML is a pain; hide entirely on phones. */
    #upload-label { display: none; }
    .cards { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 8px; }
    .card { padding: 10px 12px; }
    .card .value { font-size: 18px; }
    .charts-grid { grid-template-columns: 1fr; }
    .chart { height: 240px; }
    .chart-card { padding: 12px 10px; }
    h2 { margin-top: 20px; }
    th, td { padding: 6px 8px; font-size: 13px; }
    .public-banner { padding: 6px 12px; font-size: 11px; }
}
@media (max-width: 420px) {
    .top h1 { font-size: 15px; }
    .presets .preset { padding: 5px 6px; font-size: 11px; }
    .card .value { font-size: 16px; }
    .card .sub { font-size: 11px; }
}
