/* Veduta web app. The site's tokens, copied from /assets/site.css so the app
   stays the same when the site's stylesheet changes, and laid out for touch:
   every control is at least 44px tall. */

:root {
  --paper: #EDF0F2;
  --sheet: #F7F8FA;
  --ink: #121519;
  --ink-2: #464C55;
  --ink-3: #5F6671;
  --rule: #C9CED6;
  --field: #7E8693;
  --rule-2: #DDE1E6;
  --band: #3762D6;
  --band-ink: #FFFFFF;
  --band-wash: rgba(55, 98, 214, 0.12);
  --band-wash-2: rgba(55, 98, 214, 0.24);
  --up: #297758;
  --down: #AE4634;
  --focus: #3762D6;
  --stone: #8E592F;
  --stone-wash: rgba(142, 89, 47, 0.10);
  --push-dim: rgba(18, 21, 25, 0.10);
  --sheet-dim: rgba(18, 21, 25, 0.30);
  --sw-off: #7E8693;
  --sw-knob: #FBFCFD;
  --tint: rgba(55, 98, 214, 0.04);
  --press-shade: #000000;

  --f-display: "Bodoni Moda", "Bodoni Moda Fallback", "Bodoni Moda Fallback 2", "Bodoni Moda Fallback 3", Georgia, serif;
  --f-body: "Schibsted Grotesk", "Schibsted Grotesk Fallback", "Schibsted Grotesk Fallback 2", "Schibsted Grotesk Fallback 3", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --f-mono: "IBM Plex Mono", "IBM Plex Mono Fallback", ui-monospace, "SF Mono", Menlo, monospace;

  --gut: 16px;
  --r: 3px;
  --bar-h: 64px;
  color-scheme: light;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper: #0C0F13; --sheet: #14181F; --ink: #E8EBF0; --ink-2: #A4ACB8;
    --ink-3: #7B8391; --rule: #2B3340; --rule-2: #1F252F; --band: #7591F0;
    --band-ink: #0C0F13; --band-wash: rgba(117, 145, 240, 0.13);
    --band-wash-2: rgba(117, 145, 240, 0.26); --up: #59C098; --down: #F4836F;
    --focus: #7591F0; --field: #687182; --stone: #D9A772;
    --stone-wash: rgba(217, 167, 114, 0.10); color-scheme: dark;
    --push-dim: rgba(0, 0, 0, 0.40); --sheet-dim: rgba(0, 0, 0, 0.55);
    --sw-off: #687182; --sw-knob: #0C0F13; --press-shade: #FFFFFF; --tint: rgba(117, 145, 240, 0.10);
  }
}
:root[data-theme="dark"] {
  --paper: #0C0F13; --sheet: #14181F; --ink: #E8EBF0; --ink-2: #A4ACB8;
  --ink-3: #7B8391; --rule: #2B3340; --rule-2: #1F252F; --band: #7591F0;
  --band-ink: #0C0F13; --band-wash: rgba(117, 145, 240, 0.13);
  --band-wash-2: rgba(117, 145, 240, 0.26); --up: #59C098; --down: #F4836F;
  --focus: #7591F0; --field: #687182; --stone: #D9A772;
  --stone-wash: rgba(217, 167, 114, 0.10); color-scheme: dark;
  --push-dim: rgba(0, 0, 0, 0.40); --sheet-dim: rgba(0, 0, 0, 0.55);
    --sw-off: #687182; --sw-knob: #0C0F13; --press-shade: #FFFFFF; --tint: rgba(117, 145, 240, 0.10);
}
@media (min-width: 700px) { :root { --gut: 24px; } }

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; background: var(--paper); }
body {
  margin: 0; min-height: 100vh; min-height: 100dvh;
  background: var(--paper); color: var(--ink);
  font: 400 16px/1.5 var(--f-body);
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  overflow-x: hidden;
}
[hidden] { display: none !important; }
a { color: inherit; text-underline-offset: 3px; text-decoration-thickness: 1px; }
a:hover { color: var(--band); }
:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.skip { position: absolute; left: -999px; }
.skip:focus { left: var(--gut); top: 8px; background: var(--sheet); padding: 6px 10px; z-index: 30; }
p { margin: 0; max-width: 68ch; }
h1, h2, h3 { font-family: var(--f-display); font-weight: 500; line-height: 1.08; margin: 0;
             letter-spacing: -0.01em; text-wrap: balance; }
h1 em { font-style: italic; font-weight: 400; }
.label { font: 500 12px/1.3 var(--f-mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--stone); }
.num { font-family: var(--f-mono); font-variant-numeric: tabular-nums; }
.muted { color: var(--ink-3); }
.small { font-size: 14px; }
.up { color: var(--up); }
.down { color: var(--down); }
.nowrap { white-space: nowrap; }
.tag { display: inline-block; font: 500 11px/1 var(--f-mono); letter-spacing: 0.06em; text-transform: uppercase;
       padding: 4px 6px; border: 1px solid var(--rule); border-radius: 2px; color: var(--ink-3);
       vertical-align: middle; margin-left: 8px; }
p > .tag:first-child { margin-left: 0; margin-right: 4px; }

/* ── the bar ──────────────────────────────────────────────────────────── */
.bar {
  position: sticky; top: 0; z-index: 10;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  min-height: var(--bar-h);
  padding: env(safe-area-inset-top) max(var(--gut), env(safe-area-inset-right)) 0 max(var(--gut), env(safe-area-inset-left));
  background: var(--paper); border-bottom: 1px solid var(--rule);
}
.brand { display: flex; align-items: baseline; gap: 10px; text-decoration: none; min-height: 44px; align-items: center; }
.brand b { font: 600 26px/1 var(--f-display); letter-spacing: -0.01em; }
.brand span { font: 500 11px/1 var(--f-mono); letter-spacing: 0.08em; color: var(--ink-3); text-transform: uppercase; }
.tabs { display: flex; gap: 4px; }
.tabs a {
  display: inline-flex; align-items: center; justify-content: center; min-height: 44px; padding: 0 14px;
  color: var(--ink-2); text-decoration: none; font: 500 15px/1 var(--f-body);
  border-bottom: 2px solid transparent;
}
.tabs a:hover { color: var(--ink); }
.tabs a[aria-current="page"] { color: var(--ink); }
body.v-welcome .tabs { display: none; }

/* phones and narrow split screens: the sections move to the bottom, where a
   thumb reaches them */
@media (max-width: 699px) {
  .brand span { display: none; }
  .tabs {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 10;
    display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 0;
    background: var(--sheet); border-top: 1px solid var(--rule);
    padding: 0 env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
  }
  .tabs a { min-height: 54px; padding: 0 4px; font-size: 14px; border-bottom: 0; border-top: 2px solid transparent; }
  .tabs a[aria-current="page"] { border-top-color: transparent; }
  body { padding-bottom: calc(56px + env(safe-area-inset-bottom)); }
  body.v-welcome { padding-bottom: 0; }
  :root { --bar-h: 56px; }
}

/* ── notices ──────────────────────────────────────────────────────────── */
.notices { padding: 0; }
.main:focus { outline: none; }
.notice { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap;
          padding: 8px 0; border-bottom: 1px solid var(--rule-2); font-size: 15px; color: var(--ink-2); }
.notice p { max-width: none; }
.notice.status.wait p::before { content: ""; display: inline-block; width: 8px; height: 8px; margin-right: 8px;
                                background: var(--stone); vertical-align: middle; }

/* ── layout ───────────────────────────────────────────────────────────── */
.main { max-width: 1600px; margin: 0 auto;
        padding: 0 max(var(--gut), env(safe-area-inset-right)) 0 max(var(--gut), env(safe-area-inset-left)); }
.pane { min-width: 0; }
body.v-watch .detail { display: none; }
body.v-stock .list, body.v-other .list, body.v-welcome .list { display: none; }
body.v-boot .detail { display: none; }
@media (min-width: 900px) {
  body.v-watch .split, body.v-stock .split {
    display: grid; grid-template-columns: 340px minmax(0, 1fr); align-items: start;
  }
  body.v-watch .detail, body.v-stock .list { display: block; }
  body.v-watch .list, body.v-stock .list {
    position: sticky; top: var(--bar-h); max-height: calc(100vh - var(--bar-h)); max-height: calc(100dvh - var(--bar-h));
    overflow-y: auto; padding-right: 20px; border-right: 1px solid var(--rule);
    overscroll-behavior: contain;
  }
  body.v-watch .detail, body.v-stock .detail { padding-left: 28px; }
  .back { display: none !important; }
}
.boot { padding: 20px 0; display: grid; gap: 8px; }
.nojs { padding: 32px 0; display: grid; gap: 12px; max-width: 640px; }
.nojs h1 { font-size: 36px; }

/* ── controls ─────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: 44px;
  padding: 0 18px; border-radius: var(--r); border: 1px solid var(--ink);
  background: var(--ink); color: var(--paper); font: 600 16px/1 var(--f-body);
  text-decoration: none; cursor: pointer; touch-action: manipulation;
}
.btn:hover { background: var(--band); border-color: var(--band); color: var(--band-ink); }
.btn.ghost { background: transparent; color: var(--ink); border-color: var(--rule); }
.btn.ghost:hover { border-color: var(--ink); color: var(--ink); background: transparent; }
.btn.sm { padding: 0 14px; font-size: 15px; font-weight: 500; }
.btn.danger { background: var(--down); border-color: var(--down); color: var(--paper); }
.btn.danger:hover { background: var(--ink); border-color: var(--ink); color: var(--paper); }
.btn:disabled { opacity: 0.55; cursor: default; }
input[type=text], input[type=password] {
  font: 400 16px/1.3 var(--f-body); color: var(--ink); background: var(--sheet);
  border: 1px solid var(--field); border-radius: var(--r); padding: 10px 12px; min-height: 44px;
  width: 100%; min-width: 0;
}
input:focus { outline: 2px solid var(--focus); outline-offset: 0; }
input::placeholder { color: var(--ink-3); }
.seg { display: inline-flex; border: 1px solid var(--rule); border-radius: var(--r); max-width: 100%; }
.seg button { font: 500 14px/1 var(--f-mono); min-height: 44px; padding: 0 12px; border: 0;
              background: transparent; color: var(--ink-2); cursor: pointer; touch-action: manipulation; }
.seg button + button { border-left: 1px solid var(--rule); }
.seg button:hover { color: var(--ink); }
.seg button[aria-pressed="true"] { background: var(--ink); color: var(--paper); }
.row-btns { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.check { display: flex; align-items: center; gap: 12px; min-height: 44px; font-weight: 600; cursor: pointer; }
.check input { width: 22px; height: 22px; accent-color: var(--band); margin: 0; }
.confirm { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }

/* skeleton: a bar the size of what is coming */
.sk { display: inline-block; width: 4.5em; height: 0.8em; border-radius: 2px;
      background: linear-gradient(90deg, var(--rule-2), var(--rule), var(--rule-2));
      background-size: 200% 100%; animation: sk 1.4s linear infinite; vertical-align: middle; }
.sk.line { display: block; width: 100%; height: 12px; margin-block: 6px; }
.sk.line.big { height: 22px; width: 92%; }
.sk.line.short { width: 55%; }
.sk.w3 { width: 3em; } .sk.w4 { width: 4em; } .sk.w5 { width: 5em; } .sk.w6 { width: 6em; }
.sk.tall { height: 1.6em; }
.sk.block { display: block; width: 100%; height: 100%; }
/* a skeleton the size of the text it stands for: the text, unseen */
.sk-text { color: transparent !important; border-radius: 2px; background: linear-gradient(90deg, var(--rule-2), var(--rule), var(--rule-2));
           background-size: 200% 100%; animation: sk 1.4s linear infinite; }
@media (prefers-reduced-motion: reduce) { .sk-text { animation: none; } }
@keyframes sk { from { background-position: 200% 0; } to { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) { .sk { animation: none; } }

/* ── watchlist ────────────────────────────────────────────────────────── */
.list-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 18px 0 10px; }
.list-head h2 { font-size: 28px; }
.add { display: flex; gap: 8px; }
.add-msg { font-size: 14px; color: var(--ink-2); min-height: 1.5em; padding: 6px 0 4px; }
.add-msg:empty { min-height: 0; padding: 0; }
.rows { list-style: none; margin: 8px 0 24px; padding: 0; border-top: 1px solid var(--rule); }
.rows li { display: flex; align-items: center; gap: 8px; border-bottom: 1px solid var(--rule-2); }
.rows li.empty { display: grid; gap: 8px; padding: 18px 0; color: var(--ink-2); }
.row { flex: 1; min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr) 72px minmax(84px, auto);
       align-items: center; gap: 12px; min-height: 62px; padding: 8px 6px; text-decoration: none; color: var(--ink); }
.row:hover { color: var(--ink); background: var(--sheet); }
.row[aria-current="true"] { background: var(--band-wash); }
.row[aria-current="true"] .row-meta { color: var(--ink-2); }
.row[aria-current="true"] .row-err { color: var(--ink); }
.row-name { display: grid; gap: 2px; min-width: 0; }
.row-name b { font: 500 16px/1.2 var(--f-mono); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.row-meta, .row-err { font-size: 12.5px; color: var(--ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.row-err { color: var(--down); }
.row-fig { display: grid; justify-items: end; gap: 3px; }
.row-fig .price { font-size: 15px; }
.row-fig .chg { font-size: 13px; }
.spark { width: 72px; height: 28px; display: flex; align-items: center; }
.rm { flex: none; }

/* ── a stock ──────────────────────────────────────────────────────────── */
.s-head { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: end; gap: 6px 16px; padding: 18px 0 6px; }
.s-head .back { grid-column: 1 / -1; justify-self: start; margin-bottom: 6px; }
.s-id { min-width: 0; display: grid; gap: 4px; }
.s-id h1 { font-size: clamp(36px, 5vw, 52px); font-weight: 600; overflow-wrap: break-word; }
.s-name { font-size: 15px; }
.s-price { display: grid; justify-items: end; gap: 4px; text-align: right; }
.s-price .big { font-size: clamp(24px, 3vw, 32px); font-weight: 500; }
/* a narrow phone or a third of an iPad: the price goes under the name */
@media (max-width: 479px) {
  .s-head { grid-template-columns: minmax(0, 1fr); }
  .s-price { justify-items: start; text-align: left; grid-template-columns: auto auto; align-items: baseline; gap: 12px; }
}
/* 3.0.3: the band in one line under the price */
.s-band { font-size: 17px; line-height: 1.4; color: var(--ink); padding: 0 0 6px; max-width: 60ch; }
.s-band .num { font: 500 0.94em/1 var(--f-mono); white-space: nowrap; }
/* 3.0.3 (review): while the band and the status wait, each holds the
   sentence it will be, unseen (.sk-text), so it wraps to the lines the
   real one will take; app.js keeps the room once taken (holdRoom) */
.s-band .sk-text, .s-status .sk-text { -webkit-box-decoration-break: clone; box-decoration-break: clone; }
/* a stock whose prices did not load keeps no empty room above the message */
.stock.failed .s-band, .stock.failed .s-status { min-height: 0; }
.s-status { color: var(--ink-3); padding-bottom: 10px; }
/* 3.0.3: on a phone the band's sentence and the status take two lines once
   they arrive; their room is kept from the start, so the chart below does
   not move down when they do */
@media (max-width: 699px) {
  .s-band { min-height: calc(2 * 17px * 1.4 + 6px); }
  .s-status { min-height: calc(2 * 14px * 1.5 + 10px); }
}
.chart-wrap { height: 300px; border-top: 1px solid var(--ink); border-bottom: 1px solid var(--rule); padding-top: 8px; }
@media (min-width: 700px) { .chart-wrap { height: 380px; } }
@media (min-width: 700px) and (max-height: 700px) { .chart-wrap { height: 300px; } }
.chart { width: 100%; height: 100%; display: block; }
.ctl-row { display: flex; justify-content: space-between; align-items: center; gap: 10px; flex-wrap: wrap; padding: 12px 0; }
.readout { display: grid; gap: 8px; padding: 14px 0; border-top: 1px solid var(--rule); color: var(--ink-2); }
.readout .big { font: 500 clamp(21px, 2.4vw, 26px)/1.3 var(--f-display); color: var(--ink); max-width: 40ch; }
.readout .big .num { font: 500 0.82em/1 var(--f-mono); letter-spacing: -0.01em; white-space: nowrap; }
.readout b { font-weight: 600; color: var(--ink); }
.readout b.up { color: var(--up); } .readout b.down { color: var(--down); }
.note-scale { color: var(--ink-2); border-top: 1px solid var(--rule-2); padding-top: 8px; }
.track-row { display: flex; gap: 10px 14px; align-items: center; flex-wrap: wrap; padding: 6px 0 14px; }
.track-row p { flex-basis: 100%; }
.advice { padding: 12px 0 28px; border-top: 1px solid var(--rule-2); }
.msg { display: grid; gap: 10px; justify-items: start; padding: 12px 14px; margin: 6px 0 14px;
       background: var(--sheet); border: 1px solid var(--rule); border-radius: var(--r); color: var(--ink); }
.blank { padding: 60px 0; }

/* ── pages ────────────────────────────────────────────────────────────── */
.v-other .detail, .v-welcome .detail { max-width: 980px; }
.page-head { display: grid; gap: 10px; padding: 24px 0 12px; }
.page-head h1 { font-size: clamp(36px, 5vw, 54px); font-weight: 600; }
.lede { font-size: 17px; color: var(--ink-2); }
.block { display: grid; gap: 12px; padding: 20px 0 22px; border-top: 1px solid var(--rule); justify-items: start; }
.block > * { max-width: 100%; }
.block h2 { font-size: 26px; }
.block .scroll { width: 100%; }
.empty-block { display: grid; gap: 14px; justify-items: start; padding: 18px 0 32px; border-top: 1px solid var(--rule); color: var(--ink-2); }

/* first run */
.welcome { display: grid; gap: 16px; padding: 28px 0 32px; max-width: 720px; }
.welcome h1 { font-size: clamp(40px, 6.4vw, 68px); font-weight: 600; letter-spacing: -0.02em; }
.card { display: grid; gap: 10px; padding: 20px; background: var(--sheet); border: 1px solid var(--rule);
        border-radius: var(--r); }
.card.plain { background: transparent; }
.card h2 { font-size: 26px; }
.card label, .keyblock label { font-size: 15px; color: var(--ink-2); font-weight: 500; padding-top: 6px; }
.card .row-btns { padding-top: 6px; }
.err { color: var(--down); font-size: 14px; min-height: 1.2em; }
.err:empty { min-height: 0; }

/* settings */
.keyblock { display: grid; gap: 8px; width: 100%; max-width: 560px; padding: 6px 0 10px; }
.masked { font-size: 16px; letter-spacing: 0.08em; padding: 4px 0; }
.keymsg { font-size: 14px; color: var(--ink-2); }
.keymsg.ok { color: var(--up); }
.keymsg.bad { color: var(--down); }

/* tracked */
.key { max-width: none; display: flex; gap: 8px 18px; flex-wrap: wrap; color: var(--ink-3); font: 500 12px/1.4 var(--f-mono); padding: 4px 0 14px; }
.key i { display: inline-block; vertical-align: middle; margin-right: 6px; }
.key .k-mid { width: 16px; height: 2px; background: var(--band); }
.key .k-ml { width: 16px; height: 0; border-top: 1px dashed var(--ink-2); }
/* 3.0.3: the stock chart's key: the past, and the band's two shades */
.key .k-past { width: 16px; height: 2px; background: var(--stone); }
.key .k-band { width: 16px; height: 10px; background: linear-gradient(var(--band-wash) 0 25%, var(--band-wash-2) 25% 75%, var(--band-wash) 75%); }
.s-key { padding: 6px 0 0; }
.key .dot { width: 9px; height: 9px; border-radius: 50%; }
.d50 { background: var(--band); } .d90 { background: var(--stone); } .dout { background: var(--down); }
.trk { display: grid; gap: 12px; padding: 18px 0 22px; border-top: 1px solid var(--ink); }
.trk-head { display: flex; justify-content: space-between; align-items: start; gap: 12px; flex-wrap: wrap; }
.trk-head > div:first-child { display: grid; gap: 4px; min-width: 0; }
.trk h2 { font: 500 26px/1.1 var(--f-mono); letter-spacing: -0.01em; }
.trk-chart-wrap { height: 200px; }
.trk-chart { width: 100%; height: 100%; display: block; }
.scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; max-width: 100%; }
.tbl { width: 100%; border-collapse: collapse; font-size: 14px; font-variant-numeric: tabular-nums; }
.tbl th { text-align: left; font: 500 12px/1.3 var(--f-mono); letter-spacing: 0.03em; color: var(--ink-3);
          padding: 6px 12px 8px 0; border-bottom: 1px solid var(--rule); vertical-align: bottom; }
.tbl td { padding: 9px 12px 9px 0; border-bottom: 1px solid var(--rule-2); color: var(--ink-2); vertical-align: top; }
.tbl td:first-child { color: var(--ink); white-space: nowrap; }
.tbl .num { font-family: var(--f-mono); font-size: 13.5px; white-space: nowrap; }
.tbl .sub { display: block; font: 400 12px/1.4 var(--f-body); color: var(--ink-3); white-space: nowrap; }
.tbl .r { text-align: right; }
.tbl .aim { display: block; color: var(--ink-3); font-weight: 400; letter-spacing: 0; }
.res { font-weight: 600; white-space: nowrap; }
.res.r50 { color: var(--band); } .res.r90 { color: var(--stone); } .res.rout { color: var(--down); }
.res.muted { font-weight: 400; color: var(--ink-3); }
.rec-head { color: var(--ink); }

/* on a phone the tracked table becomes one block per checkpoint: the
   checkpoint and its result on top, the four figures labelled beneath */
@media (max-width: 640px) {
  .tbl.stack thead { display: none; }
  .tbl.stack, .tbl.stack tbody { display: block; }
  .tbl.stack tr { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 8px 14px;
                  padding: 12px 0; border-bottom: 1px solid var(--rule-2); }
  .tbl.stack td { border: 0; padding: 0; white-space: normal; }
  .tbl.stack td.res { grid-column: 2; grid-row: 1; text-align: right; }
  .tbl.stack td[data-label]::before { content: attr(data-label); display: block;
    font: 500 11px/1.4 var(--f-mono); letter-spacing: 0.03em; color: var(--ink-3); }
}

/* scorecard meters, as on /method */
.meter { display: flex; align-items: center; gap: 10px; min-width: 140px; }
.meter .track { position: relative; flex: 1; height: 6px; background: var(--rule-2); min-width: 70px; }
.meter .fill { position: absolute; left: 0; top: 0; bottom: 0; background: var(--band); }
.meter .aimtick { position: absolute; top: -4px; bottom: -4px; width: 2px; margin-left: -1px; background: var(--ink); }
.meter .mv { font: 500 14px/1 var(--f-mono); color: var(--ink); min-width: 3.2em; text-align: right; }
@media (max-width: 560px) {
  .meter { min-width: 92px; gap: 6px; }
  .meter .track { min-width: 36px; }
  .tbl th, .tbl td { padding-right: 8px; }
}

/* ── footer ───────────────────────────────────────────────────────────── */
.foot { max-width: 1600px; margin: 0 auto; display: grid; gap: 10px; font-size: 14px; color: var(--ink-3);
        border-top: 1px solid var(--rule);
        padding: 20px max(var(--gut), env(safe-area-inset-right)) 32px max(var(--gut), env(safe-area-inset-left)); }
.foot nav { display: flex; gap: 0 20px; flex-wrap: wrap; }
.foot nav a { display: inline-flex; align-items: center; min-height: 44px; }
.foot p { max-width: 90ch; }
body.v-boot .foot { display: none; }

/* ── motion (motion spec, sections 2 to 4) ─────────────────────────────── */
/* The springs as CSS, for what never turns around mid-flight (a press
   springing back, a crossfade). Anything that can be interrupted is a JS
   spring in spring.js with the same stiffness and damping. Each curve comes
   with the time it takes to settle to 0.2 percent. */
:root {
  --spring-press: linear(0, 0.022, 0.0773, 0.153, 0.2395, 0.3298, 0.419, 0.5037, 0.5818, 0.6523, 0.7146, 0.7689, 0.8153, 0.8546, 0.8873, 0.9143, 0.9361, 0.9537, 0.9675, 0.9783, 0.9865, 0.9927, 0.9972, 1.0004, 1.0025, 1.0039, 1.0046, 1.005, 1.005, 1.0048, 1.0045, 1.0041, 1.0036, 1.0032, 1.0027, 1.0023, 1);
  --spring-press-d: 192ms;
  --spring-snappy: linear(0, 0.0221, 0.0778, 0.1542, 0.2416, 0.3328, 0.4228, 0.5083, 0.5872, 0.6582, 0.721, 0.7754, 0.822, 0.8612, 0.8937, 0.9204, 0.9419, 0.9591, 0.9725, 0.9828, 0.9905, 0.9962, 1.0003, 1.003, 1.0048, 1.0058, 1.0062, 1.0063, 1.006, 1.0056, 1.0051, 1.0046, 1.004, 1.0034, 1.0029, 1.0024, 1);
  --spring-snappy-d: 385ms;
  --spring-smooth: linear(0, 0.0237, 0.0814, 0.1577, 0.2425, 0.3287, 0.412, 0.4899, 0.561, 0.6246, 0.6809, 0.7301, 0.7727, 0.8093, 0.8405, 0.867, 0.8894, 0.9083, 0.9241, 0.9373, 0.9483, 0.9575, 0.965, 0.9713, 0.9765, 0.9808, 0.9843, 0.9872, 0.9895, 0.9915, 0.9931, 0.9943, 0.9954, 0.9963, 0.997, 0.9975, 1);
  --spring-smooth-d: 539ms;
  --spring-gentle: linear(0, 0.0237, 0.0813, 0.1577, 0.2424, 0.3286, 0.4119, 0.4898, 0.5609, 0.6246, 0.6808, 0.73, 0.7726, 0.8092, 0.8404, 0.867, 0.8894, 0.9082, 0.924, 0.9373, 0.9483, 0.9574, 0.965, 0.9713, 0.9765, 0.9807, 0.9843, 0.9871, 0.9895, 0.9915, 0.993, 0.9943, 0.9954, 0.9963, 0.997, 0.9975, 1);
  --spring-gentle-d: 741ms;
  --spring-bouncy: linear(0, 0.0207, 0.0742, 0.1494, 0.2373, 0.331, 0.4251, 0.5159, 0.6008, 0.6779, 0.7465, 0.8061, 0.8569, 0.8994, 0.9341, 0.9618, 0.9834, 0.9997, 1.0115, 1.0197, 1.0248, 1.0275, 1.0284, 1.0279, 1.0265, 1.0244, 1.0219, 1.0193, 1.0166, 1.014, 1.0116, 1.0094, 1.0074, 1.0057, 1.0042, 1.003, 1);
  --spring-bouncy-d: 554ms;
  --spring-exit: linear(0, 0.0237, 0.0814, 0.1578, 0.2426, 0.3288, 0.4122, 0.4901, 0.5612, 0.6248, 0.6811, 0.7303, 0.7729, 0.8094, 0.8406, 0.8672, 0.8895, 0.9084, 0.9242, 0.9374, 0.9484, 0.9575, 0.9651, 0.9714, 0.9765, 0.9808, 0.9843, 0.9872, 0.9895, 0.9915, 0.9931, 0.9944, 0.9954, 0.9963, 0.997, 0.9975, 1);
  --spring-exit-d: 337ms;
}
@supports not (animation-timing-function: linear(0, 1)) {
  :root {
    --spring-press: cubic-bezier(0.25, 1, 0.5, 1); --spring-snappy: cubic-bezier(0.25, 1, 0.5, 1);
    --spring-smooth: cubic-bezier(0.25, 1, 0.5, 1); --spring-gentle: cubic-bezier(0.25, 1, 0.5, 1);
    --spring-bouncy: cubic-bezier(0.25, 1, 0.5, 1); --spring-exit: cubic-bezier(0.25, 1, 0.5, 1);
  }
}

/* touch: no double-tap wait anywhere a finger presses; the stock screen
   leaves sideways moves to the edge swipe */
a, button, input, label, summary, .row { touch-action: manipulation; }
@media (max-width: 899px) { body.v-stock, body.v-stock .detail, body.pushing { touch-action: pan-y pinch-zoom; } }

/* press: a button sinks the moment it is pressed (scale 0.97, a shade
   darker) and springs back with --spring-press. Nothing moves on hover. */
.btn { transition: transform var(--spring-press-d) var(--spring-press), filter var(--spring-press-d) var(--spring-press); }
.btn:active, .btn.pressed { transform: scale(0.97); filter: brightness(0.93); transition: none; }
.seg button, .tabs a { transition: opacity var(--spring-press-d) var(--spring-press); }
.seg button:active, .tabs a:active, .seg button.pressed, .tabs a.pressed { opacity: 0.7; transition: none; }

/* the segmented pill (spring.js): one pill behind the labels; the labels'
   colour is mixed by how much of the pill is over them */
.seg { --seg-ink: var(--ink-2); }
.seg.seg-live { position: relative; isolation: isolate; }
.seg-live > .seg-pill { position: absolute; left: 0; top: 0; z-index: -1; pointer-events: none;
                        background: var(--ink); border-radius: max(0px, calc(var(--r) - 1px)); transform-origin: 0 0; }
.seg.seg-live button, .seg.seg-live button[aria-pressed="true"] { background: transparent; position: relative; }
.seg.seg-live button + button { border-left-color: transparent; }
.seg-live button.seg-over { color: var(--paper); }

/* the selected tab's line: slides between tabs (snappy) */
@media (min-width: 700px) { .tabs { position: relative; } }
.tab-ind { position: absolute; left: 0; bottom: 0; width: 1px; height: 2px; background: var(--ink);
           transform-origin: 0 0; pointer-events: none; }
@media (max-width: 699px) { .tab-ind { bottom: auto; top: 0; } }

/* skeleton to content: 160 ms, opacity only (spring.js crossfade) */
@keyframes xf-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes xf-out { from { opacity: 1; } to { opacity: 0; } }
.xf-in { animation: xf-in 160ms linear; }
.xf-ghost { position: absolute; pointer-events: none; margin: 0; animation: xf-out 160ms linear forwards; }

/* a change of screen: the new one comes up from 35% (motion.js fadeIn) */

/* the phone's push: both screens on, the one that was showing held still */
body.pushing .split { position: relative; }
body.pushing .list, body.pushing .detail { display: block !important; }
body.pushing .list { position: relative; z-index: 1; }
body.pushing .detail { position: relative; z-index: 3; background: var(--paper);
                       min-height: calc(100vh - var(--bar-h)); min-height: calc(100dvh - var(--bar-h)); }
/* while they move, both panes reach the screen's edges, so the screen behind
   does not show in the side gutters (3.0.3) */
body.pushing .list, body.pushing .detail { margin-left: calc(-1 * var(--bleed-l, 0px)); margin-right: calc(-1 * var(--bleed-r, 0px));
                                           padding-left: var(--bleed-l, 0px); padding-right: var(--bleed-r, 0px); }
body.pushing .list { background: var(--paper); }
body.pushing .held { position: fixed !important; margin: 0; }
body.pushing .detail.held { z-index: 4; }
body.pushing .list.held { z-index: 1; }
body.pushing .held { box-sizing: border-box; }
.push-dim { position: fixed; left: 0; right: 0; bottom: 0; top: 0; background: var(--push-dim); opacity: 0; pointer-events: none; z-index: 2; }
/* the screen coming in from the right must not widen the page */
body.pushing .main { overflow-x: hidden; overflow-x: clip; }

/* bottom sheets (phone) */
.sheet-layer { position: fixed; left: 0; right: 0; top: 0; bottom: var(--kb, 0px); z-index: 30; }
.sheet-dim { position: absolute; inset: 0; background: var(--sheet-dim); opacity: 0; }
.sheet { position: absolute; left: 0; right: 0; bottom: 0; max-height: 88%; overflow: auto;
         background: var(--sheet); border-top: 1px solid var(--rule); border-radius: 8px 8px 0 0;
         padding: 6px max(16px, env(safe-area-inset-right)) calc(18px + env(safe-area-inset-bottom)) max(16px, env(safe-area-inset-left));
         display: grid; gap: 12px; touch-action: none; overscroll-behavior: contain; }
.sheet:focus { outline: none; }
.sheet-grab { width: 36px; height: 4px; border-radius: 2px; background: var(--rule); margin: 4px auto 4px; }
.sheet h2 { font-size: 26px; }
.sheet-body { display: grid; gap: 12px; }
.sheet-actions { padding-top: 4px; }
.sheet-actions .btn { flex: 1 1 140px; }
body.sheet-open { overflow: hidden; }

/* the switch */
.switch-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; width: 100%; max-width: 560px;
              min-height: 44px; font-weight: 600; }
.switch { appearance: none; border: 0; background: transparent; padding: 8px 0 8px 8px; margin: 0; min-height: 44px; touch-action: pan-y;
          display: inline-flex; align-items: center; cursor: pointer; color: inherit; }
.sw-track { position: relative; display: block; width: 48px; height: 28px; border-radius: 14px; background: var(--sw-off); }
.sw-knob { position: absolute; left: 2px; top: 2px; width: 24px; height: 24px; border-radius: 12px; background: var(--sw-knob); }
.switch:focus-visible { outline: none; }
.switch:focus-visible .sw-track { outline: 2px solid var(--focus); outline-offset: 2px; }

/* numbers that roll */
.rc { display: inline-block; white-space: pre; vertical-align: top; transition: color 600ms ease-out; }
.rc.roll { position: relative; overflow: hidden; clip-path: inset(0); }
.rc.roll .rn { display: inline-block; }
.rc.roll .ro { position: absolute; left: 0; top: 0; }
.rc.tint-up, .rc.tint-up .rn { color: var(--up); transition: none; }
.rc.tint-down, .rc.tint-down .rn { color: var(--down); transition: none; }
/* a cell that hugs the digits, so a rolling digit comes in at the line */
.s-price .num, .row-fig .num { display: inline-block; line-height: 1.15; }

/* a table cell that just filled in: tinted, then the tint fades (no roll) */
.tbl td { transition: background-color 400ms linear; }
.tbl td.tint { background-color: var(--tint); transition: none; }
.tbl td.tint .sub { color: var(--ink-2); }
.tbl td.tint.tint-off { background-color: transparent; transition: background-color 400ms linear; }

/* the toast */
.toast { position: fixed; left: 50%; bottom: 24px; z-index: 25; max-width: min(560px, calc(100vw - 32px));
         background: var(--sheet); border: 1px solid var(--rule); border-radius: var(--r); padding: 10px 14px;
         font-size: 15px; color: var(--ink-2); pointer-events: none; }
.toast p { position: relative; }
@media (max-width: 699px) { .toast { bottom: calc(68px + env(safe-area-inset-bottom)); } }

/* adding on a phone is a sheet; the inline form stays on an iPad */
.only-phone { display: none; }
@media (max-width: 699px) {
  .only-phone { display: inline-flex; }
  .list > .add, .list > .add-msg, .list > .add-label, .list > .add-help { display: none; }
}
.rows, .trk-list, .notices { position: relative; }
.notice.leaving { background: var(--paper); z-index: 1; }

@media (prefers-reduced-motion: reduce) {
  /* no movement and no scaling; a press still shows, by colour */
  .btn, .seg button, .tabs a { transition: none; }
  .btn:active, .btn.pressed { transform: none; }
  .xf-in { animation-duration: 120ms; }
  .xf-ghost { animation-duration: 120ms; }
}

/* ── accessibility ────────────────────────────────────────────────────── */
/* a heading that takes focus after a change of screen does not need a ring:
   it is not a control, and it is not in the tab order */
h1[tabindex="-1"]:focus { outline: none; }
/* visually hidden, still read out */
.vh { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;
      clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0; }
.list-title { font-size: 28px; }
.add-help { padding: 2px 0 6px; }
.add-label { display: block; font-size: 14px; color: var(--ink-2); padding: 0 0 6px; }
.keyname { font-size: 15px; color: var(--ink-2); font-weight: 500; padding-top: 6px; }
.notice-keys { color: var(--ink-2); max-width: 60ch; }
/* 3.0.3: how to get the free key, numbered */
.steps-box { display: grid; gap: 6px; max-width: 62ch; }
.steps { margin: 0; padding-left: 22px; display: grid; gap: 6px; color: var(--ink-2); }
.steps li::marker { font: 500 13px var(--f-mono); color: var(--stone); }
label.btn { cursor: pointer; }
.vh:focus-visible + label.btn { outline: 2px solid var(--focus); outline-offset: 2px; }
.est-label { margin-bottom: 2px; }
.links { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0 20px; }
.links a { display: inline-flex; align-items: center; min-height: 44px; }
input[aria-invalid="true"] { border-color: var(--down); }

/* 3.0.3: the portfolio, in Veduta Lite as well as Veduta for the web (moved from web.css) */
/* ── portfolio ───────────────────────────────────────────────────────────── */
.portfolio { display: grid; gap: 0; }
.pf-add { display: grid; gap: 4px; padding: 14px 0 12px; border-top: 1px solid var(--rule); }
.pf-fields { display: grid; grid-template-columns: minmax(120px, 1fr) minmax(100px, 0.8fr) minmax(170px, 1.3fr) auto;
             gap: 10px 12px; align-items: end; max-width: 860px; }
.pf-fields label { display: grid; gap: 6px; font-size: 14px; color: var(--ink-2); font-weight: 500; }
@media (max-width: 760px) {
  .pf-fields { grid-template-columns: 1fr 1fr; }
  .pf-fields label:nth-child(3), .pf-fields .btn { grid-column: 1 / -1; }
}
.tbl.pf { margin-top: 4px; }
.tbl.pf th.r, .tbl.pf td.r { text-align: right; }
.tbl.pf td { vertical-align: top; }
.pf-sym { font: 500 15px/1.3 var(--f-mono); color: var(--ink); text-decoration: none; }
a.pf-sym:hover { text-decoration: underline; color: var(--ink); }
.pf-act { white-space: nowrap; }
.pf-act .row-btns { justify-content: flex-end; flex-wrap: nowrap; }
.pf-act .confirm { justify-content: flex-end; }
.pf-edit { display: flex; gap: 12px; flex-wrap: wrap; }
.pf-edit label { display: grid; gap: 4px; font-size: 13px; color: var(--ink-2); }
.pf-edit input { width: 150px; }
.pf-editing td { background: var(--sheet); }
.pf-totals { display: grid; gap: 8px; padding: 14px 0 10px; border-top: 1px solid var(--ink); margin-top: 6px; }
.pf-totals p { color: var(--ink-2); }
.pf-totals b { color: var(--ink); font-weight: 600; }
.pf-totals .num { color: var(--ink); }
.pf-totals .num.up { color: var(--up); }
.pf-totals .num.down { color: var(--down); }
.portfolio > .small.muted, .pf-body > .small.muted { padding: 6px 0 4px; }
@media (max-width: 640px) {
  .tbl.pf.stack td.pf-act { grid-column: 1 / -1; }
  .tbl.pf.stack td.r { text-align: left; }
}

/* 3.0.3: finding a stock by its name or its symbol */
input[type=search] {
  font: 400 16px/1.3 var(--f-body); color: var(--ink); background: var(--sheet);
  border: 1px solid var(--field); border-radius: var(--r); padding: 10px 12px; min-height: 44px;
  width: 100%; min-width: 0; -webkit-appearance: none; appearance: none;
}
.sheet input[type=search] { background: var(--paper); }
.finder { display: grid; padding-bottom: 6px; }
.finds { list-style: none; margin: 6px 0 2px; padding: 0; border-top: 1px solid var(--rule); }
.list .finds { max-height: min(420px, 50vh); overflow-y: auto; overscroll-behavior: contain; }
/* in a sheet the matches scroll on their own, above the keyboard */
.sheet .finds { max-height: max(160px, calc(82dvh - var(--kb, 0px) - 250px)); overflow-y: auto;
                overscroll-behavior: contain; touch-action: pan-y; }
.find { display: flex; align-items: center; gap: 8px; border-bottom: 1px solid var(--rule-2); }
.find-open { flex: 1; min-width: 0; display: grid; grid-template-columns: 5.2em minmax(0, 1fr); gap: 1px 10px;
             align-items: baseline; min-height: 52px; padding: 7px 6px; margin: 0; border: 0; background: transparent;
             color: var(--ink); font: inherit; text-align: left; cursor: pointer; border-radius: 0; }
.find-open:hover { background: var(--paper); }
.list .find-open:hover { background: var(--sheet); }
.find-sym { font: 500 14.5px/1.25 var(--f-mono); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.find-name { font-size: 15px; line-height: 1.25; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.find-meta { grid-column: 2; font-size: 12.5px; line-height: 1.3; color: var(--ink-3); }
.find-paid .find-meta { color: var(--stone); }
.find-paid .find-sym { color: var(--ink-2); }
.find-on { flex: none; color: var(--ink-3); padding: 0 6px; white-space: nowrap; }
.find-add { flex: none; }
.finder .add-msg:not(:empty) { padding-top: 8px; }
@media (max-width: 699px) {
  .list > .finder { display: none; }
}
/* a sheet on a wider screen sits in the middle, the width of its text */
@media (min-width: 700px) {
  .sheet { left: 0; right: 0; margin: 0 auto; width: min(620px, calc(100% - 48px));
           border: 1px solid var(--rule); border-bottom: 0; }
}
@media (max-width: 400px) {
  .tabs a { font-size: 13px; }
}

/* 3.0.3: the sections. Below 1100 px the bar has five, and Paper account,
   Scorecard and Settings are behind More */
@media (max-width: 1099px) { .tabs .tab-wide { display: none; } }
@media (min-width: 1100px) { .tabs .tab-more { display: none; } }
.more { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--rule); max-width: 720px; }
.more li { border-bottom: 1px solid var(--rule-2); }
.more a { display: grid; gap: 4px; padding: 14px 4px; min-height: 64px; text-decoration: none; color: var(--ink); }
.more a:hover { background: var(--sheet); color: var(--ink); }
.more b { font: 600 18px/1.25 var(--f-body); }

/* a stock's facts, holding, paper position and headlines (both editions) */
.s-aside { display: grid; padding: 4px 0 18px; border-top: 1px solid var(--rule); }
.a-sec { display: grid; gap: 8px; padding: 14px 0; border-bottom: 1px solid var(--rule-2); justify-items: start; }
.a-sec:last-child { border-bottom: 0; }
.a-sec > * { max-width: 100%; }
.a-sec .row-btns a { min-height: 44px; display: inline-flex; align-items: center; }
.facts { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 8px 16px; margin: 0; width: 100%; }
.facts dt { font-size: 14px; color: var(--ink-3); }
.facts dd { margin: 0; font-size: 15px; color: var(--ink); min-width: 0; }
.facts .num { font-size: 14px; }
.facts .sub, .news .sub { display: block; font-size: 12.5px; line-height: 1.4; color: var(--ink-3); }
.news { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
.news a { font-weight: 500; text-decoration: none; color: var(--ink); line-height: 1.35; }
.news a:hover { text-decoration: underline; color: var(--ink); }
@media (max-width: 479px) {
  .facts { grid-template-columns: minmax(0, 1fr); gap: 2px 0; }
  .facts dd { padding-bottom: 8px; }
}

/* the deep analysis, under the forecast */
.deep { display: grid; gap: 10px; padding: 16px 0 24px; border-top: 1px solid var(--rule); justify-items: start; }
.deep h2 { font-size: 24px; }
.deep > * { max-width: 100%; }
.deep-bar { width: min(420px, 100%); height: 6px; background: var(--rule-2); position: relative; overflow: hidden; }
.deep-bar i { position: absolute; left: 0; top: 0; bottom: 0; background: var(--band); transition: width 160ms linear; }
/* only the count is tabular: in this face a tabular comma is as wide as a digit */
.deep-run .tn { font-variant-numeric: tabular-nums; }
.deep-facts { max-width: 760px; }
.deep-v { font-size: 15px; font-weight: 500; }
@media (prefers-reduced-motion: reduce) { .deep-bar i { transition: none; } }

/* a paper order, in a sheet */
.tr-form { display: grid; gap: 12px; }
.tr-form label { display: grid; gap: 6px; font-size: 15px; color: var(--ink-2); font-weight: 500; }
.tr-bracket { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.tr-form .seg { justify-self: start; }
.pa-facts { max-width: 560px; }
.pa-facts .num { font-size: 15px; }

/* Discover */
.disc { list-style: none; margin: 4px 0 8px; padding: 0; border-top: 1px solid var(--rule); max-width: 900px; }
.disc li { border-bottom: 1px solid var(--rule-2); }
.disc-row { display: grid; gap: 6px; padding: 14px 4px; text-decoration: none; color: var(--ink); }
a.disc-row:hover { background: var(--sheet); color: var(--ink); }
.disc-top { display: flex; align-items: baseline; gap: 6px 12px; flex-wrap: wrap; }
.disc-top b { font: 500 17px/1.2 var(--f-mono); }
.disc-name { color: var(--ink-2); font-size: 15px; }
.disc-top .tag { margin-left: 0; }
.disc-why { font-size: 15px; line-height: 1.45; max-width: 70ch; }
.disc-figs { display: flex; gap: 4px 16px; flex-wrap: wrap; color: var(--ink-3); }
.disc-figs .num { color: var(--ink); }
.disc-figs .num.up { color: var(--up); } .disc-figs .num.down { color: var(--down); }

/* ── the mark, and the app at work (3.0.3) ────────────────────────────────
   Veduta's mark: the path a price took, the node that is now, and the cone
   of what may come. While the app works the mark draws itself again, as the
   desktop app's does when it opens: the cone closes and the path is wiped
   from its start, then the path draws in, the node lands and the cone opens.
   A loop begins and ends on the whole mark, so starting or stopping never
   jumps. With reduced motion only the cone's shade changes. */
.vmark { display: inline-block; flex: none; color: var(--band); overflow: visible; vertical-align: middle; }
.vm-fill { fill: currentColor; opacity: 0.3; }
.vm-edge { fill: none; stroke: currentColor; stroke-width: 4.5; stroke-linecap: round; opacity: 0.85; }
.vm-tail { fill: none; stroke: currentColor; stroke-width: 8.2; stroke-linecap: round; stroke-linejoin: round;
           stroke-dasharray: 1 1.04; stroke-dashoffset: 0; }
.vm-node { fill: currentColor; }
.vm-cone, .vm-node { transform-box: view-box; transform-origin: 45.5px 47.5px; }
/* a mark drawn again by a redraw of its screen keeps its place in the loop
   (app.js sets --vm-delay from the clock), so it does not start over */
.vmark.is-loop .vm-tail { animation: vm-tail 1.6s var(--vm-delay, 0s) infinite; }
.vmark.is-loop .vm-node { animation: vm-node 1.6s var(--vm-delay, 0s) infinite; }
.vmark.is-loop .vm-cone { animation: vm-cone 1.6s var(--vm-delay, 0s) infinite; }
@keyframes vm-tail {
  0% { stroke-dashoffset: 0; animation-timing-function: cubic-bezier(0.4, 0, 1, 1); }
  14% { stroke-dashoffset: -1.02; }
  14.01% { stroke-dashoffset: 1.02; }
  22% { stroke-dashoffset: 1.02; animation-timing-function: cubic-bezier(0.2, 0, 0, 1); }
  52%, 100% { stroke-dashoffset: 0; }
}
@keyframes vm-node {
  0% { transform: scale(1); animation-timing-function: cubic-bezier(0.4, 0, 1, 1); }
  10%, 50% { transform: scale(0); animation-timing-function: cubic-bezier(0.3, 1.5, 0.6, 1); }
  62%, 100% { transform: scale(1); }
}
@keyframes vm-cone {
  0% { transform: scale(1, 1); animation-timing-function: cubic-bezier(0.4, 0, 1, 1); }
  12%, 58% { transform: scale(1, 0); animation-timing-function: cubic-bezier(0.2, 0, 0, 1); }
  84%, 100% { transform: scale(1, 1); }
}
/* a determinate form, for the deep analysis: the cone opens as it goes */
.vmark.is-progress .vm-cone { transform: scale(1, var(--p, 0)); transition: transform 200ms cubic-bezier(0.2, 0, 0, 1); }
@media (prefers-reduced-motion: reduce) {
  .vmark.is-loop .vm-tail, .vmark.is-loop .vm-node, .vmark.is-loop .vm-cone { animation: none; }
  .vmark.is-loop .vm-fill { animation: vm-shade 1.6s ease-in-out var(--vm-delay, 0s) infinite; }
  .vmark.is-progress .vm-cone { transition: none; }
}
@keyframes vm-shade { 0%, 100% { opacity: 0.3; } 50% { opacity: 0.08; } }

/* the mark in the bar: Veduta's name beside it */
.brand-mark { width: 28px; height: 28px; }
@media (max-width: 699px) { .brand-mark { width: 24px; height: 24px; } }

/* the line along the top of the window while prices or a forecast are on
   their way: it runs most of the way, then completes and fades */
.loadbar { position: fixed; left: 0; right: 0; top: env(safe-area-inset-top, 0px); height: 2px; z-index: 40;
           pointer-events: none; opacity: 0; }
.loadbar i { display: block; height: 100%; width: 0; background: var(--band); }
.loadbar.on { opacity: 1; }
.loadbar.done { opacity: 0; transition: opacity 280ms linear 160ms; }
@media (prefers-reduced-motion: reduce) {
  .loadbar i { width: 100% !important; transition: none !important; opacity: 0.6; }
}

/* starting up: the mark draws itself above the skeleton, after a moment
   (a quick start shows only the skeleton) */
.boot { justify-items: start; }
.boot-mark { width: 56px; height: 56px; margin: 18px 0 12px; opacity: 0; animation: boot-in 200ms linear 350ms forwards; }
@keyframes boot-in { to { opacity: 1; } }

/* small marks at work beside a status or in a button */
.vmark.sm { width: 18px; height: 18px; }
.keymsg .vmark { margin: -2px 6px 0 0; }
.btn .vmark { width: 18px; height: 18px; color: currentColor; }
/* the mark keeps to the first line of a status that wraps */
.disc-status { display: flex; align-items: flex-start; gap: 8px; }
.disc-status .vmark { margin-top: 1px; }
.deep-run { display: flex; align-items: center; gap: 10px; }
.deep-run .vmark { width: 28px; height: 28px; }

