/* ============================================================================
   HINOVEST — Components (calm institutional)
   ============================================================================ */

*, *::before, *::after { box-sizing: border-box; }

html, body { height: 100%; }
body {
    margin: 0;
    background: var(--color-void);
    color: var(--color-text-primary);
    font-family: var(--font-display);
    font-size: var(--text-base);
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    font-feature-settings: "cv05" 1, "ss01" 1;
}
a { color: inherit; text-decoration: none; }
button, input, select, textarea { font-family: inherit; }
/* A dir="auto" field with nothing typed has no letters to take a direction from
   and falls back to left-to-right, so a Persian placeholder - the assistant
   brief's example - was laid out backwards, the caret on the left. A field
   says which way its placeholder reads; once something is typed, that decides. */
textarea[data-placeholder-dir="rtl"]:placeholder-shown { direction: rtl; }

/* Icon glyphs sit in an empty <i>, so their box height comes from body's font
   metrics, not the glyph. Vazirmatn's deep descent (see the RTL block below)
   inflates that box in Farsi and the glyph rides high in the extra space —
   line-height: 1 pins the box to the font-size, in both directions. */
.bi { line-height: 1; }

/* Mono numerals everywhere financial */
.mono, .num {
    font-family: var(--font-mono);
    font-feature-settings: "tnum" 1, "zero" 1;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.01em;
}

::selection { background: var(--color-accent-muted); }

/* Scrollbars — quiet */
* { scrollbar-width: thin; scrollbar-color: var(--color-border-strong) transparent; }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-thumb {
    background: var(--color-border-mid);
    border: 2px solid transparent;
    background-clip: padding-box;
    border-radius: var(--radius-pill);
}
*::-webkit-scrollbar-thumb:hover { background: var(--color-border-strong); background-clip: padding-box; }

/* Universal focus-visible — an outline, not a halo.
   It used to be a two-layer box-shadow with a hard 4px ring, plus a
   border-radius forced onto whatever it landed on: around an icon, a row or a
   swatch that reads as a blue box drawn over the layout rather than a marker on
   the thing you are on. It also showed up in screenshots, because pressing a
   key — any key, a screenshot shortcut included — puts the browser in keyboard
   modality and the focused element lights up.

   outline follows the element's own border-radius and is never clipped by an
   ancestor's overflow, so it needs no radius of its own and no second layer to
   separate it from the background. 2px at a 2px offset still clears WCAG's
   focus-appearance minimum. */
:focus-visible {
    outline: 2px solid var(--color-accent-primary);
    outline-offset: 2px;
    box-shadow: none;
}

/* The sidebar is the first focusable thing on every page: eleven nav links plus
 * the topbar stand between a keyboard user and the content. Park the escape
 * hatch off-screen until it takes focus. */
.skip-link {
    position: fixed;
    inset-block-start: var(--space-3);
    inset-inline-start: var(--space-3);
    z-index: 300;
    padding: var(--space-2) var(--space-4);
    border-radius: var(--radius-sm);
    background: var(--color-accent-primary);
    color: var(--color-accent-ink);
    font-size: var(--text-sm);
    font-weight: var(--weight-semibold);
    text-decoration: none;
    transform: translateY(-200%);
    transition: transform 120ms ease;
}
/* Plain :focus, not :focus-visible — the skip link must appear for any focus that
 * reaches it, including programmatic focus restoration. */
.skip-link:focus { transform: translateY(0); }
#mainContent:focus { outline: none; }

/* A "back" arrow points at the start edge, which flips under RTL. */
html[dir="rtl"] .auth-back-icon { transform: scaleX(-1); }

/* Inputs that live INSIDE a styled pill (search boxes, tag fields): the universal ring
 * above draws a hard 4px halo around the bare input, stranded inside its own container.
 * Ring the pill instead — the treatment .tag-field already used. */
.topbar__search input:focus-visible,
.toolbar__search input:focus-visible,
.settings-filter input:focus-visible,
.tag-field input:focus-visible { box-shadow: none; }

.topbar__search,
.toolbar__search,
.settings-filter { transition: border-color 130ms ease, box-shadow 130ms ease, background 130ms ease; }
.topbar__search:hover,
.toolbar__search:hover,
.settings-filter:hover { border-color: var(--color-border-mid); }
.topbar__search:focus-within,
.toolbar__search:focus-within,
.settings-filter:focus-within {
    border-color: var(--color-accent-border);
    box-shadow: 0 0 0 3px var(--color-accent-muted);
    background: var(--color-surface-2);
}

/* ============================================================================
   SHELL
   ============================================================================ */
.shell { display: flex; min-height: 100vh; }

/* ---- Workspace backdrop ----
   The page behind the cards is not blank, and it is not wallpaper either: two
   soft washes pulled from the theme's own palette, and one equity curve lying
   along the bottom edge — the same line the dashboard draws, at a size and an
   opacity that make it scenery. It is the one graphic this product is about,
   so it is the one worth putting back there.

   Nothing crosses the reading area. An earlier version ruled the whole page
   like chart paper, and every menu that renders inline without a card of its
   own — the settings rail especially — ended up with grid lines running
   through its labels.

   Fixed, so the curve stays put while the content scrolls over it. z-index
   below zero rather than 0: .main and .content are not positioned, so a
   z-index: 0 pseudo-element would paint over their text. .shell is a plain
   flex container and makes no stacking context of its own, so the negative
   layers land between the body's background and everything in the shell.

   Behind a login only. The home, sign-in and sign-up pages have a backdrop of
   their own and .app-shell is exactly what tells the two apart. */
.app-shell::before,
.app-shell::after {
    content: "";
    position: fixed;
    pointer-events: none;
}
.app-shell::before {
    inset: 0;
    z-index: -2;
    background:
        radial-gradient(1200px 760px at 88% -10%, var(--bg-wash-a), transparent 60%),
        radial-gradient(1000px 680px at 2% 106%, var(--bg-wash-b), transparent 58%);
}
/* The curve is a mask, not an image: the shape is fixed and the colour comes
   from the theme, so a palette change repaints it with no second asset. */
.app-shell::after {
    inset: auto 0 0 0;
    height: min(46vh, 460px);
    z-index: -1;
    background: var(--bg-wash-a);
    -webkit-mask: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%201440%20400'%20preserveAspectRatio='none'%3E%3Cpath%20d='M0%20332%20C%2090%20322%20150%20300%20220%20306%20C%20300%20313%20342%20268%20420%20258%20C%20500%20248%20542%20288%20620%20278%20C%20700%20268%20742%20206%20830%20200%20C%20920%20194%20962%20234%201040%20218%20C%201130%20200%201182%20120%201270%2096%20C%201342%2078%201392%2060%201440%2044%20L1440%20400%20L0%20400%20Z'%20fill='white'%20fill-opacity='.11'/%3E%3Cpath%20d='M0%20332%20C%2090%20322%20150%20300%20220%20306%20C%20300%20313%20342%20268%20420%20258%20C%20500%20248%20542%20288%20620%20278%20C%20700%20268%20742%20206%20830%20200%20C%20920%20194%20962%20234%201040%20218%20C%201130%20200%201182%20120%201270%2096%20C%201342%2078%201392%2060%201440%2044'%20fill='none'%20stroke='white'%20stroke-width='2.5'%20stroke-linecap='round'%20stroke-linejoin='round'/%3E%3C/svg%3E") bottom / 100% 100% no-repeat;
            mask: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%201440%20400'%20preserveAspectRatio='none'%3E%3Cpath%20d='M0%20332%20C%2090%20322%20150%20300%20220%20306%20C%20300%20313%20342%20268%20420%20258%20C%20500%20248%20542%20288%20620%20278%20C%20700%20268%20742%20206%20830%20200%20C%20920%20194%20962%20234%201040%20218%20C%201130%20200%201182%20120%201270%2096%20C%201342%2078%201392%2060%201440%2044%20L1440%20400%20L0%20400%20Z'%20fill='white'%20fill-opacity='.11'/%3E%3Cpath%20d='M0%20332%20C%2090%20322%20150%20300%20220%20306%20C%20300%20313%20342%20268%20420%20258%20C%20500%20248%20542%20288%20620%20278%20C%20700%20268%20742%20206%20830%20200%20C%20920%20194%20962%20234%201040%20218%20C%201130%20200%201182%20120%201270%2096%20C%201342%2078%201392%2060%201440%2044'%20fill='none'%20stroke='white'%20stroke-width='2.5'%20stroke-linecap='round'%20stroke-linejoin='round'/%3E%3C/svg%3E") bottom / 100% 100% no-repeat;
}
/* A phone is mostly card, and the curve would only ever be seen through the
   gaps between them. Washes alone. */
@media (max-width: 720px) {
    .app-shell::after { display: none; }
}

/* ---- Sidebar ---- */
.sidebar {
    position: fixed;
    inset-block: 0;
    inset-inline-start: 0;
    width: var(--sidebar-w);
    z-index: 40;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-4) var(--space-3);
    background: var(--color-surface-0);
    border-inline-end: 1px solid var(--color-border-subtle);
    transition: width 140ms cubic-bezier(0.22, 1, 0.36, 1);
}
.shell.is-collapsed .sidebar { width: var(--sidebar-w-collapsed); }

/* The logo is drawn as a stack - dish over lettering - so that is how it is
   set here, centred in the rail rather than tucked against the inline edge.
   A row of mark-then-word was a different lockup from the one that exists. */
.brand {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-2) var(--space-4);
    margin-bottom: var(--space-2);
    overflow: hidden;
}
.brand__mark {
    /* The mark is line art on nothing, so it needs no tile behind it - the
       gradient square was there to hold a letter, and the letter is gone. */
    flex: 0 0 auto;
    height: 52px;
    display: grid;
    place-items: center;
    transition: height 140ms cubic-bezier(0.22, 1, 0.36, 1);
}
.brand__word {
    display: block;
    height: 15px;
    width: auto;
}
/* Collapsed to 64px there is no room for six letters, and scaling them down to
   fit would make the lettering the smallest thing on screen. The dish alone
   still reads as the logo, so the word leaves rather than shrinks. */
.shell.is-collapsed .brand { padding-inline: 0; }
.shell.is-collapsed .brand__mark { height: 36px; }
.shell.is-collapsed .brand__word { display: none; }

/* The list scrolls when it does not fit. The rail is a fixed, full-height
   column, so on a short window - a laptop at 650px, or a browser zoomed in -
   whatever hung below the fold could not be reached at all: no scrollbar, no
   way down. Anything added to the bottom of this list was invisible to the
   people with the smallest screens, which is not where a new feature wants to
   be. min-height:0 is what lets a flex child shrink enough to scroll. */
.nav {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-height: 0;
    overflow-y: auto;
    scrollbar-width: none;
}
.nav::-webkit-scrollbar { display: none; }
.nav__label {
    padding: var(--space-4) var(--space-3) var(--space-2);
    color: var(--color-text-tertiary);
    font-size: var(--text-2xs);
    font-weight: var(--weight-semibold);
    letter-spacing: var(--tracking-wider);
    text-transform: uppercase;
    white-space: nowrap;
    overflow: hidden;
}
.shell.is-collapsed .nav__label { height: 12px; padding-block: 8px 4px; color: transparent; }

.nav__item {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--space-3);
    height: 36px;
    padding: 0 var(--space-3);
    border-radius: var(--radius-sm);
    color: var(--color-text-secondary);
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    cursor: pointer;
    white-space: nowrap;
    transition: background 110ms ease, color 110ms ease;
}
.nav__item .ico { flex: 0 0 18px; width: 18px; text-align: center; font-size: 16px; opacity: 0.85; }
.nav__item span:not(.ico) { overflow: hidden; }
.shell.is-collapsed .nav__item span:not(.ico) { opacity: 0; }
.nav__item:hover { background: var(--color-surface-2); color: var(--color-text-primary); }
.nav__item.is-active { background: var(--color-accent-muted); color: var(--color-accent-glow); }
.nav__item.is-active .ico { opacity: 1; }
.nav__item.is-active::before {
    content: ""; position: absolute;
    inset-block: 8px; inset-inline-start: 0;
    width: 3px; border-radius: var(--radius-pill);
    background: var(--color-accent-primary);
}
.nav__badge {
    margin-inline-start: auto;
    min-width: 20px; height: 18px; padding: 0 6px;
    border-radius: var(--radius-pill);
    background: var(--color-surface-3);
    color: var(--color-text-secondary);
    font-size: var(--text-2xs); font-weight: var(--weight-semibold);
    display: grid; place-items: center;
}
.shell.is-collapsed .nav__badge { display: none; }

/* The journals tree: a row per journal under Journals, and under the open one
   that journal's pages. The summaries are nav rows like any other, minus the
   browser's own marker - the chevron at the far end says open or shut,
   pointing along the line while shut and down once open, which is the other
   way round in RTL. */
.nav-journal > summary, .nav-group__toggle { list-style: none; }
.nav-journal > summary::-webkit-details-marker,
.nav-group__toggle::-webkit-details-marker { display: none; }

/* Journals is a link and a fold at once: the row goes to the hub, the chevron
   at its end shows or hides the list. The chevron is the fold's <summary>,
   lifted onto the link's row by position - the row keeps room for it so a long
   label never runs underneath. Closed, the fold is the chevron and nothing
   else, and takes no height of its own. */
.nav-group { position: relative; }
.nav-group__link { padding-inline-end: 40px; }
.nav-group__toggle {
    position: absolute; inset-block-start: 0; inset-inline-end: 0;
    display: grid; place-items: center;
    width: 36px; height: 36px;
    border-radius: var(--radius-sm);
    color: var(--color-text-secondary);
    cursor: pointer;
    transition: background 110ms ease, color 110ms ease;
}
.nav-group__toggle:hover { background: var(--color-surface-3); color: var(--color-text-primary); }
.nav-group__toggle .nav__chev { margin: 0; opacity: 0.75; }
.nav__chev {
    margin-inline-start: auto; flex: none;
    font-size: 11px; opacity: 0.55;
    transform: rotate(-90deg);
    transition: transform 200ms ease;
}
html[dir="rtl"] .nav__chev { transform: rotate(90deg); }
details[open] > summary .nav__chev { transform: none; }

/* The nav scrolls rather than squeezes. A flex column shrinks its children to
   fit before it overflows, so with a tree of journals in it every row below
   was pressed flatter than its own 36px and the labels ran into each other. */
.nav > * { flex-shrink: 0; }
.nav-journals, .nav-journal__pages, .nav-sub { display: flex; flex-direction: column; gap: 1px; }
.nav-journals { padding-block-start: 1px; padding-inline-start: 10px; }
/* The open journal reads as the one in hand; the rest stay quiet. */
.nav-journal[open] > summary { color: var(--color-text-primary); }
.nav-journal__dot {
    flex: 0 0 8px; width: 8px; height: 8px; margin-inline: 5px;
    border-radius: 50%;
    background: var(--journal-color, var(--color-accent-primary));
}
.nav-journal__name { min-width: 0; text-overflow: ellipsis; }
/* A journal's pages hang off a guide line under its dot, like the tree they
   are - indented enough to read as belonging, not so far that a long page name
   runs out of rail. */
.nav-sub { animation: navSubIn 200ms cubic-bezier(0.22, 1, 0.36, 1) both; }
@keyframes navSubIn { from { opacity: 0; translate: 0 -6px; } }
.nav-journal__pages, .nav-sub {
    margin-inline-start: 21px;
    padding-inline-start: 6px;
    border-inline-start: 1px solid var(--color-border-subtle);
}

/* The pages slide open and shut rather than snapping. ::details-content is
   the box <details> shows and hides; interpolate-size is what lets a height
   run to and from auto, and allow-discrete keeps the content on screen while it
   folds away instead of vanishing on the first frame. Opening one journal
   closes another through the same rule, so both halves of the swap move, and
   the whole list folds under Journals the same way.

   ponytail: a browser without ::details-content or interpolate-size (Chromium
   before 131, and Firefox) opens and shuts at once, exactly as before - a
   script that measured heights would animate those too, at the cost of owning
   the toggle the browser does now. */
.nav { interpolate-size: allow-keywords; }
.nav-group__fold::details-content,
.nav-journal::details-content {
    block-size: 0;
    overflow: clip;
    transition: block-size 240ms cubic-bezier(0.22, 1, 0.36, 1), content-visibility 240ms allow-discrete;
}
.nav-group__fold[open]::details-content,
.nav-journal[open]::details-content { block-size: auto; }
html.reduce-motion :is(.nav-group__fold, .nav-journal)::details-content { transition: none; }
@media (prefers-reduced-motion: reduce) {
    :is(.nav-group__fold, .nav-journal)::details-content { transition: none; }
}

/* 64px has no room for a tree. The journal rows leave, every closed journal
   with them, and the open journal's pages stay as the flat column of icons the
   rail always was. */
.shell.is-collapsed .nav__chev,
.shell.is-collapsed .nav-group__toggle,
.shell.is-collapsed .nav-journal > summary,
.shell.is-collapsed .nav-journal:not([open]) { display: none; }
.shell.is-collapsed .nav-group__link { padding-inline-end: var(--space-3); }
.shell.is-collapsed .nav-journals,
.shell.is-collapsed .nav-journal__pages,
.shell.is-collapsed .nav-sub { margin: 0; padding-inline: 0; border: 0; }

.sidebar__spacer { flex: 1; }

/* What a plan does not include, said where the feature would be. */
.plan-lock {
    display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap;
    margin-bottom: var(--space-5); padding: var(--space-4) var(--space-5);
    border: 1px solid var(--color-accent-border); border-radius: var(--radius-lg);
    background: var(--color-accent-muted);
}
.plan-lock > .aico { flex: none; width: 22px; height: 22px; color: var(--color-accent-glow); }
.plan-lock > div { flex: 1; min-width: 200px; }
.plan-lock strong { display: block; font-size: var(--text-sm); }
.plan-lock p { margin: 2px 0 0; font-size: var(--text-xs); color: var(--color-text-secondary); }
.signal-event.is-locked { opacity: .55; }
/* A part the plan has none of (partials/plan_wall.html), and its mark in the sidebar. */
.nav__lock { margin-inline-start: auto; font-size: 11px; color: var(--color-text-tertiary); }
.plan-wall {
    display: grid; justify-items: center; gap: var(--space-3); max-width: 520px;
    margin: clamp(24px, 8vh, 80px) auto; padding: var(--space-8) var(--space-6); text-align: center;
}
.plan-wall__ico {
    position: relative; display: grid; place-items: center; width: 64px; height: 64px; border-radius: 20px;
    font-size: 28px; color: var(--color-accent-glow); background: var(--color-accent-muted);
    border: 1px solid var(--color-accent-border);
}
.plan-wall__lock {
    position: absolute; inset-block-end: -6px; inset-inline-end: -6px; display: grid; place-items: center;
    width: 26px; height: 26px; border-radius: 50%; font-size: 12px;
    color: var(--color-text-primary); background: var(--color-surface-1); border: 1px solid var(--color-border-mid);
}
.plan-wall h2 { margin: var(--space-2) 0 0; font-size: var(--text-lg); }
.plan-wall p { margin: 0; color: var(--color-text-secondary); line-height: 1.9; }
.plan-wall small { color: var(--color-text-tertiary); }
.plan-wall .btn { margin-top: var(--space-2); }
.signal-event.is-locked .switch { cursor: not-allowed; }

/* A plan card's lines (core/_plan_lines.html, plans page and landing page):
   three, then the rest folded under a count. It slides open where the browser
   can animate to an auto height, and opens at once where it cannot. */
.plan-lines ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.plan-lines li { display: flex; align-items: flex-start; gap: 8px; font-size: var(--text-sm); line-height: 1.7; color: var(--color-text-secondary); }
.plan-lines li > .aico { flex: none; width: 15px; height: 15px; margin-top: 4px; color: var(--color-profit); }
.plan-lines__more { margin-top: 8px; interpolate-size: allow-keywords; }
.plan-lines__more summary {
    display: inline-flex; align-items: center; gap: 4px; cursor: pointer; list-style: none;
    font-size: var(--text-xs); font-weight: var(--weight-semibold); color: var(--color-accent-glow);
}
.plan-lines__more summary::-webkit-details-marker { display: none; }
.plan-lines__more summary .aico { width: 14px; height: 14px; transition: rotate 200ms ease; }
.plan-lines__more[open] summary .aico { rotate: 180deg; }
.plan-lines__more ul { padding-top: 8px; }
.plan-lines__more::details-content {
    block-size: 0; overflow: hidden;
    transition: block-size 260ms ease, content-visibility 260ms allow-discrete;
}
.plan-lines__more[open]::details-content { block-size: auto; }
@media (prefers-reduced-motion: reduce) { .plan-lines__more::details-content { transition: none; } }

.userpill {
    display: flex; align-items: center; gap: var(--space-3);
    padding: var(--space-2);
    border-radius: var(--radius);
    border: 1px solid var(--color-border-subtle);
    background: var(--color-surface-1);
    overflow: hidden;
}
.userpill__avatar {
    flex: 0 0 32px; width: 32px; height: 32px;
    border-radius: var(--radius-pill);
    display: grid; place-items: center;
    background: var(--color-surface-3);
    color: var(--color-text-primary);
    font-weight: var(--weight-semibold); font-size: var(--text-sm);
}
/* flex: 1 so the name block absorbs the free space and the logout button lands at the
   pill's trailing edge instead of hugging the text. */
/* ---- Global search dropdown ---- */
.topbar__search-wrap { position: relative; display: flex; min-width: 0; }
.search-results {
    position: absolute; top: calc(100% + 6px); inset-inline-start: 0;
    width: min(420px, 92vw); max-height: 62vh; overflow-y: auto; z-index: 1200;
    padding: var(--space-2);
    border: 1px solid var(--color-border-mid); border-radius: var(--radius);
    background: var(--color-surface-1); box-shadow: var(--shadow-float);
}
.search-results__empty { margin: 0; padding: var(--space-3); font-size: var(--text-sm); color: var(--color-text-tertiary); }
.search-group + .search-group { margin-top: var(--space-2); border-top: 1px solid var(--color-border-subtle); padding-top: var(--space-2); }
.search-group__head {
    display: flex; align-items: center; gap: 6px; padding: 4px var(--space-2);
    font-size: var(--text-2xs); font-weight: 700; text-transform: uppercase;
    letter-spacing: var(--tracking-wide); color: var(--color-text-tertiary);
}
.search-group__head span { margin-inline-start: auto; font-family: var(--font-mono); font-weight: 500; }
/* "Clear all" sits in the notifications header, after the count. */
.notifications-clear {
    margin-inline-start: var(--space-2); padding: 0; border: 0; background: none;
    font: inherit; text-transform: none; letter-spacing: 0; cursor: pointer;
    color: var(--color-text-tertiary);
}
.notifications-clear:hover { color: var(--color-loss); }
/* The bell is a peek: one line per notice, however long the message is. The
   whole text is on /notifications/, which is what "See all" is for. */
.notifications-panel .search-hit__sub {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* The way out of the peek and into the full list. */
.notifications-all {
    display: block; padding: 6px var(--space-2); margin-top: var(--space-2);
    border-top: 1px solid var(--color-border-subtle);
    font-size: var(--text-xs); text-align: center; text-decoration: none;
    color: var(--color-accent-glow);
}
.notifications-all:hover { background: var(--color-accent-muted); }
.search-hit {
    display: flex; flex-direction: column; gap: 1px;
    padding: 6px var(--space-2); border-radius: var(--radius-sm);
    text-decoration: none; color: var(--color-text-primary);
}
.search-hit:hover, .search-hit.is-cursor { background: var(--color-accent-muted); }
.search-hit__label { font-size: var(--text-sm); }
.search-hit__sub { font-size: var(--text-2xs); color: var(--color-text-tertiary); }

/* ---- Notifications bell ---- */
/* The topbar's trailing controls, as one row with its own rhythm. The gap is
   the 8px minimum between touch targets — the clustering comes from the
   hairline, not from crowding the buttons together. */
.topbar__tools { display: flex; align-items: center; gap: var(--space-2); }
.topbar__bell-wrap { position: relative; display: flex; }
.notifications-panel { inset-inline-start: auto; inset-inline-end: 0; width: min(360px, 92vw); }
/* The unread marker: a coloured dot with the count in it, ringed in the bar's
   own background so it reads as a dot sitting on the bell rather than a smudge
   on the icon. --color-danger was never defined, so this was quietly falling
   back to the accent and looked like decoration. */
.topbar__bell-badge {
    position: absolute; inset-block-start: 0; inset-inline-end: 0;
    min-width: 16px; height: 16px; padding: 0 4px; border-radius: 999px;
    display: flex; align-items: center; justify-content: center;
    font-family: var(--font-mono); font-size: var(--text-2xs); font-weight: 700; line-height: 1;
    background: var(--color-loss); color: #fff;
    box-shadow: 0 0 0 2px var(--color-surface-1);
    /* A few pulses when the count appears, then rest — a badge that never
       stops animating charges its attention cost forever. */
    animation: bell-pulse 2s ease-out 3;
}
@keyframes bell-pulse {
    0%   { box-shadow: 0 0 0 2px var(--color-surface-1), 0 0 0 2px var(--color-loss-muted); }
    70%  { box-shadow: 0 0 0 2px var(--color-surface-1), 0 0 0 8px transparent; }
    100% { box-shadow: 0 0 0 2px var(--color-surface-1), 0 0 0 8px transparent; }
}
@media (prefers-reduced-motion: reduce) {
    .topbar__bell-badge { animation: none; }
}
/* And one dot per unread line, so the panel says which of them are new. */
.search-hit.is-unread .search-hit__label { font-weight: 600; }
.search-hit.is-unread .search-hit__label::before {
    content: ""; display: inline-block; vertical-align: middle;
    width: 7px; height: 7px; margin-inline-end: 6px; border-radius: 999px;
    background: var(--color-loss);
}

.userpill__meta { flex: 1; min-width: 0; overflow: hidden; }
.userpill__logout { flex: none; margin-inline-start: auto; }
.userpill__meta strong { display: block; font-size: var(--text-sm); font-weight: var(--weight-semibold); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.userpill__meta span { display: block; font-size: var(--text-xs); color: var(--color-text-tertiary); white-space: nowrap; }
/* The plan in force, on the name: what the trader has, one click from the
   plans page. */
.userpill__meta .userpill__name { display: flex; align-items: center; gap: 6px; min-width: 0; }
.userpill__name strong { min-width: 0; }
.userpill__plan {
    flex: none; max-width: 96px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    padding: 0 7px; border-radius: var(--radius-pill);
    font-size: 10px; font-weight: var(--weight-semibold); line-height: 17px;
    background: var(--color-accent-muted); color: var(--color-accent-glow); text-decoration: none;
    transition: background 150ms ease, color 150ms ease;
}
.userpill__plan:hover { background: var(--color-accent-primary); color: var(--color-void); }
.userpill__meta .userpill__plan span { display: inline; font-size: inherit; color: inherit; }
.shell.is-collapsed .userpill__meta { display: none; }

/* ---- Main column ---- */
.main {
    flex: 1;
    min-width: 0;
    margin-inline-start: var(--sidebar-w);
    transition: margin-inline-start 140ms cubic-bezier(0.22, 1, 0.36, 1);
    display: flex;
    flex-direction: column;
}
.shell.is-collapsed .main { margin-inline-start: var(--sidebar-w-collapsed); }

/* ---- Topbar ---- */
.topbar {
    position: sticky; top: 0; z-index: 30;
    height: var(--topbar-h);
    display: flex; align-items: center; gap: var(--space-3);
    padding: 0 var(--space-5);
    background: color-mix(in srgb, var(--color-void) 88%, transparent);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border-bottom: 1px solid var(--color-border-subtle);
}
.topbar__toggle {
    width: 32px; height: 32px; flex: 0 0 32px;
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-sm);
    background: transparent; color: var(--color-text-secondary);
    display: grid; place-items: center; cursor: pointer;
    transition: background 110ms ease, color 110ms ease, border-color 110ms ease;
}
.topbar__toggle:hover { background: var(--color-surface-2); color: var(--color-text-primary); }

/* The collapse chevron used to be two glyphs that JavaScript swapped between,
   so it changed direction in a single frame while the rail it describes took
   140ms to move. One glyph that turns over instead arrives when the sidebar
   does. The markup ships chevron-left, which is the LTR open state; RTL starts
   from the turned-over position and unturns to collapse, which is why both
   directions are spelled out rather than one rule with a sign flip. */
#sidebarCollapseButton .bi { transform: rotate(0deg); }
.shell.is-collapsed #sidebarCollapseButton .bi { transform: rotate(180deg); }
html[dir="rtl"] #sidebarCollapseButton .bi { transform: rotate(180deg); }
html[dir="rtl"] .shell.is-collapsed #sidebarCollapseButton .bi { transform: rotate(0deg); }
@media (prefers-reduced-motion: no-preference) {
    #sidebarCollapseButton .bi { transition: transform 200ms cubic-bezier(0.22, 1, 0.36, 1); }
    /* lucide-animated's chevron nudge, done here rather than installed: that
       component is a React one and this page is a Django template with an icon
       font, so the dependency would arrive for a single glyph. The motion is
       the whole of it - the chevron leans the way it points when you are about
       to press it. On ::before, because the <i> itself is busy being turned
       over by the rules above, and a nudge on the same transform would fight
       the turn. It rides along with that turn, which is what keeps it leaning
       the right way in both states and in both directions of text. */
    #sidebarCollapseButton .bi::before {
        display: inline-block;
        transition: transform 160ms cubic-bezier(0.22, 1, 0.36, 1);
    }
    #sidebarCollapseButton:hover .bi::before,
    #sidebarCollapseButton:focus-visible .bi::before { transform: translateX(-2px); }
}

.crumb { display: flex; align-items: center; gap: var(--space-2); font-size: var(--text-sm); color: var(--color-text-tertiary); }
.crumb b { color: var(--color-text-primary); font-weight: var(--weight-semibold); }
.crumb .sep { opacity: 0.5; }

.topbar__search {
    display: flex; align-items: center; gap: var(--space-2);
    width: min(320px, 30vw);
    height: 34px; padding: 0 var(--space-3);
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-sm);
    background: var(--color-surface-1);
    color: var(--color-text-tertiary);
    margin-inline-start: var(--space-4);
}
.topbar__search input {
    flex: 1; min-width: 0; border: 0; background: transparent;
    color: var(--color-text-primary); font-size: var(--text-sm); outline: none;
}
.topbar__search .bi-search { color: var(--color-text-tertiary); transition: color 130ms ease; }
.topbar__search:focus-within .bi-search { color: var(--color-accent-glow); }
.topbar__spacer { flex: 1; }

/* ---- Workspace tabs ---- */
/* Frozen under the topbar, which is itself sticky at 0: the strip is how you
   change page, and it was scrolling away exactly when a long page made you want
   it. box-sizing is border-box everywhere, so the topbar's height token already
   covers its border and there is no seam to close. Below the topbar's z-index,
   so its blur and its dropdowns still pass over this. */
/* The bar is the wrapper; the nav inside it is only the part that scrolls, so
   the arrows can stand outside the scroll and stay put. */
.tabs-bar {
    position: sticky; top: var(--topbar-h); z-index: 29;
    display: flex; align-items: center; gap: var(--space-1);
    padding: var(--space-2) var(--space-5) 0;
    border-bottom: 1px solid var(--color-border-subtle);
    background: var(--color-void);
}
.tabs {
    display: flex; align-items: center; gap: var(--space-1);
    flex: 1;
    /* Without this a flex child refuses to go below its content width, and the
       strip pushed the whole page wider instead of scrolling inside itself. */
    min-width: 0;
    /* Sideways only. One axis auto and the other visible makes the visible one
       auto too, which left the strip a whole scrollable pixel tall -- and the
       wheel spent it, sliding the tabs up and down inside their own bar. */
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }
/* Shown only while the strip has more tabs than it can hold -- see
   syncTabOverflow in app-shell.js. */
.tabs-bar__scroll {
    flex: 0 0 auto;
    align-self: flex-end;
    display: grid;
    place-items: center;
    width: 26px;
    height: 38px;
    padding: 0;
    border: 1px solid var(--color-border-subtle);
    border-bottom: 0;
    border-radius: var(--radius-sm) var(--radius-sm) 0 0;
    background: var(--color-surface-0);
    color: var(--color-text-secondary);
    cursor: pointer;
    transition: color 110ms ease, background 110ms ease, border-color 110ms ease;
}
.tabs-bar__scroll:hover:not(:disabled) {
    background: var(--color-surface-1);
    color: var(--color-text-primary);
    border-color: var(--color-accent-border);
}
.tabs-bar__scroll:disabled {
    opacity: 0.35;
    cursor: default;
}
/* One pair of chevrons, mirrored: the start of the strip is the right-hand
   side when the page reads right to left. */
html[dir="rtl"] .tabs-bar__scroll .bi { transform: scaleX(-1); }
.tab {
    position: relative;
    display: inline-flex; align-items: center; gap: var(--space-2);
    height: 38px; padding: 0 var(--space-3);
    border: 0; background: transparent;
    color: var(--color-text-secondary);
    font-size: var(--text-sm); font-weight: var(--weight-medium);
    cursor: pointer; white-space: nowrap;
    border-radius: var(--radius-sm) var(--radius-sm) 0 0;
    transition: color 110ms ease, background 110ms ease;
}
.tab .ico { font-size: 14px; opacity: 0.7; }
.tab:hover { color: var(--color-text-primary); background: var(--color-surface-1); }
.tab.is-active { color: var(--color-text-primary); }
.tab.is-active::after {
    content: ""; position: absolute;
    inset-inline: 6px; bottom: -1px; height: 2px;
    background: var(--color-accent-primary); border-radius: 2px 2px 0 0;
}
.tab__close {
    width: 16px; height: 16px; padding: 0; border: 0; border-radius: var(--radius-xs);
    background: transparent; color: var(--color-text-tertiary);
    display: grid; place-items: center; cursor: pointer; font-size: 13px; line-height: 1;
    opacity: 0; transition: opacity 110ms ease, background 110ms ease;
}
.tab:hover .tab__close, .tab.is-active .tab__close { opacity: 1; }
.tab__close:hover { background: var(--color-surface-3); color: var(--color-text-primary); }

/* ---- Content scroll region ---- */
.content {
    flex: 1;
    padding: var(--space-6) var(--space-5) var(--space-12);
    max-width: 1480px;
    width: 100%;
    margin: 0 auto;
}

/* ============================================================================
   PAGE HEADER
   ============================================================================ */
.page-head {
    display: flex; align-items: flex-end; justify-content: space-between;
    gap: var(--space-4); flex-wrap: wrap;
    margin-bottom: var(--space-6);
}
.page-head__eyebrow {
    display: inline-flex; align-items: center; gap: var(--space-2);
    color: var(--color-text-tertiary);
    font-size: var(--text-xs); font-weight: var(--weight-semibold);
    letter-spacing: var(--tracking-wider); text-transform: uppercase;
    margin-bottom: var(--space-2);
}
/* Accent, not profit: green/red are reserved for money in a trading product. */
.page-head__eyebrow .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--color-accent-primary); }
.page-head h1 { margin: 0; font-size: var(--text-3xl); font-weight: var(--weight-bold); letter-spacing: var(--tracking-tight); }
.page-head__sub { margin: var(--space-2) 0 0; color: var(--color-text-secondary); font-size: var(--text-sm); max-width: 60ch; }
/* One height for everything in the header's action row. A 36px button beside a
   32px segmented control beside a 42px button is the difference between a row
   of controls and three unrelated boxes that happen to be adjacent — and the
   three pages each used to pick a different number. */
.page-head__actions {
    display: flex; align-items: center; justify-content: flex-end;
    gap: var(--space-2); flex-wrap: wrap;
}
.page-head__actions > .btn,
.page-head__actions > .btn-group,
.page-head__actions > .segment { height: 38px; }
.page-head__actions > .btn-group > .btn { height: 100%; }
.page-head__actions > .segment { padding: 4px; }
.page-head__actions > .segment button { height: 100%; border-radius: calc(var(--radius-sm) - 4px); }
/* Room for a label, so "Export" and "Add trade" are the same size object. */
.page-head__actions > .btn { min-width: 104px; }
.page-head__actions > .btn-group > .btn { min-width: 0; }
/* On a phone the row is a stack, and a stack of buttons that each stop at
   their own text width is a ragged left edge. Give them the width instead. */
@media (max-width: 720px) {
    .page-head { align-items: flex-start; }
    .page-head__actions { width: 100%; }
    .page-head__actions > .btn,
    .page-head__actions > .btn-group,
    .page-head__actions > .segment { flex: 1 1 auto; }
    .page-head__actions > .btn-group > .btn { flex: 1 1 auto; }
    .page-head__actions > .segment button { flex: 1 1 auto; justify-content: center; }
}

/* ============================================================================
   BUTTONS
   ============================================================================ */
.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
    height: 36px; padding: 0 var(--space-4);
    border-radius: var(--radius-sm);
    border: 1px solid transparent;
    font-size: var(--text-sm); font-weight: var(--weight-semibold);
    cursor: pointer; white-space: nowrap; user-select: none;
    transition: background 110ms ease, color 110ms ease, border-color 110ms ease, box-shadow 110ms ease, scale 110ms ease;
}
.btn:active { scale: 0.96; }
@media (prefers-reduced-motion: reduce) { .btn:active { scale: none; } }
.btn .ico { font-size: 15px; }
/* The one button on the page that is meant to be found first. The inner top
   highlight gives the fill an edge instead of a flat sticker, and the wide,
   tinted, downward shadow lifts it off the card without a second colour. */
.btn--primary {
    background: var(--color-accent-primary);
    color: var(--color-accent-ink);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.22),
        0 1px 2px rgba(0, 0, 0, 0.22),
        0 8px 18px -10px var(--color-accent-primary);
}
.btn--primary:hover {
    background: var(--color-accent-glow);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.26),
        0 1px 2px rgba(0, 0, 0, 0.22),
        0 10px 22px -10px var(--color-accent-primary);
}
.btn--primary:active { background: var(--color-accent-deep); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.28); }
/* Not transparent: a secondary action sitting beside a primary one has to read
   as a button, not as a link that happens to have a border. It gets a surface
   of its own, one step below the card it sits on. */
.btn--ghost {
    background: var(--color-surface-1);
    color: var(--color-text-primary);
    border-color: var(--color-border-mid);
    box-shadow: var(--shadow-sm);
}
.btn--ghost:hover { background: var(--color-surface-2); border-color: var(--color-border-strong); }
.btn--ghost:active { background: var(--color-surface-3); box-shadow: none; }
.btn--subtle { background: var(--color-surface-2); color: var(--color-text-primary); border-color: var(--color-border-subtle); }
.btn--subtle:hover { background: var(--color-surface-3); border-color: var(--color-border-mid); }
.btn--danger { background: var(--color-loss-muted); color: var(--color-loss); border-color: color-mix(in srgb, var(--color-loss) 32%, transparent); }
.btn--danger:hover { background: color-mix(in srgb, var(--color-loss) 20%, transparent); border-color: color-mix(in srgb, var(--color-loss) 50%, transparent); }
.btn--sm { height: 30px; padding: 0 var(--space-3); font-size: var(--text-xs); }
.btn[disabled] { opacity: 0.45; pointer-events: none; box-shadow: none; }

/* ---- Action clusters ----
   Buttons that belong together are joined into one control instead of being
   spaced apart like unrelated ones: a shared surface, hairlines between the
   members, and only the outer corners rounded. Used for the secondary actions
   in a page header, which used to sit as three same-weight boxes in a row with
   no clue which two were the pair. */
.btn-group {
    display: inline-flex;
    align-items: center;
    border: 1px solid var(--color-border-mid);
    border-radius: var(--radius-sm);
    background: var(--color-surface-1);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
}
.btn-group > .btn {
    border: 0;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
}
.btn-group > .btn + .btn { border-inline-start: 1px solid var(--color-border-subtle); }
.btn-group > .btn:hover { background: var(--color-surface-2); }
.btn-group > .btn:active { background: var(--color-surface-3); scale: none; }
/* The ring is drawn by box-shadow, which overflow: hidden on the group would
   clip to a sliver. Pull the focused member onto its own layer instead. */
.btn-group > .btn:focus-visible { position: relative; z-index: 1; border-radius: var(--radius-xs); }

/* A hairline between two clusters that do different jobs — filters on one
   side, actions on the other. Its own element rather than a ::before on the
   next button, so it survives the buttons being reordered or wrapped. */
.actions-rule {
    align-self: stretch;
    width: 1px;
    min-height: 24px;
    margin-inline: var(--space-1);
    background: var(--color-border-mid);
}
/* Wrapped onto its own line, a vertical rule between two rows means nothing. */
@media (max-width: 720px) { .actions-rule { display: none; } }

.iconbtn {
    width: 34px; height: 34px; flex: 0 0 34px;
    display: grid; place-items: center;
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-sm);
    background: var(--color-surface-1); color: var(--color-text-secondary);
    cursor: pointer; font-size: 16px;
    transition: background 110ms ease, color 110ms ease, border-color 110ms ease;
}
/* The glyph itself sits ~2px left of its own box centre — a bootstrap-icons
   quirk, same in every direction — so the box+arrow pictograph rides visibly
   off-centre inside a square button no matter how the box is centred. */
.bi-box-arrow-right { margin-left: 2px; }
.iconbtn:hover { background: var(--color-surface-2); color: var(--color-text-primary); border-color: var(--color-border-mid); }
.iconbtn.is-active { background: var(--color-accent-muted); color: var(--color-accent-glow); border-color: var(--color-accent-border); }

/* segmented control */
.segment {
    display: inline-flex; padding: 3px;
    background: var(--color-surface-1);
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-sm);
    gap: 2px;
}
.segment button {
    /* Concentric with the 7px container: inner = outer − 3px padding. */
    height: 26px; padding: 0 var(--space-3); border: 0; border-radius: calc(var(--radius-sm) - 3px);
    background: transparent; color: var(--color-text-secondary);
    font-size: var(--text-xs); font-weight: var(--weight-semibold); cursor: pointer;
    display: inline-flex; align-items: center; gap: 6px;
    transition: background 110ms ease, color 110ms ease;
}
.segment button:hover { color: var(--color-text-primary); }
.segment button.is-active { background: var(--color-surface-3); color: var(--color-text-primary); }

/* ============================================================================
   CARDS
   ============================================================================ */
.card {
    background: var(--color-surface-1);
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-card);
}
.card__head {
    display: flex; align-items: flex-start; justify-content: space-between;
    gap: var(--space-4); padding: var(--space-5) var(--space-5) 0;
}
.card__eyebrow {
    color: var(--color-text-tertiary);
    font-size: var(--text-2xs); font-weight: var(--weight-semibold);
    letter-spacing: var(--tracking-wider); text-transform: uppercase;
}
.card__head h2,
.card__head h3 { margin: 4px 0 0; font-size: var(--text-lg); font-weight: var(--weight-semibold); letter-spacing: var(--tracking-tight); }
.card__head p { margin: 4px 0 0; color: var(--color-text-secondary); font-size: var(--text-sm); }
.card__body { padding: var(--space-5); }

/* ============================================================================
   KPI STRIP
   ============================================================================ */
.kpi-strip {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    background: var(--color-surface-1);
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-lg);
    overflow: hidden;
    margin-bottom: var(--space-5);
}
.kpi {
    padding: var(--space-5);
    border-inline-end: 1px solid var(--color-border-subtle);
    display: flex; flex-direction: column; gap: var(--space-3);
}
.kpi:last-child { border-inline-end: 0; }
.kpi__label {
    display: inline-flex; align-items: center; gap: var(--space-2);
    color: var(--color-text-secondary); font-size: var(--text-xs);
    font-weight: var(--weight-medium);
}
.kpi__label .ico { font-size: 14px; color: var(--color-text-tertiary); }
.kpi__value {
    font-family: var(--font-mono); font-size: var(--text-3xl);
    font-weight: var(--weight-semibold); line-height: 1;
    letter-spacing: var(--tracking-tight);
    font-variant-numeric: tabular-nums;
}
.kpi__foot { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
.kpi__delta {
    display: inline-flex; align-items: center; gap: 5px;
    font-size: var(--text-xs); font-weight: var(--weight-semibold);
    font-family: var(--font-mono); font-variant-numeric: tabular-nums;
}
.kpi__delta .ico { font-size: 13px; }
.kpi__hint { color: var(--color-text-tertiary); font-size: var(--text-2xs); }

/* spark */
.kpi__spark { height: 24px; width: 100%; display: block; }

/* ============================================================================
   SEMANTIC TEXT — never color alone (icon/sign accompany)
   ============================================================================ */
.is-pos { color: var(--color-profit); }
.is-neg { color: var(--color-loss); }
.is-warn { color: var(--color-warning); }
.is-info { color: var(--color-info); }
.muted { color: var(--color-text-secondary); }
.dim { color: var(--color-text-tertiary); }

/* badges */
.badge {
    display: inline-flex; align-items: center; gap: 5px;
    height: 22px; padding: 0 8px;
    border-radius: var(--radius-sm);
    font-size: var(--text-2xs); font-weight: var(--weight-semibold);
    letter-spacing: var(--tracking-wide);
    border: 1px solid transparent;
}
.badge .ico { font-size: 12px; }
.badge--pos { background: var(--color-profit-muted); color: var(--color-profit); }
.badge--neg { background: var(--color-loss-muted); color: var(--color-loss); }
.badge--warn { background: var(--color-warning-muted); color: var(--color-warning); }
.badge--info { background: var(--color-info-muted); color: var(--color-info); }
.badge--neutral { background: var(--color-surface-3); color: var(--color-text-secondary); }
/* Direction is not money: green/red stay reserved for P&L, so a losing LONG
   never shows a green badge beside a red number in the same row. */
.badge--long { background: var(--color-info-muted); color: var(--color-info); }
.badge--short { background: var(--color-warning-muted); color: var(--color-warning); }
.badge--outline { background: transparent; border-color: var(--color-border-mid); color: var(--color-text-secondary); }

/* ============================================================================
   EQUITY CHART
   ============================================================================ */
.chart-wrap { position: relative; }
/* The empty chart says why it is empty, in the middle of the space it is
   talking about. It used to be one sentence with no styling of its own, so it
   settled at the bottom of a tall blank rectangle and read like a caption for
   a chart that was not there. Laid over the plot area, it also does not change
   the card's height when it appears. */
.journal-chart__empty {
    position: absolute;
    inset: 0;
    padding: var(--space-6);
}

.chart-svg { width: 100%; height: 300px; display: block; overflow: visible; }
.chart-grid line { stroke: var(--chart-grid); stroke-width: 1; }
.chart-axis text { fill: var(--chart-axis); font-family: var(--font-mono); font-size: 11px; }
.chart-area { fill: url(#equityFill); }
.chart-line { fill: none; stroke: var(--color-accent-primary); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.chart-dot { fill: var(--color-surface-1); stroke: var(--color-accent-primary); stroke-width: 2; }
.chart-cursor { stroke: var(--color-border-strong); stroke-width: 1; stroke-dasharray: 3 3; }
.chart-tip {
    position: absolute; pointer-events: none; z-index: 5;
    padding: 8px 10px; border-radius: var(--radius-sm);
    background: var(--color-surface-3);
    border: 1px solid var(--color-border-mid);
    box-shadow: var(--shadow-float);
    font-size: var(--text-xs); white-space: nowrap;
    transform: translate(-50%, -120%); transition: opacity 90ms ease; opacity: 0;
}
.chart-tip b { font-family: var(--font-mono); font-size: var(--text-sm); }

/* ---- Brand mark ---------------------------------------------------------- */
/* The RADAR logo comes in two inks and neither one works on both grounds:
   white disappears on parchment, black disappears on midnight. The white set
   is the default because eleven of the seventeen themes are dark, and the six
   light ones take the black set below.

   content: on an <img> swaps the picture without touching a single template,
   and there are fourteen places that draw this logo. A browser that does not
   support it shows the src it was given - the old mark, which is the wrong
   brand but never a broken image. */
img[src*="logo_image"] {
    content: url("../../images/radar-mark-light.png");
}
img[src*="logo_text"] {
    content: url("../../images/radar-text-light.png");
}
/* And the whole lockup, for the places that draw it in one piece. */
img[src*="logo_full"] {
    content: url("../../images/radar-full-light.png");
}
[data-theme="parchment"] img[src*="logo_image"],
[data-theme="daylight"] img[src*="logo_image"],
[data-theme="sandstone"] img[src*="logo_image"],
[data-theme="mint"] img[src*="logo_image"],
[data-theme="lavender"] img[src*="logo_image"],
[data-theme="porcelain"] img[src*="logo_image"] {
    content: url("../../images/radar-mark-dark.png");
}
[data-theme="parchment"] img[src*="logo_text"],
[data-theme="daylight"] img[src*="logo_text"],
[data-theme="sandstone"] img[src*="logo_text"],
[data-theme="mint"] img[src*="logo_text"],
[data-theme="lavender"] img[src*="logo_text"],
[data-theme="porcelain"] img[src*="logo_text"] {
    content: url("../../images/radar-text-dark.png");
}
[data-theme="parchment"] img[src*="logo_full"],
[data-theme="daylight"] img[src*="logo_full"],
[data-theme="sandstone"] img[src*="logo_full"],
[data-theme="mint"] img[src*="logo_full"],
[data-theme="lavender"] img[src*="logo_full"],
[data-theme="porcelain"] img[src*="logo_full"] {
    content: url("../../images/radar-full-dark.png");
}

/* ---- The mark, sweeping -------------------------------------------------- */
/* The beam is the logo's own stroke, not a line drawn over it. The artwork was
   split in two: radar-body-* is the mark with the beam lifted out, and
   radar-beam-* is that stroke alone on a square canvas whose centre is the
   dish's dot - so rotating the canvas about its own centre rotates the beam
   about the dot, which is the one pivot that looks right.

   In this drawing the blade touches nothing - it stops short of the dot and
   passes between the arcs - so lifting it out leaves no notch to repair.

   Nothing leaves the mark: the beam is clipped to the quadrant the arcs cover,
   so it comes in at the top, crosses them, and goes out at the lower right,
   and overflow:hidden keeps even the clip's corners inside the logo's box. */
.radar-mark {
    position: relative;
    display: inline-flex;
    flex: none;
    line-height: 0;
    overflow: hidden;
    isolation: isolate;
}
.radar-mark img {
    display: block;
    height: 100%;
    width: auto;
    /* The whole mark, beam included, because nothing is drawing the beam on
       top of it any more - see the note on ::after below. */
    content: url("../../images/radar-mark-light.png");
}
[data-theme="parchment"] .radar-mark img,
[data-theme="daylight"] .radar-mark img,
[data-theme="sandstone"] .radar-mark img,
[data-theme="mint"] .radar-mark img,
[data-theme="lavender"] .radar-mark img,
[data-theme="porcelain"] .radar-mark img {
    content: url("../../images/radar-mark-dark.png");
}
.radar-mark::after {
    content: "";
    position: absolute;
    /* The dot: 30.5% across the artwork, 47.5% down it. Both numbers, and the
       height below, are printed by ops/split_radar_beam.py - re-run it and
       copy them across whenever the logo is redrawn. */
    left: 30.5%;
    top: 47.5%;
    /* The beam's canvas is 558 of the artwork's 545 units tall: the blade
       reaches past the top of the mark, so its square is taller than the box
       it turns inside. overflow:hidden on .radar-mark is what keeps that in. */
    height: 102%;
    aspect-ratio: 1;
    transform: translate(-50%, -50%) rotate(0deg);
    background: url("../../images/radar-beam-light.png") center / contain no-repeat;
    clip-path: polygon(50% 50%, 50% 0, 100% 0, 100% 62%);
    pointer-events: none;
}
[data-theme="parchment"] .radar-mark::after,
[data-theme="daylight"] .radar-mark::after,
[data-theme="sandstone"] .radar-mark::after,
[data-theme="mint"] .radar-mark::after,
[data-theme="lavender"] .radar-mark::after,
[data-theme="porcelain"] .radar-mark::after {
    background-image: url("../../images/radar-beam-dark.png");
}
/* And then not drawn at all. The sweep is off for now, by request: the logo
   stands still, exactly as it is drawn. Nothing was thrown away - the split
   pictures and ops/split_radar_beam.py are still in the repo - so turning it
   back on is two edits and no new files: delete this rule, and point
   .radar-mark img back at radar-body-*. The two go together; the overlay on
   top of the whole mark would draw the beam twice. */
.radar-mark::after { display: none; }
/* The beam rests at -43.9 degrees in the artwork, so the turn starts there and
   comes back to it: a full circle, ending where the logo sits still. */
@keyframes radarSweep {
    from { transform: translate(-50%, -50%) rotate(0deg); }
    to   { transform: translate(-50%, -50%) rotate(360deg); }
}
/* The beam is always there - it is part of the logo. What hovering, or
   standing in for a spinner, adds is the turning. */
.radar-mark:hover::after,
.radar-mark--scan::after {
    animation: radarSweep 3s linear infinite;
}
.radar-mark--scan::after {
    animation-duration: 2s;
}
/* Not turning means the logo as drawn, beam included. */
html.reduce-motion .radar-mark::after,
html.reduce-motion .radar-mark:hover::after,
html.reduce-motion .radar-mark--scan::after {
    animation: none;
}
@media (prefers-reduced-motion: reduce) {
    .radar-mark::after,
    .radar-mark:hover::after,
    .radar-mark--scan::after { animation: none; }
}

/* chart toolbar */
.chart-stat-row { display: flex; gap: var(--space-6); flex-wrap: wrap; margin-top: var(--space-4); padding-top: var(--space-4); border-top: 1px solid var(--color-border-subtle); }
.chart-stat { display: flex; flex-direction: column; gap: 2px; }
.chart-stat .k { color: var(--color-text-tertiary); font-size: var(--text-2xs); text-transform: uppercase; letter-spacing: var(--tracking-wide); }
.chart-stat .v { font-family: var(--font-mono); font-size: var(--text-md); font-weight: var(--weight-semibold); }
.chart-note { margin: var(--space-3) 0 0; font-size: var(--text-xs); color: var(--color-text-secondary); }
.chart-note a { margin-inline-start: var(--space-2); white-space: nowrap; }
.chart-line--capital { stroke: var(--color-text-tertiary); stroke-width: 1.5; stroke-dasharray: 5 4; }
.chart-key { display: inline-block; width: 18px; border-top: 2px dashed var(--color-text-tertiary); vertical-align: middle; }
.bar-pos { fill: var(--color-profit); }
.bar-neg { fill: var(--color-loss); }
.chart-zero { stroke: var(--color-border-strong); }
/* profit / loss calendar */
.pl-cal { max-width: 400px; margin-inline: auto; }
.pl-cal__head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); margin-bottom: var(--space-3); }
.pl-cal__head h3 { margin: 0; font-size: var(--text-md); font-weight: var(--weight-semibold); }
.pl-cal__step { display: grid; place-items: center; width: 30px; height: 30px; border: 1px solid var(--color-border-subtle); border-radius: var(--radius-sm); background: transparent; color: var(--color-text-secondary); cursor: pointer; }
.pl-cal__step:hover:not(:disabled) { border-color: var(--color-border-strong); color: var(--color-text-primary); }
.pl-cal__step:disabled { opacity: .35; cursor: default; }
.pl-cal__sum { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); margin-bottom: var(--space-3); }
.pl-cal__meta { color: var(--color-text-tertiary); font-size: var(--text-xs); }
.pl-cal__wd { display: block; text-align: center; padding-bottom: 2px; color: var(--color-text-tertiary); font-size: var(--text-2xs); font-style: normal; }
.pl-cal__grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 3px; direction: ltr; }
.pl-cal__day { display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 42px; border-radius: 6px; font-size: 10px; font-style: normal; font-weight: var(--weight-regular); color: var(--color-text-tertiary); }
b.pl-cal__day { color: var(--color-text-primary); }
.pl-cal__day span { font-family: var(--font-mono); font-size: 9.5px; font-weight: var(--weight-semibold); }

/* ============================================================================
   GRID HELPERS
   ============================================================================ */
.grid-2 { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1fr); gap: var(--space-5); }
.grid-3 { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: var(--space-5); }
.stack { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-5); }

/* metric group */
.metric-list { display: grid; gap: 1px; background: var(--color-border-subtle); border-radius: var(--radius); overflow: hidden; }
.metric-row {
    display: flex; align-items: center; justify-content: space-between; gap: var(--space-4);
    padding: var(--space-3) var(--space-4);
    background: var(--color-surface-1);
}
.metric-row__k { display: inline-flex; align-items: center; gap: var(--space-2); color: var(--color-text-secondary); font-size: var(--text-sm); }
.metric-row__k .ico { color: var(--color-text-tertiary); font-size: 14px; }
.metric-row__v { font-family: var(--font-mono); font-size: var(--text-sm); font-weight: var(--weight-semibold); font-variant-numeric: tabular-nums; }

/* ---- Global loading overlay (long-running full-page actions) -------------- */
.app-loading {
    position: fixed; inset: 0; z-index: 3000;
    display: flex; align-items: center; justify-content: center;
    background: color-mix(in srgb, var(--color-void) 60%, transparent);
    backdrop-filter: blur(2px);
}
.app-loading[hidden] { display: none; }
.app-loading__card {
    display: flex; align-items: center; gap: var(--space-3);
    padding: var(--space-4) var(--space-5);
    border: 1px solid var(--color-border-mid); border-radius: var(--radius);
    background: var(--color-surface-1); box-shadow: var(--shadow-float);
}
.app-loading__msg { font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--color-text-primary); }
/* The card names the action and spins beside it — "Sign in", not "Signing in…".
   The three dots were the app telling you it was busy in punctuation; the icon
   says the same thing and keeps moving while it does. */
.app-loading__spinner { font-size: 22px; color: var(--color-accent-primary); }
button.is-loading, .btn.is-loading { opacity: 0.7; cursor: progress; }

/* An inline "this is still arriving" — a table body waiting for its rows, a
   panel waiting for its content. The same scanning logo, at text size. */
.is-loading-inline {
    display: inline-flex; align-items: center; gap: var(--space-2);
    color: var(--color-text-tertiary);
}

/* ---- The loading mark --------------------------------------------------------
   Whatever is on its way - a page, a save, a table's rows, an OTP code - the
   logo turns its beam: the split artwork (radar-body-* under, radar-beam-*
   turning over it, the dot at the same 30.5% / 47.5% as .radar-mark), the
   blade sweeping the whole circle round the dot at one steady speed with a
   wake glowing behind it, and a ping going out from the dish once a turn. It
   replaced lucide's spinning rays, which said "busy" in nobody's voice. The
   logo in the header still stands still (see .radar-mark): only loading moves
   it. The blade used to show only across the arcs, so it popped in at twelve
   every turn; that read as a jump, and a scope does not blink anyway.
   Markup: <span class="radar-loader"><i></i></span>, the <i> being the square
   round the dot the blade turns in. icons.py's aicon "loader", LOADER_HTML in
   app-shell.js and the OTP script all write exactly that. Sized in em, so it
   drops in wherever the spinner sat. */
:root {
    --radar-body: url("../../images/radar-body-light.png");
    --radar-beam: url("../../images/radar-beam-light.png");
    --radar-text: url("../../images/radar-text-light.png");
    --radar-glow: rgba(165, 172, 255, 0.5);
}
:root:is([data-theme="parchment"], [data-theme="daylight"], [data-theme="sandstone"], [data-theme="mint"], [data-theme="lavender"], [data-theme="porcelain"]) {
    --radar-body: url("../../images/radar-body-dark.png");
    --radar-beam: url("../../images/radar-beam-dark.png");
    --radar-text: url("../../images/radar-text-dark.png");
    --radar-glow: rgba(79, 70, 229, 0.38);
}
.radar-loader {
    position: relative; display: inline-block; flex: none; vertical-align: middle;
    height: 1.35em; aspect-ratio: 404 / 545;
    background: var(--radar-body) center / contain no-repeat;
}
/* The square round the dot reaches past the mark's left edge (and a hair over
   its top); inline, it is cut back to the mark's own box so a loader beside a
   label never sweeps across the words. */
.radar-loader > i {
    position: absolute; left: 30.5%; top: 47.5%; height: 102%; aspect-ratio: 1; translate: -50% -50%;
    clip-path: inset(3.4% 0 0 27.8%);
}
.radar-loader > i::before, .radar-loader > i::after { content: ""; position: absolute; inset: 0; }
/* The blade rests at 46.1deg (up and to the right) in the artwork, so -46.1deg
   stands it at twelve: every turn starts there. */
.radar-loader > i::before { background: var(--radar-beam) center / contain no-repeat; animation: radarScan 1.6s linear infinite; }
/* The wake: what it has just crossed, still glowing. */
.radar-loader > i::after {
    background: conic-gradient(from -80deg, transparent, var(--radar-glow) 80deg, transparent 80.5deg);
    -webkit-mask-image: radial-gradient(closest-side, #000 55%, transparent);
            mask-image: radial-gradient(closest-side, #000 55%, transparent);
    animation: radarWake 1.6s linear infinite;
}
@keyframes radarScan { from { rotate: -46.1deg; } to { rotate: 313.9deg; } }
@keyframes radarWake { from { rotate: 0deg; } to { rotate: 360deg; } }
/* The ping, out from the dish as the blade passes twelve. */
.radar-loader::after {
    content: ""; position: absolute; left: 30.5%; top: 47.5%; width: 60%; aspect-ratio: 1; translate: -50% -50%;
    border-radius: 50%; border: max(1px, 0.05em) solid var(--radar-glow); opacity: 0; pointer-events: none;
    animation: radarPing 1.6s cubic-bezier(0.2, 0.6, 0.3, 1) infinite;
}
@keyframes radarPing { from { scale: 0.2; opacity: 0.9; } to { scale: 2.4; opacity: 0; } }
/* Reduced motion slows it rather than stopping it, as it did the spinner: it is
   the only sign the app is still working, and a frozen one reads as a hang.
   The !important is bridge.css's blanket rule to beat. */
@media (prefers-reduced-motion: reduce) {
    .radar-loader > i::before, .radar-loader > i::after { animation-duration: 4.8s !important; animation-iteration-count: infinite !important; }
    .radar-loader::after { display: none; }
}
html.reduce-motion .radar-loader > i::before,
html.reduce-motion .radar-loader > i::after { animation-duration: 4.8s !important; animation-iteration-count: infinite !important; }
html.reduce-motion .radar-loader::after { display: none; }

/* ---- Behind the workspace ------------------------------------------------------
   Under every page after sign-in (base.html): a quarter of a radar scope in the
   top corner away from the sidebar - four range rings, two bearings, and a faint
   beam that passes through every 16 s - fading out toward its rim. It was a
   whole scope centred under the content, bezel, bearings and contacts included,
   and it made every page busier than the cards on it; a corner says "radar" and
   leaves the page alone. Inline vector drawn in the theme's own ink
   (currentColor), so it stays a hairline at any size and every theme gets it
   right without a list of them. */
.radar-bg {
    position: fixed; inset: 0; z-index: -1; pointer-events: none; overflow: hidden; color: var(--color-text-primary);
    --radar-r: min(72vmin, 640px); --radar-x: 0%;
}
/* Left to right, the sidebar is on the left: the far corner is the other one. */
[dir="ltr"] .radar-bg { --radar-x: 100%; }
.radar-bg__scope {
    position: absolute; top: 0; left: 0; width: var(--radar-r); height: var(--radar-r);
    -webkit-mask-image: radial-gradient(circle at 0 0, #000 40%, transparent 100%);
            mask-image: radial-gradient(circle at 0 0, #000 40%, transparent 100%);
}
[dir="ltr"] .radar-bg__scope { left: auto; right: 0; scale: -1 1; }
.radar-bg__rings circle, .radar-bg__spokes line { fill: none; stroke: currentColor; stroke-opacity: 0.12; stroke-width: 1; vector-effect: non-scaling-stroke; }
.radar-bg__rings .is-major { stroke-opacity: 0.2; }
@property --radar-bg-a { syntax: '<angle>'; inherits: false; initial-value: 0deg; }
.radar-bg__sweep {
    position: absolute; inset: 0;
    background: conic-gradient(from var(--radar-bg-a) at var(--radar-x) 0, transparent 0deg, color-mix(in srgb, var(--color-accent-primary) 14%, transparent) 40deg, transparent 40.4deg);
    -webkit-mask-image: radial-gradient(circle var(--radar-r) at var(--radar-x) 0, #000 35%, transparent);
            mask-image: radial-gradient(circle var(--radar-r) at var(--radar-x) 0, #000 35%, transparent);
    /* thirty steps a second is smooth for a beam this slow and this faint, and half the repaints */
    animation: radarBgSweep 6s steps(180) infinite;
}
/* The scope is a quarter, so a full turn kept the beam out of sight three quarters
   of the time (twelve seconds of nothing). It sweeps the quarter it can be seen in -
   its bright edge enters on one side and its tail leaves the other - then rests a
   moment and starts again; the jump back happens while nothing of it shows. */
@keyframes radarBgSweep { 0% { --radar-bg-a: 45deg; } 82% { --radar-bg-a: 185deg; } 100% { --radar-bg-a: 185deg; } }
@keyframes radarBgSweepLtr { 0% { --radar-bg-a: 135deg; } 82% { --radar-bg-a: 275deg; } 100% { --radar-bg-a: 275deg; } }
[dir="ltr"] .radar-bg__sweep { animation-name: radarBgSweepLtr; }
html.reduce-motion .radar-bg__sweep, html.reduce-motion .radar-bg__blips { display: none; }
@media (prefers-reduced-motion: reduce) { .radar-bg__sweep { display: none; } }
@media print { .radar-bg { display: none; } }
/* Contacts: a few dots the beam lights up as its edge reaches them (partials/radar_bg.html places them). */
.radar-bg__blips { position: absolute; inset: 0; }
.radar-bg__blips i { position: absolute; width: 7px; height: 7px; margin: -3.5px; border-radius: 50%; opacity: 0;
    background: var(--color-accent-primary); box-shadow: 0 0 10px 2px color-mix(in srgb, var(--color-accent-primary) 55%, transparent);
    animation: radarBlip 2.4s ease-out both; }
@keyframes radarBlip { 0% { opacity: 0; transform: scale(.4); } 8% { opacity: .9; transform: scale(1.25); } 30% { opacity: .65; transform: scale(1); } 100% { opacity: 0; transform: scale(.9); } }
@media (prefers-reduced-motion: reduce) { .radar-bg__blips { display: none; } }


/* ---- The splash ----------------------------------------------------------------
   Over every page while it gets ready (base.html writes it first in <body>): the
   page's own ground, the mark and its lettering. Whenever the logo appears it
   forms (.is-forming): the dish's dot flashes on, a pulse runs out from it and
   lights the drawing into being from the inside out - arcs, then the R's bowl
   and legs - the beam fades in and starts scanning, and R-A-D-A-R arrive one
   letter at a time. The first page of a visit forms at full length; a save, a
   slow page turn or a later page that keeps us waiting forms quicker (--f
   scales every duration and delay). A later page ready within 0.4 s never shows
   the logo at all, only the ground fading. The same picture stands over a save
   or a slow page turn (.is-veil, window.radarSplash in base.html) with the
   action named under it. It leaves by opening up a little and fading. Without
   JavaScript it is never shown (html.js-splash); with reduced motion it only
   appears, drawn, its beam turning slowly. */
/* px, not em: an initial value has to be computationally independent, or the
   whole registration is dropped and the reveal flips instead of growing */
@property --reach { syntax: '<length>'; inherits: true; initial-value: 400px; }
.radar-splash { display: none; --f: 1; }
html.js-splash .radar-splash {
    position: fixed; inset: 0; z-index: 4000; display: grid; place-content: center; justify-items: center; gap: 22px;
    background: radial-gradient(circle at 50% 44%, color-mix(in srgb, var(--color-accent-primary) 11%, transparent), transparent 42%), var(--color-void);
    transition: opacity 0.45s ease, visibility 0s linear 0s;
}
/* No rings of a scope behind the mark any more. They centred on the whole stage,
   mark and word together, so every one of them read as a circle that had
   missed the logo; the pulse the mark forms from is ring enough. */
html.js-splash .radar-splash.is-veil { background: color-mix(in srgb, var(--color-void) 76%, transparent); backdrop-filter: blur(3px); }
html.js-splash .radar-splash.is-done { opacity: 0; visibility: hidden; pointer-events: none; transition: opacity 0.45s ease, visibility 0s linear 0.45s; }
/* The logo waits, unseen and unmoving, until its pictures are in: the drawing
   can never arrive after its own beam, and the formation starts on the frame it
   appears. */
.radar-splash__stage { position: relative; display: grid; justify-items: center; gap: 18px; opacity: 0; transition: opacity 0.3s ease, scale 0.6s cubic-bezier(0.16, 1, 0.3, 1), filter 0.6s ease; }
.radar-splash.is-ready .radar-splash__stage { opacity: 1; }
.radar-splash:not(.is-ready) .radar-splash__stage *,
.radar-splash:not(.is-ready) .radar-splash__stage *::before,
.radar-splash:not(.is-ready) .radar-splash__stage *::after { animation-play-state: paused; }
.radar-splash.is-done .radar-splash__stage { scale: 1.05; filter: blur(3px); }
.radar-splash__mark { font-size: 78px; }
/* here the blade has room for its whole circle, as on the scope behind it */
.radar-splash__mark > i { clip-path: none; }
.radar-splash__word { position: relative; width: 136px; aspect-ratio: 755 / 112; }
/* the lettering as five copies of the wordmark, each cut down to one letter
   (the ink runs measured from radar-text-*.png: 0-11.9, 20-35.1, 43.8-57,
   64.8-79.7 and 88.2-100 percent), so the letters can arrive one at a time */
.radar-splash__word > i { position: absolute; inset: 0; background: var(--radar-text) center / contain no-repeat; }
.radar-splash__word > i:nth-child(1) { clip-path: inset(-20% 84.04% -20% 0); }
.radar-splash__word > i:nth-child(2) { clip-path: inset(-20% 60.53% -20% 15.96%); }
.radar-splash__word > i:nth-child(3) { clip-path: inset(-20% 39.14% -20% 39.47%); }
.radar-splash__word > i:nth-child(4) { clip-path: inset(-20% 16.02% -20% 60.86%); }
.radar-splash__word > i:nth-child(5) { clip-path: inset(-20% 0 -20% 83.98%); }
.radar-splash__msg { position: relative; margin: 0; min-height: 1.5em; color: var(--color-text-secondary); font-size: var(--text-sm); font-weight: var(--weight-semibold); }
.radar-splash:not(.is-veil) .radar-splash__msg { display: none; }
.radar-splash.is-veil .radar-splash__mark { font-size: 54px; }
.radar-splash.is-veil .radar-splash__word { width: 96px; }
/* The pulse that forms the logo and the flash of the dot, both centred on the dish. */
.radar-splash__pulse { position: absolute; left: 30.5%; top: 47.5%; width: 0; height: 0; pointer-events: none; }
.radar-splash__pulse::before, .radar-splash__pulse::after { content: ""; position: absolute; left: 50%; top: 50%; translate: -50% -50%; border-radius: 50%; opacity: 0; }
.radar-splash__pulse::before { width: 3.2em; height: 3.2em; border: 0.03em solid var(--radar-glow); box-shadow: 0 0 0.25em var(--radar-glow), inset 0 0 0.25em var(--radar-glow); }
.radar-splash__pulse::after { width: 0.7em; height: 0.7em; background: radial-gradient(closest-side, #fff, var(--radar-glow) 45%, transparent); }

/* The formation. The drawing is a mask opening outward from the dot (--reach)
   with the pulse ring riding its edge; the blade keeps its one steady speed and
   only fades in, so nothing it does changes when the formation ends (base.html
   drops .is-forming then). The ping sits the formation out and starts afresh
   from the dot after it; moving its delay instead made it jump in half-grown. */
.radar-splash.is-forming .radar-splash__mark { background: none; animation: radarReach calc(0.75s * var(--f)) cubic-bezier(0.3, 0.2, 0.2, 1) calc(0.12s * var(--f)) both; }
.radar-splash.is-forming .radar-splash__mark::before {
    content: ""; position: absolute; inset: 0; background: var(--radar-body) center / contain no-repeat;
    -webkit-mask-image: radial-gradient(circle at 30.5% 47.5%, #000 calc(var(--reach) - 0.08em), transparent var(--reach));
            mask-image: radial-gradient(circle at 30.5% 47.5%, #000 calc(var(--reach) - 0.08em), transparent var(--reach));
}
.radar-splash.is-forming .radar-splash__pulse::before { animation: radarPulse calc(0.75s * var(--f)) cubic-bezier(0.3, 0.2, 0.2, 1) calc(0.12s * var(--f)) both; }
.radar-splash.is-forming .radar-splash__pulse::after { animation: radarFlash calc(0.6s * var(--f)) ease-out both; }
.radar-splash.is-forming .radar-splash__mark > i { animation: radarBeamIn calc(0.4s * var(--f)) ease calc(0.6s * var(--f)) both; }
.radar-splash.is-forming .radar-splash__mark::after { display: none; }
.radar-splash.is-forming .radar-splash__word > i { animation: radarLetter calc(0.6s * var(--f)) cubic-bezier(0.16, 1, 0.3, 1) calc((0.7s + var(--n) * 0.08s) * var(--f)) both; }
.radar-splash__word > i:nth-child(1) { --n: 0; }
.radar-splash__word > i:nth-child(2) { --n: 1; }
.radar-splash__word > i:nth-child(3) { --n: 2; }
.radar-splash__word > i:nth-child(4) { --n: 3; }
.radar-splash__word > i:nth-child(5) { --n: 4; }
@keyframes radarReach { from { --reach: 0em; } to { --reach: 1.6em; } }
@keyframes radarPulse { 0% { scale: 0; opacity: 0; } 12% { opacity: 1; } 70% { opacity: 0.9; } 100% { scale: 1; opacity: 0; } }
@keyframes radarFlash { 0% { scale: 0; opacity: 0; } 30% { scale: 1.3; opacity: 1; } 100% { scale: 0.6; opacity: 0; } }
@keyframes radarBeamIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes radarLetter { from { opacity: 0; translate: 0 0.35em; filter: blur(3px); } to { opacity: 1; translate: none; filter: none; } }

/* ============================================================================
   RULE WARNING (trades table)
   ============================================================================ */
/* One line from the warning system. Clipped to the column: the whole point is
   to notice it at a glance, and the title attribute carries the full text. */
.trade-warn {
    display: inline-flex; align-items: center; gap: 6px;
    max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    color: var(--color-loss); font-size: var(--text-xs);
}
.trade-warn .bi { flex: none; }


/* The operator's message, opened once on arrival. A <dialog>, so the backdrop,
   the focus trap and Escape come from the browser. */
dialog.announce {
    max-width: min(460px, 92vw); padding: var(--space-5);
    border: 1px solid var(--color-border-mid); border-radius: var(--radius-lg);
    background: var(--color-surface-1); color: var(--color-text-primary);
    box-shadow: var(--shadow-card);
}
dialog.announce::backdrop { background: rgba(0, 0, 0, 0.45); }
/* Text written out in both languages - a sentence built around numbers the
   dictionary cannot hold - shows in the one the page is being read in. */
html[lang="fa"] [data-lang-only="en"],
html:not([lang="fa"]) [data-lang-only="fa"] { display: none !important; }
.announce__head { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-3); }
.announce__head i { font-size: 20px; color: var(--color-accent-glow); }
.announce__head strong { font-size: var(--text-lg); }
.announce--warn .announce__head i { color: var(--color-loss); }
.announce--success .announce__head i { color: var(--color-profit); }
.announce__body { margin: 0 0 var(--space-4); white-space: pre-wrap; unicode-bidi: plaintext; color: var(--color-text-secondary); }
dialog.announce form { display: flex; justify-content: flex-end; }


/* The eye, ported from lucide-animated's eye/eye-off. Those ship as React
   components on motion/react, and this frontend has no React, no bundler and
   no npm to install one into -- so it is the same lucide geometry and the same
   two gestures, each written as one keyframe. The eye blinks: the lid flattens
   to a tenth of its height and the pupil shrinks with it. The eye-off wipes:
   the slash redraws itself along its own length. Both fire on hover and on
   keyboard focus, which is when the originals animate too.

   Inlined at each of its three call sites rather than referenced from one
   <symbol>: an animation has to select the lid and the pupil separately, and
   document CSS does not reach inside a <use> element's shadow tree. */
.ico-eye, .ico-msg, .ico-user, .ico-key, .ico-phone, .ico-plus, .ico-login, .ico-upload {
    width: 1em; height: 1em; vertical-align: -.125em;
    fill: none; stroke: currentColor; stroke-width: 2;
    stroke-linecap: round; stroke-linejoin: round;
}
.ico-eye > * { transform-box: fill-box; transform-origin: 50% 50%; }
.ico-eye .slash { stroke-dasharray: 1 1; stroke-dashoffset: 0; }
/* Anchored on the button, not on the icon's own parent. The reveal eye is a
   direct child of its button, but the send-code bubble sits in a wrapper span,
   and `:hover >` asks the wrapper to be hovered — which only happens when the
   pointer is on the 12px icon itself, not anywhere else on the button. A
   descendant of the button is what "hovering the button" actually means. */
button:hover .ico-eye .lid, button:focus-visible .ico-eye .lid { animation: icoEyeBlink .4s ease-in-out; }
button:hover .ico-eye .pupil, button:focus-visible .ico-eye .pupil { animation: icoEyePupil .4s ease-in-out; }
button:hover .ico-eye .slash, button:focus-visible .ico-eye .slash { animation: icoEyeSlash .6s ease-in-out; }
@keyframes icoEyeBlink { 50% { transform: scaleY(.1); opacity: .3; } }
@keyframes icoEyePupil { 50% { transform: scale(.3); opacity: .3; } }
@keyframes icoEyeSlash { from { stroke-dashoffset: 1; } }
@media (prefers-reduced-motion: reduce) {
    .ico-eye .lid, .ico-eye .pupil, .ico-eye .slash { animation: none !important; }
}

/* message-square and message-square-check, from the same lucide-animated set
   as the eye above and ported the same way. The bubble nudges -- a 7-degree
   wobble either side at 1.05 scale, the spring the original settles with read
   as one keyframe -- and the tick draws itself along its own length the moment
   it appears, which is when the code has actually gone out. */
button:hover .ico-msg, button:focus-visible .ico-msg { animation: icoMsgNudge .5s ease-in-out; }
.ico-msg .tick { stroke-dasharray: 1; animation: icoMsgTick .4s ease-in-out; }
@keyframes icoMsgNudge {
    0%, 100% { transform: rotate(0) scale(1); }
    33% { transform: rotate(-7deg) scale(1.05); }
    66% { transform: rotate(7deg) scale(1.05); }
}
@keyframes icoMsgTick { from { stroke-dashoffset: 1; opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
    .ico-msg, .ico-msg .tick { animation: none !important; }
}

/* user and key, same set and same port as the eye and the bubble above. The
   user draws itself: the head first, the shoulders a fifth of a second behind
   it, which is the delay the original gives that path. The key turns in the
   lock and lets go -- the original holds its turn while hovered and unwinds on
   the way out, and a single keyframe that goes and comes back says the same
   thing without needing a state to leave. */
.ico-user .head, .ico-user .body { stroke-dasharray: 1; }
.ico-user .head { transform-box: fill-box; transform-origin: 50% 50%; }
:hover > .ico-user .head, :focus-visible > .ico-user .head { animation: icoUserHead .4s ease-in-out; }
:hover > .ico-user .body, :focus-visible > .ico-user .body { animation: icoUserBody .4s ease-in-out .2s both; }
:hover > .ico-key, :focus-visible > .ico-key { animation: icoKeyTurn .8s ease-in-out; }
@keyframes icoUserHead { from { stroke-dashoffset: 1; opacity: 0; transform: scale(.5); } }
@keyframes icoUserBody { from { stroke-dashoffset: 1; opacity: 0; } }
@keyframes icoKeyTurn {
    0%, 100% { transform: rotate(0); }
    25% { transform: rotate(-33deg); }
    50% { transform: rotate(-25deg); }
    75% { transform: rotate(-28deg); }
}
@media (prefers-reduced-motion: reduce) {
    .ico-user .head, .ico-user .body, .ico-key { animation: none !important; }
}

/* The handset rings: it snaps to ten degrees and shakes itself back to
   straight, swelling a tenth on the way — the rotate and scale tracks the
   original runs together over the same 0.9s. */
:hover > .ico-phone, :focus-visible > .ico-phone { animation: icoPhoneRing .9s ease-in-out; }
@keyframes icoPhoneRing {
    0%   { transform: rotate(10deg) scale(1); }
    25%  { transform: rotate(20deg) scale(1.1); }
    50%  { transform: rotate(-10deg) scale(1.1); }
    75%  { transform: rotate(10deg) scale(1.1); }
    100% { transform: rotate(0) scale(1); }
}
@media (prefers-reduced-motion: reduce) {
    .ico-phone { animation: none !important; }
}

/* The plus turns a half turn, which for a plus lands exactly where it started
   — the original springs to 180 and holds, and the symmetry is why it can. The
   login arrow steps through the door and back, the 3-unit nudge the original
   gives the arrow and the bar together. */
:hover > .ico-plus, :focus-visible > .ico-plus { animation: icoPlusTurn .5s cubic-bezier(.34, 1.4, .64, 1); }
:hover > .ico-login .arrow, :focus-visible > .ico-login .arrow,
:hover > .ico-login .bar, :focus-visible > .ico-login .bar { animation: icoLoginIn .4s ease-in-out; }
@keyframes icoPlusTurn { from { transform: rotate(0); } to { transform: rotate(180deg); } }
@keyframes icoLoginIn { 50% { transform: translateX(3px); } }
@media (prefers-reduced-motion: reduce) {
    .ico-plus, .ico-login .arrow, .ico-login .bar { animation: none !important; }
}

/* Upload: the arrow lifts out of the tray and drops back, the one gesture the
   original plays. Only the arrow moves -- the tray it leaves behind is what
   makes the lift read as a lift. */
:hover > .ico-upload .arrow, :focus-visible > .ico-upload .arrow { animation: icoUploadOut .55s ease-in-out; }
@keyframes icoUploadOut { 45% { transform: translateY(-3px); } }
@media (prefers-reduced-motion: reduce) {
    .ico-upload .arrow { animation: none !important; }
}

/* Press, for every icon above. A separate animation name on purpose: a mouse
   is already hovering by the time it presses, so the hover rule's animation
   has both fired and finished, and re-declaring the same name changes nothing
   the browser would restart from. A different name is a different animation,
   which is what makes it play. It also covers the case hover cannot reach at
   all — a touch screen, where these icons would otherwise never move. Last in
   the file so it wins the tie against the :hover rules while held; letting go
   hands the icon back to its own gesture. */
button:active .ico-eye, button:active .ico-msg,
:active > .ico-user, :active > .ico-key, :active > .ico-phone,
:active > .ico-plus, :active > .ico-login, :active > .ico-upload { animation: icoPress .28s ease-out; }
@keyframes icoPress { 50% { transform: scale(.82); } }
@media (prefers-reduced-motion: reduce) {
    button:active .ico-eye, button:active .ico-msg,
    :active > .ico-user, :active > .ico-key, :active > .ico-phone,
    :active > .ico-plus, :active > .ico-login, :active > .ico-upload { animation: none !important; }
}

/* ── The animated lucide set ──────────────────────────────────────────────
   Geometry and gestures both come from lucide-animated.com's registry: each
   icon there is a React component whose parts carry framer-motion variants,
   and each variant is written here as the keyframe that does the same thing.
   Their springs (stiffness/damping) become cubic-beziers that overshoot once,
   which is what a spring of that stiffness looks like.

   The icons are inline rather than a sprite because nearly every gesture moves
   a part -- the arrow inside download, the lid on the trash, the eyes on the
   bot -- and document CSS cannot select inside a <use> shadow tree.

   HOVER is the trigger, as on their own site: the control that holds the icon,
   hovered or keyboard-focused. Held (:active) plays the same gesture, which is
   the only way a touch screen ever sees one. */
.aico {
    width: 1em; height: 1em; vertical-align: -.125em; flex: none;
    fill: none; stroke: currentColor; stroke-width: 2;
    stroke-linecap: round; stroke-linejoin: round;
    overflow: visible;
}
.aico > * { transform-box: fill-box; transform-origin: 50% 50%; }
.nav__item .aico, .settings-nav a .aico, .settings-nav__label .aico { width: 1em; height: 1em; }

/* One list, used by every rule below: a control, hovered, focused or held. */
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-chart-line .d1 { animation: aiDraw .3s ease-out .15s both; }
/* languages redraws itself in four beats, a tenth of a second apart — the
   accent over the A, then the rule under it, then the stroke, then the
   glyph beside it. Their stagger, as four delays. */
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-languages .d1 { animation: aiDraw .45s ease-out both; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-languages .d2 { animation: aiDraw .45s ease-out .1s both; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-languages .d3 { animation: aiDraw .45s ease-out .2s both; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-languages .d4 path { animation: aiDraw .45s ease-out .3s both; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-cpu .pv path { animation: aiPinsY .5s ease-in-out 2; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-cpu .ph path { animation: aiPinsX .5s ease-in-out 2; }
/* Each pin stretches about its own middle. Scaling the group instead would
   have slid the four pins apart rather than lengthening any of them. */
.aico-cpu path { transform-box: fill-box; transform-origin: 50% 50%; }
/* Nobody at lucide-animated animated the headphones, so this one is ours: the
   two cups take turns pressing outward the way a pair does when someone puts
   them on, and the band flexes down a hair to follow. Parts moving against
   each other, rather than the whole icon nodding. */
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-headphones .cupL { animation: aiCupL .7s ease-in-out; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-headphones .cupR { animation: aiCupR .7s ease-in-out .12s both; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-headphones .band { animation: aiBand .7s ease-in-out; }
.aico-headphones path { transform-box: fill-box; transform-origin: 50% 50%; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-gauge .needle { animation: aiNeedle .7s cubic-bezier(.34, 1.4, .64, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-search { animation: aiSearch 1s cubic-bezier(.34, 1.3, .64, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-bell { animation: aiBell .5s ease-in-out; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-moon { animation: aiMoon 1.2s ease-in-out; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) :is(.aico-settings, .aico-cog) { animation: aiHalfTurn .9s cubic-bezier(.34, 1.32, .64, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-plus { animation: aiHalfTurn .7s cubic-bezier(.34, 1.4, .64, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-download .p1 { animation: aiArrowDown .5s cubic-bezier(.34, 1.5, .64, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-logout .p1 { animation: aiStepOut .4s ease-in-out; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-send .p1 { animation: aiSendFly .5s ease-in-out; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-send .p2 { animation: aiSendTrail .55s ease-in-out .1s; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-check .d1,
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-check-check .d1 { animation: aiDrawPop .4s ease-out; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-check-check .d2 { animation: aiDrawPop .4s ease-out .1s both; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-x .d1 { animation: aiDraw .4s ease-in-out; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-x .d2 { animation: aiDraw .4s ease-in-out .2s both; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-clock .p1 { animation: aiHourHand .6s cubic-bezier(.4, 0, .2, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-clock .p2 { animation: aiMinuteHand .5s ease-in-out; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-maximize .p1 { animation: aiCornerTL .5s cubic-bezier(.34, 1.4, .64, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-maximize .p2 { animation: aiCornerTR .5s cubic-bezier(.34, 1.4, .64, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-maximize .p3 { animation: aiCornerBL .5s cubic-bezier(.34, 1.4, .64, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-maximize .p4 { animation: aiCornerBR .5s cubic-bezier(.34, 1.4, .64, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-shrink .p1 { animation: aiPullTL .5s cubic-bezier(.34, 1.4, .64, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-shrink .p2 { animation: aiPullTR .5s cubic-bezier(.34, 1.4, .64, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-shrink .p3 { animation: aiPullBL .5s cubic-bezier(.34, 1.4, .64, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-shrink .p4 { animation: aiPullBR .5s cubic-bezier(.34, 1.4, .64, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-dollar .d1 { animation: aiDraw .6s ease-in-out; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-dollar .d2 { animation: aiDrawBack .4s ease-in-out .5s both; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-link .p1,
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-link .p2 { animation: aiLinkTug 1s ease-in-out; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-panels .p1 { animation: aiPanelTop .5s ease-out; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-panels .p2 { animation: aiPanelLeft .5s ease-out .3s both; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-panels .p3 { animation: aiPanelRight .5s ease-out .4s both; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-home .d1 { animation: aiDraw .6s ease-in-out; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-menu .p1 { animation: aiMenuTop .55s cubic-bezier(.34, 1.4, .64, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-menu .p2 { animation: aiMenuMid .55s ease-in-out; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-menu .p3 { animation: aiMenuBottom .55s cubic-bezier(.34, 1.4, .64, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-rows-compact .p1, :is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-rows-cozy .p1 { animation: aiRowsDown .5s ease-in-out; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-rows-compact .p4, :is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-rows-cozy .p3 { animation: aiRowsUp .5s ease-in-out; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-rows-compact .p2 { animation: aiRowsDownHalf .5s ease-in-out; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-rows-compact .p3 { animation: aiRowsUpHalf .5s ease-in-out; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-rows-comfortable .p1 { animation: aiRowsUp .5s ease-in-out; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-rows-comfortable .p2 { animation: aiRowsDown .5s ease-in-out; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-ticket .p1 { animation: aiTicketLeft .5s cubic-bezier(.34, 1.4, .64, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-ticket .p2 { animation: aiTicketRight .5s cubic-bezier(.34, 1.4, .64, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-sort-az .p1,
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-sort-za .p1 { animation: aiSwapDown .55s cubic-bezier(.34, 1.32, .64, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-sort-az .p2,
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-sort-za .p2 { animation: aiSwapUp .55s cubic-bezier(.34, 1.32, .64, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-user-plus .p1 { animation: aiPlusIn .45s ease-out .25s both; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-user-round-plus .d1 { animation: aiDraw .2s ease-out .3s both; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-user-round-plus .d2 { animation: aiDraw .2s ease-out .6s both; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-delete .p1 { animation: aiLid .4s cubic-bezier(.34, 1.5, .64, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-delete .p2 { animation: aiCan .4s cubic-bezier(.34, 1.5, .64, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-chart-pie .p1 { animation: aiSlice .5s cubic-bezier(.34, 1.5, .64, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-copy .p1 { animation: aiCopyFront .5s cubic-bezier(.34, 1.4, .64, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-copy .p2 { animation: aiCopyBack .5s cubic-bezier(.34, 1.4, .64, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-mic .p1 { animation: aiCapsule .6s ease-in-out; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-mic-off .d1 { animation: aiDraw .4s ease-in-out .15s both; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-connect .p1 { animation: aiPlugOut .5s cubic-bezier(.34, 1.4, .64, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-connect .p2 { animation: aiSocketOut .5s cubic-bezier(.34, 1.4, .64, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-bot .p1,
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-bot-chat .p2 { animation: aiBlink .5s ease-in-out .1s; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-bot-chat { animation: aiBotWobble 1s ease-in-out; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-bot-chat .p1 { animation: aiBubble .6s ease-in-out 2; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-sparkles .p1 { animation: aiSparkle 1s ease-in-out; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-clipboard-heart .p1 { animation: aiHeartBeat .8s ease-in-out; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-sparkles .p2 { animation: aiStarBlink 2s cubic-bezier(.34, 1.2, .64, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-sparkles .p3 { animation: aiStarBlink 2s cubic-bezier(.34, 1.2, .64, 1) .15s both; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-sliders :is(.p1, .k1) { animation: aiSlideStart .5s cubic-bezier(.34, 1.5, .64, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-sliders :is(.p4, .k2) { animation: aiSlideEndFar .5s cubic-bezier(.34, 1.5, .64, 1); }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-sliders .k3 { animation: aiSlideStartFar .5s cubic-bezier(.34, 1.5, .64, 1); }

/* Staggered fades: the sun's rays, the calendar's dots, the language strokes --
   one keyframe, eight delays. */
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-sun :is(.r1, .r2, .r3, .r4, .r5, .r6, .r7, .r8) { animation: aiFadeIn .3s ease-out both; }
.aico-sun .r1 { animation-delay: .1s; } .aico-sun .r2 { animation-delay: .2s; } .aico-sun .r3 { animation-delay: .3s; } .aico-sun .r4 { animation-delay: .4s; }
.aico-sun .r5 { animation-delay: .5s; } .aico-sun .r6 { animation-delay: .6s; } .aico-sun .r7 { animation-delay: .7s; } .aico-sun .r8 { animation-delay: .8s; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-calendar :is(.r1, .r2, .r3, .r4, .r5, .r6) { animation: aiDotDim .4s ease-in-out both; }
.aico-calendar .r1 { animation-delay: 0s; } .aico-calendar .r2 { animation-delay: .1s; } .aico-calendar .r3 { animation-delay: .2s; }
.aico-calendar .r4 { animation-delay: .3s; } .aico-calendar .r5 { animation-delay: .4s; } .aico-calendar .r6 { animation-delay: .5s; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-languages :is(.r1, .r2, .r3, .r4) { animation: aiDraw .5s ease-out both; }
.aico-languages .r1 { animation-delay: 0s; } .aico-languages .r2 { animation-delay: .1s; } .aico-languages .r3 { animation-delay: .2s; } .aico-languages .r4 { animation-delay: .3s; }

@keyframes aiCupL { 0%, 100% { transform: translateX(0) scale(1); } 45% { transform: translateX(-1.4px) scale(1.12); } }
@keyframes aiCupR { 0%, 100% { transform: translateX(0) scale(1); } 45% { transform: translateX(1.4px) scale(1.12); } }
@keyframes aiBand { 0%, 100% { transform: scaleX(1) translateY(0); } 45% { transform: scaleX(1.06) translateY(.6px); } }
@keyframes aiNeedle { 0%, 100% { transform: translate(0, 0) rotate(0); } 55% { transform: translate(.5px, 3px) rotate(72deg); } }
@keyframes aiPinsY { 50% { transform: scaleY(1.5); opacity: .8; } }
@keyframes aiPinsX { 50% { transform: scaleX(1.5); opacity: .8; } }
@keyframes aiSearch { 0%, 100% { transform: translate(0, 0); } 33% { transform: translate(0, -4px); } 66% { transform: translate(-3px, 0); } }
@keyframes aiBell { 0%, 100% { transform: rotate(0); } 25% { transform: rotate(-10deg); } 50% { transform: rotate(10deg); } 75% { transform: rotate(-10deg); } }
@keyframes aiMoon { 0%, 100% { transform: rotate(0); } 20% { transform: rotate(-10deg); } 40% { transform: rotate(10deg); } 60% { transform: rotate(-5deg); } 80% { transform: rotate(5deg); } }
@keyframes aiHalfTurn { from { transform: rotate(0); } to { transform: rotate(180deg); } }
@keyframes aiSpin { to { transform: rotate(360deg); } }
@keyframes aiArrowDown { 55% { transform: translateY(2px); } }
@keyframes aiStepOut { 0%, 100% { transform: translateX(0); } 35% { transform: translateX(-3px); } 70% { transform: translateX(2px); } }
@keyframes aiSendFly { 55% { transform: translate(3px, -3px) scale(.8); } }
@keyframes aiSendTrail { from { stroke-dashoffset: 1; opacity: 0; } 60% { opacity: 1; } to { stroke-dashoffset: 0; opacity: 0; } }
@keyframes aiDraw { from { stroke-dashoffset: 1; opacity: 0; } 10% { opacity: 1; } }
@keyframes aiDrawBack { from { stroke-dashoffset: -1; opacity: 0; } 10% { opacity: 1; } }
@keyframes aiDrawPop { from { stroke-dashoffset: 1; opacity: 0; transform: scale(.5); } 10% { opacity: 1; } }
@keyframes aiHourHand { to { transform: rotate(360deg); } }
@keyframes aiMinuteHand { 55% { transform: rotate(45deg); } }
@keyframes aiCornerTL { 55% { transform: translate(-2px, -2px); } }
@keyframes aiCornerTR { 55% { transform: translate(2px, -2px); } }
@keyframes aiCornerBL { 55% { transform: translate(-2px, 2px); } }
@keyframes aiCornerBR { 55% { transform: translate(2px, 2px); } }
@keyframes aiPullTL { 55% { transform: translate(-1px, -1px); } }
@keyframes aiPullTR { 55% { transform: translate(1px, -1px); } }
@keyframes aiPullBL { 55% { transform: translate(-1px, 1px); } }
@keyframes aiPullBR { 55% { transform: translate(1px, 1px); } }
@keyframes aiLinkTug { 0%, 100% { transform: rotate(0); } 25% { transform: rotate(-5deg); } 60% { transform: rotate(0); } }
@keyframes aiPanelTop { from { opacity: 0; transform: translateY(-5px); } 40% { opacity: 1; } }
@keyframes aiPanelLeft { from { opacity: 0; transform: translateX(-10px); } 50% { opacity: 1; } }
@keyframes aiPanelRight { from { opacity: 0; transform: translateX(10px); } 50% { opacity: 1; } }
@keyframes aiMenuTop { 55% { transform: translateY(6px) rotate(45deg); } }
@keyframes aiMenuMid { 40%, 70% { opacity: 0; } }
@keyframes aiMenuBottom { 55% { transform: translateY(-6px) rotate(-45deg); } }
@keyframes aiRowsDown { 50% { transform: translateY(2px); } }
@keyframes aiRowsUp { 50% { transform: translateY(-2px); } }
@keyframes aiRowsDownHalf { 50% { transform: translateY(.8px); } }
@keyframes aiRowsUpHalf { 50% { transform: translateY(-.8px); } }
@keyframes aiTicketLeft { 55% { transform: translateX(-3px); } }
@keyframes aiTicketRight { 55% { transform: translateX(3px) rotate(4deg); } }
@keyframes aiSwapDown { 55% { transform: translateY(10px); } }
@keyframes aiSwapUp { 55% { transform: translateY(-10px); } }
@keyframes aiPlusIn { from { opacity: 0; transform: scale(0) rotate(-90deg); } 70% { opacity: 1; transform: scale(1.15) rotate(0); } }
@keyframes aiLid { 55% { transform: translateY(-1.1px); } }
@keyframes aiCan { 55% { transform: translateY(.5px); } }
@keyframes aiSlice { 55% { transform: translate(1.1px, -1.1px); } }
@keyframes aiCopyFront { 55% { transform: translate(-3px, -3px); } }
@keyframes aiCopyBack { 55% { transform: translate(3px, 3px); } }
@keyframes aiCapsule { 0%, 100% { transform: translateY(0); } 25% { transform: translateY(-3px); } 50% { transform: translateY(0); } 75% { transform: translateY(-2px); } }
@keyframes aiPlugOut { 55% { transform: translate(3px, -3px); } }
@keyframes aiSocketOut { 55% { transform: translate(-3px, 3px); } }
@keyframes aiBlink { 50% { transform: scaleY(.1); } }
@keyframes aiBotWobble { 0%, 100% { transform: rotate(0) translateY(0) scale(1); } 25% { transform: rotate(-3deg) translateY(1.5px) scale(1.03); } 55% { transform: rotate(3deg) translateY(-1.5px) scale(1.03); } }
@keyframes aiBubble { 50% { transform: scale(1.04); } }
@keyframes aiSparkle { 0%, 100% { fill: none; transform: translateY(0); } 25% { fill: currentColor; transform: translateY(-1px); } 60% { fill: currentColor; transform: translateY(0); } }
@keyframes aiStarBlink { 0% { opacity: 0; } 16% { opacity: 1; } 32%, 84% { opacity: 0; } 100% { opacity: 1; } }
@keyframes aiSlideStart { 55% { transform: translateX(-5px); } }
@keyframes aiSlideStartFar { 55% { transform: translateX(-4px); } }
@keyframes aiSlideEndFar { 55% { transform: translateX(5px); } }
@keyframes aiFadeIn { from { opacity: 0; } }
@keyframes aiDotDim { 50% { opacity: .3; } }
@keyframes aiHeartBeat { 0%, 100% { transform: scale(1); } 22% { transform: scale(1.22); } 44% { transform: scale(0.96); } 66% { transform: scale(1.12); } }

/* ---- Settings rail icons ----
   Every one of these moves a part of itself rather than being scaled as a
   whole. A column of eighteen rows that each grow on hover reads as a
   column that flinches; a column where the gear turns, the flag lifts and
   the signal leaves the mast reads as a column that answers. */
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-user-cog .spin { animation: aiSpin 1.1s ease-in-out; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-palette .c1 { animation: aiDotDim .7s ease-in-out 0s; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-palette .c2 { animation: aiDotDim .7s ease-in-out 0.08s; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-palette .c3 { animation: aiDotDim .7s ease-in-out 0.16s; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-palette .c4 { animation: aiDotDim .7s ease-in-out 0.24s; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-crosshair .pv path { animation: aiPinsY .5s ease-in-out 2; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-crosshair .ph path { animation: aiPinsX .5s ease-in-out 2; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-flag .cloth { animation: aiFlagWave .9s ease-in-out; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-smile .d1 { animation: aiDraw .45s ease-out both; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-smile .eyes { animation: aiBlink .6s ease-in-out .3s; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-notebook .rings path { animation: aiPinsX .55s ease-in-out; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-id-card .d1 { animation: aiDraw .4s ease-out both; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-id-card .d2 { animation: aiDraw .4s ease-out .1s both; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-wallet .c1 { animation: aiDotDim .8s ease-in-out 2; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-workflow .d1 { animation: aiDraw .45s ease-out both; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-shield-alert .alert { animation: aiDotDim .55s ease-in-out 2; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-triangle-alert .alert { animation: aiDotDim .55s ease-in-out 2; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-radio-tower .w1 { animation: aiFadeIn .5s ease-out both; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-radio-tower .w2 { animation: aiFadeIn .5s ease-out .15s both; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-message-square .d1 { animation: aiDraw .35s ease-out both; }
:is(a, button, label, summary, .chip, .tab, .nav__item, .workspace-tab, [role="button"]):is(:hover, :focus-visible, :active) .aico-message-square .d2 { animation: aiDraw .35s ease-out .12s both; }
/* The cloth pivots at the pole, so the transform origin is the left edge. */
.aico-flag .cloth { transform-origin: 0% 50%; }
.aico-notebook .rings path, .aico-crosshair :is(.pv, .ph) path { transform-box: fill-box; transform-origin: 50% 50%; }
@keyframes aiFlagWave { 30% { transform: skewY(-6deg) translateY(-.5px); } 65% { transform: skewY(3deg); } }
/* Dash-drawn parts need a unit-length dash to travel along. */
.aico-smile .d1, .aico-id-card :is(.d1, .d2), .aico-workflow .d1,
.aico-message-square :is(.d1, .d2) { stroke-dasharray: 1; }

/* Anything that draws itself needs a dash to draw along, and pathLength="1" in
   the markup is what makes one unit mean the whole stroke. */
.aico :is(.d1, .d2, .r1, .r2, .r3, .r4, .p2) { stroke-dasharray: 1; }
.aico-languages :is(.d3, .d4 path) { stroke-dasharray: 1; }

@keyframes aiSpin { to { transform: rotate(360deg); } }
.aico-calendar :is(.r1, .r2, .r3, .r4, .r5, .r6), .aico-sun :is(.r1, .r2, .r3, .r4) { stroke-dasharray: none; }
.aico-send .p2 { stroke-dasharray: 2 2; }
.aico-sliders .p2, .aico-ticket .p2, .aico-copy .p2, .aico-link .p2, .aico-connect .p2,
.aico-sort-az .p2, .aico-sort-za .p2, .aico-panels .p2, .aico-bot-chat .p2, .aico-sparkles .p2,
.aico-maximize .p2, .aico-shrink .p2, .aico-clock .p2, .aico-delete .p2 { stroke-dasharray: none; }

@media (prefers-reduced-motion: reduce) {
    .aico, .aico * { animation: none !important; }
}
/* The same answer for the switch in Settings → Appearance. The machine's
   preference and the app's own switch have to reach the same rules, and this
   half was missing: reduce-motion only ever blanket-shortened durations, which
   left the icons hovering, twitching and drawing themselves at 0.001ms rather
   than holding still. */
html.reduce-motion .aico,
html.reduce-motion .aico * { animation: none !important; }
html.reduce-motion .settings-nav a .ico,
html.reduce-motion .settings-nav__label .ico { transform: none !important; }

/* What a new password still has to clear, one row per rule, each row gone the
   moment it is met. No gap on the list and the spacing inside each row instead:
   a gap is charged for a row that has collapsed to nothing, which would leave
   the list holding a stack of empty space after the last rule went. */
.pwd-rules { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
/* The row's own spacing, not the inner span's: overflow:hidden clips content
   and not padding, so a padded span left 8px of empty row behind after the
   text had collapsed to nothing. */
.pwd-rules li {
    display: grid; grid-template-rows: 1fr; padding-top: var(--space-2);
    transition: grid-template-rows 240ms ease, padding-top 240ms ease, opacity 180ms ease;
}
.pwd-rules li > span {
    overflow: hidden; min-height: 0;
    display: flex; align-items: center; gap: var(--space-2);
    font-size: var(--text-2xs); color: var(--color-text-tertiary);
}
/* The delay is on the met state alone, so it is spent closing the row and not
   re-opening one: a tick that draws itself and vanishes in the same frame reads
   as a row that disappeared rather than one that was satisfied. */
.pwd-rules li.is-met { grid-template-rows: 0fr; padding-top: 0; opacity: 0; transition-delay: 420ms; }
.pwd-rules__mark { width: 14px; height: 14px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.pwd-rules__mark circle { opacity: 0.45; transition: stroke 200ms ease, opacity 200ms ease; }
.pwd-rules__mark .tick { stroke-dasharray: 1; stroke-dashoffset: 1; transition: stroke-dashoffset 260ms ease; }
.pwd-rules li.is-met .pwd-rules__mark { stroke: var(--color-profit); }
.pwd-rules li.is-met .pwd-rules__mark circle { opacity: 1; }
.pwd-rules li.is-met .pwd-rules__mark .tick { stroke-dashoffset: 0; }

/* ============================================================================
   REPORTS: risk and timing panes
   ============================================================================ */
.report-tabs { margin: var(--space-5) 0; align-self: start; width: fit-content; max-width: 100%; }
.metric-row__k { flex-direction: column; align-items: flex-start; gap: 0; }
.metric-row__hint { color: var(--color-text-tertiary); font-size: var(--text-2xs); }
.metric-row__hint:empty { display: none; }
.bar-neutral { fill: var(--color-text-tertiary); }
.mc-band { fill: var(--color-accent-primary); }
.mc-median { fill: none; stroke: var(--color-accent-primary); stroke-width: 1.5; stroke-dasharray: 4 3; }
.hbar-row { display: grid; grid-template-columns: 64px minmax(0, 1fr) 36px; align-items: center; gap: var(--space-3); padding: 5px 0; font-size: var(--text-sm); }
.hbar-row b { text-align: end; font-family: var(--font-mono); font-weight: var(--weight-semibold); }
.hbar { display: block; height: 8px; border-radius: 4px; background: var(--color-border-subtle); overflow: hidden; }
.hbar i { display: block; height: 100%; border-radius: 4px; background: var(--color-accent-primary); }
.hbar i.is-neg { background: var(--color-loss); }
.hm { display: grid; grid-template-columns: 72px repeat(24, minmax(0, 1fr)); gap: 3px; direction: ltr; font-size: 10px; color: var(--color-text-tertiary); }
.hm > b, .hm > i { min-height: 24px; border-radius: 4px; font-style: normal; }
.hm > i:not(.hm__h):not(.hm__d) { background: var(--color-border-subtle); opacity: .5; }
.hm__h { min-height: 14px !important; text-align: center; }
.hm__d { display: flex; align-items: center; }
.metric-list--wide { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }

/* habits on the review page */
.habit { padding: var(--space-3) 0; border-bottom: 1px solid var(--color-border-subtle); border-inline-start: 3px solid var(--color-border-strong); padding-inline-start: var(--space-4); margin-bottom: var(--space-3); }
.habit:last-child { margin-bottom: 0; border-bottom: 0; }
.habit h3 { margin: 0 0 var(--space-2); font-size: var(--text-sm); }
.habit dl { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-6); margin: 0; }
.habit dl div { display: flex; gap: var(--space-2); font-size: var(--text-xs); color: var(--color-text-secondary); }
.habit dd { margin: 0; font-family: var(--font-mono); color: var(--color-text-primary); }
.habit--good { border-inline-start-color: var(--color-profit); }
.habit--warn { border-inline-start-color: var(--color-warning, #d8a13f); }
.habit--bad { border-inline-start-color: var(--color-loss); }

/* what-if simulator */
.whatif-layout { display: grid; grid-template-columns: minmax(260px, 340px) minmax(0, 1fr); gap: var(--space-5); align-items: start; }
@media (max-width: 900px) { .whatif-layout { grid-template-columns: minmax(0, 1fr); } }
.whatif-rules { display: grid; gap: var(--space-3); }
.whatif-rules label { display: flex; gap: var(--space-3); align-items: flex-start; padding: var(--space-3); border: 1px solid var(--color-border-subtle); border-radius: var(--radius); cursor: pointer; font-size: var(--text-sm); }
.whatif-rules label:hover { border-color: var(--color-border-strong); }
.whatif-rules input[type="checkbox"] { margin-top: 3px; flex: none; accent-color: var(--color-accent-primary); }
.whatif-rules small { display: block; color: var(--color-text-tertiary); font-size: var(--text-2xs); font-weight: normal; }
.whatif-rules input[type="number"] { width: 58px; padding: 1px 6px; text-align: center; border: 1px solid var(--color-border-subtle); border-radius: 6px; background: var(--color-surface-2, transparent); color: inherit; }
.whatif-cmp-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: var(--space-3); margin-bottom: var(--space-4); }
.whatif-cmp { display: flex; flex-direction: column; gap: 2px; padding: var(--space-3); border: 1px solid var(--color-border-subtle); border-radius: var(--radius); }
.whatif-cmp span { color: var(--color-text-tertiary); font-size: var(--text-2xs); }
.whatif-cmp small { color: var(--color-text-secondary); font-family: var(--font-mono); }
.whatif-cmp b { font-family: var(--font-display); font-size: var(--text-xl); font-weight: var(--weight-bold); letter-spacing: -0.01em; }
.whatif-cmp__gap { display: inline-flex; align-items: center; gap: 3px; font-family: var(--font-mono); font-size: var(--text-xs); font-weight: var(--weight-semibold); color: var(--color-text-tertiary); }
.whatif-cmp__gap.is-pos { color: var(--color-profit); }
.whatif-cmp__gap.is-neg { color: var(--color-loss); }
.whatif-cmp small em { font-style: normal; color: var(--color-text-tertiary); }
[data-report-pane] .card__body, .trades-page .stack .card__body { overflow-x: auto; }
@media (max-width: 760px) {
    [data-report-pane] .grid-2, .trades-page .stack .grid-2 { grid-template-columns: minmax(0, 1fr); }
    .hm { min-width: 560px; }
}

/* reports: tab strip, overview bars */
.report-tabs { display: flex; gap: 2px; width: 100%; overflow-x: auto; scrollbar-width: none; }
.report-tabs::-webkit-scrollbar { display: none; }
.report-tabs button { flex: none; white-space: nowrap; }
.chart-line--loss { stroke: var(--color-loss); }
.netbar { display: grid; grid-template-columns: minmax(56px, 1fr) minmax(0, 1.4fr) auto; grid-template-areas: "k track v" "k track s"; align-items: center; column-gap: var(--space-3); padding: 6px 0; font-size: var(--text-sm); }
.netbar__k { grid-area: k; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.netbar__track { grid-area: track; height: 8px; border-radius: 4px; background: var(--color-border-subtle); overflow: hidden; }
.netbar__track i { display: block; height: 100%; border-radius: 4px; }
.netbar b { grid-area: v; text-align: end; font-family: var(--font-mono); font-size: var(--text-sm); }
.netbar small { grid-area: s; text-align: end; color: var(--color-text-tertiary); font-size: var(--text-2xs); }
@media (max-width: 900px) { [data-report-pane] .grid-3 { grid-template-columns: minmax(0, 1fr); } }
.reports-summary-grid .ref-stat-card__value { font-size: clamp(1.25rem, 2.4vw, 1.9rem); overflow-wrap: anywhere; }
.netbar__track i.bar-pos { background: var(--color-profit); }
.netbar__track i.bar-neg { background: var(--color-loss); }

/* dashboard: one page in named parts, with a bar that follows the scroll */
.dash-section { margin-bottom: var(--space-7, 40px); scroll-margin-top: 160px; }
.dash-section[hidden] { display: none; }
.dash-section__head { display: flex; align-items: center; gap: var(--space-4); margin-bottom: var(--space-4); }
.dash-section__head h2 { margin: 0; font-size: var(--text-md); font-weight: var(--weight-semibold); color: var(--color-text-secondary); white-space: nowrap; }
.dash-section__head::after { content: ""; flex: 1; height: 1px; background: var(--color-border-subtle); }
.dash-more { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--space-4); }
.dash-more__item { display: flex; flex-direction: column; gap: 4px; padding: var(--space-4) var(--space-5); border: 1px solid var(--color-border-subtle); border-radius: var(--radius); color: inherit; text-decoration: none; background: var(--color-surface-1); }
.dash-more__item:hover { border-color: var(--color-border-strong); }
.dash-more__item span { color: var(--color-text-tertiary); font-size: var(--text-xs); }

/* ============================================================================
   STAT TILES: a figure with what it means beside it (core/stat-widgets.js)
   ============================================================================ */
.stat-grid { display: grid; grid-template-columns: minmax(0, 1.5fr) repeat(3, minmax(0, 1fr)); gap: var(--space-4); }
.stat-grid--auto { grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }
.stat { position: relative; display: flex; flex-direction: column; gap: var(--space-4); min-width: 0; overflow: hidden;
    padding: var(--space-5); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-lg); background: var(--color-surface-1); }
.stat::before { content: ""; position: absolute; inset-inline: 0; top: 0; height: 2px; background: var(--color-border-strong); }
.stat--pos::before { background: var(--color-profit); }
.stat--neg::before { background: var(--color-loss); }
.stat--hero.stat--pos { background: linear-gradient(180deg, color-mix(in srgb, var(--color-profit) 8%, var(--color-surface-1)), var(--color-surface-1) 75%); }
.stat--hero.stat--neg { background: linear-gradient(180deg, color-mix(in srgb, var(--color-loss) 8%, var(--color-surface-1)), var(--color-surface-1) 75%); }
.stat__head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); min-height: 24px; }
.stat__label { color: var(--color-text-secondary); font-size: var(--text-sm); font-weight: var(--weight-medium); }
.stat__chip { display: inline-flex; align-items: center; gap: 3px; padding: 2px 9px; border-radius: var(--radius-pill); background: var(--color-border-subtle);
    color: var(--color-text-secondary); font-family: var(--font-mono); font-size: var(--text-xs); font-weight: var(--weight-semibold); white-space: nowrap; }
.stat__chip.is-pos { background: var(--color-profit-muted); color: var(--color-profit); }
.stat__chip.is-neg { background: var(--color-loss-muted); color: var(--color-loss); }
.stat__chip .ico { font-size: 12px; }
.stat__main { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); }
.stat__figure { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.stat__value { white-space: nowrap; font-family: var(--font-display); font-size: clamp(1.6rem, 2.3vw, 2.1rem); font-weight: var(--weight-bold); line-height: 1.05;
    letter-spacing: -0.02em; font-variant-numeric: proportional-nums; overflow-wrap: anywhere; }
.stat--hero .stat__value { font-size: clamp(2.25rem, 3.6vw, 3rem); }
.stat__value.is-pos { color: var(--color-profit); }
.stat__value.is-neg { color: var(--color-loss); }
.stat__sub { display: flex; flex-wrap: wrap; gap: 2px 12px; color: var(--color-text-tertiary); font-size: var(--text-xs); }
.stat__sub > span { white-space: nowrap; }
.stat__sub b { color: var(--color-text-secondary); font-weight: var(--weight-semibold); font-family: var(--font-mono); }
.area-spark { display: block; width: 100%; height: 56px; margin-top: auto; }

.ring { flex: none; width: 56px; height: 56px; }
.ring__track, .ring__fill { fill: none; stroke-width: 7; }
.ring__track { stroke: var(--color-border-subtle); }
.ring__fill { stroke-linecap: round; }
.ring__fill--pos { stroke: var(--color-profit); }
.ring__fill--neg { stroke: var(--color-loss); }
.ring__fill--accent { stroke: var(--color-accent-primary); }

.meter { padding-bottom: 18px; }
.meter__track { position: relative; height: 8px; border-radius: 4px; background: var(--color-border-subtle); }
.meter__fill { position: absolute; inset-block: 0; left: 0; border-radius: 4px; background: var(--color-accent-primary); }
.meter__fill--pos { background: var(--color-profit); }
.meter__fill--neg { background: var(--color-loss); }
.meter__mark { position: absolute; top: -3px; width: 2px; height: 14px; margin-left: -1px; background: var(--color-text-tertiary); border-radius: 1px; }
.meter__mark span { position: absolute; top: 17px; left: 50%; transform: translateX(-50%); color: var(--color-text-tertiary); font-family: var(--font-mono); font-size: var(--text-2xs); font-weight: normal; }

.versus { display: flex; gap: 3px; align-items: flex-end; }
.versus__side { display: flex; flex-direction: column; gap: 4px; min-width: 92px; }
.versus__side--end { align-items: flex-end; text-align: end; }
.versus__bar { display: block; height: 8px; width: 100%; border-radius: 4px; }
.versus__bar--pos { background: var(--color-profit); }
.versus__bar--neg { background: var(--color-loss); }
.versus__k { color: var(--color-text-tertiary); font-size: var(--text-2xs); white-space: nowrap; }
.versus__v { font-family: var(--font-mono); font-size: var(--text-sm); font-weight: var(--weight-semibold); }

.pips { display: inline-flex; align-items: center; gap: 3px; }
.pips i { display: block; width: 9px; height: 18px; border-radius: 2px; background: var(--color-border-strong); }
.pips--pos i { background: var(--color-profit); }
.pips--neg i { background: var(--color-loss); }
.pips em { margin-inline-start: 4px; color: var(--color-text-tertiary); font-size: var(--text-xs); font-style: normal; font-family: var(--font-mono); }

/* a card of rows where each row is a figure and its picture */

/* the equity card's own four figures */
.chart-stat-row { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-3); border-top: 0; padding-top: 0; }
.chart-stat { padding: var(--space-3) var(--space-4); border: 1px solid var(--color-border-subtle); border-radius: var(--radius); background: var(--color-surface-2, transparent); }
.chart-stat .k { text-transform: none; letter-spacing: 0; font-size: var(--text-xs); }
.chart-stat .v { font-family: var(--font-display); font-size: var(--text-xl); font-weight: var(--weight-bold); }

.reports-page .reports-explorer .reports-summary-grid { display: grid; grid-template-columns: minmax(0, 1.5fr) repeat(3, minmax(0, 1fr)); gap: var(--space-4); }

@media (max-width: 1100px) {
    .stat-grid, .reports-page .reports-explorer .reports-summary-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .stat-grid > .stat--hero, .reports-explorer .reports-summary-grid > .stat--hero { grid-column: 1 / -1; }
}
@media (max-width: 560px) {
    /* Two to a row, not one: one per row made the dashboard eight screens long. */
    .stat-grid > .stat:not(.stat--hero) { padding: var(--space-4); gap: var(--space-3); }
    .chart-stat-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* monthly results */
.months__sum { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-6); margin-bottom: var(--space-4); padding-bottom: var(--space-4); border-bottom: 1px solid var(--color-border-subtle); font-size: var(--text-sm); }
.months__sum em { color: var(--color-text-tertiary); font-style: normal; font-size: var(--text-xs); }
.months__sum b { font-weight: var(--weight-semibold); }
.months__sum bdi { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--color-text-secondary); }
.months__row { display: grid; grid-template-columns: minmax(96px, 0.9fr) minmax(0, 2.6fr) 64px 64px 84px; align-items: center; column-gap: var(--space-4); padding: var(--space-3) 0; border-bottom: 1px solid var(--color-border-subtle); font-size: var(--text-sm); }
.months__row:last-child { border-bottom: 0; }
.months { max-width: 920px; }
.months__meta { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 2px var(--space-5); margin-top: 6px; color: var(--color-text-tertiary); font-size: var(--text-xs); }
.months__meta b { color: var(--color-text-secondary); font-family: var(--font-mono); font-weight: var(--weight-semibold); }
.months__meta bdi { font-family: var(--font-mono); color: var(--color-text-secondary); }
.months__row--head { padding-top: 0; color: var(--color-text-tertiary); font-size: var(--text-2xs); font-weight: var(--weight-semibold); }
.months__row--head > span:nth-child(n+3) { text-align: end; }
.months__m { font-weight: var(--weight-semibold); }
.months__net { display: flex; align-items: center; gap: var(--space-3); min-width: 0; direction: ltr; }
.months__track { flex: 1; min-width: 40px; height: 8px; border-radius: 4px; background: var(--color-border-subtle); overflow: hidden; }
.months__track i { display: block; height: 100%; border-radius: 4px; }
.months__track i.bar-pos { background: var(--color-profit); }
.months__track i.bar-neg { background: var(--color-loss); }
.months__net b { min-width: 84px; text-align: end; font-family: var(--font-mono); font-size: var(--text-sm); }
.months__n, .months__wr { text-align: end; font-family: var(--font-mono); color: var(--color-text-secondary); }
.months__ret { text-align: end; }
@media (max-width: 640px) {
    .months__row { grid-template-columns: minmax(0, 1fr) auto; row-gap: var(--space-2); }
    .months__row--head { display: none; }
    .months__net { grid-column: 1 / -1; order: 3; }
    .months__n, .months__wr { display: none; }
}

/* bars with a tooltip and figures (core/mini-charts.js) */
.bar { opacity: .92; transition: opacity 90ms; }
.bar-hit { fill: transparent; }
.bar-hit.is-on { fill: color-mix(in srgb, var(--color-text-primary) 6%, transparent); }
.bar-val { fill: var(--color-text-secondary); font-family: var(--font-mono); font-size: 10.5px; font-weight: var(--weight-semibold); }
.bar-flat { stroke: var(--color-text-tertiary); stroke-width: 2; stroke-linecap: round; }
.mini-tip { position: fixed; z-index: 1000; pointer-events: none; padding: 8px 10px; border-radius: var(--radius-sm); background: var(--color-surface-3);
    border: 1px solid var(--color-border-mid); box-shadow: var(--shadow-float); font-size: var(--text-xs); white-space: nowrap; opacity: 0; transition: opacity 90ms; }
.mini-tip b { font-family: var(--font-mono); font-size: var(--text-sm); }
.mini-tip .dim { color: var(--color-text-tertiary); font-size: 11px; }
.facts { display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-8); margin-bottom: var(--space-4); }
.fact { display: grid; gap: 2px; }
.fact span { color: var(--color-text-tertiary); font-size: var(--text-xs); }
.fact b { font-family: var(--font-display); font-size: var(--text-xl); font-weight: var(--weight-bold); letter-spacing: -0.01em; }
.fact b.is-pos { color: var(--color-profit); }
.fact b.is-neg { color: var(--color-loss); }
.fact small { color: var(--color-text-tertiary); font-size: var(--text-2xs); }

/* A group's own link names the page; once one of its sections is lit, that
   section is the "you are here". The group steps back to a plain heading so the
   two do not wear the same tint and bar one on top of the other. */
.nav-group:has(.nav-sub .nav__item.is-active) > .nav-group__link.is-active { background: transparent; color: var(--color-text-primary); }
.nav-group:has(.nav-sub .nav__item.is-active) > .nav-group__link.is-active::before { display: none; }
.nav-group:has(.nav-sub .nav__item.is-active) > .nav-group__link.is-active .ico { color: var(--color-accent-glow); }

/* the trader's own way back to square one with the Signal Bot */
.tg-reset { display: grid; gap: var(--space-3); padding: var(--space-4); border: 1px solid var(--color-border-subtle); border-radius: var(--radius); }
.tg-reset strong { font-size: var(--text-sm); }
.tg-reset .btn { justify-self: start; }

/* what the report covers: one quiet line, the dashboard has the headline figures */
.reports-scope { display: flex; gap: var(--space-5); margin: 0 0 var(--space-4); color: var(--color-text-tertiary); font-size: var(--text-sm); }
.reports-scope b { color: var(--color-text-primary); font-family: var(--font-mono); }

/* a table running edge to edge inside a card keeps the card's rounded corners */
.card__body--flush { padding: var(--space-4) 0 0; overflow: hidden; border-radius: 0 0 var(--radius-lg) var(--radius-lg); }
/* Monte Carlo: what each axis measures and what each shade is */
.mc-axes, .mc-legend { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-5); margin: 0 0 var(--space-3); color: var(--color-text-secondary); font-size: var(--text-xs); }
.mc-legend { margin: var(--space-3) 0 0; }
.mc-legend span { display: inline-flex; align-items: center; gap: 6px; }
.mc-key { display: inline-block; width: 18px; height: 10px; border-radius: 2px; }
.mc-key--actual { height: 0; border-top: 2px solid var(--color-accent-primary); }
.mc-key--median { height: 0; border-top: 2px dashed var(--color-accent-primary); }
.mc-key--mid { background: var(--color-accent-primary); opacity: .45; }
.mc-key--wide { background: var(--color-accent-primary); opacity: .2; }

/* Reports: the second line on a chart, buy and sell dots, and the compare tab */
.chart-line--info { stroke: var(--color-info); }
.chart-line--warn { stroke: var(--color-warning); }
.chart-vline { stroke: var(--color-border-subtle); stroke-width: 1; stroke-dasharray: 2 4; }
.dot { opacity: .7; }
.dot:hover { opacity: 1; }
.dot--long { fill: var(--color-info); }
.dot--short { fill: var(--color-warning); }
.key-dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; }
.key-dot--long { background: var(--color-info); }
.key-dot--short { background: var(--color-warning); }
.key-line { display: inline-block; width: 18px; height: 0; border-top: 2px solid var(--color-accent-primary); }
.key-line--b { border-top-color: var(--color-info); }
.cmp-pick { display: flex; align-items: flex-end; flex-wrap: wrap; gap: var(--space-4); }
.cmp-pick .field { min-width: 220px; }
.cmp-vs { padding-bottom: var(--space-3); color: var(--color-text-tertiary); }
.cmp-names { margin: 0; }
.cmp-names b { color: var(--color-text-primary); }
.card__head p.cmp-a, .card__head p.cmp-b { font-weight: var(--weight-semibold); }

/* Reports laid out as a statement: a masthead, a row of graded figures, tagged findings */
.rp-mast { display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); gap: var(--space-6); align-items: end; }
.rp-mast[hidden] { display: none; }
.rp-mast__eyebrow { margin: 0; color: var(--color-text-tertiary); font-size: var(--text-xs); }
.rp-mast__hero { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px var(--space-4); margin-top: var(--space-1); color: var(--color-text-secondary); }
.rp-mast__net { font-family: var(--font-display); font-size: clamp(2.4rem, 5vw, 3.6rem); font-weight: var(--weight-bold); letter-spacing: -0.02em; line-height: 1.05; direction: ltr; unicode-bidi: isolate; }
.rp-mast__net.is-pos { color: var(--color-profit); }
.rp-mast__net.is-neg { color: var(--color-loss); }
.rp-mast__sub { margin: var(--space-3) 0 0; max-width: 62ch; color: var(--color-text-secondary); font-size: var(--text-sm); }
.rp-mast__spark { padding: var(--space-3) var(--space-4); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-lg); background: var(--color-surface-1); }
.rp-mast__spark-t { display: flex; justify-content: space-between; gap: var(--space-3); color: var(--color-text-tertiary); font-size: var(--text-xs); }
.rp-mast__spark-t b { font-family: var(--font-mono); direction: ltr; }
.rp-mast__spark .area-spark { display: block; width: 100%; height: 86px; }
@media (max-width: 900px) { .rp-mast { grid-template-columns: minmax(0, 1fr); } }

.rp-bar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-3) var(--space-5); }
.rp-bar .report-tabs { margin: 0; width: auto; }
.rp-bar .reports-scope { margin: 0; }

.rp-kpis { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1px; border: 1px solid var(--color-border-subtle); border-radius: var(--radius-lg); overflow: hidden; background: var(--color-border-subtle); }
@media (max-width: 900px) { .rp-actions { grid-template-columns: minmax(0, 1fr); } .rp-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.rp-kpi { display: flex; flex-direction: column; gap: 2px; min-width: 0; padding: var(--space-4); background: var(--color-surface-1); }
.rp-kpi__l { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); color: var(--color-text-tertiary); font-size: var(--text-xs); }
.rp-kpi__v { font-family: var(--font-display); font-size: clamp(1.4rem, 2vw, 1.8rem); font-weight: var(--weight-bold); letter-spacing: -0.01em; line-height: 1.25; }
.rp-kpi__v .is-pos { color: var(--color-profit); }
.rp-kpi__v .is-neg { color: var(--color-loss); }
.rp-kpi__d { color: var(--color-text-secondary); font-size: var(--text-xs); }
.grade { flex: none; padding: 1px 8px; border-radius: var(--radius-pill); font-size: 10.5px; font-weight: var(--weight-bold); }
.grade--good { background: var(--color-profit-muted); color: var(--color-profit); }
.grade--warn { background: var(--color-warning-muted); color: var(--color-warning); }
.grade--bad { background: var(--color-loss-muted); color: var(--color-loss); }
.grade--info { background: var(--color-info-muted); color: var(--color-info); }

.grid-2--wide { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); }
@media (max-width: 1050px) { .grid-2--wide { grid-template-columns: minmax(0, 1fr); } }

.ins { display: flex; flex-direction: column; }
.ins--cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--space-8); }
.ins--cols .ins__item:nth-last-child(2):nth-child(odd) { border-bottom: 0; }
.ins--cols .ins__item:nth-child(2) { padding-top: 0; }
@media (max-width: 900px) { .ins--cols { grid-template-columns: minmax(0, 1fr); } .ins--cols .ins__item:nth-child(2) { padding-top: var(--space-3); } }
.ins__item { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 4px var(--space-3); padding: var(--space-3) 0; border-bottom: 1px solid var(--color-border-subtle); }
.ins__item:last-child { border-bottom: 0; padding-bottom: 0; }
.ins__item:first-child { padding-top: 0; }
.ins__item h3 { margin: 0; font-size: var(--text-sm); line-height: 1.6; }
.ins__item dl { grid-column: 2; display: flex; flex-wrap: wrap; gap: 2px var(--space-5); margin: 0; }
.ins__item dl div { display: flex; gap: var(--space-2); color: var(--color-text-secondary); font-size: var(--text-xs); }
.ins__item dd { margin: 0; font-family: var(--font-mono); color: var(--color-text-primary); }
.ins__tag { align-self: start; margin-top: 2px; padding: 1px 9px; border-radius: var(--radius-pill); font-size: 11px; font-weight: var(--weight-bold); white-space: nowrap; }
.ins__tag--good { background: var(--color-profit-muted); color: var(--color-profit); }
.ins__tag--warn { background: var(--color-warning-muted); color: var(--color-warning); }
.ins__tag--bad { background: var(--color-loss-muted); color: var(--color-loss); }
.ins__tag--info { background: var(--color-info-muted); color: var(--color-info); }

.rp-actions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-3) var(--space-8); margin: 0; padding: 0; list-style: none; counter-reset: rp; }
.rp-actions li { display: grid; grid-template-columns: 26px minmax(0, 1fr); gap: var(--space-3); align-items: start; color: var(--color-text-secondary); font-size: var(--text-sm); counter-increment: rp; }
.rp-actions li::before { content: counter(rp); display: grid; place-items: center; width: 24px; height: 24px; border-radius: 50%; background: var(--color-accent-muted, var(--color-info-muted)); color: var(--color-accent-primary); font-size: 12px; font-weight: var(--weight-bold); }

.rp-note { margin: 0; padding: var(--space-3) var(--space-5) var(--space-4); color: var(--color-text-secondary); font-size: var(--text-xs); line-height: 1.7; }
.rp-note--bare { padding: var(--space-3) 0 0; }
.rp-note:empty { display: none; }
.rp-empty { padding: var(--space-4) var(--space-5); }
.rp-scale { display: flex; align-items: center; justify-content: flex-end; gap: var(--space-2); margin: var(--space-3) 0 0; color: var(--color-text-tertiary); font-size: 11px; direction: ltr; }
.rp-scale i { width: 150px; height: 8px; border-radius: 4px; background: linear-gradient(90deg, var(--color-loss), var(--color-border-subtle), var(--color-profit)); }
.rp-search { width: 190px; }
.rp-versus td:first-child { color: var(--color-text-secondary); }

.dbar { position: relative; display: block; width: 72px; height: 8px; direction: ltr; }
.dbar::before { content: ""; position: absolute; inset-block: -3px; left: 50%; width: 1px; background: var(--color-border-strong); }
.dbar i { position: absolute; top: 0; height: 8px; border-radius: 2px; }
.dbar i.bar-pos { left: 50%; background: var(--color-profit); }
.dbar i.bar-neg { right: 50%; background: var(--color-loss); }

.hm > b.hm__c { display: grid; place-items: center; font-size: 9px; font-weight: var(--weight-semibold); color: var(--color-text-primary); }
.dot--hollow { fill: var(--color-surface-1); stroke-width: 1.8; opacity: 1; }
.dot--long.dot--hollow { stroke: var(--color-info); }
.dot--short.dot--hollow { stroke: var(--color-warning); }
.chart-hover { stroke: var(--color-text-tertiary); stroke-width: 1; opacity: .6; pointer-events: none; }
.chart-hit { fill: transparent; }
.pill--long, .pill--short { padding: 1px 8px; border-radius: var(--radius-pill); font-size: 11px; font-weight: var(--weight-semibold); }
.pill--long { background: var(--color-info-muted); color: var(--color-info); }
.pill--short { background: var(--color-warning-muted); color: var(--color-warning); }
.reports-trades-table th[data-sort] { cursor: pointer; user-select: none; white-space: nowrap; }
.reports-trades-table th[data-dir="asc"]::after { content: " ▲"; font-size: 9px; }
.reports-trades-table th[data-dir="desc"]::after { content: " ▼"; font-size: 9px; }
.reports-trades-table td.num, .reports-trades-table th.num { text-align: end; }

/* Reports: what each tab is for, one plain line under a chart, and shaded lines */
.rp-lead { margin: 0 0 var(--space-4); color: var(--color-text-secondary); font-size: var(--text-sm); max-width: 78ch; }
.rp-take { margin: var(--space-3) 0 0; padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm); background: var(--color-surface-2, var(--color-border-subtle)); color: var(--color-text-secondary); font-size: var(--text-xs); line-height: 1.7; }
.rp-take:empty { display: none; }
.rp-take b { color: var(--color-text-primary); font-family: var(--font-mono); font-weight: var(--weight-semibold); }
.chart-area { stroke: none; }
.chart-area--accent { fill: var(--color-accent-primary); opacity: .12; }
.chart-area--loss { fill: var(--color-loss); opacity: .14; }
.chart-area--info { fill: var(--color-info); opacity: .12; }
.chart-area--warn { fill: var(--color-warning); opacity: .12; }
.chart-end { stroke: var(--color-surface-1); stroke-width: 2; }
.chart-end--accent { fill: var(--color-accent-primary); }
.chart-end--loss { fill: var(--color-loss); }
.chart-end--info { fill: var(--color-info); }
.chart-end--warn { fill: var(--color-warning); }

/* A phone has no room for a strip of cut-off tab names; the breadcrumb says where you are. */
@media (max-width: 720px) { .tabs-bar { display: none; } }

/* Getting started, on the journal hub: three steps, each ticked as it happens. */
.onboard { padding: var(--space-5); margin-bottom: var(--space-5); }
.onboard__title { margin: 0 0 var(--space-4); font-size: var(--text-lg, 18px); }
.onboard__steps { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-3); }
.onboard__step { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3); border: 1px solid var(--color-border-subtle); border-radius: var(--radius); }
.onboard__step.is-done { opacity: .65; }
.onboard__mark { flex: 0 0 32px; height: 32px; display: grid; place-items: center; border-radius: 50%; font-weight: 700; background: var(--color-surface-2, rgba(128,128,128,.15)); }
.onboard__step.is-done .onboard__mark { background: var(--color-profit); color: #fff; }
.onboard__mark .aico { width: 16px; height: 16px; }
.onboard__text { flex: 1; display: grid; gap: 2px; min-width: 0; }
.onboard__text small { color: var(--color-text-secondary); }
.onboard__actions { display: flex; gap: var(--space-2); flex-wrap: wrap; }
@media (max-width: 640px) { .onboard__step { flex-wrap: wrap; } .onboard__actions { width: 100%; } }

/* The expert page opens on whether the expert is working. */
.ea-status { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--space-4); margin-bottom: var(--space-4); border-radius: var(--radius); border: 1px solid var(--color-border-subtle); }
.ea-status > div { flex: 1; display: grid; gap: 2px; }
.ea-status small { color: var(--color-text-secondary); }
.ea-status__dot { flex: 0 0 12px; height: 12px; border-radius: 50%; background: var(--color-text-tertiary); }
.ea-status--on { border-color: color-mix(in srgb, var(--color-profit) 45%, transparent); background: color-mix(in srgb, var(--color-profit) 8%, transparent); }
.ea-status--on .ea-status__dot { background: var(--color-profit); box-shadow: 0 0 0 4px color-mix(in srgb, var(--color-profit) 25%, transparent); }
.ea-status--idle .ea-status__dot { background: #e0a43a; }
.ea-status--off .ea-status__dot { background: var(--color-loss); }

/* Trades on a phone: one card per trade - symbol and date, side, result, R:R -
   with the full row a tap away in the editor. The table's other columns stay
   on wider screens. */
.toolbar__more { display: none; }
@media (max-width: 720px) {
    .toolbar__more { display: inline-flex; }
    .trades-page .toolbar:not(.is-expanded) .trade-filter-group,
    .trades-page .toolbar:not(.is-expanded) .toolbar__trail { display: none; }

    .trades-page table.dt thead { display: none; }
    .trades-page table.dt, .trades-page table.dt tbody { display: block; }
    .trades-page table.dt tbody tr[data-id] {
        display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px;
        padding: 12px; margin-bottom: 8px;
        border: 1px solid var(--color-border-subtle); border-radius: var(--radius);
        background: var(--color-surface-1);
    }
    .trades-page table.dt tbody tr[data-id] > td { display: none; border: 0; padding: 0; position: static; background: none; }
    .trades-page table.dt tbody tr[data-id] > td.trade-sel-td { display: block; order: 0; }
    .trades-page table.dt tbody tr[data-id] > td[data-k="date"] { display: block; order: 1; flex: 1 1 0; min-width: 0; }
    .trades-page table.dt tbody tr[data-id] > td[data-k="pnl"] { display: block; order: 2; font-size: 16px; }
    .trades-page table.dt tbody tr[data-id] > td.sticky-end { display: block; order: 3; }
    /* The second line: side, result, R:R. */
    .trades-page table.dt tbody tr[data-id]::after { content: ""; order: 4; flex-basis: 100%; height: 0; }
    .trades-page table.dt tbody tr[data-id] > td[data-k="direction"] { display: block; order: 5; margin-inline-start: 30px; }
    .trades-page table.dt tbody tr[data-id] > td[data-k="winloss"] { display: block; order: 6; }
    .trades-page table.dt tbody tr[data-id] > td[data-k="rr"] { display: block; order: 7; }
    .trades-page table.dt tbody tr[data-id] > td[data-k="rr"]::before { content: "R:R "; color: var(--color-text-tertiary); }
}
/* Docs & tutorials in the sidebar: the book breathes by itself (the one icon that
   moves without a hover, so a trader who has never opened the docs notices it) and
   turns its pages when pointed at. Off for anyone who asked for less motion. */
.aico-book-open path { transform-box: fill-box; }
.aico-book-open .pgL { transform-origin: 100% 50%; }
.aico-book-open .pgR { transform-origin: 0% 50%; }
@keyframes aiBookL { 0%, 70%, 100% { transform: skewY(0) scaleX(1); } 82% { transform: skewY(-7deg) scaleX(.9); } }
@keyframes aiBookR { 0%, 70%, 100% { transform: skewY(0) scaleX(1); } 82% { transform: skewY(7deg) scaleX(.9); } }
@keyframes aiBookGlow { 0%, 100% { opacity: .85; } 50% { opacity: 1; } }
.nav__item--docs .aico-book-open { animation: aiBookGlow 3.4s ease-in-out infinite; }
.nav__item--docs .aico-book-open .pgL { animation: aiBookL 3.4s ease-in-out infinite; }
.nav__item--docs .aico-book-open .pgR { animation: aiBookR 3.4s ease-in-out infinite; }
.nav__item--docs:is(:hover, :focus-visible) .aico-book-open .pgL { animation: aiBookL 1s ease-in-out infinite; }
.nav__item--docs:is(:hover, :focus-visible) .aico-book-open .pgR { animation: aiBookR 1s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) {
    .nav__item--docs .aico-book-open, .nav__item--docs .aico-book-open path { animation: none !important; }
}

/* Sign-up: the optional username and password fold away under the phone. */
.auth-optional { border: 1px solid var(--color-border-subtle); border-radius: var(--radius); padding: var(--space-2) var(--space-3); }
.auth-optional > summary { cursor: pointer; font-size: var(--text-sm); color: var(--color-text-secondary); padding: var(--space-1) 0; }
.auth-optional__body { display: grid; gap: var(--space-3); padding-top: var(--space-3); }

/* Phones. Persian at 11-13px is tiring to read, so the two small steps of the
   scale grow a pixel or two; and anything a thumb has to hit is at least 40px. */
@media (max-width: 720px) {
    :root { --text-2xs: 12px; --text-xs: 13px; --text-sm: 14px; }
    .report-tabs button { min-height: 40px; padding-inline: 14px; }
    .segment button { min-height: 38px; }
}

/* Reports while the numbers are on their way: each card is a soft shimmer. */
@keyframes rp-shimmer { from { background-position: 150% 0; } to { background-position: -50% 0; } }
.reports-page.is-loading .stat, .reports-page.is-loading .card { position: relative; }
.reports-page.is-loading .stat > *, .reports-page.is-loading .card > * { visibility: hidden; }
.reports-page.is-loading .stat::after, .reports-page.is-loading .card::after {
    content: ""; position: absolute; inset: 0; border-radius: inherit;
    background: linear-gradient(90deg, transparent 30%, color-mix(in srgb, var(--color-text-primary) 7%, transparent) 50%, transparent 70%) var(--color-surface-1);
    background-size: 200% 100%; animation: rp-shimmer 1.2s linear infinite;
}
@media (prefers-reduced-motion: reduce) { .reports-page.is-loading .stat::after, .reports-page.is-loading .card::after { animation: none; } }

/* ---- Reports: what made the page hard to read --------------------------------------------
   A table set in half a row was wider than its card and scrolled sideways inside it, the net
   result (the column that matters) off the edge; the monthly grid needed 500px and was given
   300; the Compare dropdown opened inside a scroll box and was cut off; the suggested actions
   ran 1, 3, 5 down one column and 2, 4 down the other. */
@media (max-width: 1500px) {
    [data-report-pane] .grid-2:has(.dt), [data-report-pane] .grid-2:has(.months__row) { grid-template-columns: minmax(0, 1fr); }
}
[data-report-pane] .card__body.cmp-pick { overflow: visible; }
[data-report-pane] .card:has(> .cmp-pick) { position: relative; z-index: 5; }
.rp-actions { grid-template-columns: minmax(0, 1fr); max-width: 78ch; }
/* A table on a phone keeps label, count, win rate and the net result; the rest is a wider screen's. */
@media (max-width: 640px) {
    [data-report-pane] .dt .col-opt { display: none; }
    [data-report-pane] .dt th, [data-report-pane] .dt td { padding-inline: 8px; }
}
/* The monthly list lays itself out by the room its card has, not the window's. */
.card__body:has(> .months__row) { container-type: inline-size; }
@container (max-width: 560px) {
    .months__row { grid-template-columns: minmax(0, 1fr) auto; row-gap: var(--space-2); }
    .months__row--head { display: none; }
    .months__net { grid-column: 1 / -1; order: 3; }
    .months__n, .months__wr { display: none; }
}

/* Compare: a colour per journal, in the order they were picked (s0 is the first). */
.cmp-pick { flex-direction: column; align-items: stretch; }
.cmp-rows { display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-4); }
.cmp-row { display: flex; align-items: flex-end; gap: var(--space-2); min-width: 220px; flex: 1 1 220px; max-width: 320px; }
.cmp-row .field { flex: 1; min-width: 0; }
.cmp-row .field__label { display: flex; align-items: center; gap: 6px; }
.cmp-row__x { flex: 0 0 auto; width: 36px; height: 36px; display: grid; place-items: center; border: 1px solid var(--color-border-subtle); border-radius: var(--radius); background: none; color: var(--color-text-tertiary); cursor: pointer; margin-bottom: 2px; }
.cmp-row__x:hover { color: var(--color-loss); border-color: var(--color-loss); }
.cmp-tools { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.cmp-each { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 420px), 1fr)); gap: var(--space-5); }
.cmp-each .card__head p { font-weight: var(--weight-semibold); }
.cmp-names { flex-wrap: wrap; }
.chart-line--s0, .key-line--s0 { --s: var(--color-accent-primary); }
.chart-line--s1, .key-line--s1 { --s: var(--color-info); }
.chart-line--s2, .key-line--s2 { --s: var(--color-warning); }
.chart-line--s3, .key-line--s3 { --s: #20b39b; }
.chart-line--s4, .key-line--s4 { --s: #e0679b; }
.chart-line--s5, .key-line--s5 { --s: #9b7bea; }
.chart-line--s6, .key-line--s6 { --s: #c19a2e; }
.chart-line--s7, .key-line--s7 { --s: #6f8fbf; }
.chart-line[class*="chart-line--s"] { stroke: var(--s); }
.key-line[class*="key-line--s"] { border-top-color: var(--s); }
.key-dot[class*="key-line--s"] { background: var(--s); }
.chart-end[class*="chart-end--s"] { fill: currentColor; }
.chart-end--s0 { color: var(--color-accent-primary); } .chart-end--s1 { color: var(--color-info); } .chart-end--s2 { color: var(--color-warning); }
.chart-end--s3 { color: #20b39b; } .chart-end--s4 { color: #e0679b; } .chart-end--s5 { color: #9b7bea; } .chart-end--s6 { color: #c19a2e; } .chart-end--s7 { color: #6f8fbf; }

/* The compare key: chips, not a loose line of coloured dashes under a card. */
.cmp-key { display: flex; flex-wrap: wrap; gap: 6px; margin-top: var(--space-3); }
.cmp-chip { display: inline-flex; align-items: center; gap: 7px; max-width: 100%; padding: 3px 10px 3px 9px; border: 1px solid var(--color-border-subtle); border-radius: 999px; background: var(--color-surface-2); color: var(--color-text-primary); font-size: var(--text-xs); font-weight: var(--weight-semibold); line-height: 1.6; white-space: nowrap; }
.cmp-chip bdi { overflow: hidden; text-overflow: ellipsis; }
.cmp-chip--th { padding: 2px 8px; font-size: var(--text-2xs); }
.cmp-dot { flex: 0 0 auto; display: inline-block; width: 9px; height: 9px; border-radius: 50%; background: var(--s, var(--color-accent-primary)); box-shadow: 0 0 0 3px color-mix(in srgb, var(--s, var(--color-accent-primary)) 22%, transparent); }

/* ---- Profile page (accounts/profile.html) ---- */
.profile-page { display: grid; gap: var(--space-5); max-width: 980px; }
.pf-head { display: flex; align-items: center; gap: var(--space-4); padding: var(--space-5); }
.pf-avatar { flex: 0 0 auto; width: 56px; height: 56px; display: grid; place-items: center; border-radius: 50%; background: var(--color-accent-muted, var(--color-surface-2)); color: var(--color-accent-primary); font-weight: var(--weight-bold); font-size: 20px; }
.pf-who { flex: 1; min-width: 0; }
.pf-who h1 { margin: 0; font-size: var(--text-xl, 22px); }
.pf-who p { margin: 4px 0 0; font-size: var(--text-sm); }
.profile-page .card__head { align-items: center; }
.pf-plan { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: var(--space-4); padding-bottom: var(--space-4); border-bottom: 1px solid var(--color-border-subtle); }
.pf-plan__name { display: flex; align-items: center; gap: var(--space-3); font-size: var(--text-lg, 18px); }
.pf-days { min-width: 220px; display: grid; gap: 6px; }
.pf-days__num { font-size: 26px; font-weight: var(--weight-bold); color: var(--color-text-primary); }
.pf-days .dim { font-size: var(--text-xs); }
.pf-bar { height: 8px; border-radius: 99px; background: var(--color-border-subtle); overflow: hidden; }
.pf-bar i { display: block; height: 100%; border-radius: inherit; background: var(--color-accent-primary); }
.pf-bar--thin { height: 5px; }
.pf-allow { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: var(--space-4); padding-top: var(--space-4); }
.pf-allow__item { display: grid; gap: 4px; font-size: var(--text-sm); }
.pf-allow__item b { font-size: var(--text-md, 15px); }
.pf-links { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: var(--space-3); }
.pf-link { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--space-4); border: 1px solid var(--color-border-subtle); border-radius: var(--radius); color: inherit; text-decoration: none; }
.pf-link:hover { border-color: var(--color-accent-border); background: var(--color-surface-2); }
.pf-link > span { display: grid; gap: 2px; min-width: 0; }
.pf-link small { font-size: var(--text-xs); }
.profile-page .settings-section.card { padding: var(--space-5); }

/* Profile: buttons with room around them (they sat against the cards' text) */
.profile-page .card__head { flex-wrap: wrap; gap: var(--space-3) var(--space-5); }
.profile-page .card__head > div { flex: 1 1 260px; min-width: 0; }
.profile-page .card__head > .btn { flex: 0 0 auto; }
.pf-head { flex-wrap: wrap; }
.pf-head__side { display: flex; align-items: center; gap: var(--space-3); margin-inline-start: auto; }
.profile-page .form-actions { display: flex; justify-content: flex-start; margin: var(--space-4) 0 var(--space-2); }
.profile-page .settings-section__head { margin-bottom: var(--space-4); }
@media (max-width: 640px) {
    .profile-page .card__head > .btn { width: 100%; justify-content: center; }
    .pf-head__side { width: 100%; justify-content: space-between; margin-inline-start: 0; }
}

.onboard__head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-3); }
.onboard__head .onboard__title { margin-bottom: var(--space-4); }
.onboard__close { flex: 0 0 auto; margin-top: -4px; }

/* Bale (ble.ir) has no Bootstrap icon: a bubble with a "b", drawn in the text's
   colour like the bi-* glyphs it sits beside in the footer and the panel. */
.bi-bale::before {
    content: ""; display: inline-block; width: 1em; height: 1em; vertical-align: -.125em;
    background: currentColor;
    -webkit-mask: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><mask id='m'><path fill='%23fff' d='M12 1.5a10 10 0 1 1-4.9 18.7L2.5 22l1.3-4.4A10 10 0 0 1 12 1.5z'/><path d='M8.4 5.6h1.9v11.6H8.4z'/><circle cx='12.8' cy='13.2' r='3.1' fill='none' stroke='%23000' stroke-width='1.9'/></mask><rect width='24' height='24' fill='%23fff' mask='url(%23m)'/></svg>") center / contain no-repeat;
    mask: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><mask id='m'><path fill='%23fff' d='M12 1.5a10 10 0 1 1-4.9 18.7L2.5 22l1.3-4.4A10 10 0 0 1 12 1.5z'/><path d='M8.4 5.6h1.9v11.6H8.4z'/><circle cx='12.8' cy='13.2' r='3.1' fill='none' stroke='%23000' stroke-width='1.9'/></mask><rect width='24' height='24' fill='%23fff' mask='url(%23m)'/></svg>") center / contain no-repeat;
}

/* The on-page text editor (core/text-editor.js), staff only. */
.text-edit-bar {
    position: fixed; inset-block-end: 16px; inset-inline-start: 16px; z-index: 2000;
    display: flex; gap: 8px; align-items: center; flex-wrap: wrap; max-width: calc(100vw - 32px);
}
.text-edit-bar button, .text-edit-bar a {
    font: inherit; font-size: 13px; padding: 7px 12px; border-radius: 999px; cursor: pointer; text-decoration: none;
    background: var(--surface-2, #1c2333); color: var(--text, #e6e9ef); border: 1px solid var(--border, #2c3548);
    box-shadow: 0 4px 14px rgb(0 0 0 / .25);
}
.text-edit-on .text-edit-bar__toggle { background: var(--accent, #7c8cff); color: #0b0f1a; border-color: transparent; }
.text-edit-bar[data-note]::after {
    content: attr(data-note); flex-basis: 100%; font-size: 12.5px; padding: 8px 12px; border-radius: 10px;
    background: var(--surface-2, #1c2333); color: var(--text, #e6e9ef); border: 1px solid var(--border, #2c3548);
}
.text-edit-on body { cursor: text; }
.text-edit-on :is(h1, h2, h3, h4, h5, p, a, button, label, li, th, td, summary, small, strong, b, em, dt, dd, legend, span):hover {
    outline: 1px dashed var(--accent, #7c8cff); outline-offset: 2px;
}
.text-edit-on [data-sitetext] { outline: 1px dotted color-mix(in srgb, var(--accent, #7c8cff) 55%, transparent); }
.text-edit-on :is(.text-edit-bar, .text-edit-dialog) :hover { outline: none; }
.text-edit-dialog {
    width: min(520px, calc(100vw - 32px)); padding: 18px; border-radius: 14px; direction: rtl;
    background: var(--surface, #141a27); color: var(--text, #e6e9ef); border: 1px solid var(--border, #2c3548);
}
.text-edit-dialog::backdrop { background: rgb(0 0 0 / .45); }
.text-edit-dialog textarea { width: 100%; margin-block: 8px; }
.text-edit-dialog__label { font-weight: 600; }
.text-edit-dialog__actions { display: flex; gap: 8px; }
.text-edit-dialog__hint { font-size: 12px; opacity: .7; margin: 10px 0 0; }
.text-edit-dialog__error { color: var(--danger, #ff6b6b); font-size: 13px; margin: 0 0 8px; }

/* The guided tour (core/tour.js): a lit cut-out over the real element and a card
   beside it. The cut-out is a box-shadow, so it dims everything else without
   blocking it - the trader can type into the field it points at. Above
   Bootstrap's modal (1055), because the new-journal walk runs inside one. */
.tour-hole {
    position: fixed; z-index: 2100; pointer-events: none; border-radius: 12px;
    box-shadow: 0 0 0 9999px rgba(3, 5, 10, 0.66), 0 0 0 1.5px var(--color-accent-primary), 0 0 28px 6px var(--color-accent-muted);
    opacity: 0; transition: opacity .35s ease, border-radius .3s ease;
}
.tour-hole.is-on { opacity: 1; }
.tour-hole.is-glide { transition: opacity .35s ease, left .55s cubic-bezier(.65,0,.35,1), top .55s cubic-bezier(.65,0,.35,1),
    width .55s cubic-bezier(.65,0,.35,1), height .55s cubic-bezier(.65,0,.35,1); }
/* A breathing ring just outside the light: cheaper than pulsing the full-screen shadow. */
.tour-hole::after { content: ""; position: absolute; inset: -5px; border-radius: inherit; border: 2px solid var(--color-accent-glow);
    opacity: 0; animation: tourBreath 2.2s ease-in-out infinite; }
.tour-hole.is-alone { border-radius: 50%; box-shadow: 0 0 0 9999px rgba(3, 5, 10, 0.66); }
.tour-hole.is-alone::after { display: none; }
.tour-ring { position: fixed; z-index: 2100; pointer-events: none; border-radius: 12px; border: 2px solid var(--color-accent-glow);
    animation: tourRing .8s cubic-bezier(.2,.7,.3,1) forwards; }
.tour-cursor { position: fixed; left: 0; top: 0; z-index: 2102; pointer-events: none; opacity: 0;
    transition: opacity .3s ease; filter: drop-shadow(0 4px 10px rgba(0,0,0,.45)); }
.tour-cursor.is-on { opacity: 1; }
.tour-cursor svg { display: block; transform-origin: 5px 3px; }
.tour-cursor::before { content: ""; position: absolute; left: -14px; top: -16px; width: 36px; height: 36px; border-radius: 50%;
    background: var(--color-accent-glow); opacity: 0; transform: scale(.2); }
.tour-cursor.is-tap svg { animation: tourPress .28s ease; }
/* Hovering over what the trader is asked to press: a small tapping motion, "here". */
.tour-cursor.is-nudge svg { animation: tourNudge 1.2s ease-in-out infinite; }
.tour-cursor.is-nudge::before { animation: tourTap 1.2s ease-out infinite; }
.tour-pop.is-done .tour-pop__icon { color: var(--color-success, #34d399); border-color: currentColor;
    background: color-mix(in srgb, var(--color-success, #34d399) 16%, transparent); box-shadow: 0 0 18px -4px currentColor; }
@keyframes tourNudge { 0%, 100% { transform: translate(0, 0); } 45% { transform: translate(-3px, -5px); } 60% { transform: translate(0, 0) scale(.88); } }
.tour-cursor.is-tap::before { animation: tourTap .55s ease-out; }
.tour-pop {
    position: fixed; z-index: 2101; width: min(320px, calc(100vw - 24px));
    padding: var(--space-4) var(--space-4) var(--space-3); border-radius: 16px; overflow: visible;
    background: color-mix(in srgb, var(--color-surface-1) 88%, transparent); color: var(--color-text-primary);
    backdrop-filter: blur(14px) saturate(1.3); -webkit-backdrop-filter: blur(14px) saturate(1.3);
    border: 1px solid var(--color-accent-border);
    box-shadow: 0 24px 60px -12px rgba(0,0,0,.55), 0 0 0 1px rgba(255,255,255,.03) inset;
    transition: opacity .2s ease;
}
.tour-pop.is-moving { opacity: .55; }
.tour-pop.is-leaving { opacity: 0; transform: scale(.96); transition: opacity .22s ease, transform .22s ease; }
/* The arrow: a turned square on the edge facing the light (data-side, --ax/--ay from tour.js). */
.tour-pop::before { content: ""; position: absolute; width: 12px; height: 12px; background: inherit; border: inherit;
    border-width: 0 0 1px 1px; display: none; }
.tour-pop[data-side="top"]::before { display: block; top: -7px; left: calc(var(--ax) - 6px); transform: rotate(135deg); }
.tour-pop[data-side="bottom"]::before { display: block; bottom: -7px; left: calc(var(--ax) - 6px); transform: rotate(-45deg); }
.tour-pop[data-side="left"]::before { display: block; left: -7px; top: calc(var(--ay) - 6px); transform: rotate(45deg); }
.tour-pop[data-side="right"]::before { display: block; right: -7px; top: calc(var(--ay) - 6px); transform: rotate(-135deg); }
/* Between Back and Next, inside the card: on the card's top edge it ran square
   across the rounded corners and looked like it had slipped out of the frame. */
.tour-pop__bar { flex: 1; align-self: center; height: 4px; border-radius: 99px; overflow: hidden;
    background: rgba(255,255,255,.08); }
.tour-pop__bar i { display: block; height: 100%; width: 0; margin-inline-start: 0;
    background: linear-gradient(90deg, var(--color-accent-primary), var(--color-accent-glow));
    box-shadow: 0 0 10px var(--color-accent-glow); transition: width .5s cubic-bezier(.2,.8,.2,1); }
.tour-pop__content { display: flex; gap: var(--space-3); align-items: flex-start; }
.tour-pop__icon { flex: none; width: 40px; height: 40px; border-radius: 12px; display: grid; place-items: center; font-size: 19px;
    color: var(--color-accent-glow); background: var(--color-accent-muted); border: 1px solid var(--color-accent-border);
    box-shadow: 0 0 18px -4px var(--color-accent-glow); }
.tour-pop__x { position: absolute; inset-inline-end: 8px; top: 8px; background: none; border: 0; font-size: 20px;
    line-height: 1; color: var(--color-text-tertiary); cursor: pointer; }
.tour-pop__x:hover { color: var(--color-text-primary); }
.tour-pop__count { font-size: 11px; letter-spacing: .04em; color: var(--color-accent-glow); margin-bottom: 2px; }
.tour-pop__title { font-size: var(--text-base); font-weight: 700; margin: 0 0 4px; padding-inline-end: 18px; }
.tour-pop__body { margin: 0 0 var(--space-3); color: var(--color-text-secondary); line-height: 1.75; font-size: var(--text-sm); }
.tour-pop__foot { display: flex; justify-content: space-between; gap: var(--space-2); }
.tour-pop__foot [hidden] { visibility: hidden; display: inline-flex; }
@keyframes tourBreath { 0%, 100% { opacity: 0; transform: scale(1); } 50% { opacity: .55; transform: scale(1.015); } }
@keyframes tourRing { from { opacity: .9; transform: scale(1); } to { opacity: 0; transform: scale(1.18); } }
@keyframes tourTap { 0% { opacity: .6; transform: scale(.2); } 100% { opacity: 0; transform: scale(1.4); } }
@keyframes tourPress { 50% { transform: scale(.8); } }
@media (prefers-reduced-motion: reduce) {
    .tour-hole, .tour-pop, .tour-cursor, .tour-pop__bar i { transition: none; }
    .tour-hole::after, .tour-ring, .tour-cursor::before, .tour-cursor svg { animation: none !important; }
}
/* The topbar's page guide, shown for an account's first days. */
.topbar__tour { position: relative; gap: 6px; }
.topbar__tour::after { content: ""; position: absolute; top: 4px; inset-inline-end: 4px; width: 7px; height: 7px; border-radius: 50%;
    background: var(--color-accent-glow); box-shadow: 0 0 0 0 var(--color-accent-glow); animation: tourDot 2s ease-out infinite; }
@keyframes tourDot { 70% { box-shadow: 0 0 0 7px transparent; } 100% { box-shadow: 0 0 0 0 transparent; } }
@media (max-width: 640px) { .topbar__tour [data-lang-only] { display: none; } }
/* A link in the guide's answer that shows the place on the site. */
.hv-agent__msg a[data-show-me]::after { content: " ⌖"; opacity: .7; }

/* The page guide's link to the recorded tutorial for that page (tour.js). */
.tour-pop__video { display: inline-flex; align-items: center; gap: 6px; margin-top: 8px; font-size: var(--text-sm); font-weight: 600; color: var(--color-accent-primary); text-decoration: none; }
.tour-pop__video:hover { text-decoration: underline; }
.tour-pop__video[hidden] { display: none; }
