/* Investor's Secret — rounded, quiet, and legible in either theme.

   Colour is expressed twice and only twice: as a *ground* (--bg, --bg-lift, --bg-panel) and
   as an *ink* (--ink) laid over it at varying strength. Every surface, border and shade of
   text in this file is `color-mix(... var(--ink) N% ...)`, so switching the theme is a matter
   of swapping the ground and inverting the ink - there is no second stylesheet, and no rule
   that can be forgotten when one is added.

   The five semantic hues - accent/up, down, warn, info - are the customer's, chosen in
   Settings. Nothing hard-codes a hue: a bearish reading is `--down` everywhere, whatever the
   customer set it to, in every component. */

:root {
  color-scheme: dark;

  /* ground and ink */
  /* The site's ground, to the digit. The two were a shade apart - #0c0e18 against #0b0d14 -
     which is invisible on its own and obvious when a customer moves from one to the other in
     the same session. */
  --bg: #08080a;
  --bg-lift: #0c0c10;
  --bg-panel: #050506;
  --ink: #ffffff;
  --shade: #000000;
  /* Neutral, like the light theme's. These were cooled a few points on blue - #0b0d14 puts
     nine more of blue than of red on every card - which at page scale stops being a shade and
     starts being a wash the whole product sits under. The hue budget belongs to the two
     market colours; the ground is a ground. */
  /* Translucent grounds. --veil is chrome that sits over the page (the header, popovers);
     --scrim is what darkens the page behind a modal. */
  --veil: rgba(8, 8, 10, .82);
  --scrim: rgba(4, 4, 5, .74);
  /* Text laid on the accent, which is a mid-tone in both themes, so it stays dark in both. */
  --on-accent: #08090b;

  --surface: color-mix(in srgb, var(--ink) 2.5%, transparent);
  --surface-soft: color-mix(in srgb, var(--ink) 1.5%, transparent);
  --surface-hover: color-mix(in srgb, var(--ink) 4%, transparent);
  --border: color-mix(in srgb, var(--ink) 8%, transparent);
  --border-strong: color-mix(in srgb, var(--ink) 14%, transparent);
  --text: color-mix(in srgb, var(--ink) 88%, transparent);
  --text-dim: color-mix(in srgb, var(--ink) 55%, transparent);
  --text-faint: color-mix(in srgb, var(--ink) 32%, transparent);
  --text-xfaint: color-mix(in srgb, var(--ink) 15%, transparent);

  /* the customer's palette */
  /* The house colour is not a colour any more.
   *
   * `--accent` paints the *furniture*: the progress bar on the splash, the toggle you flip,
   * a focus ring, a sorted column header, a primary button. None of that is information -
   * it is the frame around information - and painting it in a hue meant every screen opened
   * with a blue wash across it that said nothing at all. The file already argues this about
   * the ground ("a hue that decorates is a hue that no longer informs"); the furniture was
   * the one place it had not been applied.
   *
   * So the accent is ink. Near-white on the dark ground, near-black on the light one, and
   * the entire chromatic budget is left to --up and --down, which are the two things on
   * screen that genuinely mean something. */
  --accent: #e9eaec;
  /* The scheme's own colours, as chosen. settings.js writes --up-raw/--down-raw inline on
     <html>; these are the fallbacks for a first paint before it has run. */
  /* The site spends its entire chromatic budget on these two and nothing else, and it is a
     far quieter pair than the app shipped with: a hue that decorates is a hue that no longer
     informs. These are the fallbacks before a customer picks a scheme of their own. */
  --up: var(--up-raw, #7d9e8b);
  --down: var(--down-raw, #a8757f);
  --warn: #e5b567;
  --info: #b7bcc4;

  --hdr-h: 56px;
  --layout-max: 1680px;
  --radius: 16px;
  --ease: cubic-bezier(.4, 0, .2, 1);
  /* Layer scale. The header is fixed at 200, so anything that must cover it starts above.
     Order: page chrome < header < modals < tour (the tour explains the modals). */
  --z-header: 200;
  --z-modal: 300;
  --z-tour: 400;
}

* { box-sizing: border-box; }

/* The `hidden` attribute is only a UA-level `display: none`, so any class that sets `display`
   silently defeats it - which is how the account menu and the Watchlist/Portfolio header
   actions stayed on screen after being hidden. Stating it once here makes the attribute mean
   what it says everywhere, whatever a component's own display value is. */
[hidden] { display: none !important; }

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

body {
  margin: 0;
  min-height: 100vh;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
               'Helvetica Neue', Arial, sans-serif;
  font-size: 14px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}
body.is-booting { overflow: hidden; }

/* Nothing behind the page. There was a tinted bloom here, on the theory that a flat ground
   reads as cheap - but a coloured wash under every screen is the thing that makes a product
   look generated rather than designed, and it fought the light theme outright. The ground is
   the ground. */

button, input { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: none; padding: 0; }
::selection { background: color-mix(in srgb, var(--accent) 25%, transparent); }

.mono { font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace; }

/* ── light theme ──────────────────────────────────────────────────────────
   One block, because of how the tokens above are built. Every surface, border and text
   colour in the file is a percentage of --ink over a ground, so inverting those two carries
   the entire stylesheet across - including any rule written after this one.

   The percentages are not reused verbatim. Dark ink on white reads heavier at the same alpha
   than white ink on black does, so the fills are pulled down and the borders up: matching the
   numbers would give grey text on grey boxes. */
html.theme-light {
  color-scheme: light;

  /* Neutral, and white where a surface is meant to read as paper.

     These greys used to be blue ones - #d3d7df on #c6cbd5, both a good few points cooler on
     blue than on red - and at page scale a tint that small stops reading as a colour choice
     and starts reading as a film laid over the whole product, as though something had not
     finished loading. Nothing on the page needed it: the hue budget belongs to the two market
     colours, and a ground that carries a hue of its own is competing with them.

     So the ground is a true neutral and the cards are white. The separation between them is
     kept - it is what stops the page reading as one flat sheet - it is just now a difference
     in lightness rather than in colour. */
  --bg: #e9e9ea;
  --bg-lift: #ffffff;
  --bg-panel: #dcdcde;
  --ink: #0b0b0d;
  --shade: #26262a;
  --veil: rgba(255, 255, 255, .92);
  --scrim: rgba(22, 22, 25, .42);

  /* Every step deeper than the dark theme's equivalent. Dark ink on a light ground needs
     more alpha to read, not less: the previous 2%/3% fills were invisible and the 12% border
     disappeared entirely on anything but a pure white card, which is what made the whole
     theme look washed out. */
  --surface: color-mix(in srgb, var(--ink) 5%, transparent);
  --surface-soft: color-mix(in srgb, var(--ink) 3.5%, transparent);
  --surface-hover: color-mix(in srgb, var(--ink) 9%, transparent);
  --border: color-mix(in srgb, var(--ink) 18%, transparent);
  --border-strong: color-mix(in srgb, var(--ink) 32%, transparent);
  --text: color-mix(in srgb, var(--ink) 97%, transparent);
  --text-dim: color-mix(in srgb, var(--ink) 74%, transparent);
  --text-faint: color-mix(in srgb, var(--ink) 58%, transparent);
  --text-xfaint: color-mix(in srgb, var(--ink) 42%, transparent);

  /* Ink here too, and dark enough to be a label on a white card: #17191d against #ffffff is
     about 15:1, so the sorted-column headers and primary chips that use it as text clear
     4.5:1 several times over. */
  --accent: #17191d;
  /* The same scheme, taken down far enough to survive a light ground. A colour picked to read
     against #07090e sits at about 2:1 against #d3d7df, and these are body-sized labels on
     verdict and action chips - so the mix is set by measurement, not by eye: the shipped
     schemes land between 4.7:1 and 7.8:1 against the page. The two sides get different
     weights because the bull colours ship lighter than the bear ones and need more taking
     down to arrive in the same place. */
  --up: color-mix(in srgb, var(--up-raw, #5aa9f2) 44%, #0a0a0c);
  --down: color-mix(in srgb, var(--down-raw, #f59e42) 50%, #0a0a0c);

  /* A tinted chrome takes its label colour down for the same reason the market colours do.
     The house blue on a light card measures about 4.4:1 and a picked custom tint can be far
     worse - #4d8df6 lands at 2.4:1 - which is a label on a button nobody can read. The fill
     and the edge stay where they are; only the text is darkened, so the pill still looks
     tinted rather than turning into a slab. */
  --chrome-text: color-mix(in srgb, var(--chrome-tint) 58%, #08080a);
  --warn: #8f6300;
  --info: #4b4f56;
  --on-accent: #ffffff;
}

/* Cards on white need an edge rather than a fill to read as cards - a 2% wash on a 3% ground
   is invisible - so the light theme leans on the border it already has. */
html.theme-light .card,
html.theme-light .overview-card,
html.theme-light .an-panel,
html.theme-light .stat-op { background: var(--bg-lift); }

/* Sparklines and chart strokes are drawn against the page, not against a card. */
html.theme-light .spark-line { stroke-opacity: .9; }
/* .7 of a mid-blue on a light ground is the '+1.00' nobody could read. */
html.theme-light .verdict .score { opacity: .85; }

/* ── button chrome ─────────────────────────────────────────────────────────
   What an *active* button looks like: the selected tab, the on segment, the lit chip, the
   current page number. Every one of those used to reach for --accent directly, which is why
   picking a colour scheme repainted the whole interface blue and why there was no way to
   have a grey chrome on a blue chart.

   Five tokens, consumed by every active-state rule in the file. A chrome variant redefines
   the tokens and nothing else, so a new one is six lines and touches nothing. --chrome-tint
   is the colour a tinted chrome tints *with*; the custom chrome overwrites it inline from
   the picker, and everything else leaves it following the accent. */
:root {
  --chrome-tint: var(--accent);
  /* Slate is the shipped treatment, including the first paint before settings.js runs. */
  --chrome-fill: color-mix(in srgb, var(--ink) 11%, transparent);
  --chrome-edge: color-mix(in srgb, var(--ink) 22%, transparent);
  --chrome-text: var(--text);
  --chrome-lift: none;
  --chrome-blur: none;
}

/* Tinted and Custom retain the original colour-wash treatment now that Slate owns the root. */
html.chrome-tinted,
html.chrome-custom {
  --chrome-fill: color-mix(in srgb, var(--chrome-tint) 10%, transparent);
  --chrome-edge: color-mix(in srgb, var(--chrome-tint) 22%, transparent);
  --chrome-text: var(--chrome-tint);
  --chrome-lift: none;
  --chrome-blur: none;
}

/* Watery is a web approximation of Apple's platform-only Liquid Glass renderer. The material
   stays clear enough to preserve context, while a pointer-driven caustic, a bright rim and a
   darker lower edge give it the lens-like depth that plain frosted glass is missing. */
html.chrome-glass {
  --glass-x: 28%;
  --glass-y: 0%;
  --glass-clear: rgb(255 255 255 / .065);
  --glass-bright: rgb(255 255 255 / .34);
  --glass-rim: rgb(255 255 255 / .24);
  --glass-depth: rgb(0 0 0 / .24);
  --chrome-fill:
    radial-gradient(90px 54px at var(--glass-x) var(--glass-y),
      var(--glass-bright), rgb(255 255 255 / .08) 34%, transparent 72%),
    linear-gradient(145deg, rgb(255 255 255 / .13), transparent 42%, rgb(255 255 255 / .035)),
    var(--glass-clear);
  --chrome-edge: var(--glass-rim);
  --chrome-text: var(--text);
  --chrome-lift:
    inset 0 1px 0 rgb(255 255 255 / .48),
    inset 1px 0 0 rgb(255 255 255 / .12),
    inset 0 -1px 0 var(--glass-depth),
    0 1px 1px rgb(255 255 255 / .08),
    0 7px 22px rgb(0 0 0 / .26);
  --chrome-blur: blur(18px) saturate(185%) contrast(1.08) brightness(1.08);
}

html.theme-light.chrome-glass {
  --glass-clear: rgb(255 255 255 / .34);
  --glass-bright: rgb(255 255 255 / .72);
  --glass-rim: rgb(255 255 255 / .7);
  --glass-depth: rgb(40 54 72 / .16);
}

html.chrome-glass :is(.tabs, .segmented) {
  border-color: rgb(255 255 255 / .13);
  background: rgb(255 255 255 / .035);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / .08), 0 8px 28px rgb(0 0 0 / .12);
  -webkit-backdrop-filter: blur(14px) saturate(145%);
  backdrop-filter: blur(14px) saturate(145%);
}

html.chrome-glass :is(
  .tab-glide, .seg-glide, .chip.is-on, .page-btn.is-active,
  .asset-chart-indicator-button.is-on b, .asset-chart-reset.is-on,
  .set-nav-item.is-active, .set-template.is-active, .set-source.is-active,
  .set-trigger.is-active, .set-chip.is-active, .sel-option.is-on
) {
  background: var(--chrome-fill);
  border-color: var(--chrome-edge);
  -webkit-backdrop-filter: var(--chrome-blur);
  backdrop-filter: var(--chrome-blur);
  box-shadow: var(--chrome-lift);
  filter: saturate(1.06);
  transform-style: preserve-3d;
}

html.chrome-glass :is(.tabs, .segmented):has(:active) :is(.tab-glide, .seg-glide),
html.chrome-glass :is(.chip.is-on, .page-btn.is-active):active {
  filter: brightness(1.14) saturate(1.12);
}

/* Slate. A plain grey pill - no colour anywhere in the chrome. */
html.chrome-slate {
  --chrome-fill: color-mix(in srgb, var(--ink) 11%, transparent);
  --chrome-edge: color-mix(in srgb, var(--ink) 22%, transparent);
  --chrome-text: var(--text);
  --chrome-lift: none;
}

/* Paper. The ground's opposite: a near-solid light chip on dark, a white one on light. */
html.chrome-paper {
  --chrome-fill: color-mix(in srgb, var(--ink) 92%, transparent);
  --chrome-edge: color-mix(in srgb, var(--ink) 92%, transparent);
  --chrome-text: var(--bg);
  --chrome-lift: 0 1px 8px color-mix(in srgb, var(--shade) 40%, transparent);
}

/* Ghost. Outline and text only - nothing filled. */
html.chrome-ghost {
  --chrome-fill: color-mix(in srgb, var(--ink) 1.8%, transparent);
  --chrome-edge: color-mix(in srgb, var(--ink) 46%, transparent);
  --chrome-text: var(--text);
  --chrome-lift: inset 0 0 0 1px color-mix(in srgb, var(--ink) 7%, transparent);
}

@media (prefers-reduced-transparency: reduce) {
  html.chrome-glass {
    --chrome-fill: color-mix(in srgb, var(--ink) 16%, var(--bg-lift));
    --chrome-blur: none;
  }
}

/* Paper turns the label into the ground colour, so an icon riding inside an active control
   has to follow it rather than staying inked. */
html.chrome-paper .chip.is-on svg,
html.chrome-paper .star.is-on svg { fill: color-mix(in srgb, var(--bg) 55%, transparent); }

/* ---------- header ---------- */

/* The header is fixed, so anything scrolled to lands underneath it and loses its top edge.
   Reserving its height here means a card scrolled into view keeps its own border visible. */
html { scroll-padding-top: calc(var(--hdr-h) + 18px); }
.card, .overview-card, .stat-op, .an-panel, .metric-col, section[id^="view-"] > * {
  scroll-margin-top: calc(var(--hdr-h) + 18px);
}

.hdr {
  position: fixed;
  inset: 0 0 auto 0;
  height: var(--hdr-h);
  z-index: var(--z-header);
  display: flex;
  align-items: center;
  background: var(--veil);
  backdrop-filter: blur(18px);
  border-bottom: 1px solid var(--border);
}

.hdr-inner {
  width: 100%;
  max-width: var(--layout-max);
  margin: 0 auto;
  padding: 0 22px;
  display: flex;
  align-items: center;
  gap: 26px;
  min-width: 0;
}

.brand {
  display: flex;
  align-items: center;
  gap: 9px;
  text-decoration: none;
  color: var(--text);
  letter-spacing: -.01em;
}

.brand-mark {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 9px;
  /* The logo is a white glyph on a dark tile - that *is* the asset, and it reads the same on
     a light page as on a dark one. Tinting it with the accent to survive the light theme made
     it a different logo, so the tile carries its own ground instead. */
  color: #ffffff;
  background: #0c0e18;
  border: 1px solid color-mix(in srgb, #ffffff 14%, transparent);
}
.brand-mark svg { height: 18px; width: auto; }
.brand-text { font-weight: 600; font-size: 15px; }
.brand-thin { color: var(--text-faint); font-weight: 400; margin-left: 4px; }

.tabs {
  position: relative;
  display: flex;
  gap: 2px;
  padding: 3px;
  border-radius: 999px;
  background: var(--surface-soft);
  border: 1px solid var(--border);
  min-width: 0;
  max-width: 100%;
}

.tab {
  position: relative;
  z-index: 1;
  padding: 6px 16px;
  border-radius: 999px;
  font-size: 13px;
  color: var(--text-dim);
  transition: color .2s var(--ease);
}
.tab:hover { color: var(--text); }
.tab.is-active { color: var(--chrome-text); }

.tab-glide, .seg-glide {
  position: absolute;
  top: 3px;
  bottom: 3px;
  left: 0;
  border-radius: 999px;
  background: var(--chrome-fill);
  border: 1px solid var(--chrome-edge);
  box-shadow: var(--chrome-lift);
  -webkit-backdrop-filter: var(--chrome-blur);
  backdrop-filter: var(--chrome-blur);
  opacity: 0;
  transition: transform .34s var(--ease), width .34s var(--ease), opacity .18s var(--ease);
  pointer-events: none;
}
.tabs.is-glide-ready .tab-glide,
.segmented.is-glide-ready .seg-glide { opacity: 1; }

.hdr-right { margin-left: auto; display: flex; align-items: center; gap: 10px; flex: none; }
.hdr-status { font-size: 12px; color: var(--text-faint); letter-spacing: .01em; }

.pulse {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--accent);
}
/* Live and stale differ by colour alone. The expanding ring this used to emit read as an
   alarm going off every 2.6 seconds for the entirely unremarkable news that the data is
   current, and it never stopped. */
.pulse.is-stale { background: var(--text-faint); }

.icon-btn {
  display: grid;
  place-items: center;
  width: 30px; height: 30px;
  border-radius: 10px;
  color: var(--text-dim);
  border: 1px solid var(--border);
  background: var(--surface-soft);
  transition: color .2s var(--ease), border-color .2s var(--ease), background .2s var(--ease);
}
.icon-btn svg { width: 15px; height: 15px; }
.icon-btn:hover { color: var(--text); border-color: var(--border-strong); background: var(--surface); }
.icon-btn.is-spinning svg { animation: spin .7s var(--ease); }
@keyframes spin { to { transform: rotate(360deg); } }

/* ---------- layout ---------- */

.page {
  position: relative;
  z-index: 1;
  max-width: var(--layout-max);
  margin: 0 auto;
  padding: calc(var(--hdr-h) + 34px) 22px 90px;
  width: 100%;
  min-width: 0;
}

.view { min-width: 0; animation: rise .34s var(--ease); }
.view.is-hidden { display: none; }
@keyframes rise { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

.page-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  margin-bottom: 22px;
}

h1 {
  margin: 0 0 4px;
  font-size: 25px;
  font-weight: 600;
  letter-spacing: -.02em;
}

.page-sub { margin: 0; color: var(--text-dim); font-size: 13.5px; }
.page-sub b { color: var(--text); font-weight: 500; }

/* ---------- highlights toggle ---------- */

.switch-wrap { display: flex; align-items: center; gap: 10px; cursor: pointer; user-select: none; }
.switch-label { font-size: 13px; color: var(--text-dim); }
.switch input { position: absolute; opacity: 0; pointer-events: none; }

.switch-track {
  display: block;
  width: 40px; height: 22px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--ink) 7%, transparent);
  border: 1px solid var(--border);
  transition: background .25s var(--ease), border-color .25s var(--ease);
}
.switch-thumb {
  display: block;
  width: 16px; height: 16px;
  margin: 2px;
  border-radius: 50%;
  background: var(--text-faint);
  transition: transform .28s var(--ease), background .25s var(--ease);
}
.switch input:checked + .switch-track { background: color-mix(in srgb, var(--accent) 22%, transparent); border-color: color-mix(in srgb, var(--accent) 40%, transparent); }
.switch input:checked + .switch-track .switch-thumb { transform: translateX(18px); background: var(--accent); }

/* ---------- highlight cards ---------- */

.highlights > *, .stat-stack > *, .tiles > * { min-width: 0; }
.stat-card > div { min-width: 0; }

/* One tidy band of equal-height boxes across the top: the stat column and the three list
   cards share a single row, so the strip reads as an organised set rather than a ragged one. */
.highlights {
  display: grid;
  grid-template-columns: minmax(230px, .8fr) repeat(3, minmax(0, 1fr));
  align-items: stretch;
  gap: 12px;
  margin-bottom: 26px;
  transition: opacity .28s var(--ease);
}
.highlights.is-off { display: none; }

.stat-stack { display: grid; grid-auto-rows: 1fr; gap: 12px; }

.card {
  background: var(--surface-soft);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px 16px;
  transition: border-color .25s var(--ease), background .25s var(--ease);
}
/* A card brightens its edge on hover. It does not fill.
   
   The fill was excluded for cards holding a `<table>`, because the rows there have their own
   hover and lighting the whole card as the cursor crossed it made the watchlist flash grey.
   That reasoning was right and the exclusion was too narrow: the rotation boards, the analyst
   boards and the statistics shortlists are grids of divs, not tables, so they were never
   caught by it - and a card of rows went grey the moment the pointer entered it, with the
   row hover underneath now invisible against it.
   
   Chasing that with a longer `:has()` list would only work until the next board. A container
   is not a row: it outlines, and the individual things inside it are what respond. */
.card:hover { border-color: var(--border-strong); }

.stat-card { display: flex; align-items: center; justify-content: space-between; gap: 14px; }
.stat-value { font-size: 19px; font-weight: 500; letter-spacing: -.02em; overflow-wrap: anywhere; }
.stat-label {
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
  margin-top: 2px;
  font-size: 12.5px; color: var(--text-dim);
}
.stat-spark { width: 116px; max-width: 40%; height: 40px; flex: 0 1 auto; min-width: 0; opacity: .9; }

.meter { width: 116px; height: 5px; border-radius: 999px; background: color-mix(in srgb, var(--ink) 7%, transparent); overflow: hidden; }
.meter span { display: block; height: 100%; border-radius: 999px; background: var(--up); transition: width .5s var(--ease); }

.list-card { display: flex; flex-direction: column; }
.list-head {
  display: flex; align-items: center; gap: 7px;
  font-size: 13px; font-weight: 500;
  margin-bottom: 9px;
}
.list-head .emoji { font-size: 13px; }
.list-head .count { margin-left: auto; font-size: 11.5px; color: var(--text-xfaint); }

.list-row {
  display: flex; align-items: center; gap: 9px;
  padding: 5px 0;
  font-size: 13px;
}
.list-row + .list-row { border-top: 1px solid color-mix(in srgb, var(--ink) 4.5%, transparent); }
.list-row img, .list-avatar {
  width: 19px; height: 19px; border-radius: 50%; flex: none;
  background: color-mix(in srgb, var(--ink) 6%, transparent);
}
.list-avatar { display: grid; place-items: center; font-size: 9px; color: var(--text-dim); letter-spacing: -.02em; }
.list-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.list-price { color: var(--text-dim); font-size: 12.5px; }
.list-extra { color: var(--text-faint); font-size: 11.5px; }

/* ---------- controls ---------- */

.controls {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
  margin-bottom: 14px;
}

.segmented {
  position: relative;
  display: flex; gap: 2px;
  padding: 4px;
  border-radius: 999px;
  background: var(--surface-soft);
  border: 1px solid var(--border);
}
.seg {
  position: relative; z-index: 1;
  padding: 7px 18px;
  border-radius: 999px;
  font-size: 13px;
  color: var(--text-dim);
  transition: color .22s var(--ease);
}
.seg:hover { color: var(--text); }
.seg.is-active { color: var(--chrome-text); }
.seg-glide { top: 4px; bottom: 4px; }

.controls-right {
  display: flex; align-items: center; justify-content: flex-end; gap: 10px;
  flex-wrap: wrap; min-width: 0; max-width: 100%;
}

.chip {
  display: inline-flex; align-items: center; gap: 7px;
  height: 36px; padding: 0 14px;
  border-radius: 10px;
  font-size: 13px;
  color: var(--text-dim);
  background: var(--surface-soft);
  border: 1px solid var(--border);
  transition: color .2s var(--ease), border-color .2s var(--ease), background .2s var(--ease);
}
.chip svg { width: 14px; height: 14px; }
.chip:hover { color: var(--text); border-color: var(--border-strong); }
.chip.is-on { color: var(--chrome-text); border-color: var(--chrome-edge); background: var(--chrome-fill); box-shadow: var(--chrome-lift); -webkit-backdrop-filter: var(--chrome-blur); backdrop-filter: var(--chrome-blur); }
.chip.is-on svg { fill: color-mix(in srgb, var(--chrome-text) 45%, transparent); }

.search {
  display: flex; align-items: center; gap: 8px;
  height: 36px; padding: 0 14px;
  border-radius: 10px;
  background: var(--surface-soft);
  border: 1px solid var(--border);
  transition: border-color .2s var(--ease), background .2s var(--ease);
  min-width: 0;
}
.search:focus-within { border-color: color-mix(in srgb, var(--accent) 35%, transparent); background: var(--surface); }
.search svg { width: 14px; height: 14px; color: var(--text-faint); flex: none; }
.search input {
  width: 190px; min-width: 0; max-width: 100%; border: none; outline: none; background: none;
  font-size: 13px;
}
.search input::placeholder { color: var(--text-faint); }
.search input::-webkit-search-cancel-button { -webkit-appearance: none; }

.class-note {
  margin: -4px 0 14px;
  font-size: 12.5px;
  color: var(--text-faint);
}

/* ---------- table ---------- */

/* No overflow clipping here: it would become the scrollport and trap the sticky header.
   The corners are rounded on the edge cells instead. */
.table-card {
  background: var(--surface-soft);
  border: 1px solid var(--border);
  border-radius: 18px;
  width: 100%;
  min-width: 0;
  max-width: 100%;
  overflow: hidden;
}

.table-scroll {
  width: 100%;
  min-width: 0;
  max-width: 100%;
  overflow-x: auto;
  overscroll-behavior-inline: contain;
  scrollbar-gutter: stable;
}

.screener { width: 100%; border-collapse: separate; border-spacing: 0; }

/* Chromium only honours sticky on the row group here, not on the cells. */
.screener thead {
  position: sticky;
  /* The horizontal table scroller is also Chromium's sticky containing block.  A header
     offset here pushes it over the first data row, which made every rank #1 look missing. */
  top: 0;
  z-index: 5;
}

.screener thead th {
  background: var(--veil);
  backdrop-filter: blur(12px);
  padding: 11px 14px 12px;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--text-faint);
  text-align: right;
  white-space: nowrap;
  border-bottom: 1px solid var(--border);
  transition: color .2s var(--ease);
  user-select: none;
}
.screener thead th:first-child { border-top-left-radius: 17px; }
.screener thead th:last-child { border-top-right-radius: 17px; }
.screener thead th.sortable { cursor: pointer; }
.screener thead th.sortable:hover { color: var(--text); }
.screener thead th.is-sorted { color: var(--accent); }
.screener th .arrow { display: inline-block; margin-left: 5px; font-size: 9px; opacity: .8; }

.col-star { width: 40px; text-align: center !important; }
.col-rank { width: 52px; text-align: right !important; }
.col-asset { text-align: left !important; }
.col-spark { width: 150px; text-align: right !important; }
.mobile-label, .mobile-valuation { display: none; }

/* One row model, everywhere.
 *
 * Every table in this app now behaves like the analyst board: nothing is drawn between rows,
 * and on hover the row lifts onto `--surface-hover` with a hairline border fading in around
 * it, rounded at both ends. A permanent rule under every row draws a grid nobody asked for
 * and made each screen look like a different product.
 *
 * A `<tr>` cannot carry a border under `border-collapse: separate`, so the row's outline is
 * assembled from its cells - top and bottom on every cell, the left and right ends on the
 * first and last. */
.screener tbody td {
  padding: 12px 14px;
  text-align: right;
  white-space: nowrap;
  border-top: 1px solid transparent;
  border-bottom: 1px solid transparent;
  transition: background .15s var(--ease), border-color .15s var(--ease);
}
.screener tbody td:first-child { border-left: 1px solid transparent; border-radius: 11px 0 0 11px; }
.screener tbody td:last-child { border-right: 1px solid transparent; border-radius: 0 11px 11px 0; }
/* One hover language for every row in this application: the row is outlined, and nothing
   is filled. A grey wash behind the cells competes with the data sitting on it - on a board
   of chips and coloured verdicts the fill is the most prominent thing on the row, which is
   exactly backwards - and the outline already says which row the pointer is on. */
.screener tbody tr:hover td {
  border-top-color: var(--border);
  border-bottom-color: var(--border);
}
.screener tbody tr:hover td:first-child { border-left-color: var(--border); }
.screener tbody tr:hover td:last-child { border-right-color: var(--border); }

.star {
  display: grid; place-items: center;
  width: 24px; height: 24px; margin: 0 auto;
  color: var(--text-xfaint);
  border-radius: 8px;
  transition: color .2s var(--ease), transform .2s var(--ease);
}
.star svg { width: 14px; height: 14px; }
.star:hover { color: var(--text-dim); transform: scale(1.12); }
.star.is-on { color: var(--chrome-text); }
.star.is-on svg { fill: color-mix(in srgb, var(--chrome-text) 40%, transparent); }

.rank { color: var(--text-faint); font-size: 12.5px; }

.asset { display: flex; align-items: center; gap: 11px; text-align: left; }
.asset-icon {
  position: relative;
  width: 26px; height: 26px; border-radius: 50%; flex: none;
  background: color-mix(in srgb, var(--ink) 5%, transparent);
  display: grid; place-items: center;
  font-size: 10px; color: var(--text-dim); letter-spacing: -.02em;
  overflow: hidden;
}
.asset-icon.has-logo img { position: absolute; inset: 0; background: var(--bg-panel); }
.asset-icon img { width: 100%; height: 100%; object-fit: cover; }
.asset-icon.is-text { font-size: 8.5px; letter-spacing: .01em; color: var(--text-faint); }
.asset-name {
  display: inline-block;
  max-width: 260px;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: bottom;
  font-weight: 500;
  letter-spacing: -.01em;
}
.asset-sym { color: var(--text-faint); font-size: 12px; margin-left: 7px; text-transform: uppercase; }
.asset-sub {
  display: block;
  max-width: 260px;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--text-xfaint);
  font-size: 11.5px;
  margin-top: -3px;
}

.price { font-size: 13.5px; letter-spacing: -.01em; }
.num { color: var(--text-dim); font-size: 13px; }

.chg { font-size: 13px; }
.chg.up { color: var(--up); }
.chg.down { color: var(--down); }
.chg.flat { color: var(--text-faint); }
.chg .tri { font-size: 8px; margin-right: 3px; vertical-align: 1px; }
.delta { font-size: 13px; color: var(--text-dim); }
.delta.up { color: color-mix(in srgb, var(--accent) 75%, transparent); }
.delta.down { color: color-mix(in srgb, var(--down) 75%, transparent); }

.tag {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 7px;
  font-size: 11.5px;
  color: var(--text-dim);
  background: color-mix(in srgb, var(--ink) 4%, transparent);
  border: 1px solid var(--border);
}

.spark { width: 132px; height: 40px; display: block; margin-left: auto; }
.spark-empty {
  width: 132px; height: 40px;
  margin-left: auto;
  border-radius: 8px;
  background: linear-gradient(90deg, color-mix(in srgb, var(--ink) 2%, transparent), color-mix(in srgb, var(--ink) 4.5%, transparent), color-mix(in srgb, var(--ink) 2%, transparent));
  background-size: 200% 100%;
}
tr.is-fetching .spark-empty { animation: shimmer 1.6s linear infinite; }
@keyframes shimmer { to { background-position: -200% 0; } }

.skeleton-row td { padding: 15px 14px; }
.skeleton-bar { height: 11px; border-radius: 6px; background: color-mix(in srgb, var(--ink) 3.5%, transparent); animation: breathe 1.8s var(--ease) infinite; }
@keyframes breathe { 50% { opacity: .45; } }

/* ---------- footer / pager ---------- */

.table-foot {
  border-radius: 0 0 17px 17px;
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
  padding: 14px 16px;
  border-top: 1px solid var(--border);
  background: color-mix(in srgb, var(--ink) 1.2%, transparent);
}
.foot-info { font-size: 12.5px; color: var(--text-faint); }
.pager { display: flex; align-items: center; gap: 5px; }

.page-btn {
  min-width: 32px; height: 32px;
  padding: 0 9px;
  border-radius: 10px;
  font-size: 12.5px;
  color: var(--text-dim);
  border: 1px solid transparent;
  transition: color .2s var(--ease), background .2s var(--ease), border-color .2s var(--ease);
}
.page-btn:hover:not(:disabled) { color: var(--text); background: var(--surface); border-color: var(--border); }
.page-btn.is-active { color: var(--chrome-text); background: var(--chrome-fill); border-color: var(--chrome-edge); box-shadow: var(--chrome-lift); }
.page-btn:disabled { color: var(--text-xfaint); cursor: default; }
.page-gap { color: var(--text-xfaint); padding: 0 2px; }

/* ---------- states ---------- */

.empty-card {
  border: 1px solid var(--border);
  border-radius: 20px;
  background: var(--surface-soft);
  padding: 54px 40px;
  text-align: center;
  max-width: 640px;
  margin: 40px auto;
}
.empty-icon {
  width: 46px; height: 46px; margin: 0 auto 16px;
  display: grid; place-items: center;
  border-radius: 14px;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 20%, transparent);
}
.empty-icon svg { width: 22px; height: 22px; }
.empty-card h2 { margin: 0 0 8px; font-size: 17px; font-weight: 500; }
.empty-card p { margin: 0 auto; color: var(--text-dim); max-width: 420px; font-size: 13.5px; }
.empty-tags { display: flex; gap: 8px; justify-content: center; margin-top: 20px; flex-wrap: wrap; }
.empty-tags span {
  padding: 5px 13px; border-radius: 7px; font-size: 12px;
  color: var(--text-faint); background: var(--surface-soft); border: 1px solid var(--border);
}

.table-msg { padding: 46px 20px; text-align: center; color: var(--text-faint); font-size: 13.5px; }
.table-msg b { display: block; color: var(--text-dim); font-weight: 500; margin-bottom: 4px; }

/* ---------- view as ----------

   The banner is not decoration. An administrator who forgets a preview is running will read
   every missing tab as a bug, so it stays on screen for as long as the preview does and says
   plainly that access is unchanged. */
.viewas-bar {
  position: fixed; left: 50%; bottom: 18px; transform: translateX(-50%);
  z-index: var(--z-modal, 90);
  display: flex; align-items: center; gap: 14px;
  padding: 9px 10px 9px 16px; border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--warn) 42%, transparent);
  background: color-mix(in srgb, var(--warn) 13%, var(--bg-lift));
  color: var(--text); font-size: 12.5px;
  box-shadow: 0 18px 44px color-mix(in srgb, var(--shade) 48%, transparent);
  animation: viewas-in .22s var(--ease);
}
@keyframes viewas-in { from { opacity: 0; transform: translate(-50%, 8px); } }
.viewas-bar b { font-weight: 600; }
.viewas-bar button {
  padding: 6px 13px; border-radius: 999px; font-size: 12px;
  border: 1px solid var(--border-strong); background: var(--bg); color: var(--text);
}
.viewas-bar button:hover { background: var(--surface-hover); }
@media (prefers-reduced-motion: reduce) { .viewas-bar { animation: none; } }
@media (max-width: 640px) { .viewas-bar { left: 12px; right: 12px; transform: none; justify-content: space-between; } }

.set-viewas { display: grid; gap: 8px; margin-top: 14px; }
.set-viewas-row {
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 12px; align-items: start;
  padding: 13px 15px; border-radius: 12px; cursor: pointer;
  border: 1px solid var(--border); background: var(--surface-soft);
  transition: border-color .16s var(--ease), background .16s var(--ease);
}
.set-viewas-row:hover { border-color: var(--border-strong); background: var(--surface-hover); }
.set-viewas-row.is-on {
  border-color: color-mix(in srgb, var(--accent) 55%, transparent);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}
.set-viewas-row input { margin-top: 3px; accent-color: var(--accent); }
.set-viewas-row b { display: block; font-size: 13.5px; font-weight: 500; }
.set-viewas-row small { display: block; margin-top: 3px; color: var(--text-faint); font-size: 12px; line-height: 1.55; }
.set-viewas-note { margin-top: 14px; }
@media (prefers-reduced-motion: reduce) { .set-viewas-row { transition: none; } }

/* ---------- the phone ----------

   The tab strip is eight items wide and does not fit a phone. Below 820px it becomes a sheet
   that drops out of the header, and the three-line button is what opens it.

   Hidden from the desktop layout entirely rather than moved, so nothing about the strip's
   glide indicator or its keyboard order changes on a machine where it already fits. */
.hdr-burger {
  display: none; flex: none;
  width: 38px; height: 34px; padding: 9px 8px; margin-right: 2px;
  border-radius: 10px; border: 1px solid var(--border); background: var(--surface);
  flex-direction: column; justify-content: space-between; align-items: stretch;
}
.hdr-burger span {
  display: block; height: 1.5px; border-radius: 2px; background: var(--text-dim);
  transition: transform .22s var(--ease), opacity .18s var(--ease);
}
.hdr-burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
.hdr-burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.hdr-burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

@media (max-width: 820px) {
  .hdr-burger { display: flex; }

  /* ...but never on the signed-out preview, where it is both useless and destructive.
   *
   * Useless: it toggles `#tabs`, and there are no tabs until somebody has signed in - so on
   * the landing page it is a menu button that opens nothing.
   *
   * Destructive: that header is a two-column grid (the wordmark, then the two doors), and the
   * burger is a third child. A third item in a two-column grid starts a new row, which put
   * "Log in" and "Sign up" on a line of their own and left the bar 78px tall with its contents
   * spilling out of it - see the header note further down. */
  body.is-signed-out .hdr-burger { display: none; }

  .hdr-inner { gap: 8px; }
  .brand-text { display: none; }
  /* ...but the preview keeps its wordmark, for the reason given at the 720px rule below: there
     are no tabs on that page competing for the room, and the name is the thing it is there to
     introduce. That exception only started at 720px, which left a gap - between 721 and 820px,
     on exactly the tablet widths, the bar showed a lone mark with an empty half-bar beside it.
     The smallest phones still drop it; that rule is at the end of the file. */
  body.is-signed-out .brand-text { display: inline; }

  /* The sheet. Laid out as a column under the header, and animated on `grid-template-rows`
     so it can slide from nothing to its own height without anybody having to measure it. */
  .tabs {
    position: absolute; top: calc(100% + 8px); left: 12px; right: 12px; z-index: 60;
    display: grid; grid-template-rows: 0fr;
    padding: 0; border-radius: 14px; border: 1px solid transparent;
    background: var(--bg-lift); box-shadow: none;
    overflow: hidden; opacity: 0; pointer-events: none;
    transition: grid-template-rows .26s var(--ease), opacity .2s var(--ease),
                padding .26s var(--ease), border-color .2s var(--ease);
  }
  .tabs.is-open {
    grid-template-rows: 1fr; opacity: 1; pointer-events: auto;
    padding: 7px; border-color: var(--border-strong);
    box-shadow: 0 24px 56px color-mix(in srgb, var(--shade) 50%, transparent);
  }
  /* The rows live in the single grid track, so the collapse animates cleanly. */
  .tabs > .tab { min-height: 0; }
  .tabs.is-open > .tab { min-height: auto; }
  .tabs .tab {
    width: 100%; text-align: left; border-radius: 9px; padding: 11px 13px; font-size: 14px;
  }
  /* The sliding pill cannot follow a vertical list, and a stale one parked over the wrong
     row is worse than none. The active tab carries its own background here instead. */
  .tab-glide { display: none; }
  .tabs .tab.is-active { background: var(--surface-hover); color: var(--text); }
}

/* The screener is a wide table and will not become a phone layout by reflowing. It scrolls
   sideways inside its own container, which is honest, and the page itself never does. */
@media (max-width: 640px) {
  body { overflow-x: hidden; }
  .page-head h1 { font-size: 21px; }
  .hdr-account-mail { display: none; }
  .hdr-inner { padding-left: 10px; padding-right: 10px; }
  .rot-picker { padding: 12px; }
  .rot-picker-card { padding: 20px 18px 18px; }
  .settings-panel, .consent-card { border-radius: 14px; }
}

/* ---------- responsive ---------- */

@media (max-width: 1180px) {
  .highlights { grid-template-columns: minmax(220px, 1fr) repeat(2, minmax(0, 1fr)); }
  .highlights .list-card:nth-child(n+5) { display: none; }
}
@media (max-width: 900px) {
  .screener thead { position: static; }
}
@media (max-width: 860px) {
  .highlights { grid-template-columns: 1fr; }
  .highlights .list-card:nth-child(n+3) { display: none; }
  .page-head { flex-direction: column; align-items: flex-start; gap: 12px; }
  .controls { align-items: stretch; }
  .controls-right { width: 100%; justify-content: flex-start; }
  .controls-right .search { flex: 1 1 190px; }
  .search input { width: 100%; }
  .segmented { overflow-x: auto; }
  h1 { font-size: 21px; }
}

/* ---------- statistics ---------- */

.segmented.compact { padding: 4px; }
.segmented.compact .seg { padding: 7px 15px; font-size: 13px; }
.segmented.compact .seg-glide { top: 4px; bottom: 4px; }

.breadth {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin: 0 0 14px;
}

.breadth-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 12px;
  border-radius: 7px;
  font-size: 12.5px;
  border: 1px solid var(--border);
  background: var(--surface-soft);
  color: var(--text-dim);
  transition: opacity .25s var(--ease);
}
.breadth-chip b { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-weight: 500; font-size: 12px; }
.breadth-chip.is-empty { opacity: .4; }
.breadth-note { font-size: 12px; color: var(--text-xfaint); margin-left: 4px; }

/* verdict levels — two strengths per side, plus a quiet middle */
.lvl-sbull { color: var(--up); border-color: color-mix(in srgb, var(--up) 38%, transparent); background: color-mix(in srgb, var(--up) 13%, transparent); }
.lvl-bull  { color: var(--up); border-color: color-mix(in srgb, var(--up) 20%, transparent);  background: color-mix(in srgb, var(--up) 6%, transparent); }
.lvl-neutral { color: var(--text-faint); }
.lvl-bear  { color: var(--down); border-color: color-mix(in srgb, var(--down) 20%, transparent);  background: color-mix(in srgb, var(--down) 6%, transparent); }
.lvl-sbear { color: var(--down); border-color: color-mix(in srgb, var(--down) 34%, transparent); background: color-mix(in srgb, var(--down) 12%, transparent); }
.lvl-none  { color: var(--text-xfaint); }

.col-trend { width: 190px; }
.col-vote { width: 118px; }
.trend-cell, .vote-cell { text-align: right !important; }

.verdict {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 5px 12px;
  border-radius: 7px;
  font-size: 12.5px;
  border: 1px solid var(--border);
  background: var(--surface-soft);
  white-space: nowrap;
}
.verdict .score { font-size: 11.5px; opacity: .7; }
.verdict.is-loading, .vote.is-loading {
  display: inline-block;
  height: 22px;
  width: 120px;
  border-radius: 999px;
  border-color: transparent;
  background: linear-gradient(90deg, color-mix(in srgb, var(--ink) 2%, transparent), color-mix(in srgb, var(--ink) 5%, transparent), color-mix(in srgb, var(--ink) 2%, transparent));
  background-size: 200% 100%;
}
tr.is-fetching .verdict.is-loading,
tr.is-fetching .vote.is-loading { animation: shimmer 1.6s linear infinite; }
.vote.is-loading { width: 62px; height: 16px; }

.vote { font-size: 12.5px; white-space: nowrap; }
.vote.up { color: var(--up); }
.vote.down { color: var(--down); }
.vote.none { color: var(--text-xfaint); }

#statsTable tbody td { padding: 12px 14px; }

/* ---------- statistics: overview panel ---------- */

.overview { margin-bottom: 26px; }
.overview.is-off { display: none; }

.stats-universe-control { display: flex; align-items: center; gap: 10px; margin-left: auto; }
.control-label { color: var(--text-faint); font-size: 12px; }
.stats-custom {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: -2px 0 14px auto; padding: 12px 14px;
  max-width: 720px; border: 1px solid var(--border); border-radius: 14px;
  background: var(--surface-soft);
}
.stats-custom.is-hidden { display: none; }
.stats-custom > label { color: var(--text-dim); font-size: 12.5px; }
.stats-custom > span { flex-basis: 100%; color: var(--text-xfaint); font-size: 11.5px; }
.stats-custom-entry { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 250px; }
.stats-custom-entry input {
  width: 100%; min-width: 0; height: 36px; padding: 0 12px;
  border: 1px solid var(--border); border-radius: 10px; outline: none;
  color: var(--text); background: color-mix(in srgb, var(--ink) 1.8%, transparent); font-size: 12.5px;
}
.stats-custom-entry input:focus { border-color: color-mix(in srgb, var(--accent) 34%, transparent); }
.stats-custom-entry input::placeholder { color: var(--text-xfaint); }
.scope-coverage {
  margin: 0 0 12px; padding: 9px 12px; border-radius: 11px;
  color: var(--text-faint); background: color-mix(in srgb, var(--warn) 4.5%, transparent);
  border: 1px solid color-mix(in srgb, var(--warn) 12%, transparent); font-size: 11.5px;
}

.tiles > * { min-width: 0; }

.tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 12px;
  margin-bottom: 14px;
}
.stat-sub { font-size: 11.5px; color: var(--text-xfaint); margin-top: 3px; }

.overview-loading { text-align: center; padding: 28px; }
.overview-loading .skeleton-bar { margin: 0 auto 12px; height: 8px; }
.overview-loading p { margin: 0; color: var(--text-faint); font-size: 13px; }

.dist { margin-bottom: 14px; }
.dist-bar {
  display: flex;
  height: 8px;
  border-radius: 999px;
  overflow: hidden;
  background: color-mix(in srgb, var(--ink) 4%, transparent);
}
.dist-seg { display: block; height: 100%; background: currentColor; opacity: .75; }
.dist-legend { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 9px; }
.dist-key { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-faint); }
.dist-key i { width: 8px; height: 8px; border-radius: 3px; background: currentColor; }
.dist-key b { color: var(--text-dim); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-weight: 500; }

.overview-lists {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  align-items: start;
  gap: 12px;
}
@media (max-width: 1180px) { .overview-lists { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 760px)  { .overview-lists { grid-template-columns: 1fr; } }
.overview-lists .list-head .count { font-size: 11px; color: var(--text-xfaint); font-weight: 400; }
.list-name.muted { color: var(--text-xfaint); }

/* ---------- statistics: table columns ---------- */

.col-stdev { width: 92px; }
.col-action { width: 116px; }
.col-rankcol { width: 74px; }
.rank-cell { text-align: right !important; color: var(--text-dim); font-size: 12.5px; }
.stdev.up { color: color-mix(in srgb, var(--accent) 80%, transparent); }
.stdev.down { color: color-mix(in srgb, var(--down) 80%, transparent); }

.vote.lvl-sbear { color: var(--down); }
.vote.lvl-bear { color: color-mix(in srgb, var(--down) 78%, transparent); }
.vote.lvl-bull { color: color-mix(in srgb, var(--accent) 78%, transparent); }
.vote.lvl-sbull { color: var(--up); }
.val-col { color: var(--text-xfaint); }

/* action calls — deliberately muted */
.action {
  display: inline-block;
  padding: 4px 11px;
  border-radius: 7px;
  font-size: 12px;
  border: 1px solid transparent;
  white-space: nowrap;
}
/* The action column reads off the colour scheme, same as the verdicts beside it.
   Long was on --accent and Accumulate on --info, which meant a customer who picked a
   green-and-red scheme got a blue Long chip next to a red Short one and no way to fix it -
   the two halves of the same decision drawn in unrelated colours. Four tiers now, out of two
   scheme colours: a full one and a softened one on each side, which is exactly the ladder the
   .lvl-* verdict chips already use. */
.act-long  { color: color-mix(in srgb, var(--up) 92%, transparent);   background: color-mix(in srgb, var(--up) 11%, transparent);   border-color: color-mix(in srgb, var(--up) 28%, transparent); }
.act-dca   { color: color-mix(in srgb, var(--up) 72%, var(--text-dim)); background: color-mix(in srgb, var(--up) 6%, transparent); border-color: color-mix(in srgb, var(--up) 17%, transparent); }
.act-tp    { color: color-mix(in srgb, var(--down) 72%, var(--text-dim)); background: color-mix(in srgb, var(--down) 6%, transparent); border-color: color-mix(in srgb, var(--down) 17%, transparent); }
.act-short { color: color-mix(in srgb, var(--down) 92%, transparent); background: color-mix(in srgb, var(--down) 11%, transparent); border-color: color-mix(in srgb, var(--down) 28%, transparent); }
.act-hold  { color: var(--text-faint); background: color-mix(in srgb, var(--ink) 3%, transparent); border-color: var(--border); }
.act-neutral { color: var(--text-faint); background: color-mix(in srgb, var(--ink) 2.5%, transparent); border-color: var(--border); }

/* The expanded matrix is column-heavy; tighten it so it stays inside the card. */
.screener.is-expanded td, .screener.is-expanded th { padding: 12px 7px; }
.screener.is-expanded .col-star { width: 34px; }
.screener.is-expanded .col-rank { width: 42px; }
.screener.is-expanded .col-asset { width: 190px; max-width: 190px; }
.screener.is-expanded .asset-name, .screener.is-expanded .asset-sub { max-width: 116px; }
.screener.is-expanded .col-vote { width: 70px; }
.screener.is-expanded .vote-cell { padding-left: 4px; padding-right: 4px; }
.screener.is-expanded .vote { font-size: 11.5px; }
.screener.is-expanded .price, .screener.is-expanded .num { font-size: 12.5px; }

/* ---------- statistics: weekly switches ---------- */

.section-title {
  display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
  margin: 28px 0 12px;
  font-size: 17px; font-weight: 500; letter-spacing: -.01em;
}
.section-note { font-size: 12.5px; color: var(--text-faint); font-weight: 400; }

.switch-list { padding: 4px 6px; }
.switch-row {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 10px;
  border-radius: 12px;
  cursor: pointer;
  transition: background .18s var(--ease);
}
.switch-row:hover { background: color-mix(in srgb, var(--ink) 2.5%, transparent); }
.switch-row + .switch-row { border-top: 1px solid color-mix(in srgb, var(--ink) 4.5%, transparent); }
.switch-icon img, .switch-icon .list-avatar { width: 24px; height: 24px; border-radius: 50%; display: block; }
.switch-main { flex: 1; min-width: 0; }
.switch-title { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 13.5px; font-weight: 500; }
.switch-title .verdict { padding: 2px 9px; font-size: 11.5px; }
.switch-note { font-size: 12.5px; color: var(--text-faint); margin-top: 2px; }
.switch-meta { display: flex; align-items: center; gap: 12px; flex: none; }
.switch-when { font-size: 12px; color: var(--text-xfaint); }

/* ---------- asset detail ---------- */

#tableBody tr[data-symbol] { cursor: pointer; }

.back-btn {
  display: inline-flex; align-items: center; gap: 7px;
  margin-bottom: 20px; padding: 7px 14px 7px 10px;
  border-radius: 10px;
  font-size: 13px; color: var(--text-dim);
  background: var(--surface-soft); border: 1px solid var(--border);
  transition: color .2s var(--ease), border-color .2s var(--ease);
}
.back-btn svg { width: 15px; height: 15px; }
.back-btn:hover { color: var(--text); border-color: var(--border-strong); }

.asset-hero { display: flex; align-items: center; gap: 16px; margin-bottom: 20px; flex-wrap: wrap; }
.asset-hero-icon {
  position: relative;
  width: 52px; height: 52px; border-radius: 50%; flex: none;
  display: grid; place-items: center; overflow: hidden;
  font-size: 14px; color: var(--text-faint);
  background: color-mix(in srgb, var(--ink) 5%, transparent);
}
.asset-hero-icon img { position: absolute; inset: 0; width: 100%; height: 100%; background: var(--bg-panel); }
.asset-hero-main h1 { display: flex; align-items: center; gap: 10px; margin: 0; font-size: 24px; }
.asset-hero-main .asset-sym { font-size: 14px; }
.asset-price { display: flex; align-items: baseline; gap: 12px; margin-top: 2px; }
.asset-price .mono { font-size: 24px; letter-spacing: -.02em; }
.asset-tags { margin-left: auto; display: flex; gap: 6px; flex-wrap: wrap; max-width: 46%; justify-content: flex-end; }

.change-strip { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; padding: 0; margin-bottom: 14px; }
.change-cell {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 12px 8px;
}
.change-cell + .change-cell { border-left: 1px solid var(--border); }
.change-label { font-size: 11.5px; color: var(--text-faint); }

.asset-grid { display: grid; grid-template-columns: 300px minmax(0, 1fr); gap: 12px; align-items: start; }
.stats-card { padding: 14px 16px; }
.stat-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 9px 0; font-size: 13px; color: var(--text-dim);
}
.stat-row + .stat-row { border-top: 1px solid color-mix(in srgb, var(--ink) 4.5%, transparent); }
.stat-row b { color: var(--text); font-weight: 500; font-size: 12.5px; }
.stat-aside { color: var(--text-faint); font-size: 11.5px; }

.chart-card { padding: 14px 16px 10px; }
.chart-controls { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 12px; }
.overlay-toggles { display: flex; gap: 6px; flex-wrap: wrap; }
.chip.tiny { height: 28px; padding: 0 11px; font-size: 12px; }
.chart-host { height: 320px; transition: opacity .2s var(--ease); }
.chart-host.is-busy { opacity: .45; }
.chart { width: 100%; height: 320px; display: block; }
.chart .axis { fill: color-mix(in srgb, var(--ink) 28%, transparent); font-size: 11px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.overlay-0 { color: color-mix(in srgb, var(--accent) 55%, transparent); }
.overlay-1 { color: color-mix(in srgb, var(--info) 55%, transparent); }
.overlay-2 { color: color-mix(in srgb, var(--warn) 55%, transparent); }
.overlay-3 { color: color-mix(in srgb, var(--down) 50%, transparent); }

.tf-card { margin-top: 12px; padding: 14px 16px; }
.tf-table { width: 100%; border-collapse: separate; border-spacing: 0; margin-top: 6px; }
.tf-table th {
  text-align: left; padding: 8px 10px; font-size: 11.5px; font-weight: 500;
  color: var(--text-faint); border-bottom: 1px solid var(--border);
}
.tf-table td { padding: 10px; border-bottom: 1px solid color-mix(in srgb, var(--ink) 4%, transparent); }
.tf-table tr:last-child td { border-bottom: none; }
.tf-label { color: var(--text-dim); font-size: 12.5px; }

.about-card { margin-top: 12px; padding: 22px 24px; }
.about-card h2 { margin: 0 0 14px; font-size: 18px; font-weight: 500; letter-spacing: -.01em; }
.about-card p { margin: 0 0 12px; color: var(--text-dim); font-size: 13.5px; line-height: 1.75; max-width: 76ch; }
.about-links { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 16px; }
.about-links a {
  padding: 6px 13px; border-radius: 10px; font-size: 12.5px; text-decoration: none;
  color: var(--text-dim); background: var(--surface-soft); border: 1px solid var(--border);
  transition: color .2s var(--ease), border-color .2s var(--ease);
}
.about-links a:hover { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 30%, transparent); }

@media (max-width: 980px) {
  .asset-grid { grid-template-columns: 1fr; }
  .asset-tags { margin-left: 0; max-width: 100%; justify-content: flex-start; }
  .change-strip { grid-auto-flow: row; grid-template-columns: repeat(3, 1fr); }
  .change-cell + .change-cell { border-left: none; }
}

.denom-switch.is-hidden { display: none; }

/* ---------- calm initial hydration ---------- */

.boot-splash {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: grid;
  place-items: center;
  overflow: hidden;
  background: var(--bg);
  transition: opacity .55s var(--ease), visibility .55s var(--ease);
}
.boot-splash.is-ready { opacity: 0; visibility: hidden; pointer-events: none; }
/* The two drifting blurred discs that used to live here are gone. They were the first thing
   anyone saw of this product and they said "template". The splash is now the mark, the bar
   and the steps - which is all it was ever for. */
.boot-ambient { display: none; }
/* A card, not text floating in the middle of a black rectangle. The splash is the first
   thing anybody sees and it was the only surface in the app with no edges. */
.boot-panel {
  position: relative;
  width: min(460px, calc(100vw - 44px));
  text-align: center;
  padding: 36px 38px 32px;
  border-radius: 20px;
  border: 1px solid color-mix(in srgb, #ffffff 9%, transparent);
  background: color-mix(in srgb, #ffffff 3%, #0b0b0e);
  box-shadow: 0 28px 70px rgba(0, 0, 0, .5);
}
.boot-mark {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  margin: 0 auto 22px;
  border-radius: 13px;
  color: #ffffff;
  background: #0c0e18;
  border: 1px solid color-mix(in srgb, #ffffff 14%, transparent);
}
.boot-mark svg { height: 28px; width: auto; }

/* The bar is the whole point of this screen now, so it is sized to be read from across a
   desk rather than tucked under the copy. */
/* Deliberately substantial. This is the only thing on the screen doing anything, it is the
   first impression of the whole product, and a hairline that inches along reads as a program
   struggling. Width is animated in JS - see `stepBootBar` - so there is no CSS transition
   here to fight it. */
.boot-bar {
  position: relative;
  height: 14px;
  margin: 32px 0 16px;
  border-radius: 999px;
  overflow: hidden;
  background: color-mix(in srgb, var(--ink) 7%, transparent);
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, .28);
}
.boot-bar span {
  display: block;
  position: relative;
  height: 100%;
  width: 0;
  border-radius: 999px;
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--accent) 55%, transparent),
    var(--accent) 62%,
    color-mix(in srgb, var(--accent) 88%, white));
  box-shadow: 0 0 16px color-mix(in srgb, var(--accent) 45%, transparent);
}
/* The leading edge, brightened. Movement is easier to see at an edge than across a fill, so
   the eye has something to track even when the bar is only drifting. */
.boot-bar span::after {
  content: "";
  position: absolute;
  top: 0; right: 0; bottom: 0;
  width: 26px;
  border-radius: 999px;
  background: linear-gradient(90deg, transparent, color-mix(in srgb, white 55%, transparent));
  opacity: .5;
}
/* A sheen travelling over the whole track while there is still work to do. It stops when the
   bar is full, which is the only moment it should. */
.boot-bar::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent,
    color-mix(in srgb, var(--ink) 16%, transparent), transparent);
  transform: translateX(-100%);
  animation: boot-sheen 2.1s var(--ease) infinite;
}
.boot-splash.is-ready .boot-bar::after { animation: none; }
@keyframes boot-sheen { to { transform: translateX(100%); } }

.boot-line { display: flex; align-items: center; gap: 16px; }
.boot-line .boot-bar { flex: 1 1 auto; margin: 32px 0; }
/* Tabular and large enough to read at a glance from across a desk. Tabular matters more than
   it sounds: proportional digits make the number jitter sideways as it counts, which is the
   same visual noise the bar was rewritten to remove. */
.boot-percent {
  color: var(--accent);
  font-size: 20px;
  font-weight: 500;
  letter-spacing: -.01em;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

.boot-steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px 6px;
  color: var(--text-xfaint);
  font-size: 10.5px;
}
/* The panel centres its text, which floats each label away from the dot that belongs to
   it. These read as a checklist, so they align left against their own marker. */
.boot-steps li {
  position: relative;
  padding-left: 14px;
  text-align: left;
  transition: color .3s var(--ease);
}
.boot-steps li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  width: 6px;
  height: 6px;
  margin-top: -3px;
  border-radius: 50%;
  background: currentColor;
  opacity: .4;
  transition: opacity .3s var(--ease), transform .3s var(--ease);
}
.boot-steps li.is-done { color: color-mix(in srgb, var(--accent) 78%, transparent); }
.boot-steps li.is-done::before { opacity: 1; transform: scale(1.15); }
.boot-steps li.is-failed { color: color-mix(in srgb, var(--warn) 80%, transparent); }
.boot-steps li.is-active { color: var(--text-dim); }
.boot-steps li.is-active::before { animation: boot-blink 1s var(--ease) infinite; }
@keyframes boot-blink { 50% { opacity: .25; } }

@media (prefers-reduced-motion: reduce) {
  .boot-bar span::after { display: none; }
  .boot-bar::after, .boot-steps li.is-active::before { animation: none; }
}
.boot-steps span.is-failed { color: color-mix(in srgb, var(--down) 78%, transparent); }
.boot-splash.is-degraded .boot-progress span {
  background: var(--warn);
}

/* ---------- signal state and mode transitions ---------- */

.trend-dot {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%; flex: none;
  background: color-mix(in srgb, var(--ink) 13%, transparent); border: 1px solid color-mix(in srgb, var(--ink) 12%, transparent);
}
.trend-dot.is-bull { background: var(--up); border-color: color-mix(in srgb, var(--accent) 80%, transparent); }
.trend-dot.is-bear { background: var(--down); border-color: color-mix(in srgb, var(--down) 85%, transparent); }
.trend-dot.is-neutral { background: color-mix(in srgb, var(--ink) 18%, transparent); }
.screener { transition: opacity .24s var(--ease), filter .24s var(--ease); }
.screener.is-quote-loading { opacity: .45; filter: saturate(.55); pointer-events: none; }
.vote.none { color: var(--text-faint); }

/* ---------- Portfolio and Posts ---------- */

.community-head { align-items: center; }
.community-head .eyebrow { display: block; }
.admin-toggle { flex: none; }
.primary-chip {
  color: var(--accent); border-color: color-mix(in srgb, var(--accent) 32%, transparent); background: color-mix(in srgb, var(--accent) 9%, transparent);
}
.primary-chip:hover { color: color-mix(in srgb, var(--accent) 80%, var(--text)); border-color: color-mix(in srgb, var(--accent) 50%, transparent); background: color-mix(in srgb, var(--accent) 13%, transparent); }
.primary-chip:disabled { opacity: .55; cursor: wait; }

.portfolio-summary {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; margin-bottom: 18px;
}
.portfolio-stat { display: flex; min-height: 115px; flex-direction: column; justify-content: center; }
.portfolio-stat > span { color: var(--text-faint); font-size: 12px; }
.portfolio-stat > b { margin-top: 5px; font-size: 20px; font-weight: 500; letter-spacing: -.02em; }
.portfolio-stat > small { margin-top: 2px; color: var(--text-xfaint); font-size: 11.5px; }
.summary-bias.up { color: var(--up); }
.summary-bias.down { color: var(--down); }
.summary-bias.flat { color: var(--text-dim); }

.admin-studio {
  margin-bottom: 18px; padding: 20px; border-radius: 18px;
  border: 1px solid color-mix(in srgb, var(--accent) 16%, transparent);
  background: linear-gradient(145deg, color-mix(in srgb, var(--accent) 4.5%, transparent), color-mix(in srgb, var(--ink) 1.2%, transparent) 46%);
}
.admin-studio.is-hidden { display: none; }
.studio-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 20px; margin-bottom: 18px; }
.studio-head .eyebrow { display: block; }
.studio-head h2 { margin: 0; font-size: 17px; font-weight: 500; }
.studio-close { font-size: 19px; line-height: 1; }
.editor-form { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px 12px; }
.editor-form label { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.editor-form label > span { color: var(--text-faint); font-size: 11.5px; }
.editor-form input, .editor-form select, .editor-form textarea {
  width: 100%; min-width: 0; border: 1px solid var(--border); border-radius: 11px; outline: none;
  color: var(--text); background: var(--scrim); font: inherit; font-size: 13px;
  transition: border-color .2s var(--ease), background .2s var(--ease);
}
.editor-form input, .editor-form select { height: 39px; padding: 0 11px; }
.editor-form textarea { resize: vertical; min-height: 94px; padding: 10px 11px; line-height: 1.55; }
.editor-form input:focus, .editor-form select:focus, .editor-form textarea:focus { border-color: color-mix(in srgb, var(--accent) 35%, transparent); background: color-mix(in srgb, var(--ink) 2.5%, transparent); }
.editor-form input::placeholder, .editor-form textarea::placeholder { color: var(--text-xfaint); }
.editor-form select { appearance: none; background-image: linear-gradient(45deg, transparent 50%, var(--text-faint) 50%), linear-gradient(135deg, var(--text-faint) 50%, transparent 50%); background-position: calc(100% - 15px) 16px, calc(100% - 11px) 16px; background-size: 4px 4px; background-repeat: no-repeat; }
.form-wide { grid-column: 1 / -1; }
.form-actions { display: flex; gap: 8px; }
.form-actions .is-hidden, .post-delete.is-hidden { display: none; }
.input-suffix { position: relative; }
.input-suffix input { padding-right: 30px; }
.input-suffix i { position: absolute; top: 9px; right: 11px; color: var(--text-faint); font-style: normal; font-size: 12px; }
.upload-field small { color: var(--text-xfaint); font-size: 11px; }
.upload-field input[type="file"] { height: auto; padding: 8px; color: var(--text-dim); }
.upload-field input[type="file"]::file-selector-button { margin-right: 10px; padding: 5px 10px; border: 0; border-radius: 7px; color: var(--text-dim); background: color-mix(in srgb, var(--ink) 6%, transparent); }
.form-error { min-height: 20px; margin: 0; color: var(--down); font-size: 12px; }

.portfolio-list { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.portfolio-entry { display: flex; flex-direction: column; min-height: 275px; padding: 18px; }
.portfolio-entry-head { display: flex; align-items: center; justify-content: space-between; gap: 14px; }
.portfolio-symbol { display: flex; align-items: center; gap: 12px; }
.portfolio-symbol b { display: block; font-size: 18px; font-weight: 600; letter-spacing: -.02em; }
.portfolio-symbol span:not(.trend-dot) { display: block; color: var(--text-faint); font-size: 11.5px; }
.allocation-ring {
  --allocation: 0deg; position: relative; width: 50px; height: 50px; flex: none; border-radius: 50%;
  display: grid; place-items: center; background: conic-gradient(var(--accent) var(--allocation), color-mix(in srgb, var(--ink) 5.5%, transparent) 0);
}
.allocation-ring::before { content: ''; position: absolute; inset: 4px; border-radius: 50%; background: var(--bg-panel); }
.allocation-ring span { position: relative; font-size: 10px; color: var(--text-dim); }
.portfolio-tags { display: flex; gap: 6px; margin-top: 15px; }
.portfolio-tags .bias-bullish { color: var(--up); border-color: color-mix(in srgb, var(--up) 20%, transparent); background: color-mix(in srgb, var(--up) 5.5%, transparent); }
.portfolio-tags .bias-bearish { color: var(--down); border-color: color-mix(in srgb, var(--down) 20%, transparent); background: color-mix(in srgb, var(--down) 5%, transparent); }
.portfolio-levels { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 8px; margin: 15px 0 12px; }
.portfolio-levels span { padding: 8px 9px; border-radius: 9px; color: var(--text-faint); background: color-mix(in srgb, var(--ink) 2.2%, transparent); font-size: 11px; }
.portfolio-levels b { display: block; overflow: hidden; margin-top: 2px; color: var(--text-dim); font-size: 11.5px; text-overflow: ellipsis; }
.portfolio-entry > p { flex: 1; margin: 0 0 14px; color: var(--text-dim); font-size: 12.5px; line-height: 1.6; }
.portfolio-entry-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding-top: 11px; border-top: 1px solid color-mix(in srgb, var(--ink) 4.5%, transparent); }
.portfolio-entry-foot time { color: var(--text-xfaint); font-size: 10.5px; }
.admin-actions { display: none; align-items: center; gap: 10px; }
.portfolio-list.is-admin .admin-actions { display: flex; }
.admin-actions button, .danger-link { color: var(--text-faint); font-size: 11.5px; }
.admin-actions button:hover { color: var(--text); }
.danger-link:hover { color: var(--down) !important; }

.post-editor { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.post-board { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; gap: 14px; }
.post-card { overflow: hidden; padding: 0; }
.post-image { position: relative; aspect-ratio: 16 / 8.4; overflow: hidden; background: color-mix(in srgb, var(--ink) 2.5%, transparent); }
.post-image::after { content: ''; position: absolute; inset: auto 0 0; height: 42%; background: linear-gradient(transparent, var(--veil)); pointer-events: none; }
.post-image img { display: block; width: 100%; height: 100%; object-fit: cover; transition: transform .7s var(--ease); }
.post-card:hover .post-image img { transform: scale(1.018); }
.post-image.is-placeholder { display: grid; place-items: center; color: var(--text-faint); background: radial-gradient(circle at 30% 20%, color-mix(in srgb, var(--accent) 12%, transparent), transparent 40%), var(--bg-panel); }
.post-content { padding: 18px 20px 17px; }
.post-meta { display: flex; align-items: center; justify-content: space-between; gap: 12px; color: var(--text-xfaint); font-size: 10.5px; text-transform: uppercase; letter-spacing: .07em; }
.post-meta > span { color: var(--accent); }
.post-content h2 { margin: 9px 0 7px; font-size: 18px; font-weight: 500; letter-spacing: -.015em; }
.post-content > p { margin: 0; color: var(--text-dim); font-size: 13px; line-height: 1.65; }
.post-actions { display: flex; align-items: center; justify-content: space-between; min-height: 33px; gap: 12px; margin-top: 17px; }
.post-admin-actions { display: flex; align-items: center; justify-content: flex-end; gap: 10px; flex-wrap: wrap; }
.like-btn { display: inline-flex; align-items: center; gap: 7px; padding: 5px 10px; border-radius: 10px; color: var(--text-faint); border: 1px solid var(--border); background: color-mix(in srgb, var(--ink) 1.8%, transparent); font-size: 11.5px; transition: color .2s var(--ease), border-color .2s var(--ease), transform .2s var(--ease); }
.like-btn svg { width: 14px; height: 14px; }
.like-btn b { font-size: 10.5px; font-weight: 500; }
.like-btn:hover { color: var(--text); border-color: var(--border-strong); }
.like-btn:active { transform: scale(.96); }
.like-btn.is-liked { color: color-mix(in srgb, var(--down) 85%, var(--text)); border-color: color-mix(in srgb, var(--down) 28%, transparent); background: color-mix(in srgb, var(--down) 6%, transparent); }
.like-btn.is-liked svg { fill: color-mix(in srgb, var(--down) 24%, transparent); }
.community-empty { grid-column: 1 / -1; }

.overview-lists { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.stats-list-card .list-head { min-height: 24px; }

@media (max-width: 1080px) {
  .portfolio-summary { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .portfolio-list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .editor-form { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 760px) {
  .hdr-inner { gap: 9px; padding: 0 12px; }
  .brand { gap: 0; }
  .brand-text { display: none; }
  .tabs { flex: 1 1 auto; overflow-x: auto; scrollbar-width: none; }
  .tabs::-webkit-scrollbar { display: none; }
  .tab { padding: 6px 10px; font-size: 12px; }
  .hdr-status { display: none; }
  .page { padding-left: 14px; padding-right: 14px; }
  .portfolio-summary, .portfolio-list, .post-board, .overview-lists { grid-template-columns: 1fr; }
  .editor-form, .post-editor { grid-template-columns: 1fr; }
  .form-wide { grid-column: auto; }
  .post-meta { align-items: flex-start; flex-direction: column; gap: 2px; }
  .stats-universe-control { width: 100%; margin-left: 0; justify-content: space-between; }
  .stats-custom { margin-left: 0; max-width: none; }
}

@media (max-width: 520px) {
  .controls-right { display: grid; grid-template-columns: minmax(0, 1fr); }
  .controls-right > *, .controls-right .search { width: 100%; max-width: 100%; }
  .controls-right .segmented .seg { flex: 1 1 0; padding-left: 9px; padding-right: 9px; }
  .controls-right .chip { justify-content: center; }
  .class-switch { width: 100%; max-width: 100%; }
  .class-switch .seg { flex: 1 1 0; padding-left: 8px; padding-right: 8px; }
  .hdr-right { gap: 5px; }
  .pulse { display: none; }
  .community-head { align-items: stretch; }
  .admin-toggle { justify-content: center; }
  .boot-steps { font-size: 9.5px; }

  /* Phone screener: the decision view is intentionally just ticker + side + valuation.
     Every row remains one large click target for opening its chart. */
  .table-scroll { overflow-x: hidden; }
  .screener { min-width: 0 !important; table-layout: fixed; }
  .screener .col-star, .screener .col-rank, .screener .market-cell,
  .screener .col-trend, .screener .col-action, .screener .col-spark,
  .screener .col-vote, .screener .col-stdev, .screener .col-rankcol,
  .screener .trend-cell, .screener .vote-cell, .screener .rank-cell { display: none; }
  .screener .col-asset, .screener .mobile-valuation { display: table-cell; }
  .screener .col-asset { width: 52%; padding-left: 16px; }
  .screener .mobile-valuation { width: 48%; padding-right: 16px; text-align: right; }
  .desktop-label { display: none; }
  .mobile-label { display: inline; }
  .asset { gap: 9px; }
  .asset-icon, .asset-name, .asset-sub { display: none; }
  .asset-copy { order: 1; min-width: 0; }
  .asset .trend-dot { order: 2; }
  .asset-sym { margin-left: 0; color: var(--text); font-size: 13px; font-weight: 500; }
  .mobile-valuation .verdict { padding: 4px 9px; font-size: 11.5px; }
  .mobile-valuation .verdict.is-loading { width: 86px; }
  .stats-universe-control { align-items: stretch; flex-direction: column; gap: 5px; }
  #statsUniverse { width: 100%; }
  #statsUniverse .seg { flex: 1 1 0; }
  .stats-custom-entry { min-width: 0; width: 100%; }
}

/* Wide displays: grow the workspace in steps so the full column set fits without a
   horizontal scroll, while keeping a readable ceiling on very large monitors. */
@media (min-width: 1760px) { :root { --layout-max: 1720px; } }
@media (min-width: 1920px) { :root { --layout-max: 1868px; } }
@media (min-width: 2100px) {
  :root { --layout-max: 2044px; }
  .asset-about-copy { columns: 4 320px; }
}
@media (min-width: 2400px) { :root { --layout-max: 2340px; } }
@media (min-width: 2560px) { :root { --layout-max: 2496px; } }

@media (prefers-reduced-motion: reduce) {
  .boot-ambient, .boot-bar::after, .pulse { animation: none; }
  .boot-splash, .tab-glide, .seg-glide { transition-duration: .01ms; }
}

/* ---------- asset chart workspace (interactive Lightweight Charts view) ---------- */

.asset-chart-hero { margin-bottom: 16px; }
.asset-chart-last-close {
  display: inline-block;
  margin-top: 2px;
  color: var(--text-xfaint);
  font-size: 11.5px;
  letter-spacing: .015em;
}

.asset-chart-change-strip { overflow: hidden; }
.asset-chart-change-strip [data-asset-change] { display: contents; }

.asset-chart-layout {
  display: grid;
  grid-template-columns: 282px minmax(0, 1fr);
  gap: 12px;
  align-items: start;
}

.asset-chart-stats { position: sticky; top: calc(var(--hdr-h) + 16px); }
.asset-chart-stats .stat-row { align-items: flex-start; }
.asset-chart-stats .stat-row > span { max-width: 52%; }
.asset-chart-stats .stat-row b { max-width: 56%; text-align: right; overflow-wrap: anywhere; }

.asset-chart-card {
  min-width: 0;
  padding: 0;
  overflow: hidden;
  background: var(--bg-panel);
}
.asset-chart-card:hover { background: var(--bg-panel); }

.asset-chart-toolbar {
  min-height: 58px;
  padding: 11px 13px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  border-bottom: 1px solid color-mix(in srgb, var(--ink) 5.5%, transparent);
}

/* The toolbar names the active timeframe outright - "DAILY TIMEFRAME" - so the chart is
   never ambiguous about which candles are on screen. */
.asset-chart-timeframe-control {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}
.asset-chart-control-label {
  color: var(--accent);
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
}
.asset-chart-timeframe-control > small {
  color: var(--text-xfaint);
  font-size: 10px;
  max-width: 46ch;
}
.asset-chart-ranges { flex: none; }
.asset-chart-ranges .seg {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  padding-left: 12px;
  padding-right: 12px;
}
.asset-chart-ranges .seg > b {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 10px;
  font-weight: 500;
}
.asset-chart-ranges .seg > span { font-size: 11.5px; }
.asset-chart-actions { display: flex; align-items: center; gap: 7px; }
.asset-chart-indicator-button { height: 32px; padding: 0 11px; font-size: 12px; }
.asset-chart-indicator-button b {
  display: grid;
  place-items: center;
  min-width: 18px;
  height: 18px;
  padding: 0 4px;
  border-radius: 7px;
  color: var(--text-dim);
  background: color-mix(in srgb, var(--ink) 5.5%, transparent);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 9.5px;
  font-weight: 500;
}
.asset-chart-indicator-button.is-on b { color: var(--chrome-text); background: var(--chrome-fill); }

/* These buttons carry an icon *and* a label. A fixed square with place-items:center stacked
   both into the same grid cell, so the glyph sat on top of the word. A flex row with a gap
   lets the button size to its contents; an icon-only button keeps the square look via
   :not(:has(span)) below. */
.asset-chart-reset {
  min-width: 32px;
  height: 32px;
  padding: 0 10px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  font-size: 12px;
  white-space: nowrap;
  border: 1px solid var(--border);
  border-radius: 10px;
  color: var(--text-faint);
  transition: color .18s var(--ease), border-color .18s var(--ease), background .18s var(--ease);
}
.asset-chart-reset svg { width: 15px; height: 15px; flex: none; }
.asset-chart-reset:not(:has(span)) { padding: 0; width: 32px; }
.asset-chart-reset:hover { color: var(--text); border-color: var(--border-strong); background: color-mix(in srgb, var(--ink) 2.5%, transparent); }

/* The indicator library, sliding both ways.
   It used to be `display: none` with a fade-in on top, which animates the opening and cannot
   animate the closing at all - `display` is not an animatable property, so it vanished on the
   frame it was dismissed. Height, padding and opacity carry it in and out instead, so pressing
   the button twice looks like one drawer rather than a reveal and a disappearance. */
.asset-chart-library {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  padding: 0 14px;
  max-height: 0; opacity: 0; overflow: hidden;
  border-bottom: 1px solid transparent;
  background: color-mix(in srgb, var(--ink) 1.2%, transparent);
  transition: max-height .28s var(--ease), opacity .2s var(--ease),
              padding .28s var(--ease), border-color .28s var(--ease);
}
.asset-chart-library.is-open {
  /* A ceiling rather than the real height, because the real one is only knowable at runtime.
     Generously above anything the library holds, so nothing is ever clipped. */
  max-height: 760px; opacity: 1; padding: 14px; border-bottom-color: var(--border);
}
@media (prefers-reduced-motion: reduce) { .asset-chart-library { transition: none; } }

.asset-chart-study-group {
  min-width: 0;
  padding: 7px;
  border: 1px solid color-mix(in srgb, var(--ink) 5.5%, transparent);
  border-radius: 13px;
  background: color-mix(in srgb, var(--shade) 10%, transparent);
}
.asset-chart-study-group-title {
  display: flex;
  flex-direction: row-reverse;
  align-items: center;
  justify-content: space-between;
  padding: 3px 6px 8px;
}
.asset-chart-study-group-title b { font-size: 12px; font-weight: 500; }
.asset-chart-study-group-title span { color: var(--text-xfaint); font-size: 10.5px; }

.asset-chart-study-row {
  display: flex;
  align-items: center;
  gap: 4px;
  border-radius: 10px;
  transition: background .18s var(--ease);
}
.asset-chart-study-row + .asset-chart-study-row { margin-top: 2px; }
.asset-chart-study-row:hover, .asset-chart-study-row.is-active { background: color-mix(in srgb, var(--ink) 2.5%, transparent); }
.asset-chart-study-toggle {
  min-width: 0;
  flex: 1;
  display: grid;
  grid-template-columns: 20px 7px minmax(0, 1fr);
  align-items: center;
  gap: 8px;
  padding: 8px 6px;
  text-align: left;
}
.asset-chart-study-check {
  width: 18px;
  height: 18px;
  display: grid;
  place-items: center;
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--accent);
  font-size: 10px;
}
.asset-chart-study-row.is-active .asset-chart-study-check {
  border-color: color-mix(in srgb, var(--accent) 34%, transparent);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
}
.asset-chart-study-toggle > i, .asset-chart-study-chip > i, .asset-chart-osc-head i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--study-color);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--study-color) 13%, transparent);
}
.asset-chart-study-toggle > span:last-child { min-width: 0; }
.asset-chart-study-toggle b { display: block; font-size: 12px; font-weight: 500; color: var(--text-dim); }
.asset-chart-study-row.is-active .asset-chart-study-toggle b { color: var(--text); }
.asset-chart-study-toggle small {
  display: block;
  margin-top: 1px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-xfaint);
  font-size: 10.5px;
}
.asset-chart-study-settings-btn {
  width: 29px;
  height: 29px;
  flex: none;
  border-radius: 8px;
  color: var(--text-xfaint);
  font-size: 12px;
  transition: color .18s var(--ease), background .18s var(--ease);
}
.asset-chart-study-settings-btn:hover, .asset-chart-study-settings-btn.is-active { color: var(--text-dim); background: color-mix(in srgb, var(--ink) 4.5%, transparent); }

.asset-chart-settings {
  grid-column: 1 / -1;
  padding: 14px;
  border: 1px solid color-mix(in srgb, var(--accent) 14%, transparent);
  border-radius: 13px;
  background: color-mix(in srgb, var(--accent) 2.5%, transparent);
}
.asset-chart-settings-head { display: flex; align-items: center; justify-content: space-between; gap: 18px; margin-bottom: 12px; }
.asset-chart-settings-head b { display: block; font-size: 12.5px; font-weight: 500; }
.asset-chart-settings-head span { display: block; color: var(--text-xfaint); font-size: 10.5px; }
.asset-chart-settings-head button { color: var(--accent); font-size: 11px; }
.asset-chart-settings-grid { display: grid; grid-template-columns: repeat(4, minmax(105px, 1fr)); gap: 9px; }
.asset-chart-settings-grid label { min-width: 0; }
.asset-chart-settings-grid label > span { display: block; margin: 0 0 4px 2px; color: var(--text-faint); font-size: 10.5px; }
.asset-chart-settings-grid input {
  width: 100%;
  height: 32px;
  padding: 0 9px;
  outline: none;
  border: 1px solid var(--border);
  border-radius: 9px;
  color: var(--text-dim);
  background: color-mix(in srgb, var(--shade) 16%, transparent);
  font-size: 11px;
  transition: border-color .18s var(--ease);
}
.asset-chart-settings-grid input:focus { border-color: color-mix(in srgb, var(--accent) 35%, transparent); }

.asset-chart-meta {
  min-height: 38px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 7px 13px;
  border-bottom: 1px solid color-mix(in srgb, var(--ink) 4%, transparent);
}
#assetChartStudies, #assetChartOhlc { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.asset-chart-study-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 8px;
  border-radius: 7px;
  color: var(--text-faint);
  background: color-mix(in srgb, var(--ink) 2.5%, transparent);
  font-size: 10.5px;
}
.asset-chart-study-chip span { color: var(--text-xfaint); font-size: 13px; line-height: 1; }
.asset-chart-study-chip:hover { color: var(--text-dim); background: color-mix(in srgb, var(--ink) 4.5%, transparent); }
.asset-chart-no-studies { color: var(--text-xfaint); font-size: 11px; }
#assetChartOhlc { justify-content: flex-end; color: var(--text-xfaint); font-size: 10px; }
#assetChartOhlc span { white-space: nowrap; }
#assetChartOhlc b { color: var(--text-faint); font-size: 10px; font-weight: 400; }

.asset-chart-stage { position: relative; min-height: 430px; background: var(--bg-panel); }
.asset-chart-main { position: relative; width: 100%; min-height: 430px; }
/* Chart canvases sit above the fill layer, matching Pine's draw order. */
.asset-chart-main > div, .asset-chart-osc-canvas > div { position: relative; z-index: 1; margin: 0 auto; }
/* Pine `fill()` layer. It must be taken out of flow: sized from the host's own height, an
   in-flow canvas grows the host, which resizes the canvas again - a loop that inflates the
   pane until the canvas exceeds the browser's maximum and stops painting altogether. */
.asset-chart-fill-layer {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}
.asset-chart-loading {
  position: absolute;
  z-index: 4;
  inset: 0;
  display: none;
  place-content: center;
  justify-items: center;
  gap: 9px;
  color: var(--text-faint);
  background: var(--veil);
  backdrop-filter: blur(4px);
  font-size: 11.5px;
}
.asset-chart-stage.is-busy .asset-chart-loading { display: grid; }
.asset-chart-loading i {
  width: 22px;
  height: 22px;
  border: 1px solid color-mix(in srgb, var(--ink) 10%, transparent);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: asset-chart-spin .8s linear infinite;
}
@keyframes asset-chart-spin { to { transform: rotate(360deg); } }

.asset-chart-oscillator { border-top: 1px solid var(--border); }
.asset-chart-osc-head {
  height: 33px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 13px;
  color: var(--text-faint);
  background: color-mix(in srgb, var(--ink) 1.2%, transparent);
  font-size: 10.5px;
}
.asset-chart-osc-head > span:first-child { display: inline-flex; align-items: center; gap: 8px; }
.asset-chart-osc-reading { font-size: 10px; }
.asset-chart-osc-canvas { position: relative; min-height: 164px; }

.asset-chart-empty {
  min-height: 164px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  padding: 24px;
  text-align: center;
  color: var(--text-faint);
  font-size: 12px;
}
.asset-chart-empty b { color: var(--text-dim); font-weight: 500; }
.asset-chart-static { display: block; width: 100%; height: 410px; padding: 8px 12px 0; }
.asset-chart-fallback {
  position: absolute;
  left: 14px;
  bottom: 10px;
  padding: 5px 9px;
  border: 1px solid color-mix(in srgb, var(--warn) 18%, transparent);
  border-radius: 8px;
  color: color-mix(in srgb, var(--warn) 75%, transparent);
  background: var(--veil);
  font-size: 10px;
}
.asset-chart-help {
  min-height: 34px;
  padding: 7px 13px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  border-top: 1px solid color-mix(in srgb, var(--ink) 4%, transparent);
  color: var(--text-xfaint);
  font-size: 10.5px;
}

.asset-chart-timeframes { margin-top: 12px; padding: 0 16px 8px; }
.asset-chart-section-head {
  min-height: 66px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 11px 0;
  border-bottom: 1px solid var(--border);
}
.asset-chart-section-head h2 { margin: 0; font-size: 16px; font-weight: 500; letter-spacing: -.01em; }
.asset-chart-eyebrow {
  display: block;
  margin-bottom: 1px;
  color: var(--accent);
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: .1em;
  text-transform: uppercase;
}
.asset-chart-quote-note {
  padding: 4px 9px;
  border: 1px solid color-mix(in srgb, var(--accent) 16%, transparent);
  border-radius: 7px;
  color: var(--text-faint);
  background: color-mix(in srgb, var(--accent) 3.5%, transparent);
  font-size: 10.5px;
}
.asset-chart-table-scroll { overflow-x: auto; }
.asset-chart-timeframes .tf-table { margin-top: 0; }

.asset-about-card { margin-top: 12px; padding: 28px 30px; }
.asset-about-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 18px;
  padding-bottom: 17px;
  border-bottom: 1px solid var(--border);
}
.asset-about-head h2 { margin: 0; font-size: 19px; font-weight: 500; letter-spacing: -.015em; }
.asset-about-head h2 span { color: var(--text-faint); font-weight: 400; }
.asset-about-kind {
  padding: 4px 10px;
  border-radius: 7px;
  color: var(--text-faint);
  background: color-mix(in srgb, var(--ink) 3%, transparent);
  border: 1px solid var(--border);
  font-size: 10.5px;
  text-transform: capitalize;
}
.asset-about-lead {
  /* No measure cap: the summary spans the card, and the body below balances into columns. */
  margin: 20px 0 18px;
  color: color-mix(in srgb, var(--ink) 70%, transparent);
  font-size: 15px;
  line-height: 1.72;
  text-wrap: pretty;
}
/* Column count follows the available width rather than being fixed at two inside a 1120px
   box, which left a wide empty gutter on the right of every large screen. `columns` takes a
   maximum count and an ideal width, so each column stays a readable measure at any size. */
.asset-about-copy {
  columns: 3 320px;
  column-gap: 42px;
  orphans: 2;
  widows: 2;
}
.asset-about-copy p {
  break-inside: avoid;
  margin: 0 0 15px;
  color: var(--text-dim);
  font-size: 13.5px;
  line-height: 1.78;
}
.asset-about-resources {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-top: 22px;
  padding-top: 17px;
  border-top: 1px solid var(--border);
}
.asset-about-resources > span { color: var(--text-xfaint); font-size: 10.5px; text-transform: uppercase; letter-spacing: .08em; }
.asset-about-resources > div { display: flex; gap: 7px; flex-wrap: wrap; }
.asset-about-resources a {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 5px 11px;
  border: 1px solid var(--border);
  border-radius: 10px;
  color: var(--text-dim);
  text-decoration: none;
  background: color-mix(in srgb, var(--ink) 1.8%, transparent);
  font-size: 11.5px;
  transition: color .18s var(--ease), border-color .18s var(--ease), background .18s var(--ease);
}
.asset-about-resources a:hover { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 28%, transparent); background: color-mix(in srgb, var(--accent) 4%, transparent); }
.asset-about-resources a span { color: var(--text-faint); }

.asset-chart-page-loading { min-height: 180px; display: grid; place-content: center; }

@media (max-width: 1100px) {
  .asset-chart-layout { grid-template-columns: 1fr; }
  .asset-chart-stats { position: static; display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); column-gap: 24px; }
  .asset-chart-stats .list-head { grid-column: 1 / -1; }
  .asset-chart-settings-grid { grid-template-columns: repeat(3, minmax(100px, 1fr)); }
}

@media (max-width: 760px) {
  .asset-chart-library { grid-template-columns: 1fr; }
  .asset-chart-settings { grid-column: 1; }
  .asset-chart-settings-grid { grid-template-columns: repeat(2, minmax(100px, 1fr)); }
  .asset-chart-meta { align-items: flex-start; flex-direction: column; }
  #assetChartOhlc { justify-content: flex-start; }
  .asset-chart-stats { grid-template-columns: 1fr; }
  .asset-chart-stats .list-head { grid-column: auto; }
  .asset-about-card { padding: 22px 20px; }
  .asset-about-copy { columns: 1; }
  .asset-about-resources { align-items: flex-start; flex-direction: column; gap: 9px; }
}

@media (max-width: 520px) {
  .asset-chart-toolbar { align-items: stretch; }
  .asset-chart-ranges { width: 100%; overflow-x: auto; }
  .asset-chart-actions { justify-content: flex-end; }
  .asset-chart-settings-grid { grid-template-columns: 1fr; }
  .asset-chart-settings-head { align-items: flex-start; flex-direction: column; gap: 7px; }
  .asset-chart-help { align-items: flex-start; flex-direction: column; gap: 2px; }
  .asset-chart-section-head { align-items: flex-start; flex-direction: column; gap: 6px; }
}

/* ---------- portfolio (per-user) ---------- */

.pf-head-right { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
#portfolioSignOut { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.pf-auth { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 380px); gap: 32px; padding: 26px 28px; }
.pf-auth-copy h2 { margin: 8px 0 10px; font-size: 20px; font-weight: 500; }
.pf-auth-copy p { margin: 0; color: var(--text-dim); font-size: 13.5px; line-height: 1.7; max-width: 46ch; }
.pf-auth-form { display: grid; gap: 12px; align-content: start; }
.pf-auth-form label, .pf-form label { display: grid; gap: 5px; min-width: 0; }
.pf-auth-form span, .pf-form span, .pf-modal label span { color: var(--text-faint); font-size: 11.5px; }
.pf-auth-form input, .pf-form input, .pf-form select, .pf-modal input, .pf-alerts input[type="email"] {
  height: 38px; padding: 0 11px; min-width: 0;
  color: var(--text); background: var(--surface); font-size: 13px;
  border: 1px solid var(--border); border-radius: 10px; outline: none;
  transition: border-color .2s var(--ease);
}
.pf-auth-form input:focus, .pf-form input:focus, .pf-form select:focus,
.pf-modal input:focus, .pf-alerts input:focus { border-color: color-mix(in srgb, var(--accent) 45%, transparent); }
.pf-auth-actions { display: flex; gap: 8px; margin-top: 2px; }
.pf-auth-form small, .pf-field-help { color: var(--text-xfaint); font-size: 11px; }

/* ---------- identity provider sign-in ---------- */

.auth-providers { display: grid; gap: 14px; align-content: start; margin-bottom: 2px; }
/* Sign in with Google. This is the button most people actually press, so it is given a lift
   and a light sweep on hover rather than sitting flat under the email fields. */
.auth-google {
  position: relative; overflow: hidden;
  display: flex; align-items: center; justify-content: center; gap: 11px;
  width: 100%; padding: 13px 16px;
  border: 1px solid color-mix(in srgb, var(--ink) 16%, transparent); border-radius: 13px;
  background: linear-gradient(180deg, color-mix(in srgb, var(--ink) 8.5%, transparent), color-mix(in srgb, var(--ink) 3.5%, transparent));
  color: var(--text); font-size: 14px; font-weight: 500;
  box-shadow: 0 4px 12px color-mix(in srgb, var(--shade) 20%, transparent);
  transition: transform .18s var(--ease), border-color .18s var(--ease),
              box-shadow .22s var(--ease), background .18s var(--ease);
}
.auth-google::after {
  content: ""; position: absolute; inset: 0 auto 0 -60%; width: 45%;
  background: linear-gradient(100deg, transparent, color-mix(in srgb, var(--ink) 16%, transparent), transparent);
  transform: skewX(-18deg); transition: left .55s var(--ease); pointer-events: none;
}
.auth-google:hover {
  transform: translateY(-1px);
  border-color: color-mix(in srgb, var(--ink) 28%, transparent);
  background: linear-gradient(180deg, color-mix(in srgb, var(--ink) 11%, transparent), color-mix(in srgb, var(--ink) 5%, transparent));
  box-shadow: 0 8px 20px color-mix(in srgb, var(--shade) 26%, transparent);
}
.auth-google:hover::after { left: 115%; }
.auth-google:active { transform: translateY(0); }
.auth-google:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.auth-google svg { width: 18px; height: 18px; flex: none; }
@media (prefers-reduced-motion: reduce) {
  .auth-google, .auth-google::after { transition: none; }
  .auth-google:hover { transform: none; }
}

/* Rules either side of the label, drawn with the row's own background rather than a mask so
   it stays correct on the card's translucent surface. */
.auth-divider { display: flex; align-items: center; gap: 12px; color: var(--text-xfaint); font-size: 11px; }
.auth-divider::before, .auth-divider::after {
  content: ''; flex: 1; height: 1px; background: var(--border);
}

.auth-link {
  color: var(--accent); font-size: 11px; text-decoration: underline;
  text-underline-offset: 2px; padding: 0;
}
.auth-link:hover { color: var(--text); }

.pf-form, .pf-connections, .pf-orders { padding: 18px 20px; margin-bottom: 14px; }
.pf-form-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 14px; }
.pf-form-head h2 { margin: 0; font-size: 15px; font-weight: 500; }
.pf-head-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.pf-form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 12px; }
.pf-form-wide { grid-column: 1 / -1; }
.pf-form-actions { display: flex; gap: 8px; margin-top: 14px; }

.pf-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 12px; margin-bottom: 14px; }
.pf-split { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); gap: 12px; margin-bottom: 14px; }
.pf-bias, .pf-alloc { padding: 16px 18px; }
.pf-bias-bar { display: flex; height: 10px; border-radius: 999px; overflow: hidden; background: color-mix(in srgb, var(--ink) 5%, transparent); margin: 12px 0 10px; }
.pf-bias-bar span { transition: width .4s var(--ease); }
.pf-bias-bar .is-bull, .pf-bias-legend i.is-bull { background: var(--up); }
.pf-bias-bar .is-bear, .pf-bias-legend i.is-bear { background: var(--down); }
.pf-bias-bar .is-neutral, .pf-bias-legend i.is-neutral { background: color-mix(in srgb, var(--ink) 22%, transparent); }
.pf-bias-legend { display: flex; gap: 16px; flex-wrap: wrap; color: var(--text-dim); font-size: 12px; }
.pf-bias-legend span { display: inline-flex; align-items: center; gap: 6px; }
.pf-bias-legend i { width: 8px; height: 8px; border-radius: 50%; }
.pf-alloc-row { display: grid; grid-template-columns: 92px minmax(0, 1fr) 48px; align-items: center; gap: 10px; padding: 5px 0; font-size: 12.5px; text-transform: capitalize; }
.pf-alloc-track { height: 6px; border-radius: 999px; background: color-mix(in srgb, var(--ink) 6%, transparent); overflow: hidden; }
.pf-alloc-track span { display: block; height: 100%; border-radius: 999px; background: var(--accent); }
.pf-alloc-row b { text-align: right; font-size: 12px; color: var(--text-dim); }

.pf-table-card { padding: 16px 18px; margin-bottom: 14px; }
.pf-table-scroll { overflow-x: auto; }
.pf-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.pf-table th { padding: 8px 10px; color: var(--text-faint); font-size: 11px; font-weight: 500; text-align: left; white-space: nowrap; }
.pf-table td { padding: 10px; border-top: 1px solid color-mix(in srgb, var(--ink) 5%, transparent); vertical-align: middle; }
.pf-table td.num, .pf-table th.num { text-align: right; }
.pf-table tr.is-close td { background: color-mix(in srgb, var(--accent) 5%, transparent); }
.pf-sub { display: block; color: var(--text-xfaint); font-size: 11px; text-transform: capitalize; }
.pf-side { padding: 3px 9px; border-radius: 7px; font-size: 11px; text-transform: capitalize; }
.pf-side.is-long { color: var(--up); background: color-mix(in srgb, var(--accent) 10%, transparent); }
.pf-side.is-short { color: var(--down); background: color-mix(in srgb, var(--down) 10%, transparent); }
.pf-row-actions { display: flex; gap: 10px; justify-content: flex-end; }
.pf-link { color: var(--text-faint); font-size: 12px; transition: color .2s var(--ease); }
.pf-link:hover { color: var(--text); }
.pf-link.danger-link:hover { color: var(--down); }

.pf-connection { display: flex; align-items: center; justify-content: space-between; gap: 14px; padding: 11px 0; border-top: 1px solid color-mix(in srgb, var(--ink) 5%, transparent); flex-wrap: wrap; }
.pf-connection-main { display: flex; align-items: center; gap: 11px; min-width: 0; }
.pf-connection-side { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.pf-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--text-xfaint); }
.pf-dot.is-ok { background: var(--up); }
.pf-dot.is-error { background: var(--down); }
.pf-error-note { color: var(--down); font-size: 11.5px; max-width: 42ch; }
.pf-empty-inline { padding: 14px 0; color: var(--text-faint); font-size: 12.5px; }
.pf-warn, .pf-warn-inline { color: var(--warn); font-size: 12px; }
.pf-warn { margin: 0 0 10px; }
.pf-permission { margin: 0 0 12px; color: var(--text-dim); font-size: 12.5px; line-height: 1.6; }
.pf-doc-link { color: var(--accent); font-size: 12px; text-decoration: none; }

.pf-notice { padding: 11px 14px; margin-bottom: 12px; border-radius: 12px; font-size: 12.5px; border: 1px solid var(--border); }
.pf-notice.is-error { color: var(--down); background: color-mix(in srgb, var(--down) 7%, transparent); border-color: color-mix(in srgb, var(--down) 22%, transparent); }
.pf-notice.is-warn { color: var(--warn); background: color-mix(in srgb, var(--warn) 7%, transparent); border-color: color-mix(in srgb, var(--warn) 22%, transparent); }
.pf-notice.is-ok { color: var(--up); background: color-mix(in srgb, var(--accent) 7%, transparent); border-color: color-mix(in srgb, var(--accent) 22%, transparent); }

.pf-modal-backdrop { position: fixed; inset: 0; z-index: var(--z-modal); display: grid; place-items: center; padding: 24px; background: var(--scrim); backdrop-filter: blur(6px); }
.pf-modal { width: min(520px, 100%); max-height: 84vh; overflow-y: auto; padding: 20px 22px; background: var(--bg-lift); }
.pf-modal.is-wide { width: min(760px, 100%); }
.pf-modal form { display: grid; gap: 12px; }
.pf-venue-search { width: 100%; height: 38px; padding: 0 12px; margin-bottom: 14px; color: var(--text); background: var(--surface); border: 1px solid var(--border); border-radius: 10px; outline: none; font-size: 13px; }
.pf-venue-scroll { max-height: 52vh; overflow-y: auto; }
.pf-venue-group h3 { margin: 4px 0 8px; color: var(--text-faint); font-size: 11px; font-weight: 500; letter-spacing: .12em; text-transform: uppercase; }
.pf-venue-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 8px; margin-bottom: 16px; }
.pf-venue { display: grid; gap: 2px; padding: 11px 12px; text-align: left; border: 1px solid var(--border); border-radius: 12px; background: var(--surface-soft); transition: border-color .2s var(--ease), background .2s var(--ease); }
.pf-venue b { font-size: 13px; font-weight: 500; }
.pf-venue span { color: var(--text-xfaint); font-size: 10.5px; }
.pf-venue:hover:not(.is-soon) { border-color: color-mix(in srgb, var(--accent) 35%, transparent); background: color-mix(in srgb, var(--accent) 6%, transparent); }
.pf-venue.is-soon { opacity: .4; cursor: not-allowed; }

.pf-alerts { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 14px; padding-top: 14px; border-top: 1px solid color-mix(in srgb, var(--ink) 5%, transparent); }
.pf-alert-toggle { display: inline-flex; align-items: center; gap: 8px; color: var(--text-dim); font-size: 12.5px; }
.pf-alerts input[type="email"] { flex: 1 1 200px; }

@media (max-width: 900px) {
  .pf-auth { grid-template-columns: 1fr; gap: 20px; }
  .pf-split { grid-template-columns: 1fr; }
}
@media (max-width: 520px) {
  .pf-head-right { width: 100%; }
  #portfolioMode { flex: 1 1 auto; }
  #portfolioMode .seg { flex: 1 1 0; }
  .pf-form-grid { grid-template-columns: 1fr 1fr; }
  .pf-alerts { flex-direction: column; align-items: stretch; }
}

.asset-chart-reset.is-on { color: var(--chrome-text); background: var(--chrome-fill); border-color: var(--chrome-edge); }

/* ---------- watchlist ---------- */

.wl-switcher { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 16px; }
.wl-delete { margin-left: auto; }
.wl-table tbody tr[data-symbol] { cursor: pointer; }
.wl-asset b { font-size: 13px; }
.wl-section td {
  padding: 12px 10px 6px; color: var(--text-faint); font-size: 10.5px;
  font-weight: 500; letter-spacing: .16em; text-transform: uppercase; border-top: none;
}
.wl-columns { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 18px; }
.wl-column-group h3 {
  margin: 0 0 8px; color: var(--text-faint); font-size: 10.5px; font-weight: 500;
  letter-spacing: .14em; text-transform: uppercase;
}
.wl-column-option { display: flex; align-items: center; gap: 8px; padding: 4px 0; font-size: 12.5px; color: var(--text-dim); cursor: pointer; }
.wl-column-option:hover { color: var(--text); }

/* ---------- signed-out shell ---------- */

/* The application markup stays in the document but is inert until a session exists, so the
   view modules can keep querying their own nodes without null checks. */
body.is-signed-out .tabs,
body.is-signed-out .page,
body.is-signed-out #statusDot,
body.is-signed-out #statusText,
body.is-signed-out #refreshBtn { display: none; }

.hdr-auth { display: flex; align-items: center; gap: 8px; }

.hdr-signin, .hdr-signup {
  padding: 7px 15px; border-radius: 10px; font-size: 13px; font-weight: 500;
  transition: background .18s var(--ease), border-color .18s var(--ease), color .18s var(--ease);
}
.hdr-signin { color: var(--text-dim); border: 1px solid transparent; }
.hdr-signin:hover { color: var(--text); background: var(--surface-hover); }
.hdr-signup { background: var(--accent); color: var(--on-accent); font-weight: 600; }
.hdr-signup:hover { filter: brightness(1.08); }

.hdr-account { position: relative; }
.hdr-account-btn {
  display: flex; align-items: center; gap: 9px;
  padding: 5px 12px 5px 5px; border-radius: 10px;
  border: 1px solid var(--border); background: var(--surface);
  color: var(--text-dim); font-size: 12.5px;
}
.hdr-account-btn:hover { background: var(--surface-hover); color: var(--text); }
.hdr-avatar {
  width: 26px; height: 26px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  background: var(--accent); color: var(--on-accent); font-size: 12px; font-weight: 600;
}
.hdr-account-mail { max-width: 168px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hdr-account-caret {
  width: 12px; height: 12px; flex: none; opacity: .5;
  transition: transform .18s var(--ease), opacity .18s var(--ease);
}
.hdr-account-btn:hover .hdr-account-caret { opacity: .9; }
.hdr-account-btn[aria-expanded="true"] .hdr-account-caret { transform: rotate(180deg); opacity: .9; }
@media (prefers-reduced-motion: reduce) { .hdr-account-caret { transition: none; } }

.hdr-menu {
  position: absolute; right: 0; top: calc(100% + 8px); z-index: 40;
  min-width: 286px; padding: 8px;
  display: grid; gap: 0;
  border: 1px solid var(--border-strong); border-radius: 16px;
  background: var(--bg-lift);
  box-shadow: 0 24px 56px color-mix(in srgb, var(--shade) 46%, transparent),
              0 2px 6px color-mix(in srgb, var(--shade) 30%, transparent);
}
/* A class-level `display` beats the `hidden` attribute's UA rule, so hiding has to be stated
   explicitly or the menu can never be dismissed.
   `display: none` cannot be transitioned, so the open state is animated on top of it with
   `@starting-style` where the browser has it and simply appears where it does not - the menu
   still works either way, it just arrives instead of sliding. Every other surface in this app
   eases; this one snapped, which is what made it read as a glitch rather than a menu. */
.hdr-menu[hidden] { display: none; }
.hdr-menu {
  transform-origin: top right;
  animation: hdr-menu-in .18s var(--ease);
}
@keyframes hdr-menu-in {
  from { opacity: 0; transform: translateY(-8px) scale(.96); }
}
/* The bridge.
   There is an 8px gap between the avatar and the panel, and a pointer crossing it leaves both
   - which would close a hover menu on the way to using it. This pseudo-element spans the gap
   so the journey never leaves `.hdr-account`. Invisible, and only present while the menu is. */
.hdr-menu::before {
  content: ""; position: absolute; left: 0; right: 0; top: -10px; height: 10px;
}
.hdr-menu button {
  transition: background .14s var(--ease), color .14s var(--ease);
}
@media (prefers-reduced-motion: reduce) {
  .hdr-menu { animation: none; }
  .hdr-menu button { transition: none; }
}
/* The identity card at the top of the menu.
   Its own inset surface rather than two lines of text, so the panel reads as "this is who you
   are, here is what you can do" instead of as a list with a caption. */
.hdr-menu-id {
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 11px; align-items: center;
  padding: 11px 11px 12px; margin-bottom: 6px;
  border-radius: 12px;
  background: var(--surface-soft);
  border: 1px solid var(--border);
}
.hdr-menu-face {
  width: 38px; height: 38px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  background: var(--accent); color: var(--on-accent); font-size: 15px; font-weight: 600;
}
.hdr-menu-face.has-picture { padding: 0; overflow: hidden; }
.hdr-menu-face img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }
.hdr-menu-who { display: grid; gap: 3px; min-width: 0; }
.hdr-menu-who b {
  color: var(--text); font-size: 13.5px; font-weight: 500; letter-spacing: -.01em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* The masked address, and the control that unmasks it. Deliberately quiet - it is a thing you
   go looking for, not a thing that catches your eye during a screen share. */
.hdr-menu-mail {
  display: flex; align-items: center; gap: 6px; min-width: 0;
  padding: 0; border: 0; background: none; cursor: pointer;
  color: var(--text-faint); font-size: 11px; font-family: var(--mono, ui-monospace, monospace);
  letter-spacing: -.01em; text-align: left;
}
.hdr-menu-mail span {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.hdr-menu-mail svg { width: 13px; height: 13px; flex: none; opacity: .6; }
.hdr-menu-mail:hover { color: var(--text-dim); }
.hdr-menu-mail:hover svg { opacity: 1; }
.hdr-menu-mail.is-shown { color: var(--text-dim); }

.hdr-menu-items { display: grid; gap: 2px; }
/* The rule above Sign out. A margin and a line, rather than a gap, because the separation is
   the point: it is the only item here that ends the session. */
.hdr-menu-items.is-last {
  margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--border);
}
.hdr-menu button {
  text-align: left; padding: 9px 10px; border-radius: 9px;
  color: var(--text-dim); font-size: 13px;
}
.hdr-menu-items button svg { width: 16px; height: 16px; flex: none; opacity: .75; }
.hdr-menu button:hover { background: var(--surface-hover); color: var(--text); }
.hdr-menu-items button:hover svg { opacity: 1; }
/* Sign out warms towards the down colour on hover only. At rest it is another row; under the
   pointer it says what it is about to do. */
.hdr-menu-out:hover {
  background: color-mix(in srgb, var(--down) 12%, transparent) !important;
  color: color-mix(in srgb, var(--down) 80%, var(--text)) !important;
}

/* TEMPORARY: the access-code control under the door. Quiet on purpose - it is scaffolding for
   testing, not a feature, and it goes when the site opens. */
.pv-door-admin { margin-top: 14px; display: grid; gap: 8px; justify-items: center; }
.pv-door-admin-open {
  background: none; border: 0; padding: 4px 6px;
  color: var(--text-xfaint, rgba(255,255,255,.3)); font-size: 11.5px; cursor: pointer;
  text-decoration: underline; text-underline-offset: 3px;
}
.pv-door-admin-open:hover { color: var(--text-faint, rgba(255,255,255,.5)); }
.pv-door-admin-form { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; align-items: center; }
.pv-door-admin-form input {
  width: 150px; padding: 9px 12px; border-radius: 999px; text-align: center;
  border: 1px solid var(--border-strong); background: rgba(0,0,0,.3);
  color: var(--text); font-size: 13px; letter-spacing: .12em;
}
.pv-door-admin-form input:focus { outline: none; border-color: var(--text-faint); }
.pv-door-ghost.sm { padding: 9px 16px; font-size: 12.5px; }
.pv-door-admin-note {
  flex-basis: 100%; text-align: center; font-size: 11.5px;
  color: var(--text-faint, rgba(255,255,255,.5)); min-height: 1em;
}

/* A door that is not open yet.
   Not `disabled` and not greyed: a greyed button reads as broken, and there is nothing broken
   here - the site is simply not accepting sign-ins. Full weight, no pointer, and a sentence
   when pressed. */
[data-gate-open].is-shut { cursor: default; opacity: .78; }
[data-gate-open].is-shut:hover { filter: none; transform: none; }

.gate-shut-note {
  position: fixed; z-index: var(--z-modal, 90); transform: translate(-50%, -4px);
  padding: 8px 13px; border-radius: 10px; max-width: 280px;
  border: 1px solid var(--border-strong); background: var(--bg-lift); color: var(--text);
  font-size: 12.5px; line-height: 1.5; text-align: center;
  box-shadow: 0 14px 34px color-mix(in srgb, var(--shade) 42%, transparent);
  opacity: 0; pointer-events: none;
  transition: opacity .18s var(--ease), transform .18s var(--ease);
}
.gate-shut-note.is-on { opacity: 1; transform: translate(-50%, 0); }
@media (prefers-reduced-motion: reduce) { .gate-shut-note { transition: none; } }

/* ---------- landing shell, and the controls the subscribe page borrows ----------

   The signed-out preview itself lives at the foot of this file, under its own palette.
   What remains here is the container it is painted into, plus the three controls the
   paywall card still uses: it is the one screen that is neither the marketing preview
   nor the application, and it reads best in the account's own accent. */

.landing { position: relative; z-index: 1; }
.landing[hidden] { display: none; }

.landing-pill {
  display: inline-block; padding: 6px 14px; border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--accent) 28%, transparent);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  color: var(--accent); font-size: 12px; letter-spacing: .04em;
}
.landing-primary, .landing-secondary {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 13px 24px; border-radius: 12px; font-size: 14.5px; font-weight: 600;
  transition: background .2s var(--ease), border-color .2s var(--ease),
              color .2s var(--ease), transform .2s var(--ease);
}
.landing-primary { background: var(--accent); color: var(--on-accent); }
.landing-primary:hover { filter: brightness(1.08); transform: translateY(-2px); }
.landing-secondary { border: 1px solid var(--border-strong); color: var(--text); }
.landing-secondary:hover { background: var(--surface-hover); transform: translateY(-2px); }
.landing-fine { margin: 14px 0 0; color: var(--text-faint); font-size: 12px; }

@media (prefers-reduced-motion: reduce) {
  .landing-primary:hover, .landing-secondary:hover { transform: none; }
}

/* ---------- sign-in dialog ----------

   The dialog is the hinge between the marketing preview and the application, and it is
   painted in the preview's ink rather than the account's accent: the person looking at it
   does not have an account's appearance yet, and a saturated blue slab is the single thing
   that made this screen look like a form bolted onto a product rather than part of one.

   Corners are rounded, not round. Nothing here is a pill. */

.gate-backdrop {
  position: fixed; inset: 0; z-index: var(--z-modal);
  display: grid; place-items: center; padding: 22px;
  background: color-mix(in srgb, #05070b 78%, transparent);
  -webkit-backdrop-filter: saturate(140%) blur(14px);
  backdrop-filter: saturate(140%) blur(14px);
  animation: gate-veil-in .32s var(--ease) both;
}
.gate-backdrop[hidden] { display: none; }
@keyframes gate-veil-in { from { opacity: 0; } }

/* The dialog itself keeps the preview palette whichever theme the browser last stored,
   so the sign-in card is the same object for everybody who sees it. */
.gate-modal {
  --gk-ink: #ffffff;
  --gk-bg: #08080a;
  --gk-lift: #101013;
  --gk-border: color-mix(in srgb, var(--gk-ink) 10%, transparent);
  --gk-border-strong: color-mix(in srgb, var(--gk-ink) 18%, transparent);
  --gk-text: color-mix(in srgb, var(--gk-ink) 95%, transparent);
  --gk-dim: color-mix(in srgb, var(--gk-ink) 70%, transparent);
  --gk-faint: color-mix(in srgb, var(--gk-ink) 52%, transparent);

  position: relative; width: min(432px, 100%);
  max-height: calc(100dvh - 44px); overflow-y: auto;
  padding: 34px 32px 30px;
  border: 1px solid var(--gk-border-strong);
  border-radius: 20px;
  background:
    radial-gradient(120% 90% at 50% -10%, color-mix(in srgb, var(--gk-ink) 6%, transparent), transparent 62%),
    var(--gk-lift);
  color: var(--gk-text);
  box-shadow: 0 40px 100px rgba(0, 0, 0, .62), inset 0 1px 0 color-mix(in srgb, var(--gk-ink) 7%, transparent);
  animation: gate-card-in .42s cubic-bezier(.16, .84, .28, 1) both;
}
@keyframes gate-card-in {
  from { opacity: 0; transform: translateY(16px) scale(.975); }
}

.gate-modal h2 {
  margin: 0 0 8px; font-size: 25px; font-weight: 640; letter-spacing: -.028em;
  color: var(--gk-text);
}
.gate-sub { margin: 0 0 24px; color: var(--gk-dim); font-size: 14px; line-height: 1.6; }
.gate-close {
  position: absolute; top: 16px; right: 16px;
  width: 32px; height: 32px; border-radius: 9px;
  border: 1px solid transparent;
  color: var(--gk-faint); font-size: 20px; line-height: 1;
  transition: background .18s var(--ease), color .18s var(--ease), border-color .18s var(--ease);
}
.gate-close:hover {
  background: color-mix(in srgb, var(--gk-ink) 7%, transparent);
  border-color: var(--gk-border); color: var(--gk-text);
}

.gate-form { display: grid; gap: 15px; margin-top: 4px; }
.gate-form label { display: grid; gap: 7px; }
.gate-form span {
  color: var(--gk-faint); font-size: 11px; letter-spacing: .13em; text-transform: uppercase;
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}
.gate-form input {
  padding: 13px 14px; border-radius: 11px;
  border: 1px solid var(--gk-border);
  background: color-mix(in srgb, var(--gk-ink) 3.5%, transparent);
  color: var(--gk-text); font-size: 14.5px;
  transition: border-color .2s var(--ease), background .2s var(--ease);
}
.gate-form input::placeholder { color: color-mix(in srgb, var(--gk-ink) 34%, transparent); }
.gate-form input:focus {
  outline: none;
  border-color: color-mix(in srgb, var(--gk-ink) 34%, transparent);
  background: color-mix(in srgb, var(--gk-ink) 6%, transparent);
}

/* Rectangular with smoothed corners, and ink rather than a hue: the primary action on this
   card is the brightest thing on it because it is white, not because it is coloured. */
.gate-submit {
  margin-top: 6px; padding: 15px 20px; border-radius: 11px;
  background: var(--gk-ink); color: var(--gk-bg);
  font-size: 14.5px; font-weight: 640; letter-spacing: -.01em;
  transition: background .2s var(--ease), opacity .2s var(--ease);
}
.gate-submit:hover:not(:disabled) { background: color-mix(in srgb, var(--gk-ink) 86%, var(--gk-bg)); }
.gate-submit:disabled { opacity: .5; cursor: default; }

.gate-switch {
  margin-top: 20px; padding-top: 18px; border-top: 1px solid var(--gk-border);
  text-align: center; color: var(--gk-faint); font-size: 13px;
  display: flex; gap: 8px; justify-content: center; flex-wrap: wrap;
}
.gate-switch button {
  color: var(--gk-text); font-size: 13px; font-weight: 550;
  text-decoration: underline; text-decoration-color: color-mix(in srgb, var(--gk-ink) 32%, transparent);
  text-underline-offset: 3px;
  transition: text-decoration-color .2s var(--ease);
}
.gate-switch button:hover { text-decoration-color: var(--gk-ink); }
.gate-reset { flex-basis: 100%; color: var(--gk-faint) !important; font-weight: 400 !important; }

.gate-notice {
  margin-bottom: 18px; padding: 12px 14px; border-radius: 11px;
  font-size: 13px; line-height: 1.6; border: 1px solid var(--gk-border);
  color: var(--gk-dim);
  animation: gate-notice-in .28s var(--ease) both;
}
@keyframes gate-notice-in { from { opacity: 0; transform: translateY(-4px); } }
.gate-notice.is-error {
  color: #e2a3ad; border-color: color-mix(in srgb, #a8757f 42%, transparent);
  background: color-mix(in srgb, #a8757f 12%, transparent);
}
.gate-notice.is-ok {
  color: #a9cbb8; border-color: color-mix(in srgb, #7d9e8b 42%, transparent);
  background: color-mix(in srgb, #7d9e8b 12%, transparent);
}
.gate-notice.is-warn {
  color: var(--gk-text); background: color-mix(in srgb, var(--gk-ink) 7%, transparent);
}

/* The provider panel, inside the dialog. It is removed entirely rather than disabled when
   the server has no identity provider configured, so nothing on this card is a door that
   cannot open. */
.gate-modal .auth-providers { gap: 16px; margin-bottom: 22px; }
.gate-modal .auth-google {
  border-radius: 11px; border-color: var(--gk-border-strong);
  background: color-mix(in srgb, var(--gk-ink) 6%, transparent);
  color: var(--gk-text); box-shadow: none; padding: 14px 16px; font-size: 14.5px;
  font-weight: 550;
}
.gate-modal .auth-google:hover {
  background: color-mix(in srgb, var(--gk-ink) 10%, transparent);
  border-color: color-mix(in srgb, var(--gk-ink) 30%, transparent);
  box-shadow: none;
}
.gate-modal .auth-divider { color: var(--gk-faint); font-size: 11px; letter-spacing: .1em; text-transform: uppercase; }
.gate-modal .auth-divider::before, .gate-modal .auth-divider::after { background: var(--gk-border); }
.gate-modal .auth-escape { color: var(--gk-faint); }
.gate-modal .auth-escape:hover { color: var(--gk-text); }

@media (prefers-reduced-motion: reduce) {
  .gate-backdrop, .gate-modal, .gate-notice { animation: none; }
}

/* ---------- posts: uniform cards, expandable notes ---------- */

/* Cards stretch to the tallest in the row so the board reads as a grid rather than a collage.
   The excerpt is clamped and the actions pinned to the bottom, so every card ends level. */
/* stretch alone only equalises within a row, so the last card in an odd-numbered board stays
   short. Sizing every implicit row to 1fr makes the whole board uniform. */
.post-board { align-items: stretch; grid-auto-rows: 1fr; }
.post-card { display: flex; flex-direction: column; }
.post-content { display: flex; flex-direction: column; flex: 1; }
.post-excerpt {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 4; line-clamp: 4;
  overflow: hidden;
}
.post-actions { margin-top: auto; }
.post-card { cursor: pointer; transition: border-color .2s var(--ease); }
.post-card:hover { border-color: var(--border-strong); }

.post-more {
  align-self: flex-start; margin-top: 9px;
  color: var(--accent); font-size: 12px;
  text-decoration: underline; text-underline-offset: 2px;
}
.post-more:hover { color: var(--text); }
.post-more[hidden] { display: none; }

body.is-modal-open { overflow: hidden; }

.post-modal-backdrop {
  position: fixed; inset: 0; z-index: var(--z-modal);
  display: grid; place-items: center; padding: 24px;
  background: var(--scrim); backdrop-filter: blur(6px);
}
.post-modal-backdrop[hidden] { display: none; }
.post-modal {
  position: relative; width: min(760px, 100%);
  max-height: calc(100vh - 48px); overflow-y: auto;
  border: 1px solid var(--border-strong); border-radius: 20px;
  background: var(--bg-lift); box-shadow: 0 16px 40px color-mix(in srgb, var(--shade) 34%, transparent);
}
.post-modal-close {
  position: absolute; top: 14px; right: 16px; z-index: 2;
  width: 34px; height: 34px; border-radius: 10px;
  background: var(--veil); color: var(--text-dim); font-size: 23px; line-height: 1;
}
.post-modal-close:hover { color: var(--text); background: var(--veil); }
.post-modal-image { aspect-ratio: 16 / 7.4; overflow: hidden; border-radius: 20px 20px 0 0; }
.post-modal-image img { width: 100%; height: 100%; object-fit: cover; display: block; }
.post-modal-meta {
  display: flex; justify-content: space-between; gap: 12px;
  padding: 24px 30px 0; color: var(--text-xfaint);
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .07em;
}
.post-modal-meta > span { color: var(--accent); }
.post-modal h2 { margin: 10px 0 16px; padding: 0 30px; font-size: 25px; font-weight: 500; letter-spacing: -.02em; }
.post-modal-body { padding: 0 30px 30px; color: var(--text-dim); font-size: 14.5px; line-height: 1.78; }
.post-modal-body p { margin: 0 0 15px; }
.post-modal-body p:last-child { margin-bottom: 0; }
.post-modal-body strong { color: var(--text); font-weight: 600; }
.post-modal-body em { color: var(--text); font-style: italic; }
.post-modal-body code {
  padding: 2px 6px; border-radius: 6px;
  background: color-mix(in srgb, var(--ink) 6%, transparent); border: 1px solid var(--border);
  color: var(--accent); font-family: ui-monospace, monospace; font-size: .88em;
}

@media (max-width: 640px) {
  .post-modal h2 { font-size: 21px; padding: 0 20px; }
  .post-modal-meta { padding: 20px 20px 0; }
  .post-modal-body { padding: 0 20px 24px; }
}

/* ---------- settings & alerts panel ---------- */

.hdr-menu-badge, .set-badge {
  margin-left: auto; min-width: 19px; padding: 1px 6px; border-radius: 999px;
  background: var(--accent); color: var(--on-accent); font-size: 10.5px; font-weight: 600; text-align: center;
}
.hdr-menu button { display: flex; align-items: center; gap: 8px; }
.hdr-avatar { position: relative; }
.hdr-avatar-dot {
  position: absolute; top: -1px; right: -1px; width: 9px; height: 9px; border-radius: 50%;
  background: var(--down); border: 2px solid var(--bg); font-style: normal;
}

.settings-backdrop {
  position: fixed; inset: 0; z-index: var(--z-modal);
  display: grid; place-items: center; padding: 24px;
  background: var(--scrim); backdrop-filter: blur(6px);
}
/* Bigger, and with room to breathe. 880x660 put four sections of form into a box the size of
   a dialog, so every group sat on top of the next and the whole thing read as cramped. */
.settings-panel {
  position: relative; display: grid; grid-template-columns: 244px minmax(0, 1fr);
  width: min(1120px, 100%); height: min(820px, calc(100vh - 48px));
  border: 1px solid var(--border-strong); border-radius: 20px;
  background: var(--bg-lift); box-shadow: 0 16px 40px color-mix(in srgb, var(--shade) 34%, transparent); overflow: hidden;
}
.settings-close {
  position: absolute; top: 13px; right: 15px; z-index: 5;
  width: 32px; height: 32px; border-radius: 9px;
  color: var(--text-faint); font-size: 22px; line-height: 1;
  /* Sits over the scrolling body, so it needs its own ground rather than letting rows show
     through underneath it. */
  background: var(--bg-lift);
}
/* Whatever lands at the top of the panel must not run under that button. */
.settings-body > .set-head-row:first-child,
.settings-body > .gate-notice:first-child + .set-head-row,
.settings-body > .set-title:first-child { padding-right: 42px; }
.settings-close:hover { background: var(--surface-hover); color: var(--text); }

.settings-nav {
  display: flex; flex-direction: column; gap: 3px; padding: 26px 16px;
  border-right: 1px solid var(--border); background: color-mix(in srgb, var(--ink) 1.2%, transparent);
}
.set-nav-item {
  display: flex; align-items: center; gap: 11px;
  padding: 11px 14px; border-radius: 10px;
  color: var(--text-dim); font-size: 13.5px; text-align: left;
  transition: background .15s var(--ease), color .15s var(--ease);
}
.set-nav-item:hover { background: var(--surface-hover); color: var(--text); }
.set-nav-item.is-active { background: var(--chrome-fill); color: var(--chrome-text); }
.set-nav-icon { opacity: .7; }

.settings-body { padding: 34px 38px 40px; overflow-y: auto; }
.set-title { margin: 0 0 6px; font-size: 17px; font-weight: 500; letter-spacing: -.01em; }
.set-title:not(:first-child) { margin-top: 40px; }
.set-hint { margin: 6px 0 18px; color: var(--text-faint); font-size: 12.5px; line-height: 1.65; max-width: 68ch; }
.set-head-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
/* The title inside this row has its margin zeroed, and `.set-title:not(:first-child)` cannot
   fire because it *is* the row's first child - so a second header had no space above it at all
   and its taller button sat on top of whatever came before. The row owns that spacing. */
.set-head-row:not(:first-child) { margin-top: 30px; }
.set-head-row .set-title { margin-bottom: 0; }
.set-head-row .set-submit, .set-head-row .set-secondary { flex: none; }

.set-rows { display: grid; gap: 1px; margin-top: 12px; border-radius: 12px; overflow: hidden; }
.set-row {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding: 12px 14px; background: var(--surface); font-size: 13px;
}
.set-row span { color: var(--text-faint); }

.set-form { display: grid; gap: 12px; margin-top: 12px; }
.set-field, .set-form label:not(.set-check) { display: grid; gap: 5px; }
.set-field span, .set-form label > span { color: var(--text-faint); font-size: 11.5px; }
.set-form input:not([type="checkbox"]), .set-field input {
  padding: 10px 12px; border-radius: 10px;
  border: 1px solid var(--border); background: var(--surface); color: var(--text); font-size: 13.5px;
}
.set-form input:focus, .set-field input:focus { outline: none; border-color: var(--accent); }
.set-check { display: flex; align-items: center; gap: 9px; color: var(--text-dim); font-size: 13px; }
.set-field { margin-top: 14px; }

/* Outlined, not filled.
 *
 * A solid block of accent for every Save on the page put the loudest colour in the app on its
 * least interesting action, four or five times per screen. These are outlined in the accent
 * and tinted faintly by it, so they still read as the primary control without shouting; the
 * hover deepens the tint and lifts the border rather than changing brightness, which is the
 * one transition that works the same in both themes. */
.set-submit, .set-secondary {
  justify-self: start; padding: 10px 18px; border-radius: 10px;
  font-size: 13.5px; font-weight: 500;
  border: 1px solid var(--border-strong); color: var(--text);
  background: color-mix(in srgb, var(--ink) 3%, transparent);
  transition: background .18s var(--ease), border-color .18s var(--ease),
              box-shadow .18s var(--ease), transform .18s var(--ease);
}
.set-submit {
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 42%, transparent);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}
.set-submit:hover:not(:disabled) {
  border-color: color-mix(in srgb, var(--accent) 70%, transparent);
  background: color-mix(in srgb, var(--accent) 15%, transparent);
  box-shadow: 0 4px 16px color-mix(in srgb, var(--accent) 18%, transparent);
}
.set-submit:active:not(:disabled), .set-secondary:active { transform: translateY(1px); }
.set-submit:disabled { opacity: .45; cursor: default; }
.set-secondary:hover {
  background: var(--surface-hover); border-color: var(--border-strong);
  box-shadow: 0 4px 14px color-mix(in srgb, var(--shade) 16%, transparent);
}
.set-submit.sm, .set-secondary.sm { padding: 7px 13px; font-size: 12.5px; }

.set-swatches { display: flex; flex-wrap: wrap; gap: 10px; }
.set-swatch {
  display: flex; align-items: center; gap: 9px; padding: 8px 14px 8px 9px;
  border: 1px solid var(--border); border-radius: 999px; color: var(--text-dim); font-size: 12.5px;
}
.set-swatch span { width: 18px; height: 18px; border-radius: 50%; }
.set-swatch:hover { border-color: var(--border-strong); color: var(--text); }
.set-swatch.is-active { border-color: var(--accent); color: var(--text); }

.set-empty {
  display: grid; gap: 7px; justify-items: start;
  margin-top: 12px; padding: 22px 20px;
  border: 1px dashed var(--border-strong); border-radius: 14px; background: var(--surface-soft);
}
.set-empty > span { font-size: 20px; color: var(--text-xfaint); }
.set-empty b { font-size: 13.5px; font-weight: 500; }
.set-empty p { margin: 0; color: var(--text-faint); font-size: 12.5px; line-height: 1.65; max-width: 52ch; }

/* --- alert feed --- */
.alert-feed { list-style: none; margin: 12px 0 0; padding: 0; display: grid; gap: 1px; border-radius: 12px; overflow: hidden; }
.alert-event {
  display: grid; grid-template-columns: 10px minmax(0, 1fr) auto; align-items: start; gap: 11px;
  padding: 12px 14px; background: var(--surface); font-size: 13px;
}
.alert-event b { display: block; font-weight: 500; }
.alert-event span { display: block; margin-top: 2px; color: var(--text-faint); font-size: 12px; }
.alert-event time { color: var(--text-xfaint); font-size: 11px; white-space: nowrap; }
.alert-dot { width: 8px; height: 8px; margin-top: 5px; border-radius: 50%; background: var(--text-xfaint); }
.alert-event.is-up .alert-dot { background: var(--up); }
.alert-event.is-down .alert-dot { background: var(--down); }
.alert-event.is-unread { background: color-mix(in srgb, var(--accent) 5%, transparent); }

/* Reading one by looking at it.
   An unread row is a control, so it says so under the pointer; and the moment it is read the
   tint and the dot ease away rather than snapping, because a row that changes instantly reads
   as the list having been rebuilt underneath you rather than as this row settling. */
.alert-event[data-alert-read] { cursor: pointer; }
.alert-event[data-alert-read]:hover { background: color-mix(in srgb, var(--accent) 9%, transparent); }
.alert-event[data-alert-read]:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--accent) 55%, transparent); outline-offset: -2px;
}
.alert-event {
  transition: background .32s var(--ease);
}
.alert-event .alert-dot { transition: opacity .32s var(--ease), transform .32s var(--ease); }
.alert-event.is-settling .alert-dot { opacity: .35; transform: scale(.6); }
@media (prefers-reduced-motion: reduce) {
  .alert-event, .alert-event .alert-dot { transition: none; }
}

/* --- rule cards --- */
.alert-rules { display: grid; gap: 10px; margin-top: 12px; }
.alert-rule {
  padding: 14px 16px; border: 1px solid var(--border); border-radius: 14px; background: var(--surface-soft);
}
.alert-rule.is-off { opacity: .55; }
.alert-rule-head { display: flex; align-items: center; gap: 11px; }
.alert-rule-head b { font-size: 13.5px; font-weight: 500; }
.alert-rule p { margin: 8px 0 0 46px; color: var(--text-dim); font-size: 12.5px; line-height: 1.6; }
.alert-rule-actions { margin-left: auto; display: flex; gap: 11px; }
.alert-rule-actions button { color: var(--text-faint); font-size: 12px; }
.alert-rule-actions button:hover { color: var(--text); }
.alert-rule-actions .danger-link:hover { color: var(--down); }

.set-switch { position: relative; flex: none; width: 35px; height: 20px; }
.set-switch input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
.set-switch span {
  position: absolute; inset: 0; border-radius: 999px; background: color-mix(in srgb, var(--ink) 12%, transparent);
  transition: background .2s var(--ease); pointer-events: none;
}
.set-switch span::after {
  content: ''; position: absolute; top: 3px; left: 3px; width: 14px; height: 14px;
  border-radius: 50%; background: var(--text-dim); transition: transform .2s var(--ease), background .2s var(--ease);
}
.set-switch input:checked + span { background: color-mix(in srgb, var(--accent) 35%, transparent); }
.set-switch input:checked + span::after { transform: translateX(15px); background: var(--accent); }

/* --- builder --- */
.set-step { display: grid; grid-template-columns: 26px minmax(0, 1fr); gap: 16px; margin-top: 30px; }
.set-step-n {
  width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center;
  background: var(--surface-hover); color: var(--text-dim); font-size: 12px;
}
.set-step h4 { margin: 3px 0 13px; font-size: 14px; font-weight: 500; }

.set-sources, .set-triggers { display: grid; grid-template-columns: repeat(auto-fit, minmax(196px, 1fr)); gap: 9px; }
.set-source, .set-trigger {
  display: grid; gap: 3px; padding: 13px 15px; text-align: left;
  border: 1px solid var(--border); border-radius: 12px; background: var(--surface-soft);
  transition: border-color .18s var(--ease), background .18s var(--ease);
}
.set-source b, .set-trigger b { font-size: 13px; font-weight: 500; }
.set-source span, .set-trigger span { color: var(--text-faint); font-size: 11.5px; line-height: 1.55; }
.set-source:hover, .set-trigger:hover { border-color: var(--border-strong); }

.set-templates {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 10px;
}
.set-template {
  display: grid;
  grid-template-columns: 76px minmax(0, 1fr);
  grid-template-areas: "preview name" "preview hint";
  column-gap: 14px;
  align-items: center;
  padding: 13px;
  text-align: left;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--surface-soft);
  transition: border-color .18s var(--ease), background .18s var(--ease);
}
.set-template:hover { border-color: var(--border-strong); background: var(--surface-hover); }
.set-template.is-active { border-color: var(--chrome-edge); background: var(--chrome-fill); }
.set-template > b { grid-area: name; font-size: 13px; font-weight: 500; }
.set-template > span:last-child {
  grid-area: hint;
  color: var(--text-faint);
  font-size: 11.5px;
  line-height: 1.5;
}
.set-template-preview {
  grid-area: preview;
  display: grid;
  align-content: center;
  gap: 5px;
  width: 76px;
  height: 52px;
  padding: 9px;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
}
.set-template-preview i { display: block; height: 4px; border-radius: 2px; background: var(--text-xfaint); }
.set-template-preview i:nth-child(1) { width: 66%; }
.set-template-preview i:nth-child(2) { width: 100%; }
.set-template-preview i:nth-child(3) { width: 82%; }
.set-template-preview.is-graphite { background: #0b0d12; border-color: #2b2e35; }
.set-template-preview.is-graphite i:nth-child(1) { background: #9da3aa; }
.set-template-preview.is-graphite i:nth-child(2) { background: #85a897; }
.set-template-preview.is-graphite i:nth-child(3) { background: #ad7b84; }
.set-template-note {
  display: grid;
  gap: 4px;
  margin-top: 14px;
  padding: 13px 15px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface-soft);
}
.set-template-note b { font-size: 13px; font-weight: 500; }
.set-template-note span { color: var(--text-faint); font-size: 12px; line-height: 1.55; }
/* An active card takes the chrome's *text* colour along with its fill.
 *
 * This was the bug the Paper chrome exposed. Every other variant fills at low alpha, so the
 * card's own --text still read fine on top of it and the omission was invisible; Paper fills
 * at 92%, which on a dark ground is a near-white card - and the label was still being drawn
 * in near-white ink on it. Any surface that paints --chrome-fill behind text has to paint
 * --chrome-text on the text, and that is now true of all of them.
 *
 * The muted sub-line is derived from the same colour rather than left on --text-faint, which
 * is a shade of the *ground's* ink and would vanish for exactly the same reason. */
.set-source.is-active, .set-trigger.is-active {
  border-color: var(--chrome-edge);
  background: var(--chrome-fill);
  color: var(--chrome-text);
}
.set-source.is-active b, .set-trigger.is-active b { color: var(--chrome-text); }
.set-source.is-active span:not(.set-chrome-demo),
.set-trigger.is-active span:not(.set-chrome-demo) {
  color: color-mix(in srgb, var(--chrome-text) 72%, transparent);
}

/* The chrome picker previews each variant on itself rather than describing it, because
   "frosted glass" and "near-solid" are words that only mean something once you have seen the
   pill. Each demo re-declares the tokens locally, so all six render side by side no matter
   which one is currently applied to the page. */
.set-chromes .set-source { grid-template-columns: auto 1fr; grid-template-areas: "demo name" "demo hint"; column-gap: 12px; align-items: center; }
.set-chromes .set-source > b { grid-area: name; }
.set-chromes .set-source > span:not(.set-chrome-demo) { grid-area: hint; }
.set-chrome-demo {
  grid-area: demo;
  display: grid; place-items: center;
  width: 46px; height: 34px;
  border-radius: 999px;
  background: var(--chrome-fill);
  border: 1px solid var(--chrome-edge);
  box-shadow: var(--chrome-lift);
  -webkit-backdrop-filter: var(--chrome-blur);
  backdrop-filter: var(--chrome-blur);
}
.set-chrome-demo i {
  display: block;
  width: 18px;
  height: 3px;
  border-radius: 2px;
  background: var(--chrome-text);
}
/* Each preview keeps its own colours even when the card behind it is the active one. */
.set-chromes .set-source.is-active .set-chrome-demo i { background: var(--chrome-text); }

.chrome-demo-tinted, .chrome-demo-custom {
  --chrome-fill: color-mix(in srgb, var(--chrome-tint) 10%, transparent);
  --chrome-edge: color-mix(in srgb, var(--chrome-tint) 22%, transparent);
  --chrome-text: var(--chrome-tint);
  --chrome-lift: none; --chrome-blur: none;
}
.chrome-demo-tinted { --chrome-tint: var(--accent); }
.chrome-demo-glass {
  --glass-x: 26%;
  --glass-y: 0%;
  --chrome-fill:
    radial-gradient(42px 28px at var(--glass-x) var(--glass-y),
      rgb(255 255 255 / .46), rgb(255 255 255 / .08) 36%, transparent 72%),
    linear-gradient(145deg, rgb(255 255 255 / .14), transparent 48%),
    rgb(255 255 255 / .065);
  --chrome-edge: rgb(255 255 255 / .28);
  --chrome-text: var(--text);
  --chrome-lift:
    inset 0 1px 0 rgb(255 255 255 / .5),
    inset 0 -1px 0 rgb(0 0 0 / .24),
    0 6px 16px rgb(0 0 0 / .25);
  --chrome-blur: blur(18px) saturate(185%) contrast(1.08);
}
.chrome-demo-slate {
  --chrome-fill: color-mix(in srgb, var(--ink) 11%, transparent);
  --chrome-edge: color-mix(in srgb, var(--ink) 22%, transparent);
  --chrome-text: var(--text); --chrome-lift: none; --chrome-blur: none;
}
.chrome-demo-paper {
  --chrome-fill: color-mix(in srgb, var(--ink) 92%, transparent);
  --chrome-edge: color-mix(in srgb, var(--ink) 92%, transparent);
  --chrome-text: var(--bg);
  --chrome-lift: 0 1px 8px color-mix(in srgb, var(--shade) 40%, transparent);
  --chrome-blur: none;
}
.chrome-demo-ghost {
  --chrome-fill: color-mix(in srgb, var(--ink) 1.8%, transparent);
  --chrome-edge: color-mix(in srgb, var(--ink) 46%, transparent);
  --chrome-text: var(--text);
  --chrome-lift: inset 0 0 0 1px color-mix(in srgb, var(--ink) 7%, transparent);
  --chrome-blur: none;
}

/* The compounded footer under a board. Separated by a rule rather than a fill so it reads as
   a sum of the rows above rather than one more row among them. */
.rot-board-total {
  border-top: 1px solid var(--border-strong);
  margin-top: 4px; padding-top: 10px;
  font-weight: 500;
}
.rot-board-total:hover { background: none; }

.asset-settings-tip.is-open { display: block; }
.asset-settings-clear {
  margin-top: 10px; padding: 7px 13px; border-radius: 10px;
  border: 1px solid var(--border); color: var(--text-dim); font-size: 12.5px;
  transition: border-color .18s var(--ease), color .18s var(--ease);
}
.asset-settings-clear:hover { border-color: var(--border-strong); color: var(--text); }

.lab-from {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 5px 12px 5px 14px;
  border: 1px solid var(--border); border-radius: 10px;
  background: var(--surface-soft);
  font-size: 12.5px; color: var(--text-dim);
  transition: border-color .18s var(--ease);
}
.lab-from:focus-within { border-color: var(--border-strong); }
.lab-from input {
  border: none; outline: none; background: none;
  color: var(--text); font-size: 12.5px;
}

/* The take-profit ladder inside one trade row. Six small pills rather than six rows: a
   position had one decision behind it, and splitting it up the table would read as six. A
   rung that never filled stays drawn - "TP4 never came" is information, and leaving it out
   would make every trade look like it went perfectly as far as it went. */
.trade-board .rot-board-head,
.trade-board .rot-board-row {
  grid-template-columns: 100px 108px minmax(0, 1fr) 104px 80px 74px 88px 100px;
}
.tp-ladder { display: flex; flex-wrap: wrap; gap: 5px; }
.tp-rung {
  display: inline-flex; align-items: baseline; gap: 5px;
  padding: 3px 9px; border-radius: 7px;
  border: 1px solid var(--border);
  font-size: 11px; color: var(--text-xfaint);
}
.tp-rung b { font-weight: 500; }
.tp-rung i { font-style: normal; font-family: ui-monospace, monospace; }
.tp-rung.is-hit {
  color: var(--up);
  border-color: color-mix(in srgb, var(--up) 30%, transparent);
  background: color-mix(in srgb, var(--up) 9%, transparent);
}
/* The second warning in the picker. Same weight as the automation one - "you are about to
   be in a position right now" is not a footnote - but tinted apart so two blocks of red do
   not read as one long paragraph nobody finishes. */
.rot-warn.is-now {
  border-color: color-mix(in srgb, var(--warn) 32%, transparent);
  background: color-mix(in srgb, var(--warn) 7%, transparent);
}
.rot-warn.is-now b { color: var(--warn); }

/* The compounding switch sits in the same grid as the fields it qualifies, so it reads as
   part of "how much" rather than as a stray preference underneath it. */
.rot-desk-hint {
  font-style: normal; font-weight: 400; color: var(--text-xfaint);
}

.rot-desk-check {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 10px 0 0;
}
.rot-desk-check input { margin-top: 2px; flex: none; }
.rot-desk-check b { display: block; font-size: 13px; font-weight: 500; color: var(--text); }
.rot-desk-check i {
  display: block; margin-top: 2px;
  font-style: normal; font-size: 12px; color: var(--text-faint); line-height: 1.5;
}

.rot-desk-fields.is-locked select,
.rot-desk-fields.is-locked input { opacity: .55; cursor: not-allowed; }
.rot-desk-locked {
  grid-column: 1 / -1; margin: 2px 0 0;
  font-size: 12px; color: var(--text-faint);
}

/* The switch board's own grid, so the optional "Your account" column lines up rather than
   pushing everything out of true. auto-fit on the last track keeps a six-column board
   identical to what it was. */
.lab-board .rot-board-head,
.lab-board .rot-board-row {
  grid-template-columns: 110px minmax(0, 1fr) 84px 96px 104px auto;
}

.tp-rung.is-pending { border-style: dashed; color: var(--text-faint); }
.rot-tag.is-live {
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--up); border-color: color-mix(in srgb, var(--up) 32%, transparent);
}
.rot-tag.is-live .rot-live-none {
  display: block; margin-top: 3px;
  font-style: normal; font-size: 11.5px; color: var(--text-faint);
}

.rot-live { margin: 0; }
.rot-tag.is-long { color: var(--up); border-color: color-mix(in srgb, var(--up) 28%, transparent); }
.rot-tag.is-short { color: var(--down); border-color: color-mix(in srgb, var(--down) 28%, transparent); }

/* The account picture, in the header and in Settings. The image fills the circle by
   `object-fit: cover` rather than by being trusted to arrive square - it is squared in the
   browser before upload, but a picture stored by an older build was not. */
.hdr-avatar.has-picture { padding: 0; overflow: hidden; }
.hdr-avatar img, .set-avatar img {
  width: 100%; height: 100%; object-fit: cover; display: block; border-radius: inherit;
}

.set-avatar-row { display: flex; align-items: center; gap: 18px; margin: 4px 0 18px; }
.set-avatar {
  flex: none;
  display: grid; place-items: center;
  width: 76px; height: 76px; border-radius: 50%; overflow: hidden;
  background: var(--surface); border: 1px solid var(--border);
  font-size: 28px; color: var(--text-dim);
}
.set-avatar-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 9px; }
.set-avatar-actions .set-hint { flex-basis: 100%; margin: 0; }
/* The file input is the label's own hit area, so the control looks like every other button
   here rather than like a browser's default "Choose file". */
.set-avatar-pick { position: relative; overflow: hidden; cursor: pointer; }
.set-avatar-pick input[type="file"] {
  position: absolute; inset: 0; opacity: 0; cursor: pointer; font-size: 0;
}

.set-chiprow { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 10px; }
.set-chip {
  padding: 7px 14px; border-radius: 7px; border: 1px solid var(--border);
  color: var(--text-dim); font-size: 12.5px;
}
.set-chip em { margin-left: 6px; font-style: normal; color: var(--text-xfaint); }
.set-chip:hover { border-color: var(--border-strong); color: var(--text); }
.set-chip.is-active { border-color: var(--chrome-edge); color: var(--chrome-text); background: var(--chrome-fill); }

.set-preview {
  margin: 24px 0 18px; padding: 15px 17px;
  border-left: 2px solid var(--accent); border-radius: 0 12px 12px 0;
  background: color-mix(in srgb, var(--accent) 5%, transparent);
}
.set-preview span { color: var(--text-xfaint); font-size: 10.5px; text-transform: uppercase; letter-spacing: .07em; }
.set-preview p { margin: 6px 0 0; font-size: 13.5px; line-height: 1.6; }

@media (max-width: 720px) {
  .settings-panel { grid-template-columns: 1fr; height: calc(100vh - 48px); }
  .settings-nav { flex-direction: row; overflow-x: auto; border-right: none; border-bottom: 1px solid var(--border); }
  .alert-rule p { margin-left: 0; }
}

/* ---------- watchlist builder ---------- */

.wl-skipped b { display: block; margin-bottom: 6px; }
.wl-skipped p { margin: 4px 0 0; font-size: 12px; line-height: 1.6; }
.wl-skipped span { color: var(--text); font-family: ui-monospace, monospace; font-size: 11.5px; }

.empty-actions { display: flex; gap: 9px; justify-content: center; flex-wrap: wrap; margin-top: 14px; }

.wl-builder { width: min(560px, 100%); }
.wl-build-field { display: grid; gap: 5px; margin-top: 13px; }
.wl-build-field span { color: var(--text-faint); font-size: 11.5px; }
.wl-build-field input {
  padding: 11px 13px; border-radius: 11px;
  border: 1px solid var(--border); background: var(--surface); color: var(--text); font-size: 14px;
}
.wl-build-field input:focus { outline: none; border-color: var(--accent); }

.wl-picks { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 14px; }
.wl-pick {
  display: inline-flex; align-items: center; gap: 7px; padding: 5px 9px 5px 12px;
  border-radius: 10px; border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
  background: color-mix(in srgb, var(--accent) 8%, transparent); color: var(--accent); font-size: 12px;
}
.wl-pick i { font-style: normal; opacity: .65; }
.wl-pick:hover { border-color: var(--accent); }
.wl-pick:hover i { opacity: 1; }

.wl-results { max-height: 250px; overflow-y: auto; margin-top: 14px; display: grid; gap: 2px; }
.wl-result {
  display: grid; grid-template-columns: 72px minmax(0, 1fr) auto 20px;
  align-items: center; gap: 10px; padding: 9px 11px; border-radius: 10px;
  text-align: left; color: var(--text-dim); font-size: 13px;
}
.wl-result:hover { background: var(--surface-hover); color: var(--text); }
.wl-result b { color: var(--text); font-weight: 500; }
.wl-result span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12.5px; }
.wl-result em {
  font-style: normal; color: var(--text-xfaint); font-size: 10.5px;
  text-transform: uppercase; letter-spacing: .06em;
}
.wl-result i { font-style: normal; color: var(--text-faint); text-align: center; }
.wl-result.is-picked { background: color-mix(in srgb, var(--accent) 7%, transparent); }
.wl-result.is-picked i { color: var(--accent); }

.wl-build-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin-top: 18px; padding-top: 15px; border-top: 1px solid var(--border);
}
.wl-build-foot span { color: var(--text-faint); font-size: 12px; }
.wl-build-foot button:disabled { opacity: .5; cursor: default; }

/* ---------- portfolio: advanced mode ---------- */

.pf-row-clickable { cursor: pointer; }
.pf-row-clickable:hover { background: var(--surface); }
.pf-has-chart { margin-left: 6px; font-style: normal; color: var(--accent); font-size: 10px; }

.pf-advanced { margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--border); }
.pf-advanced-head, .pf-fills-head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 10px;
}
.pf-advanced-head span, .pf-fills-head span {
  color: var(--text-faint); font-size: 10.5px; text-transform: uppercase; letter-spacing: .07em;
}
.chip.sm { padding: 5px 11px; font-size: 11.5px; }

.pf-fills { margin-top: 16px; }
.pf-fill {
  display: grid; grid-template-columns: 130px 1fr 1fr 140px auto;
  gap: 8px; align-items: center; margin-bottom: 8px;
}
.pf-fill select, .pf-fill input {
  padding: 8px 10px; border-radius: 9px; border: 1px solid var(--border);
  background: var(--surface); color: var(--text); font-size: 12.5px;
}
.pf-fill select:focus, .pf-fill input:focus { outline: none; border-color: var(--accent); }

.pf-chart-upload { margin-top: 18px; }
.pf-chart-drop {
  display: grid; place-items: center; padding: 26px 18px; cursor: pointer;
  border: 1px dashed var(--border-strong); border-radius: 12px;
  color: var(--text-faint); font-size: 12.5px; text-align: center;
}
.pf-chart-drop:hover { border-color: var(--accent); color: var(--text-dim); }
.pf-chart-preview { width: 100%; border-radius: 12px; border: 1px solid var(--border); display: block; }

.pf-detail { width: min(680px, 100%); }
.pf-detail h2 { display: flex; align-items: center; gap: 10px; }
.pf-status {
  padding: 3px 9px; border-radius: 7px; font-size: 10.5px;
  text-transform: uppercase; letter-spacing: .05em;
  background: var(--surface-hover); color: var(--text-faint);
}
.pf-detail-chart { width: 100%; border-radius: 12px; border: 1px solid var(--border); margin-bottom: 18px; }
.pf-detail-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 1px; border-radius: 12px; overflow: hidden; }
.pf-detail-row { padding: 11px 13px; background: var(--surface); display: grid; gap: 3px; }
.pf-detail-row span { color: var(--text-faint); font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em; }
.pf-detail-row b { font-size: 14px; font-weight: 500; font-family: ui-monospace, monospace; }
.pf-detail-fills { margin-top: 20px; }
.pf-detail-notes { margin-top: 20px; }
.pf-detail-notes span { color: var(--text-faint); font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em; }
.pf-detail-notes p { margin: 6px 0 0; color: var(--text-dim); font-size: 13.5px; line-height: 1.7; }

@media (max-width: 640px) {
  .pf-fill { grid-template-columns: 1fr 1fr; }
}

/* ---------- first-run tour ---------- */

body.is-touring { overflow: hidden; }

.tour-layer { position: fixed; inset: 0; z-index: var(--z-tour); }
.tour-layer[hidden] { display: none; }

/* Blur sits on its own layer with a rectangular hole; the spotlight below supplies the dim. */
/* The wash over everything but the spotlight.
   Halved, and deliberately. At 4px the rest of the page was unreadable, which is the wrong
   trade for a walkthrough: somebody being shown "this is the trend column" needs to see the
   table it is a column of, or the highlight points at a shape with no context. Enough to
   recede, not enough to hide. */
.tour-blur {
  position: absolute; inset: 0; pointer-events: none;
  backdrop-filter: blur(1.6px);
  -webkit-backdrop-filter: blur(1.6px);
  background: color-mix(in srgb, var(--shade) 26%, transparent);
}
.tour-blur[hidden] { display: none; }

/* The oversized shadow *is* the dimming, so moving this one element moves the whole effect. */
.tour-spot {
  position: absolute; border-radius: 14px; pointer-events: none;
  box-shadow: 0 0 0 9999px var(--scrim), 0 0 0 1.5px var(--accent),
              0 0 26px color-mix(in srgb, var(--accent) 35%, transparent);
  transition: left .42s var(--ease), top .42s var(--ease),
              width .42s var(--ease), height .42s var(--ease);
}

/* The tour pressing a tab on your behalf. Reads as a real click - the button dips and a
   ring flares out of it - so the panel change that follows has a visible cause. */
/* Live-price mode: an unfinished candle is a real caveat, so this is a banner rather
   than a tooltip - visible for as long as the mode is on, and carrying its own way out. */
/* The little "source" link that follows a quotation back to its video. Small on purpose:
   it must not compete with the words it is vouching for. */
.an-quote-src {
  display: inline-flex; align-items: center; gap: 3px; margin-left: 7px;
  padding: 1px 6px 1px 4px; border-radius: 7px; vertical-align: 1px;
  border: 1px solid var(--border); color: var(--text-faint);
  font-size: 10.5px; font-style: normal; letter-spacing: .02em; text-decoration: none;
  transition: color .16s var(--ease), border-color .16s var(--ease);
}

.an-quote-src svg { width: 9px; height: 9px; }
.an-quote-src:hover { color: var(--accent); border-color: var(--accent); }

/* ── data API ────────────────────────────────────────────────────────────── */

.api-new { display: flex; gap: 10px; margin-bottom: 18px; }
.api-new input {
  flex: 1; max-width: 320px; padding: 9px 12px; border-radius: 9px;
  border: 1px solid var(--border); background: var(--surface); color: var(--text);
  font-size: 13px;
}

/* The one moment the key exists in readable form. Loud on purpose. */
.api-created {
  margin-bottom: 18px; padding: 14px 16px; border-radius: 12px;
  border: 1px solid color-mix(in srgb, var(--warn) 34%, transparent);
  background: color-mix(in srgb, var(--warn) 9%, transparent);
}
.api-created > b { display: block; margin-bottom: 9px; color: var(--warn); font-weight: 500; font-size: 13px; }
.api-created > span { display: block; margin-top: 8px; color: var(--text-faint); font-size: 11.5px; }
.api-secret { display: flex; align-items: center; gap: 10px; }
.api-secret code {
  flex: 1; padding: 9px 12px; border-radius: 8px; overflow-x: auto; white-space: nowrap;
  border: 1px solid var(--border); background: var(--bg);
  font-family: ui-monospace, monospace; font-size: 12px; color: var(--text);
}

.api-keys { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.api-keys th, .api-keys td { padding: 9px 10px; text-align: left; border-bottom: 1px solid var(--border); }
.api-keys thead th { color: var(--text-faint); font-weight: 400; font-size: 11.5px; }
.api-keys td:last-child { text-align: right; }

.api-revoke {
  padding: 4px 10px; border-radius: 10px; cursor: pointer;
  border: 1px solid var(--border-strong); background: transparent;
  color: var(--text-faint); font-size: 11px;
  transition: color .16s var(--ease), border-color .16s var(--ease);
}
.api-revoke:hover { color: var(--down); border-color: color-mix(in srgb, var(--down) 50%, transparent); }

.api-docs { margin-top: 20px; }
.api-docs summary { cursor: pointer; font-size: 12.5px; color: var(--text-dim); }
.api-endpoints { width: 100%; border-collapse: collapse; margin-top: 10px; font-size: 12px; }
.api-endpoints td { padding: 7px 10px; border-bottom: 1px solid var(--border); vertical-align: top; }
.api-method { width: 44px; color: var(--accent); font-weight: 500; }
.api-path { width: 40%; color: var(--text); }
.api-endpoints td:last-child { color: var(--text-dim); }

.api-note { margin: 12px 0 0; font-size: 11.5px; line-height: 1.7; color: var(--text-faint); }
.api-note code {
  padding: 1px 5px; border-radius: 5px; background: var(--surface-hover);
  font-family: ui-monospace, monospace; font-size: 11px; color: var(--text-dim);
}

.api-sample {
  margin: 12px 0 0; padding: 12px 14px; border-radius: 10px; overflow-x: auto;
  border: 1px solid var(--border); background: var(--bg);
}
.api-sample code {
  font-family: ui-monospace, monospace; font-size: 11.5px;
  color: var(--text-dim); white-space: pre;
}

@media (max-width: 720px) {
  .api-keys { display: block; overflow-x: auto; }
  .api-new { flex-direction: column; }
  .api-new input { max-width: none; }
}

/* ── backtesting lab ─────────────────────────────────────────────────────── */

/* The three pieces the API panel had borrowed from the backtesting lab, kept here now that
   the lab is gone. */
.api-badge {
  margin-left: 8px;
  padding: 2px 7px;
  border-radius: 7px;
  font-style: normal;
  font-size: 10px;
  letter-spacing: .04em;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 26%, transparent);
}
.api-error { margin-top: 16px; font-size: 12.5px; color: var(--down); }
.api-empty { font-size: 12.5px; color: var(--text-faint); }

@media (max-width: 720px) {
  .lab-head { flex-direction: column; }
  .lab-trades { display: block; overflow-x: auto; }
}

/* One tutorial per settings section. The "?" sits in the section heading and the panel
   opens underneath it, in the flow, so it can never be clipped or land off-screen. */
.asset-settings-group h4 { display: flex; align-items: center; gap: 7px; }

.asset-settings-help {
  width: 16px; height: 16px; flex: none; padding: 0;
  border: 1px solid var(--border-strong); border-radius: 50%;
  background: transparent; color: var(--text-faint);
  font-size: 10.5px; line-height: 1; cursor: pointer;
  transition: color .16s var(--ease), border-color .16s var(--ease),
              background .16s var(--ease);
}

.asset-settings-help:hover { color: var(--text); border-color: var(--accent); }

.asset-settings-help.is-open {
  color: var(--bg); background: var(--accent); border-color: var(--accent);
}

.asset-settings-tip {
  margin: 0 0 10px; padding: 10px 12px;
  border: 1px solid color-mix(in srgb, var(--accent) 26%, transparent);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  border-radius: 10px;
  animation: settings-tip-in .22s var(--ease);
}

.asset-settings-tip[hidden] { display: none; }
.asset-settings-tip b { display: block; margin-bottom: 3px; font-size: 12px; color: var(--accent); font-weight: 500; }
.asset-settings-tip p { margin: 0; font-size: 12px; line-height: 1.6; color: var(--text-dim); }

@keyframes settings-tip-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .asset-settings-tip { animation: none; }
}

/* The live-price notice. A big sign, because it is the only dialog in this app that exists to
   slow somebody down rather than to move them along. */
.notice-backdrop {
  position: fixed; inset: 0; z-index: var(--z-modal);
  display: grid; place-items: center; padding: 22px;
  background: var(--scrim); backdrop-filter: blur(7px);
}
.notice-backdrop[hidden] { display: none; }
.notice-modal {
  position: relative; width: min(470px, 100%);
  padding: 32px 30px 26px; text-align: center;
  border: 1px solid var(--border-strong); border-radius: 22px;
  background: var(--bg-lift); box-shadow: 0 16px 40px color-mix(in srgb, var(--shade) 34%, transparent);
}
.notice-sign {
  width: 76px; height: 76px; margin: 0 auto 18px;
  display: grid; place-items: center; border-radius: 22px;
  color: var(--warn);
  background: color-mix(in srgb, var(--warn) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--warn) 34%, transparent);
}
.notice-sign svg { width: 42px; height: 42px; }
.notice-modal h2 { margin: 0 0 10px; font-size: 21px; font-weight: 500; }
.notice-modal p {
  margin: 0 auto 20px; max-width: 42ch;
  color: var(--text-dim); font-size: 13.5px; line-height: 1.65;
}
.notice-agree {
  display: flex; gap: 10px; align-items: flex-start; text-align: left;
  margin: 0 0 20px; padding: 13px 15px; border-radius: 13px;
  background: var(--surface-soft); border: 1px solid var(--border);
  font-size: 12.5px; line-height: 1.55; color: var(--text); cursor: pointer;
}
.notice-agree input { margin-top: 2px; flex: none; accent-color: var(--accent); }
.notice-actions { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }
/* Disabled until the box is ticked: the point is the agreement, not the click. */
.notice-actions .primary-chip[disabled] { opacity: .42; cursor: not-allowed; }
/* The live half of the switch reads exactly like the settled half: same weight, same colour,
   same pill. It used to turn amber while selected, so choosing live prices recoloured a
   control in the header - the app appeared to change state when only the price basis had.
   The switch says which basis is on by which half is selected, the way every other switch in
   the app does, and the sentence under the heading says what that basis means. */

.tab.is-tour-press {
  position: relative;
  color: var(--text);
  transform: scale(.94);
  transition: transform .16s var(--ease), color .16s var(--ease);
}

.tab.is-tour-press::after {
  content: ''; position: absolute; inset: -3px; border-radius: 9px;
  border: 1.5px solid var(--accent); pointer-events: none;
  animation: tour-press-ring .62s var(--ease);
}

@keyframes tour-press-ring {
  from { opacity: 0; transform: scale(.82); }
  45%  { opacity: 1; transform: scale(1); }
  to   { opacity: 0; transform: scale(1.18); }
}

@media (prefers-reduced-motion: reduce) {
  .tab.is-tour-press { transform: none; }
  .tab.is-tour-press::after { animation: none; opacity: 1; }
}

.tour-card {
  position: absolute; width: min(370px, calc(100vw - 24px));
  padding: 20px 22px 18px;
  border: 1px solid var(--border-strong); border-radius: 16px;
  background: var(--bg-lift); box-shadow: 0 16px 40px color-mix(in srgb, var(--shade) 34%, transparent);
  transition: top .42s var(--ease), left .42s var(--ease);
  /* The progress bar is pinned across the top of this card and is square where the card is
     round, so without this its corners sit outside the border on both sides - a three-pixel
     line poking out past the radius, which is the whole of the "loading bar goes out of
     bounds". Nothing in the card is meant to escape it, so clipping is the fix rather than
     matching the radius in two places that would then have to be kept in step. */
  overflow: hidden;
}
.tour-count {
  color: var(--accent); font-size: 10.5px; text-transform: uppercase; letter-spacing: .08em;
}
.tour-card h3 { margin: 8px 0 7px; font-size: 16px; font-weight: 500; }
.tour-card p { margin: 0; color: var(--text-dim); font-size: 13px; line-height: 1.65; }

.tour-actions {
  display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 18px;
}
.tour-nav { display: flex; gap: 8px; }
.tour-skip { color: var(--text-faint); font-size: 12.5px; }
.tour-skip:hover { color: var(--text); }
.tour-back, .tour-next { padding: 8px 16px; border-radius: 9px; font-size: 12.5px; }
.tour-back { border: 1px solid var(--border-strong); color: var(--text-dim); }
.tour-back:hover { color: var(--text); background: var(--surface-hover); }
.tour-next { background: var(--accent); color: var(--on-accent); font-weight: 600; }
.tour-next:hover { filter: brightness(1.08); }
/* On a click step the button is an escape hatch, not the way forward - the way forward is
   the thing being pointed at. Quiet, so it does not compete with the highlight, but present,
   so a click the tour failed to notice can never trap somebody on one step. */
.tour-next.is-escape {
  background: none; color: var(--text-faint); font-weight: 400;
  border: 1px solid var(--border);
}
.tour-next.is-escape:hover { filter: none; color: var(--text); border-color: var(--border-strong); }

@media (prefers-reduced-motion: reduce) {
  .tour-spot, .tour-card { transition: none; }
}

/* Google's Identity Services button renders itself; the slot only needs to centre it and
   reserve height so the dialog does not jump while the script loads. */
.auth-gsi { display: flex; justify-content: center; min-height: 44px; }
.auth-gsi:empty { min-height: 0; }
.auth-escape {
  align-self: center; color: var(--text-xfaint); font-size: 11px;
  text-decoration: underline; text-underline-offset: 2px;
}
.auth-escape:hover { color: var(--text-dim); }

/* ---------- highlights table ---------- */

.hl-table td { vertical-align: middle; }
.hl-table tbody tr.hl-row { cursor: pointer; }
.hl-table tbody tr.hl-row:hover { border-color: var(--border); }
/* The flex row lives inside the cell, never on it: `display:flex` on a <td> drops it out of
   the table layout algorithm, and every column below collapses away from its header. */
.hl-asset { min-width: 220px; }
.hl-asset-in { display: flex; align-items: center; gap: 10px; min-width: 0; }
.hl-asset-in .switch-icon { flex: none; width: 26px; height: 26px; }
.hl-asset-in .switch-icon img,
.hl-asset-in .list-avatar { width: 26px; height: 26px; border-radius: 50%; display: block; }
.hl-names { display: grid; min-width: 0; }
.hl-names b { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hl-names .asset-sym { color: var(--text-xfaint); font-size: 11px; }
.hl-pair { color: var(--text-faint); font-size: 11.5px; margin-left: 6px; }
.hl-at { color: var(--text-dim); }
.hl-when { color: var(--text-xfaint); font-size: 11.5px; white-space: nowrap; }

/* A panel that is still working should look like it, not like a panel that finished empty. */
.overview-loading.is-working .skeleton-bar { margin-bottom: 8px; }
.overview-loading.is-working p { color: var(--text-faint); font-size: 12.5px; }
@keyframes alpha-shimmer { 0% { background-position: -220px 0; } 100% { background-position: 220px 0; } }
.skeleton-bar {
  height: 10px; border-radius: 6px;
  background: linear-gradient(90deg, color-mix(in srgb, var(--ink) 4%, transparent) 0%, color-mix(in srgb, var(--ink) 9%, transparent) 50%, color-mix(in srgb, var(--ink) 4%, transparent) 100%);
  background-size: 440px 100%;
  animation: alpha-shimmer 1.25s linear infinite;
}
@media (prefers-reduced-motion: reduce) { .skeleton-bar { animation: none; } }

/* ---------- visual styles ---------- */

/* Signature is the default and needs no rules — it is what every other rule above already
   describes. The three below reshape the app by overriding tokens and a few shared shapes,
   so no component has to know which style is active. */

/* Plain: no rounding, no shadow, no motion. */
.style-plain {
  --radius: 4px;
}
.style-plain .tabs,
.style-plain .segmented,
.style-plain .hdr-account-btn,
.style-plain .wl-pick,
.style-plain .landing-primary,
.style-plain .landing-secondary { border-radius: 4px; }
.style-plain .tab-glide,
.style-plain .seg-glide { border-radius: 3px; }
.style-plain *,
.style-plain *::before,
.style-plain *::after {
  transition-duration: 0s !important;
  animation-duration: 0s !important;
  box-shadow: none !important;
}
.style-plain .hdr-avatar { border-radius: 4px; }

/* Compact: tighter rows, smaller type, more on screen. */
.style-compact { font-size: 13px; }
.style-compact .pf-table th { padding: 6px 8px; }
.style-compact .pf-table td { padding: 6px 8px; }
.style-compact .card { padding: 12px 14px; }
.style-compact .tiles { gap: 10px; }
.style-compact .hdr { --hdr-h: 48px; }
.style-compact .set-row { padding: 8px 12px; }
.style-compact .alert-event { padding: 8px 11px; }
.style-compact .post-content { padding: 12px 14px; }
.style-compact .switch-icon img,
.style-compact .hl-asset .list-avatar { width: 20px; height: 20px; }

/* High contrast: heavier borders, brighter text. */
.style-contrast {
  --border: color-mix(in srgb, var(--ink) 22%, transparent);
  --border-strong: color-mix(in srgb, var(--ink) 38%, transparent);
  --text: color-mix(in srgb, var(--ink) 98%, transparent);
  --text-dim: color-mix(in srgb, var(--ink) 78%, transparent);
  --text-faint: color-mix(in srgb, var(--ink) 60%, transparent);
  --text-xfaint: color-mix(in srgb, var(--ink) 42%, transparent);
  --surface: color-mix(in srgb, var(--ink) 5%, transparent);
  --surface-hover: color-mix(in srgb, var(--ink) 10%, transparent);
}
.style-contrast .pf-table td { border-top-color: color-mix(in srgb, var(--ink) 16%, transparent); }

/* Graphite is a complete template, based on the supplied reference: a near-black neutral
   ground, inset charcoal panels, fine cool-grey rules and low-saturation market signals.
   These declarations intentionally come after the independent styles so the template stays
   one authored look instead of inheriting whichever mix of controls was used previously. */
html.template-graphite {
  color-scheme: dark;
  --bg: #080a0f;
  --bg-lift: #111319;
  --bg-panel: #0c0e13;
  --ink: #eef0f3;
  --shade: #020307;
  --veil: rgba(8, 10, 15, .94);
  --scrim: rgba(2, 3, 7, .8);
  --surface: color-mix(in srgb, var(--ink) 3.5%, transparent);
  --surface-soft: color-mix(in srgb, var(--ink) 2.2%, transparent);
  --surface-hover: color-mix(in srgb, var(--ink) 5.5%, transparent);
  --border: color-mix(in srgb, var(--ink) 11%, transparent);
  --border-strong: color-mix(in srgb, var(--ink) 19%, transparent);
  --text: color-mix(in srgb, var(--ink) 91%, transparent);
  --text-dim: color-mix(in srgb, var(--ink) 59%, transparent);
  --text-faint: color-mix(in srgb, var(--ink) 39%, transparent);
  --text-xfaint: color-mix(in srgb, var(--ink) 23%, transparent);
  --accent: #aeb4bc;
  --up: #85a897;
  --down: #ad7b84;
  --warn: #b8a171;
  --info: #8e9eb5;
  --on-accent: #090b10;
  --radius: 11px;
  --hdr-h: 52px;
  --chrome-fill: color-mix(in srgb, var(--ink) 10%, transparent);
  --chrome-edge: color-mix(in srgb, var(--ink) 21%, transparent);
  --chrome-text: color-mix(in srgb, var(--ink) 93%, transparent);
  --chrome-lift: inset 0 1px 0 color-mix(in srgb, var(--ink) 8%, transparent);
  --chrome-blur: none;
}

.template-graphite body { font-size: 13px; letter-spacing: .005em; }
.template-graphite .hdr { background: var(--veil); backdrop-filter: blur(14px); }
.template-graphite .page { padding-top: calc(var(--hdr-h) + 28px); }
.template-graphite h1 { font-size: 22px; font-weight: 600; }
.template-graphite .page-head { margin-bottom: 16px; }
.template-graphite .highlights { gap: 9px; margin-bottom: 18px; }
.template-graphite .stat-stack { gap: 9px; }
.template-graphite .card { padding: 12px 14px; box-shadow: inset 0 1px 0 rgba(255,255,255,.018); }
.template-graphite .stat-value { font-size: 18px; }
.template-graphite .list-row { padding: 4px 0; }
.template-graphite .controls { margin-bottom: 10px; gap: 10px; }
.template-graphite .segmented { padding: 3px; }
.template-graphite .seg { padding: 6px 15px; font-size: 12px; }
.template-graphite .seg-glide { top: 3px; bottom: 3px; }
.template-graphite .chip,
.template-graphite .search { height: 32px; font-size: 12px; }
.template-graphite .table-card { border-radius: 12px; background: var(--bg-lift); }
.template-graphite .screener thead th { padding: 9px 12px 10px; font-size: 10px; }
.template-graphite .screener tbody td { padding: 9px 12px; border-top-color: var(--border); }
.template-graphite .screener tbody tr:first-child td { border-top-color: transparent; }
.template-graphite .verdict { padding: 4px 10px; border-radius: 4px; font-size: 11px; background: transparent; }
.template-graphite .tag { border-radius: 4px; background: transparent; }
.template-graphite .spark { height: 32px; }
.template-graphite .table-foot { padding: 11px 14px; }
.template-graphite .settings-panel { border-radius: 13px; }

/* ---------- colour scheme picker ---------- */

.set-pair { display: inline-flex; gap: 0; border-radius: 7px; overflow: hidden; flex: none; }
.set-pair i { display: block; width: 11px; height: 18px; }
.set-custom-colours { display: flex; gap: 14px; margin-top: 14px; flex-wrap: wrap; }
.set-custom-colours label { display: grid; gap: 5px; }
.set-custom-colours span { color: var(--text-faint); font-size: 11.5px; }
.set-custom-colours input[type="color"] {
  width: 62px; height: 34px; padding: 2px; cursor: pointer;
  border: 1px solid var(--border); border-radius: 9px; background: var(--surface);
}

/* A spinner says "still working"; a frozen bar says "broken". */
.spinner {
  width: 18px; height: 18px; border-radius: 50%;
  border: 2px solid color-mix(in srgb, var(--ink) 14%, transparent);
  border-top-color: var(--accent);
  animation: alpha-spin .7s linear infinite;
  display: inline-block;
}
@keyframes alpha-spin { to { transform: rotate(360deg); } }
.overview-loading.is-working { display: grid; gap: 10px; justify-items: start; }
@media (prefers-reduced-motion: reduce) { .spinner { animation-duration: 2.4s; } }

/* A research row explains itself on a second line. */
.list-reason {
  display: block; font-style: normal; color: var(--text-xfaint); font-size: 11px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.list-row .list-name b { font-weight: 500; }

/* ---------- indicator settings dialog ---------- */

.asset-settings-backdrop {
  position: fixed; inset: 0; z-index: var(--z-modal);
  display: grid; place-items: center; padding: 24px;
  background: var(--scrim); backdrop-filter: blur(5px);
}
.asset-settings-dialog {
  display: flex; flex-direction: column;
  width: min(760px, 100%); max-height: calc(100vh - 48px);
  border: 1px solid var(--border-strong); border-radius: 18px;
  background: var(--bg-lift); box-shadow: 0 16px 40px color-mix(in srgb, var(--shade) 34%, transparent);
  overflow: hidden;
}
.asset-settings-head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 18px;
  padding: 18px 20px 14px; border-bottom: 1px solid var(--border); flex: none;
}
.asset-settings-head b { display: block; font-size: 14px; font-weight: 500; }
.asset-settings-head span { display: block; margin-top: 2px; color: var(--text-xfaint); font-size: 11.5px; }
.asset-settings-head-actions { display: flex; align-items: center; gap: 10px; flex: none; }
.asset-settings-head-actions > button:first-child { color: var(--accent); font-size: 11.5px; }
.asset-settings-head-actions > button:first-child:hover { color: var(--text); }
.asset-settings-close {
  width: 30px; height: 30px; border-radius: 9px;
  color: var(--text-faint); font-size: 21px; line-height: 1;
}
.asset-settings-close:hover { background: var(--surface-hover); color: var(--text); }

.asset-settings-body { padding: 6px 20px 20px; overflow-y: auto; }
.asset-settings-group { margin-top: 16px; }
.asset-settings-group h4 {
  margin: 0 0 10px; color: var(--text-faint);
  font-size: 10.5px; font-weight: 500; text-transform: uppercase; letter-spacing: .07em;
}
.asset-settings-group .asset-chart-settings-grid {
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px;
}
.asset-settings-group .asset-chart-setting-toggle {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 7px 10px; border: 1px solid var(--border); border-radius: 9px;
  background: var(--surface);
}
.asset-settings-group .asset-chart-setting-toggle > span { margin: 0; }

@media (max-width: 640px) {
  .asset-settings-dialog { width: 100%; max-height: calc(100vh - 24px); }
  .asset-settings-body { padding: 6px 14px 16px; }
}

/* ── Analyst desk ──────────────────────────────────────────────────────── */

/* This view is dense and reads across, so it takes the full page width rather than the
   text column the reading views use. */
#view-analysts { max-width: none; }

.an-head-right { display: flex; align-items: center; gap: 10px; }

.an-mode {
  font-size: 13px;
  color: var(--text-dim);
  border: 1px solid var(--border);
  border-radius: 7px;
  padding: 5px 12px;
  white-space: nowrap;
}
.an-mode.is-warn {
  color: var(--warn);
  border-color: color-mix(in srgb, var(--warn) 40%, transparent);
}

.an-switch { margin: 0 0 18px; }
.an-loading { display: flex; align-items: center; gap: 10px; color: var(--text-dim); padding: 32px 0; }
.an-muted { color: var(--text-dim); font-size: 14px; }
.an-scroll { overflow-x: auto; }

/* ── chips ─────────────────────────────────────────────────────────────── */
.an-stance, .an-verdict, .an-level {
  display: inline-block;
  font-size: 13px;
  border-radius: 7px;
  padding: 4px 11px;
  white-space: nowrap;
  border: 1px solid transparent;
}
.an-stance.is-bullish, .an-verdict.is-good, .an-level.is-good {
  color: var(--up);
  background: color-mix(in srgb, var(--up) 12%, transparent);
  border-color: color-mix(in srgb, var(--up) 28%, transparent);
}
.an-stance.is-bearish, .an-verdict.is-bad, .an-level.is-bad {
  color: var(--down);
  background: color-mix(in srgb, var(--down) 12%, transparent);
  border-color: color-mix(in srgb, var(--down) 28%, transparent);
}
.an-verdict.is-warn, .an-stance.is-split {
  color: var(--warn);
  background: color-mix(in srgb, var(--warn) 12%, transparent);
  border-color: color-mix(in srgb, var(--warn) 28%, transparent);
}
.an-stance.is-neutral, .an-verdict.is-muted, .an-level.is-muted {
  color: var(--text-dim);
  background: color-mix(in srgb, var(--text-dim) 10%, transparent);
  border-color: var(--border);
}
b.is-good { color: var(--up); }
b.is-bad { color: var(--down); }

/* Search: the desk's payload is already in memory, so this filters rather than fetches. */
.an-controls {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-bottom: 18px;
}
/* `align-items: center` centres the *margin* box, so the segmented control's own 18px bottom
   margin was tipping it half that distance above the search field beside it. The row owns the
   spacing below it now, and the two controls carry the same height. */
.an-controls > .an-switch { margin-bottom: 0; }
.an-controls > .an-search input { min-height: 45px; }
.an-search { position: relative; flex: 1; min-width: 260px; max-width: 460px; }
.an-search input {
  width: 100%; padding: 10px 34px 10px 14px;
  border: 1px solid var(--border); border-radius: 11px;
  background: var(--surface-soft); color: var(--text); font: inherit; font-size: 13.5px;
}
.an-search input::placeholder { color: var(--text-xfaint); }
.an-search input:focus {
  outline: none; border-color: color-mix(in srgb, var(--accent) 45%, transparent);
  background: var(--surface-hover);
}
.an-search input::-webkit-search-cancel-button { display: none; }
.an-search-clear {
  position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
  width: 22px; height: 22px; border-radius: 50%; border: 0; background: none;
  color: var(--text-faint); font-size: 17px; line-height: 1; cursor: pointer;
}
.an-search-clear:hover { color: var(--text); background: var(--surface-hover); }

.an-found + .an-found { margin-top: 18px; }
.an-found-head {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  flex-wrap: wrap; margin-bottom: 14px;
}
.an-found-head .an-section { margin: 0; }
.an-found-head .an-asset { font-size: 20px; }
.an-found-tally { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.an-found .an-voice { display: block; margin-top: 7px; }
.an-found .an-voice::after { content: ""; }

/* Wall Street: what price alone cannot tell you. */
.ws-card { margin-bottom: 18px; }
.ws-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 16px; }
.ws-head .an-section { margin: 0; }
.ws-head .an-voice::after { content: ""; }
.ws-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(128px, 1fr)); gap: 14px;
}
.ws-stat {
  display: grid; gap: 4px; padding: 12px 14px;
  border: 1px solid var(--border); border-radius: 11px; background: var(--surface-soft);
}
.ws-label { color: var(--text-faint); font-size: 11px; text-transform: uppercase; letter-spacing: .05em; }
.ws-value { font-size: 16px; font-variant-numeric: tabular-nums; }
.ws-value .an-name { display: inline; margin-left: 5px; font-size: 11px; }
.ws-value.is-up { color: var(--up); }
.ws-value.is-down { color: var(--down); }
.ws-cases { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 18px; margin-top: 18px; }
.ws-cases h4 { margin: 0 0 8px; font-size: 12px; text-transform: uppercase; letter-spacing: .05em; font-weight: 500; }
.ws-cases h4.is-up { color: var(--up); }
.ws-cases h4.is-down { color: var(--down); }
.ws-cases ul { margin: 0; padding-left: 18px; display: grid; gap: 7px; }
.ws-cases li { color: var(--text-dim); font-size: 13px; line-height: 1.6; }

.pf-lev {
  display: inline-block; margin-left: 6px; padding: 1px 6px; border-radius: 7px;
  font-size: 10.5px; font-variant-numeric: tabular-nums;
  color: var(--warn);
  border: 1px solid color-mix(in srgb, var(--warn) 30%, transparent);
  background: color-mix(in srgb, var(--warn) 8%, transparent);
}
.pf-dust-row td { color: var(--text-xfaint); }
.pf-table .is-up { color: var(--up); }
.pf-table .is-down { color: var(--down); }

/* The shortlists are the point of the page, so they are given real weight: a full-width box
   each, a heavier heading, and the qualifying reasons as chips rather than a run-on line. */
.stat-ops {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(430px, 1fr));
  align-items: stretch; gap: 20px; margin-top: 22px;
}
/* `.overview-card` carries no border of its own, so setting only `border-color` below drew
   nothing at all and the two shortlists floated on the page with no box around them. */
.stat-op {
  padding: 26px 26px 28px;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface-soft);
}
.stat-op.is-good { border-color: color-mix(in srgb, var(--accent) 26%, transparent); }
.stat-op.is-bad { border-color: color-mix(in srgb, var(--down) 24%, transparent); }
.stat-op h3 { display: flex; align-items: center; gap: 10px; margin: 0 0 6px; font-size: 18px; font-weight: 500; }
.stat-op-dot { width: 9px; height: 9px; border-radius: 50%; flex: none; }
.stat-op-dot.is-good { background: var(--up); }
.stat-op-dot.is-bad { background: var(--down); }
.stat-op-list { list-style: none; margin: 16px 0 0; padding: 0; display: grid; gap: 2px; }
.stat-op-list li {
  display: grid; gap: 8px; padding: 13px 12px; border-radius: 11px; cursor: pointer;
  border-top: 1px solid var(--border);
}
.stat-op-list li:first-child { border-top: 0; }
.stat-op-list li:hover { background: var(--surface-hover); }
.stat-op-head { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.stat-op-head b { font-size: 15px; }
.stat-op-icon { width: 22px; height: 22px; border-radius: 50%; flex: none; }
.stat-op-icon.is-text {
  display: grid; place-items: center; font-size: 9px;
  background: var(--surface-hover); color: var(--text-dim);
}
.stat-op-name { color: var(--text-dim); font-size: 13px; }
.stat-op-rank { margin-left: auto; color: var(--text-xfaint); font-size: 12px; font-variant-numeric: tabular-nums; }
.stat-op-why { display: flex; flex-wrap: wrap; gap: 6px; }
.stat-op-tag {
  font-style: normal; font-size: 11.5px; padding: 3px 9px; border-radius: 7px;
  border: 1px solid var(--border); color: var(--text-dim);
}
.stat-op-tag.is-good { color: var(--up); border-color: color-mix(in srgb, var(--up) 28%, transparent); background: color-mix(in srgb, var(--up) 7%, transparent); }
.stat-op-tag.is-bad { color: var(--down); border-color: color-mix(in srgb, var(--down) 26%, transparent); background: color-mix(in srgb, var(--down) 7%, transparent); }

/* The three list cards get the same treatment so the page reads as one set of sections. The
   selector is `.card`, not `.overview-card` - the list cards never had the latter class, so
   the old rule matched nothing. */
.overview-lists { gap: 20px; align-items: stretch; }
.overview-lists .stats-list-card { padding: 22px 22px 18px; display: flex; flex-direction: column; }
.overview-lists .stats-list-card.is-wide { grid-column: 1 / -1; }
/* Across the full width, the rows get room to breathe rather than stretching one column's
   worth of content over three. */
.stats-list-card.is-wide .list-row { max-width: none; }
.overview-lists .list-head { font-size: 16px; margin-bottom: 6px; }

/* A card holding one row next to a card holding five looked broken rather than quiet. Empty
   slots keep every box the same shape whatever the market is doing, and read as "nothing more
   qualified" rather than as missing content. */
/* Matched to a real row (31px) so a padded card is exactly as tall as a full one, rather
   than 42px taller and drawing attention to the very thing the padding is hiding. */
.list-row.is-empty { min-height: 31px; opacity: .45; }
/* The message occupies exactly one row's worth of space, so an empty card is the same height
   as a full one rather than 14px taller. */
.list-empty-note {
  min-height: 31px; display: flex; align-items: center;
  color: var(--text-xfaint); font-size: 13px;
}
.list-row.is-empty::before {
  content: "—"; color: var(--text-xfaint); font-size: 12px;
}
.stat-op-list li.is-empty {
  min-height: 46px; cursor: default; display: flex; align-items: center;
  color: var(--text-xfaint); font-size: 12px;
}
.stat-op-list li.is-empty:hover { background: none; }

/* Wall Street experts: track record first, current calls beneath. */
.ws-rank { margin-left: auto; text-align: right; font-size: 15px; font-variant-numeric: tabular-nums; }
.ws-rank .an-name { display: block; margin-top: 1px; }
.ws-stars { margin-left: auto; color: var(--warn); font-size: 12px; letter-spacing: 1px; }
.ws-call-rating {
  padding: 3px 10px; border-radius: 7px; font-size: 11.5px;
  border: 1px solid var(--border); color: var(--text-dim);
}
.ws-call-rating.is-buy { color: var(--up); border-color: color-mix(in srgb, var(--up) 30%, transparent); background: color-mix(in srgb, var(--up) 8%, transparent); }
.ws-call-rating.is-sell { color: var(--down); border-color: color-mix(in srgb, var(--down) 30%, transparent); background: color-mix(in srgb, var(--down) 8%, transparent); }
.ws-call-date { margin-left: auto; color: var(--text-xfaint); font-size: 11.5px; }

.ws-split { display: grid; gap: 10px; }
.ws-split-row { display: grid; grid-template-columns: 46px 1fr 44px; align-items: center; gap: 10px; font-size: 13px; }
.ws-split-row b { text-align: right; font-variant-numeric: tabular-nums; }
.ws-track { height: 6px; border-radius: 999px; background: var(--surface-hover); overflow: hidden; }
.ws-track u { display: block; height: 100%; }
.ws-track u.is-up { background: var(--up); }
.ws-track u.is-down { background: var(--down); }
.ws-track u.is-flat { background: var(--text-xfaint); }

/* Leads we cannot price: visible, but never mistaken for a tradeable row. */
.an-unresolved {
  /* Room above it. It follows the board and is a different kind of thing - a lead nobody can
     price yet - so it should not read as one more row of it. */
  margin: 30px 0 18px;
  border-style: dashed;
}
.an-unresolved-list { list-style: none; margin: 14px 0 0; padding: 0; display: grid; gap: 2px; }
.an-unresolved-list li {
  display: grid; gap: 6px; padding: 12px; border-radius: 10px; cursor: help;
  border-top: 1px solid var(--border);
}
.an-unresolved-list li:first-child { border-top: 0; }
.an-unresolved-list li:hover { background: var(--surface-hover); }
.an-unresolved-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.an-unresolved-list li.is-explained::after {
  content: "Not enough information — we cannot price this asset yet, so it is filed as research.";
  color: var(--warn); font-size: 12px;
}
.an-unresolved .an-quote em { font-style: normal; color: var(--text-xfaint); }

/* Asset page: who is on record, and where to trade it. */
.asset-voices, .asset-venues { margin-top: 18px; padding: 20px 22px 22px; }
.asset-voice-scroll { overflow-x: auto; margin-top: 6px; }
.asset-voices .an-table { font-size: 14px; }
.asset-voices .an-table th { padding: 0 12px 10px; }
.asset-voices .an-table td { padding: 14px 12px; }
.asset-voice-kind { display: block; margin-top: 3px; color: var(--text-xfaint); font-size: 11.5px; }
.asset-voice-why { color: var(--text-dim); font-size: 13px; }
.asset-voice-why .an-quote { margin-top: 0; }
.asset-voice-why .an-voice { display: block; margin-top: 6px; }
.asset-voice-why .an-voice::after { content: ""; }
.an-stance { padding: 3px 10px; border-radius: 7px; font-size: 11.5px; border: 1px solid var(--border); }
.an-stance.is-bullish { color: var(--up); border-color: color-mix(in srgb, var(--up) 30%, transparent); background: color-mix(in srgb, var(--up) 8%, transparent); }
.an-stance.is-bearish { color: var(--down); border-color: color-mix(in srgb, var(--down) 30%, transparent); background: color-mix(in srgb, var(--down) 8%, transparent); }

.asset-venue-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 10px; margin-top: 12px;
}
.asset-venue {
  display: grid; gap: 3px; padding: 13px 15px; text-decoration: none;
  border: 1px solid var(--border); border-radius: 12px; background: var(--surface-soft);
  color: var(--text); transition: border-color .16s var(--ease), background .16s var(--ease);
}
.asset-venue:hover { border-color: var(--accent); background: var(--surface-hover); }
.asset-venue b { font-size: 14px; font-weight: 500; }
.asset-venue span { font-size: 11.5px; color: var(--text-dim); }
.asset-venue-note { margin: 14px 0 0; color: var(--text-xfaint); font-size: 11.5px; line-height: 1.6; }

/* The expert profile head: a card like every other, rather than a name floating on the page. */
.an-profile-head {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  padding: 22px 24px; margin: 16px 0 18px;
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-soft);
}
.an-profile-head h2 { margin: 0 0 4px; font-size: 22px; font-weight: 500; }
.an-profile-head .an-beat { margin: 0; }
.an-profile-tally { margin-left: auto; display: grid; gap: 5px; justify-items: end; }

/* The metrics chooser. */
.metrics-add {
  flex: none; width: 38px; height: 38px; border-radius: 11px;
  border: 1px solid var(--border); background: var(--surface-soft);
  color: var(--text-dim); font-size: 19px; line-height: 1; cursor: pointer;
  transition: border-color .16s var(--ease), color .16s var(--ease), background .16s var(--ease);
}
.metrics-add:hover { border-color: var(--accent); color: var(--accent); background: var(--surface-hover); }
.metrics-sheet { position: fixed; inset: 0; z-index: var(--z-modal); display: grid; place-items: center; }
.metrics-sheet[hidden] { display: none; }
.metrics-backdrop { position: absolute; inset: 0; background: var(--scrim); backdrop-filter: blur(3px); }
.metrics-dialog {
  position: relative; width: min(880px, 94vw); max-height: 86vh; overflow: auto;
  padding: 26px 28px 22px; border: 1px solid var(--border-strong);
  border-radius: var(--radius); background: var(--bg);
  box-shadow: 0 16px 40px color-mix(in srgb, var(--shade) 34%, transparent);
}
.metrics-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }
.metrics-head h2 { margin: 0 0 4px; font-size: 20px; font-weight: 500; }
.metrics-head p { margin: 0; color: var(--text-dim); font-size: 13px; }
.metrics-close {
  border: 0; background: none; color: var(--text-faint); font-size: 24px; line-height: 1; cursor: pointer;
}
.metrics-close:hover { color: var(--text); }
.metrics-cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(330px, 1fr)); gap: 18px; margin: 22px 0 18px; }
.metric-col {
  padding: 18px; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface-soft);
}
.metric-col header h3 { margin: 0 0 3px; font-size: 15px; font-weight: 500; }
.metric-col header p { margin: 0 0 14px; color: var(--text-faint); font-size: 12px; }
.metric-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; min-height: 60px; }
.metric-list.is-drop-target { outline: 1px dashed var(--accent); outline-offset: 6px; border-radius: 10px; }
.metric-chip {
  display: flex; align-items: center; gap: 10px; padding: 10px 12px;
  border: 1px solid var(--border); border-radius: 10px; background: var(--bg); cursor: grab;
}
.metric-chip.is-dragging { opacity: .4; }
.metric-chip.is-core { border-style: dashed; }
.metric-grip { color: var(--text-xfaint); font-size: 13px; }
.metric-copy { display: grid; gap: 1px; flex: 1; min-width: 0; }
.metric-copy b { font-size: 13.5px; font-weight: 500; }
.metric-copy em { font-style: normal; color: var(--text-faint); font-size: 11.5px; }
.metric-lock { color: var(--text-xfaint); font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em; }
.metric-drop { border: 0; background: none; color: var(--text-faint); font-size: 17px; line-height: 1; cursor: pointer; }
.metric-drop:hover { color: var(--down); }
.metric-picker { margin-top: 12px; }
.metric-picker summary { cursor: pointer; color: var(--accent); font-size: 13px; }
.metric-picker ul { list-style: none; margin: 10px 0 0; padding: 0; display: grid; gap: 6px; }
.metric-picker button {
  width: 100%; display: grid; gap: 1px; text-align: left; padding: 9px 11px;
  border: 1px solid var(--border); border-radius: 9px; background: var(--bg); color: var(--text); cursor: pointer;
}
.metric-picker button:hover { border-color: var(--accent); }
.metric-picker b { font-size: 13px; font-weight: 500; }
.metric-picker em { font-style: normal; color: var(--text-faint); font-size: 11.5px; }
.metrics-foot { display: flex; justify-content: space-between; gap: 12px; }

.col-extra { white-space: nowrap; font-size: 12.5px; }
.col-extra .extra-price { display: block; }
/* These columns hold reference *levels*, not verdicts, so the gap is not coloured.
   A moving average below price is bullish and a support below price is ordinary; painting both
   red because the number is negative was colour saying something the number did not. The
   file's own rule applies - the chromatic budget belongs to the two things that genuinely mean
   up and down, and a level is a place, not a direction. */
.col-extra .extra-away { font-size: 11px; color: var(--text-faint); }
.col-extra .extra-source {
  margin-left: 5px; padding: 1px 5px; border-radius: 5px; font-size: 9.5px;
  color: var(--text-xfaint); border: 1px solid var(--border);
}

/* The desk is one bounded document. Its sections are separated by rules,
   not independent floating cards. */
#view-analysts {
  overflow: hidden;
  border: 1px solid var(--border-strong);
  border-radius: 26px;
  background: var(--bg-panel);
}
#view-analysts > .page-head {
  min-height: 136px;
  align-items: center;
  margin: 0;
  padding: 24px 28px;
  border-bottom: 1px solid var(--border);
}
#view-analysts > .page-head h1 { font-size: 25px; }
#view-analysts .eyebrow {
  color: var(--text-faint);
  font: 500 11px/1.2 ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
  letter-spacing: .14em;
  text-transform: uppercase;
}
#view-analysts .an-mode {
  border-radius: 9px;
  padding: 8px 13px;
  font: 12px ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
}
#view-analysts #analystRefresh { display: none; }
#view-analysts > .an-controls {
  display: grid;
  grid-template-columns: 1fr minmax(240px, 360px);
  align-items: center;
  gap: 18px;
  margin: 0;
  padding: 14px 28px;
  border-bottom: 1px solid var(--border);
}
/* The analyst desk used to strip these back to bare buttons with a static box on the active
   one, and hide the glide entirely. That made them the only switches in the application that
   snapped instead of gliding: the same control, in the same product, behaving two different
   ways depending on which tab you were standing in. They are the shared segmented control
   now, exactly like the header tabs and the dashboard's own switches - `width: max-content`
   is all this view still needs, so the pill does not stretch across its grid column. */
#view-analysts .an-switch,
#view-analysts .an-classes { width: max-content; margin: 0; }
#view-analysts .an-search { width: 100%; max-width: none; }
#view-analysts .an-search input {
  min-height: 38px;
  border-radius: 9px;
  background: transparent;
  font: 12px ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
}
/* The row is full width and carries the desk's separating rule; the switch inside it is the
   width of its own buttons. These were the same element, so the pill stretched the whole way
   across the panel with its last option floating in the middle of it. */
#view-analysts #analystBody > .an-classes-row {
  padding: 12px 28px;
  border-bottom: 1px solid var(--border);
}
/* The analyst and expert profiles sit in the same card as the rows above them and had no
   inset of their own, so "← All analysts" and everything under it ran flush into the card's
   own border. Same 28px the rest of this card uses, so nothing touches an edge. */
#view-analysts #analystBody > .an-profile {
  padding: 18px 28px 26px;
}
@media (max-width: 640px) {
  #view-analysts #analystBody > .an-classes-row,
  #view-analysts #analystBody > .an-profile { padding-left: 16px; padding-right: 16px; }
}
.an-classes-row { display: flex; }
.an-classes-row > .an-classes { width: max-content; margin: 0; }
#view-analysts .an-seg-count { display: none; }
#view-analysts .an-lede {
  grid-template-columns: 1fr 1fr;
  gap: 0;
  margin: 0;
  padding: 0;
  border-bottom: 1px solid var(--border);
}
#view-analysts .an-lede > div {
  min-height: 152px;
  padding: 28px;
}
#view-analysts .an-lede > div + div { border-left: 1px solid var(--border); }
#view-analysts .an-lede-kicker {
  display: block;
  margin-bottom: 10px;
  color: var(--text-faint);
  font: 500 11px/1.2 ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
  letter-spacing: .08em;
}
#view-analysts .an-lede h4 {
  margin: 0 0 16px;
  color: var(--text);
  font: 600 17px/1.3 -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  letter-spacing: -.01em;
  text-transform: none;
}
#view-analysts .an-lede .an-note { display: none; }
#view-analysts .an-lean-track { height: 7px; border-radius: 4px; }
#view-analysts .an-lean-counts { font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace; font-size: 11px; }
#view-analysts .an-lean-counts b { display: none; }
#view-analysts .an-tallychip {
  border-radius: 7px;
  background: transparent;
  font: 11px ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
}
#view-analysts .an-tallychip b { display: none; }
#view-analysts .an-board {
  gap: 0;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
}
#view-analysts .an-board-head,
#view-analysts .an-row-main {
  grid-template-columns: minmax(110px, .7fr) minmax(150px, 1fr) minmax(150px, .9fr) minmax(190px, 1.25fr) minmax(280px, 1.9fr);
  gap: 22px;
}
#view-analysts .an-board-head {
  margin: 0;
  padding: 15px 28px;
  border-bottom: 1px solid var(--border);
  font: 500 10.5px ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
  letter-spacing: .1em;
}
#view-analysts .an-row {
  min-height: 96px;
  padding: 22px 28px;
  border: 0;
  border-bottom: 1px solid var(--border);
  border-radius: 0;
}
#view-analysts .an-row:last-child { border-bottom: 0; }
#view-analysts .an-row:hover { border-color: var(--border); }
#view-analysts .ws-row:hover { background: var(--surface-hover); }
#view-analysts .an-stance,
#view-analysts .an-verdict,
#view-analysts .an-level {
  border-radius: 7px;
  background: transparent;
  font: 11px ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
}
#view-analysts .an-row-who {
  display: block;
  color: var(--text-dim);
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
}
#view-analysts .an-row-who .an-side { display: inline; }
#view-analysts .an-row-who .an-side-tag { display: none; }
#view-analysts .an-row-who .an-quote {
  margin-top: 8px;
  max-width: 68ch;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  font-size: 12px;
}
#view-analysts .ws-board .an-board-head,
#view-analysts .ws-board .an-row-main {
  grid-template-columns: minmax(180px, 1.3fr) minmax(90px, .5fr) minmax(230px, 1.2fr) minmax(200px, 1.3fr);
}

@media (max-width: 900px) {
  #view-analysts > .an-controls { grid-template-columns: 1fr; }
  #view-analysts .an-search { max-width: 440px; }
  #view-analysts .an-board-head { display: none; }
  #view-analysts .an-row-main { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 640px) {
  #view-analysts { border-radius: 18px; }
  #view-analysts > .page-head,
  #view-analysts > .an-controls,
  #view-analysts #analystBody > .an-classes,
  #view-analysts .an-lede > div,
  #view-analysts .an-row { padding-left: 18px; padding-right: 18px; }
  #view-analysts .an-lede { grid-template-columns: 1fr; }
  #view-analysts .an-lede > div + div { border-left: 0; border-top: 1px solid var(--border); }
  #view-analysts .an-switch,
  #view-analysts .an-classes { width: 100%; overflow-x: auto; }
  #view-analysts .an-row-main { grid-template-columns: 1fr; }
}

/* The subscribe page. Deliberately calm: somebody seeing this has probably just paid, or is
   about to, and a wall of red would read as an error rather than a next step. It covers the
   app rather than replacing it - the session is untouched and nothing is redirected. */
/* The subscribe page.

   Somebody seeing this has almost certainly just paid, or is about to, so it is painted in
   the same ink as the preview they arrived through rather than in the account's accent. That
   is not only consistency: a saturated blue call to action on a screen that exists to ask for
   money reads as an upsell, and this screen is closer to an apology than a pitch. */
.paywall {
  /* Above the tour layer too: this is the only thing a blocked account may see, and a tour
     that had already started would otherwise draw straight over it. */
  position: fixed; inset: 0; z-index: calc(var(--z-tour) + 10);
  display: grid; place-items: center; padding: 24px;
  overflow: hidden;

  --pw-ink: #ffffff;
  --pw-bg: #08080a;
  --pw-lift: #101013;
  --pw-border: color-mix(in srgb, var(--pw-ink) 10%, transparent);
  --pw-border-strong: color-mix(in srgb, var(--pw-ink) 18%, transparent);
  --pw-text: color-mix(in srgb, var(--pw-ink) 95%, transparent);
  --pw-dim: color-mix(in srgb, var(--pw-ink) 72%, transparent);
  --pw-faint: color-mix(in srgb, var(--pw-ink) 55%, transparent);
  background: var(--pw-bg);
  color: var(--pw-text);
}
.paywall[hidden] { display: none; }
/* One pool of light above the card, no colour. */
.paywall-aurora {
  position: absolute; inset: -30% -20% auto -20%; height: 620px; pointer-events: none;
  background: radial-gradient(46% 42% at 50% 8%,
    color-mix(in srgb, var(--pw-ink) 9%, transparent), transparent 72%);
  filter: blur(10px);
}
.paywall-card {
  position: relative; width: min(580px, 100%); text-align: center;
  padding: 46px 42px 32px;
  border: 1px solid var(--pw-border-strong); border-radius: 20px;
  background: var(--pw-lift);
  box-shadow: 0 40px 100px rgba(0, 0, 0, .6),
              inset 0 1px 0 color-mix(in srgb, var(--pw-ink) 7%, transparent);
  animation: gate-card-in .42s cubic-bezier(.16, .84, .28, 1) both;
}
.paywall-card h1 {
  margin: 22px 0 14px; font-size: 32px; font-weight: 640; letter-spacing: -.03em;
  color: var(--pw-text);
}
.paywall-card p {
  margin: 0 auto; max-width: 46ch; color: var(--pw-dim);
  font-size: 15px; line-height: 1.7;
}
.paywall-card p b { color: var(--pw-text); font-weight: 600; overflow-wrap: anywhere; }
.paywall-where { margin-top: 14px !important; }
.paywall-where a {
  color: var(--pw-text); text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--pw-ink) 32%, transparent);
  text-underline-offset: 3px;
}
.paywall-where a:hover { text-decoration-color: var(--pw-ink); }
.paywall-cta { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; margin: 30px 0 20px; }

/* The subscribe page owns these three now - it is the only screen that uses them - so they
   are stated here in ink rather than inheriting an accent from a landing page that no longer
   exists. Rectangular with a smoothed corner, like every other control in the gate. */
.paywall .landing-pill {
  border-radius: 8px;
  border-color: var(--pw-border-strong);
  background: color-mix(in srgb, var(--pw-ink) 5%, transparent);
  color: var(--pw-faint);
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase; padding: 6px 12px;
}
.paywall .landing-primary,
.paywall .landing-secondary {
  min-height: 50px; padding: 0 26px; border-radius: 11px;
  font-size: 14.5px; font-weight: 580; text-decoration: none;
}
.paywall .landing-primary { background: var(--pw-ink); color: var(--pw-bg); }
.paywall .landing-primary:hover {
  filter: none; transform: none;
  background: color-mix(in srgb, var(--pw-ink) 86%, var(--pw-bg));
}
.paywall .landing-secondary { border-color: var(--pw-border-strong); color: var(--pw-text); }
.paywall .landing-secondary:hover {
  transform: none;
  border-color: color-mix(in srgb, var(--pw-ink) 34%, transparent);
  background: color-mix(in srgb, var(--pw-ink) 6%, transparent);
}
.paywall-note { color: var(--pw-faint) !important; font-size: 13px !important; }
.paywall-out {
  margin-top: 26px; border: 0; background: none; color: var(--pw-faint);
  font-size: 13px; cursor: pointer;
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--pw-ink) 24%, transparent);
  text-underline-offset: 3px;
  transition: color .2s var(--ease), text-decoration-color .2s var(--ease);
}
.paywall-out:hover { color: var(--pw-text); text-decoration-color: var(--pw-ink); }
/* The app stays mounted behind the card, so scrolling it would be confusing. */
body.is-paywalled { overflow: hidden; }
@media (prefers-reduced-motion: reduce) {
  .paywall-aurora, .paywall-card { animation: none; }
}

/* ── table ─────────────────────────────────────────────────────────────── */
.an-table { width: 100%; border-collapse: collapse; font-size: 15px; }
.an-table th {
  text-align: left;
  font-size: 12px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-dim);
  font-weight: 500;
  padding: 0 14px 10px;
  white-space: nowrap;
}
.an-table td { padding: 16px 14px; border-top: 1px solid var(--border); vertical-align: top; }


.an-asset {
  border: 0;
  background: none;
  color: var(--text);
  font: inherit;
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  padding: 0;
}
.an-asset:hover { color: var(--accent); }
.an-name { display: block; color: var(--text-dim); font-size: 13px; margin-top: 3px; }
/* `.an-reason` is a span inside a cell, never the cell itself: `display: block` on a <td>
   drops it out of the table's column sizing, so the header keeps its full column width while
   the cell shrinks to its content - which is what left the Why column's rule hanging 378px
   past its rows. */
.an-reason { display: block; color: var(--text-dim); font-size: 13px; margin-top: 7px; max-width: 40ch; }
.an-why > .an-reason:first-child { margin-top: 0; }
.an-who { min-width: 220px; }

.an-quote {
  display: block;
  margin-top: 8px;
  padding-left: 11px;
  border-left: 2px solid var(--border);
  color: var(--text-dim);
  font-size: 13px;
  font-style: italic;
  max-width: 44ch;
}
.an-voice { color: var(--text-dim); font-size: 13px; text-decoration: none; }
.an-voice::after { content: " · "; }
.an-voice:last-child::after { content: ""; }
.an-voice:hover { color: var(--accent); }

/* ── the two bars ──────────────────────────────────────────────────────
   `an-lean` is which way a group points; `an-record` is how much of what they said our own
   read backs. Both are 8px tall on the same scale wherever they appear, so a record on one
   profile can be compared with a record on another by eye. */
.an-lean { display: block; }
.an-lean-track {
  display: block; height: 8px; border-radius: 999px; overflow: hidden;
  background: color-mix(in srgb, var(--down) 78%, transparent);
}
.an-lean-bull { display: block; height: 100%; background: var(--up); }
.an-lean-counts {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  margin-top: 8px; color: var(--text-dim); font-size: 12.5px;
}
.an-lean-counts b { color: var(--text); font-size: 17px; font-weight: 600; letter-spacing: -.01em; }
.an-lean-counts em { font-style: normal; color: var(--text-faint); margin-left: auto; }

.an-record { display: block; }
.an-record-track {
  display: flex; height: 8px; border-radius: 999px; overflow: hidden;
  background: color-mix(in srgb, var(--ink) 7%, transparent);
}
.an-record-good { display: block; height: 100%; background: var(--up); }
.an-record-bad { display: block; height: 100%; background: var(--down); }
.an-record-counts {
  display: block; margin-top: 7px; color: var(--text-dim); font-size: 12.5px;
}
.an-record-counts b { font-weight: 600; }

/* ── board lede ────────────────────────────────────────────────────────
   One strip, two halves. It replaced three cards - a donut and two bar charts - two of which
   restated what the list underneath already showed in the same order. */
.an-lede {
  display: grid; grid-template-columns: minmax(260px, 1fr) minmax(300px, 1.3fr);
  gap: 28px; align-items: start;
  padding: 4px 4px 24px; margin: 0 0 6px;
  border-bottom: 1px solid var(--border);
}
.an-lede h4 {
  margin: 0 0 14px; font-size: 12px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--text-dim); font-weight: 500;
}
.an-lede .an-note { margin-top: 14px; }
.an-tallies { display: flex; flex-wrap: wrap; gap: 8px; }
.an-tallychip {
  display: inline-flex; align-items: baseline; gap: 7px;
  padding: 5px 11px; border-radius: 7px; font-size: 12.5px;
  border: 1px solid var(--border); background: var(--surface); color: var(--text-dim);
}
.an-tallychip b { font-size: 14px; font-weight: 600; color: var(--text); }
.an-tallychip.is-good { border-color: color-mix(in srgb, var(--up) 28%, transparent); }
.an-tallychip.is-good b { color: var(--up); }
.an-tallychip.is-bad { border-color: color-mix(in srgb, var(--down) 28%, transparent); }
.an-tallychip.is-bad b { color: var(--down); }
.an-tallychip.is-warn { border-color: color-mix(in srgb, var(--warn) 28%, transparent); }
.an-tallychip.is-warn b { color: var(--warn); }
@media (max-width: 820px) { .an-lede { grid-template-columns: 1fr; gap: 22px; } }

/* ── the board, and Wall Street: rows on shared columns ────────────────
   Both were grids of bordered cards. Forty frames on one screen is a wall: every item shouts
   at the same volume and the page's own structure disappears inside them. The Dashboard's
   table carries far more per row and reads instantly, because the eye follows a column and a
   hairline is all that is needed to separate two things.

   Nothing was dropped to get here. The columns carry what lines up; the second line carries
   the two things that never could - the quote, and who is on each side. */
/* The board and the Wall Street table are the same object as the panel list.
   Same surface, same padding, same radius, same row behaviour - because they are three views
   of one idea and looked like three different products. `.an-people` is the reference. */
.an-board {
  display: grid;
  gap: 2px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-soft);
  padding: 6px;
  margin-bottom: 26px;
}
.an-board-head,
.an-row-main {
  display: grid;
  grid-template-columns:
    minmax(100px, .65fr) minmax(120px, .8fr) minmax(130px, .75fr)
    minmax(140px, .9fr) minmax(200px, 1.35fr) minmax(150px, 1fr);
  gap: 22px;
  align-items: start;
}
.an-board-head {
  padding: 6px 14px 10px; margin-bottom: 2px;
  font-size: 11px; letter-spacing: .07em; text-transform: uppercase; color: var(--text-faint);
  border-bottom: 1px solid var(--border);
}
.an-row {
  display: grid; gap: 7px;
  padding: 11px 14px 12px;
  border-radius: 11px;
  /* No hairline between rows, and no coloured rail down the left either. The verdict is
     already a chip in its own column; drawing it a second time as a stripe made every row
     look like an alert and made the board look like something other than a table. */
  border: 1px solid transparent;
  transition: background .15s var(--ease), border-color .15s var(--ease);
}
.an-row:hover { border-color: var(--border); }
.an-row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* What they actually said, in its own column rather than as a paragraph slung under the row.
   Full-width prose forced every row to be two rows tall and pushed the columns beside it out
   of alignment with the header. */
.an-row-said, .an-row-who { min-width: 0; }
/* Who said it, beside what they said, rather than as a paragraph slung under the row. */
.an-row-who { display: flex; flex-wrap: wrap; gap: 5px; align-content: start; }
.an-row-said .an-quote {
  margin: 0; max-width: none; font-size: 12.5px; line-height: 1.55;
  /* Four lines, then it stops. A five-minute monologue is not a column. */
  display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical;
  overflow: hidden;
}

.an-row-asset { display: grid; gap: 2px; align-content: start; justify-items: start; }
.an-row-asset .an-asset { text-align: left; }
.an-row-asset .an-asset { font-size: 16px; }
.an-row-asset .an-name { margin-top: 0; }

.an-row-panel { display: grid; gap: 7px; justify-items: start; }
.an-row-panel .an-lean { width: 100%; max-width: 160px; }
.an-row-tally { color: var(--text-faint); font-size: 12px; }

.an-row-read { display: flex; flex-wrap: wrap; gap: 7px; align-content: start; }

.an-row-verdict { display: grid; gap: 6px; justify-items: start; }
.an-row-reason { color: var(--text-dim); font-size: 12.5px; line-height: 1.55; }

/* The quiet second line. Indented under the asset column so the eye keeps its place. */
.an-row-detail {
  padding-top: 2px;
  display: grid; gap: 8px;
  padding-left: 2px;
  max-width: 120ch;
}
.an-row-detail .an-quote { margin-top: 0; max-width: none; }
.an-row-voices { display: grid; gap: 5px; }

@media (max-width: 1080px) {
  .an-board-head { display: none; }
  .an-row-main { grid-template-columns: 1fr 1fr; gap: 14px; }
}
@media (max-width: 620px) {
  .an-row-main { grid-template-columns: 1fr; }
}

/* Wall Street rides the same rails with its own column widths. */
.ws-board .an-board-head,
.ws-board .an-row-main {
  grid-template-columns:
    minmax(180px, 1.3fr) minmax(90px, .5fr) minmax(230px, 1.2fr) minmax(200px, 1.3fr);
}
.ws-row { cursor: pointer; }
.ws-row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.ws-row .an-avatar { width: 34px; height: 34px; font-size: 14px; }
.ws-row .an-row-asset { grid-template-columns: 34px 1fr; gap: 11px; align-items: center; }
.ws-rank-cell { display: grid; gap: 1px; font-variant-numeric: tabular-nums; }
.ws-rank-cell b { font-size: 15px; font-weight: 600; }
.ws-record {
  display: grid; gap: 4px; font-size: 12.5px; color: var(--text-dim); justify-items: start;
}
.ws-record .ws-stars { margin-left: 0; }
.ws-record b { color: var(--text); font-variant-numeric: tabular-nums; }
.ws-record b.is-up { color: var(--up); }
.ws-record b.is-down { color: var(--down); }
.ws-open { display: grid; gap: 5px; align-content: start; }
.ws-open-call { display: flex; align-items: center; gap: 7px; font-size: 12.5px; }

/* Both profiles open the same way: a way back on the left, the outside link on the right. */
/* The desk is a bounded panel with its own edge, and this row sat flush against it: the
   back button touched the left border and "open channel" touched the right. Controls do not
   sit on a border. */
/* Flush with the cards below it, not four pixels shy of them.
   A near-miss is worse than either extreme: the eye reads the button as touching the panel
   edge precisely because it almost lines up with it and does not. Zero inset puts its left
   edge on the same line as every card underneath. */
.an-profile-nav {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin-bottom: 16px;
  padding: 0;
}

/* Two figures on one line, above the calls, rather than four cards in front of them. */
.an-summary {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: clamp(18px, 3vw, 40px);
  padding: 18px 20px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-soft);
}
.an-summary-item h4 {
  margin: 0 0 10px;
  font-size: 10.5px; font-weight: 500; letter-spacing: .08em; text-transform: uppercase;
  color: var(--text-faint);
}
.an-summary-note { margin: 10px 4px 0; }

.an-video-summary {
  margin: 8px 0 0; color: var(--text-dim); font-size: 13.5px; line-height: 1.6; max-width: 90ch;
}

/* ── bars ──────────────────────────────────────────────────────────────── */

.an-bars { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.an-bars li { display: grid; grid-template-columns: 5.5rem 1fr auto; align-items: center; gap: 10px; }
.an-bar-name { font-size: 14px; }
.an-bar-track { height: 8px; border-radius: 999px; background: var(--border); overflow: hidden; }
.an-bar-fill { display: block; height: 100%; background: var(--accent); border-radius: 999px; }
.an-bar-count { color: var(--text-dim); font-size: 12px; white-space: nowrap; }

/* ── the panel, as a list ──────────────────────────────────────────────
   One row per person, four columns that line up down the page: who, their record, and which
   way they lean. A grid of cards let every record bar start at a different x, which is the
   one thing that makes a set of bars unreadable. */
.an-people {
  display: grid; gap: 2px;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface-soft); padding: 6px;
}
.an-people-head,
.an-person {
  display: grid; align-items: center; gap: 20px;
  /* The record column is capped rather than fluid. A bar 800px wide to show "11 of 13" is a
     proportion drawn at a size that implies precision it does not have, and on a wide screen
     it separated the name from its own numbers by half the page. */
  grid-template-columns: 34px minmax(140px, 1fr) minmax(200px, 340px) minmax(130px, .6fr) minmax(150px, .7fr);
  justify-content: start;
}
.an-people-head {
  padding: 6px 14px 10px; margin-bottom: 2px;
  border-bottom: 1px solid var(--border);
  font-size: 11px; letter-spacing: .07em; text-transform: uppercase; color: var(--text-faint);
}
.an-people-head > span:first-child { grid-column: 1 / 3; }
.an-person {
  width: 100%; text-align: left; padding: 11px 14px; border-radius: 11px;
  border: 1px solid transparent; background: none; color: inherit; font: inherit;
  cursor: pointer; transition: background .15s var(--ease), border-color .15s var(--ease);
}
.an-person:hover { background: var(--surface-hover); border-color: var(--border); }
.an-person:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.an-person-who b { display: block; font-size: 15px; font-weight: 500; }
.an-person-lean { display: grid; gap: 5px; justify-items: start; }
.an-person-split { color: var(--text-faint); font-size: 12px; }
.an-person .an-avatar { width: 34px; height: 34px; font-size: 14px; }
.an-person-pick { display: grid; gap: 5px; justify-items: start; }
.an-pick { display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.an-pick b { font-size: 14.5px; font-weight: 500; }

@media (max-width: 900px) {
  .an-people-head { display: none; }
  .an-person { grid-template-columns: 34px 1fr; row-gap: 10px; }
  .an-person-record, .an-person-lean, .an-person-pick { grid-column: 2; }
}

.an-avatar {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  color: var(--accent);
  font-weight: 700;
  font-size: 17px;
}
.an-avatar.is-large { width: 58px; height: 58px; font-size: 23px; }
.an-who-name b { display: block; font-size: 16px; }
.an-beat { color: var(--text-dim); font-size: 13px; }
.an-tally { color: var(--text-dim); font-size: 13px; }

/* ── profile ───────────────────────────────────────────────────────────── */
.an-back {
  border: 1px solid var(--border);
  background: var(--surface-soft);
  color: var(--text);
  font: inherit;
  font-size: 14px;
  border-radius: 10px;
  padding: 7px 15px;
  cursor: pointer;
}
.an-back:hover { border-color: var(--accent); color: var(--accent); }


.an-cards {
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  align-items: start;
  margin-bottom: 28px;
}
.an-card {
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface-soft); padding: 20px 22px 22px;
}
.an-card .an-section { margin-top: 0; }
.an-card h4 + .an-record, .an-card h4 + .an-lean { margin-top: 2px; }
.an-card h4 {
  margin: 0 0 14px;
  font-size: 12px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-dim);
  font-weight: 500;
}
.an-card-figure { display: flex; align-items: center; gap: 18px; }
.an-legend { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; font-size: 14px; }
.an-legend i { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 8px; }
.an-legend i.is-good { background: var(--up); }
.an-legend i.is-bad { background: var(--down); }
.an-note { color: var(--text-dim); font-size: 12px; margin: 14px 0 0; line-height: 1.5; }

.an-section {
  font-size: 13px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-dim);
  font-weight: 500;
  margin: 28px 0 12px;
}

.an-videos { list-style: none; margin: 0; padding: 0; display: grid; gap: 18px; }
.an-video-head a { color: var(--text); text-decoration: none; font-size: 16px; font-weight: 500; }
.an-video-head a:hover { color: var(--accent); }
.an-meta { display: block; color: var(--text-dim); font-size: 13px; margin-top: 5px; }
.an-points { list-style: none; margin: 10px 0 0; padding: 0; display: grid; gap: 7px; }
.an-points li {
  color: var(--text-dim);
  font-size: 14px;
  line-height: 1.55;
  padding-left: 14px;
  position: relative;
  max-width: 90ch;
}
.an-points li::before { content: "·"; position: absolute; left: 4px; }

@media (max-width: 860px) {
  .an-table th:nth-child(4), .an-table td:nth-child(4),
  .an-table th:nth-child(5), .an-table td:nth-child(5) { display: none; }
}

/* Each side of an argument gets its own run of names, tagged with its count. */
.an-side { display: block; margin-bottom: 7px; }
.an-side:last-of-type { margin-bottom: 0; }
.an-side-tag {
  display: inline-block;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  border-radius: 5px;
  padding: 2px 7px;
  margin-right: 8px;
  vertical-align: 1px;
}
.an-side.is-bullish .an-side-tag {
  color: var(--up);
  background: color-mix(in srgb, var(--up) 14%, transparent);
}
.an-side.is-bearish .an-side-tag {
  color: var(--down);
  background: color-mix(in srgb, var(--down) 14%, transparent);
}

/* The profile is a wide page, so its tables and lists get room. Line length is still capped
   for readability - the fix for a wide screen is more columns, not longer lines. */
/* The fixed four-column layout and the suppressed scroll below both belong to the *creator*
   profile, whose table has exactly four columns. The expert table has six, so forcing those
   rules on it pushed "Our trend" and "Our valuation" off the right edge with no way to reach
   them. It sizes to its content and scrolls if it has to. */
.an-profile.is-expert .an-table { table-layout: auto; min-width: 760px; }
.an-profile.is-expert .an-scroll { overflow-x: auto; }
.an-profile:not(.is-expert) .an-table { table-layout: fixed; width: 100%; min-width: 0; }
.an-profile:not(.is-expert) .an-table th:nth-child(1), .an-profile:not(.is-expert) .an-table td:nth-child(1) { width: 22%; }
.an-profile:not(.is-expert) .an-table th:nth-child(2), .an-profile:not(.is-expert) .an-table td:nth-child(2) { width: 13%; }
.an-profile:not(.is-expert) .an-table th:nth-child(3), .an-profile:not(.is-expert) .an-table td:nth-child(3) { width: 18%; }
.an-profile:not(.is-expert) .an-table th:nth-child(4), .an-profile:not(.is-expert) .an-table td:nth-child(4) { width: 47%; }
/* The table already fits, so the scroll container must not introduce one - an overflow here
   is what let the panel's own border run through the last column. */
.an-profile:not(.is-expert) .an-scroll { overflow-x: visible; }
.an-profile .an-table td { word-break: break-word; }
.an-profile .an-reason { max-width: none; }
.an-profile .an-quote { max-width: none; }

.an-profile .an-videos {
  grid-template-columns: repeat(auto-fill, minmax(430px, 1fr));
  gap: 24px 32px;
  align-items: start;
}
.an-profile .an-points li { max-width: none; }

/* ── Data desk ─────────────────────────────────────────────────────────── */
#view-sources { max-width: none; }

.an-bars.is-wide li { grid-template-columns: 6.5rem 1fr auto; }
.an-bar-fill.is-good { background: var(--up); }
.an-bar-fill.is-bad { background: var(--down); }

.an-bar-fill.is-warn { background: var(--warn); }

/* ── Statistics: the outside view ──────────────────────────────────────── */
.stat-outside { grid-column: 1 / -1; margin-top: 16px; }
.stat-outside-sub { color: var(--text-dim); font-size: 13px; margin: 0 0 14px; }
.stat-outside-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 2px;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  padding: 6px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-soft);
}
/* Same row as the panel and the shortlists: nothing drawn until the pointer arrives. */
.stat-outside-list li {
  border: 1px solid transparent;
  border-radius: 11px;
  padding: 12px 14px;
  cursor: pointer;
  transition: background .15s var(--ease), border-color .15s var(--ease);
}
.stat-outside-list li:hover { background: var(--surface-hover); border-color: var(--border); }
.stat-outside-head { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.stat-outside-head b { font-size: 16px; }
.stat-outside-count { color: var(--text-dim); font-size: 12px; margin-left: auto; }
.stat-outside-why { display: block; color: var(--text-dim); font-size: 13px; margin-top: 7px; line-height: 1.45; }

/* Tour: progress, the click hint, and letting clicks through on interactive steps. */
.tour-progress {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  border-radius: 16px 16px 0 0;
  overflow: hidden;
  background: var(--border-strong);
}
.tour-progress span {
  display: block;
  height: 100%;
  width: 0;
  background: var(--accent);
  transition: width .42s var(--ease);
}
.tour-hint {
  margin: 12px 0 0 !important;
  color: var(--accent) !important;
  font-size: 12.5px !important;
  font-weight: 600;
}
.tour-hint[hidden] { display: none; }

/* On a "click this" step the overlay must not eat the click it is asking for. The spotlight
   already has pointer-events: none, so only the card needs to stay interactive. */
.tour-layer.is-interactive { pointer-events: none; }
.tour-layer.is-interactive .tour-card { pointer-events: auto; }
.tour-spot { animation: tour-pulse 2.4s var(--ease) infinite; }
@keyframes tour-pulse {
  0%, 100% { box-shadow: 0 0 0 9999px var(--scrim), 0 0 0 1.5px var(--accent),
                         0 0 26px color-mix(in srgb, var(--accent) 35%, transparent); }
  50% { box-shadow: 0 0 0 9999px var(--scrim), 0 0 0 2.5px var(--accent),
                    0 0 34px color-mix(in srgb, var(--accent) 55%, transparent); }
}
.tour-spot[hidden] { display: none; }
@media (prefers-reduced-motion: reduce) {
  .tour-spot { animation: none; }
  .tour-progress span { transition: none; }
}

/* Per-class switch on the two desks. The count makes an empty market obvious before you
   click into it. */
.an-classes { margin: 0 0 18px; }
.an-seg-count {
  display: inline-block;
  margin-left: 7px;
  padding: 1px 6px;
  border-radius: 5px;
  font-size: 11px;
  background: color-mix(in srgb, var(--text) 10%, transparent);
  color: var(--text-dim);
}
.seg.is-active .an-seg-count { color: var(--text); }

/* Profile sections use the same panel language as the Dashboard cards, so a page never
   changes its visual rules halfway down. */
.an-panel {
  display: block;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-soft);
  padding: 4px 18px 18px;
  margin-bottom: 14px;
}
.an-panel .an-section { margin-top: 18px; }
.an-video {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-soft);
  padding: 14px 16px;
}
.an-profile .an-videos { gap: 14px; }

/* ── Indicator settings: real controls ─────────────────────────────────────
   The grid rule above sizes every `input`, which caught checkboxes too - they kept the
   platform's own blue tick and ignored the theme entirely. Both controls are rebuilt here:
   the native element stays for semantics and keyboard use, and is painted over. */

/* Checkbox -> switch. The `<i>` is the track; the pseudo-element is the knob. */
.asset-settings-group .asset-chart-setting-toggle input[type="checkbox"] {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
  margin: 0;
  pointer-events: none;
}
.asset-settings-group .asset-chart-setting-toggle {
  cursor: pointer;
  transition: border-color .18s var(--ease), background .18s var(--ease);
}
.asset-settings-group .asset-chart-setting-toggle:hover { border-color: var(--border-strong); }
.asset-settings-group .asset-chart-setting-toggle i {
  position: relative;
  flex: 0 0 auto;
  display: block;
  width: 34px;
  height: 19px;
  border-radius: 999px;
  border: 1px solid var(--border-strong);
  background: color-mix(in srgb, var(--shade) 30%, transparent);
  transition: background .18s var(--ease), border-color .18s var(--ease);
}
.asset-settings-group .asset-chart-setting-toggle i::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 13px;
  height: 13px;
  border-radius: 50%;
  background: var(--text-faint);
  transition: transform .18s var(--ease), background .18s var(--ease);
}
.asset-settings-group .asset-chart-setting-toggle input:checked + i {
  background: color-mix(in srgb, var(--accent) 34%, transparent);
  border-color: color-mix(in srgb, var(--accent) 62%, transparent);
}
.asset-settings-group .asset-chart-setting-toggle input:checked + i::after {
  transform: translateX(15px);
  background: var(--accent);
}
.asset-settings-group .asset-chart-setting-toggle input:focus-visible + i {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Select -> themed control with our own chevron. */
.asset-chart-settings-grid select,
.asset-settings-group select {
  width: 100%;
  height: 32px;
  padding: 0 28px 0 9px;
  outline: none;
  border: 1px solid var(--border);
  border-radius: 9px;
  color: var(--text);
  background-color: color-mix(in srgb, var(--shade) 16%, transparent);
  font: inherit;
  font-size: 11px;
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--text-faint) 50%),
    linear-gradient(135deg, var(--text-faint) 50%, transparent 50%);
  background-position: calc(100% - 15px) 13px, calc(100% - 10px) 13px;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  transition: border-color .18s var(--ease);
}
.asset-chart-settings-grid select:hover,
.asset-settings-group select:hover { border-color: var(--border-strong); }
.asset-chart-settings-grid select:focus,
.asset-settings-group select:focus { border-color: color-mix(in srgb, var(--accent) 35%, transparent); }
/* The dropdown list itself is drawn by the OS; this is the one part we can colour. */
.asset-chart-settings-grid select option,
.asset-settings-group select option { background: var(--bg-lift); color: var(--text); }

/* Number inputs: kill the spinner so the value is not squeezed by stepper arrows. */
.asset-chart-settings-grid input[type="number"] { appearance: textfield; -moz-appearance: textfield; }
.asset-chart-settings-grid input[type="number"]::-webkit-outer-spin-button,
.asset-chart-settings-grid input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* A long settings list has to scroll inside the dialog, never past the window. */
.asset-settings-body { overscroll-behavior: contain; scrollbar-width: thin; }
.asset-settings-body::-webkit-scrollbar { width: 10px; }
.asset-settings-body::-webkit-scrollbar-thumb {
  border: 3px solid transparent;
  background-clip: content-box;
  border-radius: 999px;
  background-color: var(--border-strong);
}

/* An arrow that points at whatever the tour is asking you to click. It sits below the
   highlighted element by default and flips above when there is no room underneath. */
.tour-pointer {
  position: absolute;
  width: 30px;
  height: 44px;
  color: var(--accent);
  pointer-events: none;
  filter: drop-shadow(0 0 10px color-mix(in srgb, var(--accent) 55%, transparent));
  animation: tour-point 1.15s var(--ease) infinite;
  transition: left .3s var(--ease), top .3s var(--ease);
}
.tour-pointer[hidden] { display: none; }
.tour-pointer svg { width: 100%; height: 100%; display: block; }
/* Pointing up at the element above it is the default; flipped when shown underneath. */
.tour-pointer.is-above { transform: rotate(180deg); }
@keyframes tour-point {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-7px); }
}
.tour-pointer.is-above { animation-name: tour-point-above; }
@keyframes tour-point-above {
  0%, 100% { transform: rotate(180deg) translateY(0); }
  50% { transform: rotate(180deg) translateY(-7px); }
}
@media (prefers-reduced-motion: reduce) {
  .tour-pointer { animation: none; }
}

/* ── Statistics: buy / sell opportunities ──────────────────────────────── */
.stat-ops {
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
  margin-top: 16px;
}
.stat-op h3 { display: flex; align-items: center; gap: 9px; }
.stat-op-dot { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto; }
.stat-op-dot.is-good { background: var(--up); box-shadow: none; }
.stat-op-dot.is-bad { background: var(--down); box-shadow: none; }

/* The same row as the analyst panel, so the two pages read as one product.
   No hairlines between rows; a transparent border that fades in under the pointer. */
.stat-op-list {
  list-style: none; margin: 14px 0 0; padding: 6px; display: grid; gap: 2px;
  counter-reset: op;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface-soft);
}
.stat-op-list li {
  position: relative;
  padding: 11px 14px 12px 34px;
  border: 1px solid transparent;
  border-radius: 11px;
  cursor: pointer;
  transition: background .15s var(--ease), border-color .15s var(--ease);
}
.stat-op-list li:hover { background: var(--surface-hover); border-color: var(--border); }
.stat-op-list li::before {
  counter-increment: op;
  content: counter(op);
  position: absolute;
  left: 13px;
  top: 13px;
  color: var(--text-xfaint);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}
.stat-op-head { display: flex; align-items: baseline; gap: 9px; flex-wrap: wrap; }
.stat-op-head b { font-size: 16px; }
.stat-op-name { color: var(--text-dim); font-size: 13px; flex: 1 1 auto; }
.stat-op-agree {
  font-size: 11px;
  border-radius: 5px;
  padding: 2px 7px;
  white-space: nowrap;
}
.stat-op-agree.is-good { color: var(--up); background: color-mix(in srgb, var(--up) 14%, transparent); }
.stat-op-agree.is-bad { color: var(--down); background: color-mix(in srgb, var(--down) 14%, transparent); }
.stat-op-why { display: block; margin-top: 6px; color: var(--text-dim); font-size: 12.5px; line-height: 1.5; }

/* ── Themed dropdown ───────────────────────────────────────────────────────
   The native <select> stays in the DOM for its value, events and keyboard access; it is
   covered by a button we can style, and the option list is drawn ourselves because macOS
   renders its own and no CSS reaches it. */
.sel { position: relative; display: block; }
.sel select {
  position: absolute;
  inset: 0;
  opacity: 0;
  pointer-events: none;
}
.sel-button {
  width: 100%;
  height: 32px;
  padding: 0 28px 0 9px;
  text-align: left;
  border: 1px solid var(--border);
  border-radius: 9px;
  color: var(--text);
  background-color: color-mix(in srgb, var(--shade) 16%, transparent);
  font: inherit;
  font-size: 11px;
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--text-faint) 50%),
    linear-gradient(135deg, var(--text-faint) 50%, transparent 50%);
  background-position: calc(100% - 15px) 13px, calc(100% - 10px) 13px;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  transition: border-color .18s var(--ease);
}
.sel-button:hover { border-color: var(--border-strong); }
.sel-button[aria-expanded="true"] { border-color: color-mix(in srgb, var(--accent) 55%, transparent); }

.sel-list {
  position: fixed;
  z-index: calc(var(--z-modal) + 10);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 4px;
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  background: var(--bg-lift);
  box-shadow: 0 16px 40px color-mix(in srgb, var(--shade) 34%, transparent);
  scrollbar-width: thin;
}
.sel-option {
  display: block;
  width: 100%;
  padding: 7px 9px;
  text-align: left;
  border: 0;
  border-radius: 7px;
  background: none;
  color: var(--text-dim);
  font: inherit;
  font-size: 11.5px;
  cursor: pointer;
}
.sel-option:hover { background: var(--surface-hover); color: var(--text); }
.sel-option.is-on { color: var(--chrome-text); background: var(--chrome-fill); }

/* ── One loader, everywhere ────────────────────────────────────────────────
   The app had three loading idioms: a spinner, a breathing skeleton bar, and a bare line of
   text. A single circular loader means "still working" reads the same wherever it appears. */
.loader {
  display: grid;
  place-items: center;
  gap: 14px;
  padding: 44px 0;
  color: var(--text-dim);
  font-size: 13px;
  text-align: center;
}
.loader-ring {
  width: 42px;
  height: 42px;
  border-radius: 50%;
  border: 3px solid color-mix(in srgb, var(--accent) 16%, transparent);
  border-top-color: var(--accent);
  animation: alpha-spin .8s linear infinite;
}
.loader-ring.is-small { width: 22px; height: 22px; border-width: 2px; }
.loader-ring.is-large { width: 56px; height: 56px; border-width: 4px; }
/* An inline variant for a row of text, so the same circle is used at every size. */
.loader.is-inline { display: flex; padding: 22px 0; justify-content: flex-start; }
@media (prefers-reduced-motion: reduce) {
  .loader-ring { animation-duration: 2.4s; }
}

/* RMX dashboard. The Pine prints the matrix as a table in a chart corner; this is that table,
   as DOM rather than canvas so the numbers stay sharp at any zoom and can be selected. */
#assetPriceChart { position: relative; }
.rmx-dash {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 3;
  pointer-events: none;
  font-variant-numeric: tabular-nums;
  border-radius: 8px;
  overflow: hidden;
  border: 1px solid color-mix(in srgb, var(--border) 80%, transparent);
  background: color-mix(in srgb, #080808 88%, transparent);
  backdrop-filter: blur(3px);
}
.rmx-dash table { border-collapse: collapse; font-size: 10px; line-height: 1.05; }
.rmx-dash caption {
  padding: 4px 8px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .09em;
  color: #fff;
  text-align: center;
}
.rmx-dash th, .rmx-dash td { padding: 2px 7px; color: color-mix(in srgb, #fff 88%, transparent); }
.rmx-dash th {
  font-size: 9px;
  font-weight: 600;
  letter-spacing: .07em;
  color: color-mix(in srgb, #fff 62%, transparent);
  text-align: left;
}
.rmx-dash .rmx-dot { padding-right: 2px; text-align: center; }
.rmx-dash .rmx-net, .rmx-dash .rmx-pct, .rmx-dash .rmx-note { text-align: right; }
.rmx-dash .rmx-final td, .rmx-dash .rmx-signal td { font-weight: 700; }
/* On a phone the table would cover the chart it annotates. */
@media (max-width: 720px) { .rmx-dash { display: none; } }

/* A video whose transcript could not be read. Deliberately not a stance chip: it is the
   absence of a reading, and it must not look like one. */
.an-unread { font-style: italic; color: var(--text-faint); }

/* ---------- portfolio: the two halves ---------- */

/* Left is the customer's account and how much of it the systems may touch; right is the
   systems themselves. They scroll together as one page rather than as two panes, because a
   decision on the right almost always needs a number from the left to make sense. */
.pf-stack { display: grid; gap: 30px; align-items: start; }
/* The rotation body is a plain div holding a stack of cards, so without this its sections
   sit flush against each other and the whole column reads as one undifferentiated slab. */
#rotationBody { display: grid; gap: 18px; align-content: start; }
.pf-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  gap: 20px;
  align-items: start;
}
.pf-col { min-width: 0; display: grid; gap: 14px; align-content: start; }
/* Just the refresh control now, so it sits to the right on its own line. */
.pf-col-head {
  display: flex; align-items: center; justify-content: flex-end; gap: 14px;
  padding-bottom: 4px;
}
.pf-col-head h2 { margin: 4px 0 6px; font-size: 20px; font-weight: 500; letter-spacing: -.01em; }
.pf-col-head .rot-sub { max-width: 46ch; }

@media (max-width: 1180px) {
  .pf-split { grid-template-columns: 1fr; }
}

/* Read and trade are two permissions, and the toggle for the second one says which state it
   is in rather than only offering to change it. */
.pf-trade-toggle {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 12px; color: var(--text-dim); cursor: pointer; white-space: nowrap;
}
.pf-trade-toggle input { accent-color: var(--warn); }
.pf-trade-toggle input:checked + span { color: var(--warn); }

/* ---------- rotation desk ---------- */

.rot-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; }
.rot-head h2 { margin: 0 0 5px; font-size: 18px; font-weight: 500; }
.rot-sub { margin: 0; color: var(--text-dim); font-size: 12.5px; line-height: 1.6; }
.rot-muted { color: var(--text-faint); font-size: 12.5px; }

.rot-mode {
  flex: none; padding: 5px 12px; border-radius: 7px; font-size: 12px;
  border: 1px solid var(--border); color: var(--text-dim);
}
.rot-mode.is-good { color: var(--up); border-color: color-mix(in srgb, var(--up) 32%, transparent); }
.rot-mode.is-bad { color: var(--down); border-color: color-mix(in srgb, var(--down) 32%, transparent); }
.rot-mode.is-warn { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 32%, transparent); }

/* Return, drawdown and the benchmark, at the same size. The drawdown is not a footnote to the
   return - it is the other half of the same fact, and a customer who reads only the first
   number has not been told what the system does. */
.rot-figures { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.rot-figure { display: grid; gap: 3px; }
.rot-figure b {
  font-size: 20px; font-weight: 600; letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
}
.rot-figure b.is-up { color: var(--up); }
.rot-figure b.is-down { color: var(--down); }
.rot-figure span { color: var(--text-faint); font-size: 11.5px; }

.rot-curve { width: 100%; height: 120px; display: block; overflow: visible; }
.rot-curve.is-empty {
  display: grid; place-items: center; color: var(--text-faint); font-size: 12.5px;
  border: 1px dashed var(--border); border-radius: 12px;
}
.rot-curve-line { stroke: var(--up); stroke-width: 1.8; vector-effect: non-scaling-stroke; }
.rot-curve-bench {
  stroke: var(--text-xfaint); stroke-width: 1.4; vector-effect: non-scaling-stroke;
}
.rot-legend { display: flex; gap: 16px; color: var(--text-faint); font-size: 11.5px; }
.rot-legend i { display: inline-block; width: 14px; height: 2px; margin-right: 6px; vertical-align: 3px; }
.rot-key-line { background: var(--up); }
.rot-key-bench { background: var(--text-xfaint); }

.rot-split { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); gap: 18px; }
@media (max-width: 720px) { .rot-split { grid-template-columns: 1fr; } }

.rot-table, .rot-stats { width: 100%; border-collapse: collapse; font-size: 13px; }
.rot-table th, .rot-stats th {
  text-align: left; padding: 0 8px 8px; font-weight: 500;
  font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--text-faint);
}
.rot-table td, .rot-stats td { padding: 7px 8px; border-top: 1px solid var(--border); }
.rot-table .num, .rot-stats .num { text-align: right; font-variant-numeric: tabular-nums; }
.rot-table tr.is-held td { background: color-mix(in srgb, var(--accent) 8%, transparent); }
.rot-table tr.is-off td { color: var(--text-xfaint); }
.rot-table .rot-held { color: var(--up); text-align: center; }
.rot-trend.is-bull { color: var(--up); }
.rot-trend.is-bear { color: var(--down); }
.rot-stats td.is-down { color: var(--down); }

/* ── the desk ─────────────────────────────────────────────────────────────
   The one place the account, the figure and the mode are asked for. Spacious on purpose:
   this is where somebody decides how much of their money a program may move, and a cramped
   row of controls is not the place to make that decision. */
.rot-desk { display: grid; gap: 22px; padding: 26px 28px 24px; }
.rot-desk-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }
.rot-desk-head h2 { margin: 0 0 6px; font-size: 19px; font-weight: 500; letter-spacing: -.01em; }
.rot-desk-head .rot-sub { max-width: 62ch; }

.rot-desk-fields {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 18px 20px;
}
.rot-desk-field { display: grid; gap: 7px; font-size: 12px; color: var(--text-dim); }
.rot-desk-field.is-wide { grid-column: span 2; min-width: 0; }
.rot-desk-field > span:first-child { letter-spacing: .01em; }
.rot-desk-field input:not([type="checkbox"]), .rot-desk-field select {
  width: 100%; padding: 10px 12px; border-radius: 10px; font: inherit; font-size: 14px;
  border: 1px solid var(--border); background: var(--bg-lift); color: var(--text);
}
.rot-desk-field input:focus, .rot-desk-field select:focus {
  outline: none; border-color: color-mix(in srgb, var(--accent) 45%, transparent);
}

/* Four ways to act, laid out as four equal choices. Locked ones stay in the row: a customer
   deciding whether this is for them should see where it goes, and be told it is not here
   yet, rather than find it appear one day unannounced. */
.rot-modes { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 12px; }
.rot-mode-btn {
  position: relative; display: grid; gap: 6px; align-content: start; text-align: left;
  padding: 16px 18px 17px; border-radius: 13px; cursor: pointer;
  border: 1px solid var(--border); background: var(--surface-soft); color: var(--text);
  transition: border-color .16s var(--ease), background .16s var(--ease), transform .16s var(--ease);
}
.rot-mode-btn:hover:not(:disabled) {
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
  background: color-mix(in srgb, var(--accent) 6%, transparent);
}
.rot-mode-btn:active:not(:disabled) { transform: translateY(1px); }
.rot-mode-btn:disabled { cursor: default; opacity: .5; }
.rot-mode-btn.is-on {
  border-color: color-mix(in srgb, var(--accent) 60%, transparent);
  background: color-mix(in srgb, var(--accent) 11%, transparent);
}
.rot-mode-name { font-size: 15px; font-weight: 500; letter-spacing: -.01em; }
.rot-mode-hint { font-size: 12px; color: var(--text-faint); line-height: 1.55; }
.rot-lock { font-style: normal; margin-left: 7px; font-size: 11px; opacity: .7; }
.rot-mode-spin {
  position: absolute; top: 14px; right: 15px; width: 15px; height: 15px; border-radius: 50%;
  border: 2px solid color-mix(in srgb, var(--ink) 14%, transparent);
  border-top-color: var(--accent); animation: rot-spin .7s linear infinite;
}
@keyframes rot-spin { to { transform: rotate(360deg); } }

.rot-desk-note { margin: 0; font-size: 13px; color: var(--text-dim); line-height: 1.6; }
.rot-desk-note.is-on { color: var(--text); }
.rot-desk-note .pf-link { margin-left: 8px; }
.rot-live-facts {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1px;
  overflow: hidden; border: 1px solid var(--border); border-radius: 12px;
  background: var(--border);
}
/* The sleeve and the figure on the form disagree. Loud, because it is the one state on this
   page where the customer's money is doing something other than what they asked for. */
.rot-live-facts.is-off { border-color: color-mix(in srgb, var(--warn) 55%, transparent); }
.rot-live-facts.is-off b { color: var(--warn); }
.rot-desk-warn {
  margin: 0; padding: 11px 14px; border-radius: 11px; font-size: 12.5px; line-height: 1.6;
  border: 1px solid color-mix(in srgb, var(--warn) 34%, transparent);
  background: color-mix(in srgb, var(--warn) 9%, transparent);
  color: var(--text);
}
.rot-live-facts span {
  min-width: 0; display: grid; gap: 4px; padding: 11px 13px;
  background: var(--bg-lift);
}
.rot-live-facts small {
  color: var(--text-faint); font-size: 10px; letter-spacing: .07em; text-transform: uppercase;
}
.rot-live-facts b {
  overflow: hidden; color: var(--text); font-size: 12.5px; font-weight: 550;
  text-overflow: ellipsis; white-space: nowrap; font-variant-numeric: tabular-nums;
}
@media (max-width: 900px) { .rot-live-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 520px) { .rot-live-facts { grid-template-columns: 1fr; } }
.rot-desk-actions { display: flex; flex-wrap: wrap; gap: 9px; align-items: center; }

/* The engine picker: the second half of the decision the mode button starts. */
.rot-picker {
  position: fixed; inset: 0; z-index: 60; display: grid; place-items: center; padding: 24px;
  background: color-mix(in srgb, #050506 82%, transparent);
  backdrop-filter: blur(6px);
  animation: rot-fade .16s var(--ease);
}
@keyframes rot-fade { from { opacity: 0; } }
.rot-picker-card {
  width: min(620px, 100%); display: grid; gap: 20px; padding: 28px 30px 24px;
  border-radius: 18px; border: 1px solid var(--border); background: var(--bg-lift);
  box-shadow: 0 30px 70px rgba(0, 0, 0, .45);
}
.rot-picker-card h3 { margin: 0 0 6px; font-size: 19px; font-weight: 500; letter-spacing: -.01em; }
.rot-picker-card .pf-link { justify-self: start; }
.rot-engines { display: grid; gap: 10px; }
.rot-engine {
  display: grid; gap: 6px; text-align: left; cursor: pointer;
  padding: 16px 18px; border-radius: 13px;
  border: 1px solid var(--border);
  background: color-mix(in srgb, var(--ink) 4%, var(--bg-lift)); color: var(--text);
  transition: border-color .16s var(--ease), background .16s var(--ease);
}
.rot-engine:hover:not(:disabled) {
  border-color: color-mix(in srgb, var(--accent) 50%, transparent);
  background: color-mix(in srgb, var(--accent) 7%, transparent);
}
.rot-engine:disabled { cursor: default; opacity: .55; }
.rot-engine-name { font-size: 15px; font-weight: 500; }
.rot-engine-blurb { font-size: 12.5px; color: var(--text-faint); line-height: 1.6; }
.rot-engine-locked { font-size: 12px; color: var(--warn); }

/* ── what the system may use ──────────────────────────────────────────────

   Two lists with one visual difference between them, and the difference is the whole point:
   the offered rows have a tick box and respond to a pointer, the customer's own rows have
   neither and are dimmed. Somebody scanning this should be able to see which of their
   positions are in play without reading a word of it. */
.rot-hand { width: min(560px, 100%); gap: 16px; }
.rot-hand-head {
  margin: 0; font-size: 10px; letter-spacing: .07em; text-transform: uppercase;
  color: var(--text-faint);
}
.rot-hand-list { display: grid; gap: 2px; margin: 0; padding: 0; list-style: none; }
.rot-hand-row {
  border-radius: 11px; border: 1px solid transparent;
  background: color-mix(in srgb, var(--ink) 4%, var(--bg-lift));
  transition: border-color .16s var(--ease), background .16s var(--ease);
}
.rot-hand-row label {
  display: grid; grid-template-columns: auto 1fr; gap: 12px; align-items: start;
  padding: 13px 15px; cursor: pointer;
}
.rot-hand-row input { margin: 3px 0 0; accent-color: var(--accent); cursor: pointer; }
.rot-hand-row:not(.is-off):hover {
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
  background: color-mix(in srgb, var(--accent) 6%, transparent);
}
.rot-hand-row.is-on {
  border-color: color-mix(in srgb, var(--accent) 60%, transparent);
  background: color-mix(in srgb, var(--accent) 9%, transparent);
}
/* Not merely unticked - unofferable. No box, no hover, no pointer: three separate signals
   that this row is not a control, because a dimmed row alone reads as "disabled for now". */
.rot-hand-row.is-off { opacity: .62; background: none; border-color: var(--border); }
/* Offered, but on inference rather than on a ledger entry. Marked, because the row is asking
   the customer to confirm something the server could not - and a tick box that looks identical
   to a proven one is quietly presenting a guess as a fact. */
.rot-hand-row.is-unproven:not(.is-on) { border-color: color-mix(in srgb, var(--warn) 26%, transparent); }
.rot-hand-row.is-unproven .rot-hand-what small { color: color-mix(in srgb, var(--warn) 78%, var(--text-faint)); }
.rot-hand-row.is-off .rot-hand-what { padding: 13px 15px; }
.rot-hand-what { display: grid; gap: 4px; min-width: 0; }
.rot-hand-what b {
  font-size: 14px; font-weight: 500; font-variant-numeric: tabular-nums;
}
.rot-hand-what small { font-size: 12px; color: var(--text-faint); line-height: 1.6; }
.rot-hand-none, .rot-hand-note {
  margin: 0; font-size: 12.5px; line-height: 1.65; color: var(--text-dim);
}
.rot-hand-note {
  padding: 11px 14px; border-radius: 11px;
  border: 1px solid var(--border); background: var(--surface-soft);
}
.rot-hand-actions { flex-wrap: wrap; justify-content: flex-end; }
.rot-hand-actions .pf-link { margin-right: auto; }

/* ── the start-up sequence ────────────────────────────────────────────────

   Starting a system is four round trips and takes as long as the exchange takes. Drawn as a
   list that fills in rather than as a spinner, because "which of the four is it on" is the
   question somebody watching actually has, and a spinner answers none of it. */
.rot-picker.is-running { animation: none; }
.rot-start { width: min(520px, 100%); gap: 18px; }
.rot-steps { display: grid; gap: 2px; margin: 0; padding: 0; list-style: none; }
.rot-step {
  display: grid; grid-template-columns: 22px 1fr auto; align-items: center;
  gap: 12px; padding: 11px 4px; font-size: 13.5px; line-height: 1.5;
  color: var(--text-faint);
  transition: color .22s var(--ease);
}
.rot-step + .rot-step { border-top: 1px solid var(--border); }
.rot-step.is-running, .rot-step.is-done { color: var(--text); }
.rot-step-mark {
  width: 16px; height: 16px; border-radius: 50%; justify-self: center;
  border: 1.5px solid color-mix(in srgb, var(--ink) 20%, transparent);
  transition: border-color .22s var(--ease), background .22s var(--ease);
}
.rot-step.is-running .rot-step-mark {
  border-color: color-mix(in srgb, var(--ink) 16%, transparent);
  border-top-color: var(--accent);
  animation: rot-spin .7s linear infinite;
}
/* A tick drawn with two borders rather than a glyph: it inherits the accent, it scales with
   the row, and it cannot arrive as a missing-font box on a machine without the emoji. */
.rot-step.is-done .rot-step-mark {
  border-color: transparent; border-radius: 0; width: 6px; height: 11px;
  border-right: 2px solid var(--up); border-bottom: 2px solid var(--up);
  transform: translateY(-2px) rotate(42deg);
  animation: rot-tick .24s var(--ease);
}
@keyframes rot-tick { from { opacity: 0; transform: translateY(-2px) rotate(42deg) scale(.4); } }
.rot-step.is-failed .rot-step-mark {
  border-color: var(--down); background: color-mix(in srgb, var(--down) 30%, transparent);
}
.rot-step-label { min-width: 0; }
.rot-step-note { font-size: 12px; color: var(--text-faint); }
.rot-start-facts {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1px;
  overflow: hidden; border: 1px solid var(--border); border-radius: 12px;
  background: var(--border);
  animation: rot-rise .24s var(--ease);
}
@keyframes rot-rise { from { opacity: 0; transform: translateY(6px); } }
.rot-start-facts span { display: grid; gap: 4px; padding: 11px 13px; background: var(--bg-lift); min-width: 0; }
.rot-start-facts small {
  color: var(--text-faint); font-size: 10px; letter-spacing: .07em; text-transform: uppercase;
}
.rot-start-facts b {
  overflow: hidden; font-size: 13px; font-weight: 550; text-overflow: ellipsis;
  white-space: nowrap; font-variant-numeric: tabular-nums;
}
.rot-start-error {
  margin: 0; padding: 11px 14px; border-radius: 11px; font-size: 12.5px; line-height: 1.6;
  border: 1px solid color-mix(in srgb, var(--warn) 34%, transparent);
  background: color-mix(in srgb, var(--warn) 9%, transparent);
}
.rot-start-wait { margin: 0; font-size: 12px; color: var(--text-faint); }
.rot-start-actions { display: flex; gap: 10px; align-items: center; }

/* The repair, inside the panel that reported the fault. One labelled number and one button:
   anything more here would be a second copy of the desk, and the desk is four inches below
   this dialog already. */
.rot-start-fix {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 12px;
  padding: 14px; border-radius: 12px;
  border: 1px solid var(--border); background: var(--surface-soft);
}
.rot-start-fix label { display: grid; gap: 6px; flex: 1 1 190px; min-width: 0; }
.rot-start-fix label > span {
  font-size: 10px; letter-spacing: .07em; text-transform: uppercase; color: var(--text-faint);
}
.rot-start-fix .rot-capital { display: flex; align-items: center; gap: 8px; }
.rot-start-fix input {
  flex: 1 1 auto; min-width: 0; padding: 9px 12px; border-radius: 9px;
  border: 1px solid var(--border); background: var(--bg); color: var(--text);
  font-variant-numeric: tabular-nums;
}
.rot-start-fix input:focus { outline: none; border-color: var(--border-strong); }
.rot-start-fix b { font-size: 12.5px; color: var(--text-dim); font-weight: 500; }

@media (prefers-reduced-motion: reduce) {
  .rot-step.is-running .rot-step-mark { animation: none; border-top-color: var(--accent); }
  .rot-step.is-done .rot-step-mark, .rot-start-facts, .rot-picker { animation: none; }
}

/* ── the switch board ─────────────────────────────────────────────────────
   Rows on shared columns, not a table of cells. One line per switch. */
.rot-board-card { display: grid; gap: 16px; padding: 24px 26px 8px; }
.rot-board-card.is-asking {
  border-color: color-mix(in srgb, var(--warn) 40%, transparent);
}
.rot-board-head-row {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;
}
.rot-board-head-row h2 { margin: 0 0 5px; font-size: 18px; font-weight: 500; letter-spacing: -.01em; }
.rot-board { display: grid; gap: 2px; }
/* A container is not a row. Only the rows inside it respond to the pointer - a whole table
   lighting up under the cursor tells the reader nothing about what they are pointing at. */
.rot-board:hover, .rot-board-card:hover, .an-board:hover, .an-people:hover,
.stat-op-list:hover, .stat-outside-list:hover { background: none; }
.rot-board-head, .rot-board-row {
  display: grid;
  grid-template-columns:
    minmax(120px, .85fr) minmax(90px, .65fr) minmax(170px, 1.2fr)
    minmax(110px, .8fr) minmax(95px, .55fr) minmax(95px, .55fr);
  gap: 8px 20px; align-items: baseline;
}
.rot-board.is-asking .rot-board-head,
.rot-board.is-asking .rot-board-row {
  grid-template-columns:
    minmax(120px, .9fr) minmax(90px, .7fr) minmax(150px, 1fr)
    minmax(200px, 1.6fr) minmax(180px, auto);
}
.rot-board-head {
  padding: 10px 14px 9px; border-bottom: 1px solid var(--border);
  font-size: 11px; letter-spacing: .07em; text-transform: uppercase; color: var(--text-faint);
}
/* Same row as everywhere else: nothing drawn until the pointer is on it. */
.rot-board-row {
  padding: 12px 14px 13px; font-size: 13.5px;
  border: 1px solid transparent; border-radius: 11px;
  transition: background .15s var(--ease), border-color .15s var(--ease);
}
.rot-board-row:hover { border-color: var(--border); }
.rot-board-row.is-quiet { color: var(--text-faint); }
.rot-board-right { text-align: right; justify-self: end; font-variant-numeric: tabular-nums; }
.rot-board-right i { color: var(--text-faint); font-style: normal; margin: 0 3px; }
.rot-board-detail {
  grid-column: 1 / -1; margin-top: 2px;
  font-size: 12px; color: var(--text-faint); line-height: 1.55;
}
.rot-board-detail.is-bad { color: var(--down); }
/* The asking board puts the instruction in its own column rather than under the row: it is
   the thing being answered, not a footnote to it. */
.rot-instruction { font-size: 12.5px; color: var(--text-dim); line-height: 1.55; }
.rot-when { color: var(--text-dim); font-size: 12.5px; font-variant-numeric: tabular-nums; }
.rot-move { display: inline-flex; align-items: baseline; gap: 7px; }
.rot-move i { color: var(--text-faint); font-style: normal; }
.rot-change { font-variant-numeric: tabular-nums; }
.rot-change.is-up { color: var(--up); }
.rot-change.is-down { color: var(--down); }
/* The side column carries two tags - the direction, and whether the trade is still open.
   They were laid out by a `margin-left` on the tag itself, which does nothing once the pair
   wraps onto two lines: "LONG" sat directly on top of "OPEN" with no air between them. */
.rot-side-tags { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 6px; }
.rot-side-tags .rot-tag { margin-left: 0; }

.rot-tag {
  margin-left: 9px; padding: 3px 9px; border-radius: 7px;
  font-size: 10.5px; letter-spacing: .04em; text-transform: uppercase;
  border: 1px solid var(--border); color: var(--text-faint); white-space: nowrap;
}
.rot-tag.is-filled, .rot-tag.is-approved {
  color: var(--up); border-color: color-mix(in srgb, var(--up) 32%, transparent);
}
/* Neutral. A tag is a label, not a control, and outlining it in the accent made every board
   look like it was full of links. */
.rot-tag.is-alert { color: var(--text-dim); border-color: var(--border-strong); }
.rot-tag.is-declined { color: var(--text-faint); }
.rot-tag.is-error, .rot-tag.is-rejected {
  color: var(--down); border-color: color-mix(in srgb, var(--down) 32%, transparent);
}
.rot-answer { display: flex; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
.rot-head-right { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }

@media (max-width: 900px) {
  .rot-board-head { display: none; }
  .rot-board-row, .rot-board.is-asking .rot-board-row { grid-template-columns: 1fr 1fr; }
  .rot-board-right { justify-self: start; text-align: left; }
  .rot-desk-field.is-wide { grid-column: auto; }
}

/* The automation strip. When it is live it is the loudest thing in the panel, on purpose. */
.rot-controls {
  display: grid; gap: 14px; padding: 16px 18px;
  border: 1px solid var(--border); border-radius: 13px; background: var(--surface-soft);
}
.rot-controls.is-live {
  border-color: color-mix(in srgb, var(--warn) 45%, transparent);
  background: color-mix(in srgb, var(--warn) 5%, transparent);
}
.rot-state { display: grid; gap: 5px; }
.rot-badge {
  justify-self: start; padding: 4px 11px; border-radius: 7px;
  font-size: 11.5px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  border: 1px solid var(--border); color: var(--text-dim);
}
.rot-badge.is-live {
  color: var(--warn); border-color: var(--warn);
  background: color-mix(in srgb, var(--warn) 14%, transparent);
}
.rot-badge.is-paper { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 45%, transparent); }

.rot-fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 12px; }
.rot-fields label { display: grid; gap: 5px; font-size: 12px; color: var(--text-dim); }
/* Text and number fields fill their column; a checkbox is not a field and must keep its own
   size, or the box stretches the width of the row and throws its own label to the far edge. */
.rot-fields input:not([type="checkbox"]), .rot-fields select,
.rot-settings input:not([type="checkbox"]), .rot-settings select {
  width: 100%; padding: 8px 10px; border-radius: 9px; font: inherit; font-size: 13px;
  border: 1px solid var(--border); background: var(--bg-lift); color: var(--text);
}
.rot-fields input:focus, .rot-fields select:focus,
.rot-settings input:focus, .rot-settings select:focus {
  outline: none; border-color: color-mix(in srgb, var(--accent) 45%, transparent);
}
.rot-capital { display: flex; gap: 8px; align-items: center; }
.rot-capital input { flex: 1 1 90px; min-width: 0; }
.rot-capital select { flex: 0 0 auto; width: auto; }
.rot-unit { color: var(--text-faint); font-size: 11.5px; white-space: nowrap; }

.rot-explainer {
  margin: 0; color: var(--text-faint); font-size: 12px; line-height: 1.6; max-width: 70ch;
}
.rot-blocked {
  margin: 0; padding: 9px 12px; border-radius: 10px; font-size: 12.5px;
  color: var(--warn); background: color-mix(in srgb, var(--warn) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--warn) 28%, transparent);
}
.rot-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.danger-chip {
  color: var(--down);
  border-color: color-mix(in srgb, var(--down) 40%, transparent);
  background: color-mix(in srgb, var(--down) 10%, transparent);
}

.rot-toggle {
  justify-self: start; font-size: 12.5px; color: var(--text-dim);
  border-bottom: 1px solid var(--border);
}
.rot-toggle:hover { color: var(--accent); border-color: var(--accent); }

.rot-settings {
  display: grid; gap: 12px; padding: 16px 18px;
  border: 1px solid var(--border); border-radius: 13px; background: var(--surface-soft);
}
.rot-settings h4 {
  margin: 4px 0 0; font-size: 11px; letter-spacing: .07em; text-transform: uppercase;
  color: var(--text-faint); font-weight: 500;
}
.rot-assets { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 10px; }
.rot-asset-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 8px 11px; border: 1px solid var(--border); border-radius: 10px;
}
.rot-check {
  display: flex; align-items: center; justify-content: flex-start; gap: 9px;
  font-size: 13px; cursor: pointer; line-height: 1.5;
}
.rot-check input { flex: none; accent-color: var(--accent); }
.rot-check span { flex: 0 1 auto; }
.rot-standalone { padding-top: 2px; }
.rot-lev { display: flex; align-items: center; gap: 7px; font-size: 11px; color: var(--text-faint); }
.rot-lev input { width: 68px; padding: 5px 7px; }
.rot-select { display: grid; gap: 5px; font-size: 12px; color: var(--text-dim); }

.rot-busy { color: var(--text-faint); font-size: 12.5px; }

.rot-ledger .rot-table td { vertical-align: top; }
.rot-when { color: var(--text-faint); font-size: 12px; white-space: nowrap; }
.rot-status {
  display: inline-block; padding: 2px 8px; border-radius: 7px; font-size: 11px;
  border: 1px solid var(--border); color: var(--text-dim);
}
.rot-status.is-filled { color: var(--up); border-color: color-mix(in srgb, var(--up) 32%, transparent); }
.rot-status.is-simulated { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 32%, transparent); }
.rot-status.is-rejected, .rot-status.is-error {
  color: var(--down); border-color: color-mix(in srgb, var(--down) 32%, transparent);
}
.rot-status.is-blocked { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 32%, transparent); }
.rot-ledger .rot-sub { display: block; margin-top: 3px; max-width: 44ch; }

/* ---------- the risk disclosure gate ---------- */

/* One screen, no scrolling of the page itself.
 *
 * This used to be a narrow column of stacked paragraphs that ran twice the height of a laptop
 * and pushed its own accept button off the bottom. It is eight short sections, and eight
 * short sections fit side by side. The whole thing now sits inside the viewport: the text
 * scrolls in its own two-column area, and the confirmation stays visible underneath it the
 * entire time, so what is being agreed to is never out of sight of the button that agrees.
 */
.disc {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  gap: 18px;
  /* Narrow, and deliberately so.
     At 1180px this filled the window edge to edge, and the walkthrough card - which is
     positioned against whatever it is pointing at - had nowhere to sit that was not on top of
     the text. A single column of prose is also simply easier to read to the end of, which is
     the entire point of a screen somebody has to get to the bottom of. */
  max-width: 760px;
  /* Centred, and the page head above it is centred to match - see `#view-portfolio.is-gated`.
     Left-aligned, a single 760px card sat in the corner of a wide window with a slab of empty
     space beside it; centred but with a left-aligned heading above, the two blocks were on
     different alignments entirely. Both move together now. */
  margin: 0 auto;
  /* The header is fixed and the page has its own padding; this is what is left. */
  height: calc(100vh - var(--hdr-h) - 190px);
  min-height: 420px;
}
.disc-head { display: flex; align-items: flex-start; gap: 16px; }
.disc-head h1 { margin: 0 0 6px; font-size: 23px; font-weight: 500; letter-spacing: -.02em; }
.disc-head p { margin: 0; color: var(--text-dim); font-size: 14px; line-height: 1.6; max-width: 78ch; }
/* "Nothing here is financial advice", at the weight it deserves. Every other word on this
   screen is grey body copy; this one line is not, because it is the line somebody has to have
   read and understood before any of the rest means anything. */
.disc-head .disc-shout {
  margin: 0 0 8px; color: var(--text); font-size: 15.5px; font-weight: 600;
  line-height: 1.5; letter-spacing: .01em;
}
.disc-mark {
  flex: none; display: grid; place-items: center; width: 38px; height: 38px;
  border-radius: 12px; font-size: 19px; font-weight: 600;
  color: var(--warn);
  background: color-mix(in srgb, var(--warn) 12%, transparent);
}

/* One column, scrolled.
   Two columns inside a scrolling box is the worst of both: the reader gets to the bottom of
   column one, scrolls, and loses their place entirely because the text they were following
   has moved sideways. One column scrolls the way everybody expects a document to. */
.disc-scroll {
  min-height: 0;
  overflow-y: auto; overscroll-behavior: contain;
  padding: 20px 26px;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  /* No `columns` property at all, not even `columns: 1`.
     Setting it to one still establishes a multi-column formatting context, and in a box with a
     fixed height that sends the overflow *sideways* into fresh columns rather than down: the
     element reported a scrollHeight identical to its clientHeight while holding 1,356 words,
     so it could not be scrolled and the read-to-the-end gate was satisfied instantly. */
  scroll-behavior: smooth;
}
.disc-scroll:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.disc-section { break-inside: avoid-column; margin: 0 0 20px; }
.disc-section h3 { margin: 0 0 8px; font-size: 14px; font-weight: 600; }
.disc-section p {
  margin: 0 0 9px; color: var(--text-dim); font-size: 13px; line-height: 1.65;
}
.disc-end { margin: 4px 0 0; color: var(--text-xfaint); font-size: 12px; }

.disc-foot { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.disc-agree {
  display: flex; gap: 11px; align-items: flex-start; flex: 1 1 420px;
  cursor: pointer; font-size: 13px; line-height: 1.55; color: var(--text-dim);
}
.disc-agree.is-locked { opacity: .5; cursor: not-allowed; }
.disc-agree input { margin-top: 2px; flex: none; accent-color: var(--accent); }
.disc-hint { margin: 0; color: var(--text-faint); font-size: 12px; flex: 0 1 auto; }
.disc-error { margin: 0; color: var(--down); font-size: 13px; flex: 1 0 100%; }
.disc-accept { flex: none; padding: 11px 24px; border-radius: 11px; }
.disc-accept[disabled] { opacity: .45; cursor: not-allowed; }


/* Whether the last change actually reached the server. */
.rot-save {
  padding: 3px 9px; border-radius: 7px; font-size: 11px; letter-spacing: .03em;
  border: 1px solid var(--border); color: var(--text-faint);
}
.rot-save.is-saving { color: var(--text-dim); }
.rot-save.is-saved {
  color: var(--up); border-color: color-mix(in srgb, var(--up) 34%, transparent);
}
.rot-save.is-failed {
  color: var(--down); border-color: var(--down);
  background: color-mix(in srgb, var(--down) 12%, transparent);
}
.rot-state { grid-auto-flow: row; }
.rot-state .rot-badge, .rot-state .rot-save { justify-self: start; }
.rot-status.is-no-op { color: var(--text-faint); }

/* ── the lab ──────────────────────────────────────────────────────────────
   A workbench. Denser than the rest of the app on purpose: the person reading it has a
   TradingView window open beside it and is comparing bar for bar. */
.lab-card { display: grid; gap: 20px; padding: 26px 28px 24px; }
#labBody { display: grid; gap: 22px; align-content: start; }
.lab-lede { max-width: 92ch; }
.lab-head { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; }
.lab-figure {
  margin-left: auto; font-size: 17px; font-weight: 500; font-variant-numeric: tabular-nums;
}
.lab-figure em { display: block; font-style: normal; font-size: 11.5px; color: var(--text-faint); }
.lab-chart { width: 100%; height: 520px; }
/* The book's curve is shorter than the replay's: it has no scrubber under it and no
   switch log beside it, so 520px left a hundred pixels of empty card. */
.lab-chart.is-book { height: 420px; }

/* The unconfirmed bar. Neon, and it says why, because it is the only thing on this page that
   can still change under the reader. */
.lab-repaint {
  display: flex; gap: 14px; align-items: flex-start;
  padding: 13px 16px; border-radius: 12px;
  border: 1px solid var(--border); background: var(--surface-soft);
}
.lab-repaint p { margin: 4px 0 0; font-size: 12.5px; color: var(--text-dim); line-height: 1.6; }
.lab-repaint-mark {
  flex: 0 0 auto; width: 9px; height: 9px; margin-top: 5px; border-radius: 50%;
  background: var(--text-faint);
}
.lab-repaint.is-live { border-color: color-mix(in srgb, #39ff9e 45%, transparent); }
.lab-repaint.is-live .lab-repaint-mark {
  background: #39ff9e; box-shadow: 0 0 0 0 rgba(57, 255, 158, .6);
  animation: lab-pulse 1.9s ease-out infinite;
}
@keyframes lab-pulse {
  70% { box-shadow: 0 0 0 9px rgba(57, 255, 158, 0); }
  100% { box-shadow: 0 0 0 0 rgba(57, 255, 158, 0); }
}

.lab-legend { display: flex; flex-wrap: wrap; gap: 6px 16px; font-size: 11.5px; color: var(--text-faint); }
.lab-legend span { display: inline-flex; align-items: center; gap: 6px; }
.lab-legend i { width: 9px; height: 9px; border-radius: 2px; }
.lab-legend .is-live { color: #39ff9e; }

.lab-scrub { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.lab-scrub input[type="range"] { flex: 1 1 220px; min-width: 160px; accent-color: var(--accent); }
.lab-at { font-size: 12.5px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.lab-at em { font-style: normal; color: var(--text-faint); margin-left: 7px; }

.lab-board .rot-board-head, .lab-board .rot-board-row {
  grid-template-columns: minmax(110px, .8fr) minmax(180px, 1.3fr)
    minmax(80px, .45fr) minmax(100px, .55fr) minmax(100px, .55fr);
}
.lab-board .is-up { color: var(--up); }
.lab-board .is-down { color: var(--down); }
/* ── the statistics panes ───────────────────────────────────────────────
 *
 * Two tables and a chart. The only styling decision with an opinion in it is on `.lab-edge`:
 * the edge column is the one number on the page worth acting on, so it is the one that gets
 * the up/down colour, and the raw hit rate next to it deliberately does not - a green 60%
 * beside a grey baseline of 58% is how a reader talks themselves into noise. */
.lab-panes { margin-bottom: 18px; }
.lab-rules { margin-bottom: 18px; width: 100%; }
.lab-strip {
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-bottom: 18px;
}
.lab-strip .lab-figure { margin-left: auto; text-align: right; }
.lab-from select {
  background: transparent; border: 0; color: var(--text); font: inherit; font-size: 12.5px;
  outline: none; cursor: pointer;
}
.lab-from select option { background: var(--surface); color: var(--text); }

.lab-baseline {
  display: grid; gap: 6px; margin-bottom: 18px; padding: 16px 18px;
  border: 1px solid var(--border); border-radius: 14px;
  background: color-mix(in srgb, var(--ink) 2.5%, transparent);
}
.lab-baseline b { font-size: 12px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--text-faint); font-weight: 500; }
.lab-baseline p { margin: 0; font-size: 13px; line-height: 1.65; color: var(--text-dim); }
.lab-baseline p b { font-size: inherit; letter-spacing: 0; text-transform: none;
  color: var(--text); font-weight: 600; }

/* Wide tables scroll inside themselves. The page never scrolls sideways. */
.lab-scroll { overflow-x: auto; }
.lab-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.lab-table th, .lab-table td {
  padding: 9px 14px 9px 0; text-align: right; white-space: nowrap;
  border-bottom: 1px solid var(--hairline);
}
.lab-table th:first-child, .lab-table td:first-child { text-align: left; }
.lab-table th {
  font-weight: 500; color: var(--text-faint); font-size: 11px;
  letter-spacing: .06em; text-transform: uppercase;
}
.lab-table th[data-tip] { cursor: help; }
.lab-table tbody tr:last-child td { border-bottom: 0; }
.lab-table td.is-up { color: var(--up); }
.lab-table td.is-down { color: var(--down); }
.lab-none { color: var(--text-faint); text-align: left !important; font-style: italic; }

.lab-stats { display: flex; flex-wrap: wrap; gap: 10px 28px; }
.lab-stat { display: grid; gap: 2px; }
.lab-stat span {
  font-size: 11px; letter-spacing: .07em; text-transform: uppercase; color: var(--text-faint);
}
.lab-stat b { font-size: 20px; font-weight: 560; letter-spacing: -.02em; }
.lab-stat b.is-up { color: var(--up); }
.lab-stat b.is-down { color: var(--down); }
.lab-stat em { font-style: normal; font-size: 11.5px; color: var(--text-faint); }

.lab-missing {
  margin: 0; padding: 10px 14px; border-radius: 10px;
  border: 1px solid var(--border); background: color-mix(in srgb, var(--ink) 2.5%, transparent);
  font-size: 12.5px; line-height: 1.6; color: var(--text-dim);
}
.lab-missing b { color: var(--text); font-weight: 500; }

.lab-key {
  width: 16px; height: 2px; border-radius: 2px; background: var(--key, currentColor);
  display: inline-block; vertical-align: middle; margin-right: 6px;
}
.lab-key.is-faint { background: color-mix(in srgb, var(--ink) 42%, transparent); }

.lab-notes { margin: 0; padding-left: 18px; display: grid; gap: 8px; }
.lab-notes li { font-size: 12.5px; color: var(--text-dim); line-height: 1.6; }

/* ── the create-key dialog ────────────────────────────────────────────────
   Two doors to the same key. The one on the left is a name and a button; the one on the
   right asks what somebody is trying to pull and writes the request for them. */
.api-new { align-items: center; }
.api-new .api-sub { max-width: 52ch; }
.api-sub { color: var(--text-faint); font-size: 12px; line-height: 1.6; margin: 0; }

.api-modal {
  position: fixed; inset: 0; z-index: 60; display: grid; place-items: center; padding: 24px;
  background: var(--scrim); backdrop-filter: blur(6px);
}
.api-modal.is-entering { animation: rot-fade .16s var(--ease); }
.api-dialog {
  width: min(640px, 100%); max-height: calc(100vh - 48px); overflow: auto;
  display: grid; gap: 20px; padding: 28px 30px 22px;
  border-radius: 18px; border: 1px solid var(--border); background: var(--bg-lift);
  box-shadow: 0 30px 70px rgba(0, 0, 0, .45);
}
.api-dialog h3 { margin: 0 0 6px; font-size: 19px; font-weight: 500; letter-spacing: -.01em; }
.api-dialog h4 { margin: 0 0 4px; font-size: 14px; font-weight: 500; }
.api-dialog-foot { display: flex; align-items: center; justify-content: space-between; gap: 14px; }

.api-doors { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px; }
.api-door {
  display: grid; gap: 7px; text-align: left; cursor: pointer; padding: 18px 20px;
  border-radius: 13px; border: 1px solid var(--border);
  background: color-mix(in srgb, var(--ink) 4%, var(--bg-lift)); color: var(--text);
  transition: border-color .16s var(--ease), background .16s var(--ease);
}
.api-door:hover {
  border-color: color-mix(in srgb, var(--accent) 50%, transparent);
  background: color-mix(in srgb, var(--accent) 7%, transparent);
}
.api-door-name { font-size: 15.5px; font-weight: 500; }
.api-door-hint { font-size: 12.5px; color: var(--text-faint); line-height: 1.6; }

.api-question { display: grid; gap: 10px; }
.api-choices { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 9px; }
.api-choice {
  display: grid; gap: 4px; text-align: left; cursor: pointer; padding: 12px 14px;
  border-radius: 11px; border: 1px solid var(--border);
  background: color-mix(in srgb, var(--ink) 4%, var(--bg-lift)); color: var(--text);
  transition: border-color .16s var(--ease), background .16s var(--ease);
}
.api-choice:hover { border-color: color-mix(in srgb, var(--accent) 45%, transparent); }
.api-choice.is-on {
  border-color: color-mix(in srgb, var(--accent) 60%, transparent);
  background: color-mix(in srgb, var(--accent) 11%, transparent);
}
.api-choice-name { font-size: 13.5px; font-weight: 500; }
.api-choice-hint { font-size: 11.5px; color: var(--text-faint); line-height: 1.5; }

.api-field {
  width: 100%; padding: 10px 12px; border-radius: 10px; font: inherit; font-size: 14px;
  border: 1px solid var(--border); color: var(--text);
  background: color-mix(in srgb, var(--ink) 6%, var(--bg-lift));
}
.api-field:focus { outline: none; border-color: color-mix(in srgb, var(--accent) 45%, transparent); }

.api-preview {
  display: grid; gap: 6px; padding: 12px 14px; border-radius: 11px;
  border: 1px dashed var(--border);
  background: color-mix(in srgb, var(--ink) 4%, var(--bg-lift));
}
.api-preview span { font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--text-faint); }
.api-preview code { font-size: 13px; color: var(--accent); word-break: break-all; }

.api-made { display: grid; gap: 10px; }
.api-made > b { color: var(--warn); font-weight: 500; font-size: 13.5px; }
.api-made .api-sample { margin: 0; }
.api-copy-request { justify-self: start; }

/* An error the reader can act on, rather than the server's own word for it. */
.lab-broke {
  display: grid; gap: 9px; justify-items: start; max-width: 62ch;
  padding: 20px 22px; border-radius: 14px;
  border: 1px solid var(--border); background: var(--surface-soft);
}
.lab-broke b { font-size: 15px; font-weight: 500; }
.lab-broke p { margin: 0; font-size: 13px; color: var(--text-dim); line-height: 1.65; }

/* The lab's equity pane, and the leg comparison in its table. */
.lab-equity { width: 100%; height: 190px; }
.lab-legend .lab-key-hodl {
  width: 12px; height: 2px; border-radius: 1px;
  background: color-mix(in srgb, var(--ink) 34%, transparent);
}
/* Only the winner of each pair is coloured. The loser stays quiet rather than being painted
   red, because "made less than the other one" is not the same as "lost money". */
.lab-leg { font-variant-numeric: tabular-nums; color: var(--text-faint); }
.lab-leg.is-best { color: var(--up); font-weight: 500; }
.lab-leg.is-rest { color: var(--text-faint); }

/* A creator's picture inside the avatar circle. The source is a 16:9 video thumbnail, so it
   is cropped by the circle rather than squashed into it; the initial stays underneath and
   shows through if the image fails, which `onerror` makes it do by removing itself. */
.an-avatar.has-image { position: relative; overflow: hidden; padding: 0; }
.an-avatar.has-image img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; border-radius: inherit;
}
.an-quiet-note {
  margin: 14px 4px 0; font-size: 12px; color: var(--text-xfaint); line-height: 1.6;
  max-width: 78ch;
}

/* ── the API page ─────────────────────────────────────────────────────────
   It opens by saying what is behind the key and what a call looks like, rather than by
   handing a stranger a table of paths and a button. */
#apiBody { display: grid; gap: 22px; align-content: start; }
/* Headline and button on the left, the three numbers across on the right. With the
   explanatory paragraph gone the left column is short, so the two sides are centred against
   each other rather than top-aligned around a hole. */
.api-hero {
  display: grid; gap: 32px; padding: 30px 32px;
  grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr);
  align-items: center;
}
.api-hero-copy h2 {
  margin: 8px 0 10px; font-size: 27px; font-weight: 500; letter-spacing: -.02em;
  line-height: 1.2;
}
.api-hero-copy p { margin: 0 0 18px; color: var(--text-dim); font-size: 14px; line-height: 1.65; max-width: 52ch; }
.api-hero-actions { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }
.api-hero-actions .api-sub { max-width: 34ch; }

.api-figures { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; align-content: center; }
.api-figure {
  display: grid; grid-template-columns: auto 1fr; gap: 2px 10px; align-items: baseline;
  padding: 13px 16px; border-radius: 12px;
  border: 1px solid var(--border);
  background: color-mix(in srgb, var(--ink) 2.5%, transparent);
}
.api-figure { grid-template-columns: 1fr; gap: 3px; }
.api-figure b { font-size: 22px; font-weight: 500; font-variant-numeric: tabular-nums; }
.api-figure span { font-size: 12.5px; color: var(--text-dim); }
.api-figure em { grid-column: 1 / -1; font-style: normal; font-size: 11.5px; color: var(--text-faint); line-height: 1.5; }


.api-keys-card, .api-docs-card { padding: 24px 26px; display: grid; gap: 14px; }
.api-section-head { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.api-section-head h3 { margin: 0; font-size: 17px; font-weight: 500; letter-spacing: -.01em; }
.api-docs-card .api-docs { margin: 0; }

@media (max-width: 900px) {
  .api-hero { grid-template-columns: 1fr; }
}
/* Switch-to-switch jumps sit apart from the single-bar arrows: they do different jobs and
   pressing the wrong one during an audit costs you your place. */
.lab-jump { display: inline-flex; gap: 6px; padding-left: 8px; margin-left: 2px;
  border-left: 1px solid var(--border); }


/* ── one table, everywhere ────────────────────────────────────────────────
   The watchlist, the holdings book, the timeframe grid, the highlights and the API key list
   all get the analyst board's row: no rules between rows, a rounded lift under the pointer,
   and the same small uppercase head. Written once here rather than five times above. */
.wl-table, .pf-table, .tf-table, .hl-table, .an-table, .api-keys, .chart-table {
  width: 100%; border-collapse: separate; border-spacing: 0;
}
.wl-table thead th, .pf-table thead th, .tf-table thead th, .hl-table thead th,
.an-table thead th, .api-keys thead th, .chart-table thead th {
  padding: 11px 14px 12px;
  font-size: 11px; font-weight: 500;
  letter-spacing: .07em; text-transform: uppercase;
  color: var(--text-faint);
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.wl-table tbody td, .pf-table tbody td, .tf-table tbody td, .hl-table tbody td,
.an-table tbody td, .api-keys tbody td, .chart-table tbody td {
  padding: 12px 14px;
  border-top: 1px solid transparent;
  border-bottom: 1px solid transparent;
  transition: background .15s var(--ease), border-color .15s var(--ease);
}
.wl-table tbody td:first-child, .pf-table tbody td:first-child,
.tf-table tbody td:first-child, .hl-table tbody td:first-child,
.an-table tbody td:first-child, .api-keys tbody td:first-child,
.chart-table tbody td:first-child {
  border-left: 1px solid transparent; border-radius: 11px 0 0 11px;
}
.wl-table tbody td:last-child, .pf-table tbody td:last-child,
.tf-table tbody td:last-child, .hl-table tbody td:last-child,
.an-table tbody td:last-child, .api-keys tbody td:last-child,
.chart-table tbody td:last-child {
  border-right: 1px solid transparent; border-radius: 0 11px 11px 0;
}
.wl-table tbody tr:hover td, .pf-table tbody tr:hover td, .tf-table tbody tr:hover td,
.hl-table tbody tr:hover td, .an-table tbody tr:hover td, .api-keys tbody tr:hover td,
.chart-table tbody tr:hover td {
  border-top-color: var(--border);
  border-bottom-color: var(--border);
}
.wl-table tbody tr:hover td:first-child, .pf-table tbody tr:hover td:first-child,
.tf-table tbody tr:hover td:first-child, .hl-table tbody tr:hover td:first-child,
.an-table tbody tr:hover td:first-child, .api-keys tbody tr:hover td:first-child,
.chart-table tbody tr:hover td:first-child { border-left-color: var(--border); }
.wl-table tbody tr:hover td:last-child, .pf-table tbody tr:hover td:last-child,
.tf-table tbody tr:hover td:last-child, .hl-table tbody tr:hover td:last-child,
.an-table tbody tr:hover td:last-child, .api-keys tbody tr:hover td:last-child,
.chart-table tbody tr:hover td:last-child { border-right-color: var(--border); }

/* Trade history stays ink-on-ground on hover. Template and appearance overrides may change
   `--surface-hover`, so pinning this table to transparent prevents the broad grey slab shown
   behind an audited position while retaining the quiet outline used to track the row. */
.tf-table tbody tr:hover td { background: transparent !important; }

/* A system that is actually running, and the one warning worth reading. */
.rot-live {
  display: inline-block; width: 8px; height: 8px; margin-right: 8px; border-radius: 50%;
  background: var(--up); vertical-align: baseline;
  box-shadow: 0 0 0 0 color-mix(in srgb, var(--up) 60%, transparent);
  animation: rot-live 2s ease-out infinite;
}
@keyframes rot-live {
  70%  { box-shadow: 0 0 0 8px color-mix(in srgb, var(--up) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--up) 0%, transparent); }
}
@media (prefers-reduced-motion: reduce) { .rot-live { animation: none; } }

.rot-warn {
  display: grid; gap: 7px; padding: 15px 17px; border-radius: 12px;
  border: 1px solid color-mix(in srgb, var(--warn) 34%, transparent);
  background: color-mix(in srgb, var(--warn) 8%, transparent);
}
.rot-warn b { color: var(--warn); font-weight: 500; font-size: 13.5px; }
.rot-warn p { margin: 0; font-size: 12.5px; color: var(--text-dim); line-height: 1.65; }

/* Reach, stated on the row and again on the profile. It is the ordering, so it is legible. */
.an-subs { color: var(--text-dim); font-weight: 500; }

/* An alert reads as the sentence it is, with the name somebody filed it under underneath.
   The name was the headline and the sentence the footnote, which is backwards: nobody needs
   to be told their rule is called "Untitled". */
.alert-rule-who { display: grid; gap: 3px; min-width: 0; }
.alert-rule-who b { font-size: 13.5px; font-weight: 500; line-height: 1.5; }
.alert-rule-name { font-size: 11.5px; color: var(--text-xfaint); }

/* ── the API reference, as structure ──────────────────────────────────────
   Cards, pills and one example. It was two paragraphs of prose and three curl blocks, on the
   one page whose job is getting somebody to their first request. */
.api-block { display: grid; gap: 14px; }
.api-block + .api-block { margin-top: 30px; }
.api-block h3 { margin: 0; font-size: 15px; font-weight: 500; letter-spacing: -.01em; }

.api-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(272px, 1fr)); gap: 10px; }
.api-card {
  display: grid; gap: 8px; padding: 15px 17px;
  border: 1px solid var(--border); border-radius: 13px;
  background: color-mix(in srgb, var(--ink) 2.5%, transparent);
  transition: border-color .15s var(--ease), background .15s var(--ease);
}
.api-card:hover { border-color: var(--border-strong); background: var(--surface-hover); }
.api-card header { display: flex; align-items: baseline; gap: 9px; }
.api-card header b { font-size: 14px; font-weight: 500; }
.api-card code {
  font-family: ui-monospace, monospace; font-size: 12px;
  color: var(--text-dim); word-break: break-all;
}
.api-card p { margin: 0; font-size: 12.5px; color: var(--text-faint); line-height: 1.55; }
/* A method is a label, not a control. Outlined in the accent it read as a button. */
.api-verb {
  font-size: 10px; letter-spacing: .08em; color: var(--text-faint);
  border: 1px solid var(--border); padding: 2px 6px; border-radius: 5px;
}
.api-returns {
  margin-left: auto; font-size: 10.5px; letter-spacing: .05em; text-transform: uppercase;
  color: var(--text-xfaint);
}

.api-split { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 28px; }
.api-split > div { display: grid; gap: 12px; align-content: start; }

.api-pills { display: flex; flex-wrap: wrap; gap: 8px; }
.api-pill {
  padding: 6px 13px; border-radius: 7px; font-size: 12.5px;
  font-family: ui-monospace, monospace;
  border: 1px solid var(--border); color: var(--text-dim);
  background: color-mix(in srgb, var(--ink) 3%, transparent);
}
.api-opts { display: grid; gap: 8px; }
.api-opt { display: flex; align-items: baseline; gap: 11px; flex-wrap: wrap; }
.api-opt code {
  font-family: ui-monospace, monospace; font-size: 12px; color: var(--text);
}
.api-opt em { font-style: normal; font-size: 12.5px; color: var(--text-faint); }

.api-flow { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.api-flow i { color: var(--text-xfaint); font-style: normal; }
.api-step {
  display: grid; gap: 3px; padding: 11px 15px; border-radius: 11px;
  border: 1px solid var(--border);
  background: color-mix(in srgb, var(--ink) 3%, transparent);
}
.api-step code {
  font-family: ui-monospace, monospace; font-size: 12.5px; color: var(--text);
}
.api-step em { font-style: normal; font-size: 11px; color: var(--text-xfaint); }
.api-caps { display: flex; flex-wrap: wrap; gap: 22px; font-size: 12.5px; color: var(--text-faint); }
.api-caps b { color: var(--text); font-variant-numeric: tabular-nums; }

/* The startup failsafe's own line. It borrowed the progress commentary's element until that
   was removed, at which point a failed module graph produced a splash that said nothing. */
.boot-fail {
  margin: 26px 0 0; font-size: 13px; line-height: 1.6; color: var(--down);
}

/* ═══════════════════════════════════════════════════════════════════════════
   THE SIGNED-OUT PREVIEW

   uptrick.io's nav points at this page, so it is a room in that building and
   not a building of its own: the same bar, the same links, the same ink over
   the same ground, and a way back on every screen.

   It introduces one product and then gets out of the way. A name, a sentence,
   a door, and the product itself directly underneath. There are no plans on
   this page and no second pitch - the site already did that, and repeating it
   here is how a product page turns into a duplicate homepage.

   Colour is expressed twice: a ground (--pv-bg) and an ink (--pv-ink) laid
   over it at varying strength. Two hues exist, --pv-up and --pv-down, and
   they are spent only inside the market data, where a colour means a
   direction. One further hue, --pv-arc, exists only for the live edge around
   the preview frame, which is the same current that runs around the Ultra
   card on uptrick.io.

   Shape: rectangles with smoothed corners. The header bar is the one pill,
   because a bar is a bar.
   ═══════════════════════════════════════════════════════════════════════════ */

body.is-signed-out {
  --pv-bg: #08080a;
  --pv-lift: #0c0c10;
  --pv-sunk: #05070b;
  --pv-ink: #ffffff;

  --pv-surface: color-mix(in srgb, var(--pv-ink) 2.5%, transparent);
  --pv-surface-soft: color-mix(in srgb, var(--pv-ink) 1.5%, transparent);
  --pv-surface-hover: color-mix(in srgb, var(--pv-ink) 5%, transparent);
  --pv-border: color-mix(in srgb, var(--pv-ink) 9%, transparent);
  --pv-border-strong: color-mix(in srgb, var(--pv-ink) 16%, transparent);
  --pv-hairline: color-mix(in srgb, var(--pv-ink) 7%, transparent);

  --pv-text: color-mix(in srgb, var(--pv-ink) 95%, transparent);
  --pv-dim: color-mix(in srgb, var(--pv-ink) 72%, transparent);
  --pv-faint: color-mix(in srgb, var(--pv-ink) 55%, transparent);
  --pv-xfaint: color-mix(in srgb, var(--pv-ink) 40%, transparent);

  --pv-up: #7d9e8b;
  --pv-down: #a8757f;
  --pv-arc: #20e0d5;

  --pv-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
  --pv-ease: cubic-bezier(.4, 0, .2, 1);
  --pv-gutter: clamp(20px, 4vw, 44px);
  --pv-container: 1240px;
  --pv-hdr: 78px;

  /* The application's own tokens are answered too, so any shared control that
     lands on this page is painted in the same ink rather than in whatever
     accent the last visitor happened to store. */
  --bg: var(--pv-bg);
  --bg-lift: var(--pv-lift);
  --bg-panel: var(--pv-sunk);
  --ink: var(--pv-ink);
  --surface: var(--pv-surface);
  --surface-soft: var(--pv-surface-soft);
  --surface-hover: var(--pv-surface-hover);
  --border: var(--pv-border);
  --border-strong: var(--pv-border-strong);
  --text: var(--pv-text);
  --text-dim: var(--pv-dim);
  --text-faint: var(--pv-faint);
  --text-xfaint: var(--pv-xfaint);
  --up: var(--pv-up);
  --down: var(--pv-down);

  background: var(--pv-bg);
  color: var(--pv-text);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  letter-spacing: -.006em;
}

/* ── header ─────────────────────────────────────────────────────────────── */

body.is-signed-out .hdr {
  inset: 12px 0 auto;
  height: var(--pv-hdr);
  padding: 0 var(--pv-gutter);
  border: 0;
  background: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
/* Three tracks, so the nav sits dead centre of the bar however wide the
   wordmark or the buttons are. Flex would centre it between them instead. */
body.is-signed-out .hdr-inner {
  width: 100%;
  max-width: var(--pv-container);
  min-height: 58px;
  margin: 0 auto;
  padding: 9px 9px 9px 20px;
  /* Two columns: the mark, and the two doors. It was three - `1fr auto 1fr` - because there
     was a Pricing link centred between them, and the actions were only at the right edge by
     virtue of being the *third* child. Taking the middle one out left them holding the centre
     column, floating in the middle of an otherwise empty bar. Nothing sits between them now,
     so nothing is reserved for it. */
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 24px;
  border: 1px solid var(--pv-border);
  border-radius: 999px;
  background: color-mix(in srgb, var(--pv-bg) 72%, transparent);
  box-shadow: inset 0 1px 0 color-mix(in srgb, var(--pv-ink) 4%, transparent);
  -webkit-backdrop-filter: saturate(160%) blur(18px);
  backdrop-filter: saturate(160%) blur(18px);
  transition: background .3s var(--pv-ease), border-color .3s var(--pv-ease),
              box-shadow .3s var(--pv-ease);
}
/* Near solid once the page has moved. Display type scrolling underneath a
   merely tinted panel still reads through it, which turns the bar into a
   smear rather than a bar. */
body.is-signed-out .hdr.is-stuck .hdr-inner {
  background: color-mix(in srgb, var(--pv-bg) 97%, transparent);
  border-color: var(--pv-border-strong);
  box-shadow: 0 10px 34px rgba(0, 0, 0, .45);
}
body.is-signed-out .brand-mark {
  width: 30px; height: 30px; border-radius: 9px;
  color: var(--pv-text); background: transparent;
  border: 1px solid var(--pv-border-strong);
}
body.is-signed-out .brand-text { font-size: 15px; letter-spacing: -.02em; }
body.is-signed-out .brand-thin { color: var(--pv-dim); }

/* uptrick.io's links, set exactly as they are set there. */
.pv-nav { display: none; }
body.is-signed-out .pv-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(16px, 2vw, 28px);
}
body.is-signed-out .pv-nav a {
  font-size: 14.5px;
  color: var(--pv-dim);
  text-decoration: none;
  white-space: nowrap;
  padding: 6px 0;
  transition: color .22s var(--pv-ease);
}
body.is-signed-out .pv-nav a:hover { color: var(--pv-text); }

body.is-signed-out .hdr-right { justify-self: end; }
body.is-signed-out .hdr-auth { gap: 8px; }
body.is-signed-out .hdr-signin,
body.is-signed-out .hdr-signup {
  min-height: 40px;
  padding: 0 18px;
  border-radius: 999px;
  border: 1px solid transparent;
  font-size: 13.5px;
  font-weight: 560;
  letter-spacing: -.01em;
  /* Two words each, and on a 320px screen the pill was narrow enough to break them - "Log /
     in" and "Sign / up" stacked inside their own buttons. A label that wraps is never what was
     wanted; if there is no room the button should shrink, not fold. */
  white-space: nowrap;
  transition: background .22s var(--pv-ease), border-color .22s var(--pv-ease),
              color .22s var(--pv-ease);
}

body.is-signed-out .hdr-signin { color: var(--pv-dim); border-color: var(--pv-border); }
body.is-signed-out .hdr-signin:hover {
  color: var(--pv-text); background: var(--pv-surface-hover);
  border-color: var(--pv-border-strong);
}
body.is-signed-out .hdr-signup { color: var(--pv-bg); background: var(--pv-ink); }
body.is-signed-out .hdr-signup:hover {
  filter: none;
  background: color-mix(in srgb, var(--pv-ink) 86%, var(--pv-bg));
}

/* ── page shell ─────────────────────────────────────────────────────────── */

body.is-signed-out .landing {
  position: relative;
  width: 100%;
  margin: 0;
  padding: 0;
  overflow-x: clip;
}
.pv-wrap {
  width: 100%;
  max-width: var(--pv-container);
  margin: 0 auto;
  padding: 0 var(--pv-gutter);
}

/* One pool of light behind the name, no colour. It is the only thing on the
   page that is not either type or product. */
.pv-glow {
  position: absolute;
  z-index: 0;
  top: -18%; left: 50%;
  width: min(1100px, 130%);
  aspect-ratio: 1;
  transform: translateX(-50%);
  pointer-events: none;
  background: radial-gradient(circle,
    color-mix(in srgb, var(--pv-ink) 8%, transparent) 0%,
    color-mix(in srgb, var(--pv-ink) 3%, transparent) 34%,
    transparent 66%);
}

/* The spotlight on the name.
 *
 * Small on purpose. The brief was "premium", and the way that reads on a dark page is one
 * considered light rather than a lot of glow - so this is a single narrow beam falling from
 * above the header onto the headline, and nothing else. A wide ambient wash is what
 * `.pv-glow` already is; another one would just raise the black.
 *
 * **No clip-path, and that is the whole design note.** The first two passes cut a trapezoid
 * and blurred it - 30px, then 58px - and both times the clip survived as two faint diagonals
 * and a horizontal cut where the box ended, so the hero had a grey triangle printed on it
 * rather than a light. Blur cannot rescue a hard edge on a shape this large; it only spends
 * paint. Radial gradients have no edge to begin with, so the cone here is two of them
 * stacked: a narrow tall one at the ceiling for the origin, a wider shorter one under it for
 * the spread. Together they read as a beam and there is no geometry left to see.
 *
 * The source - the thin streak the beam leaves from - is the part that does the work. Two
 * pixels of light, and without something to come *from*, a tapering glow is just a gradient.
 */
.pv-beam {
  position: absolute; z-index: 0; pointer-events: none;
  top: -20px; left: 50%; transform: translateX(-50%);
  /* Tall enough to actually land on the name. At 500px the light gave out a hundred pixels
     above the headline, which is a glow at the top of the page rather than a spotlight on
     anything. */
  width: min(820px, 90vw); height: clamp(420px, 46vw, 640px);
  background:
    /* the origin: narrow, and reaching furthest down the page */
    radial-gradient(26% 72% at 50% 0%,
      color-mix(in srgb, var(--pv-ink) 12%, transparent), transparent 76%),
    /* the spread it opens into */
    radial-gradient(58% 96% at 50% 2%,
      color-mix(in srgb, var(--pv-ink) 6%, transparent), transparent 78%);
  filter: blur(26px);
  animation: pv-beam-in 1.8s var(--pv-ease) .3s both;
}
.pv-beam-source {
  position: absolute; z-index: 0; pointer-events: none;
  top: 0; left: 50%; transform: translateX(-50%);
  width: min(150px, 26vw); height: 2px;
  border-radius: 999px;
  background: linear-gradient(to right, transparent,
    color-mix(in srgb, var(--pv-ink) 34%, transparent), transparent);
  filter: blur(3px);
  animation: pv-beam-in 1.8s var(--pv-ease) .3s both;
}
@keyframes pv-beam-in { from { opacity: 0; } to { opacity: 1; } }

/* A reader who asked for less motion still gets the light, just not the fade onto it. */
@media (prefers-reduced-motion: reduce) {
  .pv-beam, .pv-beam-source { animation: none; }
}

/* ── the introduction ───────────────────────────────────────────────────── */

.pv-open {
  position: relative;
  z-index: 1;
  text-align: center;
  padding: calc(var(--pv-hdr) + clamp(70px, 11vw, 150px)) 0 clamp(46px, 6vw, 80px);
}
.pv-kicker {
  /* Block, not inline-block. The name below it is an inline-block so its
     spotlight overlay can size to the text rather than the column, and two
     inline-blocks in a centred container share a line. */
  display: block;
  margin-bottom: clamp(22px, 3vw, 34px);
  font-family: var(--pv-mono);
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--pv-faint);
  animation: pv-rise .8s var(--pv-ease) .1s both;
}

/* The name, and the one piece of theatre on the page.

   It arrives out of focus and settles, and a single pool of light travels
   across the letters once and stops. The sweep is on the text itself, not on
   a box around it, and it does not repeat: a headline that pulses forever is
   a headline nobody finishes reading. */
.pv-word {
  position: relative;
  display: inline-block;
  margin: 0;
  font-size: clamp(44px, 8.4vw, 116px);
  font-weight: 680;
  line-height: 1;
  letter-spacing: -.045em;
  /* The letters rest well below full ink until the light has crossed them.
     At 74% the sweep had nothing to reveal - a white band over near-white
     text is not a spotlight, it is a slightly whiter patch. */
  color: color-mix(in srgb, var(--pv-ink) 46%, transparent);
  animation: pv-word-in 1.15s var(--pv-ease) .18s both,
             pv-word-settle 1.25s var(--pv-ease) 1.85s both;
}
@keyframes pv-word-in {
  from { opacity: 0; transform: translateY(18px) scale(.985); filter: blur(14px); }
  to { opacity: 1; transform: none; filter: blur(0); }
}
@keyframes pv-word-settle { to { color: var(--pv-text); } }

/* The travelling light. A copy of the word, clipped to a narrow bright band
   that crosses once and fades out, leaving the settled text behind it. */
.pv-word::after {
  content: attr(data-word);
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: linear-gradient(100deg,
    transparent 38%,
    color-mix(in srgb, var(--pv-ink) 100%, transparent) 47%,
    color-mix(in srgb, var(--pv-ink) 100%, transparent) 53%,
    transparent 62%);
  background-size: 280% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  /* The band is the brightest thing on the page while it is travelling, and
     it carries its own bloom so the light looks like it is falling on the
     letters rather than being painted inside them. */
  filter: drop-shadow(0 0 22px color-mix(in srgb, var(--pv-ink) 42%, transparent));
  animation: pv-word-spot 2.6s var(--pv-ease) .7s both;
}
@keyframes pv-word-spot {
  from { background-position: 190% 0; opacity: 1; }
  78% { opacity: 1; }
  to { background-position: -70% 0; opacity: 0; }
}

.pv-line {
  max-width: 46ch;
  margin: clamp(20px, 2.6vw, 30px) auto 0;
  font-size: clamp(16px, 1.5vw, 19.5px);
  line-height: 1.62;
  color: var(--pv-dim);
  text-wrap: balance;
  animation: pv-rise .85s var(--pv-ease) .5s both;
}

/* ── buttons ────────────────────────────────────────────────────────────── */

.pv-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin-top: clamp(30px, 3.6vw, 44px);
  animation: pv-rise .85s var(--pv-ease) .68s both;
}
.pv-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 52px;
  padding: 0 26px;
  border: 1px solid transparent;
  border-radius: 11px;
  font-size: 15px;
  font-weight: 580;
  letter-spacing: -.012em;
  line-height: 1;
  white-space: nowrap;
  /* Half of these are anchors, and an anchor is underlined by the stylesheet
     the application shares. A control is not a link, whichever element it
     happens to be built from. */
  text-decoration: none;
  transition: background .22s var(--pv-ease), border-color .22s var(--pv-ease),
              color .22s var(--pv-ease), transform .22s var(--pv-ease);
}
.pv-btn-arrow { transition: transform .25s var(--pv-ease); }
.pv-btn:hover .pv-btn-arrow { transform: translateX(3px); }
.pv-btn-primary { background: var(--pv-ink); color: var(--pv-bg); }
.pv-btn-primary:hover { background: color-mix(in srgb, var(--pv-ink) 86%, var(--pv-bg)); }
.pv-btn-ghost { border-color: var(--pv-border-strong); color: var(--pv-text); }
.pv-btn-ghost:hover {
  border-color: color-mix(in srgb, var(--pv-ink) 34%, transparent);
  background: var(--pv-surface-hover);
}
.pv-btn:active { transform: translateY(1px); }

@keyframes pv-rise {
  from { opacity: 0; transform: translateY(14px); }
  to { opacity: 1; transform: none; }
}

/* What it does, under the name. Four short claims rather than a paragraph: this is the one
   place a visitor decides whether the product is for them, and a paragraph is where that
   decision goes to be postponed. */
.pv-does {
  display: grid;
  /* Four across on a desktop, two on a tablet, one on a phone. At 240px they wrapped 3 + 1,
     which reads as a list that ran out rather than as a set of four. */
  grid-template-columns: repeat(auto-fit, minmax(196px, 1fr));
  gap: clamp(20px, 2.4vw, 30px);
  max-width: 1120px;
  margin: clamp(44px, 5vw, 68px) auto 0;
  padding: clamp(26px, 3vw, 34px) 0 0;
  border-top: 1px solid var(--pv-hairline);
  list-style: none;
  text-align: left;
  animation: pv-rise .85s var(--pv-ease) .82s both;
}
.pv-does li { display: grid; gap: 7px; align-content: start; }
.pv-does b {
  font-size: 15px; font-weight: 620; letter-spacing: -.015em; color: var(--pv-text);
}
.pv-does span { font-size: 13.5px; line-height: 1.6; color: var(--pv-faint); }

/* ── the product ──────────────────────────────────────────────────────────
   Four surfaces in depth, not one flat picture. The dashboard is front and
   centre; the desk, the statistics and the automation lean in behind it and
   bleed off the sides, which is what makes the page read as a product with
   rooms in it rather than a table with a logo on top. */

.pv-show { position: relative; z-index: 1; padding: 0 0 clamp(60px, 8vw, 110px); }

/* The stack breaks out of the container to the full width of the window, and
   the dashboard inside it is what stays container-width. Without that there is
   nowhere for the leaning panels to be: a full-width dashboard leaves no room
   beside it, and the panels end up almost entirely behind it, showing a
   sliver of sliced text that reads as breakage rather than as depth.

   Wider windows therefore show more of them, which is the right way round. */
.pv-show .pv-wrap { max-width: none; padding-inline: 0; }
.pv-stack {
  position: relative;
  width: 100%;
  perspective: 2200px;
  perspective-origin: 50% 42%;
  padding: clamp(20px, 4vw, 64px) 0 clamp(28px, 5vw, 76px);
}

/* The panels behind. Each is a real little screen: the same chrome, the same
   type, at a size where you read the shape rather than the words. */
.pv-aside {
  position: absolute;
  overflow: hidden;
  border: 1px solid color-mix(in srgb, var(--pv-ink) 13%, transparent);
  border-radius: 16px;
  background: var(--pv-lift);
  box-shadow: 0 40px 90px rgba(0, 0, 0, .66);
  font-size: clamp(6.4px, .62vw, 9px);
  line-height: 1.5;
  transform-origin: 50% 50%;
  opacity: 0;
  transition: opacity 1s var(--pv-ease), transform 1.15s var(--pv-ease);
  will-change: opacity, transform;
}
.pv-aside-bar {
  display: flex; align-items: center; gap: .55em;
  padding: 0 1.3em; height: 3.4em;
  border-bottom: 1px solid var(--pv-hairline);
  background: color-mix(in srgb, var(--pv-ink) 2.4%, transparent);
}
.pv-aside-bar span {
  width: .7em; height: .7em; border-radius: 50%;
  background: color-mix(in srgb, var(--pv-ink) 20%, transparent);
}
.pv-aside-bar b {
  margin-left: .8em; font-family: var(--pv-mono); font-size: 1.05em; font-weight: 500;
  letter-spacing: .12em; text-transform: uppercase; color: var(--pv-faint);
}
.pv-aside-body { padding: 1.4em 1.5em; display: grid; gap: .75em; align-content: start; }
.pv-aside-lede { display: grid; gap: .25em; margin-bottom: .3em; }
.pv-aside-lede b { font-size: 1.65em; font-weight: 620; letter-spacing: -.025em; color: var(--pv-text); }
.pv-aside-lede em { font-style: normal; font-size: 1.1em; color: var(--pv-xfaint); }

/* The desk: who said it, what they said, whether we agree. */
.pv-voice {
  display: flex; align-items: center; gap: .8em;
  padding: .75em 0;
  border-top: 1px solid var(--pv-hairline);
  font-size: 1.2em;
}
.pv-voice i {
  display: grid; place-items: center;
  width: 2.1em; height: 2.1em; border-radius: 50%; flex: none;
  border: 1px solid var(--pv-border);
  font-style: normal; font-size: .82em; color: var(--pv-faint);
}
.pv-voice b { flex: 1; min-width: 0; font-weight: 500; color: var(--pv-dim);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pv-voice u {
  text-decoration: none; padding: .2em .6em; border-radius: .45em;
  border: 1px solid var(--pv-border); font-size: .88em;
}
.pv-voice u.up { color: var(--pv-up); border-color: color-mix(in srgb, var(--pv-up) 34%, transparent); }
.pv-voice u.dn { color: var(--pv-down); border-color: color-mix(in srgb, var(--pv-down) 34%, transparent); }
.pv-voice em { font-style: normal; font-size: .88em; color: var(--pv-xfaint); white-space: nowrap; }

/* Statistics: the three shortlists, as counts. */
.pv-ops { display: grid; grid-template-columns: repeat(3, 1fr); gap: .7em; }
.pv-ops > div {
  display: grid; gap: .3em; padding: 1em;
  border: 1px solid var(--pv-hairline); border-radius: .8em;
}
.pv-ops small {
  font-family: var(--pv-mono); font-size: .92em; letter-spacing: .07em;
  text-transform: uppercase; color: var(--pv-faint);
}
.pv-ops strong {
  font-family: var(--pv-mono); font-size: 2.4em; font-weight: 500; letter-spacing: -.03em;
  color: var(--pv-text); line-height: 1;
}
.pv-ops i { font-style: normal; font-size: .92em; color: var(--pv-xfaint); line-height: 1.4; }
.pv-ops i.up { color: color-mix(in srgb, var(--pv-up) 88%, transparent); }
.pv-ops i.dn { color: color-mix(in srgb, var(--pv-down) 88%, transparent); }
.pv-dist { display: flex; gap: .25em; height: .5em; border-radius: 999px; overflow: hidden; }
.pv-dist span { width: var(--w); background: color-mix(in srgb, var(--pv-ink) 20%, transparent); }
.pv-dist span:first-child { background: var(--pv-up); }
.pv-dist span:last-child { background: var(--pv-down); }

/* Automation: a switch waiting to be answered, which is the whole shape of it. */
.pv-auto-row { display: flex; align-items: center; gap: .8em; font-size: 1.35em; }
.pv-auto-row b { flex: 1; font-weight: 560; color: var(--pv-text); }
.pv-auto-row u {
  text-decoration: none; padding: .2em .65em; border-radius: .45em; font-size: .82em;
  border: 1px solid var(--pv-border); color: var(--pv-faint);
}
.pv-auto-row u.on {
  color: var(--pv-up); border-color: color-mix(in srgb, var(--pv-up) 36%, transparent);
  background: color-mix(in srgb, var(--pv-up) 10%, transparent);
}
.pv-auto-note { font-size: 1.15em; color: var(--pv-xfaint); }
.pv-auto-note b { color: var(--pv-dim); font-weight: 500; }
.pv-auto-cta { display: flex; gap: .5em; margin-top: .2em; }
.pv-auto-cta i {
  padding: .5em 1.1em; border-radius: .55em; font-style: normal; font-size: 1.1em;
  border: 1px solid var(--pv-border); color: var(--pv-faint);
}
.pv-auto-cta i.ok { color: var(--pv-bg); background: var(--pv-ink); border-color: var(--pv-ink); font-weight: 600; }

/* Watchlist: a second foreground object balances Automation without mirroring it. */
.pv-watch-title, .pv-watch-row, .pv-watch-foot { display: flex; align-items: center; gap: .8em; }
.pv-watch-title b { flex: 1; color: var(--pv-text); font-size: 1.35em; font-weight: 580; }
.pv-watch-title u { text-decoration: none; color: var(--pv-up); font-family: var(--pv-mono); }
.pv-watch-row { padding: .8em 0; border-block: 1px solid var(--pv-hairline); font-size: 1.18em; }
.pv-watch-row span { flex: 1; color: var(--pv-dim); }
.pv-watch-row b { color: var(--pv-text); font-family: var(--pv-mono); font-weight: 500; }
.pv-watch-row i { font-style: normal; color: var(--pv-up); font-family: var(--pv-mono); }
.pv-watch-foot { justify-content: space-between; color: var(--pv-xfaint); font-size: 1.05em; }
.pv-watch-foot i { padding: .4em .75em; border: 1px solid var(--pv-border); border-radius: .5em; font-style: normal; color: var(--pv-faint); }

/* Placement. Each panel is tipped away from the reader and pushed back in Z,
   so the dashboard in front of them reads as the nearest object rather than
   as a bigger one. */
/* Turned hard enough to read as turned. At 19 degrees on a panel this size
   the perspective is barely doing anything and the result looks like a flat
   rectangle that happens to be behind another one. */
/* Both sit wholly inside the window. Bleeding them past its edge sliced their
   type against it, and half a word cut by the browser frame reads as a layout
   fault, not as a screen standing behind another one. They disappear on their
   inner side instead, behind the dashboard, which is where an object further
   away is supposed to go. */
/* A rotated panel occupies more room than its layout box: the half turned
   toward the reader swings out past it, and by how much depends on the window
   width. Rather than chase that with a breakpoint, each panel dissolves along
   its outer edge - so whatever falls off the side of the window fades into
   the ground instead of being guillotined mid-word, at every width. */
.pv-aside--analysts {
  z-index: 1;
  left: 3%; top: 1%;
  width: 35%;
  transform: rotateX(7deg) rotateY(27deg) rotateZ(-3.5deg) translate3d(-3%, 4%, -300px);
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, #000 26%, #000 100%);
  mask-image: linear-gradient(90deg, transparent 0%, #000 26%, #000 100%);
}
.pv-aside--stats {
  z-index: 1;
  right: 3%; top: 5%;
  width: 33%;
  transform: rotateX(7deg) rotateY(-27deg) rotateZ(3.5deg) translate3d(3%, 3%, -280px);
  -webkit-mask-image: linear-gradient(270deg, transparent 0%, #000 26%, #000 100%);
  mask-image: linear-gradient(270deg, transparent 0%, #000 26%, #000 100%);
}
/* In front of the dashboard, straddling its lower-left corner. A float that
   sits wholly inside a panel is just another card on it; half on and half off
   is what puts it in front. */
.pv-aside--auto {
  z-index: 4;
  left: 7%; bottom: 1%;
  width: 20%;
  transform: rotateX(5deg) rotateY(16deg) rotateZ(-2deg) translate3d(-4%, 6%, 150px);
}
.pv-aside--watch {
  z-index: 4;
  right: 7%; bottom: 2%;
  width: 21%;
  transform: rotateX(5deg) rotateY(-17deg) rotateZ(2.2deg) translate3d(4%, 7%, 165px);
}
.pv-stack.is-in .pv-aside { opacity: 1; }
/* Each panel's resting transform, with the zoom's departure folded into the same declaration.
   It has to be one `transform` - a second rule setting the property again would replace the
   rotations rather than adding to them - so `--pv-shift` is a translate on the front of it,
   and it is zero until the runway starts moving. */
.pv-stack.is-in .pv-aside--analysts {
  transform: translate3d(var(--pv-shift, 0px), 0, 0)
             rotateX(7deg) rotateY(27deg) rotateZ(-3.5deg) translate3d(0, 0, -300px);
}
.pv-stack.is-in .pv-aside--stats {
  transform: translate3d(var(--pv-shift, 0px), 0, 0)
             rotateX(7deg) rotateY(-27deg) rotateZ(3.5deg) translate3d(0, 0, -280px);
}
.pv-stack.is-in .pv-aside--auto {
  transform: translate3d(var(--pv-shift, 0px), 0, 0)
             rotateX(5deg) rotateY(16deg) rotateZ(-2deg) translate3d(0, 0, 150px);
}
.pv-stack.is-in .pv-aside--watch {
  transform: translate3d(var(--pv-shift, 0px), 0, 0)
             rotateX(5deg) rotateY(-17deg) rotateZ(2.2deg) translate3d(0, 0, 165px);
}
/* Behind the front panel, so they read as background rather than as competition. */
.pv-aside--analysts, .pv-aside--stats { filter: saturate(.85) brightness(.86); }

/* The frame the dashboard sits in. It rises into place once, on scroll, and
   then holds still. */
.pv-frame {
  position: relative;
  z-index: 3;
  isolation: isolate;
  /* A little narrower than the container the rest of the page uses, which is
     the room the panels behind it lean into. */
  width: min(1120px, 100% - var(--pv-gutter) * 2);
  margin-inline: auto;
  border-radius: 20px;
  background: var(--pv-lift);
  box-shadow: 0 50px 120px rgba(0, 0, 0, .75);
  opacity: 0;
  transform: translateY(26px) scale(.99);
  transition: opacity .9s var(--pv-ease), transform 1.05s var(--pv-ease);
  will-change: opacity, transform;
}
.pv-stack.is-in .pv-frame { opacity: 1; transform: none; }

/* ── the live edge ────────────────────────────────────────────────────────
   A current that travels around the frame and *is* its border.

   This replaced an SVG turbulence filter borrowed from the Ultra card. That
   construction is fine around a 360px pricing card and is not fine around a
   1120px panel: four feTurbulence passes at ten octaves over an area that
   large are re-rastered every frame, which is what made the edge sit still,
   then start crawling, then take the page down with it. The filter also
   displaced the border by up to 18px, so on a narrow window the "border" was
   drawn well inside the panel, straight across the content.

   What replaces it costs the compositor one rotation and the main thread
   nothing. A conic gradient is painted *once* into an oversized square, and
   that square is spun with `transform`. The obvious version of this animates
   the gradient's own angle instead, which looks identical and repaints the
   whole gradient every frame - the same mistake one layer down.

   The square is then clipped to the frame's rounded rectangle and masked down
   to a 1.5px band, so what shows is a line exactly on the edge. It is on the
   edge because it *is* the edge; there is no border underneath it. */

.pv-edge {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
}
.pv-edge-ring {
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  overflow: hidden;
}

/* The bloom the edge throws. Deliberately *static*: a blurred layer that also
   rotates has to be re-rastered every frame, and measured on this page that
   one property was the difference between 61fps and 37 - the entire cost of
   the effect, in the one layer nobody looks directly at. So the glow is an
   even ring of light that simply sits there, and every bit of the motion
   comes from the crisp band travelling over it. Blurring a border rather than
   a gradient keeps it even all the way round. */
.pv-edge-halo {
  position: absolute;
  inset: -3px;
  z-index: -1;
  border: 3px solid color-mix(in srgb, var(--pv-arc) 62%, transparent);
  border-radius: inherit;
  filter: blur(15px);
  opacity: .72;
}
.pv-edge-halo::before { content: none; }

/* The spinning light. Square and oversized so its corners still cover the
   frame at every angle: a rotating rectangle only covers a box whose half
   diagonal fits inside the rectangle's shorter half side. */
.pv-edge-ring::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 155%;
  aspect-ratio: 1;
  transform-origin: 50% 50%;
  background: conic-gradient(
    transparent 0deg 168deg,
    color-mix(in srgb, var(--pv-arc) 30%, transparent) 214deg,
    var(--pv-arc) 268deg,
    #c8fffa 292deg,
    var(--pv-arc) 316deg,
    color-mix(in srgb, var(--pv-arc) 24%, transparent) 344deg,
    transparent 360deg);
  animation: pv-spin 7s linear infinite;
  will-change: transform;
}
/* The band. Everything inside the 1.5px inset is masked away, leaving a line. */
.pv-edge-ring {
  padding: 1.5px;
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
}

@keyframes pv-spin {
  from { transform: translate(-50%, -50%) rotate(0turn); }
  to { transform: translate(-50%, -50%) rotate(1turn); }
}

/* Stopped while the sign-in dialog is up. It is behind a full-window blur there, so it
   cannot be seen, and every frame it moves forces that blur to be recomputed. */
body.is-gate-open .pv-edge-ring::before { animation-play-state: paused; }

/* ── the interface, drawn in markup ─────────────────────────────────────────
   Everything below is sized in `em` off one root font size on `.pv-app`, so
   the whole mock scales as one object with the viewport instead of thirty
   declarations each needing their own breakpoint. */

.pv-app {
  position: relative;
  overflow: hidden;
  border-radius: 20px;
  background: var(--pv-lift);
  font-size: clamp(7.4px, .78vw, 11px);
  line-height: 1.5;
}
/* Reads as a screen rather than a page: the light falls on the top edge. */
.pv-app::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  box-shadow: inset 0 1px 0 color-mix(in srgb, var(--pv-ink) 9%, transparent),
              inset 0 0 0 1px color-mix(in srgb, var(--pv-ink) 6%, transparent);
  z-index: 3;
}

.pv-app-bar {
  display: flex;
  align-items: center;
  gap: 1.6em;
  padding: .85em 1.2em;
  border-bottom: 1px solid var(--pv-hairline);
  background: color-mix(in srgb, var(--pv-ink) 2%, transparent);
}
.pv-app-brand {
  display: flex;
  align-items: center;
  gap: .55em;
  font-size: 1.15em;
  letter-spacing: -.02em;
  color: var(--pv-dim);
  white-space: nowrap;
}
.pv-app-brand b { color: var(--pv-text); font-weight: 620; margin-left: .28em; }
.pv-app-mark {
  display: grid;
  place-items: center;
  width: 1.75em; height: 1.75em;
  border: 1px solid var(--pv-border-strong);
  border-radius: .45em;
  color: var(--pv-text);
}
.pv-app-mark svg { width: .58em; height: 1.05em; }
.pv-app-tabs { display: flex; gap: .15em; }
.pv-app-tabs i {
  padding: .45em .85em;
  border-radius: 999px;
  font-size: 1.02em;
  font-style: normal;
  color: var(--pv-xfaint);
  white-space: nowrap;
}
.pv-app-tabs i.on {
  color: var(--pv-text);
  background: color-mix(in srgb, var(--pv-ink) 10%, transparent);
}
.pv-app-right { margin-left: auto; display: flex; align-items: center; gap: .7em; }
.pv-app-dot {
  width: .55em; height: .55em; border-radius: 50%;
  background: var(--pv-up);
  box-shadow: 0 0 0 .3em color-mix(in srgb, var(--pv-up) 16%, transparent);
}
.pv-app-stamp {
  font-family: var(--pv-mono); font-size: .92em; font-style: normal;
  color: var(--pv-xfaint); white-space: nowrap;
}
.pv-app-avatar {
  display: grid; place-items: center;
  width: 2em; height: 2em; border-radius: 50%;
  border: 1px solid var(--pv-border-strong);
  font-size: .95em; font-style: normal; color: var(--pv-dim);
}

.pv-app-page { padding: 1.5em 1.4em 1.7em; display: grid; gap: 1.15em; }
.pv-app-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 1.5em; }
.pv-app-head h2 {
  margin: 0; font-size: 2em; font-weight: 640; letter-spacing: -.03em; color: var(--pv-text);
}
.pv-app-head p {
  margin: .4em 0 0; max-width: 52ch;
  font-size: 1.05em; color: var(--pv-faint); line-height: 1.55;
}
.pv-app-switch { display: inline-flex; align-items: center; gap: .6em; white-space: nowrap; }
.pv-app-switch i { font-style: normal; font-size: 1em; color: var(--pv-faint); }
.pv-app-switch u {
  position: relative;
  width: 2.4em; height: 1.35em;
  border-radius: 999px;
  background: color-mix(in srgb, var(--pv-ink) 26%, transparent);
  text-decoration: none;
}
.pv-app-switch u::after {
  content: "";
  position: absolute; top: 50%; right: .18em;
  width: 1em; height: 1em;
  border-radius: 50%;
  background: var(--pv-ink);
  transform: translateY(-50%);
}

.pv-app-strip { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: .7em; }
.pv-app-stat, .pv-app-list {
  display: grid;
  align-content: start;
  gap: .4em;
  padding: .95em 1em;
  border: 1px solid var(--pv-hairline);
  border-radius: .85em;
  background: color-mix(in srgb, var(--pv-ink) 1.6%, transparent);
}
.pv-app-stat b {
  font-family: var(--pv-mono); font-size: 1.65em; font-weight: 500; letter-spacing: -.03em;
  color: var(--pv-text);
}
.pv-app-stat em { font-style: normal; font-size: .95em; color: var(--pv-xfaint); }
/* Drawn against the card, not filled: a sparkline with a shaded area under it
   reads as a chart that wants attention, and this one is a footnote. */
.pv-spark { width: 100%; height: 2.6em; margin-top: .2em; overflow: visible; }
.pv-spark path { fill: none; stroke: var(--pv-up); stroke-width: 1.3; vector-effect: non-scaling-stroke; }
.pv-app-meter {
  display: block; height: .38em; margin-top: .35em; border-radius: 999px;
  background: color-mix(in srgb, var(--pv-ink) 9%, transparent); overflow: hidden;
}
.pv-app-meter i { display: block; height: 100%; border-radius: 999px; background: var(--pv-up); }
.pv-app-list-hd {
  font-family: var(--pv-mono); font-size: .88em; letter-spacing: .1em; text-transform: uppercase;
  color: var(--pv-faint); margin-bottom: .2em;
}
.pv-app-row { display: flex; align-items: center; gap: .5em; font-size: .98em; }
.pv-app-row img { width: 1.3em; height: 1.3em; object-fit: contain; opacity: .85; }
.pv-app-row b { flex: 1; min-width: 0; font-weight: 500; color: var(--pv-dim);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pv-app-row u { text-decoration: none; font-family: var(--pv-mono); }
.pv-app-row u.up { color: var(--pv-up); }

.pv-app-controls { display: flex; gap: .5em; flex-wrap: wrap; align-items: center; }
.pv-app-seg {
  display: inline-flex; gap: .1em; padding: .2em;
  border: 1px solid var(--pv-hairline); border-radius: 999px;
}
.pv-app-seg i {
  padding: .4em .85em; border-radius: 999px; font-size: .95em; font-style: normal;
  color: var(--pv-xfaint); white-space: nowrap;
}
.pv-app-seg i.on { color: var(--pv-text); background: color-mix(in srgb, var(--pv-ink) 10%, transparent); }

/* The rest of the real toolbar: the starred filter, the search field and the
   button that adds metric columns. Leaving these out made the mock look like
   a report; they are how the board is actually driven. */
.pv-app-chip, .pv-app-search {
  display: inline-flex; align-items: center; gap: .55em;
  height: 2.55em; padding: 0 .95em;
  border: 1px solid var(--pv-hairline); border-radius: 999px;
  font-size: .95em; color: var(--pv-xfaint); white-space: nowrap;
}
.pv-app-chip svg, .pv-app-search svg { width: 1.25em; height: 1.25em; flex: none; }
.pv-app-search { flex: 1; min-width: 9em; max-width: 18em; justify-content: flex-start; }
.pv-app-plus {
  display: grid; place-items: center;
  width: 2.55em; height: 2.55em;
  border: 1px dashed color-mix(in srgb, var(--pv-ink) 18%, transparent);
  border-radius: 999px;
  font-size: 1.25em; line-height: 1; color: var(--pv-faint);
}

.pv-app-table {
  border: 1px solid var(--pv-hairline);
  border-radius: .85em;
  overflow: hidden;
  background: color-mix(in srgb, var(--pv-ink) 1.4%, transparent);
}
.pv-app-tr {
  display: grid;
  grid-template-columns: minmax(0, 1.7fr) minmax(0, .95fr) minmax(0, .7fr)
                         minmax(0, 1.15fr) minmax(0, 1.15fr) minmax(0, .95fr);
  align-items: center;
  gap: .7em;
  padding: .72em 1em;
  border-bottom: 1px solid var(--pv-hairline);
  font-size: 1em;
  color: var(--pv-dim);
}
.pv-app-tr:last-child { border-bottom: 0; }
.pv-app-th {
  font-family: var(--pv-mono); font-size: .85em; letter-spacing: .1em; text-transform: uppercase;
  color: var(--pv-xfaint);
  background: color-mix(in srgb, var(--pv-ink) 2.4%, transparent);
}
.pv-app-sym { display: flex; align-items: center; gap: .55em; color: var(--pv-text); }
.pv-app-sym img { width: 1.5em; height: 1.5em; object-fit: contain; opacity: .9; }
.pv-app-sym u {
  text-decoration: none; font-family: var(--pv-mono); font-size: .88em; color: var(--pv-xfaint);
}
.pv-num { font-family: var(--pv-mono); font-variant-numeric: tabular-nums; }
.pv-num.up { color: var(--pv-up); }
.pv-num.dn { color: var(--pv-down); }

/* The verdict chip carries its score, because the label alone is a claim and
   the number is the evidence for it. */
.pv-chip {
  display: inline-flex; align-items: baseline; gap: .45em;
  padding: .3em .7em;
  border: 1px solid var(--pv-border);
  border-radius: .5em;
  font-size: .95em;
  white-space: nowrap;
  width: fit-content;
}
.pv-chip i {
  font-style: normal; font-family: var(--pv-mono); font-size: .86em; opacity: .72;
}
.pv-chip.up { color: var(--pv-up); border-color: color-mix(in srgb, var(--pv-up) 36%, transparent); }
.pv-chip.dn { color: var(--pv-down); border-color: color-mix(in srgb, var(--pv-down) 36%, transparent); }
.pv-chip.nt { color: var(--pv-faint); }
.pv-act {
  padding: .3em .7em; border-radius: .5em; font-size: .95em; font-weight: 550;
  white-space: nowrap; width: fit-content;
  border: 1px solid transparent;
}
.pv-act.dca { color: var(--pv-up); background: color-mix(in srgb, var(--pv-up) 14%, transparent);
  border-color: color-mix(in srgb, var(--pv-up) 30%, transparent); }
.pv-act.tp { color: var(--pv-down); background: color-mix(in srgb, var(--pv-down) 14%, transparent);
  border-color: color-mix(in srgb, var(--pv-down) 30%, transparent); }
.pv-act.hold { color: var(--pv-dim); border-color: var(--pv-border); }
.pv-act.none { color: var(--pv-xfaint); }

/* ── footer ─────────────────────────────────────────────────────────────── */

.pv-foot {
  position: relative;
  z-index: 1;
  padding: clamp(26px, 3vw, 40px) 0;
  border-top: 1px solid var(--pv-hairline);
}
.pv-foot-inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: 18px; flex-wrap: wrap;
}
.pv-foot-back {
  display: inline-flex; align-items: center; gap: 9px;
  font-size: 13.5px; color: var(--pv-faint); text-decoration: none;
  transition: color .22s var(--pv-ease);
}
.pv-foot-back span { transition: transform .25s var(--pv-ease); }
.pv-foot-back:hover { color: var(--pv-text); }
.pv-foot-back:hover span { transform: translateX(-3px); }
.pv-foot-fine {
  font-family: var(--pv-mono); font-size: 11px; letter-spacing: .08em; color: var(--pv-xfaint);
}

/* ── cursor ───────────────────────────────────────────────────────────────
   The same direct pointer uptrick.io uses, so arriving from the site does not
   feel like landing somewhere else. Mounted only while signed out, so no
   control inside the application loses its native cursor. */

.site-cursor { display: none; }
@media (pointer: fine) {
  body.is-signed-out,
  body.is-signed-out a,
  body.is-signed-out button,
  body.is-signed-out input,
  body.is-signed-out label { cursor: none !important; }
  /* The dialog is a form. Taking the caret away from a field somebody is
     typing an address into is the one place this costs more than it gives. */
  body.is-signed-out .gate-backdrop,
  body.is-signed-out .gate-backdrop * { cursor: auto !important; }
  body.is-signed-out .gate-backdrop button,
  body.is-signed-out .gate-backdrop a { cursor: pointer !important; }
  body.is-signed-out .gate-backdrop input { cursor: text !important; }

  body.is-signed-out .site-cursor {
    position: fixed;
    z-index: calc(var(--z-modal) + 10);
    left: 0; top: 0;
    display: block;
    width: 9px; height: 9px;
    border-radius: 999px;
    background: #f4f6f7;
    pointer-events: none;
    opacity: 0;
    mix-blend-mode: difference;
    transition: width .18s var(--pv-ease), height .18s var(--pv-ease),
                opacity .18s var(--pv-ease);
    transform: translate3d(-40px, -40px, 0) translate(-50%, -50%);
    will-change: transform, width, height;
  }
  body.is-signed-out .site-cursor.is-visible { opacity: 1; }
  body.is-signed-out .site-cursor.is-clickable { width: 15px; height: 15px; }
  body.is-signed-out .site-cursor.is-pressed { width: 6px; height: 6px; }
  body.is-signed-out .site-cursor.is-native { opacity: 0; }
}

/* ── responsive ─────────────────────────────────────────────────────────── */

@media (max-width: 1180px) {
  /* The leaning panels need room either side. Below this they would be more
     than half off-screen, which reads as breakage rather than as depth, so
     the composition flattens to the dashboard alone. */
  .pv-aside { display: none; }
  .pv-stack { perspective: none; padding-block: 0; }
  .pv-show .pv-wrap { padding-inline: var(--pv-gutter); }
  .pv-frame { width: 100%; }
}
@media (max-width: 1040px) {
  body.is-signed-out .hdr-inner { gap: 16px; }
  .pv-app-strip { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .pv-app-search { display: none; }
}
@media (max-width: 720px) {
  body.is-signed-out .hdr { inset: 8px 0 auto; padding-inline: 12px; }
  body.is-signed-out .hdr-inner { padding-left: 16px; gap: 12px; }
  body.is-signed-out .hdr-signin,
  body.is-signed-out .hdr-signup { min-height: 36px; padding-inline: 14px; font-size: 12.5px; }
  .pv-actions { flex-direction: column; align-items: stretch; }
  .pv-btn { width: 100%; }
  /* The application hides its wordmark below 760px so the tab strip has room.
     There are no tabs on this page, and the name is the thing it is
     introducing, so it stays. */
  body.is-signed-out .brand { gap: 10px; }
  body.is-signed-out .brand-text { display: inline; font-size: 14px; }

  body.is-signed-out .pv-nav { display: none; }

  .pv-app { font-size: 9px; }
  /* On a phone the toolbar is the least interesting row on the screen and the
     first to become clutter. The class switch alone survives. */
  .pv-app-controls > :nth-child(n+3) { display: none; }
  /* A six-column market table does not fit a phone, and shrinking the type
     until it does makes it a picture of a table rather than a table. Three
     columns survive: what it is, what it costs, and what to do about it.
     Exactly three must be hidden - hiding two leaves four items to flow into
     three tracks, and the fourth wraps onto a line of its own. */
  .pv-app-tr { grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr) minmax(0, 1.05fr); }
  .pv-app-tr > :nth-child(3),
  .pv-app-tr > :nth-child(4),
  .pv-app-tr > :nth-child(5) { display: none; }
  .pv-app-head { flex-direction: column; gap: .8em; }
  .pv-app-tabs, .pv-app-stamp { display: none; }
  .pv-foot-inner { flex-direction: column; align-items: flex-start; gap: 10px; }
}

@media (prefers-reduced-motion: reduce) {
  .pv-kicker, .pv-word, .pv-word::after, .pv-line, .pv-actions { animation: none; }
  .pv-word { color: var(--pv-text); }
  .pv-word::after { content: none; }
  .pv-frame, .pv-aside { opacity: 1; transform: none; transition: none; }
  .pv-stack { perspective: none; }
  .pv-aside { display: none; }
  /* The edge is the one thing here that loops. It is a decorative current
     around a frame, so for a reader who has asked for stillness it stops
     travelling and becomes a plain quiet border rather than disappearing and
     leaving an unframed box. */
  .pv-edge-ring::before { animation: none; background: var(--pv-border-strong); }
  .pv-edge-halo { display: none; }
  .pv-btn, .site-cursor { transition: none !important; }
}

/* ── members: who uses this, and what for ─────────────────────────────────
   Administrators only. Built from the same tokens as everything else, so it inherits both
   themes and every colour scheme without a rule of its own - the one exception is the
   category palette, which has to stay fixed because a slice's colour is its identity. */
.adm-top { display: flex; justify-content: flex-end; margin-bottom: 16px; }
.adm-tiles {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px;
  margin-bottom: 16px;
}
.adm-tile {
  display: grid; gap: 4px; padding: 15px 17px; border-radius: 14px;
  border: 1px solid var(--border); background: var(--bg-lift);
}
.adm-tile small {
  color: var(--text-faint); font-size: 10px; letter-spacing: .07em; text-transform: uppercase;
}
.adm-tile b { font-size: 22px; font-weight: 500; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.adm-tile i { font-size: 11.5px; font-style: normal; color: var(--text-faint); }
@media (max-width: 900px) { .adm-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 520px) { .adm-tiles { grid-template-columns: 1fr; } }

.adm-card { display: grid; gap: 18px; padding: 24px 26px; margin-bottom: 16px; }
.adm-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }
.adm-head h2 { margin: 0 0 4px; font-size: 18px; font-weight: 500; letter-spacing: -.01em; }
.adm-block { display: grid; gap: 10px; }
.adm-block h3 {
  margin: 0; font-size: 11px; font-weight: 550; letter-spacing: .07em;
  text-transform: uppercase; color: var(--text-faint);
}

.adm-table td { vertical-align: middle; }
.adm-table tbody tr { cursor: pointer; }
.adm-table tbody tr.is-open {
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}
.adm-who { display: grid; gap: 1px; min-width: 0; }
.adm-who b { font-weight: 500; }
.adm-who i { font-style: normal; font-size: 11.5px; color: var(--text-faint); }
.adm-top-cell, .adm-top { display: inline-flex; align-items: center; gap: 7px; }
.adm-top small { color: var(--text-faint); font-size: 11.5px; }
.adm-seen { color: var(--text-faint); font-size: 12px; white-space: nowrap; }
.adm-idle { color: var(--text-xfaint); }
.adm-swatch { width: 9px; height: 9px; border-radius: 3px; flex: none; }

/* One running system, as a badge. Live ones - armed and on `auto`, the only combination that
   spends money unattended - carry the accent; every other mode is quiet grey, because a page
   that shouts about a paper run has nothing left to shout with when a real one appears. */
.adm-autos { display: flex; flex-wrap: wrap; gap: 6px; }
.adm-auto {
  display: inline-flex; align-items: baseline; gap: 6px; padding: 3px 9px;
  border-radius: 999px; font-size: 11.5px;
  border: 1px solid var(--border); background: var(--surface); color: var(--text-dim);
}
.adm-auto b { font-weight: 550; color: var(--text); letter-spacing: .02em; }
.adm-auto i { font-style: normal; }
.adm-auto em { font-style: normal; color: var(--text-faint); }
.adm-auto.is-live {
  border-color: color-mix(in srgb, var(--up) 45%, transparent);
  background: color-mix(in srgb, var(--up) 12%, transparent);
  color: var(--text);
}
.adm-autos.is-full { gap: 8px; }
.adm-autos.is-full .adm-auto { padding: 7px 13px; font-size: 12.5px; }

.adm-split { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 26px; align-items: center; }
@media (max-width: 720px) { .adm-split { grid-template-columns: 1fr; justify-items: center; } }
.adm-split-body { min-width: 0; width: 100%; }
.adm-donut { position: relative; width: var(--size); height: var(--size); flex: none; }
.adm-donut svg { display: block; width: 100%; height: 100%; }
.adm-arc { transition: opacity .16s var(--ease); }
.adm-donut:hover .adm-arc { opacity: .45; }
.adm-donut .adm-arc:hover { opacity: 1; }
.adm-donut-centre {
  position: absolute; inset: 0; display: grid; align-content: center; justify-items: center;
  gap: 1px; pointer-events: none; text-align: center;
}
.adm-donut-centre b { font-size: 17px; font-weight: 500; font-variant-numeric: tabular-nums; }
.adm-donut-centre small { font-size: 10px; color: var(--text-faint); letter-spacing: .06em; text-transform: uppercase; }
.adm-donut.is-empty {
  display: grid; place-items: center; text-align: center; border-radius: 50%;
  border: 2px dashed var(--border); color: var(--text-faint); font-size: 11.5px; padding: 18px;
}

.adm-legend { display: grid; gap: 3px; margin: 0; padding: 0; list-style: none; }
.adm-legend li {
  display: grid; grid-template-columns: 9px minmax(84px, auto) minmax(40px, 1fr) auto 34px;
  align-items: center; gap: 10px; padding: 4px 0; font-size: 12.5px;
}
.adm-legend-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.adm-legend-bar {
  height: 5px; border-radius: 999px; background: var(--surface); overflow: hidden;
}
.adm-legend-bar i { display: block; height: 100%; border-radius: 999px; }
.adm-legend b { font-weight: 500; font-variant-numeric: tabular-nums; }
.adm-legend small { color: var(--text-faint); text-align: right; font-variant-numeric: tabular-nums; }

.adm-plain { display: grid; gap: 1px; margin: 0; padding: 0; list-style: none; }
.adm-plain li {
  display: flex; align-items: center; gap: 10px; padding: 8px 2px; font-size: 12.5px;
  border-top: 1px solid var(--border);
}
.adm-plain li:first-child { border-top: none; }
.adm-plain b { font-weight: 500; }
.adm-plain span { color: var(--text-faint); }
.adm-plain em { margin-left: auto; font-style: normal; color: var(--text-dim); white-space: nowrap; }
.adm-places b { font-variant-numeric: tabular-nums; }

.adm-days { width: 100%; height: 64px; display: block; }
.adm-person { border-color: color-mix(in srgb, var(--accent) 30%, var(--border)); }

/* The worker-is-down banner. Given its own rule because a `pf-notice` is a one-line toast and
   this is two sentences that have to be read - a customer whose systems are armed and not
   being swept is being told the single most important thing this page can say. */
.rot-unattended { display: grid; gap: 5px; margin-bottom: 16px; }
.rot-unattended b { font-weight: 600; }
.rot-unattended p { margin: 0; font-size: 12.5px; line-height: 1.6; opacity: .92; }

/* ── closing a holding ─────────────────────────────────────────────────────
   A market order against a real account, so the control is deliberately not a one-tap
   button: the size is chosen, the figure is spelled out in the units being sold, and the
   confirm is the danger colour. */
.pf-close-cell { text-align: right; white-space: nowrap; }
.pf-close-btn { color: var(--text-dim); }
.pf-close-btn:hover { color: var(--down); }
.pf-table tbody tr:not(:hover) .pf-close-btn { opacity: .55; }

.pf-close-modal { width: min(440px, 100%); display: grid; gap: 18px; padding: 26px 28px 22px; }
.pf-close-modal h3 { margin: 0 0 5px; font-size: 18px; font-weight: 500; letter-spacing: -.01em; }
.pf-close-amount {
  display: flex; align-items: baseline; gap: 12px; padding: 14px 16px;
  border-radius: 12px; border: 1px solid var(--border); background: var(--surface-soft);
}
.pf-close-amount b { font-size: 26px; font-weight: 500; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.pf-close-amount span { font-size: 12.5px; color: var(--text-dim); font-variant-numeric: tabular-nums; }

.pf-close-range { -webkit-appearance: none; appearance: none; width: 100%; height: 26px; background: none; cursor: pointer; }
.pf-close-range::-webkit-slider-runnable-track {
  height: 6px; border-radius: 999px; background: color-mix(in srgb, var(--ink) 10%, transparent);
}
.pf-close-range::-moz-range-track {
  height: 6px; border-radius: 999px; background: color-mix(in srgb, var(--ink) 10%, transparent);
}
.pf-close-range::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none; margin-top: -7px;
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--accent); border: 3px solid var(--bg-lift);
  box-shadow: 0 1px 6px rgba(0, 0, 0, .45);
}
.pf-close-range::-moz-range-thumb {
  width: 20px; height: 20px; border-radius: 50%; border: 3px solid var(--bg-lift);
  background: var(--accent); box-shadow: 0 1px 6px rgba(0, 0, 0, .45);
}
.pf-close-range:focus-visible::-webkit-slider-thumb { outline: 2px solid var(--border-strong); outline-offset: 2px; }

.pf-close-presets { display: flex; gap: 8px; flex-wrap: wrap; }
.pf-close-presets .chip { padding: 6px 14px; font-size: 12.5px; }
.pf-close-warn { margin: 0; font-size: 12px; line-height: 1.6; color: var(--text-faint); }
.pf-close-actions { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
/* The confirm is amber rather than the bear colour.
   `--down` is the customer's, and on the Mono scheme it is a mid grey - which makes the one
   button on this dialog that sends a market order look exactly like the one that does not.
   `--warn` is semantic rather than decorative: it means "this is irreversible", it means that
   under every scheme, and it is the same colour Stop automation already uses. */
[data-close-confirm] {
  color: var(--warn);
  border-color: color-mix(in srgb, var(--warn) 45%, transparent);
  background: color-mix(in srgb, var(--warn) 12%, transparent);
}
[data-close-confirm]:hover:not(:disabled) {
  border-color: color-mix(in srgb, var(--warn) 65%, transparent);
  background: color-mix(in srgb, var(--warn) 18%, transparent);
}

/* ── tooltips ──────────────────────────────────────────────────────────────
   One bubble on the body, positioned per hover by `mountTooltips` in core.js. It lives
   outside every scroll container on the page, which is the whole point: the tips that most
   need explaining sit inside tables that scroll, and a pseudo-element there is clipped by its
   own container. */
.tip-bubble {
  position: fixed; top: 0; left: 0; z-index: calc(var(--z-modal) + 5);
  max-width: min(320px, calc(100vw - 24px));
  padding: 7px 11px; border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--bg-lift); color: var(--text-dim);
  font-size: 11.5px; font-weight: 400; line-height: 1.55;
  letter-spacing: 0; text-transform: none; text-align: left;
  /* The bubble takes its text through `textContent`, so a tip that wants two lines - the
     engine columns put what the number *means* on the first one - needs newlines honoured.
     `pre-line` keeps ordinary wrapping and collapses runs of spaces, so every other tip in
     the app is unaffected. */
  white-space: pre-line;
  box-shadow: 0 10px 28px rgba(0, 0, 0, .38);
  pointer-events: none;
  opacity: 0;
  transition: opacity .15s var(--ease);
  will-change: transform, opacity;
}
.tip-bubble.is-on { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .tip-bubble { transition: none; } }

/* The book, while the exchanges are being read. */
.pf-loading { padding: 46px 26px; display: grid; place-items: center; }
/* The quote value under a holding's quantity. Quiet, because the quantity is the number an
   order is sized in and this is the one that makes it comparable. */
.pf-qty-quote { display: block; margin-top: 2px; font-size: 11px; }

/* The tour, while a step is still resolving. Some steps wait on content that is still being
   drawn, and a Next button that looks live and does nothing for four seconds is the single
   most common way a walkthrough reads as broken. */
/* The card while a step is still resolving. A thin bar travelling across the top edge, which
   says "working" without taking the buttons away - the press is queued either way, and a
   control that greys out on a slow step reads as a control that has failed. */
.tour-card.is-waiting::after {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 2px;
  border-radius: 2px 2px 0 0; overflow: hidden;
  background: linear-gradient(90deg, transparent,
    color-mix(in srgb, var(--accent) 70%, transparent), transparent);
  background-size: 40% 100%; background-repeat: no-repeat;
  animation: tour-working 1.05s var(--ease) infinite;
}
@keyframes tour-working {
  from { background-position: -40% 0; }
  to   { background-position: 140% 0; }
}
@media (prefers-reduced-motion: reduce) {
  .tour-card.is-waiting::after { animation: none; background-position: 50% 0; }
}

/* ── members: the two switches and the access flags ────────────────────────
   A real switch rather than a checkbox with a label. The thumb travels, the track fills, and
   both move on the same curve — the point of an animated toggle is that you can see which way
   it went without reading anything, and a jump tells you nothing. */
.adm-switches { display: grid; gap: 10px; }
.adm-switch {
  display: grid; grid-template-columns: 42px 1fr; gap: 14px; align-items: start;
  padding: 14px 16px; border-radius: 13px; cursor: pointer;
  border: 1px solid var(--border); background: var(--surface-soft);
  transition: border-color .18s var(--ease), background .18s var(--ease);
}
.adm-switch:hover { border-color: var(--border-strong); }
.adm-switch input { position: absolute; opacity: 0; pointer-events: none; }
.adm-switch-track {
  position: relative; width: 42px; height: 24px; border-radius: 999px; margin-top: 1px;
  border: 1px solid var(--border-strong);
  background: color-mix(in srgb, var(--ink) 7%, transparent);
  transition: background .22s var(--ease), border-color .22s var(--ease);
}
.adm-switch-track i {
  position: absolute; top: 3px; left: 3px; width: 16px; height: 16px; border-radius: 50%;
  background: var(--text-faint);
  transition: transform .22s var(--ease), background .22s var(--ease);
}
.adm-switch.is-on .adm-switch-track {
  background: color-mix(in srgb, var(--accent) 26%, transparent);
  border-color: color-mix(in srgb, var(--accent) 55%, transparent);
}
.adm-switch.is-on .adm-switch-track i { transform: translateX(18px); background: var(--accent); }
.adm-switch.is-danger.is-on .adm-switch-track {
  background: color-mix(in srgb, var(--warn) 26%, transparent);
  border-color: color-mix(in srgb, var(--warn) 55%, transparent);
}
.adm-switch.is-danger.is-on .adm-switch-track i { background: var(--warn); }
.adm-switch.is-on { border-color: var(--border-strong); background: var(--surface); }
.adm-switch input:focus-visible + .adm-switch-track {
  outline: 2px solid var(--border-strong); outline-offset: 2px;
}
.adm-switch-copy { display: grid; gap: 3px; min-width: 0; }
.adm-switch-copy b { font-size: 13.5px; font-weight: 550; }
.adm-switch-copy em { font-style: normal; font-size: 12px; color: var(--text-faint); line-height: 1.6; }
@media (prefers-reduced-motion: reduce) {
  .adm-switch, .adm-switch-track, .adm-switch-track i { transition: none; }
}

/* A cell that is empty still holds its column open. Without this the flex row collapsed and
   the two columns beside it slid by different amounts on different rows, which is the kind of
   unevenness everybody sees and nobody can name. */
/* Both of these are spans inside their cells rather than the cells themselves: `display:flex`
   on a `<td>` removes it from the table layout, so it no longer matches the row's height and
   its borders draw in the wrong place. `min-height` keeps an empty one holding its column
   open, which is what stopped the columns beside it sliding about. */
.adm-autos, .adm-flags {
  display: flex; flex-wrap: wrap; gap: 6px; min-height: 22px; align-items: center;
}
.adm-top { min-width: 0; }
.adm-top-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.adm-flag {
  display: inline-flex; align-items: center; padding: 2px 9px; border-radius: 999px;
  font-size: 11px; border: 1px solid var(--border); color: var(--text-dim);
}
.adm-flag.is-blocked {
  color: var(--warn); border-color: color-mix(in srgb, var(--warn) 40%, transparent);
  background: color-mix(in srgb, var(--warn) 10%, transparent);
}
.adm-flag.is-warn { color: var(--text-dim); }
.adm-flag.is-api {
  color: var(--accent); border-color: color-mix(in srgb, var(--accent) 40%, transparent);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
}
.adm-table tbody tr.is-blocked td:first-child { opacity: .6; }
.adm-denied tbody tr { cursor: default; }

/* ── the landing zoom ──────────────────────────────────────────────────────
 *
 * The showcase is a dashboard with four little panels leaning behind it. Scrolling past it
 * used to be exactly that: it went by. This turns the passage into the composition resolving.
 *
 * The first attempt zoomed to 2.35x, and that was wrong in a way that only shows up once you
 * do it: at that scale you are not looking at a dashboard any more, you are looking at a crop
 * of one, with every edge sliced by the window. The movement should read as the thing coming
 * *towards* you and then settling behind what comes next - not as a magnifying glass. So the
 * scale is now gentle (1 to 1.18, roughly the width of a laptop screen and no wider), and the
 * work is done by opacity and by the edges dissolving instead.
 *
 * Three movements, on one timeline:
 *   0.00-0.28  the side panels leave, quickly, along the axes they arrived on
 *   0.00-1.00  the dashboard grows a little, its edges melt, and it fades back to a wash
 *   0.42-0.75  the light comes up and the way in fades over the top of it
 *
 * Mechanically: `.pv-zoom` is a tall empty runway and `.pv-zoom-stage` sticks to the viewport
 * inside it, so scroll distance becomes animation time without the page appearing to stall.
 * gate.js writes a single `--pv-z` from 0 to 1 and every rule below reads it.
 */
.pv-zoom {
  --pv-z: 0;
  position: relative;
  /* Long enough for the dashboard to recede and the card to arrive after it, and no longer:
     there is nothing to read on the way down any more, so a runway sized for three steps
     just traps somebody who wants to get past the section. */
  height: 300vh;
  padding: 0;
}
.pv-zoom-stage {
  position: sticky; top: 0;
  height: 100vh; min-height: 560px;
  display: grid; place-items: center;
  overflow: hidden;
}
.pv-zoom-stage > .pv-wrap { width: 100%; position: relative; }

/* The dashboard becoming the background.
 *
 * It does not leave. It grows just enough to reach the width of the window, loses its edges
 * to a mask so it stops being a card sitting on black, and settles to a wash the door reads
 * over. Everything here is compositor work - transform, opacity, mask - so a 300vh scroll
 * stays at frame rate. */
.pv-zoom .pv-stack.is-in .pv-frame {
  /* How far in from each edge the picture has dissolved. Zero at rest, so the card is a crisp
     card until the scroll starts asking it to be something else. */
  --pv-melt: calc(var(--pv-z) * 26%);
  transform: translateY(calc(-2vh * var(--pv-z)))
             scale(calc(1 + 0.18 * var(--pv-z)));
  transform-origin: 50% 44%;
  transition: none;
  /* Never fully gone: past the middle of the runway this *is* the background, and a backdrop
     that disappears leaves the door standing on nothing. */
  opacity: clamp(0.11, calc(1 - var(--pv-z) * 1.05), 1);
  border-color: color-mix(in srgb, var(--pv-ink) calc(13% - 13% * var(--pv-z)), transparent);
  box-shadow: 0 50px 120px rgba(0, 0, 0, calc(.75 - .72 * var(--pv-z)));
  -webkit-mask-image:
    linear-gradient(to right, transparent, #000 var(--pv-melt),
                    #000 calc(100% - var(--pv-melt)), transparent),
    linear-gradient(to bottom, transparent, #000 var(--pv-melt),
                    #000 calc(100% - var(--pv-melt)), transparent);
  -webkit-mask-composite: source-in;
  mask-image:
    linear-gradient(to right, transparent, #000 var(--pv-melt),
                    #000 calc(100% - var(--pv-melt)), transparent),
    linear-gradient(to bottom, transparent, #000 var(--pv-melt),
                    #000 calc(100% - var(--pv-melt)), transparent);
  mask-composite: intersect;
}

/* The panels behind, getting out of the way. Each leaves along the axis it arrived on, so the
   composition comes apart the way it was assembled rather than all four sliding one way - and
   it happens early, because they are what the dashboard has to be freed from. */
.pv-zoom .pv-stack.is-in .pv-aside {
  transition: none;
  opacity: clamp(0, calc(1 - var(--pv-z) * 3.8), 1);
}
.pv-zoom .pv-aside--analysts { --pv-out: -1; }
.pv-zoom .pv-aside--stats    { --pv-out:  1; }
.pv-zoom .pv-aside--auto     { --pv-out: -1; }
.pv-zoom .pv-aside--watch    { --pv-out:  1; }
.pv-stack.is-in .pv-aside {
  --pv-shift: calc(var(--pv-out, 1) * var(--pv-z) * 34vw);
}

/* The spotlight.
 *
 * It arrives *with* the card and not before it. An earlier version started lifting at 0.30,
 * which is the middle of the zoom - so light bled in from one side while the dashboard was
 * still coming forward, and the movement stopped reading as a zoom and started reading as
 * scrolling down into something else. Same ramp as the card now: nothing until the zoom is
 * essentially finished.
 *
 * Two layers, because one radial pool reads as a smudge rather than as light: a wide pool
 * that lifts the whole area off black, and a narrow beam falling from above the card, which
 * is the part that makes it a spotlight. Both neutral - a coloured version of this was the
 * only tinted thing on the screen and looked like a stain.
 *
 * `--pv-lit` is the single ramp both layers and the card share, so the light and the thing it
 * is lighting can never arrive at different times. */
.pv-zoom { --pv-lit: clamp(0, calc((var(--pv-z) - 0.56) * 3.4), 1); }

.pv-door-glow {
  position: absolute; left: 50%; top: 50%;
  width: min(1180px, 96vw); aspect-ratio: 1.45;
  transform: translate(-50%, -50%) scale(calc(.86 + .14 * var(--pv-lit)));
  pointer-events: none; z-index: 2;
  opacity: var(--pv-lit);
  background:
    /* the beam, falling from above and narrowing towards the card */
    radial-gradient(52% 46% at 50% 4%,
      color-mix(in srgb, var(--pv-ink) 19%, transparent), transparent 74%),
    /* the pool it lands in */
    radial-gradient(closest-side at 50% 54%,
      color-mix(in srgb, var(--pv-ink) 12%, transparent), transparent 76%);
  filter: blur(14px);
}

/* ── the way in ────────────────────────────────────────────────────────────
 *
 * One card at the end of the zoom. It was a numbered path with a line drawing itself through
 * three steps; that put three paragraphs of reading between the dashboard and the button,
 * which is the opposite of what the end of a landing page is for. A popup says the same thing
 * in one sentence and gets out of the way.
 *
 * The pop is scale and fade together off `--pv-lit`, the same ramp the spotlight uses, so it
 * belongs to the scroll rather than to a timer - reverse the wheel and it goes back out at
 * exactly the rate it came in. No `transition`: the scroll *is* the timeline, and a transition
 * on top of it would fight every frame the driver writes.
 */
.pv-door {
  position: absolute; inset: 0; z-index: 4;
  display: grid; place-content: center; justify-items: center;
  text-align: center; padding: 0 var(--pv-gutter);
  pointer-events: none;
  opacity: var(--pv-lit);
  transition: none;
}
.pv-door-card {
  display: grid; justify-items: center; gap: 14px;
  max-width: 56ch; padding: clamp(28px, 4vh, 44px) clamp(28px, 5vw, 56px);
  border-radius: 22px;
  border: 1px solid color-mix(in srgb, var(--pv-ink) 10%, transparent);
  background: color-mix(in srgb, var(--pv-bg) 80%, transparent);
  -webkit-backdrop-filter: blur(22px); backdrop-filter: blur(22px);
  box-shadow: 0 40px 120px color-mix(in srgb, #000 55%, transparent);
  /* Up from slightly small and slightly low. 0.94 rather than 0.8: a card that grows from
     nothing reads as a modal being opened, and this one is meant to have been waiting at the
     end of the scroll. */
  transform: translateY(calc(18px - 18px * var(--pv-lit)))
             scale(calc(.94 + .06 * var(--pv-lit)));
}

/* Only clickable once it has actually arrived, or it swallows presses aimed at the dashboard
   it is fading in over. */
.pv-door.is-open { pointer-events: auto; }
.pv-door-kicker {
  margin: 0; color: var(--pv-faint); font-size: 12px;
  letter-spacing: .18em; text-transform: uppercase;
}
.pv-door h2 {
  margin: 0; color: var(--pv-text); font-weight: 620;
  font-size: clamp(25px, 3.2vw, 40px); letter-spacing: -.03em; line-height: 1.1;
  text-shadow: 0 2px 30px color-mix(in srgb, var(--pv-bg) 80%, transparent);
}
.pv-door-sub {
  margin: 0; max-width: 46ch; color: var(--pv-dim);
  font-size: clamp(14px, 1.5vw, 17px); line-height: 1.6;
  text-shadow: 0 1px 18px color-mix(in srgb, var(--pv-bg) 85%, transparent);
}
.pv-door-actions { display: flex; flex-wrap: wrap; gap: 12px; justify-content: center; margin-top: 10px; }
.pv-door-primary, .pv-door-ghost {
  padding: 13px 26px; border-radius: 999px; font-size: 14.5px; font-weight: 560;
  border: 1px solid transparent; cursor: pointer;
  transition: transform .16s var(--pv-ease), background .16s var(--pv-ease),
              border-color .16s var(--pv-ease);
}
.pv-door-primary {
  background: var(--pv-ink); color: var(--pv-bg);
  box-shadow: 0 10px 40px color-mix(in srgb, var(--pv-ink) 18%, transparent);
}
.pv-door-primary:hover { transform: translateY(-1px); }
.pv-door-ghost {
  background: color-mix(in srgb, var(--pv-bg) 55%, transparent); color: var(--pv-text);
  border-color: color-mix(in srgb, var(--pv-ink) 26%, transparent);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
}
.pv-door-ghost:hover { border-color: color-mix(in srgb, var(--pv-ink) 46%, transparent); }
.pv-door-link {
  margin-top: 4px; color: var(--pv-faint); font-size: 13px; text-decoration: none;
  border-bottom: 1px solid color-mix(in srgb, var(--pv-ink) 18%, transparent);
}
.pv-door-link:hover { color: var(--pv-text); }

/* No runway where it would be wrong.
   A phone has no room for the panels the zoom exists to clear away, and a reader who has
   asked for less motion has asked for exactly this. Both fall back to the static composition
   the page had before, which is complete on its own. */
@media (max-width: 900px), (prefers-reduced-motion: reduce) {
  .pv-zoom { height: auto; padding: 0 0 clamp(60px, 8vw, 110px); }
  .pv-zoom-stage { position: static; height: auto; min-height: 0; display: block; overflow: visible; }
  .pv-zoom .pv-stack.is-in .pv-frame {
    transform: none; opacity: 1;
    -webkit-mask-image: none; mask-image: none;
  }
  .pv-zoom .pv-stack.is-in .pv-aside { opacity: 1; }
  .pv-stack.is-in .pv-aside { --pv-shift: 0px; }
  .pv-door-glow { display: none; }
  .pv-door {
    position: static; opacity: 1; transform: none; pointer-events: auto;
    padding: clamp(48px, 8vw, 90px) var(--pv-gutter) 0;
  }
  .pv-door-card { transform: none; box-shadow: none; background: transparent;
    border-color: transparent; padding: 0; }
}

/* ── members: who uses this, and what for ─────────────────────────────────
   Administrators only. Built from the same tokens as everything else, so it inherits both
   themes and every colour scheme without a rule of its own - the one exception is the
   category palette, which has to stay fixed because a slice's colour is its identity. */
.adm-top { display: flex; justify-content: flex-end; margin-bottom: 16px; }
.adm-tiles {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px;
  margin-bottom: 16px;
}
.adm-tile {
  display: grid; gap: 4px; padding: 15px 17px; border-radius: 14px;
  border: 1px solid var(--border); background: var(--bg-lift);
}
.adm-tile small {
  color: var(--text-faint); font-size: 10px; letter-spacing: .07em; text-transform: uppercase;
}
.adm-tile b { font-size: 22px; font-weight: 500; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.adm-tile i { font-size: 11.5px; font-style: normal; color: var(--text-faint); }
@media (max-width: 900px) { .adm-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 520px) { .adm-tiles { grid-template-columns: 1fr; } }

.adm-card { display: grid; gap: 18px; padding: 24px 26px; margin-bottom: 16px; }
.adm-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }
.adm-head h2 { margin: 0 0 4px; font-size: 18px; font-weight: 500; letter-spacing: -.01em; }
.adm-block { display: grid; gap: 10px; }
.adm-block h3 {
  margin: 0; font-size: 11px; font-weight: 550; letter-spacing: .07em;
  text-transform: uppercase; color: var(--text-faint);
}

.adm-table td { vertical-align: middle; }
.adm-table tbody tr { cursor: pointer; }
.adm-table tbody tr.is-open {
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}
.adm-who { display: grid; gap: 1px; min-width: 0; }
.adm-who b { font-weight: 500; }
.adm-who i { font-style: normal; font-size: 11.5px; color: var(--text-faint); }
.adm-top-cell, .adm-top { display: inline-flex; align-items: center; gap: 7px; }
.adm-top small { color: var(--text-faint); font-size: 11.5px; }
.adm-seen { color: var(--text-faint); font-size: 12px; white-space: nowrap; }
.adm-idle { color: var(--text-xfaint); }
.adm-swatch { width: 9px; height: 9px; border-radius: 3px; flex: none; }

/* One running system, as a badge. Live ones - armed and on `auto`, the only combination that
   spends money unattended - carry the accent; every other mode is quiet grey, because a page
   that shouts about a paper run has nothing left to shout with when a real one appears. */
.adm-autos { display: flex; flex-wrap: wrap; gap: 6px; }
.adm-auto {
  display: inline-flex; align-items: baseline; gap: 6px; padding: 3px 9px;
  border-radius: 999px; font-size: 11.5px;
  border: 1px solid var(--border); background: var(--surface); color: var(--text-dim);
}
.adm-auto b { font-weight: 550; color: var(--text); letter-spacing: .02em; }
.adm-auto i { font-style: normal; }
.adm-auto em { font-style: normal; color: var(--text-faint); }
.adm-auto.is-live {
  border-color: color-mix(in srgb, var(--up) 45%, transparent);
  background: color-mix(in srgb, var(--up) 12%, transparent);
  color: var(--text);
}
.adm-autos.is-full { gap: 8px; }
.adm-autos.is-full .adm-auto { padding: 7px 13px; font-size: 12.5px; }

.adm-split { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 26px; align-items: center; }
@media (max-width: 720px) { .adm-split { grid-template-columns: 1fr; justify-items: center; } }
.adm-split-body { min-width: 0; width: 100%; }
.adm-donut { position: relative; width: var(--size); height: var(--size); flex: none; }
.adm-donut svg { display: block; width: 100%; height: 100%; }
.adm-arc { transition: opacity .16s var(--ease); }
.adm-donut:hover .adm-arc { opacity: .45; }
.adm-donut .adm-arc:hover { opacity: 1; }
.adm-donut-centre {
  position: absolute; inset: 0; display: grid; align-content: center; justify-items: center;
  gap: 1px; pointer-events: none; text-align: center;
}
.adm-donut-centre b { font-size: 17px; font-weight: 500; font-variant-numeric: tabular-nums; }
.adm-donut-centre small { font-size: 10px; color: var(--text-faint); letter-spacing: .06em; text-transform: uppercase; }
.adm-donut.is-empty {
  display: grid; place-items: center; text-align: center; border-radius: 50%;
  border: 2px dashed var(--border); color: var(--text-faint); font-size: 11.5px; padding: 18px;
}

.adm-legend { display: grid; gap: 3px; margin: 0; padding: 0; list-style: none; }
.adm-legend li {
  display: grid; grid-template-columns: 9px minmax(84px, auto) minmax(40px, 1fr) auto 34px;
  align-items: center; gap: 10px; padding: 4px 0; font-size: 12.5px;
}
.adm-legend-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.adm-legend-bar {
  height: 5px; border-radius: 999px; background: var(--surface); overflow: hidden;
}
.adm-legend-bar i { display: block; height: 100%; border-radius: 999px; }
.adm-legend b { font-weight: 500; font-variant-numeric: tabular-nums; }
.adm-legend small { color: var(--text-faint); text-align: right; font-variant-numeric: tabular-nums; }

.adm-plain { display: grid; gap: 1px; margin: 0; padding: 0; list-style: none; }
.adm-plain li {
  display: flex; align-items: center; gap: 10px; padding: 8px 2px; font-size: 12.5px;
  border-top: 1px solid var(--border);
}
.adm-plain li:first-child { border-top: none; }
.adm-plain b { font-weight: 500; }
.adm-plain span { color: var(--text-faint); }
.adm-plain em { margin-left: auto; font-style: normal; color: var(--text-dim); white-space: nowrap; }
.adm-places b { font-variant-numeric: tabular-nums; }

.adm-days { width: 100%; height: 64px; display: block; }
.adm-person { border-color: color-mix(in srgb, var(--accent) 30%, var(--border)); }

/* The worker-is-down banner. Given its own rule because a `pf-notice` is a one-line toast and
   this is two sentences that have to be read - a customer whose systems are armed and not
   being swept is being told the single most important thing this page can say. */
.rot-unattended { display: grid; gap: 5px; margin-bottom: 16px; }
.rot-unattended b { font-weight: 600; }
.rot-unattended p { margin: 0; font-size: 12.5px; line-height: 1.6; opacity: .92; }

/* ── closing a holding ─────────────────────────────────────────────────────
   A market order against a real account, so the control is deliberately not a one-tap
   button: the size is chosen, the figure is spelled out in the units being sold, and the
   confirm is the danger colour. */
.pf-close-cell { text-align: right; white-space: nowrap; }
.pf-close-btn { color: var(--text-dim); }
.pf-close-btn:hover { color: var(--down); }
.pf-table tbody tr:not(:hover) .pf-close-btn { opacity: .55; }

.pf-close-modal { width: min(440px, 100%); display: grid; gap: 18px; padding: 26px 28px 22px; }
.pf-close-modal h3 { margin: 0 0 5px; font-size: 18px; font-weight: 500; letter-spacing: -.01em; }
.pf-close-amount {
  display: flex; align-items: baseline; gap: 12px; padding: 14px 16px;
  border-radius: 12px; border: 1px solid var(--border); background: var(--surface-soft);
}
.pf-close-amount b { font-size: 26px; font-weight: 500; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.pf-close-amount span { font-size: 12.5px; color: var(--text-dim); font-variant-numeric: tabular-nums; }

.pf-close-range { -webkit-appearance: none; appearance: none; width: 100%; height: 26px; background: none; cursor: pointer; }
.pf-close-range::-webkit-slider-runnable-track {
  height: 6px; border-radius: 999px; background: color-mix(in srgb, var(--ink) 10%, transparent);
}
.pf-close-range::-moz-range-track {
  height: 6px; border-radius: 999px; background: color-mix(in srgb, var(--ink) 10%, transparent);
}
.pf-close-range::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none; margin-top: -7px;
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--accent); border: 3px solid var(--bg-lift);
  box-shadow: 0 1px 6px rgba(0, 0, 0, .45);
}
.pf-close-range::-moz-range-thumb {
  width: 20px; height: 20px; border-radius: 50%; border: 3px solid var(--bg-lift);
  background: var(--accent); box-shadow: 0 1px 6px rgba(0, 0, 0, .45);
}
.pf-close-range:focus-visible::-webkit-slider-thumb { outline: 2px solid var(--border-strong); outline-offset: 2px; }

.pf-close-presets { display: flex; gap: 8px; flex-wrap: wrap; }
.pf-close-presets .chip { padding: 6px 14px; font-size: 12.5px; }
.pf-close-warn { margin: 0; font-size: 12px; line-height: 1.6; color: var(--text-faint); }
.pf-close-actions { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
/* The confirm is amber rather than the bear colour.
   `--down` is the customer's, and on the Mono scheme it is a mid grey - which makes the one
   button on this dialog that sends a market order look exactly like the one that does not.
   `--warn` is semantic rather than decorative: it means "this is irreversible", it means that
   under every scheme, and it is the same colour Stop automation already uses. */
[data-close-confirm] {
  color: var(--warn);
  border-color: color-mix(in srgb, var(--warn) 45%, transparent);
  background: color-mix(in srgb, var(--warn) 12%, transparent);
}
[data-close-confirm]:hover:not(:disabled) {
  border-color: color-mix(in srgb, var(--warn) 65%, transparent);
  background: color-mix(in srgb, var(--warn) 18%, transparent);
}

/* ── tooltips ──────────────────────────────────────────────────────────────
   One bubble on the body, positioned per hover by `mountTooltips` in core.js. It lives
   outside every scroll container on the page, which is the whole point: the tips that most
   need explaining sit inside tables that scroll, and a pseudo-element there is clipped by its
   own container. */
.tip-bubble {
  position: fixed; top: 0; left: 0; z-index: calc(var(--z-modal) + 5);
  max-width: min(320px, calc(100vw - 24px));
  padding: 7px 11px; border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--bg-lift); color: var(--text-dim);
  font-size: 11.5px; font-weight: 400; line-height: 1.55;
  letter-spacing: 0; text-transform: none; text-align: left;
  box-shadow: 0 10px 28px rgba(0, 0, 0, .38);
  pointer-events: none;
  opacity: 0;
  transition: opacity .15s var(--ease);
  will-change: transform, opacity;
}
.tip-bubble.is-on { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .tip-bubble { transition: none; } }

/* The book, while the exchanges are being read. */
.pf-loading { padding: 46px 26px; display: grid; place-items: center; }
/* The quote value under a holding's quantity. Quiet, because the quantity is the number an
   order is sized in and this is the one that makes it comparable. */
.pf-qty-quote { display: block; margin-top: 2px; font-size: 11px; }

/* The tour, while a step is still resolving. Some steps wait on content that is still being
   drawn, and a Next button that looks live and does nothing for four seconds is the single
   most common way a walkthrough reads as broken. */
/* The card while a step is still resolving. A thin bar travelling across the top edge, which
   says "working" without taking the buttons away - the press is queued either way, and a
   control that greys out on a slow step reads as a control that has failed. */
.tour-card.is-waiting::after {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 2px;
  border-radius: 2px 2px 0 0; overflow: hidden;
  background: linear-gradient(90deg, transparent,
    color-mix(in srgb, var(--accent) 70%, transparent), transparent);
  background-size: 40% 100%; background-repeat: no-repeat;
  animation: tour-working 1.05s var(--ease) infinite;
}
@keyframes tour-working {
  from { background-position: -40% 0; }
  to   { background-position: 140% 0; }
}
@media (prefers-reduced-motion: reduce) {
  .tour-card.is-waiting::after { animation: none; background-position: 50% 0; }
}

/* ── members: the two switches and the access flags ────────────────────────
   A real switch rather than a checkbox with a label. The thumb travels, the track fills, and
   both move on the same curve — the point of an animated toggle is that you can see which way
   it went without reading anything, and a jump tells you nothing. */
.adm-switches { display: grid; gap: 10px; }
.adm-switch {
  display: grid; grid-template-columns: 42px 1fr; gap: 14px; align-items: start;
  padding: 14px 16px; border-radius: 13px; cursor: pointer;
  border: 1px solid var(--border); background: var(--surface-soft);
  transition: border-color .18s var(--ease), background .18s var(--ease);
}
.adm-switch:hover { border-color: var(--border-strong); }
.adm-switch input { position: absolute; opacity: 0; pointer-events: none; }
.adm-switch-track {
  position: relative; width: 42px; height: 24px; border-radius: 999px; margin-top: 1px;
  border: 1px solid var(--border-strong);
  background: color-mix(in srgb, var(--ink) 7%, transparent);
  transition: background .22s var(--ease), border-color .22s var(--ease);
}
.adm-switch-track i {
  position: absolute; top: 3px; left: 3px; width: 16px; height: 16px; border-radius: 50%;
  background: var(--text-faint);
  transition: transform .22s var(--ease), background .22s var(--ease);
}
.adm-switch.is-on .adm-switch-track {
  background: color-mix(in srgb, var(--accent) 26%, transparent);
  border-color: color-mix(in srgb, var(--accent) 55%, transparent);
}
.adm-switch.is-on .adm-switch-track i { transform: translateX(18px); background: var(--accent); }
.adm-switch.is-danger.is-on .adm-switch-track {
  background: color-mix(in srgb, var(--warn) 26%, transparent);
  border-color: color-mix(in srgb, var(--warn) 55%, transparent);
}
.adm-switch.is-danger.is-on .adm-switch-track i { background: var(--warn); }
.adm-switch.is-on { border-color: var(--border-strong); background: var(--surface); }
.adm-switch input:focus-visible + .adm-switch-track {
  outline: 2px solid var(--border-strong); outline-offset: 2px;
}
.adm-switch-copy { display: grid; gap: 3px; min-width: 0; }
.adm-switch-copy b { font-size: 13.5px; font-weight: 550; }
.adm-switch-copy em { font-style: normal; font-size: 12px; color: var(--text-faint); line-height: 1.6; }
@media (prefers-reduced-motion: reduce) {
  .adm-switch, .adm-switch-track, .adm-switch-track i { transition: none; }
}

/* A cell that is empty still holds its column open. Without this the flex row collapsed and
   the two columns beside it slid by different amounts on different rows, which is the kind of
   unevenness everybody sees and nobody can name. */
.adm-autos { display: flex; flex-wrap: wrap; gap: 6px; min-height: 22px; align-items: center; }
.adm-top { min-width: 0; }
.adm-top-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.adm-flags { display: flex; gap: 6px; flex-wrap: wrap; min-height: 22px; align-items: center; }
.adm-flag {
  display: inline-flex; align-items: center; padding: 2px 9px; border-radius: 999px;
  font-size: 11px; border: 1px solid var(--border); color: var(--text-dim);
}
.adm-flag.is-blocked {
  color: var(--warn); border-color: color-mix(in srgb, var(--warn) 40%, transparent);
  background: color-mix(in srgb, var(--warn) 10%, transparent);
}
.adm-flag.is-warn { color: var(--text-dim); }
.adm-flag.is-api {
  color: var(--accent); border-color: color-mix(in srgb, var(--accent) 40%, transparent);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
}
.adm-table tbody tr.is-blocked td:first-child { opacity: .6; }
.adm-denied tbody tr { cursor: default; }


/* The desk's budget, when it is under what the contract can actually open. Stated under the
   field rather than only signalled by colour: "at least 79 USDT" is the whole message, and a
   customer who has typed 10 needs the number, not a red tint. */
.rot-desk-hint.is-short { color: var(--warn); }
.rot-desk-short {
  grid-column: 1 / -1;
  margin: 0; padding: 11px 14px; border-radius: 11px;
  font-size: 12.5px; line-height: 1.6; color: var(--text);
  border: 1px solid color-mix(in srgb, var(--warn) 34%, transparent);
  background: color-mix(in srgb, var(--warn) 9%, transparent);
}
.rot-desk-short b { font-weight: 600; }

/* A holding a running system is managing. Small, beside the symbol, and the same warning
   colour the Stop button uses - it is the same fact: this belongs to something that is
   currently acting on its own. */
.pf-managed {
  display: inline-flex; align-items: center; margin-left: 7px;
  padding: 1px 7px; border-radius: 999px;
  font-size: 10px; font-weight: 600; letter-spacing: .04em;
  color: var(--warn);
  border: 1px solid color-mix(in srgb, var(--warn) 38%, transparent);
  background: color-mix(in srgb, var(--warn) 11%, transparent);
}
.pf-close-managed { display: grid; gap: 5px; }
.pf-close-managed p { margin: 0; font-size: 12.5px; line-height: 1.6; opacity: .92; }

/* The tiles inside a member's panel are the same object as the ones at the top of the page,
   at the size a panel can carry. */
.adm-tiles-inline { grid-template-columns: repeat(3, minmax(0, 1fr)); margin-bottom: 4px; }
.adm-tiles-inline .adm-tile { padding: 11px 13px; }
.adm-tiles-inline .adm-tile b { font-size: 18px; }
@media (max-width: 700px) { .adm-tiles-inline { grid-template-columns: 1fr; } }

/* The page, while a dialog is open. See `watchOverlays` in core.js for what counts as one.
   The gutter replaces the scrollbar's width so nothing shifts sideways when it goes. */
html.is-locked, html.is-locked body { overflow: hidden; }
html.is-locked body { padding-right: var(--scrollbar, 0px); }

/* What an engine needs, stated on the engine. The picker is the last screen before an order,
   and the minimum is a property of the engine being chosen rather than of the desk - Trend on
   a BTC perpetual needs about eighty, an XRP rotation about five. */
.rot-engine-name { display: flex; align-items: baseline; gap: 9px; flex-wrap: wrap; }
.rot-engine-min {
  font-style: normal; font-size: 11px; font-weight: 400; color: var(--text-faint);
  padding: 1px 8px; border-radius: 999px; border: 1px solid var(--border);
}
.rot-engine.is-short { cursor: default; opacity: .62; }
.rot-engine.is-short .rot-engine-min {
  color: var(--warn); border-color: color-mix(in srgb, var(--warn) 40%, transparent);
}

/* ── the measurement notice ────────────────────────────────────────────────
   A gate, not a strip. The app records where people spend their time, and a banner somebody
   can scroll past is consent to having been shown a banner rather than to the thing itself.
   It covers the product, it cannot be dismissed, and declining signs you out. */
.consent {
  position: fixed; inset: 0; z-index: calc(var(--z-tour) + 20);
  display: grid; place-items: center; padding: 24px;
  background: color-mix(in srgb, var(--shade) 88%, transparent);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  animation: rot-fade .2s var(--ease);
  overflow-y: auto;
}
.consent[hidden] { display: none; }
.consent-card {
  /* A bigger window, because there is genuinely a lot to read now and a narrow column of it
     reads as a wall. Wide enough for a comfortable measure, tall enough that the reader is
     not scrolling a porthole. */
  width: min(840px, 100%); max-height: calc(100dvh - 40px); overflow-y: auto;
  display: grid; gap: 16px; padding: 34px 38px 28px;
  border-radius: 20px; border: 1px solid var(--border-strong);
  background: var(--bg-lift);
  box-shadow: 0 40px 100px rgba(0, 0, 0, .6);
}
.consent-kicker {
  color: var(--text-faint); font-size: 11px; letter-spacing: .18em; text-transform: uppercase;
}
.consent-card h2 {
  margin: 0; font-size: 25px; font-weight: 560; letter-spacing: -.02em; line-height: 1.15;
}
/* The notice itself: one column of plain prose, scrolled to the end before anything unlocks.
   No rules, no bold, no tinted callout - every one of those is a handhold for an eye trying to
   get to the button, and this is the one screen where skimming is the failure mode. Generous
   line height and paragraph spacing, because the only concession to readability that does not
   also make it skimmable is room. */
.consent-read {
  max-height: min(62dvh, 620px); overflow-y: auto;
  padding-right: 18px;
  color: var(--text-dim); font-size: 14px; line-height: 1.9;
}
.consent-read p { margin: 0 0 17px; }
.consent-read p:last-child { margin-bottom: 0; }
.consent-read:focus-visible { outline: none; }
.consent-gate { margin: 0; color: var(--text-faint); font-size: 12px; }
.consent-agree.is-locked { opacity: .45; cursor: default; }
.consent-agree.is-locked input { cursor: default; }
.consent-agree {
  display: flex; gap: 11px; align-items: flex-start; cursor: pointer;
  font-size: 13px; line-height: 1.6; color: var(--text);
}
.consent-agree input { margin-top: 3px; flex: none; }
.consent-actions { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.consent-accept {
  padding: 12px 22px; border-radius: 999px; font-size: 14px; font-weight: 560;
  background: var(--accent); color: var(--on-accent); border: none;
  transition: opacity .16s var(--ease), transform .16s var(--ease);
}
.consent-accept:disabled { opacity: .4; cursor: not-allowed; }
.consent-accept:not(:disabled):hover { transform: translateY(-1px); }
.consent-decline {
  padding: 12px 18px; border-radius: 999px; font-size: 13px;
  color: var(--text-faint); border: 1px solid var(--border); background: none;
}
.consent-decline:hover { color: var(--text); border-color: var(--border-strong); }
.consent-fine { margin: 0; color: var(--text-xfaint); font-size: 11px; }
@media (prefers-reduced-motion: reduce) { .consent { animation: none; } }

/* ── the pre-launch countdown ──────────────────────────────────────────────
   One line above the header, and it has to look like an invitation rather than a sale.

   What that means here, concretely: no flipping digits, no red, no urgency. A hairline rule,
   letter-spaced small caps, and a single number in the page's own serif-free type at a size
   that does not shout. The only colour is a thin warm seam along the bottom edge - enough to
   read as deliberate, not enough to read as a banner ad.

   `position: fixed` above the header rather than in the document flow, because the header is
   fixed too: putting this in the flow would leave it behind on the first scroll while the bar
   it is supposed to sit above stayed put. The header and the page are pushed down by the same
   amount through `--countdown-h`, set only when the bar is actually on screen. */
:root { --countdown-h: 0px; }
body.has-countdown { --countdown-h: 38px; }

.countdown {
  position: fixed;
  inset: 0 0 auto 0;
  height: var(--countdown-h);
  z-index: calc(var(--z-header) + 1);
  display: flex;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--ink) 4%, var(--bg));
  border-bottom: 1px solid var(--border);
  /* Two shadows. The inset one is the warm seam along the bottom edge - light catching an edge
     rather than a coloured stripe. The outer one is a short fade onto the page beneath it.

     The fade earns its place on the preview, where the header is a floating pill on a
     transparent bar: the display headline scrolls up through the gap around that pill, and
     against a hard edge it was being sliced in half mid-letter. A few pixels of falloff and it
     dissolves under the bar instead. Not clipped by `overflow: hidden` below, because an outer
     box-shadow is painted outside the element's own box. */
  box-shadow: inset 0 -1px 0 color-mix(in srgb, #c9a227 26%, transparent),
              0 12px 14px -8px var(--bg);
  overflow: hidden;
}

body.has-countdown .hdr { top: var(--countdown-h); }

.countdown-inner {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 0 18px;
  min-width: 0;
}

/* The mark: a small warm dot, the same gesture the header's status pulse makes, without the
   animation. A blinking light beside a launch date is a countdown clock by another name. */
.countdown-mark {
  align-self: center;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: #c9a227;
  box-shadow: 0 0 0 3px color-mix(in srgb, #c9a227 16%, transparent);
  flex: none;
}

.countdown-label,
.countdown-note {
  font-size: 10.5px;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--ink) 46%, transparent);
  white-space: nowrap;
}

.countdown-value {
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: .04em;
  color: var(--text);
  white-space: nowrap;
}

/* The note is the first thing to go when there is no room for it: the number and what it
   counts to are the message, and the rest is a courtesy. */
.countdown-note {
  padding-left: 10px;
  border-left: 1px solid var(--border);
}

/* Two lengths of the label, and the note is never the thing that gets dropped: who may come in
   is the half a visitor most needs. On a narrow bar the words get shorter instead. */
.cd-short { display: none; }

@media (max-width: 720px) {
  .cd-long { display: none; }
  .cd-short { display: inline; }
  .countdown-label,
  .countdown-note { letter-spacing: .08em; font-size: 10px; }
  .countdown-note { padding-left: 8px; }
  .countdown-inner { gap: 7px; padding: 0 10px; }
}

/* Below this even the short forms will not sit on one line beside the number, and a countdown
   that wraps is worse than a short one. The access rule is on the page itself regardless. */
@media (max-width: 400px) {
  .countdown-note { display: none; }
}

/* ── before the doors open ─────────────────────────────────────────────────
   The countdown appears, and that is the whole of it.

   This also used to strip the page back: the scroll-driven showcase, the four capabilities and
   the long description all went, on the reasoning that handing the product to somebody who
   cannot sign up spends it for nothing. That reasoning was wrong about this page. The walk
   into the dashboard *is* the pitch - it is the reason somebody waits for the date instead of
   closing the tab - and hiding it left a name, a sentence and a bare countdown that said very
   little about why anybody should care.

   So the page is the page, launched or not. Only the bar above it changes.

   Nothing is keyed on `.is-prelaunch` any more. The class is still set, because whether the
   product has opened is worth having in one place and the countdown above reads the same
   fact - but the page below the bar no longer changes shape for it. */

/* ── the smallest phones ───────────────────────────────────────────────────
   Below 720px the preview deliberately keeps its wordmark: there are no tabs on that page, and
   the name is the thing it is introducing, so the rule that hides it in the application does
   not apply. That reasoning holds down to about 380px and then stops - at 320px the name, "Log
   in" and "Sign up" do not fit on one line between them, and something has to give. What gave
   first was the buttons: their labels broke in half ("Log / in"), and once `white-space` stopped
   that, "Sign up" ran 30px past the end of the bar instead.

   So on the narrowest screens the wordmark drops back to the mark alone. It is still a link
   home and still says whose site this is, and the two doors are what somebody is here to press.

   Placed at the end of the file on purpose: the 720px block above sets `display: inline` on the
   same element at the same specificity, so this only wins by coming after it. */
@media (max-width: 380px) {
  body.is-signed-out .brand-text { display: none; }
  body.is-signed-out .hdr-inner { padding-left: 12px; gap: 10px; }
  body.is-signed-out .hdr-auth { gap: 6px; }
  body.is-signed-out .hdr-signin,
  body.is-signed-out .hdr-signup { padding-inline: 13px; font-size: 12.5px; }
}

/* ── the preview header on a phone ─────────────────────────────────────────
   The signed-out header is a floating pill on a transparent bar: the page scrolls underneath
   it, which is the intended effect on a wide screen where the content is centred and the
   margins either side of the pill are empty.

   On a phone there are no empty margins. The pill is inset 12px, the body text runs the full
   width, and what showed in those two strips - and in the gap above the pill - was sharp
   slivers of letters sliding past, which reads as a rendering fault rather than as depth.

   A gradient rather than a flat fill, so the bar still dissolves into the page instead of
   becoming a hard-edged block: solid behind the pill, gone by the bottom of it. */
@media (max-width: 720px) {
  body.is-signed-out .hdr {
    background: linear-gradient(to bottom,
                var(--pv-bg) 0%,
                var(--pv-bg) 62%,
                color-mix(in srgb, var(--pv-bg) 55%, transparent) 84%,
                transparent 100%);
  }
}

/* ── "Beta", said where the risk is ────────────────────────────────────────
   Automation is the one tab that can lose somebody money while they are not looking, and it
   is still being tested. That belongs on screen rather than only in a disclosure read once,
   months ago - so it is on the tab, on the page title, and in a sentence above the controls.

   Amber rather than red. Red is the colour this app uses for a position going against you,
   and borrowing it for a status label would make a permanent badge read as a live alarm. */
.tab-tag,
.title-tag {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 5px;
  border-radius: 4px;
  font-size: 9px;
  font-weight: 650;
  letter-spacing: .08em;
  text-transform: uppercase;
  vertical-align: middle;
  color: #d8a018;
  background: color-mix(in srgb, #d8a018 14%, transparent);
  border: 1px solid color-mix(in srgb, #d8a018 32%, transparent);
  /* Never the thing the eye lands on first: the tab's own label is what somebody is reading. */
  line-height: 1.45;
  translate: 0 -1px;
}

.title-tag {
  font-size: 10px;
  padding: 2px 7px;
  margin-left: 10px;
  translate: 0 -4px;
}

/* The tab strip is tight at narrow widths and the label matters more than the badge. */
@media (max-width: 900px) {
  .tab-tag { display: none; }
}

.beta-note {
  margin: 14px 0 0;
  max-width: 78ch;
  padding: 11px 14px;
  border-radius: 10px;
  border: 1px solid color-mix(in srgb, #d8a018 26%, transparent);
  background: color-mix(in srgb, #d8a018 7%, transparent);
  color: var(--text);
  font-size: 13px;
  line-height: 1.55;
}
.beta-note b { color: #e8b73a; font-weight: 600; }

/* ── automation, closed while it is tested ─────────────────────────────────
   Shown in place of the desk for anybody who is not an administrator. Deliberately shaped like
   an explanation rather than an error: nothing has gone wrong, and the reader has not done
   anything wrong either - the feature is simply not finished. */
.beta-wall {
  /* The same 760px as the disclosure card, so the page is one column whichever of the two is
     on screen and the heading above lines up with both. */
  max-width: 760px;
  /* Centred with the page head above it, for the reason given on `.disc`. */
  margin: 6px auto 0;
  padding: 30px 34px;
  border-radius: 16px;
  border: 1px solid var(--border);
  background: var(--surface);
  text-align: left;
}
.beta-wall-tag {
  display: inline-block;
  margin-bottom: 14px;
  padding: 2px 8px;
  border-radius: 5px;
  font-size: 10px;
  font-weight: 650;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #d8a018;
  background: color-mix(in srgb, #d8a018 14%, transparent);
  border: 1px solid color-mix(in srgb, #d8a018 32%, transparent);
}
.beta-wall h2 { margin: 0 0 12px; font-size: 21px; font-weight: 500; }
.beta-wall p { margin: 0 0 12px; color: var(--text-dim); font-size: 14px; line-height: 1.62; }
.beta-wall p:last-child { margin-bottom: 0; }
.beta-wall-next {
  padding-top: 14px;
  border-top: 1px solid var(--border);
  font-size: 13px;
}


/* ── Automation, while it is a single column ───────────────────────────────
   One card on screen - the disclosure, or the beta notice - rather than the full-width desk.
   The whole page centres for it, heading included, so the block sits in the middle of the
   window instead of being pinned to the left edge with everything else empty.

   `.is-gated` is set by `portfolio.js`, which is what decides which of the two is showing. The
   desk keeps the app's ordinary left margin, because a heading centred over a full-width table
   would be floating in the middle of nothing. */
#view-portfolio.is-gated > .page-head {
  max-width: 760px;
  margin-left: auto;
  margin-right: auto;
}
#view-portfolio.is-gated > .page-head .beta-note { max-width: none; }

/* ── the beta screen's own presentation ────────────────────────────────────
   This is the last thing between somebody and a desk that places real orders, so it is built
   to be looked at rather than skimmed past: a slow amber glow behind the card, a ring mark,
   and the one sentence that matters set apart from the rest.

   Restrained on purpose. Amber, not red - red is what this app uses for a position going
   against you, and borrowing it here would read as an error rather than as a notice. Nothing
   pulses or moves quickly; the glow drifts and that is all. */
.beta-wall {
  position: relative;
  overflow: hidden;
  text-align: center;
  padding: 40px 34px 34px;
}

.beta-wall-glow {
  position: absolute;
  inset: -60% 20% auto;
  height: 260px;
  pointer-events: none;
  background: radial-gradient(50% 50% at 50% 50%,
              color-mix(in srgb, #d8a018 26%, transparent) 0%, transparent 72%);
  filter: blur(10px);
  animation: beta-drift 14s ease-in-out infinite alternate;
}
@keyframes beta-drift {
  from { transform: translate3d(-6%, 0, 0) scale(1); opacity: .75; }
  to   { transform: translate3d(6%, 4%, 0) scale(1.12); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .beta-wall-glow { animation: none; }
}

.beta-wall-mark {
  position: relative;
  width: 48px;
  height: 48px;
  margin: 0 auto 16px;
  color: #d8a018;
}
.beta-wall-mark svg { width: 100%; height: 100%; display: block; }

/* Everything except the glow, which must stay out of the flow.
   `.beta-wall > *` caught it too, turning `position: absolute` into `relative` - so the glow
   claimed 261px of vertical space and pushed the whole card down behind an empty gap. */
.beta-wall > *:not(.beta-wall-glow) { position: relative; }
.beta-wall .beta-wall-tag { margin-bottom: 12px; }
.beta-wall h2 { font-size: 23px; }
.beta-wall p { max-width: 52ch; margin-left: auto; margin-right: auto; }

.beta-wall-actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 9px;
  margin: 24px 0 4px;
}
.beta-wall-go {
  padding: 11px 26px;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, #d8a018 42%, transparent);
  background: color-mix(in srgb, #d8a018 13%, transparent);
  color: #e8b73a;
  font-size: 14px;
  font-weight: 560;
  cursor: pointer;
  transition: background .2s var(--ease), border-color .2s var(--ease);
}
.beta-wall-go:hover {
  background: color-mix(in srgb, #d8a018 20%, transparent);
  border-color: color-mix(in srgb, #d8a018 62%, transparent);
}
/* Said under the button rather than on it. A button that shouts is pressed without reading;
   a quiet line under one is read on the way to pressing it. */
.beta-wall-caution {
  font-size: 11px;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--ink) 40%, transparent);
}

.beta-wall .beta-wall-next { margin-top: 22px; }
