@font-face{font-family:"Manrope";font-style:normal;font-display:swap;font-weight:200 800;src:url(/fonts/manrope-latin-a30ddcd34970.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:"Manrope";font-style:normal;font-display:swap;font-weight:200 800;src:url(/fonts/manrope-latin-ext-3911b66d9f2e.woff2) format("woff2");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}
@font-face{font-family:"Manrope";font-style:normal;font-display:swap;font-weight:200 800;src:url(/fonts/manrope-cyrillic-c268b459a932.woff2) format("woff2");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}
@font-face{font-family:"Manrope";font-style:normal;font-display:swap;font-weight:200 800;src:url(/fonts/manrope-cyrillic-ext-de37de877dc1.woff2) format("woff2");unicode-range:U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}

  /* --- VANTIAS -----------------------------------------------------------
     One palette, named by ROLE rather than by hue, so a component never
     reaches for a raw colour. Everything downstream -- the dashboard sheet,
     the portfolio sheet, the reference blocks -- is written against these
     tokens, which is why the whole surface can be restyled from this block.

     THE GROUND IS DEEP GREY AND THE INK IS NEAR-WHITE. Turned over on
     16 Sep 2026: the light sheet read as paper, and this is an instrument
     somebody watches for hours. The canvas is a cool near-black grey, the
     panels sit a step LIGHTER than it, and the wells a step darker -- three
     levels, so a card reads as something resting on the surface and an input
     as a hole cut into it.

     NOT BLACK, AND NOT BLUE. Pure black makes every edge a hard line and
     every white letter glare; a navy tint is the default "dark mode" of every
     dashboard ever screenshotted. This grey is neutral with a trace of cool.

     THE SEMANTIC COLOURS ARE LIT, NOT NEON. MEASURED on 25 Sep 2026 against
     the RAISED card #181C22 -- the lightest ground any of them sits on, so
     the worst case -- WCAG ratios: text 14.83, accent 12.27, muted 6.70,
     positive 7.59, negative 5.61, warning 7.63, high 6.27, alternate 6.01.
     Every one clears 4.5:1 with room, because a number a holder reads at
     night is the whole product. The two chart palettes were re-validated on
     the new card as well; see `view_portfolio.TYPE_PALETTE`. */
  :root {
    color-scheme: dark;
    /* DEEPER, AND LIT FROM ABOVE. Turned over again on 25 Sep 2026: the
       graphite read as flat because nothing on it caught any light. The
       canvas went a step darker so that a panel, a hairline and a glow have
       somewhere to show up -- still neutral, still not navy, still not black.
       The three levels stay: well darker than the canvas, panel lighter,
       raised panel lighter again. */
    --bg: #0B0D10;            /* canvas            */
    --bg2: #07090B;           /* inset, well       */
    --card: #12151A;          /* card, form, table */
    --card-2: #181C22;        /* a card raised above a card */
    --card-3: #1E232A;        /* the raised card under the pointer */
    --border: #232830;        /* hairline divider  */
    --line: #232830;
    --rule-strong: #343B45;   /* a divider meant to be seen */
    --text: #ECEFF3;          /* data and headings */
    --muted: #9AA3AE;         /* labels, prose     */
    --accent: #D5DBE3;        /* links, tabs, tags: platinum, not a hue */
    --accent2: #D5DBE3;
    --accent-soft: rgba(213,219,227,.08);
    --accent-line: rgba(213,219,227,.28);
    /* THE LIGHT ITSELF. One cool-white, used at low alpha for the glow behind
       the page, the halo round the mark and the live dot. Platinum lit, not a
       colour: a blue here would make this a second product. */
    --glow: rgba(196,212,236,.10);
    --glow-strong: rgba(214,226,244,.55);
    /* THE SIGNATURE. A one-pixel platinum line that fades out at both ends --
       under the top bar and across the head of the figure a panel exists to
       show. It is what reads as "finished" on a dark sheet, and it costs one
       gradient. */
    --hairline: linear-gradient(90deg, transparent, rgba(226,232,240,.55), transparent);
    /* A PANEL IS LIT FROM ABOVE. The sheen is the top 140 pixels of every
       panel catching a little light; with a hairline highlight on the top
       edge (in the shadows below) it is what separates a surface from a
       rectangle filled with grey. `--surface` is a whole `background` value,
       sheen and fill together, so a component writes one word. */
    --sheen: linear-gradient(180deg, rgba(255,255,255,.034), rgba(255,255,255,0) 140px);
    --surface: var(--sheen), var(--card);
    --surface-2: linear-gradient(180deg, rgba(255,255,255,.05), rgba(255,255,255,0) 120px), var(--card-2);
    /* THE ONE FILLED BUTTON. Brushed platinum with ink on it, a lit top edge
       and a soft light under it; everything else is a ghost. */
    --btn: linear-gradient(180deg, #EEF1F5 0%, #C7CED7 100%);
    --btn-hover: linear-gradient(180deg, #F7F9FB 0%, #D2D8E0 100%);
    --btn-glow: 0 10px 26px -14px rgba(214,226,244,.60),
                inset 0 1px 0 rgba(255,255,255,.70),
                inset 0 -1px 0 rgba(0,0,0,.18);
    --btn-glow-hover: 0 14px 32px -14px rgba(214,226,244,.75),
                      inset 0 1px 0 rgba(255,255,255,.80),
                      inset 0 -1px 0 rgba(0,0,0,.18);
    --pos: #56C08D;           /* profit, growth    */
    /* The step between "good" and the first sign of trouble. The SAME hue as
       --pos and lighter, rather than a yellow-green: measured with
       scripts/validate_palette.py, a yellow-green separates from --pos by 2.1
       under deuteranopia and this separates by 11.5 under protanopia, because
       lightness survives colour blindness and hue does not. */
    --pos-weak: #A3E0C0;
    --neg: #E2736A;           /* loss              */
    --warn: #D7A54A;          /* risk, impact      */
    --high: #D98A4F;          /* the band between warn and loss */
    /* THE TINT AND THE EDGE THAT GO WITH EACH SEMANTIC INK. A tint on a dark
       ground has to be lighter than its ground, which means the tint is the
       INK at low alpha, never a second colour. */
    --pos-soft: rgba(86,192,141,.11);  --pos-line: rgba(86,192,141,.34);
    --neg-soft: rgba(226,115,106,.11); --neg-line: rgba(226,115,106,.34);
    --warn-soft: rgba(215,165,74,.11); --warn-line: rgba(215,165,74,.34);
    --high-soft: rgba(217,138,79,.11); --high-line: rgba(217,138,79,.34);
    /* The one hue that is not platinum: what is NOT a dollar market, and the
       YT leg. A category, not a severity, so it must not be read as either
       good or bad. */
    --alt: #9A8CF0;
    --alt-soft: rgba(154,140,240,.11);
    --alt-line: rgba(154,140,240,.34);
    --on-accent: #0E1013;     /* text ON the accent */
    --mark-tile: #DDE1E6;     /* the wordmark's ground */
    --mark-ink: #101215;      /* the V itself */

    /* SHADOW, NOT BORDER, IS WHAT SEPARATES -- and on a dark ground a shadow
       only seats a panel that is already told apart by being lighter. Each
       elevation carries a one-pixel lit top edge (the inset), a tight contact
       shadow, and a wide soft fall-off pulled in by a negative spread so it
       pools UNDER the panel instead of haloing round it. */
    --shadow-1: inset 0 1px 0 rgba(255,255,255,.035), 0 1px 2px rgba(0,0,0,.45),
                0 22px 44px -26px rgba(0,0,0,.85);
    --shadow-2: inset 0 1px 0 rgba(255,255,255,.06), 0 2px 6px rgba(0,0,0,.40),
                0 32px 72px -24px rgba(0,0,0,.92);
    /* The edge of a box with more content past it. A token rather than a
       literal because it is used in a gradient, where a raw rgba would be the
       one colour on the page nobody could find again. */
    --edge-hint: rgba(0,0,0,.45);
    --lift: inset 0 1px 0 rgba(255,255,255,.05);
    --ease: 200ms cubic-bezier(.2,.7,.2,1);

    /* THE TYPEFACE IS SHIPPED, NOT HOPED FOR. Manrope, served from this
       service (see `FONT_CSS`): a system stack is Segoe on one machine, San
       Francisco on the next and DejaVu on a server, and a figure that changes
       shape between two readers' screens is not one design. The stack after
       it is the fallback while the file arrives. */
    --font: "Manrope", ui-sans-serif, system-ui, -apple-system, "Segoe UI",
            Roboto, sans-serif;
    --mono: ui-monospace, "JetBrains Mono", "SF Mono", "Cascadia Mono",
            Menlo, Consolas, monospace;

    /* A scale with real distance between a label and the number it labels:
       the two used to sit .22rem apart, which is why the screen read as one
       undifferentiated block. */
    --fs-2xs: .69rem; --fs-xs: .75rem; --fs-sm: .83rem; --fs-sm2: .9rem;
    --fs-base: .95rem; --fs-md: 1.05rem; --fs-lg: 1.15rem; --fs-xl: 1.45rem;
    --fs-2xl: 1.8rem;
    --fs-data: 1.22rem;       /* the number a card exists to show */

    --pad-card: 1.35rem 1.45rem;
    --pad-cell: .8rem .9rem;
    --radius: 16px;
    --radius-sm: 12px;
    --radius-xs: 8px;
    /* ONE COLUMN WIDTH FOR EVERY PAGE, so the top bar, the page head and the
       content start at the same x. They did not: the board's header ran the
       full window while its cards sat in a 1180px column, and the eye read
       the step between them as a misalignment -- because it was one. */
    --page-w: 1240px;
    --gutter: 1.35rem;
  }
  @media (prefers-reduced-motion: reduce) {
    :root { --ease: 1ms linear; }
    /* A smooth scroll is motion whatever else is stilled, and it is the kind
       that makes some readers ill. Turned off here rather than left to the
       `--ease` token, which does not reach it. */
    html { scroll-behavior: auto; }
  }
  * { box-sizing: border-box; }
  /* THE LIGHT COMES FROM ABOVE THE PAGE. Two wide, faint washes of cool
     white, pinned to the window rather than the document so they stay where
     a lamp would be while the list scrolls under them. At these alphas they
     are felt rather than seen -- take them away and the sheet goes flat. */
  body {
    margin: 0; color: var(--text);
    background:
      radial-gradient(1100px 520px at 50% -200px, var(--glow), transparent 70%),
      radial-gradient(760px 460px at 100% -140px, rgba(170,190,225,.05), transparent 70%),
      var(--bg);
    background-attachment: fixed;
    font-family: var(--font);
    font-size: var(--fs-base); line-height: 1.55;
    -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
  }
  h1, h2, h3 { letter-spacing: -.02em; text-wrap: balance; }
  /* A LINK IS NOT A COLOUR HERE. The accent is graphite, so an underline --
     offset and thin -- is what says "this is a link"; colour alone would not,
     and on this ground nothing should have to shout to be found. */
  a { color: var(--accent); text-underline-offset: .2em;
      text-decoration-thickness: 1px; text-decoration-color: var(--accent-line);
      transition: text-decoration-color var(--ease), color var(--ease); }
  a:hover { text-decoration-color: var(--accent); }
  code, .mono { font-family: var(--mono); font-size: .92em; }
  button, input, select, textarea { font-family: inherit; }

  /* SCROLLBARS BELONG TO THE PALETTE TOO. Left alone, a browser draws its own
     -- which on this dark ground is a bright white bar across the bottom of
     every table that scrolls sideways, and the portfolio has one under a nine
     column table where it is impossible to miss.

     Both syntaxes, because they are not interchangeable: `scrollbar-color` is
     the standard and Firefox honours it; the `::-webkit-` pseudo-elements are
     what Chrome and Safari read. Declared on `*` rather than on `body` so a
     bar drawn inside a scrolling box is styled as well as the page's own. */
  /* THE `hidden` ATTRIBUTE MUST WIN. A browser hides `[hidden]` through its
     own stylesheet, and ANY author rule that sets `display` on the same
     element beats it -- author styles outrank the user agent's.

     Found live: the portfolio's undo bar carried `hidden` from the moment the
     page loaded and was visible anyway, because `.pf-undo { display:flex }`
     sat one line below. It read as a permanent "Position removed. Undo" that
     referred to nothing. Nobody had written a bug; two correct lines simply
     disagreed, and the cascade settled it the wrong way.

     Declared once, here, so no component has to remember. `!important` is the
     right tool exactly once: `hidden` is not a style, it is a statement that
     the element is not currently relevant, and nothing should be able to
     argue with it. */
  [hidden] { display: none !important; }

  /* SELECTED TEXT WAS THE ONE THING ON THE PAGE STILL WEARING THE BROWSER'S
     COLOURS. A default selection is a saturated blue, and on a graphite sheet
     whose whole palette is platinum it is the loudest thing on screen the
     moment a reader drags across a number to copy it -- which, on a service
     people copy figures out of, is often. The accent's own tint, with the ink
     left alone so contrast is unchanged. */
  /* NO `color` HERE, and that was the bug in the line it replaced: it set the
     DARK on-accent ink over a tint that is 28% platinum on a near-black page,
     so selected text went dark-on-dark -- about 2:1 -- at the one moment a
     reader was copying a figure out. With only a background, the text keeps
     its own ink. */
  ::selection { background: var(--accent-line); }

  /* An in-page jump used to teleport. `smooth` is scoped to the root so it
     applies to anchors and `scrollIntoView` alike, and is dropped entirely
     under reduced motion a few rules below. */
  html { scroll-behavior: smooth; }

  * { scrollbar-width: thin; scrollbar-color: var(--rule-strong) transparent; }
  ::-webkit-scrollbar { width: 10px; height: 10px; }
  ::-webkit-scrollbar-track { background: transparent; }
  ::-webkit-scrollbar-thumb {
    background: var(--rule-strong); border-radius: 999px;
    border: 2px solid transparent; background-clip: content-box;
  }
  ::-webkit-scrollbar-thumb:hover { background: var(--muted); background-clip: content-box; }
  ::-webkit-scrollbar-corner { background: transparent; }

  /* Every figure in this service lines up in a column somewhere. */
  b, strong, td.num, .num { font-variant-numeric: tabular-nums; }

  .muted { color: var(--muted); }
  .pos { color: var(--pos); } .neg { color: var(--neg); } .mid { color: var(--warn); }
  .ok { color: var(--pos); } .bad { color: var(--neg); }
  .ico { width: 1em; height: 1em; vertical-align: -.12em; }
  /* The direction glyphs, HERE because every page draws them -- the book's
     outbound links, the sign-in page's way to the introduction, the top
     bar's way in. They were in the board's sheet, so everywhere else they
     came out a size larger than the words beside them. */
  .ico-out { width: .85em; height: .85em; opacity: .8; }
  .ico-right, .ico-left { width: .9em; height: .9em; opacity: .75;
    transition: transform var(--ease), opacity var(--ease); }
  .ico-warn { color: var(--warn); }

  /* --- THE LABEL TREATMENT ------------------------------------------------
     A terminal column header, applied wherever a word names a number. Small,
     recessive, uppercase and tracked so it reads as a header rather than as
     prose competing with the figure beside it. */
  .lbl, .pt-grid span, .pt-metrics span, .tb-grid > div > span:first-child {
    font-size: var(--fs-2xs); color: var(--muted); text-transform: uppercase;
    letter-spacing: .07em; font-weight: 600; line-height: 1.35;
  }
  /* How often the rate cleared its hurdle, per window. A row of small facts
     under the metrics, not a chart: two numbers and their spread. */
  .pt-hh { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 18px;
           margin: 6px 0 2px; }
  .pt-hh-lbl { font-size: var(--fs-2xs); color: var(--muted);
               text-transform: uppercase; letter-spacing: .07em;
               font-weight: 600; }
  .pt-hh-w { display: inline-flex; align-items: baseline; gap: 6px; }
  .pt-hh-w small { font-size: var(--fs-2xs); color: var(--muted); }

  /* The reason a break-even is out of reach, under the number itself. Not
     uppercase and not tracked: it is a sentence, not a column header, and the
     rule above would otherwise catch it and shout it. */
  .pt-metrics .pt-be {
    display: block; font-size: var(--fs-2xs); color: var(--muted);
    text-transform: none; letter-spacing: 0; font-weight: 400;
    margin-top: 2px; line-height: 1.35;
  }

  /* --- PILLS --------------------------------------------------------------
     Metadata reads as a badge, not as a run-on sentence. One primitive, three
     tones, used by the tags, the risk badges and the reference blocks. */
  .pill, em.ok, em.mid, em.bad, .pt-tag, .pt-count, .pf-type, .pf-src,
  .tb-new, .vcode {
    display: inline-flex; align-items: center; gap: .3rem;
    font-style: normal; font-size: var(--fs-2xs); font-weight: 600;
    letter-spacing: .04em; border-radius: 999px;
    padding: .18rem .55rem; background: var(--bg2);
    border: 1px solid var(--border); color: var(--muted);
  }
  em.ok { color: var(--pos); border-color: var(--pos-line); background: var(--pos-soft); }
  em.mid { color: var(--warn); border-color: var(--warn-line); background: var(--warn-soft); }
  em.bad { color: var(--neg); border-color: var(--neg-line); background: var(--neg-soft); }

  /* --- TIME TO MATURITY ---------------------------------------------------
     A bar under the figure, so a glance separates a market maturing this
     month from one maturing next year without reading either number.
     THE DENOMINATOR IS A FIXED ONE-YEAR HORIZON, not the market's own launch
     date: the launch is not on the scan path, and a bar drawn against a start
     this service does not have would be a picture of an assumption. Full bar
     means a year or more left; an empty one means days. */
  .mt-bar {
    display: block; height: 3px; margin-top: .35rem; border-radius: 2px;
    background: var(--bg2); overflow: hidden;
  }
  .mt-bar > i {
    display: block; height: 100%; border-radius: 2px;
    background: var(--accent); opacity: .75;
  }
  .mt-bar.is-short > i { background: var(--warn); opacity: 1; }

  /* --- WHERE IT LIVES -----------------------------------------------------
     The chain glyph, and what it is NOT. It was a filled grey square holding
     a place for protocol icons that never arrived, and a filled rectangle of
     nothing is the universal picture of a broken image. This is a hollow
     hexagon at the weight of the words around it: contextual, and quiet
     enough that the eye passes straight over it to the name. */
  .ico-chain {
    width: .82em; height: .82em; margin-right: .3rem; vertical-align: -.09em;
    stroke-width: 1.6; opacity: .72; flex: none;
  }

  /* --- FORMS --------------------------------------------------------------
     Inset against the panel, not raised: an input is a hole in the card. */
  input, select, textarea {
    background: var(--bg2); color: var(--text); border: 1px solid var(--border);
    border-radius: var(--radius-sm); padding: .62rem .75rem; font: inherit;
    font-size: var(--fs-sm2); font-weight: 600;
    box-shadow: inset 0 1px 2px rgba(0,0,0,.35);
    transition: border-color var(--ease), box-shadow var(--ease),
                background-color var(--ease);
  }
  /* THE PLATFORM'S OWN ARROW IS A GREY BITMAP on half the machines that will
     open this, and the one thing on a panel nobody chose. Drawn here instead,
     in the muted ink, as a data URI -- which the content policy already
     allows for images. */
  select {
    -webkit-appearance: none; appearance: none; padding-right: 2.1rem;
    cursor: pointer;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%239AA3AE' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: right .7rem center;
    background-size: 14px;
  }
  select option { background: var(--card-2); color: var(--text); }
  input::placeholder { color: var(--muted); opacity: .6; font-weight: 500; }
  input:hover, select:hover, textarea:hover { border-color: var(--rule-strong); }
  input:focus, select:focus, textarea:focus {
    outline: none; border-color: var(--accent-line);
    box-shadow: 0 0 0 4px var(--accent-soft), inset 0 1px 2px rgba(0,0,0,.35);
  }
  :focus-visible { outline: 2px solid var(--accent); outline-offset: 2px;
                   border-radius: var(--radius-xs); }

  /* THE PAGE HEAD: an eyebrow, the title, one line under it. It sits in the
     same column as everything below it -- see `--page-w`. */
  header.top {
    max-width: var(--page-w); margin: 0 auto;
    padding: 2.1rem var(--gutter) 1.1rem;
  }
  header.top h1 {
    margin: 0 0 .45rem; font-size: var(--fs-2xl); font-weight: 800;
    letter-spacing: -.03em; line-height: 1.12;
    display: flex; gap: .6rem; align-items: center;
  }
  header.top .sub {
    margin: 0 0 1rem; font-size: var(--fs-sm2); color: var(--muted);
    font-weight: 500; max-width: 78ch; line-height: 1.6;
  }
  /* THE EYEBROW. A small tracked line over a title that says what KIND of
     page this is, with a lit dot in front of it -- the one place the service
     states its own register before the reader has read a word. */
  .vt-eyebrow {
    display: flex; align-items: center; gap: .6rem; margin: 0 0 .75rem;
    font-size: var(--fs-2xs); font-weight: 750; letter-spacing: .2em;
    text-transform: uppercase; color: var(--muted);
  }
  .vt-eyebrow::before {
    content: ""; width: 6px; height: 6px; flex: none; border-radius: 50%;
    background: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft), 0 0 12px var(--glow-strong);
  }
  footer {
    max-width: var(--page-w); margin: 3rem auto 0;
    padding: 1.5rem var(--gutter) 2.6rem; position: relative;
    border-top: 1px solid var(--border);
    font-size: var(--fs-sm); color: var(--muted); font-weight: 450;
    line-height: 1.6;
  }
  .vline { margin-top: .7rem; font-size: var(--fs-xs); }
  .vcode { background: var(--bg2); }
  main { max-width: var(--page-w); margin: 0 auto; padding-bottom: 1rem; }
  /* The column pages -- the book, one holding, the engine, the introduction
     -- keep the same gutter as the top bar above them. */
  main.wrap { padding-left: var(--gutter); padding-right: var(--gutter); }
  /* A PAGE'S OWN HEAD, for the pages whose sheets do not carry one. */
  .vt-head { padding: 2.1rem 0 .2rem; }
  .vt-head h1 { margin: 0 0 .9rem; font-size: var(--fs-2xl); font-weight: 800;
    letter-spacing: -.03em; line-height: 1.12; }

  /* THE MARK. It used to travel with the name as a separate wordmark at the
     top of each page; the top bar carries both now (`.vt-brand`). */
  .vt-mark { border-radius: 5px; display: block; flex: none; }

  /* --- THE EXPLAINED TERM -------------------------------------------------
     A dotted-underlined word with a small box behind it, and the reason it
     replaced `title=`: a native tooltip does not exist on a touch screen, does
     not appear for eight hundred milliseconds on a desktop, cannot hold two
     sentences, and cannot be read by anyone navigating with a keyboard. The
     words being explained here -- "extreme", "denomination", "control" -- are
     the ones a holder most needs explained, so they were in the worst possible
     place for it.

     IT IS A BUTTON, not a hover target. Click, Enter and Space all open it;
     Escape and the next click anywhere close it. The box is positioned by the
     browser against the term itself, which is why the term carries
     `position:relative` and nothing measures anything in script. */
  .vt-term { position: relative; display: inline-flex; align-items: center; }
  button.vt-key {
    font: inherit; color: inherit; background: none; border: 0; padding: 0;
    cursor: help; text-decoration: underline dotted var(--accent-line);
    text-underline-offset: .22em; text-decoration-thickness: 1px;
    display: inline-flex; align-items: center; gap: .25rem;
  }
  button.vt-key:hover { text-decoration-color: var(--accent); }
  button.vt-key::after {
    content: "?"; font-size: .62em; font-weight: 700; line-height: 1;
    width: 1.15em; height: 1.15em; border-radius: 999px; flex: none;
    display: inline-flex; align-items: center; justify-content: center;
    color: var(--muted); border: 1px solid var(--border);
    background: var(--bg2); transition: color var(--ease),
                border-color var(--ease);
  }
  button.vt-key[aria-expanded="true"]::after,
  button.vt-key:hover::after { color: var(--text); border-color: var(--rule-strong); }
  /* A badge that explains itself keeps its own shape: no dotted rule, and the
     question mark would crowd it, so the badge IS the affordance. */
  button.vt-key.is-badge { text-decoration: none; cursor: help; }
  button.vt-key.is-badge::after { content: none; }
  /* FIXED, not absolute, and that is not a detail. Two of the places a term
     appears -- the risk cell of the positions table, and the market table --
     live inside a box with `overflow-x:auto`, which clips anything drawn
     outside it. An absolutely-positioned box would have had its explanation
     cut off exactly where the explanation was most needed. Fixed takes it out
     of every scroll container; the script places it against the button and
     closes it if the page scrolls underneath. */
  .vt-pop {
    position: fixed; z-index: 40; pointer-events: auto;
    width: max-content; max-width: min(30ch, 78vw);
    background: var(--surface-2); color: var(--text);
    border: 1px solid var(--rule-strong); border-radius: var(--radius-sm);
    box-shadow: var(--shadow-2), var(--lift);
    padding: .6rem .7rem; font-size: var(--fs-xs); font-weight: 400;
    line-height: 1.45; text-align: left; white-space: normal;
    animation: vt-pop var(--ease) both;
  }

  .vt-pop b { display: block; margin-bottom: .2rem; font-size: var(--fs-2xs);
    letter-spacing: .05em; text-transform: uppercase; color: var(--muted); }
  @keyframes vt-pop {
    from { opacity: 0; transform: translateY(-3px); }
    to { opacity: 1; transform: none; }
  }
  @media (prefers-reduced-motion: reduce) { .vt-pop { animation: none; } }

  /* While a swap is in flight. A whole-page spinner would be a bigger
     interruption than the reload this replaced; this is a hairline at the top
     of the window and a slight dimming of the column being replaced -- enough
     to say "asked", not enough to make the reader wait for it. */
  .vt-loading main { opacity: .55; transition: opacity var(--ease); }
  .vt-loading::before {
    content: ""; position: fixed; inset: 0 0 auto; height: 2px; z-index: 90;
    background: linear-gradient(90deg, transparent, var(--accent), transparent);
    animation: vt-sweep 900ms linear infinite;
  }
  @keyframes vt-sweep {
    from { transform: translateX(-100%); } to { transform: translateX(100%); }
  }
  @media (prefers-reduced-motion: reduce) {
    .vt-loading::before { animation: none; opacity: .5; }
    .vt-loading main { transition: none; }
  }

  /* =========================================================================
     THE CHART COMPONENT, shared by both pages.
     It was built for the portfolio and lived there, which left every chart on
     the dashboard a picture again -- the same complaint, one page over. A
     component used by two pages belongs where both can reach it.
     The class names keep their `pf-` prefix: they are names, renaming them
     across the stylesheets, the scripts and the tests would change nothing
     that a reader can see.
     ========================================================================= */
  /* --- A CHART YOU CAN ASK A QUESTION OF ----------------------------------
     THE GRID, THE AXES AND THE CARD. These were sparklines: a shape with no
     scale on it, so a rising line said the book had grown and nothing more.
     Three things changed -- rules at named values, dates along the bottom, and
     a card that names every series under the pointer with its own colour.

     THE LABELS ARE HTML AND THE PLOT IS SVG. The plot is stretched to the
     column's width, which is right for a line and fatal for a letter; type
     inside it would stretch with the container. Outside, positioned by
     percentage, it stays the size it was set in. */
  /* The sparkline wears the same component but stays inline: it lives inside
     a line of text on a card, not in a column of its own. */
  .spark-plot { display:inline-block; position:relative; }
  .spark-plot .pf-canvas { display:inline-block; }
  .spark-plot .pf-readout { min-width:6.5rem; }
  .pf-plot { position:relative; display:grid;
    grid-template-columns:auto 1fr; grid-template-rows:auto auto auto;
    column-gap:.45rem; margin:.15rem 0 .2rem; }
  .pf-canvas { position:relative; grid-column:2; grid-row:1; }
  .pf-plot svg { cursor:crosshair; touch-action:pan-y; display:block;
    width:100%; }
  /* The y labels sit against the plot's own height, each pinned to the rule it
     names -- translated up by half a line so the text centres on the rule. */
  .pf-yaxis { position:relative; grid-column:1; grid-row:1; width:3.1rem; }
  .pf-yaxis > span { position:absolute; right:0; transform:translateY(-50%);
    font-size:var(--fs-2xs); color:var(--muted); white-space:nowrap;
    font-variant-numeric:tabular-nums; }
  .pf-xaxis { position:relative; grid-column:2; grid-row:2; height:1.05rem;
    margin-top:.2rem; }
  .pf-xaxis > span { position:absolute; transform:translateX(-50%);
    font-size:var(--fs-2xs); color:var(--muted); white-space:nowrap; }
  /* The first and last labels are pulled inside the box rather than hanging
     off its edges, which is where a centred label at 0% and 100% would sit. */
  .pf-xaxis > span:first-child { transform:none; }
  .pf-xaxis > span:last-child { transform:translateX(-100%); }
  .pf-plot-note { grid-column:2; grid-row:3; margin:.35rem 0 0;
    font-size:var(--fs-2xs); color:var(--muted); line-height:1.45; }
  /* RECESSIVE ON PURPOSE. A grid is there to be measured against, not to be
     seen; at this weight it reads as texture until the eye looks for it. */
  .pf-grid { stroke:var(--border); stroke-width:1; opacity:.55;
    vector-effect:non-scaling-stroke; pointer-events:none; }
  /* THE LINE IS SOLID, AND THAT IS THE POINT OF IT. It was a dotted hairline
     at half opacity, which is a decoration; what a reader needs is a straight
     edge they can run their eye down to the date axis and up to the value
     axis. A dashed line breaks that edge into pieces and the eye has to
     rebuild it. Solid, at an opacity that still sits under the series. */
  .pf-cross { stroke:var(--accent); stroke-width:1; opacity:.6;
    vector-effect:non-scaling-stroke; pointer-events:none; }
  /* AN HTML DOT, NOT AN SVG CIRCLE -- see `_plot_frame`: these plots are
     stretched unevenly, and a circle drawn inside one comes out an ellipse.
     Positioned by percentage over the canvas, so it is round at any width.
     `translate(-50%,-50%)` puts its CENTRE on the reading rather than its
     top-left corner. */
  .pf-mark { position:absolute; z-index:15; width:.5rem; height:.5rem;
    margin:0; border-radius:50%; background:var(--card);
    border:2px solid var(--accent); transform:translate(-50%, -50%);
    pointer-events:none; }
  .pf-band { fill:var(--accent); opacity:.09; pointer-events:none; }
  /* THE VALUE LINE AND ITS AREA, here and not in the book's sheet: the
     engine page draws the same line and does not load that sheet, so its
     journal charts were polylines with no stroke at all -- black fills on a
     black panel. A component two pages draw belongs where both can see it.

     THE LINE GLOWS, faintly: a drop-shadow in the line's own ink, which on
     this ground is what makes a trace read as lit rather than printed. */
  .pf-spark-line { fill:none; stroke:var(--accent); stroke-width:1.6;
    vector-effect:non-scaling-stroke; stroke-linejoin:round;
    stroke-linecap:round;
    filter:drop-shadow(0 0 5px rgba(214,226,244,.35)); }
  .pf-spark-fill { fill:var(--accent); opacity:.14; }
  .pf-fade-top { stop-color:var(--accent); stop-opacity:.24; }
  .pf-fade-end { stop-color:var(--accent); stop-opacity:0; }
  .pf-spark-fill[style] { opacity:1; }
  .pf-spark-dot { fill:var(--accent); }
  /* PINNED LOOKS PINNED. A frozen reading and a live one must not be
     indistinguishable: the crosshair brightens and thickens and the card takes
     the accent edge, so nobody reads yesterday's point as today's pointer.
     It used to be the dashes that went away on pinning; now that the line is
     solid while hovering, weight and opacity carry the difference. */
  .pf-plot.is-pinned .pf-cross { stroke-width:1.5; opacity:.95; }
  .pf-plot.is-pinned .pf-readout { border-color:var(--accent-line); }
  .pf-plot.is-pinned svg { cursor:default; }

  /* --- THE READOUT CARD ---------------------------------------------------
     A heading with the day, then one row per series: its colour, its name,
     its number. It replaced a single run-on line, which worked for one value
     and fell apart the moment a day had both a result and a money movement. */
  .pf-readout { position:absolute; top:.1rem; z-index:20; pointer-events:none;
    background:var(--surface-2); border:1px solid var(--rule-strong);
    border-radius:var(--radius-sm); box-shadow:var(--shadow-2), var(--lift);
    padding:.4rem .55rem; font-size:var(--fs-2xs); white-space:nowrap;
    font-variant-numeric:tabular-nums; min-width:8.5rem; }
  .pf-ro-head { color:var(--muted); font-weight:600; letter-spacing:.04em;
    padding-bottom:.28rem; margin-bottom:.28rem;
    border-bottom:1px solid var(--border); }
  .pf-ro-row { display:flex; align-items:center; gap:.4rem; line-height:1.55; }
  .pf-ro-row > i { width:.5rem; height:.5rem; border-radius:2px; flex:none; }
  .pf-ro-row > span { color:var(--muted); }
  .pf-ro-row > b { margin-left:auto; color:var(--text); font-weight:700; }
  .pf-ro-row > b.pos { color:var(--pos); }
  .pf-ro-row > b.neg { color:var(--neg); }


  /* --- WHAT RESTS AND WHAT FLOATS -----------------------------------------
     Two elevations, applied here once so no component invents a third. A
     panel at rest carries `--shadow-1`; anything the reader has opened, or
     that sits above the page, carries `--shadow-2` and a slightly wider
     radius. The lift on open is what the old flat-bordered screen lacked. */
  .pt-card, .pf-form, .pf-tablewrap, .pt-summary div, .lg-card,
  .pf-undo, .pf-sum, .rk-sys {
    box-shadow: var(--shadow-1);
    transition: box-shadow var(--ease), border-color var(--ease);
  }

  /* --- THE SHARED TABLE, AND WHY IT LIVES HERE ----------------------------
     `.pf-table` inside `.pf-tablewrap` is used by two pages: the book and the
     engine. The rules lived in the BOOK's stylesheet, which the engine page
     does not load -- so the engine's three tables were served with no width,
     no padding, no rules between cells, and, worst of it, no scrolling box.
     A five-column table with prose in the first cell then pushed the whole
     document sideways on a phone, taking the pinned bar out of reach with it.

     A component used by two pages is not one page's furniture. The same
     lesson the language switch taught, in a stylesheet instead of a rule.

     NO `min-width` HERE. The book's nine columns need a floor to scroll
     against; the engine's five do not, and forcing 52rem on them invents a
     sideways scroll on a table that would have fitted. The floor belongs to
     the table that needs it, in the sheet that knows. */
  /* THE SIDEWAYS SCROLL, MADE VISIBLE. Nine columns do not fit a phone and
     several do not fit a laptop, and until now the only way to learn there
     was more to the right was to try. Two pairs of gradients do it with no
     script: the `local` layers scroll away with the content, the `scroll`
     layers stay put, so a shadow appears at an edge exactly while there is
     something past it and vanishes when you reach the end.

     NOT A SCROLLBAR SUBSTITUTE -- the bar is styled a few rules up and stays.
     This is the hint you see without looking for it.

     DELIBERATELY NOT STICKY HEADERS, which is what this box seems to want.
     `overflow-x: auto` makes `overflow-y` compute to `auto` as well, so the
     wrapper is its own scroll container in both axes while having no height
     to scroll -- a `position: sticky` header inside it would be a rule that
     renders, validates, and does nothing at all. */
  .pf-tablewrap { overflow-x: auto; border-radius: var(--radius);
    border: 1px solid var(--border);
    background:
      linear-gradient(to right, var(--card) 40%, transparent)
        left center / 2.4rem 100% no-repeat local,
      linear-gradient(to left, var(--card) 40%, transparent)
        right center / 2.4rem 100% no-repeat local,
      radial-gradient(farthest-side at 0 50%, var(--edge-hint), transparent)
        left center / .85rem 100% no-repeat scroll,
      radial-gradient(farthest-side at 100% 50%, var(--edge-hint), transparent)
        right center / .85rem 100% no-repeat scroll,
      var(--card); }
  .pf-table { width: 100%; border-collapse: collapse;
    font-size: var(--fs-sm2); }
  .pf-table th, .pf-table td { padding: .8rem .95rem; text-align: left;
    border-bottom: 1px solid var(--border); white-space: nowrap;
    vertical-align: top; }
  .pf-table th { font-size: var(--fs-2xs); color: var(--muted);
    font-weight: 700; text-transform: uppercase; letter-spacing: .09em;
    white-space: nowrap; background: rgba(255,255,255,.018);
    border-bottom-color: var(--rule-strong); }
  /* The figures are the reason for the table, so they are set like figures. */
  .pf-table td.num { text-align: right; font-size: var(--fs-base);
    font-weight: 600; }
  .pf-table th.num { text-align: right; }
  /* The row under the pointer arrived instantly and left instantly, which on
     a nine-column table reads as a flicker while the eye travels. The same
     `--ease` everything else moves on; `background-color` only, because
     transitioning `background` would animate the wrapper's gradients too. */
  .pf-table tbody tr td {
    transition: background-color var(--ease); }
  .pf-table tbody tr:hover td { background-color: rgba(255,255,255,.028); }
  .pf-table tbody tr:last-child td { border-bottom: 0; }
  .pf-table small { font-size: var(--fs-2xs); margin-left: .4rem;
    color: var(--muted); font-weight: 400; }
  .pf-empty { text-align: center; color: var(--muted); padding: 2rem .7rem; }
  .pt-card:hover { box-shadow: var(--shadow-2); }

  /* NOTHING ON THIS PAGE ACKNOWLEDGED BEING PRESSED. A control that changes
     on hover and then holds perfectly still under the finger reads as not
     having registered -- which on a slow route is exactly when a reader
     clicks it a second time. One pixel down and slightly dimmed: enough to
     feel, too little to notice.

     THE SAME LIST AS THE FORTY-FOUR-PIXEL RULE below, because it is the same
     question -- which things here are pressed. `:active` needs no reduced
     motion guard: it is a state, not an animation, and it is already
     instantaneous. */
  .pt-tab:active, .pt-btn:active, .pf-submit:active, .pf-refresh:active,
  .pt-sort:active, .pf-del:active, .pt-showall:active, .vt-back:active,
  .pf-open:active, .lg-submit:active, .pt-lang:active {
    transform: translateY(1px); filter: brightness(.94); }

  details[open] > summary ~ * { animation: vt-unfold var(--ease) both; }
  @keyframes vt-unfold {
    from { opacity: 0; transform: translateY(-2px); }
    to { opacity: 1; transform: none; }
  }
  @media (prefers-reduced-motion: reduce) {
    details[open] > summary ~ * { animation: none; }
    .pt-card:hover { box-shadow: var(--shadow-1); }
  }
  summary { transition: color var(--ease); }

  /* =========================================================================
     THE SHELL: ONE TOP BAR FOR EVERY PAGE (25 Sep 2026).
     Every page drew its own chrome -- a wordmark row with two links on the
     board, a heading-with-nav on the book, a heading whose styles lived in
     the BOOK's sheet on the engine page (so it rendered as "VANTIASEngine"
     with a bare "Sign out" link under it), and a third arrangement on the
     introduction. Moving between them, the product changed shape under the
     reader. One bar now: the mark, the four places, and on the right what
     state the data is in and the way out.

     NOT STICKY BY DEFAULT. The board and every page you go INTO already pin
     a working bar of their own -- tabs and filters, or the way back -- and a
     second pinned strip above it would take a fifth of a laptop screen. A
     page with no working bar of its own asks for `is-pinned`.
     ========================================================================= */
  .vt-top {
    position: relative; z-index: 34;
    background: rgba(11,13,16,.72);
    -webkit-backdrop-filter: saturate(150%) blur(14px);
    backdrop-filter: saturate(150%) blur(14px);
    border-bottom: 1px solid rgba(35,40,48,.85);
  }
  .vt-top.is-pinned { position: sticky; top: 0; }
  .vt-top::after {
    content: ""; position: absolute; left: 0; right: 0; bottom: -1px;
    height: 1px; background: var(--hairline); opacity: .5;
    pointer-events: none;
  }
  .vt-top-in {
    max-width: var(--page-w); margin: 0 auto; min-height: 64px;
    padding: 0 var(--gutter); display: flex; align-items: center;
    gap: .6rem 1.1rem; flex-wrap: wrap;
  }
  .vt-brand {
    display: inline-flex; align-items: center; gap: .7rem; flex: none;
    color: var(--text); text-decoration: none; border-radius: var(--radius-xs);
  }
  /* The mark carries the light: a soft halo under the tile, the way a lit
     object sits on a dark table. */
  .vt-brand .vt-mark {
    border-radius: 9px;
    filter: drop-shadow(0 3px 12px rgba(214,226,244,.22));
  }
  .vt-brand-t { display: inline-flex; flex-direction: column; gap: 3px;
    line-height: 1; }
  .vt-brand-t b { font-size: .86rem; font-weight: 800; letter-spacing: .2em;
    text-transform: uppercase; }
  .vt-brand-t small { font-size: .52rem; font-weight: 650; letter-spacing: .44em;
    text-transform: uppercase; color: var(--muted); }
  .vt-nav { display: flex; align-items: center; gap: 2px; margin-left: .6rem; }
  .vt-nav a {
    position: relative; display: inline-flex; align-items: center;
    padding: .5rem .85rem; border-radius: 999px; white-space: nowrap;
    color: var(--muted); font-size: var(--fs-sm2); font-weight: 650;
    text-decoration: none;
    transition: color var(--ease), background-color var(--ease);
  }
  .vt-nav a:hover { color: var(--text); background: rgba(255,255,255,.045); }
  .vt-nav a.is-on { color: var(--text); }
  /* WHERE YOU ARE is a lit dot under the word, not a filled pill: the bar is
     chrome and should stay quieter than the page it heads. */
  .vt-nav a.is-on::after {
    content: ""; position: absolute; left: 50%; bottom: 1px;
    width: 5px; height: 5px; margin-left: -2.5px; border-radius: 50%;
    background: var(--accent); box-shadow: 0 0 10px var(--glow-strong);
  }
  .vt-top-end { margin-left: auto; display: flex; align-items: center;
    gap: .75rem; }
  /* THE STATE OF THE DATA, in the bar, with a dot that says it at a glance:
     lit green while the book is fresh, warn once it is stale. The sentence
     beside it says the same thing in words, so the dot is never alone. */
  .vt-status { display: inline-flex; align-items: center; gap: .55rem;
    font-size: var(--fs-2xs); font-weight: 600; color: var(--muted);
    letter-spacing: .01em; white-space: nowrap; }
  .vt-status i { width: 7px; height: 7px; border-radius: 50%; flex: none;
    background: var(--pos);
    box-shadow: 0 0 0 3px var(--pos-soft), 0 0 10px rgba(86,192,141,.55); }
  .vt-status.is-stale i { background: var(--warn);
    box-shadow: 0 0 0 3px var(--warn-soft), 0 0 10px rgba(215,165,74,.5); }
  .vt-status.is-unknown i { background: var(--muted); box-shadow: none; }
  .vt-out, .vt-in {
    display: inline-flex; align-items: center; gap: .4rem; min-height: 34px;
    padding: .38rem .85rem; border-radius: var(--radius-sm);
    font-size: var(--fs-sm); font-weight: 650; text-decoration: none;
    white-space: nowrap; color: var(--muted);
    border: 1px solid var(--border); background: rgba(255,255,255,.02);
    transition: color var(--ease), border-color var(--ease),
                background-color var(--ease);
  }
  .vt-out:hover { color: var(--text); border-color: var(--rule-strong);
    background: rgba(255,255,255,.05); }
  /* Signing IN is the one action a visitor's bar offers, so it is the one
     filled control on it. */
  .vt-in { color: var(--on-accent); background: var(--btn);
    border-color: transparent; box-shadow: var(--btn-glow); }
  .vt-in:hover { background: var(--btn-hover); box-shadow: var(--btn-glow-hover);
    color: var(--on-accent); }
  .vt-top .pt-langs { box-shadow: none; }

  /* --- BUTTONS, ONE FAMILY ------------------------------------------------
     Every filled control on the service -- recalculate, add a position, sign
     in -- is the same brushed platinum with the same lit edge, so "this is
     the thing to press" is learnt once. HERE and not in the three pages'
     sheets, which is where three slightly different copies of it lived. */
  .pt-btn, .pf-submit, .lg-submit {
    font: inherit; font-size: var(--fs-sm2); font-weight: 750;
    letter-spacing: .01em; cursor: pointer; min-height: 40px;
    padding: .58rem 1.15rem; border-radius: var(--radius-sm);
    background: var(--btn); color: var(--on-accent);
    border: 1px solid rgba(255,255,255,.35); box-shadow: var(--btn-glow);
    transition: transform var(--ease), box-shadow var(--ease),
                background var(--ease), border-color var(--ease);
  }
  .pt-btn:hover, .pf-submit:hover, .lg-submit:hover {
    background: var(--btn-hover); box-shadow: var(--btn-glow-hover);
    transform: translateY(-1px);
  }
  .lg-submit:disabled { transform: none; box-shadow: none; opacity: .5;
    cursor: not-allowed; }
  /* THE SECOND BUTTON IN A PAIR IS A GHOST. "Recalculate" and "Refresh data"
     sat side by side in the same fill and read as one control twice. */
  .pt-btn.is-ghost {
    background: rgba(255,255,255,.03); color: var(--text);
    border-color: var(--rule-strong); box-shadow: var(--lift);
  }
  .pt-btn.is-ghost:hover { background: rgba(255,255,255,.07);
    border-color: var(--muted); }

  /* --- A STRIP OF FIGURES, LED BY ITS FIRST ---------------------------------
     The first cell of a strip -- the figure the strip is led by -- carries
     the platinum line across its head and a trace of light under it. */
  .pt-summary > div:first-child, .ab-cov-cell:first-child {
    background: var(--hairline) top / 100% 1px no-repeat,
                linear-gradient(180deg, rgba(226,232,240,.05), transparent 70%),
                var(--card-2);
  }

  /* --- THE BOOK'S FIGURE STRIP, AND WHY IT LIVES HERE ------------------------
     `.pf-sum-*`, `.pf-caveat` and `.pf-h2` were the book's, and the engine
     page uses all of them -- without loading the book's sheet. Its estimator
     percentiles and its verdict counts were served as bare spans and bold
     text run together on one line, its section headings at the browser's
     default size. Sixth time for this mistake; the rule in the memory file
     is right and this is it applied.

     Inside the book's summary panel the strip is part of that panel; standing
     on its own, as on the engine page, it is its own lit panel. Each cell
     draws its own left and top rule and the panel's `overflow:hidden` trims
     the outer ones, whatever number of columns the width allows. */
  .pf-sum-figures { display:grid; gap:0;
    grid-template-columns:repeat(auto-fit,minmax(11.5rem,1fr)); }
  :not(.pf-summary) > .pf-sum-figures {
    margin:.4rem 0 1rem; overflow:hidden; background:var(--surface);
    border:1px solid var(--border); border-radius:var(--radius);
    box-shadow:var(--shadow-1); }
  .pf-sum-fig { display:flex; flex-direction:column; gap:.3rem; min-width:0;
    padding:1.1rem 1.25rem 1.05rem;
    box-shadow:-1px 0 0 var(--border), 0 -1px 0 var(--border); }
  .pf-sum-fig:first-child {
    background:var(--hairline) top / 100% 1px no-repeat,
               linear-gradient(180deg, rgba(226,232,240,.05), transparent 70%); }
  .pf-sum-k { font-size:var(--fs-xs); color:var(--muted); font-weight:650;
    letter-spacing:.01em; }
  .pf-sum-k::first-letter { text-transform:uppercase; }
  /* `anywhere`, because a token count carries six decimals and at display
     size "15,164.642778" is wider than the cell it sits in: it ran over the
     next figure on the holding's page. A break inside a number is ugly; a
     number printed on top of another is wrong. */
  .pf-sum-v { font-size:1.6rem; font-weight:780; line-height:1.12;
    font-variant-numeric:tabular-nums; letter-spacing:-.035em;
    overflow-wrap:anywhere; }
  .pf-sum-v.accent { color:var(--accent); }
  .pf-sum-sub { font-size:var(--fs-2xs); color:var(--muted); line-height:1.45; }
  .pf-caveat { margin:0 0 1rem; font-size:var(--fs-sm); color:var(--muted);
    font-weight:450; line-height:1.6; max-width:82ch; }
  .pf-h2 { font-size:var(--fs-lg); font-weight:800; letter-spacing:-.025em;
    margin:2.4rem 0 .9rem; padding-bottom:.65rem;
    border-bottom:1px solid var(--border); }

  /* --- NUMBERS ARE SET, NOT TYPED -----------------------------------------
     Manrope's figures are generous; at display sizes they want tighter
     tracking and a heavier weight, or a column of them reads as loose. */
  .pt-grid b, .pf-sum-v, .ab-fig b, .ab-cov-cell b, .pt-metrics b {
    letter-spacing: -.03em; font-weight: 750;
  }

  /* --- A RISING ENTRANCE ---------------------------------------------------
     Panels settle into place over a quarter second when a page opens. Not
     on every panel of a 183-card board -- only what is above the fold on
     most pages: the head, the strip and the first blocks. */
  header.top, .pt-summary, .pf-summary, .en-intro, .ab-hero, .lg-card,
  .pf-poshead {
    animation: vt-rise 420ms cubic-bezier(.2,.7,.2,1) both;
  }
  .pt-summary { animation-delay: 60ms; }
  .pf-summary { animation-delay: 60ms; }
  @keyframes vt-rise {
    from { opacity: 0; transform: translateY(6px); }
    to { opacity: 1; transform: none; }
  }
  /* ONCE, ON ARRIVAL. A recalculation or a change of language swaps the
     head and the column in place, and a panel rising into view every time a
     number is recomputed is motion that says nothing. The swap marks the
     page as settled and the entrance does not play again. */
  @media (prefers-reduced-motion: reduce) {
    header.top, .pt-summary, .pf-summary, .en-intro, .ab-hero, .lg-card,
    .pf-poshead { animation: none; }
  }
  .vt-settled header.top, .vt-settled .pt-summary, .vt-settled .pf-summary,
  .vt-settled .en-intro, .vt-settled .ab-hero, .vt-settled .pf-poshead {
    animation: none; }

/* A SEGMENTED SWITCH, not two links. It read as body text with a border round
   it: underlined on hover, no affordance, and small enough to miss. A switch
   says "a control with two positions, one of them chosen", which is what it
   is. */
.pt-langs{position:static;display:inline-flex;
  padding:3px;gap:2px;border-radius:999px;background:var(--bg2);
  border:1px solid var(--border);z-index:5;
  box-shadow:var(--shadow-1)}
.pt-lang{display:inline-flex;align-items:center;justify-content:center;
  min-width:2.6rem;min-height:1.9rem;padding:0 .6rem;border-radius:999px;
  font-size:.78rem;font-weight:600;letter-spacing:.05em;color:var(--muted);
  text-decoration:none;border:0;transition:background var(--ease),color var(--ease)}
.pt-lang:hover{color:var(--text);background:var(--accent-soft);
  text-decoration:none}
.pt-lang.is-on{background:var(--accent);color:var(--on-accent);
  box-shadow:var(--shadow-1)}
.pt-lang.is-on:hover{background:var(--accent);color:var(--on-accent)}
.pt-lang:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
/* THE DEFAULT IS IN FLOW, AND THAT IS THE FIX FOR A BUG THAT CAME BACK FOUR
   TIMES. The switch used to be absolute by default and reset to static inside
   an allow-list of containers, with a comment saying every new home had to add
   itself. Three homes were added and the fourth -- the about page's own
   `<nav>` -- was missed, so on a phone the switch sat on top of "sign in".
   An allow-list that must be edited by whoever adds a header is not a rule,
   it is a trap with a note attached.

   So the polarity is inverted. In flow, always; floating only where a page
   has no bar to put it in, which is exactly one page: the sign-in form, whose
   layout is a centred card on an empty sheet. A new header anywhere else gets
   the correct behaviour without knowing this file exists. */
.lg-body>.pt-langs{position:absolute;top:.9rem;right:.9rem}

/* The switch is two targets side by side and they were 38x34 -- under the
   forty-four a finger needs, on the one control every page carries. The
   height comes from the shared rule in RESPONSIVE_CSS; the width is here. */
@media (max-width:640px){.lg-body>.pt-langs{top:.6rem;right:.6rem}
  .pt-lang{min-width:2.9rem}}
@media (prefers-reduced-motion:reduce){.pt-lang{transition:none}}

/* --- THE PINNED WAY BACK, on every page you go INTO ------------------------
   See `subnav()`. It is deliberately the size of a control: the link it
   replaced was small grey text under a heading, and a heading three screens
   up is not a way out of anything. It carries the language switch with it so
   a sub-page has one bar rather than two things pinned at different heights.

   OPAQUE, like the dashboard's own pinned bar, because content scrolls
   underneath it and on a dark sheet translucent text over moving text is
   unreadable for the second it takes to pass. */
/* THE CONTENT OF THE BAR SITS IN THE PAGE'S COLUMN while the bar itself
   runs the width of the window: the padding grows by exactly the margin the
   column leaves, so "All markets" starts where the cards start. Inside a
   `.wrap` -- a column already -- the bar bleeds out over the column's gutter
   and takes it back as padding, for the same alignment. */
.vt-subnav{position:sticky;top:0;z-index:31;display:flex;align-items:center;
  gap:.9rem;flex-wrap:wrap;background:var(--bg);
  border-bottom:1px solid var(--border);
  padding:.6rem max(var(--gutter),calc((100% - var(--page-w)) / 2 + var(--gutter)));
  margin:0 0 1.3rem}
.wrap>.vt-subnav{margin-left:calc(-1 * var(--gutter));
  margin-right:calc(-1 * var(--gutter));padding-left:var(--gutter);
  padding-right:var(--gutter)}
.vt-back{display:inline-flex;align-items:center;gap:.45rem;
  font-size:var(--fs-sm);font-weight:650;letter-spacing:.01em;
  text-decoration:none;color:var(--text);
  border:1px solid var(--rule-strong);background:var(--surface-2);
  border-radius:999px;padding:.42rem .9rem .42rem .75rem;
  box-shadow:var(--lift);
  transition:border-color var(--ease),color var(--ease)}
.vt-back:hover{border-color:var(--accent-line);color:var(--accent)}
.vt-back:hover .ico-left{transform:translateX(-2px)}
.vt-subnav .pt-langs{margin-left:auto}
@media (max-width:640px){.vt-subnav{padding-top:.5rem;padding-bottom:.5rem;gap:.6rem}}

  @media (max-width: 860px) {
    :root { --gutter: 1rem; }
    body { font-size: 1rem; }
    header.top { padding-top: 1.5rem; }
    header.top h1 { font-size: 1.55rem; }
    /* --- THE TOP BAR IN TWO ROWS, NOT THREE -----------------------------
       Left to wrap, it stacked the mark, the four places and the controls
       into three rows -- a sixth of a phone screen before the page began.
       The mark and the controls share the first row; the places get the
       second to themselves and scroll sideways if a language makes them
       wider than the glass. */
    .vt-top-in { min-height: 0; padding-top: .55rem; padding-bottom: .2rem;
      gap: .35rem .6rem; }
    .vt-brand { order: 1; }
    .vt-top-end { order: 2; gap: .5rem; }
    .vt-nav { order: 3; flex-basis: 100%; margin: 0 0 0 -.7rem;
      overflow-x: auto; scrollbar-width: none; }
    .vt-nav::-webkit-scrollbar { display: none; }
    .vt-nav a { padding: .55rem .7rem .7rem; }
    .vt-brand-t small { display: none; }
    .pt-grid, .pt-summary, .pt-metrics {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }
    .tb-grid { grid-template-columns: 1fr; }
    .pt-card { padding: 1rem .9rem; }
    .pf-tablewrap { -webkit-overflow-scrolling: touch; }
    .pt-controls, .pf-form { gap: .7rem; }
    .pt-controls label, .pf-field { flex: 1 1 100%; }
    .pt-controls input, .pf-field input, .pf-field select { width: 100%; }

    /* --- SIXTEEN PIXELS, AND IT HAS TO BE PIXELS ------------------------
       Safari on iOS ZOOMS THE WHOLE PAGE IN when a form control smaller
       than 16px takes focus, and it does not zoom back out when the field
       is left. The controls were set at `--fs-sm2`, which is .9rem -- 14.4
       pixels -- so tapping the sign-in field, the board's search, a filter
       select or the wallet box left the reader on a page half again too
       wide, scrolled somewhere they did not choose, with no way back but a
       pinch. Every form on the service was affected.

       NOT a rem: the threshold is absolute, and a rem is only 16px while
       nobody has changed their browser's text size. Somebody who set theirs
       larger is fine either way; somebody who set it smaller would get the
       zoom back with a rem and never know why. */
    input, select, textarea { font-size: 16px; }

    /* Forty-four pixels is the smallest target a finger hits reliably. */
    .pt-tab, .pt-btn, .pf-submit, .pf-refresh, .pt-sort, .pf-del,
    .pt-showall, .vt-back, .pf-open, .lg-submit, .pt-lang { min-height: 44px; }
    .pt-tab { padding: .65rem .9rem; }
    .tb > summary, .pt-risk summary, .pt-trust summary, .pt-loop summary {
      padding: .5rem 0; min-height: 44px;
    }
    .tb-watch, .pt-note, .pt-note-row { font-size: .88rem; }

    /* --- THE PINNED BAR ON A NARROW SCREEN ------------------------------
       Two rows instead of one, and the selects go full width: three of them
       squeezed onto a phone's width are three targets too small to hit. The
       count moves under them rather than fighting for the same line. */
    .pt-stick { padding: .45rem 1rem .5rem; }
    .pt-filters { gap: .45rem; }
    .pt-f { flex: 1 1 8.5rem; }
    .pt-f select { flex: 1 1 auto; width: 100%; min-height: 38px; }
    .pt-fcount { margin-left: 0; flex-basis: 100%; }
    /* THE HERO CELL STOPS SPANNING. At two columns a cell spanning both is
       the whole row, which is right -- but at one column the span is a no-op
       that leaves the grid confused about its own width. */
    .pt-grid > div.pt-hero { grid-column: span 2; }
    .pt-hero b { font-size: 1.45rem; }
    /* The actions drop to their own line rather than crushing the name. */
    .pt-actions { margin-left: 0; flex-basis: 100%; }
    .pt-cta { min-height: 38px; }
    /* A popover that is 30 characters wide on a phone runs off the screen. */
    .vt-pop { max-width: calc(100vw - 24px); }
  }
  @media (max-width: 640px) {
    /* THE DATA'S AGE LEAVES THE BAR ON A PHONE, and nothing is lost by it:
       the board and the market page both say it in full under their first
       panel, and the bar needs the width for the two controls. */
    .vt-status { display: none; }
    .vt-out { padding: .35rem .7rem; }
  }
  @media (max-width: 520px) {
    .pt-grid, .pt-summary, .pt-metrics { grid-template-columns: 1fr; }
    .pt-grid > div.pt-hero { grid-column: auto; }
    .pt-head { gap: .4rem; }
    .pt-name { font-size: 1.05rem; }
    header.top h1 { font-size: 1.3rem; flex-wrap: wrap; }
    .pf-head h1 { font-size: 1.3rem; }
    /* One tab strip that scrolls sideways beats three tabs wrapped onto two
       lines and pushing the filters off the top of the screen. */
    .pt-stick-row .pt-tabs { overflow-x: auto; flex-wrap: nowrap;
                             -webkit-overflow-scrolling: touch; }
    .pt-tabs::-webkit-scrollbar { display: none; }
    .pt-tab { white-space: nowrap; }
  }

  /* --- A TALL, NARROW WINDOW ON A DESKTOP -------------------------------
     The pinned bar earns its place by being small. On a short window it can
     take a quarter of the screen, at which point the thing it was meant to
     help -- reading the board -- is what it is costing. */
  @media (max-height: 560px) {
    .pt-stick { position: static; }
  }
