/* Dark by default: this is opened at 07:00 and after the close, often in the
   dark, and a white flash on a phone at those hours is its own small hostility. */

:root {
  --bg: #0f1115;
  --card: #181b22;
  --line: #262b35;
  --text: #e7e9ee;
  --muted: #949bab;
  --buy: #3ecf8e;
  --sell: #ff6b6b;
  --accent: #4c8dff;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 16px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  padding-bottom: env(safe-area-inset-bottom);
}

header { padding: 24px 20px 8px; }
.header-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.guide-link {
  color: var(--muted); font-size: 13px; text-decoration: none; flex: 0 0 auto;
  border: 1px solid var(--line); border-radius: 8px; padding: 6px 12px;
  margin-top: 4px; white-space: nowrap;
}
.guide-link:hover, .guide-link:focus { color: var(--text); border-color: var(--accent); }
h1 { margin: 0; font-size: 28px; letter-spacing: -0.02em; }
/* The wordmark stands in for the heading text. Sized in CSS rather than left
   at its natural size so it holds on a phone as well as a monitor. */
.brand { line-height: 0; }
.brand img { width: 220px; height: auto; max-width: 62vw; }

/* Sits under the wordmark on every screen. One paragraph, so it wraps
   rather than stacking -- this is above every page, and a tall header is
   paid for on each of them. No max-width: the old 52ch cap predates the
   badge and was narrower than "Timely signals. Approve the trade." plus
   the badge combined, so it forced the wrap this rule exists to avoid. A
   narrow viewport still wraps it naturally; nothing here needs to force
   that on a wide one too. */
.tagline {
  margin: 10px 0 0;
  font-size: 15px;
  line-height: 1.45;
}
/* The payoff, now the loudest word in the header rather than the quietest.
   Same pill shape as the BUY/SELL badges on a signal card -- a tinted
   background at low opacity, full-strength text in the same hue -- so a
   second badge-like element in the header reads as the same visual language
   rather than a one-off. Inline with the sentence before it, not stacked
   beneath it: it is the payoff of that sentence, not a separate line. */
.tagline .wheel {
  display: inline-block; margin-left: 6px; font-weight: 700;
  background: rgba(76,141,255,.15); color: var(--accent);
  padding: 3px 10px; border-radius: 999px;
}
.sub { margin: 4px 0 0; color: var(--muted); font-size: 14px; }

.tabs { display: flex; gap: 8px; padding: 12px 20px; }
.tab {
  flex: 1; padding: 10px; border-radius: 10px; border: 1px solid var(--line);
  background: transparent; color: var(--muted); font-size: 15px; cursor: pointer;
}
.tab.active { background: var(--card); color: var(--text); }

main { padding: 4px 20px 40px; }
.hidden { display: none !important; }

.card {
  background: var(--card); border: 1px solid var(--line); border-radius: 14px;
  padding: 16px; margin-bottom: 12px; cursor: pointer;
}
.card:active { transform: scale(0.995); }

.card-top { display: flex; justify-content: space-between; align-items: baseline; }
.symbol { font-size: 20px; font-weight: 650; letter-spacing: -0.01em; }
.action { font-size: 13px; font-weight: 650; padding: 3px 9px; border-radius: 999px; }
.action.BUY  { background: rgba(62,207,142,.15); color: var(--buy); }
.action.SELL { background: rgba(255,107,107,.15); color: var(--sell); }

/* The labels grew from one word ("Entry") to three ("Buy back at (profit)"),
   because one word could be read as the opposite of what it meant on a short.
   So the row wraps instead of overflowing, and each price stays with its
   label. */
.prices {
  display: flex; flex-wrap: wrap; gap: 6px 18px; margin-top: 10px;
  font-size: 14px; color: var(--muted);
}
.prices > span { display: flex; align-items: baseline; gap: 5px; white-space: nowrap; }
.prices b { color: var(--text); font-weight: 600; }
/* The profit price green and the stop red, so the pair is legible before the
   words are read. Colour is never the only cue -- the label says which. */
.prices b.up { color: var(--buy); }
.prices b.down { color: var(--sell); }
.price-label { font-size: 12px; }
#sheet-prices dd.up { color: var(--buy); }
#sheet-prices dd.down { color: var(--sell); }
.why { margin: 10px 0 0; font-size: 14px; color: var(--muted); }
.expires { margin-top: 8px; font-size: 12px; color: var(--muted); }

.empty { color: var(--muted); text-align: center; padding: 48px 20px; }

/* Approval sheet */
.sheet {
  position: fixed; inset: 0; background: rgba(0,0,0,.6);
  display: flex; align-items: flex-end; z-index: 20;
}
.sheet-inner {
  background: var(--card); width: 100%; border-radius: 18px 18px 0 0;
  padding: 20px 20px calc(20px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--line);
}
.sheet h2 { margin: 0 0 12px; font-size: 20px; }

/* Above the trade sheet (z-index 20), deliberately: a subscriber who has not
   accepted the current terms must not be able to open a trade underneath
   this. No close button in the markup and nothing here adds a
   click-outside-to-dismiss handler -- unlike .sheet, this is not meant to be
   escapable. */
.legal-gate {
  position: fixed; inset: 0; background: rgba(0,0,0,.75);
  display: flex; align-items: center; justify-content: center; z-index: 50;
  padding: 20px;
}
.legal-gate-inner {
  background: var(--card); border: 1px solid var(--line); border-radius: 18px;
  padding: 24px; width: 100%; max-width: 440px;
  max-height: calc(100vh - 40px); overflow-y: auto;
}
.legal-gate-inner h2 { margin: 0 0 8px; font-size: 20px; }
.legal-gate-inner .check { align-items: flex-start; font-size: 14px; line-height: 1.5; }
.legal-gate-inner .check input { margin-top: 3px; }
.legal-gate-inner .row { margin-top: 4px; }
.legal-gate-inner .primary { width: 100%; }
dl { display: grid; grid-template-columns: auto 1fr; gap: 4px 16px; margin: 0 0 16px; font-size: 15px; }
dt { color: var(--muted); }
dd { margin: 0; text-align: right; font-variant-numeric: tabular-nums; }

label { display: block; font-size: 14px; color: var(--muted); margin-bottom: 6px; }
input {
  width: 100%; padding: 14px; font-size: 18px; border-radius: 10px;
  border: 1px solid var(--line); background: var(--bg); color: var(--text);
}
.hint { font-size: 13px; color: var(--muted); margin: 8px 0 16px; }

.row { display: flex; gap: 10px; }
button { font-family: inherit; }
.primary, .secondary {
  flex: 1; padding: 15px; border-radius: 12px; font-size: 16px;
  font-weight: 600; border: none; cursor: pointer;
}
.primary { background: var(--accent); color: #fff; }
.primary:disabled { opacity: .5; }
.secondary { background: transparent; border: 1px solid var(--line); color: var(--text); }
.link {
  display: block; width: 100%; margin-top: 12px; padding: 10px;
  background: none; border: none; color: var(--muted); font-size: 15px; cursor: pointer;
}
.error { color: var(--sell); font-size: 14px; margin: 12px 0 0; }

footer { padding: 0 20px 32px; }
footer p { color: var(--muted); font-size: 13px; text-align: center; margin: 0; }

/* Settings */
.card.static { cursor: default; }
.card.static h2 { margin: 0 0 10px; font-size: 18px; }
.why.small { font-size: 13px; }
.card.static label { margin-top: 14px; }
.card.static input[type="text"], .card.static input[type="password"] { margin-bottom: 2px; }
.check { display: flex; align-items: center; gap: 10px; margin: 16px 0; color: var(--text); font-size: 15px; }
.check input { width: auto; }
.card.static .row { margin-top: 18px; }

/* ---- the record -------------------------------------------------------- */
/* Deliberately plain. The scorecard's credibility comes from the numbers being
   checkable, and dressing it up like a marketing page works against that. */
.stats { display: grid; gap: 14px; margin-top: 4px; }
.stat { display: grid; gap: 2px; }
.stat-label { font-size: 0.82rem; opacity: 0.7; }
.stat-value { font-size: 1.35rem; font-variant-numeric: tabular-nums; }
.stat-value .of { font-size: 0.8rem; opacity: 0.65; font-variant-numeric: normal; }
/* The unflattering categories get the same weight as the wins, not smaller
   type in a corner. */
.stat-note { font-size: 0.78rem; opacity: 0.65; line-height: 1.45; }

/* ---- account warnings --------------------------------------------------- */
/* Loud for the urgent ones and quiet for the rest. A subscriber who sees the
   same styling for "you may be about to owe shares" and "you already hold some
   of this" learns to skim both. */
.warnings { display: grid; gap: 10px; margin: 0 0 16px; }
.warn {
  border-left: 3px solid currentColor;
  padding: 10px 12px;
  border-radius: 4px;
  font-size: 0.92rem;
  line-height: 1.5;
}
.warn-urgent { color: #c0392b; background: rgba(192, 57, 43, 0.08); }
.warn-note   { color: inherit; background: rgba(127, 127, 127, 0.10); opacity: 0.9; }
.warn b { display: block; margin-bottom: 2px; }
.warn-summary { font-size: 0.85rem; opacity: 0.75; }

/* ------------------------------------------------------------- positions */

.checked-note { color: var(--muted); font-size: 14px; margin: 4px 0 14px; }
.checked-note.small { font-size: 13px; margin-top: 18px; }

.pos {
  border-top: 1px solid var(--line);
  padding: 10px 0 2px;
}
.pos-head { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }
.pos-head b { font-size: 16px; letter-spacing: 0.01em; }
.pos-size { color: var(--muted); font-size: 13px; }

.pos-figures, .pos-totals {
  display: flex; flex-wrap: wrap; gap: 6px 20px;
  font-size: 14px; font-variant-numeric: tabular-nums;
}
.pos-figures { margin-top: 4px; }
.pos-totals {
  margin: 2px 0 6px; padding-bottom: 10px;
  font-size: 16px;
}
.pos-label { color: var(--muted); font-size: 13px; }

.up { color: var(--buy); }
.down { color: var(--sell); }
.flat { color: var(--muted); }

/* ------------------------------------------------------------------ sign in */

.providers { display: flex; flex-direction: column; gap: 10px; margin-top: 14px; }

/* Anchors, not buttons: a provider flow is a browser redirect and has to leave
   this page, so it must behave like a link -- openable in a new tab, and
   working with JavaScript broken. */
.provider {
  display: block; padding: 13px 16px; border-radius: 10px;
  border: 1px solid var(--line); background: var(--card);
  color: var(--text); font-size: 15px; font-weight: 600;
  text-align: center; text-decoration: none;
  /* 44px minimum: a thumb target on a phone, and it costs a desktop nothing. */
  min-height: 44px; box-sizing: border-box;
}
.provider:hover { border-color: var(--accent); }
.provider:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ----------------------------------------------------------- recovery codes */

/* Monospaced and widely spaced: these get copied onto paper by hand, and the
   alphabet already excludes the characters people mistranscribe. */
.codes ol { margin: 12px 0 0; padding-left: 22px; }
.codes li { margin: 6px 0; }
.codes code {
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  font-size: 15px; letter-spacing: 0.08em;
}

/* Used where the absence of recovery is being described, which is a live risk
   rather than a suggestion. */
.warn { color: var(--sell); }

/* ------------------------------------------------------------- public front */

/* The first thing a stranger sees. Slightly larger than an ordinary card
   because it is doing the explaining, and the numbers inside it are the pitch. */
.front-hero h2 { font-size: 22px; letter-spacing: -0.01em; }
.front-hero .stats { margin-top: 16px; }

/* The denominator, never smaller than a whisper. A win rate printed without
   what it is out of is the thing this product is selling against, so the two
   must not be styled as headline and footnote. */
.front-hero .of { color: var(--muted); font-weight: 500; }
.front-hero b { color: var(--text); }

/* ------------------------------------------------- email and password form */

/* Separated from the provider buttons above it, because it is the other kind of
   answer to the same question and running them together reads as one long list
   of equally likely options. Most people will use a provider. */
#password-form {
  margin-top: 20px; padding-top: 18px; border-top: 1px solid var(--line);
}
#password-form label:first-of-type { margin-top: 0; }
#password-form .row { margin-top: 16px; }

/* ------------------------------------------------------------- the chart
   Two series on one axis, and the styling carries an argument rather than a
   taste. The record is the accent; the estimate is grey, dashed and inside a
   shaded band, because it is a back-cast and nothing in it was published to
   anybody. Three separate signals saying one thing, on purpose.

   Colours checked rather than eyeballed, against this card's #181b22 surface:
   #4c8dff and #6f7a8c separate by OKLab dE 17.2 under both protanopia and
   deutanopia simulation (target 8) and 17.2 for normal vision (floor 15).
   The grey is below the chroma floor by design -- it IS meant to read as grey,
   which is the "highlight one, mute the rest" case rather than two equal
   categories. */

:root {
  --chart-real: #4c8dff;
  --chart-est: #6f7a8c;
}

/* One filter row, above the card it scopes. */
.perf-controls { display: flex; gap: 6px; margin: 0 0 10px; flex-wrap: wrap; }
.range {
  flex: 1; min-width: 44px; padding: 7px 4px; border-radius: 9px;
  border: 1px solid var(--line); background: transparent; color: var(--muted);
  font-size: 13px; font-weight: 600; cursor: pointer;
}
.range.active { background: var(--card); color: var(--text); border-color: #38414f; }

.perf-head { margin: 6px 0 2px; }
/* Proportional figures, not tabular: at this size equal-width digits make a
   number like 121 look loose. Same sans as everything else -- a display face
   on a hero figure reads as decoration. */
.perf-headline { font-size: 32px; font-weight: 650; letter-spacing: -0.02em; }
.perf-headline-note { display: block; color: var(--muted); font-size: 13px; margin-top: 2px; }

.perf-legend { display: flex; gap: 14px; flex-wrap: wrap; margin: 12px 0 6px; font-size: 13px; color: var(--muted); }
.perf-legend .key { display: inline-flex; align-items: center; gap: 6px; }
.perf-legend i { width: 14px; height: 2px; border-radius: 1px; display: inline-block; }
.perf-legend .real i { background: var(--chart-real); }
.perf-legend .est i {
  background: repeating-linear-gradient(90deg, var(--chart-est) 0 4px, transparent 4px 7px);
}

.perf-plot { position: relative; margin: 4px 0 2px; }
/* Held at reduced opacity while a new range loads, rather than collapsed to a
   skeleton -- a skeleton flash here is a layout jump on every tap. */
.perf-plot.loading { opacity: .45; transition: opacity .15s; }
.perf-svg { display: block; max-width: 100%; height: auto; touch-action: pan-y; }

.perf-shade { fill: var(--chart-est); opacity: .085; }
/* Hairline, solid, one step off the surface. Never dashed -- a dashed grid
   reads as a threshold that isn't there. */
.perf-grid { stroke: var(--line); stroke-width: 1; }
.perf-grid.zero { stroke: #333c4a; }
.perf-boundary { stroke: #4a5566; stroke-width: 1; }
.perf-tick { fill: var(--muted); font-size: 11px; font-variant-numeric: tabular-nums; }

.perf-line { fill: none; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.perf-line.real { stroke: var(--chart-real); }
.perf-line.est { stroke: var(--chart-est); stroke-dasharray: 5 4; }
/* 2px ring in the surface colour so the mark stays legible where it crosses
   anything -- the ring is part of the hit target, not just spacing. */
.perf-dot.real { fill: var(--chart-real); stroke: var(--card); stroke-width: 2; }
.perf-endlabel { fill: var(--text); font-size: 12px; font-weight: 600; }
.perf-endchip { fill: var(--card); opacity: .88; }

.perf-cross { stroke: #55606f; stroke-width: 1; pointer-events: none; }
.perf-hit { fill: transparent; cursor: crosshair; }

.perf-tip {
  position: absolute; pointer-events: none; z-index: 4;
  background: #10131a; border: 1px solid var(--line); border-radius: 9px;
  padding: 7px 9px; font-size: 12px; line-height: 1.45; white-space: nowrap;
  box-shadow: 0 4px 14px rgba(0,0,0,.45);
}
.perf-tip .tip-date { display: block; color: var(--muted); margin-bottom: 3px; }
.perf-tip .tip-row { display: flex; align-items: center; gap: 6px; }
.perf-tip .tip-row i { width: 9px; height: 9px; border-radius: 50%; display: inline-block; }
.perf-tip .tip-row i.real { background: var(--chart-real); }
.perf-tip .tip-row i.est { background: var(--chart-est); }
.perf-tip .tip-note { display: block; color: var(--muted); margin-top: 2px; font-style: italic; }

.perf-foot { margin: 12px 0 0; font-size: 13px; color: var(--muted); line-height: 1.5; }
.perf-foot b { color: var(--text); }
.perf-foot.small { font-size: 12px; margin-top: 8px; }

/* The table twin. Every value on the chart is reachable without seeing colour. */
.perf-table { margin-top: 12px; }
.perf-table summary { cursor: pointer; color: var(--muted); font-size: 13px; }
.perf-table-scroll { max-height: 280px; overflow: auto; margin-top: 8px; }
.perf-table table { width: 100%; border-collapse: collapse; font-size: 13px; }
.perf-table th, .perf-table td {
  text-align: left; padding: 5px 8px 5px 0; border-bottom: 1px solid var(--line);
}
.perf-table th { color: var(--muted); font-weight: 600; position: sticky; top: 0; background: var(--card); }
/* Tabular here and only here -- these digits align vertically in a column. */
.perf-table td:last-child { font-variant-numeric: tabular-nums; }

/* ------------------------------------------------- ticker, company, dates */

/* The ticker is a link out to Google Finance. Underlined only on hover so a
   feed of twenty cards is not a wall of blue rules. */
.ticker { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.symbol.link { color: var(--text); text-decoration: none; }
.symbol.link:hover, .symbol.link:focus { text-decoration: underline; }
.company {
  font-size: 12px; color: var(--muted); font-weight: 400;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 42vw;
}
/* The date every signal card carries. Written out rather than "3 days ago":
   this feed exists to be checked against a price chart, and a relative time
   cannot be. */
.when { margin: 10px 0 0; font-size: 12px; color: var(--muted); }
.when .clock { opacity: .75; }
/* Sits inside the shaded band. Small, spaced and muted -- it has to be legible
   without competing with the data, and it is doing the job the shading alone
   cannot do while the real record is only a session long. */
.perf-shade-label {
  fill: var(--chart-est); font-size: 9px; font-weight: 700; letter-spacing: .09em;
  opacity: .85;
}

/* -------------------------------------------------------- strategy picker
   Everything on the Record tab describes one strategy, and this says which.
   Sits above the cards it scopes, like the chart's range row. */

.picker { margin: 0 0 12px; position: relative; }

.strategy-bar, .strategy-single { display: flex; gap: 8px; align-items: stretch; }

.strategy-toggle, .strategy-single {
  flex: 1; display: flex; align-items: center; gap: 8px; min-width: 0;
  padding: 10px 12px; border-radius: 11px; border: 1px solid var(--line);
  background: var(--card); color: var(--text); font-size: 15px;
  cursor: pointer; text-align: left;
}
.strategy-single { cursor: default; }
.strategy-label {
  color: var(--muted); font-size: 12px; text-transform: uppercase;
  letter-spacing: .06em; flex: none;
}
.strategy-name {
  font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.strategy-toggle .chev { margin-left: auto; color: var(--muted); flex: none; }

.follow {
  flex: none; padding: 10px 14px; border-radius: 11px; font-size: 14px;
  font-weight: 600; cursor: pointer;
  border: 1px solid var(--accent); background: transparent; color: var(--accent);
}
/* Following is the quieter state: it is a thing already done, not a call to
   action, and an equally loud button invites an accidental unfollow. */
.follow.on { border-color: var(--line); background: transparent; color: var(--muted); }
.follow:disabled { opacity: .5; cursor: default; }

.strategy-menu {
  position: absolute; left: 0; right: 0; top: calc(100% + 6px); z-index: 12;
  background: var(--card); border: 1px solid var(--line); border-radius: 12px;
  padding: 10px; box-shadow: 0 10px 28px rgba(0,0,0,.5);
}
#strategy-search {
  width: 100%; padding: 9px 11px; border-radius: 9px; font-size: 15px;
  border: 1px solid var(--line); background: var(--bg); color: var(--text);
}
.strategy-list { max-height: 320px; overflow: auto; margin-top: 8px; }

.strategy-row {
  display: flex; flex-direction: column; gap: 3px; width: 100%; text-align: left;
  padding: 10px; border-radius: 9px; border: 1px solid transparent;
  background: transparent; color: var(--text); cursor: pointer;
}
.strategy-row:hover { background: rgba(255,255,255,.04); }
.strategy-row.active { border-color: var(--accent); background: rgba(76,141,255,.08); }
.strategy-row-top { display: flex; align-items: baseline; gap: 8px; }
.following {
  font-size: 11px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  color: var(--buy); background: rgba(62,207,142,.14); padding: 2px 7px; border-radius: 999px;
}
.strategy-meta { font-size: 12px; color: var(--muted); }
.strategy-desc { font-size: 13px; color: var(--muted); line-height: 1.45; }
.empty.small { padding: 18px 8px; font-size: 14px; }

/* Which account a trade is going to, in the approval sheet. */
.sheet-account {
  display: flex; flex-direction: column; gap: 3px;
  margin: 12px 0 4px; padding: 10px 12px;
  border: 1px solid var(--line); border-radius: 10px; font-size: 14px;
}
.sheet-account .muted { color: var(--muted); font-size: 13px; }
.sheet-account .warn { color: var(--sell); font-size: 13px; }

/* The account the key card is editing. */
#key-target {
  width: 100%; padding: 10px 11px; margin-bottom: 2px;
  border-radius: 9px; border: 1px solid var(--line);
  background: var(--bg); color: var(--text); font-size: 15px;
}

/* Per-strategy attribution on the Positions tab. */
.ledger-row { border-top: 1px solid var(--line); padding: 12px 0 4px; }
.ledger-row:first-of-type { border-top: 0; }
.ledger-top { display: flex; justify-content: space-between; align-items: baseline; }
.ledger-held { color: var(--muted); font-size: 13px; }
.ledger-parts { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.ledger-part {
  font-size: 13px; padding: 3px 9px; border-radius: 999px;
  background: rgba(76,141,255,.10); border: 1px solid rgba(76,141,255,.25);
}
.ledger-part.muted { background: transparent; border-color: var(--line); color: var(--muted); }
/* A position we cannot divide is marked, not hidden -- a smaller total than the
   account holds needs its reason visible or it reads as a bug. */
.ledger-row.contested .ledger-part { background: rgba(255,107,107,.10); border-color: rgba(255,107,107,.3); }

.account-heading {
  margin: 22px 0 6px; font-size: 15px; color: var(--muted);
  text-transform: uppercase; letter-spacing: .06em;
}
/* Not a warning: sharing an account is a reasonable arrangement and the only
   one live trading allows. Neutral, so it reads as a fact rather than a fault. */
.limitation { border-color: #38414f; }

/* Out to the broker, to create an account or generate its keys. */
.broker-links { display: flex; flex-direction: column; gap: 4px; margin: 10px 0 14px; }
.broker-links a { color: var(--accent); text-decoration: none; }
.broker-links a:hover { text-decoration: underline; }

.ledger-part .up { color: var(--buy); }
.ledger-part .down { color: var(--sell); }

/* The plain-English explainer under a signal's readings. Set apart by a rule
   rather than made smaller: it is a second way of saying the same thing, not a
   footnote to it, and the reader who needs it needs it legible. */
.why.explainer {
  margin-top: 6px; border-left: 2px solid var(--line); padding-left: 10px;
}
.why.explainer b { color: var(--text); font-weight: 600; }

/* Sits above the prices on a SELL card, because it changes how the three
   numbers below it should be read. Not styled as a warning -- shorting is a
   normal trade and we publish these signals to everybody. */
.short-note {
  margin: 10px 0 0; font-size: 13px; color: var(--muted); line-height: 1.5;
  max-width: 62ch;
}

/* The story behind a signal. Quieter than the reasoning above it -- it is
   where the claim came from, not the claim. */
.why.news { margin-top: 8px; font-size: 13px; }
.why.news a { color: var(--accent); text-decoration: none; }
.why.news a:hover, .why.news a:focus { text-decoration: underline; }
.news-source { opacity: 0.7; font-size: 12px; }

/* Sits under the explainer. Restrained on purpose -- on the pending tab the
   whole card is a tap target for the trade, so this must not read as the
   card's main action.

   `.link` is a full-width centred button, which is right for "I can't sign in"
   at the foot of a form and wrong here: centred under left-aligned prose it
   reads as floating loose in the card. Left-aligned and only as wide as its
   text, so it hangs off the paragraph it belongs to. */
.glossary-link {
  font-size: 12px; margin-top: 8px; padding: 6px 0;
  width: auto; text-align: left; text-decoration: underline;
  text-underline-offset: 3px;
}

/* Shown at the top of the approval sheet when this browser has no key. Framed
   as something to fix, not as an error -- the subscriber did nothing wrong, they
   arrived in a browser that does not have their details. */
.sheet-nokey {
  border: 1px solid var(--line); border-left: 3px solid var(--accent);
  border-radius: 8px; padding: 12px 14px; margin: 4px 0 16px;
}
.sheet-nokey p { margin: 0 0 8px; font-size: 14px; color: var(--muted); line-height: 1.5; }
.sheet-nokey p:last-child { margin-bottom: 0; }
.sheet-nokey p:first-child { color: var(--text); }
.sheet-nokey b { color: var(--text); }
.sheet-nokey .small { font-size: 13px; opacity: 0.85; }

/* -------------------------------------------------------------- your activity */
/* What the subscriber did with the feed. Deliberately quieter than a signal
   card: this is a record of decisions already made, not something to act on. */
.activity-filter { display: flex; align-items: center; gap: 10px; margin: 4px 0 14px; }
.activity-filter label { color: var(--muted); font-size: 13px; margin: 0; }
.activity-filter select { flex: 1; max-width: 320px; }

.empty-note { display: inline-block; margin-top: 8px; font-size: 13px; opacity: 0.75; }
.activity-card { opacity: 0.97; }
.activity-what { margin: 8px 0 0; font-size: 14px; }
.activity-what .where { color: var(--muted); font-size: 13px; margin-left: 6px; }
.activity-what .when { color: var(--muted); font-size: 13px; margin-left: 6px; }
/* A left edge that says the outcome before the words are read. Never the only
   cue -- "You approved" / "You passed" is spelled out on every row. */
.activity-card.approved { border-left: 3px solid var(--buy); }
.activity-card.rejected { border-left: 3px solid var(--line); }
.activity-card.expired  { border-left: 3px solid var(--line); opacity: 0.8; }
.activity-error { margin: 8px 0 0; font-size: 13px; color: var(--sell); }

/* ----------------------------------------------------------------- glossary */
/* Plain-language definitions of the financial words used above, closed by
   default. A `<details>` rather than tooltips: `title` text needs a mouse, and
   this is read on a phone. Placed above the desktop breakpoint because these
   rules apply at every width -- TestDesktopLayout exists because they kept
   landing below it. */
.glossary { margin: 18px 0 8px; border-top: 1px solid var(--line); padding-top: 12px; }
.glossary summary {
  cursor: pointer; color: var(--muted); font-size: 13px; padding: 6px 0;
  /* A thumb target, same minimum as every other tappable thing here. */
  min-height: 32px; display: flex; align-items: center; gap: 8px;
}
/* `display: flex` on a <summary> removes the browser's own disclosure
   triangle, which left the glossary looking like a line of dead text -- no
   affordance that it opened at all. Drawn back explicitly. */
.glossary summary::-webkit-details-marker { display: none; }
.glossary summary::before {
  content: "›"; display: inline-block; font-size: 16px; line-height: 1;
  transition: transform 0.15s ease; transform: rotate(0deg);
}
.glossary[open] summary::before { transform: rotate(90deg); }
.glossary summary:hover { color: var(--text); }
/* The global `dl` is built for the price sheet: two columns with the numbers
   right-aligned against them. A glossary inherited that and came out as
   narrow terms beside full-width right-aligned prose, which is close to
   unreadable. Definitions stack under their terms and read left. */
.glossary dl { display: block; margin: 6px 0 0; }
.glossary dt {
  font-size: 13px; font-weight: 600; margin-top: 14px; color: var(--text);
}
.glossary dd {
  margin: 3px 0 0; font-size: 13px; color: var(--muted); line-height: 1.5;
  text-align: left; font-variant-numeric: normal; max-width: 68ch;
}
.glossary dd b { color: var(--text); font-weight: 600; }

/* ------------------------------------------------------------------ desktop */
/* The phone layout above stays the default and is not rebuilt here. It is what
   most of this is opened on, and widening a mobile-first sheet degrades far more
   gracefully than narrowing a desktop-first one.
 
   What actually goes wrong on a monitor is not that anything breaks: it is that
   everything stretches. Five short words become five 300px buttons, a sentence
   runs to two hundred characters, and a settings form with two fields fills a
   27-inch screen. The fixes below are all the same fix -- stop things growing
   past the width at which they were legible. */

@media (min-width: 720px) {
  /* A measure, not a width. Text set across 1500px is unreadable however much
     room the monitor has, because the eye loses the line on the way back. */
  header, .tabs, main, footer {
    max-width: 880px;
    margin-left: auto;
    margin-right: auto;
  }

  /* Sized to their labels. `flex: 1` divides the row evenly, which is right on a
     phone where the row IS the width, and absurd on a monitor. */
  .tab { flex: 0 0 auto; padding: 10px 20px; }
  .tabs { gap: 10px; }

  /* There is a pointer now, so say what is clickable. A signal card opens the
     approval sheet; a static card is a form and already says `cursor: default`. */
  .card:not(.static):hover { border-color: var(--accent); }

  /* Prose narrower than the card it sits in. The stats beside it want the full
     width; the sentences do not. */
  .why { max-width: 68ch; }

  /* Two or three across instead of a single stacked column. On a phone these
     stack because there is no room; on a monitor stacking them makes a
     scorecard look longer and thinner than it is.

     Capped rather than `1fr`: equal fractions of 880px push two figures to
     opposite ends of the card, which reads as two unrelated facts rather than a
     row of them. A number and its label want to stay near their neighbours. */
  .stats {
    grid-template-columns: repeat(auto-fit, minmax(180px, 230px));
    gap: 18px 32px;
    justify-content: start;
  }

  /* Buttons stop growing. `flex: 1` on a phone gives a thumb a target; on a
     monitor it gives a mouse a 400px "Save" button. */
  .row { justify-content: flex-start; }
  .primary, .secondary { flex: 0 1 auto; min-width: 160px; padding: 13px 22px; }
  .card.static .row { gap: 12px; }

  /* A bottom sheet is a phone idiom -- it comes up under the thumb. With a
     mouse it should be a dialog in the middle of the screen, at a size that
     matches the little it contains. */
  .sheet { align-items: center; justify-content: center; }
  .sheet-inner {
    width: min(460px, 92vw);
    border-radius: 18px;
    border: 1px solid var(--line);
    padding: 24px;
  }

  /* The sign-in choices are a short list of options, not a stack of full-width
     bars. */
  .providers { max-width: 380px; }

  /* Recovery codes read in two columns rather than one long strip, which is
     also closer to how somebody will write them down. */
  .codes ol { columns: 2; column-gap: 32px; }
}

/* Wider still: hold the measure rather than continuing to grow. Beyond about
   this point extra pixels add nothing a reader wants. */
@media (min-width: 1200px) {
  header, .tabs, main, footer { max-width: 960px; }
}
